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.isDefined(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', 'es2020', 'es2022', '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 empty string option of moduleSuffixes to compiler-options ", () => { 424 assertCompilerOptions( 425 { 426 compilerOptions: { 427 moduleSuffixes: [".ios", ""] 428 } 429 }, "tsconfig.json", 430 { 431 compilerOptions: { 432 moduleSuffixes: [".ios", ""] 433 }, 434 errors: [] 435 } 436 ); 437 }); 438 439 it("Convert empty string option of moduleSuffixes to compiler-options ", () => { 440 assertCompilerOptions( 441 { 442 compilerOptions: { 443 moduleSuffixes: [""] 444 } 445 }, "tsconfig.json", 446 { 447 compilerOptions: { 448 moduleSuffixes: [""] 449 }, 450 errors: [] 451 } 452 ); 453 }); 454 455 it("Convert trailing-whitespace string option of moduleSuffixes to compiler-options ", () => { 456 assertCompilerOptions( 457 { 458 compilerOptions: { 459 moduleSuffixes: [" "] 460 } 461 }, "tsconfig.json", 462 { 463 compilerOptions: { 464 moduleSuffixes: [" "] 465 }, 466 errors: [] 467 } 468 ); 469 }); 470 471 it("Convert empty option of moduleSuffixes to compiler-options ", () => { 472 assertCompilerOptions( 473 { 474 compilerOptions: { 475 moduleSuffixes: [] 476 } 477 }, "tsconfig.json", 478 { 479 compilerOptions: { 480 moduleSuffixes: [] 481 }, 482 errors: [] 483 } 484 ); 485 }); 486 487 it("Convert incorrectly format tsconfig.json to compiler-options ", () => { 488 assertCompilerOptions( 489 { 490 compilerOptions: { 491 modu: "commonjs", 492 } 493 }, "tsconfig.json", 494 { 495 compilerOptions: {}, 496 errors: [{ 497 file: undefined, 498 start: 0, 499 length: 0, 500 messageText: "Unknown compiler option 'modu'.", 501 code: Diagnostics.Unknown_compiler_option_0.code, 502 category: Diagnostics.Unknown_compiler_option_0.category 503 }] 504 } 505 ); 506 }); 507 508 it("Convert default tsconfig.json to compiler-options ", () => { 509 assertCompilerOptions({}, "tsconfig.json", 510 { 511 compilerOptions: {}, 512 errors: [] 513 } 514 ); 515 }); 516 517 it("Convert negative numbers in tsconfig.json ", () => { 518 assertCompilerOptions( 519 { 520 compilerOptions: { 521 allowJs: true, 522 maxNodeModuleJsDepth: -1 523 } 524 }, "tsconfig.json", 525 { 526 compilerOptions: { 527 allowJs: true, 528 maxNodeModuleJsDepth: -1 529 }, 530 errors: [] 531 } 532 ); 533 }); 534 535 // jsconfig.json 536 it("Convert correctly format jsconfig.json to compiler-options ", () => { 537 assertCompilerOptions( 538 { 539 compilerOptions: { 540 module: "commonjs", 541 target: "es5", 542 noImplicitAny: false, 543 sourceMap: false, 544 lib: ["es5", "es2015.core", "es2015.symbol"] 545 } 546 }, "jsconfig.json", 547 { 548 compilerOptions: { 549 allowJs: true, 550 maxNodeModuleJsDepth: 2, 551 allowSyntheticDefaultImports: true, 552 skipLibCheck: true, 553 noEmit: true, 554 module: ModuleKind.CommonJS, 555 target: ScriptTarget.ES5, 556 noImplicitAny: false, 557 sourceMap: false, 558 lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"] 559 }, 560 errors: [] 561 } 562 ); 563 }); 564 565 it("Convert correctly format jsconfig.json with allowJs is false to compiler-options ", () => { 566 assertCompilerOptions( 567 { 568 compilerOptions: { 569 module: "commonjs", 570 target: "es5", 571 noImplicitAny: false, 572 sourceMap: false, 573 allowJs: false, 574 lib: ["es5", "es2015.core", "es2015.symbol"] 575 } 576 }, "jsconfig.json", 577 { 578 compilerOptions: { 579 allowJs: false, 580 maxNodeModuleJsDepth: 2, 581 allowSyntheticDefaultImports: true, 582 skipLibCheck: true, 583 noEmit: true, 584 module: ModuleKind.CommonJS, 585 target: ScriptTarget.ES5, 586 noImplicitAny: false, 587 sourceMap: false, 588 lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"] 589 }, 590 errors: [] 591 } 592 ); 593 }); 594 595 it("Convert incorrectly format jsconfig.json to compiler-options ", () => { 596 assertCompilerOptions( 597 { 598 compilerOptions: { 599 modu: "commonjs", 600 } 601 }, "jsconfig.json", 602 { 603 compilerOptions: 604 { 605 allowJs: true, 606 maxNodeModuleJsDepth: 2, 607 allowSyntheticDefaultImports: true, 608 skipLibCheck: true, 609 noEmit: true 610 }, 611 errors: [{ 612 file: undefined, 613 start: 0, 614 length: 0, 615 messageText: "Unknown compiler option 'modu'.", 616 code: Diagnostics.Unknown_compiler_option_0.code, 617 category: Diagnostics.Unknown_compiler_option_0.category 618 }] 619 } 620 ); 621 }); 622 623 it("Convert default jsconfig.json to compiler-options ", () => { 624 assertCompilerOptions({}, "jsconfig.json", 625 { 626 compilerOptions: 627 { 628 allowJs: true, 629 maxNodeModuleJsDepth: 2, 630 allowSyntheticDefaultImports: true, 631 skipLibCheck: true, 632 noEmit: true 633 }, 634 errors: [] 635 } 636 ); 637 }); 638 639 it("Convert tsconfig options when there are multiple invalid strings", () => { 640 assertCompilerOptionsWithJsonText(`{ 641 "compilerOptions": { 642 "target": "<%- options.useTsWithBabel ? 'esnext' : 'es5' %>", 643 "module": "esnext", 644 <%_ if (options.classComponent) { _%> 645 "experimentalDecorators": true, 646 <%_ } _%> 647 "sourceMap": true, 648 "types": [ 649 "webpack-env"<% if (hasMocha || hasJest) { %>,<% } %> 650 <%_ if (hasMocha) { _%> 651 "mocha", 652 "chai" 653 <%_ } else if (hasJest) { _%> 654 "jest" 655 <%_ } _%> 656 ] 657 } 658} 659`, 660 "tsconfig.json", 661 { 662 compilerOptions: { 663 target: undefined, 664 module: ModuleKind.ESNext, 665 experimentalDecorators: true, 666 }, 667 hasParseErrors: true 668 }); 669 }); 670 671 it("Convert a tsconfig file with stray trailing characters", () => { 672 assertCompilerOptionsWithJsonText(`{ 673 "compilerOptions": { 674 "target": "esnext" 675 } 676 } blah`, "tsconfig.json", { 677 compilerOptions: { 678 target: ScriptTarget.ESNext 679 }, 680 hasParseErrors: true, 681 errors: [{ 682 ...Diagnostics.The_root_value_of_a_0_file_must_be_an_object, 683 messageText: "The root value of a 'tsconfig.json' file must be an object.", 684 file: undefined, 685 start: 0, 686 length: 0 687 }] 688 }); 689 }); 690 691 it("Convert a tsconfig file with stray leading characters", () => { 692 assertCompilerOptionsWithJsonText(`blah { 693 "compilerOptions": { 694 "target": "esnext" 695 } 696 }`, "tsconfig.json", { 697 compilerOptions: { 698 target: ScriptTarget.ESNext 699 }, 700 hasParseErrors: true, 701 errors: [{ 702 ...Diagnostics.The_root_value_of_a_0_file_must_be_an_object, 703 messageText: "The root value of a 'tsconfig.json' file must be an object.", 704 file: undefined, 705 start: 0, 706 length: 0 707 }] 708 }); 709 }); 710 711 it("Convert a tsconfig file as an array", () => { 712 assertCompilerOptionsWithJsonText(`[{ 713 "compilerOptions": { 714 "target": "esnext" 715 } 716 }]`, "tsconfig.json", { 717 compilerOptions: { 718 target: ScriptTarget.ESNext 719 }, 720 errors: [{ 721 ...Diagnostics.The_root_value_of_a_0_file_must_be_an_object, 722 messageText: "The root value of a 'tsconfig.json' file must be an object.", 723 file: undefined, 724 start: 0, 725 length: 0 726 }] 727 }); 728 }); 729 730 it("raises an error if you've set a compiler flag in the root without including 'compilerOptions'", () => { 731 assertCompilerOptionsWithJsonText(`{ 732 "module": "esnext", 733 }`, "tsconfig.json", { 734 compilerOptions: {}, 735 errors: [{ 736 ...Diagnostics._0_should_be_set_inside_the_compilerOptions_object_of_the_config_json_file, 737 messageText: "'module' should be set inside the 'compilerOptions' object of the config json file.", 738 file: undefined, 739 start: 0, 740 length: 0 741 }] 742 }); 743 }); 744 745 it("does not raise an error if you've set a compiler flag in the root when you have included 'compilerOptions'", () => { 746 assertCompilerOptionsWithJsonText(`{ 747 "target": "esnext", 748 "compilerOptions": { 749 "module": "esnext" 750 } 751 }`, "tsconfig.json", { 752 compilerOptions: { 753 module: ModuleKind.ESNext 754 }, 755 errors: [] 756 }); 757 }); 758 759 it("Don't crash when root expression is not object at all", () => { 760 assertCompilerOptionsWithJsonText(`42`, "tsconfig.json", { 761 compilerOptions: {}, 762 errors: [{ 763 ...Diagnostics.The_root_value_of_a_0_file_must_be_an_object, 764 messageText: "The root value of a 'tsconfig.json' file must be an object.", 765 file: undefined, 766 start: 0, 767 length: 0 768 }] 769 }); 770 }); 771 772 it("Allow trailing comments", () => { 773 assertCompilerOptionsWithJsonText(`{} // no options`, "tsconfig.json", { 774 compilerOptions: {}, 775 errors: [] 776 }); 777 }); 778 }); 779} 780