Skip to content

Commit b5f418f

Browse files
committed
Merge pull request #7522 from Microsoft/parseCompilerFlagsWithListOptions
Parsing compiler flags which takes options in form of list
2 parents 1156141 + 9e2df04 commit b5f418f

File tree

8 files changed

+891
-149
lines changed

8 files changed

+891
-149
lines changed

Jakefile.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,10 @@ var harnessSources = harnessCoreSources.concat([
150150
"reuseProgramStructure.ts",
151151
"cachingInServerLSHost.ts",
152152
"moduleResolution.ts",
153-
"tsconfigParsing.ts"
153+
"tsconfigParsing.ts",
154+
"commandLineParsing.ts",
155+
"convertCompilerOptionsFromJson.ts",
156+
"convertTypingOptionsFromJson.ts"
154157
].map(function (f) {
155158
return path.join(unittestsDirectory, f);
156159
})).concat([

src/compiler/commandLineParser.ts

Lines changed: 141 additions & 118 deletions
Large diffs are not rendered by default.

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2240,11 +2240,11 @@
22402240
"category": "Message",
22412241
"code": 6002
22422242
},
2243-
"Specifies the location where debugger should locate map files instead of generated locations.": {
2243+
"Specify the location where debugger should locate map files instead of generated locations.": {
22442244
"category": "Message",
22452245
"code": 6003
22462246
},
2247-
"Specifies the location where debugger should locate TypeScript files instead of source locations.": {
2247+
"Specify the location where debugger should locate TypeScript files instead of source locations.": {
22482248
"category": "Message",
22492249
"code": 6004
22502250
},
@@ -2276,7 +2276,7 @@
22762276
"category": "Message",
22772277
"code": 6011
22782278
},
2279-
"Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES2015' (experimental)": {
2279+
"Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES2015'": {
22802280
"category": "Message",
22812281
"code": 6015
22822282
},
@@ -2364,14 +2364,10 @@
23642364
"category": "Error",
23652365
"code": 6045
23662366
},
2367-
"Argument for '--module' option must be 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'none'.": {
2367+
"Argument for '{0}' option must be: {1}": {
23682368
"category": "Error",
23692369
"code": 6046
23702370
},
2371-
"Argument for '--target' option must be 'ES3', 'ES5', or 'ES2015'.": {
2372-
"category": "Error",
2373-
"code": 6047
2374-
},
23752371
"Locale must be of the form <language> or <language>-<territory>. For example '{0}' or '{1}'.": {
23762372
"category": "Error",
23772373
"code": 6048
@@ -2408,30 +2404,22 @@
24082404
"category": "Message",
24092405
"code": 6056
24102406
},
2411-
"Specifies the root directory of input files. Use to control the output directory structure with --outDir.": {
2407+
"Specify the root directory of input files. Use to control the output directory structure with --outDir.": {
24122408
"category": "Message",
24132409
"code": 6058
24142410
},
24152411
"File '{0}' is not under 'rootDir' '{1}'. 'rootDir' is expected to contain all source files.": {
24162412
"category": "Error",
24172413
"code": 6059
24182414
},
2419-
"Specifies the end of line sequence to be used when emitting files: 'CRLF' (dos) or 'LF' (unix).": {
2415+
"Specify the end of line sequence to be used when emitting files: 'CRLF' (dos) or 'LF' (unix).": {
24202416
"category": "Message",
24212417
"code": 6060
24222418
},
24232419
"NEWLINE": {
24242420
"category": "Message",
24252421
"code": 6061
24262422
},
2427-
"Argument for '--newLine' option must be 'CRLF' or 'LF'.": {
2428-
"category": "Error",
2429-
"code": 6062
2430-
},
2431-
"Argument for '--moduleResolution' option must be 'node' or 'classic'.": {
2432-
"category": "Error",
2433-
"code": 6063
2434-
},
24352423
"Option '{0}' can only be specified in 'tsconfig.json' file.": {
24362424
"category": "Error",
24372425
"code": 6064
@@ -2448,7 +2436,7 @@
24482436
"category": "Message",
24492437
"code": 6068
24502438
},
2451-
"Specifies module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6).": {
2439+
"Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6).": {
24522440
"category": "Message",
24532441
"code": 6069
24542442
},
@@ -2492,10 +2480,6 @@
24922480
"category": "Message",
24932481
"code": 6080
24942482
},
2495-
"Argument for '--jsx' must be 'preserve' or 'react'.": {
2496-
"category": "Message",
2497-
"code": 6081
2498-
},
24992483
"Only 'amd' and 'system' modules are supported alongside --{0}.": {
25002484
"category": "Error",
25012485
"code": 6082
@@ -2504,7 +2488,7 @@
25042488
"category": "Message",
25052489
"code": 6083
25062490
},
2507-
"Specifies the object invoked for createElement and __spread when targeting 'react' JSX emit": {
2491+
"Specify the object invoked for createElement and __spread when targeting 'react' JSX emit": {
25082492
"category": "Message",
25092493
"code": 6084
25102494
},
@@ -2620,7 +2604,6 @@
26202604
"category": "Message",
26212605
"code": 6112
26222606
},
2623-
26242607
"Variable '{0}' implicitly has an '{1}' type.": {
26252608
"category": "Error",
26262609
"code": 7005

src/compiler/types.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2381,6 +2381,8 @@ namespace ts {
23812381
export type PathSubstitutions = Map<string[]>;
23822382
export type TsConfigOnlyOptions = RootPaths | PathSubstitutions;
23832383

2384+
export type CompilerOptionsValue = string | number | boolean | (string | number)[] | TsConfigOnlyOptions;
2385+
23842386
export interface CompilerOptions {
23852387
allowNonTsExtensions?: boolean;
23862388
charset?: string;
@@ -2437,14 +2439,17 @@ namespace ts {
24372439
allowSyntheticDefaultImports?: boolean;
24382440
allowJs?: boolean;
24392441
noImplicitUseStrict?: boolean;
2442+
lib?: string[];
24402443
/* @internal */ stripInternal?: boolean;
24412444

24422445
// Skip checking lib.d.ts to help speed up tests.
24432446
/* @internal */ skipDefaultLibCheck?: boolean;
24442447
// Do not perform validation of output file name in transpile scenarios
24452448
/* @internal */ suppressOutputPathCheck?: boolean;
24462449

2447-
[option: string]: string | number | boolean | TsConfigOnlyOptions;
2450+
list?: string[];
2451+
2452+
[option: string]: CompilerOptionsValue;
24482453
}
24492454

24502455
export interface TypingOptions {
@@ -2529,7 +2534,7 @@ namespace ts {
25292534
/* @internal */
25302535
export interface CommandLineOptionBase {
25312536
name: string;
2532-
type: "string" | "number" | "boolean" | "object" | Map<number>; // a value of a primitive type, or an object literal mapping named values to actual values
2537+
type: "string" | "number" | "boolean" | "object" | "list" | Map<number | string>; // a value of a primitive type, or an object literal mapping named values to actual values
25332538
isFilePath?: boolean; // True if option value is a path or fileName
25342539
shortName?: string; // A short mnemonic for convenience - for instance, 'h' can be used in place of 'help'
25352540
description?: DiagnosticMessage; // The message describing what the command line switch does
@@ -2545,8 +2550,7 @@ namespace ts {
25452550

25462551
/* @internal */
25472552
export interface CommandLineOptionOfCustomType extends CommandLineOptionBase {
2548-
type: Map<number>; // an object literal mapping named values to actual values
2549-
error: DiagnosticMessage; // The error given when the argument does not fit a customized 'type'
2553+
type: Map<number | string>; // an object literal mapping named values to actual values
25502554
}
25512555

25522556
/* @internal */
@@ -2555,7 +2559,13 @@ namespace ts {
25552559
}
25562560

25572561
/* @internal */
2558-
export type CommandLineOption = CommandLineOptionOfCustomType | CommandLineOptionOfPrimitiveType | TsConfigOnlyOption;
2562+
export interface CommandLineOptionOfListType extends CommandLineOptionBase {
2563+
type: "list";
2564+
element: CommandLineOptionOfCustomType | CommandLineOptionOfPrimitiveType;
2565+
}
2566+
2567+
/* @internal */
2568+
export type CommandLineOption = CommandLineOptionOfCustomType | CommandLineOptionOfPrimitiveType | TsConfigOnlyOption | CommandLineOptionOfListType;
25592569

25602570
/* @internal */
25612571
export const enum CharacterCodes {
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/// <reference path="..\..\..\src\harness\harness.ts" />
2+
/// <reference path="..\..\..\src\compiler\commandLineParser.ts" />
3+
4+
namespace ts {
5+
describe('parseCommandLine', () => {
6+
7+
function assertParseResult(commandLine: string[], expectedParsedCommandLine: ts.ParsedCommandLine) {
8+
const parsed = ts.parseCommandLine(commandLine);
9+
const parsedCompilerOptions = JSON.stringify(parsed.options);
10+
const expectedCompilerOptions = JSON.stringify(expectedParsedCommandLine.options);
11+
assert.equal(parsedCompilerOptions, expectedCompilerOptions);
12+
13+
const parsedErrors = parsed.errors;
14+
const expectedErrors = expectedParsedCommandLine.errors;
15+
assert.isTrue(parsedErrors.length === expectedErrors.length, `Expected error: ${JSON.stringify(expectedErrors)}. Actual error: ${JSON.stringify(parsedErrors)}.`);
16+
for (let i = 0; i < parsedErrors.length; ++i) {
17+
const parsedError = parsedErrors[i];
18+
const expectedError = expectedErrors[i];
19+
assert.equal(parsedError.code, expectedError.code);
20+
assert.equal(parsedError.category, expectedError.category);
21+
assert.equal(parsedError.messageText, expectedError.messageText);
22+
}
23+
24+
const parsedFileNames = parsed.fileNames;
25+
const expectedFileNames = expectedParsedCommandLine.fileNames;
26+
assert.isTrue(parsedFileNames.length === expectedFileNames.length, `Expected fileNames: [${JSON.stringify(expectedFileNames)}]. Actual fileNames: [${JSON.stringify(parsedFileNames)}].`);
27+
for (let i = 0; i < parsedFileNames.length; ++i) {
28+
const parsedFileName = parsedFileNames[i];
29+
const expectedFileName = expectedFileNames[i];
30+
assert.equal(parsedFileName, expectedFileName);
31+
}
32+
}
33+
34+
it("Parse empty options of --jsx ", () => {
35+
// 0.ts --jsx
36+
assertParseResult(["0.ts", "--jsx"],
37+
{
38+
errors: [{
39+
messageText: "Compiler option 'jsx' expects an argument.",
40+
category: ts.Diagnostics.Compiler_option_0_expects_an_argument.category,
41+
code: ts.Diagnostics.Compiler_option_0_expects_an_argument.code,
42+
43+
file: undefined,
44+
start: undefined,
45+
length: undefined,
46+
}, {
47+
messageText: "Argument for '--jsx' option must be: 'preserve', 'react'",
48+
category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
49+
code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
50+
51+
file: undefined,
52+
start: undefined,
53+
length: undefined,
54+
}],
55+
fileNames: ["0.ts"],
56+
options: {}
57+
});
58+
});
59+
60+
it("Parse empty options of --module ", () => {
61+
// 0.ts --
62+
assertParseResult(["0.ts", "--module"],
63+
{
64+
errors: [{
65+
messageText: "Compiler option 'module' expects an argument.",
66+
category: ts.Diagnostics.Compiler_option_0_expects_an_argument.category,
67+
code: ts.Diagnostics.Compiler_option_0_expects_an_argument.code,
68+
69+
file: undefined,
70+
start: undefined,
71+
length: undefined,
72+
}, {
73+
messageText: "Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015'",
74+
category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
75+
code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
76+
77+
file: undefined,
78+
start: undefined,
79+
length: undefined,
80+
}],
81+
fileNames: ["0.ts"],
82+
options: {}
83+
});
84+
});
85+
86+
it("Parse empty options of --newLine ", () => {
87+
// 0.ts --newLine
88+
assertParseResult(["0.ts", "--newLine"],
89+
{
90+
errors: [{
91+
messageText: "Compiler option 'newLine' expects an argument.",
92+
category: ts.Diagnostics.Compiler_option_0_expects_an_argument.category,
93+
code: ts.Diagnostics.Compiler_option_0_expects_an_argument.code,
94+
95+
file: undefined,
96+
start: undefined,
97+
length: undefined,
98+
}, {
99+
messageText: "Argument for '--newLine' option must be: 'crlf', 'lf'",
100+
category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
101+
code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
102+
103+
file: undefined,
104+
start: undefined,
105+
length: undefined,
106+
}],
107+
fileNames: ["0.ts"],
108+
options: {}
109+
});
110+
});
111+
112+
it("Parse empty options of --target ", () => {
113+
// 0.ts --target
114+
assertParseResult(["0.ts", "--target"],
115+
{
116+
errors: [{
117+
messageText: "Compiler option 'target' expects an argument.",
118+
category: ts.Diagnostics.Compiler_option_0_expects_an_argument.category,
119+
code: ts.Diagnostics.Compiler_option_0_expects_an_argument.code,
120+
121+
file: undefined,
122+
start: undefined,
123+
length: undefined,
124+
}, {
125+
messageText: "Argument for '--target' option must be: 'es3', 'es5', 'es6', 'es2015'",
126+
category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
127+
code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
128+
129+
file: undefined,
130+
start: undefined,
131+
length: undefined,
132+
}],
133+
fileNames: ["0.ts"],
134+
options: {}
135+
});
136+
});
137+
138+
it("Parse empty options of --moduleResolution ", () => {
139+
// 0.ts --moduleResolution
140+
assertParseResult(["0.ts", "--moduleResolution"],
141+
{
142+
errors: [{
143+
messageText: "Compiler option 'moduleResolution' expects an argument.",
144+
category: ts.Diagnostics.Compiler_option_0_expects_an_argument.category,
145+
code: ts.Diagnostics.Compiler_option_0_expects_an_argument.code,
146+
147+
file: undefined,
148+
start: undefined,
149+
length: undefined,
150+
}, {
151+
messageText: "Argument for '--moduleResolution' option must be: 'node', 'classic'",
152+
category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
153+
code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
154+
155+
file: undefined,
156+
start: undefined,
157+
length: undefined,
158+
}],
159+
fileNames: ["0.ts"],
160+
options: {}
161+
});
162+
});
163+
164+
it("Parse multiple compiler flags with input files at the end", () => {
165+
// --module commonjs --target es5 0.ts
166+
assertParseResult(["--module", "commonjs", "--target", "es5", "0.ts"],
167+
{
168+
errors: [],
169+
fileNames: ["0.ts"],
170+
options: {
171+
module: ts.ModuleKind.CommonJS,
172+
target: ts.ScriptTarget.ES5,
173+
}
174+
});
175+
});
176+
177+
it("Parse multiple compiler flags with input files in the middle", () => {
178+
// --module commonjs --target es5 0.ts --noImplicitAny
179+
assertParseResult(["--module", "commonjs", "--target", "es5", "0.ts", "--noImplicitAny"],
180+
{
181+
errors: [],
182+
fileNames: ["0.ts"],
183+
options: {
184+
module: ts.ModuleKind.CommonJS,
185+
target: ts.ScriptTarget.ES5,
186+
noImplicitAny: true,
187+
}
188+
});
189+
});
190+
});
191+
}

0 commit comments

Comments
 (0)