1import { 2 AlternateModeDiagnostics, 3 append, 4 arrayFrom, 5 ArrayLiteralExpression, 6 arrayToMap, 7 assign, 8 BuildOptions, 9 changeExtension, 10 CharacterCodes, 11 combinePaths, 12 CommandLineOption, 13 CommandLineOptionOfCustomType, 14 CommandLineOptionOfListType, 15 CompilerOptions, 16 CompilerOptionsValue, 17 ConfigFileSpecs, 18 containsPath, 19 convertToRelativePath, 20 createCompilerDiagnostic, 21 createDiagnosticForNodeInSourceFile, 22 createGetCanonicalFileName, 23 Debug, 24 Diagnostic, 25 DiagnosticMessage, 26 Diagnostics, 27 DidYouMeanOptionsDiagnostics, 28 directorySeparator, 29 emptyArray, 30 endsWith, 31 ensureTrailingDirectorySeparator, 32 ESMap, 33 every, 34 Expression, 35 extend, 36 Extension, 37 FileExtensionInfo, 38 fileExtensionIs, 39 fileExtensionIsOneOf, 40 filter, 41 filterMutate, 42 find, 43 findIndex, 44 firstDefined, 45 flatten, 46 forEach, 47 forEachEntry, 48 getBaseFileName, 49 getDirectoryPath, 50 getEntries, 51 getFileMatcherPatterns, 52 getLocaleSpecificMessage, 53 getNormalizedAbsolutePath, 54 getRegexFromPattern, 55 getRegularExpressionForWildcard, 56 getRegularExpressionsForWildcards, 57 getRelativePathFromFile, 58 getSpellingSuggestion, 59 getSupportedExtensions, 60 getSupportedExtensionsWithJsonIfResolveJsonModule, 61 getTextOfPropertyName, 62 getTsConfigPropArray, 63 getTsConfigPropArrayElementValue, 64 hasExtension, 65 hasProperty, 66 ImportsNotUsedAsValues, 67 isArray, 68 isArrayLiteralExpression, 69 isComputedNonLiteralName, 70 isImplicitGlob, 71 isObjectLiteralExpression, 72 isRootedDiskPath, 73 isString, 74 isStringDoubleQuoted, 75 isStringLiteral, 76 JsonSourceFile, 77 JsxEmit, 78 length, 79 map, 80 Map, 81 mapDefined, 82 mapIterator, 83 MapLike, 84 ModuleDetectionKind, 85 ModuleKind, 86 ModuleResolutionKind, 87 NewLineKind, 88 Node, 89 NodeArray, 90 nodeModuleNameResolver, 91 normalizePath, 92 normalizeSlashes, 93 NumericLiteral, 94 ObjectLiteralExpression, 95 ParseConfigHost, 96 ParsedCommandLine, 97 parseJsonText, 98 Path, 99 PerformanceDotting, 100 PollingWatchKind, 101 PrefixUnaryExpression, 102 ProjectReference, 103 PropertyName, 104 Push, 105 removeTrailingDirectorySeparator, 106 returnTrue, 107 ScriptTarget, 108 startsWith, 109 StringLiteral, 110 SyntaxKind, 111 sys, 112 toFileNameLowerCase, 113 toPath, 114 tracing, 115 trimString, 116 TsConfigOnlyOption, 117 TsConfigSourceFile, 118 TypeAcquisition, 119 unescapeLeadingUnderscores, 120 WatchDirectoryFlags, 121 WatchDirectoryKind, 122 WatchFileKind, 123 WatchOptions, 124} from "./_namespaces/ts"; 125 126/** @internal */ 127export const compileOnSaveCommandLineOption: CommandLineOption = { 128 name: "compileOnSave", 129 type: "boolean", 130 defaultValueDescription: false, 131}; 132 133const jsxOptionMap = new Map(getEntries({ 134 "preserve": JsxEmit.Preserve, 135 "react-native": JsxEmit.ReactNative, 136 "react": JsxEmit.React, 137 "react-jsx": JsxEmit.ReactJSX, 138 "react-jsxdev": JsxEmit.ReactJSXDev, 139})); 140 141/** @internal */ 142export const inverseJsxOptionMap = new Map(arrayFrom(mapIterator(jsxOptionMap.entries(), ([key, value]: [string, JsxEmit]) => ["" + value, key] as const))); 143 144// NOTE: The order here is important to default lib ordering as entries will have the same 145// order in the generated program (see `getDefaultLibPriority` in program.ts). This 146// order also affects overload resolution when a type declared in one lib is 147// augmented in another lib. 148const libEntries: [string, string][] = [ 149 // JavaScript only 150 ["es5", "lib.es5.d.ts"], 151 ["es6", "lib.es2015.d.ts"], 152 ["es2015", "lib.es2015.d.ts"], 153 ["es7", "lib.es2016.d.ts"], 154 ["es2016", "lib.es2016.d.ts"], 155 ["es2017", "lib.es2017.d.ts"], 156 ["es2018", "lib.es2018.d.ts"], 157 ["es2019", "lib.es2019.d.ts"], 158 ["es2020", "lib.es2020.d.ts"], 159 ["es2021", "lib.es2021.d.ts"], 160 ["es2022", "lib.es2022.d.ts"], 161 ["esnext", "lib.esnext.d.ts"], 162 // Host only 163 ["dom", "lib.dom.d.ts"], 164 ["dom.iterable", "lib.dom.iterable.d.ts"], 165 ["webworker", "lib.webworker.d.ts"], 166 ["webworker.importscripts", "lib.webworker.importscripts.d.ts"], 167 ["webworker.iterable", "lib.webworker.iterable.d.ts"], 168 ["scripthost", "lib.scripthost.d.ts"], 169 // ES2015 Or ESNext By-feature options 170 ["es2015.core", "lib.es2015.core.d.ts"], 171 ["es2015.collection", "lib.es2015.collection.d.ts"], 172 ["es2015.generator", "lib.es2015.generator.d.ts"], 173 ["es2015.iterable", "lib.es2015.iterable.d.ts"], 174 ["es2015.promise", "lib.es2015.promise.d.ts"], 175 ["es2015.proxy", "lib.es2015.proxy.d.ts"], 176 ["es2015.reflect", "lib.es2015.reflect.d.ts"], 177 ["es2015.symbol", "lib.es2015.symbol.d.ts"], 178 ["es2015.symbol.wellknown", "lib.es2015.symbol.wellknown.d.ts"], 179 ["es2016.array.include", "lib.es2016.array.include.d.ts"], 180 ["es2017.object", "lib.es2017.object.d.ts"], 181 ["es2017.sharedmemory", "lib.es2017.sharedmemory.d.ts"], 182 ["es2017.string", "lib.es2017.string.d.ts"], 183 ["es2017.intl", "lib.es2017.intl.d.ts"], 184 ["es2017.typedarrays", "lib.es2017.typedarrays.d.ts"], 185 ["es2018.asyncgenerator", "lib.es2018.asyncgenerator.d.ts"], 186 ["es2018.asynciterable", "lib.es2018.asynciterable.d.ts"], 187 ["es2018.intl", "lib.es2018.intl.d.ts"], 188 ["es2018.promise", "lib.es2018.promise.d.ts"], 189 ["es2018.regexp", "lib.es2018.regexp.d.ts"], 190 ["es2019.array", "lib.es2019.array.d.ts"], 191 ["es2019.object", "lib.es2019.object.d.ts"], 192 ["es2019.string", "lib.es2019.string.d.ts"], 193 ["es2019.symbol", "lib.es2019.symbol.d.ts"], 194 ["es2019.intl", "lib.es2019.intl.d.ts"], 195 ["es2020.bigint", "lib.es2020.bigint.d.ts"], 196 ["es2020.date", "lib.es2020.date.d.ts"], 197 ["es2020.promise", "lib.es2020.promise.d.ts"], 198 ["es2020.sharedmemory", "lib.es2020.sharedmemory.d.ts"], 199 ["es2020.string", "lib.es2020.string.d.ts"], 200 ["es2020.symbol.wellknown", "lib.es2020.symbol.wellknown.d.ts"], 201 ["es2020.intl", "lib.es2020.intl.d.ts"], 202 ["es2020.number", "lib.es2020.number.d.ts"], 203 ["es2021.promise", "lib.es2021.promise.d.ts"], 204 ["es2021.string", "lib.es2021.string.d.ts"], 205 ["es2021.weakref", "lib.es2021.weakref.d.ts"], 206 ["es2021.intl", "lib.es2021.intl.d.ts"], 207 ["es2022.array", "lib.es2022.array.d.ts"], 208 ["es2022.error", "lib.es2022.error.d.ts"], 209 ["es2022.intl", "lib.es2022.intl.d.ts"], 210 ["es2022.object", "lib.es2022.object.d.ts"], 211 ["es2022.sharedmemory", "lib.es2022.sharedmemory.d.ts"], 212 ["es2022.string", "lib.es2022.string.d.ts"], 213 ["esnext.array", "lib.es2022.array.d.ts"], 214 ["esnext.symbol", "lib.es2019.symbol.d.ts"], 215 ["esnext.asynciterable", "lib.es2018.asynciterable.d.ts"], 216 ["esnext.intl", "lib.esnext.intl.d.ts"], 217 ["esnext.bigint", "lib.es2020.bigint.d.ts"], 218 ["esnext.string", "lib.es2022.string.d.ts"], 219 ["esnext.promise", "lib.es2021.promise.d.ts"], 220 ["esnext.weakref", "lib.es2021.weakref.d.ts"] 221]; 222 223/** 224 * An array of supported "lib" reference file names used to determine the order for inclusion 225 * when referenced, as well as for spelling suggestions. This ensures the correct ordering for 226 * overload resolution when a type declared in one lib is extended by another. 227 * @internal 228 */ 229export const libs = libEntries.map(entry => entry[0]); 230 231/** 232 * A map of lib names to lib files. This map is used both for parsing the "lib" command line 233 * option as well as for resolving lib reference directives. 234 * @internal 235 */ 236export const libMap = new Map(libEntries); 237 238/** 239 * Watch related options 240 * @internal 241 */ 242export const optionsForWatch: CommandLineOption[] = [ 243 { 244 name: "watchFile", 245 type: new Map(getEntries({ 246 fixedpollinginterval: WatchFileKind.FixedPollingInterval, 247 prioritypollinginterval: WatchFileKind.PriorityPollingInterval, 248 dynamicprioritypolling: WatchFileKind.DynamicPriorityPolling, 249 fixedchunksizepolling: WatchFileKind.FixedChunkSizePolling, 250 usefsevents: WatchFileKind.UseFsEvents, 251 usefseventsonparentdirectory: WatchFileKind.UseFsEventsOnParentDirectory, 252 })), 253 category: Diagnostics.Watch_and_Build_Modes, 254 description: Diagnostics.Specify_how_the_TypeScript_watch_mode_works, 255 defaultValueDescription: WatchFileKind.UseFsEvents, 256 }, 257 { 258 name: "watchDirectory", 259 type: new Map(getEntries({ 260 usefsevents: WatchDirectoryKind.UseFsEvents, 261 fixedpollinginterval: WatchDirectoryKind.FixedPollingInterval, 262 dynamicprioritypolling: WatchDirectoryKind.DynamicPriorityPolling, 263 fixedchunksizepolling: WatchDirectoryKind.FixedChunkSizePolling, 264 })), 265 category: Diagnostics.Watch_and_Build_Modes, 266 description: Diagnostics.Specify_how_directories_are_watched_on_systems_that_lack_recursive_file_watching_functionality, 267 defaultValueDescription: WatchDirectoryKind.UseFsEvents, 268 }, 269 { 270 name: "fallbackPolling", 271 type: new Map(getEntries({ 272 fixedinterval: PollingWatchKind.FixedInterval, 273 priorityinterval: PollingWatchKind.PriorityInterval, 274 dynamicpriority: PollingWatchKind.DynamicPriority, 275 fixedchunksize: PollingWatchKind.FixedChunkSize, 276 })), 277 category: Diagnostics.Watch_and_Build_Modes, 278 description: Diagnostics.Specify_what_approach_the_watcher_should_use_if_the_system_runs_out_of_native_file_watchers, 279 defaultValueDescription: PollingWatchKind.PriorityInterval, 280 }, 281 { 282 name: "synchronousWatchDirectory", 283 type: "boolean", 284 category: Diagnostics.Watch_and_Build_Modes, 285 description: Diagnostics.Synchronously_call_callbacks_and_update_the_state_of_directory_watchers_on_platforms_that_don_t_support_recursive_watching_natively, 286 defaultValueDescription: false, 287 }, 288 { 289 name: "excludeDirectories", 290 type: "list", 291 element: { 292 name: "excludeDirectory", 293 type: "string", 294 isFilePath: true, 295 extraValidation: specToDiagnostic 296 }, 297 category: Diagnostics.Watch_and_Build_Modes, 298 description: Diagnostics.Remove_a_list_of_directories_from_the_watch_process, 299 }, 300 { 301 name: "excludeFiles", 302 type: "list", 303 element: { 304 name: "excludeFile", 305 type: "string", 306 isFilePath: true, 307 extraValidation: specToDiagnostic 308 }, 309 category: Diagnostics.Watch_and_Build_Modes, 310 description: Diagnostics.Remove_a_list_of_files_from_the_watch_mode_s_processing, 311 }, 312]; 313 314/** @internal */ 315export const commonOptionsWithBuild: CommandLineOption[] = [ 316 { 317 name: "help", 318 shortName: "h", 319 type: "boolean", 320 showInSimplifiedHelpView: true, 321 isCommandLineOnly: true, 322 category: Diagnostics.Command_line_Options, 323 description: Diagnostics.Print_this_message, 324 defaultValueDescription: false, 325 }, 326 { 327 name: "help", 328 shortName: "?", 329 type: "boolean", 330 isCommandLineOnly: true, 331 category: Diagnostics.Command_line_Options, 332 defaultValueDescription: false, 333 }, 334 { 335 name: "watch", 336 shortName: "w", 337 type: "boolean", 338 showInSimplifiedHelpView: true, 339 isCommandLineOnly: true, 340 category: Diagnostics.Command_line_Options, 341 description: Diagnostics.Watch_input_files, 342 defaultValueDescription: false, 343 }, 344 { 345 name: "preserveWatchOutput", 346 type: "boolean", 347 showInSimplifiedHelpView: false, 348 category: Diagnostics.Output_Formatting, 349 description: Diagnostics.Disable_wiping_the_console_in_watch_mode, 350 defaultValueDescription: false, 351 }, 352 { 353 name: "listFiles", 354 type: "boolean", 355 category: Diagnostics.Compiler_Diagnostics, 356 description: Diagnostics.Print_all_of_the_files_read_during_the_compilation, 357 defaultValueDescription: false, 358 }, 359 { 360 name: "explainFiles", 361 type: "boolean", 362 category: Diagnostics.Compiler_Diagnostics, 363 description: Diagnostics.Print_files_read_during_the_compilation_including_why_it_was_included, 364 defaultValueDescription: false, 365 }, 366 { 367 name: "listEmittedFiles", 368 type: "boolean", 369 category: Diagnostics.Compiler_Diagnostics, 370 description: Diagnostics.Print_the_names_of_emitted_files_after_a_compilation, 371 defaultValueDescription: false, 372 }, 373 { 374 name: "pretty", 375 type: "boolean", 376 showInSimplifiedHelpView: true, 377 category: Diagnostics.Output_Formatting, 378 description: Diagnostics.Enable_color_and_formatting_in_TypeScript_s_output_to_make_compiler_errors_easier_to_read, 379 defaultValueDescription: true, 380 }, 381 { 382 name: "traceResolution", 383 type: "boolean", 384 category: Diagnostics.Compiler_Diagnostics, 385 description: Diagnostics.Log_paths_used_during_the_moduleResolution_process, 386 defaultValueDescription: false, 387 }, 388 { 389 name: "diagnostics", 390 type: "boolean", 391 category: Diagnostics.Compiler_Diagnostics, 392 description: Diagnostics.Output_compiler_performance_information_after_building, 393 defaultValueDescription: false, 394 }, 395 { 396 name: "extendedDiagnostics", 397 type: "boolean", 398 category: Diagnostics.Compiler_Diagnostics, 399 description: Diagnostics.Output_more_detailed_compiler_performance_information_after_building, 400 defaultValueDescription: false, 401 }, 402 { 403 name: "generateCpuProfile", 404 type: "string", 405 isFilePath: true, 406 paramType: Diagnostics.FILE_OR_DIRECTORY, 407 category: Diagnostics.Compiler_Diagnostics, 408 description: Diagnostics.Emit_a_v8_CPU_profile_of_the_compiler_run_for_debugging, 409 defaultValueDescription: "profile.cpuprofile" 410 }, 411 { 412 name: "generateTrace", 413 type: "string", 414 isFilePath: true, 415 isCommandLineOnly: true, 416 paramType: Diagnostics.DIRECTORY, 417 category: Diagnostics.Compiler_Diagnostics, 418 description: Diagnostics.Generates_an_event_trace_and_a_list_of_types 419 }, 420 { 421 name: "incremental", 422 shortName: "i", 423 type: "boolean", 424 category: Diagnostics.Projects, 425 description: Diagnostics.Save_tsbuildinfo_files_to_allow_for_incremental_compilation_of_projects, 426 transpileOptionValue: undefined, 427 defaultValueDescription: Diagnostics.false_unless_composite_is_set 428 }, 429 { 430 name: "assumeChangesOnlyAffectDirectDependencies", 431 type: "boolean", 432 affectsSemanticDiagnostics: true, 433 affectsEmit: true, 434 affectsMultiFileEmitBuildInfo: true, 435 category: Diagnostics.Watch_and_Build_Modes, 436 description: Diagnostics.Have_recompiles_in_projects_that_use_incremental_and_watch_mode_assume_that_changes_within_a_file_will_only_affect_files_directly_depending_on_it, 437 defaultValueDescription: false, 438 }, 439 { 440 name: "locale", 441 type: "string", 442 category: Diagnostics.Command_line_Options, 443 isCommandLineOnly: true, 444 description: Diagnostics.Set_the_language_of_the_messaging_from_TypeScript_This_does_not_affect_emit, 445 defaultValueDescription: Diagnostics.Platform_specific 446 }, 447]; 448 449/** @internal */ 450export const targetOptionDeclaration: CommandLineOptionOfCustomType = { 451 name: "target", 452 shortName: "t", 453 type: new Map(getEntries({ 454 es3: ScriptTarget.ES3, 455 es5: ScriptTarget.ES5, 456 es6: ScriptTarget.ES2015, 457 es2015: ScriptTarget.ES2015, 458 es2016: ScriptTarget.ES2016, 459 es2017: ScriptTarget.ES2017, 460 es2018: ScriptTarget.ES2018, 461 es2019: ScriptTarget.ES2019, 462 es2020: ScriptTarget.ES2020, 463 es2021: ScriptTarget.ES2021, 464 es2022: ScriptTarget.ES2022, 465 esnext: ScriptTarget.ESNext, 466 })), 467 affectsSourceFile: true, 468 affectsModuleResolution: true, 469 affectsEmit: true, 470 affectsMultiFileEmitBuildInfo: true, 471 paramType: Diagnostics.VERSION, 472 showInSimplifiedHelpView: true, 473 category: Diagnostics.Language_and_Environment, 474 description: Diagnostics.Set_the_JavaScript_language_version_for_emitted_JavaScript_and_include_compatible_library_declarations, 475 defaultValueDescription: ScriptTarget.ES3, 476}; 477 478/** @internal */ 479export const moduleOptionDeclaration: CommandLineOptionOfCustomType = { 480 name: "module", 481 shortName: "m", 482 type: new Map(getEntries({ 483 none: ModuleKind.None, 484 commonjs: ModuleKind.CommonJS, 485 amd: ModuleKind.AMD, 486 system: ModuleKind.System, 487 umd: ModuleKind.UMD, 488 es6: ModuleKind.ES2015, 489 es2015: ModuleKind.ES2015, 490 es2020: ModuleKind.ES2020, 491 es2022: ModuleKind.ES2022, 492 esnext: ModuleKind.ESNext, 493 node16: ModuleKind.Node16, 494 nodenext: ModuleKind.NodeNext, 495 })), 496 affectsModuleResolution: true, 497 affectsEmit: true, 498 affectsMultiFileEmitBuildInfo: true, 499 paramType: Diagnostics.KIND, 500 showInSimplifiedHelpView: true, 501 category: Diagnostics.Modules, 502 description: Diagnostics.Specify_what_module_code_is_generated, 503 defaultValueDescription: undefined, 504}; 505 506const commandOptionsWithoutBuild: CommandLineOption[] = [ 507 // CommandLine only options 508 { 509 name: "all", 510 type: "boolean", 511 showInSimplifiedHelpView: true, 512 category: Diagnostics.Command_line_Options, 513 description: Diagnostics.Show_all_compiler_options, 514 defaultValueDescription: false, 515 }, 516 { 517 name: "version", 518 shortName: "v", 519 type: "boolean", 520 showInSimplifiedHelpView: true, 521 category: Diagnostics.Command_line_Options, 522 description: Diagnostics.Print_the_compiler_s_version, 523 defaultValueDescription: false, 524 }, 525 { 526 name: "init", 527 type: "boolean", 528 showInSimplifiedHelpView: true, 529 category: Diagnostics.Command_line_Options, 530 description: Diagnostics.Initializes_a_TypeScript_project_and_creates_a_tsconfig_json_file, 531 defaultValueDescription: false, 532 }, 533 { 534 name: "project", 535 shortName: "p", 536 type: "string", 537 isFilePath: true, 538 showInSimplifiedHelpView: true, 539 category: Diagnostics.Command_line_Options, 540 paramType: Diagnostics.FILE_OR_DIRECTORY, 541 description: Diagnostics.Compile_the_project_given_the_path_to_its_configuration_file_or_to_a_folder_with_a_tsconfig_json, 542 }, 543 { 544 name: "build", 545 type: "boolean", 546 shortName: "b", 547 showInSimplifiedHelpView: true, 548 category: Diagnostics.Command_line_Options, 549 description: Diagnostics.Build_one_or_more_projects_and_their_dependencies_if_out_of_date, 550 defaultValueDescription: false, 551 }, 552 { 553 name: "showConfig", 554 type: "boolean", 555 showInSimplifiedHelpView: true, 556 category: Diagnostics.Command_line_Options, 557 isCommandLineOnly: true, 558 description: Diagnostics.Print_the_final_configuration_instead_of_building, 559 defaultValueDescription: false, 560 }, 561 { 562 name: "listFilesOnly", 563 type: "boolean", 564 category: Diagnostics.Command_line_Options, 565 affectsSemanticDiagnostics: true, 566 affectsEmit: true, 567 affectsMultiFileEmitBuildInfo: true, 568 isCommandLineOnly: true, 569 description: Diagnostics.Print_names_of_files_that_are_part_of_the_compilation_and_then_stop_processing, 570 defaultValueDescription: false, 571 }, 572 573 // Basic 574 targetOptionDeclaration, 575 moduleOptionDeclaration, 576 { 577 name: "lib", 578 type: "list", 579 element: { 580 name: "lib", 581 type: libMap, 582 defaultValueDescription: undefined, 583 }, 584 affectsProgramStructure: true, 585 showInSimplifiedHelpView: true, 586 category: Diagnostics.Language_and_Environment, 587 description: Diagnostics.Specify_a_set_of_bundled_library_declaration_files_that_describe_the_target_runtime_environment, 588 transpileOptionValue: undefined 589 }, 590 { 591 name: "allowJs", 592 type: "boolean", 593 affectsModuleResolution: true, 594 showInSimplifiedHelpView: true, 595 category: Diagnostics.JavaScript_Support, 596 description: Diagnostics.Allow_JavaScript_files_to_be_a_part_of_your_program_Use_the_checkJS_option_to_get_errors_from_these_files, 597 defaultValueDescription: false, 598 }, 599 { 600 name: "checkJs", 601 type: "boolean", 602 showInSimplifiedHelpView: true, 603 category: Diagnostics.JavaScript_Support, 604 description: Diagnostics.Enable_error_reporting_in_type_checked_JavaScript_files, 605 defaultValueDescription: false, 606 }, 607 { 608 name: "jsx", 609 type: jsxOptionMap, 610 affectsSourceFile: true, 611 affectsEmit: true, 612 affectsMultiFileEmitBuildInfo: true, 613 affectsModuleResolution: true, 614 paramType: Diagnostics.KIND, 615 showInSimplifiedHelpView: true, 616 category: Diagnostics.Language_and_Environment, 617 description: Diagnostics.Specify_what_JSX_code_is_generated, 618 defaultValueDescription: undefined, 619 }, 620 { 621 name: "declaration", 622 shortName: "d", 623 type: "boolean", 624 affectsEmit: true, 625 affectsMultiFileEmitBuildInfo: true, 626 showInSimplifiedHelpView: true, 627 category: Diagnostics.Emit, 628 transpileOptionValue: undefined, 629 description: Diagnostics.Generate_d_ts_files_from_TypeScript_and_JavaScript_files_in_your_project, 630 defaultValueDescription: Diagnostics.false_unless_composite_is_set, 631 }, 632 { 633 name: "declarationMap", 634 type: "boolean", 635 affectsEmit: true, 636 affectsMultiFileEmitBuildInfo: true, 637 showInSimplifiedHelpView: true, 638 category: Diagnostics.Emit, 639 transpileOptionValue: undefined, 640 defaultValueDescription: false, 641 description: Diagnostics.Create_sourcemaps_for_d_ts_files 642 }, 643 { 644 name: "emitDeclarationOnly", 645 type: "boolean", 646 affectsEmit: true, 647 affectsMultiFileEmitBuildInfo: true, 648 showInSimplifiedHelpView: true, 649 650 category: Diagnostics.Emit, 651 description: Diagnostics.Only_output_d_ts_files_and_not_JavaScript_files, 652 transpileOptionValue: undefined, 653 defaultValueDescription: false, 654 }, 655 { 656 name: "sourceMap", 657 type: "boolean", 658 affectsEmit: true, 659 affectsMultiFileEmitBuildInfo: true, 660 showInSimplifiedHelpView: true, 661 category: Diagnostics.Emit, 662 defaultValueDescription: false, 663 description: Diagnostics.Create_source_map_files_for_emitted_JavaScript_files, 664 }, 665 { 666 name: "outFile", 667 type: "string", 668 affectsEmit: true, 669 affectsMultiFileEmitBuildInfo: true, 670 affectsDeclarationPath: true, 671 affectsBundleEmitBuildInfo: true, 672 isFilePath: true, 673 paramType: Diagnostics.FILE, 674 showInSimplifiedHelpView: true, 675 category: Diagnostics.Emit, 676 description: Diagnostics.Specify_a_file_that_bundles_all_outputs_into_one_JavaScript_file_If_declaration_is_true_also_designates_a_file_that_bundles_all_d_ts_output, 677 transpileOptionValue: undefined, 678 }, 679 { 680 name: "outDir", 681 type: "string", 682 affectsEmit: true, 683 affectsMultiFileEmitBuildInfo: true, 684 affectsDeclarationPath: true, 685 isFilePath: true, 686 paramType: Diagnostics.DIRECTORY, 687 showInSimplifiedHelpView: true, 688 category: Diagnostics.Emit, 689 description: Diagnostics.Specify_an_output_folder_for_all_emitted_files, 690 }, 691 { 692 name: "rootDir", 693 type: "string", 694 affectsEmit: true, 695 affectsMultiFileEmitBuildInfo: true, 696 affectsDeclarationPath: true, 697 isFilePath: true, 698 paramType: Diagnostics.LOCATION, 699 category: Diagnostics.Modules, 700 description: Diagnostics.Specify_the_root_folder_within_your_source_files, 701 defaultValueDescription: Diagnostics.Computed_from_the_list_of_input_files 702 }, 703 { 704 name: "composite", 705 type: "boolean", 706 affectsEmit: true, 707 affectsMultiFileEmitBuildInfo: true, 708 affectsBundleEmitBuildInfo: true, 709 isTSConfigOnly: true, 710 category: Diagnostics.Projects, 711 transpileOptionValue: undefined, 712 defaultValueDescription: false, 713 description: Diagnostics.Enable_constraints_that_allow_a_TypeScript_project_to_be_used_with_project_references, 714 }, 715 { 716 name: "tsBuildInfoFile", 717 type: "string", 718 affectsEmit: true, 719 affectsMultiFileEmitBuildInfo: true, 720 affectsBundleEmitBuildInfo: true, 721 isFilePath: true, 722 paramType: Diagnostics.FILE, 723 category: Diagnostics.Projects, 724 transpileOptionValue: undefined, 725 defaultValueDescription: ".tsbuildinfo", 726 description: Diagnostics.Specify_the_path_to_tsbuildinfo_incremental_compilation_file, 727 }, 728 { 729 name: "removeComments", 730 type: "boolean", 731 affectsEmit: true, 732 affectsMultiFileEmitBuildInfo: true, 733 showInSimplifiedHelpView: true, 734 category: Diagnostics.Emit, 735 defaultValueDescription: false, 736 description: Diagnostics.Disable_emitting_comments, 737 }, 738 { 739 name: "noEmit", 740 type: "boolean", 741 showInSimplifiedHelpView: true, 742 category: Diagnostics.Emit, 743 description: Diagnostics.Disable_emitting_files_from_a_compilation, 744 transpileOptionValue: undefined, 745 defaultValueDescription: false, 746 }, 747 { 748 name: "importHelpers", 749 type: "boolean", 750 affectsEmit: true, 751 affectsMultiFileEmitBuildInfo: true, 752 category: Diagnostics.Emit, 753 description: Diagnostics.Allow_importing_helper_functions_from_tslib_once_per_project_instead_of_including_them_per_file, 754 defaultValueDescription: false, 755 }, 756 { 757 name: "importsNotUsedAsValues", 758 type: new Map(getEntries({ 759 remove: ImportsNotUsedAsValues.Remove, 760 preserve: ImportsNotUsedAsValues.Preserve, 761 error: ImportsNotUsedAsValues.Error, 762 })), 763 affectsEmit: true, 764 affectsSemanticDiagnostics: true, 765 affectsMultiFileEmitBuildInfo: true, 766 category: Diagnostics.Emit, 767 description: Diagnostics.Specify_emit_Slashchecking_behavior_for_imports_that_are_only_used_for_types, 768 defaultValueDescription: ImportsNotUsedAsValues.Remove, 769 }, 770 { 771 name: "downlevelIteration", 772 type: "boolean", 773 affectsEmit: true, 774 affectsMultiFileEmitBuildInfo: true, 775 category: Diagnostics.Emit, 776 description: Diagnostics.Emit_more_compliant_but_verbose_and_less_performant_JavaScript_for_iteration, 777 defaultValueDescription: false, 778 }, 779 { 780 name: "isolatedModules", 781 type: "boolean", 782 category: Diagnostics.Interop_Constraints, 783 description: Diagnostics.Ensure_that_each_file_can_be_safely_transpiled_without_relying_on_other_imports, 784 transpileOptionValue: true, 785 defaultValueDescription: false, 786 }, 787 788 // Strict Type Checks 789 { 790 name: "strict", 791 type: "boolean", 792 // Though this affects semantic diagnostics, affectsSemanticDiagnostics is not set here 793 // The value of each strictFlag depends on own strictFlag value or this and never accessed directly. 794 // But we need to store `strict` in builf info, even though it won't be examined directly, so that the 795 // flags it controls (e.g. `strictNullChecks`) will be retrieved correctly 796 affectsMultiFileEmitBuildInfo: true, 797 showInSimplifiedHelpView: true, 798 category: Diagnostics.Type_Checking, 799 description: Diagnostics.Enable_all_strict_type_checking_options, 800 defaultValueDescription: false, 801 }, 802 { 803 name: "noImplicitAny", 804 type: "boolean", 805 affectsSemanticDiagnostics: true, 806 affectsMultiFileEmitBuildInfo: true, 807 strictFlag: true, 808 category: Diagnostics.Type_Checking, 809 description: Diagnostics.Enable_error_reporting_for_expressions_and_declarations_with_an_implied_any_type, 810 defaultValueDescription: Diagnostics.false_unless_strict_is_set 811 }, 812 { 813 name: "strictNullChecks", 814 type: "boolean", 815 affectsSemanticDiagnostics: true, 816 affectsMultiFileEmitBuildInfo: true, 817 strictFlag: true, 818 category: Diagnostics.Type_Checking, 819 description: Diagnostics.When_type_checking_take_into_account_null_and_undefined, 820 defaultValueDescription: Diagnostics.false_unless_strict_is_set 821 }, 822 { 823 name: "strictFunctionTypes", 824 type: "boolean", 825 affectsSemanticDiagnostics: true, 826 affectsMultiFileEmitBuildInfo: true, 827 strictFlag: true, 828 category: Diagnostics.Type_Checking, 829 description: Diagnostics.When_assigning_functions_check_to_ensure_parameters_and_the_return_values_are_subtype_compatible, 830 defaultValueDescription: Diagnostics.false_unless_strict_is_set 831 }, 832 { 833 name: "strictBindCallApply", 834 type: "boolean", 835 affectsSemanticDiagnostics: true, 836 affectsMultiFileEmitBuildInfo: true, 837 strictFlag: true, 838 category: Diagnostics.Type_Checking, 839 description: Diagnostics.Check_that_the_arguments_for_bind_call_and_apply_methods_match_the_original_function, 840 defaultValueDescription: Diagnostics.false_unless_strict_is_set 841 }, 842 { 843 name: "strictPropertyInitialization", 844 type: "boolean", 845 affectsSemanticDiagnostics: true, 846 affectsMultiFileEmitBuildInfo: true, 847 strictFlag: true, 848 category: Diagnostics.Type_Checking, 849 description: Diagnostics.Check_for_class_properties_that_are_declared_but_not_set_in_the_constructor, 850 defaultValueDescription: Diagnostics.false_unless_strict_is_set 851 }, 852 { 853 name: "noImplicitThis", 854 type: "boolean", 855 affectsSemanticDiagnostics: true, 856 affectsMultiFileEmitBuildInfo: true, 857 strictFlag: true, 858 category: Diagnostics.Type_Checking, 859 description: Diagnostics.Enable_error_reporting_when_this_is_given_the_type_any, 860 defaultValueDescription: Diagnostics.false_unless_strict_is_set 861 }, 862 { 863 name: "useUnknownInCatchVariables", 864 type: "boolean", 865 affectsSemanticDiagnostics: true, 866 affectsMultiFileEmitBuildInfo: true, 867 strictFlag: true, 868 category: Diagnostics.Type_Checking, 869 description: Diagnostics.Default_catch_clause_variables_as_unknown_instead_of_any, 870 defaultValueDescription: false, 871 }, 872 { 873 name: "alwaysStrict", 874 type: "boolean", 875 affectsSourceFile: true, 876 affectsEmit: true, 877 affectsMultiFileEmitBuildInfo: true, 878 strictFlag: true, 879 category: Diagnostics.Type_Checking, 880 description: Diagnostics.Ensure_use_strict_is_always_emitted, 881 defaultValueDescription: Diagnostics.false_unless_strict_is_set 882 }, 883 884 // Additional Checks 885 { 886 name: "noUnusedLocals", 887 type: "boolean", 888 affectsSemanticDiagnostics: true, 889 affectsMultiFileEmitBuildInfo: true, 890 category: Diagnostics.Type_Checking, 891 description: Diagnostics.Enable_error_reporting_when_local_variables_aren_t_read, 892 defaultValueDescription: false, 893 }, 894 { 895 name: "noUnusedParameters", 896 type: "boolean", 897 affectsSemanticDiagnostics: true, 898 affectsMultiFileEmitBuildInfo: true, 899 category: Diagnostics.Type_Checking, 900 description: Diagnostics.Raise_an_error_when_a_function_parameter_isn_t_read, 901 defaultValueDescription: false, 902 }, 903 { 904 name: "exactOptionalPropertyTypes", 905 type: "boolean", 906 affectsSemanticDiagnostics: true, 907 affectsMultiFileEmitBuildInfo: true, 908 category: Diagnostics.Type_Checking, 909 description: Diagnostics.Interpret_optional_property_types_as_written_rather_than_adding_undefined, 910 defaultValueDescription: false, 911 }, 912 { 913 name: "noImplicitReturns", 914 type: "boolean", 915 affectsSemanticDiagnostics: true, 916 affectsMultiFileEmitBuildInfo: true, 917 category: Diagnostics.Type_Checking, 918 description: Diagnostics.Enable_error_reporting_for_codepaths_that_do_not_explicitly_return_in_a_function, 919 defaultValueDescription: false, 920 }, 921 { 922 name: "noFallthroughCasesInSwitch", 923 type: "boolean", 924 affectsBindDiagnostics: true, 925 affectsSemanticDiagnostics: true, 926 affectsMultiFileEmitBuildInfo: true, 927 category: Diagnostics.Type_Checking, 928 description: Diagnostics.Enable_error_reporting_for_fallthrough_cases_in_switch_statements, 929 defaultValueDescription: false, 930 }, 931 { 932 name: "noUncheckedIndexedAccess", 933 type: "boolean", 934 affectsSemanticDiagnostics: true, 935 affectsMultiFileEmitBuildInfo: true, 936 category: Diagnostics.Type_Checking, 937 description: Diagnostics.Add_undefined_to_a_type_when_accessed_using_an_index, 938 defaultValueDescription: false, 939 }, 940 { 941 name: "noImplicitOverride", 942 type: "boolean", 943 affectsSemanticDiagnostics: true, 944 affectsMultiFileEmitBuildInfo: true, 945 category: Diagnostics.Type_Checking, 946 description: Diagnostics.Ensure_overriding_members_in_derived_classes_are_marked_with_an_override_modifier, 947 defaultValueDescription: false, 948 }, 949 { 950 name: "noPropertyAccessFromIndexSignature", 951 type: "boolean", 952 affectsSemanticDiagnostics: true, 953 affectsMultiFileEmitBuildInfo: true, 954 showInSimplifiedHelpView: false, 955 category: Diagnostics.Type_Checking, 956 description: Diagnostics.Enforces_using_indexed_accessors_for_keys_declared_using_an_indexed_type, 957 defaultValueDescription: false, 958 }, 959 960 // Module Resolution 961 { 962 name: "moduleResolution", 963 type: new Map(getEntries({ 964 node: ModuleResolutionKind.NodeJs, 965 classic: ModuleResolutionKind.Classic, 966 node16: ModuleResolutionKind.Node16, 967 nodenext: ModuleResolutionKind.NodeNext, 968 })), 969 affectsModuleResolution: true, 970 paramType: Diagnostics.STRATEGY, 971 category: Diagnostics.Modules, 972 description: Diagnostics.Specify_how_TypeScript_looks_up_a_file_from_a_given_module_specifier, 973 defaultValueDescription: Diagnostics.module_AMD_or_UMD_or_System_or_ES6_then_Classic_Otherwise_Node 974 }, 975 { 976 name: "baseUrl", 977 type: "string", 978 affectsModuleResolution: true, 979 isFilePath: true, 980 category: Diagnostics.Modules, 981 description: Diagnostics.Specify_the_base_directory_to_resolve_non_relative_module_names 982 }, 983 { 984 // this option can only be specified in tsconfig.json 985 // use type = object to copy the value as-is 986 name: "paths", 987 type: "object", 988 affectsModuleResolution: true, 989 isTSConfigOnly: true, 990 category: Diagnostics.Modules, 991 description: Diagnostics.Specify_a_set_of_entries_that_re_map_imports_to_additional_lookup_locations, 992 transpileOptionValue: undefined 993 }, 994 { 995 // this option can only be specified in tsconfig.json 996 // use type = object to copy the value as-is 997 name: "rootDirs", 998 type: "list", 999 isTSConfigOnly: true, 1000 element: { 1001 name: "rootDirs", 1002 type: "string", 1003 isFilePath: true 1004 }, 1005 affectsModuleResolution: true, 1006 category: Diagnostics.Modules, 1007 description: Diagnostics.Allow_multiple_folders_to_be_treated_as_one_when_resolving_modules, 1008 transpileOptionValue: undefined, 1009 defaultValueDescription: Diagnostics.Computed_from_the_list_of_input_files 1010 }, 1011 { 1012 name: "typeRoots", 1013 type: "list", 1014 element: { 1015 name: "typeRoots", 1016 type: "string", 1017 isFilePath: true 1018 }, 1019 affectsModuleResolution: true, 1020 category: Diagnostics.Modules, 1021 description: Diagnostics.Specify_multiple_folders_that_act_like_Slashnode_modules_Slash_types 1022 }, 1023 { 1024 name: "types", 1025 type: "list", 1026 element: { 1027 name: "types", 1028 type: "string" 1029 }, 1030 affectsProgramStructure: true, 1031 showInSimplifiedHelpView: true, 1032 category: Diagnostics.Modules, 1033 description: Diagnostics.Specify_type_package_names_to_be_included_without_being_referenced_in_a_source_file, 1034 transpileOptionValue: undefined 1035 }, 1036 { 1037 name: "allowSyntheticDefaultImports", 1038 type: "boolean", 1039 affectsSemanticDiagnostics: true, 1040 affectsMultiFileEmitBuildInfo: true, 1041 category: Diagnostics.Interop_Constraints, 1042 description: Diagnostics.Allow_import_x_from_y_when_a_module_doesn_t_have_a_default_export, 1043 defaultValueDescription: Diagnostics.module_system_or_esModuleInterop 1044 }, 1045 { 1046 name: "esModuleInterop", 1047 type: "boolean", 1048 affectsSemanticDiagnostics: true, 1049 affectsEmit: true, 1050 affectsMultiFileEmitBuildInfo: true, 1051 showInSimplifiedHelpView: true, 1052 category: Diagnostics.Interop_Constraints, 1053 description: Diagnostics.Emit_additional_JavaScript_to_ease_support_for_importing_CommonJS_modules_This_enables_allowSyntheticDefaultImports_for_type_compatibility, 1054 defaultValueDescription: false, 1055 }, 1056 { 1057 name: "preserveSymlinks", 1058 type: "boolean", 1059 category: Diagnostics.Interop_Constraints, 1060 description: Diagnostics.Disable_resolving_symlinks_to_their_realpath_This_correlates_to_the_same_flag_in_node, 1061 defaultValueDescription: false, 1062 }, 1063 { 1064 name: "allowUmdGlobalAccess", 1065 type: "boolean", 1066 affectsSemanticDiagnostics: true, 1067 affectsMultiFileEmitBuildInfo: true, 1068 category: Diagnostics.Modules, 1069 description: Diagnostics.Allow_accessing_UMD_globals_from_modules, 1070 defaultValueDescription: false, 1071 }, 1072 { 1073 name: "moduleSuffixes", 1074 type: "list", 1075 element: { 1076 name: "suffix", 1077 type: "string", 1078 }, 1079 listPreserveFalsyValues: true, 1080 affectsModuleResolution: true, 1081 category: Diagnostics.Modules, 1082 description: Diagnostics.List_of_file_name_suffixes_to_search_when_resolving_a_module, 1083 }, 1084 1085 // Source Maps 1086 { 1087 name: "sourceRoot", 1088 type: "string", 1089 affectsEmit: true, 1090 affectsMultiFileEmitBuildInfo: true, 1091 paramType: Diagnostics.LOCATION, 1092 category: Diagnostics.Emit, 1093 description: Diagnostics.Specify_the_root_path_for_debuggers_to_find_the_reference_source_code, 1094 }, 1095 { 1096 name: "mapRoot", 1097 type: "string", 1098 affectsEmit: true, 1099 affectsMultiFileEmitBuildInfo: true, 1100 paramType: Diagnostics.LOCATION, 1101 category: Diagnostics.Emit, 1102 description: Diagnostics.Specify_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations, 1103 }, 1104 { 1105 name: "inlineSourceMap", 1106 type: "boolean", 1107 affectsEmit: true, 1108 affectsMultiFileEmitBuildInfo: true, 1109 category: Diagnostics.Emit, 1110 description: Diagnostics.Include_sourcemap_files_inside_the_emitted_JavaScript, 1111 defaultValueDescription: false, 1112 }, 1113 { 1114 name: "inlineSources", 1115 type: "boolean", 1116 affectsEmit: true, 1117 affectsMultiFileEmitBuildInfo: true, 1118 category: Diagnostics.Emit, 1119 description: Diagnostics.Include_source_code_in_the_sourcemaps_inside_the_emitted_JavaScript, 1120 defaultValueDescription: false, 1121 }, 1122 1123 // Experimental 1124 { 1125 name: "experimentalDecorators", 1126 type: "boolean", 1127 affectsSemanticDiagnostics: true, 1128 affectsMultiFileEmitBuildInfo: true, 1129 category: Diagnostics.Language_and_Environment, 1130 description: Diagnostics.Enable_experimental_support_for_TC39_stage_2_draft_decorators, 1131 defaultValueDescription: false, 1132 }, 1133 { 1134 name: "emitDecoratorMetadata", 1135 type: "boolean", 1136 affectsSemanticDiagnostics: true, 1137 affectsEmit: true, 1138 affectsMultiFileEmitBuildInfo: true, 1139 category: Diagnostics.Language_and_Environment, 1140 description: Diagnostics.Emit_design_type_metadata_for_decorated_declarations_in_source_files, 1141 defaultValueDescription: false, 1142 }, 1143 1144 // Advanced 1145 { 1146 name: "jsxFactory", 1147 type: "string", 1148 category: Diagnostics.Language_and_Environment, 1149 description: Diagnostics.Specify_the_JSX_factory_function_used_when_targeting_React_JSX_emit_e_g_React_createElement_or_h, 1150 defaultValueDescription: "`React.createElement`" 1151 }, 1152 { 1153 name: "jsxFragmentFactory", 1154 type: "string", 1155 category: Diagnostics.Language_and_Environment, 1156 description: Diagnostics.Specify_the_JSX_Fragment_reference_used_for_fragments_when_targeting_React_JSX_emit_e_g_React_Fragment_or_Fragment, 1157 defaultValueDescription: "React.Fragment", 1158 }, 1159 { 1160 name: "jsxImportSource", 1161 type: "string", 1162 affectsSemanticDiagnostics: true, 1163 affectsEmit: true, 1164 affectsMultiFileEmitBuildInfo: true, 1165 affectsModuleResolution: true, 1166 category: Diagnostics.Language_and_Environment, 1167 description: Diagnostics.Specify_module_specifier_used_to_import_the_JSX_factory_functions_when_using_jsx_Colon_react_jsx_Asterisk, 1168 defaultValueDescription: "react" 1169 }, 1170 { 1171 name: "ets", 1172 type: "object", 1173 affectsSourceFile: true, 1174 affectsEmit: true, 1175 affectsModuleResolution: true, 1176 category: Diagnostics.Language_and_Environment, 1177 description: Diagnostics.Unknown_build_option_0, 1178 }, 1179 { 1180 name: "packageManagerType", 1181 type: "string", 1182 affectsSourceFile: true, 1183 affectsEmit: true, 1184 affectsModuleResolution: true, 1185 category: Diagnostics.Language_and_Environment, 1186 description: Diagnostics.Unknown_build_option_0, 1187 }, 1188 { 1189 name: "emitNodeModulesFiles", 1190 type: "boolean", 1191 category: Diagnostics.Language_and_Environment, 1192 description: Diagnostics.Unknown_build_option_0, 1193 defaultValueDescription: false, 1194 }, 1195 { 1196 name: "resolveJsonModule", 1197 type: "boolean", 1198 affectsModuleResolution: true, 1199 category: Diagnostics.Modules, 1200 description: Diagnostics.Enable_importing_json_files, 1201 defaultValueDescription: false, 1202 }, 1203 1204 { 1205 name: "out", 1206 type: "string", 1207 affectsEmit: true, 1208 affectsMultiFileEmitBuildInfo: true, 1209 affectsDeclarationPath: true, 1210 affectsBundleEmitBuildInfo: true, 1211 isFilePath: false, // This is intentionally broken to support compatability with existing tsconfig files 1212 // for correct behaviour, please use outFile 1213 category: Diagnostics.Backwards_Compatibility, 1214 paramType: Diagnostics.FILE, 1215 transpileOptionValue: undefined, 1216 description: Diagnostics.Deprecated_setting_Use_outFile_instead, 1217 }, 1218 { 1219 name: "reactNamespace", 1220 type: "string", 1221 affectsEmit: true, 1222 affectsMultiFileEmitBuildInfo: true, 1223 category: Diagnostics.Language_and_Environment, 1224 description: Diagnostics.Specify_the_object_invoked_for_createElement_This_only_applies_when_targeting_react_JSX_emit, 1225 defaultValueDescription: "`React`", 1226 }, 1227 { 1228 name: "skipDefaultLibCheck", 1229 type: "boolean", 1230 // We need to store these to determine whether `lib` files need to be rechecked 1231 affectsMultiFileEmitBuildInfo: true, 1232 category: Diagnostics.Completeness, 1233 description: Diagnostics.Skip_type_checking_d_ts_files_that_are_included_with_TypeScript, 1234 defaultValueDescription: false, 1235 }, 1236 { 1237 name: "charset", 1238 type: "string", 1239 category: Diagnostics.Backwards_Compatibility, 1240 description: Diagnostics.No_longer_supported_In_early_versions_manually_set_the_text_encoding_for_reading_files, 1241 defaultValueDescription: "utf8" 1242 }, 1243 { 1244 name: "emitBOM", 1245 type: "boolean", 1246 affectsEmit: true, 1247 affectsMultiFileEmitBuildInfo: true, 1248 category: Diagnostics.Emit, 1249 description: Diagnostics.Emit_a_UTF_8_Byte_Order_Mark_BOM_in_the_beginning_of_output_files, 1250 defaultValueDescription: false, 1251 }, 1252 { 1253 name: "newLine", 1254 type: new Map(getEntries({ 1255 crlf: NewLineKind.CarriageReturnLineFeed, 1256 lf: NewLineKind.LineFeed 1257 })), 1258 affectsEmit: true, 1259 affectsMultiFileEmitBuildInfo: true, 1260 paramType: Diagnostics.NEWLINE, 1261 category: Diagnostics.Emit, 1262 description: Diagnostics.Set_the_newline_character_for_emitting_files, 1263 defaultValueDescription: Diagnostics.Platform_specific 1264 }, 1265 { 1266 name: "noErrorTruncation", 1267 type: "boolean", 1268 affectsSemanticDiagnostics: true, 1269 affectsMultiFileEmitBuildInfo: true, 1270 category: Diagnostics.Output_Formatting, 1271 description: Diagnostics.Disable_truncating_types_in_error_messages, 1272 defaultValueDescription: false, 1273 }, 1274 { 1275 name: "noLib", 1276 type: "boolean", 1277 category: Diagnostics.Language_and_Environment, 1278 affectsProgramStructure: true, 1279 description: Diagnostics.Disable_including_any_library_files_including_the_default_lib_d_ts, 1280 // We are not returning a sourceFile for lib file when asked by the program, 1281 // so pass --noLib to avoid reporting a file not found error. 1282 transpileOptionValue: true, 1283 defaultValueDescription: false, 1284 }, 1285 { 1286 name: "noResolve", 1287 type: "boolean", 1288 affectsModuleResolution: true, 1289 category: Diagnostics.Modules, 1290 description: Diagnostics.Disallow_import_s_require_s_or_reference_s_from_expanding_the_number_of_files_TypeScript_should_add_to_a_project, 1291 // We are not doing a full typecheck, we are not resolving the whole context, 1292 // so pass --noResolve to avoid reporting missing file errors. 1293 transpileOptionValue: true, 1294 defaultValueDescription: false, 1295 }, 1296 { 1297 name: "stripInternal", 1298 type: "boolean", 1299 affectsEmit: true, 1300 affectsMultiFileEmitBuildInfo: true, 1301 category: Diagnostics.Emit, 1302 description: Diagnostics.Disable_emitting_declarations_that_have_internal_in_their_JSDoc_comments, 1303 defaultValueDescription: false, 1304 }, 1305 { 1306 name: "disableSizeLimit", 1307 type: "boolean", 1308 affectsProgramStructure: true, 1309 category: Diagnostics.Editor_Support, 1310 description: Diagnostics.Remove_the_20mb_cap_on_total_source_code_size_for_JavaScript_files_in_the_TypeScript_language_server, 1311 defaultValueDescription: false, 1312 }, 1313 { 1314 name: "disableSourceOfProjectReferenceRedirect", 1315 type: "boolean", 1316 isTSConfigOnly: true, 1317 category: Diagnostics.Projects, 1318 description: Diagnostics.Disable_preferring_source_files_instead_of_declaration_files_when_referencing_composite_projects, 1319 defaultValueDescription: false, 1320 }, 1321 { 1322 name: "disableSolutionSearching", 1323 type: "boolean", 1324 isTSConfigOnly: true, 1325 category: Diagnostics.Projects, 1326 description: Diagnostics.Opt_a_project_out_of_multi_project_reference_checking_when_editing, 1327 defaultValueDescription: false, 1328 }, 1329 { 1330 name: "disableReferencedProjectLoad", 1331 type: "boolean", 1332 isTSConfigOnly: true, 1333 category: Diagnostics.Projects, 1334 description: Diagnostics.Reduce_the_number_of_projects_loaded_automatically_by_TypeScript, 1335 defaultValueDescription: false, 1336 }, 1337 { 1338 name: "noImplicitUseStrict", 1339 type: "boolean", 1340 affectsSemanticDiagnostics: true, 1341 affectsMultiFileEmitBuildInfo: true, 1342 category: Diagnostics.Backwards_Compatibility, 1343 description: Diagnostics.Disable_adding_use_strict_directives_in_emitted_JavaScript_files, 1344 defaultValueDescription: false, 1345 }, 1346 { 1347 name: "noEmitHelpers", 1348 type: "boolean", 1349 affectsEmit: true, 1350 affectsMultiFileEmitBuildInfo: true, 1351 category: Diagnostics.Emit, 1352 description: Diagnostics.Disable_generating_custom_helper_functions_like_extends_in_compiled_output, 1353 defaultValueDescription: false, 1354 }, 1355 { 1356 name: "noEmitOnError", 1357 type: "boolean", 1358 affectsEmit: true, 1359 affectsMultiFileEmitBuildInfo: true, 1360 category: Diagnostics.Emit, 1361 transpileOptionValue: undefined, 1362 description: Diagnostics.Disable_emitting_files_if_any_type_checking_errors_are_reported, 1363 defaultValueDescription: false, 1364 }, 1365 { 1366 name: "preserveConstEnums", 1367 type: "boolean", 1368 affectsEmit: true, 1369 affectsMultiFileEmitBuildInfo: true, 1370 category: Diagnostics.Emit, 1371 description: Diagnostics.Disable_erasing_const_enum_declarations_in_generated_code, 1372 defaultValueDescription: false, 1373 }, 1374 { 1375 name: "declarationDir", 1376 type: "string", 1377 affectsEmit: true, 1378 affectsMultiFileEmitBuildInfo: true, 1379 affectsDeclarationPath: true, 1380 isFilePath: true, 1381 paramType: Diagnostics.DIRECTORY, 1382 category: Diagnostics.Emit, 1383 transpileOptionValue: undefined, 1384 description: Diagnostics.Specify_the_output_directory_for_generated_declaration_files, 1385 }, 1386 { 1387 name: "skipLibCheck", 1388 type: "boolean", 1389 // We need to store these to determine whether `lib` files need to be rechecked 1390 affectsMultiFileEmitBuildInfo: true, 1391 category: Diagnostics.Completeness, 1392 description: Diagnostics.Skip_type_checking_all_d_ts_files, 1393 defaultValueDescription: false, 1394 }, 1395 { 1396 name: "allowUnusedLabels", 1397 type: "boolean", 1398 affectsBindDiagnostics: true, 1399 affectsSemanticDiagnostics: true, 1400 affectsMultiFileEmitBuildInfo: true, 1401 category: Diagnostics.Type_Checking, 1402 description: Diagnostics.Disable_error_reporting_for_unused_labels, 1403 defaultValueDescription: undefined, 1404 }, 1405 { 1406 name: "allowUnreachableCode", 1407 type: "boolean", 1408 affectsBindDiagnostics: true, 1409 affectsSemanticDiagnostics: true, 1410 affectsMultiFileEmitBuildInfo: true, 1411 category: Diagnostics.Type_Checking, 1412 description: Diagnostics.Disable_error_reporting_for_unreachable_code, 1413 defaultValueDescription: undefined, 1414 }, 1415 { 1416 name: "suppressExcessPropertyErrors", 1417 type: "boolean", 1418 affectsSemanticDiagnostics: true, 1419 affectsMultiFileEmitBuildInfo: true, 1420 category: Diagnostics.Backwards_Compatibility, 1421 description: Diagnostics.Disable_reporting_of_excess_property_errors_during_the_creation_of_object_literals, 1422 defaultValueDescription: false, 1423 }, 1424 { 1425 name: "suppressImplicitAnyIndexErrors", 1426 type: "boolean", 1427 affectsSemanticDiagnostics: true, 1428 affectsMultiFileEmitBuildInfo: true, 1429 category: Diagnostics.Backwards_Compatibility, 1430 description: Diagnostics.Suppress_noImplicitAny_errors_when_indexing_objects_that_lack_index_signatures, 1431 defaultValueDescription: false, 1432 }, 1433 { 1434 name: "forceConsistentCasingInFileNames", 1435 type: "boolean", 1436 affectsModuleResolution: true, 1437 category: Diagnostics.Interop_Constraints, 1438 description: Diagnostics.Ensure_that_casing_is_correct_in_imports, 1439 defaultValueDescription: false, 1440 }, 1441 { 1442 name: "maxNodeModuleJsDepth", 1443 type: "number", 1444 affectsModuleResolution: true, 1445 category: Diagnostics.JavaScript_Support, 1446 description: Diagnostics.Specify_the_maximum_folder_depth_used_for_checking_JavaScript_files_from_node_modules_Only_applicable_with_allowJs, 1447 defaultValueDescription: 0, 1448 }, 1449 { 1450 name: "noStrictGenericChecks", 1451 type: "boolean", 1452 affectsSemanticDiagnostics: true, 1453 affectsMultiFileEmitBuildInfo: true, 1454 category: Diagnostics.Backwards_Compatibility, 1455 description: Diagnostics.Disable_strict_checking_of_generic_signatures_in_function_types, 1456 defaultValueDescription: false, 1457 }, 1458 { 1459 name: "useDefineForClassFields", 1460 type: "boolean", 1461 affectsSemanticDiagnostics: true, 1462 affectsEmit: true, 1463 affectsMultiFileEmitBuildInfo: true, 1464 category: Diagnostics.Language_and_Environment, 1465 description: Diagnostics.Emit_ECMAScript_standard_compliant_class_fields, 1466 defaultValueDescription: Diagnostics.true_for_ES2022_and_above_including_ESNext 1467 }, 1468 { 1469 name: "preserveValueImports", 1470 type: "boolean", 1471 affectsEmit: true, 1472 affectsMultiFileEmitBuildInfo: true, 1473 category: Diagnostics.Emit, 1474 description: Diagnostics.Preserve_unused_imported_values_in_the_JavaScript_output_that_would_otherwise_be_removed, 1475 defaultValueDescription: false, 1476 }, 1477 1478 { 1479 name: "keyofStringsOnly", 1480 type: "boolean", 1481 category: Diagnostics.Backwards_Compatibility, 1482 description: Diagnostics.Make_keyof_only_return_strings_instead_of_string_numbers_or_symbols_Legacy_option, 1483 defaultValueDescription: false, 1484 }, 1485 { 1486 // A list of plugins to load in the language service 1487 name: "plugins", 1488 type: "list", 1489 isTSConfigOnly: true, 1490 element: { 1491 name: "plugin", 1492 type: "object" 1493 }, 1494 description: Diagnostics.Specify_a_list_of_language_service_plugins_to_include, 1495 category: Diagnostics.Editor_Support, 1496 1497 }, 1498 { 1499 name: "moduleDetection", 1500 type: new Map(getEntries({ 1501 auto: ModuleDetectionKind.Auto, 1502 legacy: ModuleDetectionKind.Legacy, 1503 force: ModuleDetectionKind.Force, 1504 })), 1505 affectsModuleResolution: true, 1506 description: Diagnostics.Control_what_method_is_used_to_detect_module_format_JS_files, 1507 category: Diagnostics.Language_and_Environment, 1508 defaultValueDescription: Diagnostics.auto_Colon_Treat_files_with_imports_exports_import_meta_jsx_with_jsx_Colon_react_jsx_or_esm_format_with_module_Colon_node16_as_modules, 1509 }, 1510 { 1511 name: "ignoreDeprecations", 1512 type: "string", 1513 defaultValueDescription: undefined, 1514 }, 1515 { 1516 name: "etsAnnotationsEnable", 1517 type: "boolean", 1518 affectsSemanticDiagnostics: true, 1519 affectsEmit: true, 1520 affectsMultiFileEmitBuildInfo: true, 1521 category: Diagnostics.Language_and_Environment, 1522 description: Diagnostics.Enable_support_of_ETS_annotations, 1523 defaultValueDescription: false, 1524 }, 1525]; 1526 1527/** @internal */ 1528export const optionDeclarations: CommandLineOption[] = [ 1529 ...commonOptionsWithBuild, 1530 ...commandOptionsWithoutBuild, 1531]; 1532 1533/** @internal */ 1534export const semanticDiagnosticsOptionDeclarations: readonly CommandLineOption[] = 1535 optionDeclarations.filter(option => !!option.affectsSemanticDiagnostics); 1536 1537/** @internal */ 1538export const affectsEmitOptionDeclarations: readonly CommandLineOption[] = 1539 optionDeclarations.filter(option => !!option.affectsEmit); 1540 1541/** @internal */ 1542export const affectsDeclarationPathOptionDeclarations: readonly CommandLineOption[] = 1543 optionDeclarations.filter(option => !!option.affectsDeclarationPath); 1544 1545/** @internal */ 1546export const moduleResolutionOptionDeclarations: readonly CommandLineOption[] = 1547 optionDeclarations.filter(option => !!option.affectsModuleResolution); 1548 1549/** @internal */ 1550export const sourceFileAffectingCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option => 1551 !!option.affectsSourceFile || !!option.affectsModuleResolution || !!option.affectsBindDiagnostics); 1552 1553/** @internal */ 1554export const optionsAffectingProgramStructure: readonly CommandLineOption[] = 1555 optionDeclarations.filter(option => !!option.affectsProgramStructure); 1556 1557/** @internal */ 1558export const transpileOptionValueCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option => 1559 hasProperty(option, "transpileOptionValue")); 1560 1561/** 1562 * Build related options 1563 * @internal 1564 */ 1565export const optionsForBuild: CommandLineOption[] = [ 1566 { 1567 name: "verbose", 1568 shortName: "v", 1569 category: Diagnostics.Command_line_Options, 1570 description: Diagnostics.Enable_verbose_logging, 1571 type: "boolean", 1572 defaultValueDescription: false, 1573 }, 1574 { 1575 name: "dry", 1576 shortName: "d", 1577 category: Diagnostics.Command_line_Options, 1578 description: Diagnostics.Show_what_would_be_built_or_deleted_if_specified_with_clean, 1579 type: "boolean", 1580 defaultValueDescription: false, 1581 }, 1582 { 1583 name: "force", 1584 shortName: "f", 1585 category: Diagnostics.Command_line_Options, 1586 description: Diagnostics.Build_all_projects_including_those_that_appear_to_be_up_to_date, 1587 type: "boolean", 1588 defaultValueDescription: false, 1589 }, 1590 { 1591 name: "clean", 1592 category: Diagnostics.Command_line_Options, 1593 description: Diagnostics.Delete_the_outputs_of_all_projects, 1594 type: "boolean", 1595 defaultValueDescription: false, 1596 } 1597]; 1598 1599/** @internal */ 1600export const buildOpts: CommandLineOption[] = [ 1601 ...commonOptionsWithBuild, 1602 ...optionsForBuild 1603]; 1604 1605/** @internal */ 1606export const typeAcquisitionDeclarations: CommandLineOption[] = [ 1607 { 1608 /* @deprecated typingOptions.enableAutoDiscovery 1609 * Use typeAcquisition.enable instead. 1610 */ 1611 name: "enableAutoDiscovery", 1612 type: "boolean", 1613 defaultValueDescription: false, 1614 }, 1615 { 1616 name: "enable", 1617 type: "boolean", 1618 defaultValueDescription: false, 1619 }, 1620 { 1621 name: "include", 1622 type: "list", 1623 element: { 1624 name: "include", 1625 type: "string" 1626 } 1627 }, 1628 { 1629 name: "exclude", 1630 type: "list", 1631 element: { 1632 name: "exclude", 1633 type: "string" 1634 } 1635 }, 1636 { 1637 name: "disableFilenameBasedTypeAcquisition", 1638 type: "boolean", 1639 defaultValueDescription: false, 1640 }, 1641]; 1642 1643/** @internal */ 1644export interface OptionsNameMap { 1645 optionsNameMap: ESMap<string, CommandLineOption>; 1646 shortOptionNames: ESMap<string, string>; 1647} 1648 1649/** @internal */ 1650export function createOptionNameMap(optionDeclarations: readonly CommandLineOption[]): OptionsNameMap { 1651 const optionsNameMap = new Map<string, CommandLineOption>(); 1652 const shortOptionNames = new Map<string, string>(); 1653 forEach(optionDeclarations, option => { 1654 optionsNameMap.set(option.name.toLowerCase(), option); 1655 if (option.shortName) { 1656 shortOptionNames.set(option.shortName, option.name); 1657 } 1658 }); 1659 1660 return { optionsNameMap, shortOptionNames }; 1661} 1662 1663let optionsNameMapCache: OptionsNameMap; 1664 1665/** @internal */ 1666export function getOptionsNameMap(): OptionsNameMap { 1667 return optionsNameMapCache ||= createOptionNameMap(optionDeclarations); 1668} 1669 1670const compilerOptionsAlternateMode: AlternateModeDiagnostics = { 1671 diagnostic: Diagnostics.Compiler_option_0_may_only_be_used_with_build, 1672 getOptionsNameMap: getBuildOptionsNameMap 1673}; 1674 1675/** @internal */ 1676export const defaultInitCompilerOptions: CompilerOptions = { 1677 module: ModuleKind.CommonJS, 1678 target: ScriptTarget.ES2016, 1679 strict: true, 1680 esModuleInterop: true, 1681 forceConsistentCasingInFileNames: true, 1682 skipLibCheck: true 1683}; 1684 1685/** @internal */ 1686export function convertEnableAutoDiscoveryToEnable(typeAcquisition: TypeAcquisition): TypeAcquisition { 1687 // Convert deprecated typingOptions.enableAutoDiscovery to typeAcquisition.enable 1688 if (typeAcquisition && typeAcquisition.enableAutoDiscovery !== undefined && typeAcquisition.enable === undefined) { 1689 return { 1690 enable: typeAcquisition.enableAutoDiscovery, 1691 include: typeAcquisition.include || [], 1692 exclude: typeAcquisition.exclude || [] 1693 }; 1694 } 1695 return typeAcquisition; 1696} 1697 1698/** @internal */ 1699export function createCompilerDiagnosticForInvalidCustomType(opt: CommandLineOptionOfCustomType): Diagnostic { 1700 return createDiagnosticForInvalidCustomType(opt, createCompilerDiagnostic); 1701} 1702 1703function createDiagnosticForInvalidCustomType(opt: CommandLineOptionOfCustomType, createDiagnostic: (message: DiagnosticMessage, arg0: string, arg1: string) => Diagnostic): Diagnostic { 1704 const namesOfType = arrayFrom(opt.type.keys()).map(key => `'${key}'`).join(", "); 1705 return createDiagnostic(Diagnostics.Argument_for_0_option_must_be_Colon_1, `--${opt.name}`, namesOfType); 1706} 1707 1708/** @internal */ 1709export function parseCustomTypeOption(opt: CommandLineOptionOfCustomType, value: string, errors: Push<Diagnostic>) { 1710 return convertJsonOptionOfCustomType(opt, trimString(value || ""), errors); 1711} 1712 1713/** @internal */ 1714export function parseListTypeOption(opt: CommandLineOptionOfListType, value = "", errors: Push<Diagnostic>): (string | number)[] | undefined { 1715 value = trimString(value); 1716 if (startsWith(value, "-")) { 1717 return undefined; 1718 } 1719 if (value === "") { 1720 return []; 1721 } 1722 const values = value.split(","); 1723 switch (opt.element.type) { 1724 case "number": 1725 return mapDefined(values, v => validateJsonOptionValue(opt.element, parseInt(v), errors)); 1726 case "string": 1727 return mapDefined(values, v => validateJsonOptionValue(opt.element, v || "", errors)); 1728 default: 1729 return mapDefined(values, v => parseCustomTypeOption(opt.element as CommandLineOptionOfCustomType, v, errors)); 1730 } 1731} 1732 1733/** @internal */ 1734export interface OptionsBase { 1735 [option: string]: CompilerOptionsValue | TsConfigSourceFile | undefined; 1736} 1737 1738/** @internal */ 1739export interface ParseCommandLineWorkerDiagnostics extends DidYouMeanOptionsDiagnostics { 1740 getOptionsNameMap: () => OptionsNameMap; 1741 optionTypeMismatchDiagnostic: DiagnosticMessage; 1742} 1743 1744function getOptionName(option: CommandLineOption) { 1745 return option.name; 1746} 1747 1748function createUnknownOptionError( 1749 unknownOption: string, 1750 diagnostics: DidYouMeanOptionsDiagnostics, 1751 createDiagnostics: (message: DiagnosticMessage, arg0: string, arg1?: string) => Diagnostic, 1752 unknownOptionErrorText?: string 1753) { 1754 if (diagnostics.alternateMode?.getOptionsNameMap().optionsNameMap.has(unknownOption.toLowerCase())) { 1755 return createDiagnostics(diagnostics.alternateMode.diagnostic, unknownOption); 1756 } 1757 1758 const possibleOption = getSpellingSuggestion(unknownOption, diagnostics.optionDeclarations, getOptionName); 1759 return possibleOption ? 1760 createDiagnostics(diagnostics.unknownDidYouMeanDiagnostic, unknownOptionErrorText || unknownOption, possibleOption.name) : 1761 createDiagnostics(diagnostics.unknownOptionDiagnostic, unknownOptionErrorText || unknownOption); 1762} 1763 1764/** @internal */ 1765export function parseCommandLineWorker( 1766 diagnostics: ParseCommandLineWorkerDiagnostics, 1767 commandLine: readonly string[], 1768 readFile?: (path: string) => string | undefined) { 1769 const options = {} as OptionsBase; 1770 let watchOptions: WatchOptions | undefined; 1771 const fileNames: string[] = []; 1772 const errors: Diagnostic[] = []; 1773 1774 parseStrings(commandLine); 1775 return { 1776 options, 1777 watchOptions, 1778 fileNames, 1779 errors 1780 }; 1781 1782 function parseStrings(args: readonly string[]) { 1783 let i = 0; 1784 while (i < args.length) { 1785 const s = args[i]; 1786 i++; 1787 if (s.charCodeAt(0) === CharacterCodes.at) { 1788 parseResponseFile(s.slice(1)); 1789 } 1790 else if (s.charCodeAt(0) === CharacterCodes.minus) { 1791 const inputOptionName = s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1); 1792 const opt = getOptionDeclarationFromName(diagnostics.getOptionsNameMap, inputOptionName, /*allowShort*/ true); 1793 if (opt) { 1794 i = parseOptionValue(args, i, diagnostics, opt, options, errors); 1795 } 1796 else { 1797 const watchOpt = getOptionDeclarationFromName(watchOptionsDidYouMeanDiagnostics.getOptionsNameMap, inputOptionName, /*allowShort*/ true); 1798 if (watchOpt) { 1799 i = parseOptionValue(args, i, watchOptionsDidYouMeanDiagnostics, watchOpt, watchOptions || (watchOptions = {}), errors); 1800 } 1801 else { 1802 errors.push(createUnknownOptionError(inputOptionName, diagnostics, createCompilerDiagnostic, s)); 1803 } 1804 } 1805 } 1806 else { 1807 fileNames.push(s); 1808 } 1809 } 1810 } 1811 1812 function parseResponseFile(fileName: string) { 1813 const text = tryReadFile(fileName, readFile || (fileName => sys.readFile(fileName))); 1814 if (!isString(text)) { 1815 errors.push(text); 1816 return; 1817 } 1818 1819 const args: string[] = []; 1820 let pos = 0; 1821 while (true) { 1822 while (pos < text.length && text.charCodeAt(pos) <= CharacterCodes.space) pos++; 1823 if (pos >= text.length) break; 1824 const start = pos; 1825 if (text.charCodeAt(start) === CharacterCodes.doubleQuote) { 1826 pos++; 1827 while (pos < text.length && text.charCodeAt(pos) !== CharacterCodes.doubleQuote) pos++; 1828 if (pos < text.length) { 1829 args.push(text.substring(start + 1, pos)); 1830 pos++; 1831 } 1832 else { 1833 errors.push(createCompilerDiagnostic(Diagnostics.Unterminated_quoted_string_in_response_file_0, fileName)); 1834 } 1835 } 1836 else { 1837 while (text.charCodeAt(pos) > CharacterCodes.space) pos++; 1838 args.push(text.substring(start, pos)); 1839 } 1840 } 1841 parseStrings(args); 1842 } 1843} 1844 1845function parseOptionValue( 1846 args: readonly string[], 1847 i: number, 1848 diagnostics: ParseCommandLineWorkerDiagnostics, 1849 opt: CommandLineOption, 1850 options: OptionsBase, 1851 errors: Diagnostic[] 1852) { 1853 if (opt.isTSConfigOnly) { 1854 const optValue = args[i]; 1855 if (optValue === "null") { 1856 options[opt.name] = undefined; 1857 i++; 1858 } 1859 else if (opt.type === "boolean") { 1860 if (optValue === "false") { 1861 options[opt.name] = validateJsonOptionValue(opt, /*value*/ false, errors); 1862 i++; 1863 } 1864 else { 1865 if (optValue === "true") i++; 1866 errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file_or_set_to_false_or_null_on_command_line, opt.name)); 1867 } 1868 } 1869 else { 1870 errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file_or_set_to_null_on_command_line, opt.name)); 1871 if (optValue && !startsWith(optValue, "-")) i++; 1872 } 1873 } 1874 else { 1875 // Check to see if no argument was provided (e.g. "--locale" is the last command-line argument). 1876 if (!args[i] && opt.type !== "boolean") { 1877 errors.push(createCompilerDiagnostic(diagnostics.optionTypeMismatchDiagnostic, opt.name, getCompilerOptionValueTypeString(opt))); 1878 } 1879 1880 if (args[i] !== "null") { 1881 switch (opt.type) { 1882 case "number": 1883 options[opt.name] = validateJsonOptionValue(opt, parseInt(args[i]), errors); 1884 i++; 1885 break; 1886 case "boolean": 1887 // boolean flag has optional value true, false, others 1888 const optValue = args[i]; 1889 options[opt.name] = validateJsonOptionValue(opt, optValue !== "false", errors); 1890 // consume next argument as boolean flag value 1891 if (optValue === "false" || optValue === "true") { 1892 i++; 1893 } 1894 break; 1895 case "string": 1896 options[opt.name] = validateJsonOptionValue(opt, args[i] || "", errors); 1897 i++; 1898 break; 1899 case "list": 1900 const result = parseListTypeOption(opt, args[i], errors); 1901 options[opt.name] = result || []; 1902 if (result) { 1903 i++; 1904 } 1905 break; 1906 // If not a primitive, the possible types are specified in what is effectively a map of options. 1907 default: 1908 options[opt.name] = parseCustomTypeOption(opt as CommandLineOptionOfCustomType, args[i], errors); 1909 i++; 1910 break; 1911 } 1912 } 1913 else { 1914 options[opt.name] = undefined; 1915 i++; 1916 } 1917 } 1918 return i; 1919} 1920 1921/** @internal */ 1922export const compilerOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnostics = { 1923 alternateMode: compilerOptionsAlternateMode, 1924 getOptionsNameMap, 1925 optionDeclarations, 1926 unknownOptionDiagnostic: Diagnostics.Unknown_compiler_option_0, 1927 unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, 1928 optionTypeMismatchDiagnostic: Diagnostics.Compiler_option_0_expects_an_argument 1929}; 1930export function parseCommandLine(commandLine: readonly string[], readFile?: (path: string) => string | undefined): ParsedCommandLine { 1931 return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine, readFile); 1932} 1933 1934/** @internal */ 1935export function getOptionFromName(optionName: string, allowShort?: boolean): CommandLineOption | undefined { 1936 return getOptionDeclarationFromName(getOptionsNameMap, optionName, allowShort); 1937} 1938 1939function getOptionDeclarationFromName(getOptionNameMap: () => OptionsNameMap, optionName: string, allowShort = false): CommandLineOption | undefined { 1940 optionName = optionName.toLowerCase(); 1941 const { optionsNameMap, shortOptionNames } = getOptionNameMap(); 1942 // Try to translate short option names to their full equivalents. 1943 if (allowShort) { 1944 const short = shortOptionNames.get(optionName); 1945 if (short !== undefined) { 1946 optionName = short; 1947 } 1948 } 1949 return optionsNameMap.get(optionName); 1950} 1951 1952/** @internal */ 1953export interface ParsedBuildCommand { 1954 buildOptions: BuildOptions; 1955 watchOptions: WatchOptions | undefined; 1956 projects: string[]; 1957 errors: Diagnostic[]; 1958} 1959 1960let buildOptionsNameMapCache: OptionsNameMap; 1961function getBuildOptionsNameMap(): OptionsNameMap { 1962 return buildOptionsNameMapCache || (buildOptionsNameMapCache = createOptionNameMap(buildOpts)); 1963} 1964 1965const buildOptionsAlternateMode: AlternateModeDiagnostics = { 1966 diagnostic: Diagnostics.Compiler_option_0_may_not_be_used_with_build, 1967 getOptionsNameMap 1968}; 1969 1970const buildOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnostics = { 1971 alternateMode: buildOptionsAlternateMode, 1972 getOptionsNameMap: getBuildOptionsNameMap, 1973 optionDeclarations: buildOpts, 1974 unknownOptionDiagnostic: Diagnostics.Unknown_build_option_0, 1975 unknownDidYouMeanDiagnostic: Diagnostics.Unknown_build_option_0_Did_you_mean_1, 1976 optionTypeMismatchDiagnostic: Diagnostics.Build_option_0_requires_a_value_of_type_1 1977}; 1978 1979/** @internal */ 1980export function parseBuildCommand(args: readonly string[]): ParsedBuildCommand { 1981 const { options, watchOptions, fileNames: projects, errors } = parseCommandLineWorker( 1982 buildOptionsDidYouMeanDiagnostics, 1983 args 1984 ); 1985 const buildOptions = options as BuildOptions; 1986 1987 if (projects.length === 0) { 1988 // tsc -b invoked with no extra arguments; act as if invoked with "tsc -b ." 1989 projects.push("."); 1990 } 1991 1992 // Nonsensical combinations 1993 if (buildOptions.clean && buildOptions.force) { 1994 errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force")); 1995 } 1996 if (buildOptions.clean && buildOptions.verbose) { 1997 errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose")); 1998 } 1999 if (buildOptions.clean && buildOptions.watch) { 2000 errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch")); 2001 } 2002 if (buildOptions.watch && buildOptions.dry) { 2003 errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry")); 2004 } 2005 2006 return { buildOptions, watchOptions, projects, errors }; 2007} 2008 2009/** @internal */ 2010export function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string { 2011 const diagnostic = createCompilerDiagnostic.apply(undefined, arguments); 2012 return diagnostic.messageText as string; 2013} 2014 2015export type DiagnosticReporter = (diagnostic: Diagnostic) => void; 2016/** 2017 * Reports config file diagnostics 2018 */ 2019export interface ConfigFileDiagnosticsReporter { 2020 /** 2021 * Reports unrecoverable error when parsing config file 2022 */ 2023 onUnRecoverableConfigFileDiagnostic: DiagnosticReporter; 2024} 2025 2026/** 2027 * Interface extending ParseConfigHost to support ParseConfigFile that reads config file and reports errors 2028 */ 2029export interface ParseConfigFileHost extends ParseConfigHost, ConfigFileDiagnosticsReporter { 2030 getCurrentDirectory(): string; 2031} 2032 2033/** 2034 * Reads the config file, reports errors if any and exits if the config file cannot be found 2035 */ 2036export function getParsedCommandLineOfConfigFile( 2037 configFileName: string, 2038 optionsToExtend: CompilerOptions | undefined, 2039 host: ParseConfigFileHost, 2040 extendedConfigCache?: Map<ExtendedConfigCacheEntry>, 2041 watchOptionsToExtend?: WatchOptions, 2042 extraFileExtensions?: readonly FileExtensionInfo[], 2043): ParsedCommandLine | undefined { 2044 const configFileText = tryReadFile(configFileName, fileName => host.readFile(fileName)); 2045 if (!isString(configFileText)) { 2046 host.onUnRecoverableConfigFileDiagnostic(configFileText); 2047 return undefined; 2048 } 2049 2050 const result = parseJsonText(configFileName, configFileText); 2051 const cwd = host.getCurrentDirectory(); 2052 result.path = toPath(configFileName, cwd, createGetCanonicalFileName(host.useCaseSensitiveFileNames)); 2053 result.resolvedPath = result.path; 2054 result.originalFileName = result.fileName; 2055 return parseJsonSourceFileConfigFileContent( 2056 result, 2057 host, 2058 getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), 2059 optionsToExtend, 2060 getNormalizedAbsolutePath(configFileName, cwd), 2061 /*resolutionStack*/ undefined, 2062 extraFileExtensions, 2063 extendedConfigCache, 2064 watchOptionsToExtend 2065 ); 2066} 2067 2068/** 2069 * Read tsconfig.json file 2070 * @param fileName The path to the config file 2071 */ 2072export function readConfigFile(fileName: string, readFile: (path: string) => string | undefined): { config?: any; error?: Diagnostic } { 2073 const textOrDiagnostic = tryReadFile(fileName, readFile); 2074 return isString(textOrDiagnostic) ? parseConfigFileTextToJson(fileName, textOrDiagnostic) : { config: {}, error: textOrDiagnostic }; 2075} 2076 2077/** 2078 * Parse the text of the tsconfig.json file 2079 * @param fileName The path to the config file 2080 * @param jsonText The text of the config file 2081 */ 2082export function parseConfigFileTextToJson(fileName: string, jsonText: string): { config?: any; error?: Diagnostic } { 2083 const jsonSourceFile = parseJsonText(fileName, jsonText); 2084 return { 2085 config: convertConfigFileToObject(jsonSourceFile, jsonSourceFile.parseDiagnostics, /*reportOptionsErrors*/ false, /*optionsIterator*/ undefined), 2086 error: jsonSourceFile.parseDiagnostics.length ? jsonSourceFile.parseDiagnostics[0] : undefined 2087 }; 2088} 2089 2090/** 2091 * Read tsconfig.json file 2092 * @param fileName The path to the config file 2093 */ 2094export function readJsonConfigFile(fileName: string, readFile: (path: string) => string | undefined): TsConfigSourceFile { 2095 const textOrDiagnostic = tryReadFile(fileName, readFile); 2096 return isString(textOrDiagnostic) ? parseJsonText(fileName, textOrDiagnostic) : { fileName, parseDiagnostics: [textOrDiagnostic] } as TsConfigSourceFile; 2097} 2098 2099/** @internal */ 2100export function tryReadFile(fileName: string, readFile: (path: string) => string | undefined): string | Diagnostic { 2101 let text: string | undefined; 2102 try { 2103 text = readFile(fileName); 2104 } 2105 catch (e) { 2106 return createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message); 2107 } 2108 return text === undefined ? createCompilerDiagnostic(Diagnostics.Cannot_read_file_0, fileName) : text; 2109} 2110 2111function commandLineOptionsToMap(options: readonly CommandLineOption[]) { 2112 return arrayToMap(options, getOptionName); 2113} 2114 2115const typeAcquisitionDidYouMeanDiagnostics: DidYouMeanOptionsDiagnostics = { 2116 optionDeclarations: typeAcquisitionDeclarations, 2117 unknownOptionDiagnostic: Diagnostics.Unknown_type_acquisition_option_0, 2118 unknownDidYouMeanDiagnostic: Diagnostics.Unknown_type_acquisition_option_0_Did_you_mean_1, 2119}; 2120 2121let watchOptionsNameMapCache: OptionsNameMap; 2122function getWatchOptionsNameMap(): OptionsNameMap { 2123 return watchOptionsNameMapCache || (watchOptionsNameMapCache = createOptionNameMap(optionsForWatch)); 2124} 2125const watchOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnostics = { 2126 getOptionsNameMap: getWatchOptionsNameMap, 2127 optionDeclarations: optionsForWatch, 2128 unknownOptionDiagnostic: Diagnostics.Unknown_watch_option_0, 2129 unknownDidYouMeanDiagnostic: Diagnostics.Unknown_watch_option_0_Did_you_mean_1, 2130 optionTypeMismatchDiagnostic: Diagnostics.Watch_option_0_requires_a_value_of_type_1 2131}; 2132 2133let commandLineCompilerOptionsMapCache: ESMap<string, CommandLineOption>; 2134function getCommandLineCompilerOptionsMap() { 2135 return commandLineCompilerOptionsMapCache || (commandLineCompilerOptionsMapCache = commandLineOptionsToMap(optionDeclarations)); 2136} 2137let commandLineWatchOptionsMapCache: ESMap<string, CommandLineOption>; 2138function getCommandLineWatchOptionsMap() { 2139 return commandLineWatchOptionsMapCache || (commandLineWatchOptionsMapCache = commandLineOptionsToMap(optionsForWatch)); 2140} 2141let commandLineTypeAcquisitionMapCache: ESMap<string, CommandLineOption>; 2142function getCommandLineTypeAcquisitionMap() { 2143 return commandLineTypeAcquisitionMapCache || (commandLineTypeAcquisitionMapCache = commandLineOptionsToMap(typeAcquisitionDeclarations)); 2144} 2145 2146let _tsconfigRootOptions: TsConfigOnlyOption; 2147function getTsconfigRootOptionsMap() { 2148 if (_tsconfigRootOptions === undefined) { 2149 _tsconfigRootOptions = { 2150 name: undefined!, // should never be needed since this is root 2151 type: "object", 2152 elementOptions: commandLineOptionsToMap([ 2153 { 2154 name: "compilerOptions", 2155 type: "object", 2156 elementOptions: getCommandLineCompilerOptionsMap(), 2157 extraKeyDiagnostics: compilerOptionsDidYouMeanDiagnostics, 2158 }, 2159 { 2160 name: "watchOptions", 2161 type: "object", 2162 elementOptions: getCommandLineWatchOptionsMap(), 2163 extraKeyDiagnostics: watchOptionsDidYouMeanDiagnostics, 2164 }, 2165 { 2166 name: "typingOptions", 2167 type: "object", 2168 elementOptions: getCommandLineTypeAcquisitionMap(), 2169 extraKeyDiagnostics: typeAcquisitionDidYouMeanDiagnostics, 2170 }, 2171 { 2172 name: "typeAcquisition", 2173 type: "object", 2174 elementOptions: getCommandLineTypeAcquisitionMap(), 2175 extraKeyDiagnostics: typeAcquisitionDidYouMeanDiagnostics 2176 }, 2177 { 2178 name: "extends", 2179 type: "string", 2180 category: Diagnostics.File_Management, 2181 }, 2182 { 2183 name: "references", 2184 type: "list", 2185 element: { 2186 name: "references", 2187 type: "object" 2188 }, 2189 category: Diagnostics.Projects, 2190 }, 2191 { 2192 name: "files", 2193 type: "list", 2194 element: { 2195 name: "files", 2196 type: "string" 2197 }, 2198 category: Diagnostics.File_Management, 2199 }, 2200 { 2201 name: "include", 2202 type: "list", 2203 element: { 2204 name: "include", 2205 type: "string" 2206 }, 2207 category: Diagnostics.File_Management, 2208 defaultValueDescription: Diagnostics.if_files_is_specified_otherwise_Asterisk_Asterisk_Slash_Asterisk 2209 }, 2210 { 2211 name: "exclude", 2212 type: "list", 2213 element: { 2214 name: "exclude", 2215 type: "string" 2216 }, 2217 category: Diagnostics.File_Management, 2218 defaultValueDescription: Diagnostics.node_modules_bower_components_jspm_packages_plus_the_value_of_outDir_if_one_is_specified 2219 }, 2220 compileOnSaveCommandLineOption 2221 ]) 2222 }; 2223 } 2224 return _tsconfigRootOptions; 2225} 2226 2227/** @internal */ 2228export interface JsonConversionNotifier { 2229 /** 2230 * Notifies parent option object is being set with the optionKey and a valid optionValue 2231 * Currently it notifies only if there is element with type object (parentOption) and 2232 * has element's option declarations map associated with it 2233 * @param parentOption parent option name in which the option and value are being set 2234 * @param option option declaration which is being set with the value 2235 * @param value value of the option 2236 */ 2237 onSetValidOptionKeyValueInParent(parentOption: string, option: CommandLineOption, value: CompilerOptionsValue): void; 2238 /** 2239 * Notify when valid root key value option is being set 2240 * @param key option key 2241 * @param keyNode node corresponding to node in the source file 2242 * @param value computed value of the key 2243 * @param ValueNode node corresponding to value in the source file 2244 */ 2245 onSetValidOptionKeyValueInRoot(key: string, keyNode: PropertyName, value: CompilerOptionsValue, valueNode: Expression): void; 2246 /** 2247 * Notify when unknown root key value option is being set 2248 * @param key option key 2249 * @param keyNode node corresponding to node in the source file 2250 * @param value computed value of the key 2251 * @param ValueNode node corresponding to value in the source file 2252 */ 2253 onSetUnknownOptionKeyValueInRoot(key: string, keyNode: PropertyName, value: CompilerOptionsValue, valueNode: Expression): void; 2254} 2255 2256function convertConfigFileToObject(sourceFile: JsonSourceFile, errors: Push<Diagnostic>, reportOptionsErrors: boolean, optionsIterator: JsonConversionNotifier | undefined): any { 2257 const rootExpression: Expression | undefined = sourceFile.statements[0]?.expression; 2258 const knownRootOptions = reportOptionsErrors ? getTsconfigRootOptionsMap() : undefined; 2259 if (rootExpression && rootExpression.kind !== SyntaxKind.ObjectLiteralExpression) { 2260 errors.push(createDiagnosticForNodeInSourceFile( 2261 sourceFile, 2262 rootExpression, 2263 Diagnostics.The_root_value_of_a_0_file_must_be_an_object, 2264 getBaseFileName(sourceFile.fileName) === "jsconfig.json" ? "jsconfig.json" : "tsconfig.json" 2265 )); 2266 // Last-ditch error recovery. Somewhat useful because the JSON parser will recover from some parse errors by 2267 // synthesizing a top-level array literal expression. There's a reasonable chance the first element of that 2268 // array is a well-formed configuration object, made into an array element by stray characters. 2269 if (isArrayLiteralExpression(rootExpression)) { 2270 const firstObject = find(rootExpression.elements, isObjectLiteralExpression); 2271 if (firstObject) { 2272 return convertToObjectWorker(sourceFile, firstObject, errors, /*returnValue*/ true, knownRootOptions, optionsIterator); 2273 } 2274 } 2275 return {}; 2276 } 2277 return convertToObjectWorker(sourceFile, rootExpression, errors, /*returnValue*/ true, knownRootOptions, optionsIterator); 2278} 2279 2280/** 2281 * Convert the json syntax tree into the json value 2282 */ 2283export function convertToObject(sourceFile: JsonSourceFile, errors: Push<Diagnostic>): any { 2284 return convertToObjectWorker(sourceFile, sourceFile.statements[0]?.expression, errors, /*returnValue*/ true, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined); 2285} 2286 2287/** 2288 * Convert the json syntax tree into the json value and report errors 2289 * This returns the json value (apart from checking errors) only if returnValue provided is true. 2290 * Otherwise it just checks the errors and returns undefined 2291 * @internal 2292 */ 2293export function convertToObjectWorker( 2294 sourceFile: JsonSourceFile, 2295 rootExpression: Expression | undefined, 2296 errors: Push<Diagnostic>, 2297 returnValue: boolean, 2298 knownRootOptions: CommandLineOption | undefined, 2299 jsonConversionNotifier: JsonConversionNotifier | undefined): any { 2300 if (!rootExpression) { 2301 return returnValue ? {} : undefined; 2302 } 2303 2304 return convertPropertyValueToJson(rootExpression, knownRootOptions); 2305 2306 function isRootOptionMap(knownOptions: ESMap<string, CommandLineOption> | undefined) { 2307 return knownRootOptions && (knownRootOptions as TsConfigOnlyOption).elementOptions === knownOptions; 2308 } 2309 2310 function convertObjectLiteralExpressionToJson( 2311 node: ObjectLiteralExpression, 2312 knownOptions: ESMap<string, CommandLineOption> | undefined, 2313 extraKeyDiagnostics: DidYouMeanOptionsDiagnostics | undefined, 2314 parentOption: string | undefined 2315 ): any { 2316 const result: any = returnValue ? {} : undefined; 2317 for (const element of node.properties) { 2318 if (element.kind !== SyntaxKind.PropertyAssignment) { 2319 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element, Diagnostics.Property_assignment_expected)); 2320 continue; 2321 } 2322 2323 if (element.questionToken) { 2324 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.questionToken, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, "?")); 2325 } 2326 if (!isDoubleQuotedString(element.name)) { 2327 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.name, Diagnostics.String_literal_with_double_quotes_expected)); 2328 } 2329 2330 const textOfKey = isComputedNonLiteralName(element.name) ? undefined : getTextOfPropertyName(element.name); 2331 const keyText = textOfKey && unescapeLeadingUnderscores(textOfKey); 2332 const option = keyText && knownOptions ? knownOptions.get(keyText) : undefined; 2333 if (keyText && extraKeyDiagnostics && !option) { 2334 if (knownOptions) { 2335 errors.push(createUnknownOptionError( 2336 keyText, 2337 extraKeyDiagnostics, 2338 (message, arg0, arg1) => createDiagnosticForNodeInSourceFile(sourceFile, element.name, message, arg0, arg1) 2339 )); 2340 } 2341 else { 2342 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.name, extraKeyDiagnostics.unknownOptionDiagnostic, keyText)); 2343 } 2344 } 2345 const value = convertPropertyValueToJson(element.initializer, option); 2346 if (typeof keyText !== "undefined") { 2347 if (returnValue) { 2348 result[keyText] = value; 2349 } 2350 // Notify key value set, if user asked for it 2351 if (jsonConversionNotifier && 2352 // Current callbacks are only on known parent option or if we are setting values in the root 2353 (parentOption || isRootOptionMap(knownOptions))) { 2354 const isValidOptionValue = isCompilerOptionsValue(option, value); 2355 if (parentOption) { 2356 if (isValidOptionValue) { 2357 // Notify option set in the parent if its a valid option value 2358 jsonConversionNotifier.onSetValidOptionKeyValueInParent(parentOption, option!, value); 2359 } 2360 } 2361 else if (isRootOptionMap(knownOptions)) { 2362 if (isValidOptionValue) { 2363 // Notify about the valid root key value being set 2364 jsonConversionNotifier.onSetValidOptionKeyValueInRoot(keyText, element.name, value, element.initializer); 2365 } 2366 else if (!option) { 2367 // Notify about the unknown root key value being set 2368 jsonConversionNotifier.onSetUnknownOptionKeyValueInRoot(keyText, element.name, value, element.initializer); 2369 } 2370 } 2371 } 2372 } 2373 } 2374 return result; 2375 } 2376 2377 function convertArrayLiteralExpressionToJson( 2378 elements: NodeArray<Expression>, 2379 elementOption: CommandLineOption | undefined 2380 ) { 2381 if (!returnValue) { 2382 elements.forEach(element => convertPropertyValueToJson(element, elementOption)); 2383 return undefined; 2384 } 2385 2386 // Filter out invalid values 2387 return filter(elements.map(element => convertPropertyValueToJson(element, elementOption)), v => v !== undefined); 2388 } 2389 2390 function convertPropertyValueToJson(valueExpression: Expression, option: CommandLineOption | undefined): any { 2391 let invalidReported: boolean | undefined; 2392 switch (valueExpression.kind) { 2393 case SyntaxKind.TrueKeyword: 2394 reportInvalidOptionValue(option && option.type !== "boolean"); 2395 return validateValue(/*value*/ true); 2396 2397 case SyntaxKind.FalseKeyword: 2398 reportInvalidOptionValue(option && option.type !== "boolean"); 2399 return validateValue(/*value*/ false); 2400 2401 case SyntaxKind.NullKeyword: 2402 reportInvalidOptionValue(option && option.name === "extends"); // "extends" is the only option we don't allow null/undefined for 2403 return validateValue(/*value*/ null); // eslint-disable-line no-null/no-null 2404 2405 case SyntaxKind.StringLiteral: 2406 if (!isDoubleQuotedString(valueExpression)) { 2407 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.String_literal_with_double_quotes_expected)); 2408 } 2409 reportInvalidOptionValue(option && (isString(option.type) && option.type !== "string")); 2410 const text = (valueExpression as StringLiteral).text; 2411 if (option && !isString(option.type)) { 2412 const customOption = option as CommandLineOptionOfCustomType; 2413 // Validate custom option type 2414 if (!customOption.type.has(text.toLowerCase())) { 2415 errors.push( 2416 createDiagnosticForInvalidCustomType( 2417 customOption, 2418 (message, arg0, arg1) => createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, message, arg0, arg1) 2419 ) 2420 ); 2421 invalidReported = true; 2422 } 2423 } 2424 return validateValue(text); 2425 2426 case SyntaxKind.NumericLiteral: 2427 reportInvalidOptionValue(option && option.type !== "number"); 2428 return validateValue(Number((valueExpression as NumericLiteral).text)); 2429 2430 case SyntaxKind.PrefixUnaryExpression: 2431 if ((valueExpression as PrefixUnaryExpression).operator !== SyntaxKind.MinusToken || (valueExpression as PrefixUnaryExpression).operand.kind !== SyntaxKind.NumericLiteral) { 2432 break; // not valid JSON syntax 2433 } 2434 reportInvalidOptionValue(option && option.type !== "number"); 2435 return validateValue(-Number(((valueExpression as PrefixUnaryExpression).operand as NumericLiteral).text)); 2436 2437 case SyntaxKind.ObjectLiteralExpression: 2438 reportInvalidOptionValue(option && option.type !== "object"); 2439 const objectLiteralExpression = valueExpression as ObjectLiteralExpression; 2440 2441 // Currently having element option declaration in the tsconfig with type "object" 2442 // determines if it needs onSetValidOptionKeyValueInParent callback or not 2443 // At moment there are only "compilerOptions", "typeAcquisition" and "typingOptions" 2444 // that satifies it and need it to modify options set in them (for normalizing file paths) 2445 // vs what we set in the json 2446 // If need arises, we can modify this interface and callbacks as needed 2447 if (option) { 2448 const { elementOptions, extraKeyDiagnostics, name: optionName } = option as TsConfigOnlyOption; 2449 return validateValue(convertObjectLiteralExpressionToJson(objectLiteralExpression, 2450 elementOptions, extraKeyDiagnostics, optionName)); 2451 } 2452 else { 2453 return validateValue(convertObjectLiteralExpressionToJson( 2454 objectLiteralExpression, /* knownOptions*/ undefined, 2455 /*extraKeyDiagnosticMessage */ undefined, /*parentOption*/ undefined)); 2456 } 2457 2458 case SyntaxKind.ArrayLiteralExpression: 2459 reportInvalidOptionValue(option && option.type !== "list"); 2460 return validateValue(convertArrayLiteralExpressionToJson( 2461 (valueExpression as ArrayLiteralExpression).elements, 2462 option && (option as CommandLineOptionOfListType).element)); 2463 } 2464 2465 // Not in expected format 2466 if (option) { 2467 reportInvalidOptionValue(/*isError*/ true); 2468 } 2469 else { 2470 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.Property_value_can_only_be_string_literal_numeric_literal_true_false_null_object_literal_or_array_literal)); 2471 } 2472 2473 return undefined; 2474 2475 function validateValue(value: CompilerOptionsValue) { 2476 if (!invalidReported) { 2477 const diagnostic = option?.extraValidation?.(value); 2478 if (diagnostic) { 2479 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, ...diagnostic)); 2480 return undefined; 2481 } 2482 } 2483 return value; 2484 } 2485 2486 function reportInvalidOptionValue(isError: boolean | undefined) { 2487 if (isError) { 2488 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.Compiler_option_0_requires_a_value_of_type_1, option!.name, getCompilerOptionValueTypeString(option!))); 2489 invalidReported = true; 2490 } 2491 } 2492 } 2493 2494 function isDoubleQuotedString(node: Node): boolean { 2495 return isStringLiteral(node) && isStringDoubleQuoted(node, sourceFile); 2496 } 2497} 2498 2499function getCompilerOptionValueTypeString(option: CommandLineOption) { 2500 return option.type === "list" ? 2501 "Array" : 2502 isString(option.type) ? option.type : "string"; 2503} 2504 2505function isCompilerOptionsValue(option: CommandLineOption | undefined, value: any): value is CompilerOptionsValue { 2506 if (option) { 2507 if (isNullOrUndefined(value)) return true; // All options are undefinable/nullable 2508 if (option.type === "list") { 2509 return isArray(value); 2510 } 2511 const expectedType = isString(option.type) ? option.type : "string"; 2512 return typeof value === expectedType; 2513 } 2514 return false; 2515} 2516 2517/** @internal */ 2518export interface TSConfig { 2519 compilerOptions: CompilerOptions; 2520 compileOnSave: boolean | undefined; 2521 exclude?: readonly string[]; 2522 files: readonly string[] | undefined; 2523 include?: readonly string[]; 2524 references: readonly ProjectReference[] | undefined; 2525} 2526 2527/** @internal */ 2528export interface ConvertToTSConfigHost { 2529 getCurrentDirectory(): string; 2530 useCaseSensitiveFileNames: boolean; 2531} 2532 2533/** 2534 * Generate an uncommented, complete tsconfig for use with "--showConfig" 2535 * @param configParseResult options to be generated into tsconfig.json 2536 * @param configFileName name of the parsed config file - output paths will be generated relative to this 2537 * @param host provides current directory and case sensitivity services 2538 * 2539 * @internal 2540 */ 2541export function convertToTSConfig(configParseResult: ParsedCommandLine, configFileName: string, host: ConvertToTSConfigHost): TSConfig { 2542 const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames); 2543 const files = map( 2544 filter( 2545 configParseResult.fileNames, 2546 !configParseResult.options.configFile?.configFileSpecs?.validatedIncludeSpecs ? returnTrue : matchesSpecs( 2547 configFileName, 2548 configParseResult.options.configFile.configFileSpecs.validatedIncludeSpecs, 2549 configParseResult.options.configFile.configFileSpecs.validatedExcludeSpecs, 2550 host, 2551 ) 2552 ), 2553 f => getRelativePathFromFile(getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), getNormalizedAbsolutePath(f, host.getCurrentDirectory()), getCanonicalFileName) 2554 ); 2555 const optionMap = serializeCompilerOptions(configParseResult.options, { configFilePath: getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), useCaseSensitiveFileNames: host.useCaseSensitiveFileNames }); 2556 const watchOptionMap = configParseResult.watchOptions && serializeWatchOptions(configParseResult.watchOptions); 2557 const config = { 2558 compilerOptions: { 2559 ...optionMapToObject(optionMap), 2560 showConfig: undefined, 2561 configFile: undefined, 2562 configFilePath: undefined, 2563 help: undefined, 2564 init: undefined, 2565 listFiles: undefined, 2566 listEmittedFiles: undefined, 2567 project: undefined, 2568 build: undefined, 2569 version: undefined, 2570 }, 2571 watchOptions: watchOptionMap && optionMapToObject(watchOptionMap), 2572 references: map(configParseResult.projectReferences, r => ({ ...r, path: r.originalPath ? r.originalPath : "", originalPath: undefined })), 2573 files: length(files) ? files : undefined, 2574 ...(configParseResult.options.configFile?.configFileSpecs ? { 2575 include: filterSameAsDefaultInclude(configParseResult.options.configFile.configFileSpecs.validatedIncludeSpecs), 2576 exclude: configParseResult.options.configFile.configFileSpecs.validatedExcludeSpecs 2577 } : {}), 2578 compileOnSave: !!configParseResult.compileOnSave ? true : undefined 2579 }; 2580 return config; 2581} 2582 2583function optionMapToObject(optionMap: ESMap<string, CompilerOptionsValue>): object { 2584 return { 2585 ...arrayFrom(optionMap.entries()).reduce((prev, cur) => ({ ...prev, [cur[0]]: cur[1] }), {}), 2586 }; 2587} 2588 2589function filterSameAsDefaultInclude(specs: readonly string[] | undefined) { 2590 if (!length(specs)) return undefined; 2591 if (length(specs) !== 1) return specs; 2592 if (specs![0] === defaultIncludeSpec) return undefined; 2593 return specs; 2594} 2595 2596function matchesSpecs(path: string, includeSpecs: readonly string[] | undefined, excludeSpecs: readonly string[] | undefined, host: ConvertToTSConfigHost): (path: string) => boolean { 2597 if (!includeSpecs) return returnTrue; 2598 const patterns = getFileMatcherPatterns(path, excludeSpecs, includeSpecs, host.useCaseSensitiveFileNames, host.getCurrentDirectory()); 2599 const excludeRe = patterns.excludePattern && getRegexFromPattern(patterns.excludePattern, host.useCaseSensitiveFileNames); 2600 const includeRe = patterns.includeFilePattern && getRegexFromPattern(patterns.includeFilePattern, host.useCaseSensitiveFileNames); 2601 if (includeRe) { 2602 if (excludeRe) { 2603 return path => !(includeRe.test(path) && !excludeRe.test(path)); 2604 } 2605 return path => !includeRe.test(path); 2606 } 2607 if (excludeRe) { 2608 return path => excludeRe.test(path); 2609 } 2610 return returnTrue; 2611} 2612 2613function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption): ESMap<string, string | number> | undefined { 2614 if (optionDefinition.type === "string" || optionDefinition.type === "number" || optionDefinition.type === "boolean" || optionDefinition.type === "object") { 2615 // this is of a type CommandLineOptionOfPrimitiveType 2616 return undefined; 2617 } 2618 else if (optionDefinition.type === "list") { 2619 return getCustomTypeMapOfCommandLineOption(optionDefinition.element); 2620 } 2621 else { 2622 return optionDefinition.type; 2623 } 2624} 2625 2626/** @internal */ 2627export function getNameOfCompilerOptionValue(value: CompilerOptionsValue, customTypeMap: ESMap<string, string | number>): string | undefined { 2628 // There is a typeMap associated with this command-line option so use it to map value back to its name 2629 return forEachEntry(customTypeMap, (mapValue, key) => { 2630 if (mapValue === value) { 2631 return key; 2632 } 2633 }); 2634} 2635 2636function serializeCompilerOptions( 2637 options: CompilerOptions, 2638 pathOptions?: { configFilePath: string, useCaseSensitiveFileNames: boolean } 2639): ESMap<string, CompilerOptionsValue> { 2640 return serializeOptionBaseObject(options, getOptionsNameMap(), pathOptions); 2641} 2642 2643function serializeWatchOptions(options: WatchOptions) { 2644 return serializeOptionBaseObject(options, getWatchOptionsNameMap()); 2645} 2646 2647function serializeOptionBaseObject( 2648 options: OptionsBase, 2649 { optionsNameMap }: OptionsNameMap, 2650 pathOptions?: { configFilePath: string, useCaseSensitiveFileNames: boolean } 2651): ESMap<string, CompilerOptionsValue> { 2652 const result = new Map<string, CompilerOptionsValue>(); 2653 const getCanonicalFileName = pathOptions && createGetCanonicalFileName(pathOptions.useCaseSensitiveFileNames); 2654 2655 for (const name in options) { 2656 if (hasProperty(options, name)) { 2657 // tsconfig only options cannot be specified via command line, 2658 // so we can assume that only types that can appear here string | number | boolean 2659 if (optionsNameMap.has(name) && (optionsNameMap.get(name)!.category === Diagnostics.Command_line_Options || optionsNameMap.get(name)!.category === Diagnostics.Output_Formatting)) { 2660 continue; 2661 } 2662 const value = options[name] as CompilerOptionsValue; 2663 const optionDefinition = optionsNameMap.get(name.toLowerCase()); 2664 if (optionDefinition) { 2665 const customTypeMap = getCustomTypeMapOfCommandLineOption(optionDefinition); 2666 if (!customTypeMap) { 2667 // There is no map associated with this compiler option then use the value as-is 2668 // This is the case if the value is expect to be string, number, boolean or list of string 2669 if (pathOptions && optionDefinition.isFilePath) { 2670 result.set(name, getRelativePathFromFile(pathOptions.configFilePath, getNormalizedAbsolutePath(value as string, getDirectoryPath(pathOptions.configFilePath)), getCanonicalFileName!)); 2671 } 2672 else { 2673 result.set(name, value); 2674 } 2675 } 2676 else { 2677 if (optionDefinition.type === "list") { 2678 result.set(name, (value as readonly (string | number)[]).map(element => getNameOfCompilerOptionValue(element, customTypeMap)!)); // TODO: GH#18217 2679 } 2680 else { 2681 // There is a typeMap associated with this command-line option so use it to map value back to its name 2682 result.set(name, getNameOfCompilerOptionValue(value, customTypeMap)); 2683 } 2684 } 2685 } 2686 } 2687 } 2688 return result; 2689} 2690 2691/** 2692 * Generate a list of the compiler options whose value is not the default. 2693 * @param options compilerOptions to be evaluated.' 2694 * 2695 * @internal 2696 */ 2697export function getCompilerOptionsDiffValue(options: CompilerOptions, newLine: string): string { 2698 const compilerOptionsMap = getSerializedCompilerOption(options); 2699 return getOverwrittenDefaultOptions(); 2700 2701 function makePadding(paddingLength: number): string { 2702 return Array(paddingLength + 1).join(" "); 2703 } 2704 2705 function getOverwrittenDefaultOptions() { 2706 const result: string[] = []; 2707 const tab = makePadding(2); 2708 commandOptionsWithoutBuild.forEach(cmd => { 2709 if (!compilerOptionsMap.has(cmd.name)) { 2710 return; 2711 } 2712 2713 const newValue = compilerOptionsMap.get(cmd.name); 2714 const defaultValue = getDefaultValueForOption(cmd); 2715 if (newValue !== defaultValue) { 2716 result.push(`${tab}${cmd.name}: ${newValue}`); 2717 } 2718 else if (hasProperty(defaultInitCompilerOptions, cmd.name)) { 2719 result.push(`${tab}${cmd.name}: ${defaultValue}`); 2720 } 2721 }); 2722 return result.join(newLine) + newLine; 2723 } 2724} 2725 2726/** 2727 * Get the compiler options to be written into the tsconfig.json. 2728 * @param options commandlineOptions to be included in the compileOptions. 2729 */ 2730function getSerializedCompilerOption(options: CompilerOptions): ESMap<string, CompilerOptionsValue> { 2731 const compilerOptions = extend(options, defaultInitCompilerOptions); 2732 return serializeCompilerOptions(compilerOptions); 2733} 2734/** 2735 * Generate tsconfig configuration when running command line "--init" 2736 * @param options commandlineOptions to be generated into tsconfig.json 2737 * @param fileNames array of filenames to be generated into tsconfig.json 2738 * 2739 * @internal 2740 */ 2741export function generateTSConfig(options: CompilerOptions, fileNames: readonly string[], newLine: string): string { 2742 const compilerOptionsMap = getSerializedCompilerOption(options); 2743 return writeConfigurations(); 2744 2745 function makePadding(paddingLength: number): string { 2746 return Array(paddingLength + 1).join(" "); 2747 } 2748 2749 function isAllowedOptionForOutput({ category, name, isCommandLineOnly }: CommandLineOption): boolean { 2750 // Skip options which do not have a category or have categories which are more niche 2751 const categoriesToSkip = [Diagnostics.Command_line_Options, Diagnostics.Editor_Support, Diagnostics.Compiler_Diagnostics, Diagnostics.Backwards_Compatibility, Diagnostics.Watch_and_Build_Modes, Diagnostics.Output_Formatting]; 2752 return !isCommandLineOnly && category !== undefined && (!categoriesToSkip.includes(category) || compilerOptionsMap.has(name)); 2753 } 2754 2755 function writeConfigurations() { 2756 // Filter applicable options to place in the file 2757 const categorizedOptions = new Map<DiagnosticMessage, CommandLineOption[]>(); 2758 // Set allowed categories in order 2759 categorizedOptions.set(Diagnostics.Projects, []); 2760 categorizedOptions.set(Diagnostics.Language_and_Environment, []); 2761 categorizedOptions.set(Diagnostics.Modules, []); 2762 categorizedOptions.set(Diagnostics.JavaScript_Support, []); 2763 categorizedOptions.set(Diagnostics.Emit, []); 2764 categorizedOptions.set(Diagnostics.Interop_Constraints, []); 2765 categorizedOptions.set(Diagnostics.Type_Checking, []); 2766 categorizedOptions.set(Diagnostics.Completeness, []); 2767 for (const option of optionDeclarations) { 2768 if (isAllowedOptionForOutput(option)) { 2769 let listForCategory = categorizedOptions.get(option.category!); 2770 if (!listForCategory) categorizedOptions.set(option.category!, listForCategory = []); 2771 listForCategory.push(option); 2772 } 2773 } 2774 2775 // Serialize all options and their descriptions 2776 let marginLength = 0; 2777 let seenKnownKeys = 0; 2778 const entries: { value: string, description?: string }[] = []; 2779 categorizedOptions.forEach((options, category) => { 2780 if (entries.length !== 0) { 2781 entries.push({ value: "" }); 2782 } 2783 entries.push({ value: `/* ${getLocaleSpecificMessage(category)} */` }); 2784 for (const option of options) { 2785 let optionName; 2786 if (compilerOptionsMap.has(option.name)) { 2787 optionName = `"${option.name}": ${JSON.stringify(compilerOptionsMap.get(option.name))}${(seenKnownKeys += 1) === compilerOptionsMap.size ? "" : ","}`; 2788 } 2789 else { 2790 optionName = `// "${option.name}": ${JSON.stringify(getDefaultValueForOption(option))},`; 2791 } 2792 entries.push({ 2793 value: optionName, 2794 description: `/* ${option.description && getLocaleSpecificMessage(option.description) || option.name} */` 2795 }); 2796 marginLength = Math.max(optionName.length, marginLength); 2797 } 2798 }); 2799 2800 // Write the output 2801 const tab = makePadding(2); 2802 const result: string[] = []; 2803 result.push(`{`); 2804 result.push(`${tab}"compilerOptions": {`); 2805 result.push(`${tab}${tab}/* ${getLocaleSpecificMessage(Diagnostics.Visit_https_Colon_Slash_Slashaka_ms_Slashtsconfig_to_read_more_about_this_file)} */`); 2806 result.push(""); 2807 // Print out each row, aligning all the descriptions on the same column. 2808 for (const entry of entries) { 2809 const { value, description = "" } = entry; 2810 result.push(value && `${tab}${tab}${value}${description && (makePadding(marginLength - value.length + 2) + description)}`); 2811 } 2812 if (fileNames.length) { 2813 result.push(`${tab}},`); 2814 result.push(`${tab}"files": [`); 2815 for (let i = 0; i < fileNames.length; i++) { 2816 result.push(`${tab}${tab}${JSON.stringify(fileNames[i])}${i === fileNames.length - 1 ? "" : ","}`); 2817 } 2818 result.push(`${tab}]`); 2819 } 2820 else { 2821 result.push(`${tab}}`); 2822 } 2823 result.push(`}`); 2824 2825 return result.join(newLine) + newLine; 2826 } 2827} 2828 2829/** @internal */ 2830export function convertToOptionsWithAbsolutePaths(options: CompilerOptions, toAbsolutePath: (path: string) => string) { 2831 const result: CompilerOptions = {}; 2832 const optionsNameMap = getOptionsNameMap().optionsNameMap; 2833 2834 for (const name in options) { 2835 if (hasProperty(options, name)) { 2836 result[name] = convertToOptionValueWithAbsolutePaths( 2837 optionsNameMap.get(name.toLowerCase()), 2838 options[name] as CompilerOptionsValue, 2839 toAbsolutePath 2840 ); 2841 } 2842 } 2843 if (result.configFilePath) { 2844 result.configFilePath = toAbsolutePath(result.configFilePath); 2845 } 2846 return result; 2847} 2848 2849function convertToOptionValueWithAbsolutePaths(option: CommandLineOption | undefined, value: CompilerOptionsValue, toAbsolutePath: (path: string) => string) { 2850 if (option && !isNullOrUndefined(value)) { 2851 if (option.type === "list") { 2852 const values = value as readonly (string | number)[]; 2853 if (option.element.isFilePath && values.length) { 2854 return values.map(toAbsolutePath); 2855 } 2856 } 2857 else if (option.isFilePath) { 2858 return toAbsolutePath(value as string); 2859 } 2860 } 2861 return value; 2862} 2863 2864/** 2865 * Parse the contents of a config file (tsconfig.json). 2866 * @param json The contents of the config file to parse 2867 * @param host Instance of ParseConfigHost used to enumerate files in folder. 2868 * @param basePath A root directory to resolve relative path entries in the config 2869 * file to. e.g. outDir 2870 */ 2871export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: readonly FileExtensionInfo[], extendedConfigCache?: Map<ExtendedConfigCacheEntry>, existingWatchOptions?: WatchOptions): ParsedCommandLine { 2872 return parseJsonConfigFileContentWorker(json, /*sourceFile*/ undefined, host, basePath, existingOptions, existingWatchOptions, configFileName, resolutionStack, extraFileExtensions, extendedConfigCache); 2873} 2874 2875/** 2876 * Parse the contents of a config file (tsconfig.json). 2877 * @param jsonNode The contents of the config file to parse 2878 * @param host Instance of ParseConfigHost used to enumerate files in folder. 2879 * @param basePath A root directory to resolve relative path entries in the config 2880 * file to. e.g. outDir 2881 */ 2882export function parseJsonSourceFileConfigFileContent(sourceFile: TsConfigSourceFile, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: readonly FileExtensionInfo[], extendedConfigCache?: Map<ExtendedConfigCacheEntry>, existingWatchOptions?: WatchOptions): ParsedCommandLine { 2883 tracing?.push(tracing.Phase.Parse, "parseJsonSourceFileConfigFileContent", { path: sourceFile.fileName }); 2884 PerformanceDotting.start("parseJsonSourceFileConfigFileContent"); 2885 const result = parseJsonConfigFileContentWorker(/*json*/ undefined, sourceFile, host, basePath, existingOptions, existingWatchOptions, configFileName, resolutionStack, extraFileExtensions, extendedConfigCache); 2886 PerformanceDotting.stop("parseJsonSourceFileConfigFileContent"); 2887 tracing?.pop(); 2888 return result; 2889} 2890 2891/** @internal */ 2892export function setConfigFileInOptions(options: CompilerOptions, configFile: TsConfigSourceFile | undefined) { 2893 if (configFile) { 2894 Object.defineProperty(options, "configFile", { enumerable: false, writable: false, value: configFile }); 2895 } 2896} 2897 2898function isNullOrUndefined(x: any): x is null | undefined { 2899 return x === undefined || x === null; // eslint-disable-line no-null/no-null 2900} 2901 2902function directoryOfCombinedPath(fileName: string, basePath: string) { 2903 // Use the `getNormalizedAbsolutePath` function to avoid canonicalizing the path, as it must remain noncanonical 2904 // until consistent casing errors are reported 2905 return getDirectoryPath(getNormalizedAbsolutePath(fileName, basePath)); 2906} 2907 2908/** @internal */ 2909export const defaultIncludeSpec = "**/*"; 2910 2911/** 2912 * Parse the contents of a config file from json or json source file (tsconfig.json). 2913 * @param json The contents of the config file to parse 2914 * @param sourceFile sourceFile corresponding to the Json 2915 * @param host Instance of ParseConfigHost used to enumerate files in folder. 2916 * @param basePath A root directory to resolve relative path entries in the config 2917 * file to. e.g. outDir 2918 * @param resolutionStack Only present for backwards-compatibility. Should be empty. 2919 */ 2920function parseJsonConfigFileContentWorker( 2921 json: any, 2922 sourceFile: TsConfigSourceFile | undefined, 2923 host: ParseConfigHost, 2924 basePath: string, 2925 existingOptions: CompilerOptions = {}, 2926 existingWatchOptions: WatchOptions | undefined, 2927 configFileName?: string, 2928 resolutionStack: Path[] = [], 2929 extraFileExtensions: readonly FileExtensionInfo[] = [], 2930 extendedConfigCache?: ESMap<string, ExtendedConfigCacheEntry> 2931): ParsedCommandLine { 2932 Debug.assert((json === undefined && sourceFile !== undefined) || (json !== undefined && sourceFile === undefined)); 2933 const errors: Diagnostic[] = []; 2934 2935 const parsedConfig = parseConfig(json, sourceFile, host, basePath, configFileName, resolutionStack, errors, extendedConfigCache); 2936 const { raw } = parsedConfig; 2937 const options = extend(existingOptions, parsedConfig.options || {}); 2938 const watchOptions = existingWatchOptions && parsedConfig.watchOptions ? 2939 extend(existingWatchOptions, parsedConfig.watchOptions) : 2940 parsedConfig.watchOptions || existingWatchOptions; 2941 2942 options.configFilePath = configFileName && normalizeSlashes(configFileName); 2943 const configFileSpecs = getConfigFileSpecs(); 2944 if (sourceFile) sourceFile.configFileSpecs = configFileSpecs; 2945 setConfigFileInOptions(options, sourceFile); 2946 2947 const basePathForFileNames = normalizePath(configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath); 2948 return { 2949 options, 2950 watchOptions, 2951 fileNames: getFileNames(basePathForFileNames), 2952 projectReferences: getProjectReferences(basePathForFileNames), 2953 typeAcquisition: parsedConfig.typeAcquisition || getDefaultTypeAcquisition(), 2954 raw, 2955 errors, 2956 // Wildcard directories (provided as part of a wildcard path) are stored in a 2957 // file map that marks whether it was a regular wildcard match (with a `*` or `?` token), 2958 // or a recursive directory. This information is used by filesystem watchers to monitor for 2959 // new entries in these paths. 2960 wildcardDirectories: getWildcardDirectories(configFileSpecs, basePathForFileNames, host.useCaseSensitiveFileNames), 2961 compileOnSave: !!raw.compileOnSave, 2962 }; 2963 2964 function getConfigFileSpecs(): ConfigFileSpecs { 2965 const referencesOfRaw = getPropFromRaw<ProjectReference>("references", element => typeof element === "object", "object"); 2966 const filesSpecs = toPropValue(getSpecsFromRaw("files")); 2967 if (filesSpecs) { 2968 const hasZeroOrNoReferences = referencesOfRaw === "no-prop" || isArray(referencesOfRaw) && referencesOfRaw.length === 0; 2969 const hasExtends = hasProperty(raw, "extends"); 2970 if (filesSpecs.length === 0 && hasZeroOrNoReferences && !hasExtends) { 2971 if (sourceFile) { 2972 const fileName = configFileName || "tsconfig.json"; 2973 const diagnosticMessage = Diagnostics.The_files_list_in_config_file_0_is_empty; 2974 const nodeValue = firstDefined(getTsConfigPropArray(sourceFile, "files"), property => property.initializer); 2975 const error = nodeValue 2976 ? createDiagnosticForNodeInSourceFile(sourceFile, nodeValue, diagnosticMessage, fileName) 2977 : createCompilerDiagnostic(diagnosticMessage, fileName); 2978 errors.push(error); 2979 } 2980 else { 2981 createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json"); 2982 } 2983 } 2984 } 2985 2986 let includeSpecs = toPropValue(getSpecsFromRaw("include")); 2987 2988 const excludeOfRaw = getSpecsFromRaw("exclude"); 2989 let isDefaultIncludeSpec = false; 2990 let excludeSpecs = toPropValue(excludeOfRaw); 2991 if (excludeOfRaw === "no-prop" && raw.compilerOptions) { 2992 const outDir = raw.compilerOptions.outDir; 2993 const declarationDir = raw.compilerOptions.declarationDir; 2994 2995 if (outDir || declarationDir) { 2996 excludeSpecs = [outDir, declarationDir].filter(d => !!d); 2997 } 2998 } 2999 3000 if (filesSpecs === undefined && includeSpecs === undefined) { 3001 includeSpecs = [defaultIncludeSpec]; 3002 isDefaultIncludeSpec = true; 3003 } 3004 let validatedIncludeSpecs: readonly string[] | undefined, validatedExcludeSpecs: readonly string[] | undefined; 3005 3006 // The exclude spec list is converted into a regular expression, which allows us to quickly 3007 // test whether a file or directory should be excluded before recursively traversing the 3008 // file system. 3009 3010 if (includeSpecs) { 3011 validatedIncludeSpecs = validateSpecs(includeSpecs, errors, /*disallowTrailingRecursion*/ true, sourceFile, "include"); 3012 } 3013 3014 if (excludeSpecs) { 3015 validatedExcludeSpecs = validateSpecs(excludeSpecs, errors, /*disallowTrailingRecursion*/ false, sourceFile, "exclude"); 3016 } 3017 3018 return { 3019 filesSpecs, 3020 includeSpecs, 3021 excludeSpecs, 3022 validatedFilesSpec: filter(filesSpecs, isString), 3023 validatedIncludeSpecs, 3024 validatedExcludeSpecs, 3025 pathPatterns: undefined, // Initialized on first use 3026 isDefaultIncludeSpec, 3027 }; 3028 } 3029 3030 function getFileNames(basePath: string): string[] { 3031 const fileNames = getFileNamesFromConfigSpecs(configFileSpecs, basePath, options, host, extraFileExtensions); 3032 if (shouldReportNoInputFiles(fileNames, canJsonReportNoInputFiles(raw), resolutionStack)) { 3033 errors.push(getErrorForNoInputFiles(configFileSpecs, configFileName)); 3034 } 3035 return fileNames; 3036 } 3037 3038 function getProjectReferences(basePath: string): readonly ProjectReference[] | undefined { 3039 let projectReferences: ProjectReference[] | undefined; 3040 const referencesOfRaw = getPropFromRaw<ProjectReference>("references", element => typeof element === "object", "object"); 3041 if (isArray(referencesOfRaw)) { 3042 for (const ref of referencesOfRaw) { 3043 if (typeof ref.path !== "string") { 3044 createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "reference.path", "string"); 3045 } 3046 else { 3047 (projectReferences || (projectReferences = [])).push({ 3048 path: getNormalizedAbsolutePath(ref.path, basePath), 3049 originalPath: ref.path, 3050 prepend: ref.prepend, 3051 circular: ref.circular 3052 }); 3053 } 3054 } 3055 } 3056 return projectReferences; 3057 } 3058 3059 type PropOfRaw<T> = readonly T[] | "not-array" | "no-prop"; 3060 function toPropValue<T>(specResult: PropOfRaw<T>) { 3061 return isArray(specResult) ? specResult : undefined; 3062 } 3063 3064 function getSpecsFromRaw(prop: "files" | "include" | "exclude"): PropOfRaw<string> { 3065 return getPropFromRaw(prop, isString, "string"); 3066 } 3067 3068 function getPropFromRaw<T>(prop: "files" | "include" | "exclude" | "references", validateElement: (value: unknown) => boolean, elementTypeName: string): PropOfRaw<T> { 3069 if (hasProperty(raw, prop) && !isNullOrUndefined(raw[prop])) { 3070 if (isArray(raw[prop])) { 3071 const result = raw[prop] as T[]; 3072 if (!sourceFile && !every(result, validateElement)) { 3073 errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, prop, elementTypeName)); 3074 } 3075 return result; 3076 } 3077 else { 3078 createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, prop, "Array"); 3079 return "not-array"; 3080 } 3081 } 3082 return "no-prop"; 3083 } 3084 3085 function createCompilerDiagnosticOnlyIfJson(message: DiagnosticMessage, arg0?: string, arg1?: string) { 3086 if (!sourceFile) { 3087 errors.push(createCompilerDiagnostic(message, arg0, arg1)); 3088 } 3089 } 3090} 3091 3092function isErrorNoInputFiles(error: Diagnostic) { 3093 return error.code === Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code; 3094} 3095 3096function getErrorForNoInputFiles({ includeSpecs, excludeSpecs }: ConfigFileSpecs, configFileName: string | undefined) { 3097 return createCompilerDiagnostic( 3098 Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, 3099 configFileName || "tsconfig.json", 3100 JSON.stringify(includeSpecs || []), 3101 JSON.stringify(excludeSpecs || [])); 3102} 3103 3104function shouldReportNoInputFiles(fileNames: string[], canJsonReportNoInutFiles: boolean, resolutionStack?: Path[]) { 3105 return fileNames.length === 0 && canJsonReportNoInutFiles && (!resolutionStack || resolutionStack.length === 0); 3106} 3107 3108/** @internal */ 3109export function canJsonReportNoInputFiles(raw: any) { 3110 return !hasProperty(raw, "files") && !hasProperty(raw, "references"); 3111} 3112 3113/** @internal */ 3114export function updateErrorForNoInputFiles(fileNames: string[], configFileName: string, configFileSpecs: ConfigFileSpecs, configParseDiagnostics: Diagnostic[], canJsonReportNoInutFiles: boolean) { 3115 const existingErrors = configParseDiagnostics.length; 3116 if (shouldReportNoInputFiles(fileNames, canJsonReportNoInutFiles)) { 3117 configParseDiagnostics.push(getErrorForNoInputFiles(configFileSpecs, configFileName)); 3118 } 3119 else { 3120 filterMutate(configParseDiagnostics, error => !isErrorNoInputFiles(error)); 3121 } 3122 return existingErrors !== configParseDiagnostics.length; 3123} 3124 3125export interface ParsedTsconfig { 3126 raw: any; 3127 options?: CompilerOptions; 3128 watchOptions?: WatchOptions; 3129 typeAcquisition?: TypeAcquisition; 3130 /** 3131 * Note that the case of the config path has not yet been normalized, as no files have been imported into the project yet 3132 */ 3133 extendedConfigPath?: string; 3134} 3135 3136function isSuccessfulParsedTsconfig(value: ParsedTsconfig) { 3137 return !!value.options; 3138} 3139 3140/** 3141 * This *just* extracts options/include/exclude/files out of a config file. 3142 * It does *not* resolve the included files. 3143 */ 3144function parseConfig( 3145 json: any, 3146 sourceFile: TsConfigSourceFile | undefined, 3147 host: ParseConfigHost, 3148 basePath: string, 3149 configFileName: string | undefined, 3150 resolutionStack: string[], 3151 errors: Push<Diagnostic>, 3152 extendedConfigCache?: ESMap<string, ExtendedConfigCacheEntry> 3153): ParsedTsconfig { 3154 basePath = normalizeSlashes(basePath); 3155 const resolvedPath = getNormalizedAbsolutePath(configFileName || "", basePath); 3156 3157 if (resolutionStack.indexOf(resolvedPath) >= 0) { 3158 errors.push(createCompilerDiagnostic(Diagnostics.Circularity_detected_while_resolving_configuration_Colon_0, [...resolutionStack, resolvedPath].join(" -> "))); 3159 return { raw: json || convertToObject(sourceFile!, errors) }; 3160 } 3161 3162 const ownConfig = json ? 3163 parseOwnConfigOfJson(json, host, basePath, configFileName, errors) : 3164 parseOwnConfigOfJsonSourceFile(sourceFile!, host, basePath, configFileName, errors); 3165 3166 if (ownConfig.options?.paths) { 3167 // If we end up needing to resolve relative paths from 'paths' relative to 3168 // the config file location, we'll need to know where that config file was. 3169 // Since 'paths' can be inherited from an extended config in another directory, 3170 // we wouldn't know which directory to use unless we store it here. 3171 ownConfig.options.pathsBasePath = basePath; 3172 } 3173 if (ownConfig.extendedConfigPath) { 3174 // copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios. 3175 resolutionStack = resolutionStack.concat([resolvedPath]); 3176 const extendedConfig = getExtendedConfig(sourceFile, ownConfig.extendedConfigPath, host, resolutionStack, errors, extendedConfigCache); 3177 if (extendedConfig && isSuccessfulParsedTsconfig(extendedConfig)) { 3178 const baseRaw = extendedConfig.raw; 3179 const raw = ownConfig.raw; 3180 let relativeDifference: string | undefined ; 3181 const setPropertyInRawIfNotUndefined = (propertyName: string) => { 3182 if (!raw[propertyName] && baseRaw[propertyName]) { 3183 raw[propertyName] = map(baseRaw[propertyName], (path: string) => isRootedDiskPath(path) ? path : combinePaths( 3184 relativeDifference ||= convertToRelativePath(getDirectoryPath(ownConfig.extendedConfigPath!), basePath, createGetCanonicalFileName(host.useCaseSensitiveFileNames)), 3185 path 3186 )); 3187 } 3188 }; 3189 setPropertyInRawIfNotUndefined("include"); 3190 setPropertyInRawIfNotUndefined("exclude"); 3191 setPropertyInRawIfNotUndefined("files"); 3192 if (raw.compileOnSave === undefined) { 3193 raw.compileOnSave = baseRaw.compileOnSave; 3194 } 3195 ownConfig.options = assign({}, extendedConfig.options, ownConfig.options); 3196 ownConfig.watchOptions = ownConfig.watchOptions && extendedConfig.watchOptions ? 3197 assign({}, extendedConfig.watchOptions, ownConfig.watchOptions) : 3198 ownConfig.watchOptions || extendedConfig.watchOptions; 3199 // TODO extend type typeAcquisition 3200 } 3201 } 3202 3203 return ownConfig; 3204} 3205 3206function parseOwnConfigOfJson( 3207 json: any, 3208 host: ParseConfigHost, 3209 basePath: string, 3210 configFileName: string | undefined, 3211 errors: Push<Diagnostic> 3212): ParsedTsconfig { 3213 if (hasProperty(json, "excludes")) { 3214 errors.push(createCompilerDiagnostic(Diagnostics.Unknown_option_excludes_Did_you_mean_exclude)); 3215 } 3216 3217 const options = convertCompilerOptionsFromJsonWorker(json.compilerOptions, basePath, errors, configFileName); 3218 // typingOptions has been deprecated and is only supported for backward compatibility purposes. 3219 // It should be removed in future releases - use typeAcquisition instead. 3220 const typeAcquisition = convertTypeAcquisitionFromJsonWorker(json.typeAcquisition || json.typingOptions, basePath, errors, configFileName); 3221 const watchOptions = convertWatchOptionsFromJsonWorker(json.watchOptions, basePath, errors); 3222 json.compileOnSave = convertCompileOnSaveOptionFromJson(json, basePath, errors); 3223 let extendedConfigPath: string | undefined; 3224 3225 if (json.extends) { 3226 if (!isString(json.extends)) { 3227 errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "extends", "string")); 3228 } 3229 else { 3230 const newBase = configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath; 3231 extendedConfigPath = getExtendsConfigPath(json.extends, host, newBase, errors, createCompilerDiagnostic); 3232 } 3233 } 3234 return { raw: json, options, watchOptions, typeAcquisition, extendedConfigPath }; 3235} 3236 3237function parseOwnConfigOfJsonSourceFile( 3238 sourceFile: TsConfigSourceFile, 3239 host: ParseConfigHost, 3240 basePath: string, 3241 configFileName: string | undefined, 3242 errors: Push<Diagnostic> 3243): ParsedTsconfig { 3244 const options = getDefaultCompilerOptions(configFileName); 3245 let typeAcquisition: TypeAcquisition | undefined, typingOptionstypeAcquisition: TypeAcquisition | undefined; 3246 let watchOptions: WatchOptions | undefined; 3247 let extendedConfigPath: string | undefined; 3248 let rootCompilerOptions: PropertyName[] | undefined; 3249 3250 const optionsIterator: JsonConversionNotifier = { 3251 onSetValidOptionKeyValueInParent(parentOption: string, option: CommandLineOption, value: CompilerOptionsValue) { 3252 let currentOption; 3253 switch (parentOption) { 3254 case "compilerOptions": 3255 currentOption = options; 3256 break; 3257 case "watchOptions": 3258 currentOption = (watchOptions || (watchOptions = {})); 3259 break; 3260 case "typeAcquisition": 3261 currentOption = (typeAcquisition || (typeAcquisition = getDefaultTypeAcquisition(configFileName))); 3262 break; 3263 case "typingOptions": 3264 currentOption = (typingOptionstypeAcquisition || (typingOptionstypeAcquisition = getDefaultTypeAcquisition(configFileName))); 3265 break; 3266 default: 3267 Debug.fail("Unknown option"); 3268 } 3269 3270 currentOption[option.name] = normalizeOptionValue(option, basePath, value); 3271 }, 3272 onSetValidOptionKeyValueInRoot(key: string, _keyNode: PropertyName, value: CompilerOptionsValue, valueNode: Expression) { 3273 switch (key) { 3274 case "extends": 3275 const newBase = configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath; 3276 extendedConfigPath = getExtendsConfigPath( 3277 value as string, 3278 host, 3279 newBase, 3280 errors, 3281 (message, arg0) => 3282 createDiagnosticForNodeInSourceFile(sourceFile, valueNode, message, arg0) 3283 ); 3284 return; 3285 } 3286 }, 3287 onSetUnknownOptionKeyValueInRoot(key: string, keyNode: PropertyName, _value: CompilerOptionsValue, _valueNode: Expression) { 3288 if (key === "excludes") { 3289 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, keyNode, Diagnostics.Unknown_option_excludes_Did_you_mean_exclude)); 3290 } 3291 if (find(commandOptionsWithoutBuild, (opt) => opt.name === key)) { 3292 rootCompilerOptions = append(rootCompilerOptions, keyNode); 3293 } 3294 } 3295 }; 3296 const json = convertConfigFileToObject(sourceFile, errors, /*reportOptionsErrors*/ true, optionsIterator); 3297 3298 if (!typeAcquisition) { 3299 if (typingOptionstypeAcquisition) { 3300 typeAcquisition = (typingOptionstypeAcquisition.enableAutoDiscovery !== undefined) ? 3301 { 3302 enable: typingOptionstypeAcquisition.enableAutoDiscovery, 3303 include: typingOptionstypeAcquisition.include, 3304 exclude: typingOptionstypeAcquisition.exclude 3305 } : 3306 typingOptionstypeAcquisition; 3307 } 3308 else { 3309 typeAcquisition = getDefaultTypeAcquisition(configFileName); 3310 } 3311 } 3312 3313 if (rootCompilerOptions && json && json.compilerOptions === undefined) { 3314 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, rootCompilerOptions[0], Diagnostics._0_should_be_set_inside_the_compilerOptions_object_of_the_config_json_file, getTextOfPropertyName(rootCompilerOptions[0]) as string)); 3315 } 3316 3317 return { raw: json, options, watchOptions, typeAcquisition, extendedConfigPath }; 3318} 3319 3320function getExtendsConfigPath( 3321 extendedConfig: string, 3322 host: ParseConfigHost, 3323 basePath: string, 3324 errors: Push<Diagnostic>, 3325 createDiagnostic: (message: DiagnosticMessage, arg1?: string) => Diagnostic) { 3326 extendedConfig = normalizeSlashes(extendedConfig); 3327 if (isRootedDiskPath(extendedConfig) || startsWith(extendedConfig, "./") || startsWith(extendedConfig, "../")) { 3328 let extendedConfigPath = getNormalizedAbsolutePath(extendedConfig, basePath); 3329 if (!host.fileExists(extendedConfigPath) && !endsWith(extendedConfigPath, Extension.Json)) { 3330 extendedConfigPath = `${extendedConfigPath}.json`; 3331 if (!host.fileExists(extendedConfigPath)) { 3332 errors.push(createDiagnostic(Diagnostics.File_0_not_found, extendedConfig)); 3333 return undefined; 3334 } 3335 } 3336 return extendedConfigPath; 3337 } 3338 // If the path isn't a rooted or relative path, resolve like a module 3339 const resolved = nodeModuleNameResolver(extendedConfig, combinePaths(basePath, "tsconfig.json"), { moduleResolution: ModuleResolutionKind.NodeJs }, host, /*cache*/ undefined, /*projectRefs*/ undefined, /*lookupConfig*/ true); 3340 if (resolved.resolvedModule) { 3341 return resolved.resolvedModule.resolvedFileName; 3342 } 3343 errors.push(createDiagnostic(Diagnostics.File_0_not_found, extendedConfig)); 3344 return undefined; 3345} 3346 3347export interface ExtendedConfigCacheEntry { 3348 extendedResult: TsConfigSourceFile; 3349 extendedConfig: ParsedTsconfig | undefined; 3350} 3351 3352function getExtendedConfig( 3353 sourceFile: TsConfigSourceFile | undefined, 3354 extendedConfigPath: string, 3355 host: ParseConfigHost, 3356 resolutionStack: string[], 3357 errors: Push<Diagnostic>, 3358 extendedConfigCache?: ESMap<string, ExtendedConfigCacheEntry> 3359): ParsedTsconfig | undefined { 3360 const path = host.useCaseSensitiveFileNames ? extendedConfigPath : toFileNameLowerCase(extendedConfigPath); 3361 let value: ExtendedConfigCacheEntry | undefined; 3362 let extendedResult: TsConfigSourceFile; 3363 let extendedConfig: ParsedTsconfig | undefined; 3364 if (extendedConfigCache && (value = extendedConfigCache.get(path))) { 3365 ({ extendedResult, extendedConfig } = value); 3366 } 3367 else { 3368 extendedResult = readJsonConfigFile(extendedConfigPath, path => host.readFile(path)); 3369 if (!extendedResult.parseDiagnostics.length) { 3370 extendedConfig = parseConfig(/*json*/ undefined, extendedResult, host, getDirectoryPath(extendedConfigPath), 3371 getBaseFileName(extendedConfigPath), resolutionStack, errors, extendedConfigCache); 3372 } 3373 if (extendedConfigCache) { 3374 extendedConfigCache.set(path, { extendedResult, extendedConfig }); 3375 } 3376 } 3377 if (sourceFile) { 3378 sourceFile.extendedSourceFiles = [extendedResult.fileName]; 3379 if (extendedResult.extendedSourceFiles) { 3380 sourceFile.extendedSourceFiles.push(...extendedResult.extendedSourceFiles); 3381 } 3382 } 3383 if (extendedResult.parseDiagnostics.length) { 3384 errors.push(...extendedResult.parseDiagnostics); 3385 return undefined; 3386 } 3387 return extendedConfig!; 3388} 3389 3390function convertCompileOnSaveOptionFromJson(jsonOption: any, basePath: string, errors: Push<Diagnostic>): boolean { 3391 if (!hasProperty(jsonOption, compileOnSaveCommandLineOption.name)) { 3392 return false; 3393 } 3394 const result = convertJsonOption(compileOnSaveCommandLineOption, jsonOption.compileOnSave, basePath, errors); 3395 return typeof result === "boolean" && result; 3396} 3397 3398export function convertCompilerOptionsFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: CompilerOptions, errors: Diagnostic[] } { 3399 const errors: Diagnostic[] = []; 3400 const options = convertCompilerOptionsFromJsonWorker(jsonOptions, basePath, errors, configFileName); 3401 return { options, errors }; 3402} 3403 3404export function convertTypeAcquisitionFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: TypeAcquisition, errors: Diagnostic[] } { 3405 const errors: Diagnostic[] = []; 3406 const options = convertTypeAcquisitionFromJsonWorker(jsonOptions, basePath, errors, configFileName); 3407 return { options, errors }; 3408} 3409 3410function getDefaultCompilerOptions(configFileName?: string) { 3411 const options: CompilerOptions = configFileName && getBaseFileName(configFileName) === "jsconfig.json" 3412 ? { allowJs: true, maxNodeModuleJsDepth: 2, allowSyntheticDefaultImports: true, skipLibCheck: true, noEmit: true } 3413 : {}; 3414 return options; 3415} 3416 3417function convertCompilerOptionsFromJsonWorker(jsonOptions: any, 3418 basePath: string, errors: Push<Diagnostic>, configFileName?: string): CompilerOptions { 3419 3420 const options = getDefaultCompilerOptions(configFileName); 3421 convertOptionsFromJson(getCommandLineCompilerOptionsMap(), jsonOptions, basePath, options, compilerOptionsDidYouMeanDiagnostics, errors); 3422 if (configFileName) { 3423 options.configFilePath = normalizeSlashes(configFileName); 3424 } 3425 return options; 3426} 3427 3428function getDefaultTypeAcquisition(configFileName?: string): TypeAcquisition { 3429 return { enable: !!configFileName && getBaseFileName(configFileName) === "jsconfig.json", include: [], exclude: [] }; 3430} 3431 3432function convertTypeAcquisitionFromJsonWorker(jsonOptions: any, 3433 basePath: string, errors: Push<Diagnostic>, configFileName?: string): TypeAcquisition { 3434 3435 const options = getDefaultTypeAcquisition(configFileName); 3436 const typeAcquisition = convertEnableAutoDiscoveryToEnable(jsonOptions); 3437 3438 convertOptionsFromJson(getCommandLineTypeAcquisitionMap(), typeAcquisition, basePath, options, typeAcquisitionDidYouMeanDiagnostics, errors); 3439 return options; 3440} 3441 3442function convertWatchOptionsFromJsonWorker(jsonOptions: any, basePath: string, errors: Push<Diagnostic>): WatchOptions | undefined { 3443 return convertOptionsFromJson(getCommandLineWatchOptionsMap(), jsonOptions, basePath, /*defaultOptions*/ undefined, watchOptionsDidYouMeanDiagnostics, errors); 3444} 3445 3446function convertOptionsFromJson(optionsNameMap: ESMap<string, CommandLineOption>, jsonOptions: any, basePath: string, 3447 defaultOptions: undefined, diagnostics: DidYouMeanOptionsDiagnostics, errors: Push<Diagnostic>): WatchOptions | undefined; 3448function convertOptionsFromJson(optionsNameMap: ESMap<string, CommandLineOption>, jsonOptions: any, basePath: string, 3449 defaultOptions: CompilerOptions | TypeAcquisition, diagnostics: DidYouMeanOptionsDiagnostics, errors: Push<Diagnostic>): CompilerOptions | TypeAcquisition; 3450function convertOptionsFromJson(optionsNameMap: ESMap<string, CommandLineOption>, jsonOptions: any, basePath: string, 3451 defaultOptions: CompilerOptions | TypeAcquisition | WatchOptions | undefined, diagnostics: DidYouMeanOptionsDiagnostics, errors: Push<Diagnostic>) { 3452 3453 if (!jsonOptions) { 3454 return; 3455 } 3456 3457 for (const id in jsonOptions) { 3458 const opt = optionsNameMap.get(id); 3459 if (opt) { 3460 (defaultOptions || (defaultOptions = {}))[opt.name] = convertJsonOption(opt, jsonOptions[id], basePath, errors); 3461 } 3462 else { 3463 errors.push(createUnknownOptionError(id, diagnostics, createCompilerDiagnostic)); 3464 } 3465 } 3466 return defaultOptions; 3467} 3468 3469/** @internal */ 3470export function convertJsonOption(opt: CommandLineOption, value: any, basePath: string, errors: Push<Diagnostic>): CompilerOptionsValue { 3471 if (isCompilerOptionsValue(opt, value)) { 3472 const optType = opt.type; 3473 if (optType === "list" && isArray(value)) { 3474 return convertJsonOptionOfListType(opt , value, basePath, errors); 3475 } 3476 else if (!isString(optType)) { 3477 return convertJsonOptionOfCustomType(opt as CommandLineOptionOfCustomType, value as string, errors); 3478 } 3479 const validatedValue = validateJsonOptionValue(opt, value, errors); 3480 return isNullOrUndefined(validatedValue) ? validatedValue : normalizeNonListOptionValue(opt, basePath, validatedValue); 3481 } 3482 else { 3483 errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, opt.name, getCompilerOptionValueTypeString(opt))); 3484 } 3485} 3486 3487function normalizeOptionValue(option: CommandLineOption, basePath: string, value: any): CompilerOptionsValue { 3488 if (isNullOrUndefined(value)) return undefined; 3489 if (option.type === "list") { 3490 const listOption = option; 3491 if (listOption.element.isFilePath || !isString(listOption.element.type)) { 3492 return filter(map(value, v => normalizeOptionValue(listOption.element, basePath, v)), v => listOption.listPreserveFalsyValues ? true : !!v) as CompilerOptionsValue; 3493 } 3494 return value; 3495 } 3496 else if (!isString(option.type)) { 3497 return option.type.get(isString(value) ? value.toLowerCase() : value); 3498 } 3499 return normalizeNonListOptionValue(option, basePath, value); 3500} 3501 3502function normalizeNonListOptionValue(option: CommandLineOption, basePath: string, value: any): CompilerOptionsValue { 3503 if (option.isFilePath) { 3504 value = getNormalizedAbsolutePath(value, basePath); 3505 if (value === "") { 3506 value = "."; 3507 } 3508 } 3509 return value; 3510} 3511 3512function validateJsonOptionValue<T extends CompilerOptionsValue>(opt: CommandLineOption, value: T, errors: Push<Diagnostic>): T | undefined { 3513 if (isNullOrUndefined(value)) return undefined; 3514 const d = opt.extraValidation?.(value); 3515 if (!d) return value; 3516 errors.push(createCompilerDiagnostic(...d)); 3517 return undefined; 3518} 3519 3520function convertJsonOptionOfCustomType(opt: CommandLineOptionOfCustomType, value: string, errors: Push<Diagnostic>) { 3521 if (isNullOrUndefined(value)) return undefined; 3522 const key = value.toLowerCase(); 3523 const val = opt.type.get(key); 3524 if (val !== undefined) { 3525 return validateJsonOptionValue(opt, val, errors); 3526 } 3527 else { 3528 errors.push(createCompilerDiagnosticForInvalidCustomType(opt)); 3529 } 3530} 3531 3532function convertJsonOptionOfListType(option: CommandLineOptionOfListType, values: readonly any[], basePath: string, errors: Push<Diagnostic>): any[] { 3533 return filter(map(values, v => convertJsonOption(option.element, v, basePath, errors)), v => option.listPreserveFalsyValues ? true : !!v); 3534} 3535 3536/** 3537 * Tests for a path that ends in a recursive directory wildcard. 3538 * Matches **, \**, **\, and \**\, but not a**b. 3539 * 3540 * NOTE: used \ in place of / above to avoid issues with multiline comments. 3541 * 3542 * Breakdown: 3543 * (^|\/) # matches either the beginning of the string or a directory separator. 3544 * \*\* # matches the recursive directory wildcard "**". 3545 * \/?$ # matches an optional trailing directory separator at the end of the string. 3546 */ 3547const invalidTrailingRecursionPattern = /(^|\/)\*\*\/?$/; 3548 3549/** 3550 * Matches the portion of a wildcard path that does not contain wildcards. 3551 * Matches \a of \a\*, or \a\b\c of \a\b\c\?\d. 3552 * 3553 * NOTE: used \ in place of / above to avoid issues with multiline comments. 3554 * 3555 * Breakdown: 3556 * ^ # matches the beginning of the string 3557 * [^*?]* # matches any number of non-wildcard characters 3558 * (?=\/[^/]*[*?]) # lookahead that matches a directory separator followed by 3559 * # a path component that contains at least one wildcard character (* or ?). 3560 */ 3561const wildcardDirectoryPattern = /^[^*?]*(?=\/[^/]*[*?])/; 3562 3563/** 3564 * Gets the file names from the provided config file specs that contain, files, include, exclude and 3565 * other properties needed to resolve the file names 3566 * @param configFileSpecs The config file specs extracted with file names to include, wildcards to include/exclude and other details 3567 * @param basePath The base path for any relative file specifications. 3568 * @param options Compiler options. 3569 * @param host The host used to resolve files and directories. 3570 * @param extraFileExtensions optionaly file extra file extension information from host 3571 * 3572 * @internal 3573 */ 3574export function getFileNamesFromConfigSpecs( 3575 configFileSpecs: ConfigFileSpecs, 3576 basePath: string, 3577 options: CompilerOptions, 3578 host: ParseConfigHost, 3579 extraFileExtensions: readonly FileExtensionInfo[] = emptyArray 3580): string[] { 3581 basePath = normalizePath(basePath); 3582 3583 const keyMapper = createGetCanonicalFileName(host.useCaseSensitiveFileNames); 3584 3585 // Literal file names (provided via the "files" array in tsconfig.json) are stored in a 3586 // file map with a possibly case insensitive key. We use this map later when when including 3587 // wildcard paths. 3588 const literalFileMap = new Map<string, string>(); 3589 3590 // Wildcard paths (provided via the "includes" array in tsconfig.json) are stored in a 3591 // file map with a possibly case insensitive key. We use this map to store paths matched 3592 // via wildcard, and to handle extension priority. 3593 const wildcardFileMap = new Map<string, string>(); 3594 3595 // Wildcard paths of json files (provided via the "includes" array in tsconfig.json) are stored in a 3596 // file map with a possibly case insensitive key. We use this map to store paths matched 3597 // via wildcard of *.json kind 3598 const wildCardJsonFileMap = new Map<string, string>(); 3599 const { validatedFilesSpec, validatedIncludeSpecs, validatedExcludeSpecs } = configFileSpecs; 3600 3601 // Rather than re-query this for each file and filespec, we query the supported extensions 3602 // once and store it on the expansion context. 3603 const supportedExtensions = getSupportedExtensions(options, extraFileExtensions); 3604 const supportedExtensionsWithJsonIfResolveJsonModule = getSupportedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions); 3605 3606 // Literal files are always included verbatim. An "include" or "exclude" specification cannot 3607 // remove a literal file. 3608 if (validatedFilesSpec) { 3609 for (const fileName of validatedFilesSpec) { 3610 const file = getNormalizedAbsolutePath(fileName, basePath); 3611 literalFileMap.set(keyMapper(file), file); 3612 } 3613 } 3614 3615 let jsonOnlyIncludeRegexes: readonly RegExp[] | undefined; 3616 if (validatedIncludeSpecs && validatedIncludeSpecs.length > 0) { 3617 for (const file of host.readDirectory(basePath, flatten(supportedExtensionsWithJsonIfResolveJsonModule), validatedExcludeSpecs, validatedIncludeSpecs, /*depth*/ undefined)) { 3618 if (fileExtensionIs(file, Extension.Json)) { 3619 // Valid only if *.json specified 3620 if (!jsonOnlyIncludeRegexes) { 3621 const includes = validatedIncludeSpecs.filter(s => endsWith(s, Extension.Json)); 3622 const includeFilePatterns = map(getRegularExpressionsForWildcards(includes, basePath, "files"), pattern => `^${pattern}$`); 3623 jsonOnlyIncludeRegexes = includeFilePatterns ? includeFilePatterns.map(pattern => getRegexFromPattern(pattern, host.useCaseSensitiveFileNames)) : emptyArray; 3624 } 3625 const includeIndex = findIndex(jsonOnlyIncludeRegexes, re => re.test(file)); 3626 if (includeIndex !== -1) { 3627 const key = keyMapper(file); 3628 if (!literalFileMap.has(key) && !wildCardJsonFileMap.has(key)) { 3629 wildCardJsonFileMap.set(key, file); 3630 } 3631 } 3632 continue; 3633 } 3634 // If we have already included a literal or wildcard path with a 3635 // higher priority extension, we should skip this file. 3636 // 3637 // This handles cases where we may encounter both <file>.ts and 3638 // <file>.d.ts (or <file>.js if "allowJs" is enabled) in the same 3639 // directory when they are compilation outputs. 3640 if (hasFileWithHigherPriorityExtension(file, literalFileMap, wildcardFileMap, supportedExtensions, keyMapper)) { 3641 continue; 3642 } 3643 3644 // We may have included a wildcard path with a lower priority 3645 // extension due to the user-defined order of entries in the 3646 // "include" array. If there is a lower priority extension in the 3647 // same directory, we should remove it. 3648 removeWildcardFilesWithLowerPriorityExtension(file, wildcardFileMap, supportedExtensions, keyMapper); 3649 3650 const key = keyMapper(file); 3651 if (!literalFileMap.has(key) && !wildcardFileMap.has(key)) { 3652 wildcardFileMap.set(key, file); 3653 } 3654 } 3655 } 3656 3657 const literalFiles = arrayFrom(literalFileMap.values()); 3658 const wildcardFiles = arrayFrom(wildcardFileMap.values()); 3659 3660 return literalFiles.concat(wildcardFiles, arrayFrom(wildCardJsonFileMap.values())); 3661} 3662 3663/** @internal */ 3664export function isExcludedFile( 3665 pathToCheck: string, 3666 spec: ConfigFileSpecs, 3667 basePath: string, 3668 useCaseSensitiveFileNames: boolean, 3669 currentDirectory: string 3670): boolean { 3671 const { validatedFilesSpec, validatedIncludeSpecs, validatedExcludeSpecs } = spec; 3672 if (!length(validatedIncludeSpecs) || !length(validatedExcludeSpecs)) return false; 3673 3674 basePath = normalizePath(basePath); 3675 3676 const keyMapper = createGetCanonicalFileName(useCaseSensitiveFileNames); 3677 if (validatedFilesSpec) { 3678 for (const fileName of validatedFilesSpec) { 3679 if (keyMapper(getNormalizedAbsolutePath(fileName, basePath)) === pathToCheck) return false; 3680 } 3681 } 3682 3683 return matchesExcludeWorker(pathToCheck, validatedExcludeSpecs, useCaseSensitiveFileNames, currentDirectory, basePath); 3684} 3685 3686function invalidDotDotAfterRecursiveWildcard(s: string) { 3687 // We used to use the regex /(^|\/)\*\*\/(.*\/)?\.\.($|\/)/ to check for this case, but 3688 // in v8, that has polynomial performance because the recursive wildcard match - **/ - 3689 // can be matched in many arbitrary positions when multiple are present, resulting 3690 // in bad backtracking (and we don't care which is matched - just that some /.. segment 3691 // comes after some **/ segment). 3692 const wildcardIndex = startsWith(s, "**/") ? 0 : s.indexOf("/**/"); 3693 if (wildcardIndex === -1) { 3694 return false; 3695 } 3696 const lastDotIndex = endsWith(s, "/..") ? s.length : s.lastIndexOf("/../"); 3697 return lastDotIndex > wildcardIndex; 3698} 3699 3700/** @internal */ 3701export function matchesExclude( 3702 pathToCheck: string, 3703 excludeSpecs: readonly string[] | undefined, 3704 useCaseSensitiveFileNames: boolean, 3705 currentDirectory: string 3706) { 3707 return matchesExcludeWorker( 3708 pathToCheck, 3709 filter(excludeSpecs, spec => !invalidDotDotAfterRecursiveWildcard(spec)), 3710 useCaseSensitiveFileNames, 3711 currentDirectory 3712 ); 3713} 3714 3715function matchesExcludeWorker( 3716 pathToCheck: string, 3717 excludeSpecs: readonly string[] | undefined, 3718 useCaseSensitiveFileNames: boolean, 3719 currentDirectory: string, 3720 basePath?: string 3721) { 3722 const excludePattern = getRegularExpressionForWildcard(excludeSpecs, combinePaths(normalizePath(currentDirectory), basePath), "exclude"); 3723 const excludeRegex = excludePattern && getRegexFromPattern(excludePattern, useCaseSensitiveFileNames); 3724 if (!excludeRegex) return false; 3725 if (excludeRegex.test(pathToCheck)) return true; 3726 return !hasExtension(pathToCheck) && excludeRegex.test(ensureTrailingDirectorySeparator(pathToCheck)); 3727} 3728 3729function validateSpecs(specs: readonly string[], errors: Push<Diagnostic>, disallowTrailingRecursion: boolean, jsonSourceFile: TsConfigSourceFile | undefined, specKey: string): readonly string[] { 3730 return specs.filter(spec => { 3731 if (!isString(spec)) return false; 3732 const diag = specToDiagnostic(spec, disallowTrailingRecursion); 3733 if (diag !== undefined) { 3734 errors.push(createDiagnostic(...diag)); 3735 } 3736 return diag === undefined; 3737 }); 3738 3739 function createDiagnostic(message: DiagnosticMessage, spec: string): Diagnostic { 3740 const element = getTsConfigPropArrayElementValue(jsonSourceFile, specKey, spec); 3741 return element ? 3742 createDiagnosticForNodeInSourceFile(jsonSourceFile!, element, message, spec) : 3743 createCompilerDiagnostic(message, spec); 3744 } 3745} 3746 3747function specToDiagnostic(spec: string, disallowTrailingRecursion?: boolean): [DiagnosticMessage, string] | undefined { 3748 if (disallowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) { 3749 return [Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec]; 3750 } 3751 else if (invalidDotDotAfterRecursiveWildcard(spec)) { 3752 return [Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec]; 3753 } 3754} 3755 3756/** 3757 * Gets directories in a set of include patterns that should be watched for changes. 3758 */ 3759function getWildcardDirectories({ validatedIncludeSpecs: include, validatedExcludeSpecs: exclude }: ConfigFileSpecs, path: string, useCaseSensitiveFileNames: boolean): MapLike<WatchDirectoryFlags> { 3760 // We watch a directory recursively if it contains a wildcard anywhere in a directory segment 3761 // of the pattern: 3762 // 3763 // /a/b/**/d - Watch /a/b recursively to catch changes to any d in any subfolder recursively 3764 // /a/b/*/d - Watch /a/b recursively to catch any d in any immediate subfolder, even if a new subfolder is added 3765 // /a/b - Watch /a/b recursively to catch changes to anything in any recursive subfoler 3766 // 3767 // We watch a directory without recursion if it contains a wildcard in the file segment of 3768 // the pattern: 3769 // 3770 // /a/b/* - Watch /a/b directly to catch any new file 3771 // /a/b/a?z - Watch /a/b directly to catch any new file matching a?z 3772 const rawExcludeRegex = getRegularExpressionForWildcard(exclude, path, "exclude"); 3773 const excludeRegex = rawExcludeRegex && new RegExp(rawExcludeRegex, useCaseSensitiveFileNames ? "" : "i"); 3774 const wildcardDirectories: MapLike<WatchDirectoryFlags> = {}; 3775 if (include !== undefined) { 3776 const recursiveKeys: string[] = []; 3777 for (const file of include) { 3778 const spec = normalizePath(combinePaths(path, file)); 3779 if (excludeRegex && excludeRegex.test(spec)) { 3780 continue; 3781 } 3782 3783 const match = getWildcardDirectoryFromSpec(spec, useCaseSensitiveFileNames); 3784 if (match) { 3785 const { key, flags } = match; 3786 const existingFlags = wildcardDirectories[key]; 3787 if (existingFlags === undefined || existingFlags < flags) { 3788 wildcardDirectories[key] = flags; 3789 if (flags === WatchDirectoryFlags.Recursive) { 3790 recursiveKeys.push(key); 3791 } 3792 } 3793 } 3794 } 3795 3796 // Remove any subpaths under an existing recursively watched directory. 3797 for (const key in wildcardDirectories) { 3798 if (hasProperty(wildcardDirectories, key)) { 3799 for (const recursiveKey of recursiveKeys) { 3800 if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) { 3801 delete wildcardDirectories[key]; 3802 } 3803 } 3804 } 3805 } 3806 } 3807 3808 return wildcardDirectories; 3809} 3810 3811function getWildcardDirectoryFromSpec(spec: string, useCaseSensitiveFileNames: boolean): { key: string, flags: WatchDirectoryFlags } | undefined { 3812 const match = wildcardDirectoryPattern.exec(spec); 3813 if (match) { 3814 // We check this with a few `indexOf` calls because 3 `indexOf`/`lastIndexOf` calls is 3815 // less algorithmically complex (roughly O(3n) worst-case) than the regex we used to use, 3816 // \/[^/]*?[*?][^/]*\/ which was polynominal in v8, since arbitrary sequences of wildcard 3817 // characters could match any of the central patterns, resulting in bad backtracking. 3818 const questionWildcardIndex = spec.indexOf("?"); 3819 const starWildcardIndex = spec.indexOf("*"); 3820 const lastDirectorySeperatorIndex = spec.lastIndexOf(directorySeparator); 3821 return { 3822 key: useCaseSensitiveFileNames ? match[0] : toFileNameLowerCase(match[0]), 3823 flags: (questionWildcardIndex !== -1 && questionWildcardIndex < lastDirectorySeperatorIndex) 3824 || (starWildcardIndex !== -1 && starWildcardIndex < lastDirectorySeperatorIndex) 3825 ? WatchDirectoryFlags.Recursive : WatchDirectoryFlags.None 3826 }; 3827 } 3828 if (isImplicitGlob(spec.substring(spec.lastIndexOf(directorySeparator) + 1))) { 3829 return { 3830 key: removeTrailingDirectorySeparator(useCaseSensitiveFileNames ? spec : toFileNameLowerCase(spec)), 3831 flags: WatchDirectoryFlags.Recursive 3832 }; 3833 } 3834 return undefined; 3835} 3836 3837/** 3838 * Determines whether a literal or wildcard file has already been included that has a higher 3839 * extension priority. 3840 * 3841 * @param file The path to the file. 3842 */ 3843function hasFileWithHigherPriorityExtension(file: string, literalFiles: ESMap<string, string>, wildcardFiles: ESMap<string, string>, extensions: readonly string[][], keyMapper: (value: string) => string) { 3844 const extensionGroup = forEach(extensions, group => fileExtensionIsOneOf(file, group) ? group : undefined); 3845 if (!extensionGroup) { 3846 return false; 3847 } 3848 for (const ext of extensionGroup) { 3849 if (fileExtensionIs(file, ext)) { 3850 return false; 3851 } 3852 const higherPriorityPath = keyMapper(changeExtension(file, ext)); 3853 if (literalFiles.has(higherPriorityPath) || wildcardFiles.has(higherPriorityPath)) { 3854 if (ext === Extension.Dts && (fileExtensionIs(file, Extension.Js) || fileExtensionIs(file, Extension.Jsx))) { 3855 // LEGACY BEHAVIOR: An off-by-one bug somewhere in the extension priority system for wildcard module loading allowed declaration 3856 // files to be loaded alongside their js(x) counterparts. We regard this as generally undesirable, but retain the behavior to 3857 // prevent breakage. 3858 continue; 3859 } 3860 return true; 3861 } 3862 } 3863 3864 return false; 3865} 3866 3867/** 3868 * Removes files included via wildcard expansion with a lower extension priority that have 3869 * already been included. 3870 * 3871 * @param file The path to the file. 3872 */ 3873function removeWildcardFilesWithLowerPriorityExtension(file: string, wildcardFiles: ESMap<string, string>, extensions: readonly string[][], keyMapper: (value: string) => string) { 3874 const extensionGroup = forEach(extensions, group => fileExtensionIsOneOf(file, group) ? group : undefined); 3875 if (!extensionGroup) { 3876 return; 3877 } 3878 for (let i = extensionGroup.length - 1; i >= 0; i--) { 3879 const ext = extensionGroup[i]; 3880 if (fileExtensionIs(file, ext)) { 3881 return; 3882 } 3883 const lowerPriorityPath = keyMapper(changeExtension(file, ext)); 3884 wildcardFiles.delete(lowerPriorityPath); 3885 } 3886} 3887 3888/** 3889 * Produces a cleaned version of compiler options with personally identifying info (aka, paths) removed. 3890 * Also converts enum values back to strings. 3891 * @internal 3892 */ 3893export function convertCompilerOptionsForTelemetry(opts: CompilerOptions): CompilerOptions { 3894 const out: CompilerOptions = {}; 3895 for (const key in opts) { 3896 if (hasProperty(opts, key)) { 3897 const type = getOptionFromName(key); 3898 if (type !== undefined) { // Ignore unknown options 3899 out[key] = getOptionValueWithEmptyStrings(opts[key], type); 3900 } 3901 } 3902 } 3903 return out; 3904} 3905 3906function getOptionValueWithEmptyStrings(value: any, option: CommandLineOption): {} { 3907 switch (option.type) { 3908 case "object": // "paths". Can't get any useful information from the value since we blank out strings, so just return "". 3909 return ""; 3910 case "string": // Could be any arbitrary string -- use empty string instead. 3911 return ""; 3912 case "number": // Allow numbers, but be sure to check it's actually a number. 3913 return typeof value === "number" ? value : ""; 3914 case "boolean": 3915 return typeof value === "boolean" ? value : ""; 3916 case "list": 3917 const elementType = option.element; 3918 return isArray(value) ? value.map(v => getOptionValueWithEmptyStrings(v, elementType)) : ""; 3919 default: 3920 return forEachEntry(option.type, (optionEnumValue, optionStringValue) => { 3921 if (optionEnumValue === value) { 3922 return optionStringValue; 3923 } 3924 })!; // TODO: GH#18217 3925 } 3926} 3927 3928 3929function getDefaultValueForOption(option: CommandLineOption) { 3930 switch (option.type) { 3931 case "number": 3932 return 1; 3933 case "boolean": 3934 return true; 3935 case "string": 3936 const defaultValue = option.defaultValueDescription; 3937 return option.isFilePath ? `./${defaultValue && typeof defaultValue === "string" ? defaultValue : ""}` : ""; 3938 case "list": 3939 return []; 3940 case "object": 3941 return {}; 3942 default: 3943 const iterResult = option.type.keys().next(); 3944 if (!iterResult.done) return iterResult.value; 3945 return Debug.fail("Expected 'option.type' to have entries."); 3946 } 3947} 3948