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