• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    describe("unittests:: config:: convertCompilerOptionsFromJson", () => {
3        const formatDiagnosticHost: FormatDiagnosticsHost = {
4            getCurrentDirectory: () => "/apath/",
5            getCanonicalFileName: createGetCanonicalFileName(/*useCaseSensitiveFileNames*/ true),
6            getNewLine: () => "\n"
7        };
8
9        interface ExpectedResultWithParsingSuccess {
10            compilerOptions: CompilerOptions;
11            errors: readonly Diagnostic[];
12        }
13
14        interface ExpectedResultWithParsingFailure {
15            compilerOptions: CompilerOptions;
16            hasParseErrors: true;
17        }
18
19        type ExpectedResult = ExpectedResultWithParsingSuccess | ExpectedResultWithParsingFailure;
20
21        function isExpectedResultWithParsingFailure(expectedResult: ExpectedResult): expectedResult is ExpectedResultWithParsingFailure {
22            return !!(expectedResult as ExpectedResultWithParsingFailure).hasParseErrors;
23        }
24
25        function assertCompilerOptions(json: any, configFileName: string, expectedResult: ExpectedResultWithParsingSuccess) {
26            assertCompilerOptionsWithJson(json, configFileName, expectedResult);
27            assertCompilerOptionsWithJsonNode(json, configFileName, expectedResult);
28        }
29
30        function assertCompilerOptionsWithJson(json: any, configFileName: string, expectedResult: ExpectedResultWithParsingSuccess) {
31            const { options: actualCompilerOptions, errors: actualErrors } = convertCompilerOptionsFromJson(json.compilerOptions, "/apath/", configFileName);
32
33            const parsedCompilerOptions = JSON.stringify(actualCompilerOptions);
34            const expectedCompilerOptions = JSON.stringify({ ...expectedResult.compilerOptions, configFilePath: configFileName });
35            assert.equal(parsedCompilerOptions, expectedCompilerOptions);
36
37            verifyErrors(actualErrors, expectedResult.errors, /*ignoreLocation*/ true);
38        }
39
40        function assertCompilerOptionsWithJsonNode(json: any, configFileName: string, expectedResult: ExpectedResultWithParsingSuccess) {
41            assertCompilerOptionsWithJsonText(JSON.stringify(json), configFileName, expectedResult);
42        }
43
44        function assertCompilerOptionsWithJsonText(fileText: string, configFileName: string, expectedResult: ExpectedResult) {
45            const result = parseJsonText(configFileName, fileText);
46            assert(!!result.endOfFileToken);
47            assert.equal(!!result.parseDiagnostics.length, isExpectedResultWithParsingFailure(expectedResult));
48            const host: ParseConfigHost = new fakes.ParseConfigHost(new vfs.FileSystem(/*ignoreCase*/ false, { cwd: "/apath/" }));
49            const { options: actualCompilerOptions, errors: actualParseErrors } = parseJsonSourceFileConfigFileContent(result, host, "/apath/", /*existingOptions*/ undefined, configFileName);
50            expectedResult.compilerOptions.configFilePath = configFileName;
51
52            const parsedCompilerOptions = JSON.stringify(actualCompilerOptions);
53            const expectedCompilerOptions = JSON.stringify(expectedResult.compilerOptions);
54            assert.equal(parsedCompilerOptions, expectedCompilerOptions);
55            assert.equal(actualCompilerOptions.configFile, result);
56
57            if (!isExpectedResultWithParsingFailure(expectedResult)) {
58                verifyErrors(actualParseErrors.filter(error => error.code !== Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code), expectedResult.errors);
59            }
60        }
61
62        function verifyErrors(actualErrors: Diagnostic[], expectedErrors: readonly Diagnostic[], ignoreLocation?: boolean) {
63            assert.isTrue(expectedErrors.length === actualErrors.length, `Expected error: ${JSON.stringify(expectedErrors.map(getDiagnosticString), undefined, " ")}. Actual error: ${JSON.stringify(actualErrors.map(getDiagnosticString), undefined, " ")}.`);
64            for (let i = 0; i < actualErrors.length; i++) {
65                const actualError = actualErrors[i];
66                const expectedError = expectedErrors[i];
67
68                assert.equal(actualError.code, expectedError.code, `Expected error-code: ${JSON.stringify(expectedError.code)}. Actual error-code: ${JSON.stringify(actualError.code)}.`);
69                assert.equal(actualError.category, expectedError.category, `Expected error-category: ${JSON.stringify(expectedError.category)}. Actual error-category: ${JSON.stringify(actualError.category)}.`);
70                if (!ignoreLocation) {
71                    assert(actualError.file);
72                    assert(actualError.start);
73                    assert(actualError.length);
74                }
75            }
76
77            function getDiagnosticString(diagnostic: Diagnostic) {
78                if (ignoreLocation) {
79                    const { file, ...rest } = diagnostic;
80                    diagnostic = { file: undefined, ...rest };
81                }
82                return formatDiagnostic(diagnostic, formatDiagnosticHost);
83            }
84        }
85
86        // tsconfig.json tests
87        it("Convert correctly format tsconfig.json to compiler-options ", () => {
88            assertCompilerOptions(
89                {
90                    compilerOptions: {
91                        module: "commonjs",
92                        target: "es5",
93                        noImplicitAny: false,
94                        sourceMap: false,
95                        lib: ["es5", "es2015.core", "es2015.symbol"]
96                    }
97                }, "tsconfig.json",
98                {
99                    compilerOptions: {
100                        module: ModuleKind.CommonJS,
101                        target: ScriptTarget.ES5,
102                        noImplicitAny: false,
103                        sourceMap: false,
104                        lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
105                    },
106                    errors: []
107                }
108            );
109        });
110
111        it("Convert correctly format tsconfig.json with allowJs is false to compiler-options ", () => {
112            assertCompilerOptions(
113                {
114                    compilerOptions: {
115                        module: "commonjs",
116                        target: "es5",
117                        noImplicitAny: false,
118                        sourceMap: false,
119                        allowJs: false,
120                        lib: ["es5", "es2015.core", "es2015.symbol"]
121                    }
122                }, "tsconfig.json",
123                {
124                    compilerOptions: {
125                        module: ModuleKind.CommonJS,
126                        target: ScriptTarget.ES5,
127                        noImplicitAny: false,
128                        sourceMap: false,
129                        allowJs: false,
130                        lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
131                    },
132                    errors: []
133                }
134            );
135        });
136
137        it("Convert incorrect option of jsx to compiler-options ", () => {
138            assertCompilerOptions(
139                {
140                    compilerOptions: {
141                        module: "commonjs",
142                        target: "es5",
143                        noImplicitAny: false,
144                        sourceMap: false,
145                        jsx: ""
146                    }
147                }, "tsconfig.json",
148                {
149                    compilerOptions: {
150                        module: ModuleKind.CommonJS,
151                        target: ScriptTarget.ES5,
152                        noImplicitAny: false,
153                        sourceMap: false,
154                    },
155                    errors: [{
156                        file: undefined,
157                        start: 0,
158                        length: 0,
159                        messageText: "Argument for '--jsx' option must be: 'preserve', 'react-native', 'react'.",
160                        code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
161                        category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
162                    }]
163                }
164            );
165        });
166
167        it("Convert incorrect option of module to compiler-options ", () => {
168            assertCompilerOptions(
169                {
170                    compilerOptions: {
171                        module: "",
172                        target: "es5",
173                        noImplicitAny: false,
174                        sourceMap: false,
175                    }
176                }, "tsconfig.json",
177                {
178                    compilerOptions: {
179                        target: ScriptTarget.ES5,
180                        noImplicitAny: false,
181                        sourceMap: false,
182                    },
183                    errors: [{
184                        file: undefined,
185                        start: 0,
186                        length: 0,
187                        messageText: "Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'esnext'.",
188                        code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
189                        category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
190                    }]
191                }
192            );
193        });
194
195        it("Convert incorrect option of newLine to compiler-options ", () => {
196            assertCompilerOptions(
197                {
198                    compilerOptions: {
199                        newLine: "",
200                        target: "es5",
201                        noImplicitAny: false,
202                        sourceMap: false,
203                    }
204                }, "tsconfig.json",
205                {
206                    compilerOptions: {
207                        target: ScriptTarget.ES5,
208                        noImplicitAny: false,
209                        sourceMap: false,
210                    },
211                    errors: [{
212                        file: undefined,
213                        start: 0,
214                        length: 0,
215                        messageText: "Argument for '--newLine' option must be: 'crlf', 'lf'.",
216                        code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
217                        category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
218                    }]
219                }
220            );
221        });
222
223        it("Convert incorrect option of target to compiler-options ", () => {
224            assertCompilerOptions(
225                {
226                    compilerOptions: {
227                        target: "",
228                        noImplicitAny: false,
229                        sourceMap: false,
230                    }
231                }, "tsconfig.json",
232                {
233                    compilerOptions: {
234                        noImplicitAny: false,
235                        sourceMap: false,
236                    },
237                    errors: [{
238                        file: undefined,
239                        start: 0,
240                        length: 0,
241                        messageText: "Argument for '--target' option must be: 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'esnext'.",
242                        code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
243                        category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
244                    }]
245                }
246            );
247        });
248
249        it("Convert incorrect option of module-resolution to compiler-options ", () => {
250            assertCompilerOptions(
251                {
252                    compilerOptions: {
253                        moduleResolution: "",
254                        noImplicitAny: false,
255                        sourceMap: false,
256                    }
257                }, "tsconfig.json",
258                {
259                    compilerOptions: {
260                        noImplicitAny: false,
261                        sourceMap: false,
262                    },
263                    errors: [{
264                        file: undefined,
265                        start: 0,
266                        length: 0,
267                        messageText: "Argument for '--moduleResolution' option must be: 'node', 'classic'.",
268                        code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
269                        category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
270                    }]
271                }
272            );
273        });
274
275        it("Convert incorrect option of libs to compiler-options ", () => {
276            assertCompilerOptions(
277                {
278                    compilerOptions: {
279                        module: "commonjs",
280                        target: "es5",
281                        noImplicitAny: false,
282                        sourceMap: false,
283                        lib: ["es5", "es2015.core", "incorrectLib"]
284                    }
285                }, "tsconfig.json",
286                {
287                    compilerOptions: {
288                        module: ModuleKind.CommonJS,
289                        target: ScriptTarget.ES5,
290                        noImplicitAny: false,
291                        sourceMap: false,
292                        lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts"]
293                    },
294                    errors: [{
295                        file: undefined,
296                        start: 0,
297                        length: 0,
298                        messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint', 'esnext.bigint', 'esnext.string', 'esnext.promise'.",
299                        code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
300                        category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
301                    }]
302                }
303            );
304        });
305
306        it("Convert empty string option of libs to compiler-options ", () => {
307            assertCompilerOptions(
308                {
309                    compilerOptions: {
310                        module: "commonjs",
311                        target: "es5",
312                        noImplicitAny: false,
313                        sourceMap: false,
314                        lib: ["es5", ""]
315                    }
316                }, "tsconfig.json",
317                {
318                    compilerOptions: {
319                        module: ModuleKind.CommonJS,
320                        target: ScriptTarget.ES5,
321                        noImplicitAny: false,
322                        sourceMap: false,
323                        lib: ["lib.es5.d.ts"]
324                    },
325                    errors: [{
326                        file: undefined,
327                        start: 0,
328                        length: 0,
329                        messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise'.",
330                        code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
331                        category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
332                    }]
333                }
334            );
335        });
336
337        it("Convert empty string option of libs to compiler-options ", () => {
338            assertCompilerOptions(
339                {
340                    compilerOptions: {
341                        module: "commonjs",
342                        target: "es5",
343                        noImplicitAny: false,
344                        sourceMap: false,
345                        lib: [""]
346                    }
347                }, "tsconfig.json",
348                {
349                    compilerOptions: {
350                        module: ModuleKind.CommonJS,
351                        target: ScriptTarget.ES5,
352                        noImplicitAny: false,
353                        sourceMap: false,
354                        lib: []
355                    },
356                    errors: [{
357                        file: undefined,
358                        start: 0,
359                        length: 0,
360                        messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise'.",
361                        code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
362                        category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
363                    }]
364                }
365            );
366        });
367
368        it("Convert trailing-whitespace string option of libs to compiler-options ", () => {
369            assertCompilerOptions(
370                {
371                    compilerOptions: {
372                        module: "commonjs",
373                        target: "es5",
374                        noImplicitAny: false,
375                        sourceMap: false,
376                        lib: ["   "]
377                    }
378                }, "tsconfig.json",
379                {
380                    compilerOptions: {
381                        module: ModuleKind.CommonJS,
382                        target: ScriptTarget.ES5,
383                        noImplicitAny: false,
384                        sourceMap: false,
385                        lib: []
386                    },
387                    errors: [{
388                        file: undefined,
389                        start: 0,
390                        length: 0,
391                        messageText: "Argument for '--lib' option must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'esnext.array', 'esnext.symbol', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise'.",
392                        code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
393                        category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
394                    }]
395                }
396            );
397        });
398
399        it("Convert empty option of libs to compiler-options ", () => {
400            assertCompilerOptions(
401                {
402                    compilerOptions: {
403                        module: "commonjs",
404                        target: "es5",
405                        noImplicitAny: false,
406                        sourceMap: false,
407                        lib: []
408                    }
409                }, "tsconfig.json",
410                {
411                    compilerOptions: {
412                        module: ModuleKind.CommonJS,
413                        target: ScriptTarget.ES5,
414                        noImplicitAny: false,
415                        sourceMap: false,
416                        lib: []
417                    },
418                    errors: []
419                }
420            );
421        });
422
423        it("Convert incorrectly format tsconfig.json to compiler-options ", () => {
424            assertCompilerOptions(
425                {
426                    compilerOptions: {
427                        modu: "commonjs",
428                    }
429                }, "tsconfig.json",
430                {
431                    compilerOptions: {},
432                    errors: [{
433                        file: undefined,
434                        start: 0,
435                        length: 0,
436                        messageText: "Unknown compiler option 'modu'.",
437                        code: Diagnostics.Unknown_compiler_option_0.code,
438                        category: Diagnostics.Unknown_compiler_option_0.category
439                    }]
440                }
441            );
442        });
443
444        it("Convert default tsconfig.json to compiler-options ", () => {
445            assertCompilerOptions({}, "tsconfig.json",
446                {
447                    compilerOptions: {},
448                    errors: []
449                }
450            );
451        });
452
453        it("Convert negative numbers in tsconfig.json ", () => {
454            assertCompilerOptions(
455                {
456                    compilerOptions: {
457                        allowJs: true,
458                        maxNodeModuleJsDepth: -1
459                    }
460                }, "tsconfig.json",
461                {
462                    compilerOptions: {
463                        allowJs: true,
464                        maxNodeModuleJsDepth: -1
465                    },
466                    errors: []
467                }
468            );
469        });
470
471        // jsconfig.json
472        it("Convert correctly format jsconfig.json to compiler-options ", () => {
473            assertCompilerOptions(
474                {
475                    compilerOptions: {
476                        module: "commonjs",
477                        target: "es5",
478                        noImplicitAny: false,
479                        sourceMap: false,
480                        lib: ["es5", "es2015.core", "es2015.symbol"]
481                    }
482                }, "jsconfig.json",
483                {
484                    compilerOptions: {
485                        allowJs: true,
486                        maxNodeModuleJsDepth: 2,
487                        allowSyntheticDefaultImports: true,
488                        skipLibCheck: true,
489                        noEmit: true,
490                        module: ModuleKind.CommonJS,
491                        target: ScriptTarget.ES5,
492                        noImplicitAny: false,
493                        sourceMap: false,
494                        lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
495                    },
496                    errors: []
497                }
498            );
499        });
500
501        it("Convert correctly format jsconfig.json with allowJs is false to compiler-options ", () => {
502            assertCompilerOptions(
503                {
504                    compilerOptions: {
505                        module: "commonjs",
506                        target: "es5",
507                        noImplicitAny: false,
508                        sourceMap: false,
509                        allowJs: false,
510                        lib: ["es5", "es2015.core", "es2015.symbol"]
511                    }
512                }, "jsconfig.json",
513                {
514                    compilerOptions: {
515                        allowJs: false,
516                        maxNodeModuleJsDepth: 2,
517                        allowSyntheticDefaultImports: true,
518                        skipLibCheck: true,
519                        noEmit: true,
520                        module: ModuleKind.CommonJS,
521                        target: ScriptTarget.ES5,
522                        noImplicitAny: false,
523                        sourceMap: false,
524                        lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
525                    },
526                    errors: []
527                }
528            );
529        });
530
531        it("Convert incorrectly format jsconfig.json to compiler-options ", () => {
532            assertCompilerOptions(
533                {
534                    compilerOptions: {
535                        modu: "commonjs",
536                    }
537                }, "jsconfig.json",
538                {
539                    compilerOptions:
540                    {
541                        allowJs: true,
542                        maxNodeModuleJsDepth: 2,
543                        allowSyntheticDefaultImports: true,
544                        skipLibCheck: true,
545                        noEmit: true
546                    },
547                    errors: [{
548                        file: undefined,
549                        start: 0,
550                        length: 0,
551                        messageText: "Unknown compiler option 'modu'.",
552                        code: Diagnostics.Unknown_compiler_option_0.code,
553                        category: Diagnostics.Unknown_compiler_option_0.category
554                    }]
555                }
556            );
557        });
558
559        it("Convert default jsconfig.json to compiler-options ", () => {
560            assertCompilerOptions({}, "jsconfig.json",
561                {
562                    compilerOptions:
563                    {
564                        allowJs: true,
565                        maxNodeModuleJsDepth: 2,
566                        allowSyntheticDefaultImports: true,
567                        skipLibCheck: true,
568                        noEmit: true
569                    },
570                    errors: []
571                }
572            );
573        });
574
575        it("Convert tsconfig options when there are multiple invalid strings", () => {
576            assertCompilerOptionsWithJsonText(`{
577  "compilerOptions": {
578    "target": "<%- options.useTsWithBabel ? 'esnext' : 'es5' %>",
579    "module": "esnext",
580    <%_ if (options.classComponent) { _%>
581    "experimentalDecorators": true,
582    <%_ } _%>
583    "sourceMap": true,
584    "types": [
585      "webpack-env"<% if (hasMocha || hasJest) { %>,<% } %>
586      <%_ if (hasMocha) { _%>
587      "mocha",
588      "chai"
589      <%_ } else if (hasJest) { _%>
590      "jest"
591      <%_ } _%>
592    ]
593  }
594}
595`,
596            "tsconfig.json",
597            {
598                compilerOptions: {
599                    target: undefined,
600                    module: ModuleKind.ESNext,
601                    experimentalDecorators: true,
602                },
603                hasParseErrors: true
604            });
605        });
606    });
607}
608