• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    describe("unittests:: config:: commandLineParsing:: parseCommandLine", () => {
3        function assertParseResult(subScenario: string, commandLine: string[], workerDiagnostic?: () => ParseCommandLineWorkerDiagnostics) {
4            it(subScenario, () => {
5                const baseline: string[] = [];
6                baseline.push(commandLine.join(" "));
7                const parsed = parseCommandLineWorker(workerDiagnostic?.() || compilerOptionsDidYouMeanDiagnostics, commandLine);
8                baseline.push("CompilerOptions::");
9                baseline.push(JSON.stringify(parsed.options, /*replacer*/ undefined, " "));
10                baseline.push("WatchOptions::");
11                baseline.push(JSON.stringify(parsed.watchOptions, /*replacer*/ undefined, " "));
12                baseline.push("FileNames::");
13                baseline.push(parsed.fileNames.join());
14                baseline.push("Errors::");
15                baseline.push(formatDiagnostics(parsed.errors, {
16                    getCurrentDirectory: () => "/",
17                    getCanonicalFileName: identity,
18                    getNewLine: () => "\n",
19                }));
20                Harness.Baseline.runBaseline(`config/commandLineParsing/parseCommandLine/${subScenario}.js`, baseline.join("\n"));
21            });
22        }
23
24        // --lib es6 0.ts
25        assertParseResult("Parse single option of library flag", ["--lib", "es6", "0.ts"]);
26        assertParseResult("Handles may only be used with --build flags", ["--clean", "--dry", "--force", "--verbose"]);
27        // --declarations --allowTS
28        assertParseResult("Handles did you mean for misspelt flags", ["--declarations", "--allowTS"]);
29        // --lib es5,es2015.symbol.wellknown 0.ts
30        assertParseResult("Parse multiple options of library flags", ["--lib", "es5,es2015.symbol.wellknown", "0.ts"]);
31        // --lib es5,invalidOption 0.ts
32        assertParseResult("Parse invalid option of library flags", ["--lib", "es5,invalidOption", "0.ts"]);
33        // 0.ts --jsx
34        assertParseResult("Parse empty options of --jsx", ["0.ts", "--jsx"]);
35        // 0.ts --
36        assertParseResult("Parse empty options of --module", ["0.ts", "--module"]);
37        // 0.ts --newLine
38        assertParseResult("Parse empty options of --newLine", ["0.ts", "--newLine"]);
39        // 0.ts --target
40        assertParseResult("Parse empty options of --target", ["0.ts", "--target"]);
41        // 0.ts --moduleResolution
42        assertParseResult("Parse empty options of --moduleResolution", ["0.ts", "--moduleResolution"]);
43        // 0.ts --lib
44        assertParseResult("Parse empty options of --lib", ["0.ts", "--lib"]);
45        // 0.ts --lib
46        // This test is an error because the empty string is falsey
47        assertParseResult("Parse empty string of --lib", ["0.ts", "--lib", ""]);
48        // 0.ts --lib
49        assertParseResult("Parse immediately following command line argument of --lib", ["0.ts", "--lib", "--sourcemap"]);
50        // --lib es5, es7 0.ts
51        assertParseResult("Parse --lib option with extra comma", ["--lib", "es5,", "es7", "0.ts"]);
52        // --lib es5, es7 0.ts
53        assertParseResult("Parse --lib option with trailing white-space", ["--lib", "es5, ", "es7", "0.ts"]);
54        // --lib es5,es2015.symbol.wellknown --target es5 0.ts
55        assertParseResult("Parse multiple compiler flags with input files at the end", ["--lib", "es5,es2015.symbol.wellknown", "--target", "es5", "0.ts"]);
56        // --module commonjs --target es5 0.ts --lib es5,es2015.symbol.wellknown
57        assertParseResult("Parse multiple compiler flags with input files in the middle", ["--module", "commonjs", "--target", "es5", "0.ts", "--lib", "es5,es2015.symbol.wellknown"]);
58        // --module commonjs --target es5 --lib es5 0.ts --library es2015.array,es2015.symbol.wellknown
59        assertParseResult("Parse multiple library compiler flags ", ["--module", "commonjs", "--target", "es5", "--lib", "es5", "0.ts", "--lib", "es2015.core, es2015.symbol.wellknown "]);
60        assertParseResult("Parse explicit boolean flag value", ["--strictNullChecks", "false", "0.ts"]);
61        assertParseResult("Parse non boolean argument after boolean flag", ["--noImplicitAny", "t", "0.ts"]);
62        assertParseResult("Parse implicit boolean flag value", ["--strictNullChecks"]);
63        assertParseResult("parse --incremental", ["--incremental", "0.ts"]);
64        assertParseResult("parse --tsBuildInfoFile", ["--tsBuildInfoFile", "build.tsbuildinfo", "0.ts"]);
65
66        describe("parses command line null for tsconfig only option", () => {
67            interface VerifyNull {
68                subScenario: string,
69                optionName: string;
70                nonNullValue?: string;
71                workerDiagnostic?: () => ParseCommandLineWorkerDiagnostics;
72            }
73            function verifyNull({ subScenario, optionName, nonNullValue, workerDiagnostic }: VerifyNull) {
74                describe(subScenario, () => {
75                    assertParseResult(
76                        `${subScenario} allows setting it to null`,
77                        [`--${optionName}`, "null", "0.ts"],
78                        workerDiagnostic
79                    );
80                    if (nonNullValue) {
81                        assertParseResult(
82                            `${subScenario} errors if non null value is passed`,
83                            [`--${optionName}`, nonNullValue, "0.ts"],
84                            workerDiagnostic
85                        );
86                    }
87
88                    assertParseResult(
89                        `${subScenario} errors if its followed by another option`,
90                        ["0.ts", "--strictNullChecks", `--${optionName}`],
91                        workerDiagnostic
92                    );
93
94                    assertParseResult(
95                        `${subScenario} errors if its last option`,
96                        ["0.ts", `--${optionName}`],
97                        workerDiagnostic
98                    );
99                });
100            }
101
102            interface VerifyNullNonIncludedOption {
103                subScenario: string,
104                type: () => "string" | "number" | ESMap<string, number | string>;
105                nonNullValue?: string;
106            }
107            function verifyNullNonIncludedOption({ subScenario, type, nonNullValue }: VerifyNullNonIncludedOption) {
108                verifyNull({
109                    subScenario,
110                    optionName: "optionName",
111                    nonNullValue,
112                    workerDiagnostic: () => {
113                        const optionDeclarations: CommandLineOption[] = [
114                            ...compilerOptionsDidYouMeanDiagnostics.optionDeclarations,
115                            {
116                                name: "optionName",
117                                type: type(),
118                                isTSConfigOnly: true,
119                                category: Diagnostics.Backwards_Compatibility,
120                                description: Diagnostics.Enable_project_compilation,
121                                defaultValueDescription: undefined,
122                            }
123                        ];
124                        return {
125                            ...compilerOptionsDidYouMeanDiagnostics,
126                            optionDeclarations,
127                            getOptionsNameMap: () => createOptionNameMap(optionDeclarations)
128                        };
129                    }
130                });
131            }
132
133            describe("option of type boolean", () => {
134                assertParseResult(
135                    "allows setting option type boolean to false",
136                    ["--composite", "false", "0.ts"],
137                );
138
139                verifyNull({
140                    subScenario: "option of type boolean",
141                    optionName: "composite",
142                    nonNullValue: "true",
143                });
144            });
145
146            verifyNull({
147                subScenario: "option of type object",
148                optionName: "paths",
149            });
150
151            verifyNull({
152                subScenario: "option of type list",
153                optionName: "rootDirs",
154                nonNullValue: "abc,xyz",
155            });
156            verifyNullNonIncludedOption({
157                subScenario: "option of type string",
158                type: () => "string",
159                nonNullValue: "hello"
160            });
161
162            verifyNullNonIncludedOption({
163                subScenario: "option of type number",
164                type: () => "number",
165                nonNullValue: "10"
166            });
167
168            verifyNullNonIncludedOption({
169                subScenario: "option of type custom map",
170                type: () => new Map(getEntries({
171                    node: ModuleResolutionKind.NodeJs,
172                    classic: ModuleResolutionKind.Classic,
173                })),
174                nonNullValue: "node"
175            });
176        });
177
178        assertParseResult("allows tsconfig only option to be set to null", ["--composite", "null", "-tsBuildInfoFile", "null", "0.ts"]);
179
180        describe("Watch options", () => {
181            assertParseResult("parse --watchFile", ["--watchFile", "UseFsEvents", "0.ts"]);
182            assertParseResult("parse --watchDirectory", ["--watchDirectory", "FixedPollingInterval", "0.ts"]);
183            assertParseResult("parse --fallbackPolling", ["--fallbackPolling", "PriorityInterval", "0.ts"]);
184            assertParseResult("parse --synchronousWatchDirectory", ["--synchronousWatchDirectory", "0.ts"]);
185            assertParseResult("errors on missing argument to --fallbackPolling", ["0.ts", "--fallbackPolling"]);
186            assertParseResult("parse --excludeDirectories", ["--excludeDirectories", "**/temp", "0.ts"]);
187            assertParseResult("errors on invalid excludeDirectories", ["--excludeDirectories", "**/../*", "0.ts"]);
188            assertParseResult("parse --excludeFiles", ["--excludeFiles", "**/temp/*.ts", "0.ts"]);
189            assertParseResult("errors on invalid excludeFiles", ["--excludeFiles", "**/../*", "0.ts"]);
190        });
191    });
192
193    describe("unittests:: config:: commandLineParsing:: parseBuildOptions", () => {
194        function assertParseResult(subScenario: string, commandLine: string[]) {
195            it(subScenario, () => {
196                const baseline: string[] = [];
197                baseline.push(commandLine.join(" "));
198                const parsed = parseBuildCommand(commandLine);
199                baseline.push("buildOptions::");
200                baseline.push(JSON.stringify(parsed.buildOptions, /*replacer*/ undefined, " "));
201                baseline.push("WatchOptions::");
202                baseline.push(JSON.stringify(parsed.watchOptions, /*replacer*/ undefined, " "));
203                baseline.push("Projects::");
204                baseline.push(parsed.projects.join());
205                baseline.push("Errors::");
206                baseline.push(formatDiagnostics(parsed.errors, {
207                    getCurrentDirectory: () => "/",
208                    getCanonicalFileName: identity,
209                    getNewLine: () => "\n",
210                }));
211                Harness.Baseline.runBaseline(`config/commandLineParsing/parseBuildOptions/${subScenario}.js`, baseline.join("\n"));
212            });
213        }
214        assertParseResult("parse build without any options ", []);
215        assertParseResult("Parse multiple options", ["--verbose", "--force", "tests"]);
216        assertParseResult("Parse option with invalid option", ["--verbose", "--invalidOption"]);
217        assertParseResult("Parse multiple flags with input projects at the end", ["--force", "--verbose", "src", "tests"]);
218        assertParseResult("Parse multiple flags with input projects in the middle", ["--force", "src", "tests", "--verbose"]);
219        assertParseResult("Parse multiple flags with input projects in the beginning", ["src", "tests", "--force", "--verbose"]);
220        assertParseResult("parse build with --incremental", ["--incremental", "tests"]);
221        assertParseResult("parse build with --locale en-us", ["--locale", "en-us", "src"]);
222        assertParseResult("parse build with --tsBuildInfoFile", ["--tsBuildInfoFile", "build.tsbuildinfo", "tests"]);
223        assertParseResult("reports other common may not be used with --build flags", ["--declaration", "--strict"]);
224
225        describe("Combining options that make no sense together", () => {
226            function verifyInvalidCombination(flag1: keyof BuildOptions, flag2: keyof BuildOptions) {
227                assertParseResult(`--${flag1} and --${flag2} together is invalid`, [`--${flag1}`, `--${flag2}`]);
228            }
229            verifyInvalidCombination("clean", "force");
230            verifyInvalidCombination("clean", "verbose");
231            verifyInvalidCombination("clean", "watch");
232            verifyInvalidCombination("watch", "dry");
233        });
234
235        describe("Watch options", () => {
236            assertParseResult("parse --watchFile", ["--watchFile", "UseFsEvents", "--verbose"]);
237            assertParseResult("parse --watchDirectory", ["--watchDirectory", "FixedPollingInterval", "--verbose"]);
238            assertParseResult("parse --fallbackPolling", ["--fallbackPolling", "PriorityInterval", "--verbose"]);
239            assertParseResult("parse --synchronousWatchDirectory", ["--synchronousWatchDirectory", "--verbose"]);
240            assertParseResult("errors on missing argument", ["--verbose", "--fallbackPolling"]);
241            assertParseResult("errors on invalid excludeDirectories", ["--excludeDirectories", "**/../*"]);
242            assertParseResult("parse --excludeFiles", ["--excludeFiles", "**/temp/*.ts"]);
243            assertParseResult("errors on invalid excludeFiles", ["--excludeFiles", "**/../*"]);
244        });
245    });
246}
247