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 1391 /* @internal */ 1392 export const optionDeclarations: CommandLineOption[] = [ 1393 ...commonOptionsWithBuild, 1394 ...commandOptionsWithoutBuild, 1395 ]; 1396 1397 /* @internal */ 1398 export const semanticDiagnosticsOptionDeclarations: readonly CommandLineOption[] = 1399 optionDeclarations.filter(option => !!option.affectsSemanticDiagnostics); 1400 1401 /* @internal */ 1402 export const affectsEmitOptionDeclarations: readonly CommandLineOption[] = 1403 optionDeclarations.filter(option => !!option.affectsEmit); 1404 1405 /* @internal */ 1406 export const affectsDeclarationPathOptionDeclarations: readonly CommandLineOption[] = 1407 optionDeclarations.filter(option => !!option.affectsDeclarationPath); 1408 1409 /* @internal */ 1410 export const moduleResolutionOptionDeclarations: readonly CommandLineOption[] = 1411 optionDeclarations.filter(option => !!option.affectsModuleResolution); 1412 1413 /* @internal */ 1414 export const sourceFileAffectingCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option => 1415 !!option.affectsSourceFile || !!option.affectsModuleResolution || !!option.affectsBindDiagnostics); 1416 1417 /* @internal */ 1418 export const optionsAffectingProgramStructure: readonly CommandLineOption[] = 1419 optionDeclarations.filter(option => !!option.affectsProgramStructure); 1420 1421 /* @internal */ 1422 export const transpileOptionValueCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option => 1423 hasProperty(option, "transpileOptionValue")); 1424 1425 // Build related options 1426 /* @internal */ 1427 export const optionsForBuild: CommandLineOption[] = [ 1428 { 1429 name: "verbose", 1430 shortName: "v", 1431 category: Diagnostics.Command_line_Options, 1432 description: Diagnostics.Enable_verbose_logging, 1433 type: "boolean", 1434 defaultValueDescription: false, 1435 }, 1436 { 1437 name: "dry", 1438 shortName: "d", 1439 category: Diagnostics.Command_line_Options, 1440 description: Diagnostics.Show_what_would_be_built_or_deleted_if_specified_with_clean, 1441 type: "boolean", 1442 defaultValueDescription: false, 1443 }, 1444 { 1445 name: "force", 1446 shortName: "f", 1447 category: Diagnostics.Command_line_Options, 1448 description: Diagnostics.Build_all_projects_including_those_that_appear_to_be_up_to_date, 1449 type: "boolean", 1450 defaultValueDescription: false, 1451 }, 1452 { 1453 name: "clean", 1454 category: Diagnostics.Command_line_Options, 1455 description: Diagnostics.Delete_the_outputs_of_all_projects, 1456 type: "boolean", 1457 defaultValueDescription: false, 1458 } 1459 ]; 1460 1461 /* @internal */ 1462 export const buildOpts: CommandLineOption[] = [ 1463 ...commonOptionsWithBuild, 1464 ...optionsForBuild 1465 ]; 1466 1467 /* @internal */ 1468 export const typeAcquisitionDeclarations: CommandLineOption[] = [ 1469 { 1470 /* @deprecated typingOptions.enableAutoDiscovery 1471 * Use typeAcquisition.enable instead. 1472 */ 1473 name: "enableAutoDiscovery", 1474 type: "boolean", 1475 defaultValueDescription: false, 1476 }, 1477 { 1478 name: "enable", 1479 type: "boolean", 1480 defaultValueDescription: false, 1481 }, 1482 { 1483 name: "include", 1484 type: "list", 1485 element: { 1486 name: "include", 1487 type: "string" 1488 } 1489 }, 1490 { 1491 name: "exclude", 1492 type: "list", 1493 element: { 1494 name: "exclude", 1495 type: "string" 1496 } 1497 }, 1498 { 1499 name: "disableFilenameBasedTypeAcquisition", 1500 type: "boolean", 1501 defaultValueDescription: false, 1502 }, 1503 ]; 1504 1505 /* @internal */ 1506 export interface OptionsNameMap { 1507 optionsNameMap: ESMap<string, CommandLineOption>; 1508 shortOptionNames: ESMap<string, string>; 1509 } 1510 1511 /*@internal*/ 1512 export function createOptionNameMap(optionDeclarations: readonly CommandLineOption[]): OptionsNameMap { 1513 const optionsNameMap = new Map<string, CommandLineOption>(); 1514 const shortOptionNames = new Map<string, string>(); 1515 forEach(optionDeclarations, option => { 1516 optionsNameMap.set(option.name.toLowerCase(), option); 1517 if (option.shortName) { 1518 shortOptionNames.set(option.shortName, option.name); 1519 } 1520 }); 1521 1522 return { optionsNameMap, shortOptionNames }; 1523 } 1524 1525 let optionsNameMapCache: OptionsNameMap; 1526 1527 /* @internal */ 1528 export function getOptionsNameMap(): OptionsNameMap { 1529 return optionsNameMapCache ||= createOptionNameMap(optionDeclarations); 1530 } 1531 1532 const compilerOptionsAlternateMode: AlternateModeDiagnostics = { 1533 diagnostic: Diagnostics.Compiler_option_0_may_only_be_used_with_build, 1534 getOptionsNameMap: getBuildOptionsNameMap 1535 }; 1536 1537 /* @internal */ 1538 export const defaultInitCompilerOptions: CompilerOptions = { 1539 module: ModuleKind.CommonJS, 1540 target: ScriptTarget.ES2016, 1541 strict: true, 1542 esModuleInterop: true, 1543 forceConsistentCasingInFileNames: true, 1544 skipLibCheck: true 1545 }; 1546 1547 /* @internal */ 1548 export function convertEnableAutoDiscoveryToEnable(typeAcquisition: TypeAcquisition): TypeAcquisition { 1549 // Convert deprecated typingOptions.enableAutoDiscovery to typeAcquisition.enable 1550 if (typeAcquisition && typeAcquisition.enableAutoDiscovery !== undefined && typeAcquisition.enable === undefined) { 1551 return { 1552 enable: typeAcquisition.enableAutoDiscovery, 1553 include: typeAcquisition.include || [], 1554 exclude: typeAcquisition.exclude || [] 1555 }; 1556 } 1557 return typeAcquisition; 1558 } 1559 1560 /* @internal */ 1561 export function createCompilerDiagnosticForInvalidCustomType(opt: CommandLineOptionOfCustomType): Diagnostic { 1562 return createDiagnosticForInvalidCustomType(opt, createCompilerDiagnostic); 1563 } 1564 1565 function createDiagnosticForInvalidCustomType(opt: CommandLineOptionOfCustomType, createDiagnostic: (message: DiagnosticMessage, arg0: string, arg1: string) => Diagnostic): Diagnostic { 1566 const namesOfType = arrayFrom(opt.type.keys()).map(key => `'${key}'`).join(", "); 1567 return createDiagnostic(Diagnostics.Argument_for_0_option_must_be_Colon_1, `--${opt.name}`, namesOfType); 1568 } 1569 1570 /* @internal */ 1571 export function parseCustomTypeOption(opt: CommandLineOptionOfCustomType, value: string, errors: Push<Diagnostic>) { 1572 return convertJsonOptionOfCustomType(opt, trimString(value || ""), errors); 1573 } 1574 1575 /* @internal */ 1576 export function parseListTypeOption(opt: CommandLineOptionOfListType, value = "", errors: Push<Diagnostic>): (string | number)[] | undefined { 1577 value = trimString(value); 1578 if (startsWith(value, "-")) { 1579 return undefined; 1580 } 1581 if (value === "") { 1582 return []; 1583 } 1584 const values = value.split(","); 1585 switch (opt.element.type) { 1586 case "number": 1587 return mapDefined(values, v => validateJsonOptionValue(opt.element, parseInt(v), errors)); 1588 case "string": 1589 return mapDefined(values, v => validateJsonOptionValue(opt.element, v || "", errors)); 1590 default: 1591 return mapDefined(values, v => parseCustomTypeOption(opt.element as CommandLineOptionOfCustomType, v, errors)); 1592 } 1593 } 1594 1595 /*@internal*/ 1596 export interface OptionsBase { 1597 [option: string]: CompilerOptionsValue | TsConfigSourceFile | undefined; 1598 } 1599 1600 /*@internal*/ 1601 export interface ParseCommandLineWorkerDiagnostics extends DidYouMeanOptionsDiagnostics { 1602 getOptionsNameMap: () => OptionsNameMap; 1603 optionTypeMismatchDiagnostic: DiagnosticMessage; 1604 } 1605 1606 function getOptionName(option: CommandLineOption) { 1607 return option.name; 1608 } 1609 1610 function createUnknownOptionError( 1611 unknownOption: string, 1612 diagnostics: DidYouMeanOptionsDiagnostics, 1613 createDiagnostics: (message: DiagnosticMessage, arg0: string, arg1?: string) => Diagnostic, 1614 unknownOptionErrorText?: string 1615 ) { 1616 if (diagnostics.alternateMode?.getOptionsNameMap().optionsNameMap.has(unknownOption.toLowerCase())) { 1617 return createDiagnostics(diagnostics.alternateMode.diagnostic, unknownOption); 1618 } 1619 1620 const possibleOption = getSpellingSuggestion(unknownOption, diagnostics.optionDeclarations, getOptionName); 1621 return possibleOption ? 1622 createDiagnostics(diagnostics.unknownDidYouMeanDiagnostic, unknownOptionErrorText || unknownOption, possibleOption.name) : 1623 createDiagnostics(diagnostics.unknownOptionDiagnostic, unknownOptionErrorText || unknownOption); 1624 } 1625 1626 /*@internal*/ 1627 export function parseCommandLineWorker( 1628 diagnostics: ParseCommandLineWorkerDiagnostics, 1629 commandLine: readonly string[], 1630 readFile?: (path: string) => string | undefined) { 1631 const options = {} as OptionsBase; 1632 let watchOptions: WatchOptions | undefined; 1633 const fileNames: string[] = []; 1634 const errors: Diagnostic[] = []; 1635 1636 parseStrings(commandLine); 1637 return { 1638 options, 1639 watchOptions, 1640 fileNames, 1641 errors 1642 }; 1643 1644 function parseStrings(args: readonly string[]) { 1645 let i = 0; 1646 while (i < args.length) { 1647 const s = args[i]; 1648 i++; 1649 if (s.charCodeAt(0) === CharacterCodes.at) { 1650 parseResponseFile(s.slice(1)); 1651 } 1652 else if (s.charCodeAt(0) === CharacterCodes.minus) { 1653 const inputOptionName = s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1); 1654 const opt = getOptionDeclarationFromName(diagnostics.getOptionsNameMap, inputOptionName, /*allowShort*/ true); 1655 if (opt) { 1656 i = parseOptionValue(args, i, diagnostics, opt, options, errors); 1657 } 1658 else { 1659 const watchOpt = getOptionDeclarationFromName(watchOptionsDidYouMeanDiagnostics.getOptionsNameMap, inputOptionName, /*allowShort*/ true); 1660 if (watchOpt) { 1661 i = parseOptionValue(args, i, watchOptionsDidYouMeanDiagnostics, watchOpt, watchOptions || (watchOptions = {}), errors); 1662 } 1663 else { 1664 errors.push(createUnknownOptionError(inputOptionName, diagnostics, createCompilerDiagnostic, s)); 1665 } 1666 } 1667 } 1668 else { 1669 fileNames.push(s); 1670 } 1671 } 1672 } 1673 1674 function parseResponseFile(fileName: string) { 1675 const text = tryReadFile(fileName, readFile || (fileName => sys.readFile(fileName))); 1676 if (!isString(text)) { 1677 errors.push(text); 1678 return; 1679 } 1680 1681 const args: string[] = []; 1682 let pos = 0; 1683 while (true) { 1684 while (pos < text.length && text.charCodeAt(pos) <= CharacterCodes.space) pos++; 1685 if (pos >= text.length) break; 1686 const start = pos; 1687 if (text.charCodeAt(start) === CharacterCodes.doubleQuote) { 1688 pos++; 1689 while (pos < text.length && text.charCodeAt(pos) !== CharacterCodes.doubleQuote) pos++; 1690 if (pos < text.length) { 1691 args.push(text.substring(start + 1, pos)); 1692 pos++; 1693 } 1694 else { 1695 errors.push(createCompilerDiagnostic(Diagnostics.Unterminated_quoted_string_in_response_file_0, fileName)); 1696 } 1697 } 1698 else { 1699 while (text.charCodeAt(pos) > CharacterCodes.space) pos++; 1700 args.push(text.substring(start, pos)); 1701 } 1702 } 1703 parseStrings(args); 1704 } 1705 } 1706 1707 function parseOptionValue( 1708 args: readonly string[], 1709 i: number, 1710 diagnostics: ParseCommandLineWorkerDiagnostics, 1711 opt: CommandLineOption, 1712 options: OptionsBase, 1713 errors: Diagnostic[] 1714 ) { 1715 if (opt.isTSConfigOnly) { 1716 const optValue = args[i]; 1717 if (optValue === "null") { 1718 options[opt.name] = undefined; 1719 i++; 1720 } 1721 else if (opt.type === "boolean") { 1722 if (optValue === "false") { 1723 options[opt.name] = validateJsonOptionValue(opt, /*value*/ false, errors); 1724 i++; 1725 } 1726 else { 1727 if (optValue === "true") i++; 1728 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)); 1729 } 1730 } 1731 else { 1732 errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file_or_set_to_null_on_command_line, opt.name)); 1733 if (optValue && !startsWith(optValue, "-")) i++; 1734 } 1735 } 1736 else { 1737 // Check to see if no argument was provided (e.g. "--locale" is the last command-line argument). 1738 if (!args[i] && opt.type !== "boolean") { 1739 errors.push(createCompilerDiagnostic(diagnostics.optionTypeMismatchDiagnostic, opt.name, getCompilerOptionValueTypeString(opt))); 1740 } 1741 1742 if (args[i] !== "null") { 1743 switch (opt.type) { 1744 case "number": 1745 options[opt.name] = validateJsonOptionValue(opt, parseInt(args[i]), errors); 1746 i++; 1747 break; 1748 case "boolean": 1749 // boolean flag has optional value true, false, others 1750 const optValue = args[i]; 1751 options[opt.name] = validateJsonOptionValue(opt, optValue !== "false", errors); 1752 // consume next argument as boolean flag value 1753 if (optValue === "false" || optValue === "true") { 1754 i++; 1755 } 1756 break; 1757 case "string": 1758 options[opt.name] = validateJsonOptionValue(opt, args[i] || "", errors); 1759 i++; 1760 break; 1761 case "list": 1762 const result = parseListTypeOption(opt, args[i], errors); 1763 options[opt.name] = result || []; 1764 if (result) { 1765 i++; 1766 } 1767 break; 1768 // If not a primitive, the possible types are specified in what is effectively a map of options. 1769 default: 1770 options[opt.name] = parseCustomTypeOption(opt as CommandLineOptionOfCustomType, args[i], errors); 1771 i++; 1772 break; 1773 } 1774 } 1775 else { 1776 options[opt.name] = undefined; 1777 i++; 1778 } 1779 } 1780 return i; 1781 } 1782 1783 /*@internal*/ 1784 export const compilerOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnostics = { 1785 alternateMode: compilerOptionsAlternateMode, 1786 getOptionsNameMap, 1787 optionDeclarations, 1788 unknownOptionDiagnostic: Diagnostics.Unknown_compiler_option_0, 1789 unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, 1790 optionTypeMismatchDiagnostic: Diagnostics.Compiler_option_0_expects_an_argument 1791 }; 1792 export function parseCommandLine(commandLine: readonly string[], readFile?: (path: string) => string | undefined): ParsedCommandLine { 1793 return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine, readFile); 1794 } 1795 1796 /** @internal */ 1797 export function getOptionFromName(optionName: string, allowShort?: boolean): CommandLineOption | undefined { 1798 return getOptionDeclarationFromName(getOptionsNameMap, optionName, allowShort); 1799 } 1800 1801 function getOptionDeclarationFromName(getOptionNameMap: () => OptionsNameMap, optionName: string, allowShort = false): CommandLineOption | undefined { 1802 optionName = optionName.toLowerCase(); 1803 const { optionsNameMap, shortOptionNames } = getOptionNameMap(); 1804 // Try to translate short option names to their full equivalents. 1805 if (allowShort) { 1806 const short = shortOptionNames.get(optionName); 1807 if (short !== undefined) { 1808 optionName = short; 1809 } 1810 } 1811 return optionsNameMap.get(optionName); 1812 } 1813 1814 /*@internal*/ 1815 export interface ParsedBuildCommand { 1816 buildOptions: BuildOptions; 1817 watchOptions: WatchOptions | undefined; 1818 projects: string[]; 1819 errors: Diagnostic[]; 1820 } 1821 1822 let buildOptionsNameMapCache: OptionsNameMap; 1823 function getBuildOptionsNameMap(): OptionsNameMap { 1824 return buildOptionsNameMapCache || (buildOptionsNameMapCache = createOptionNameMap(buildOpts)); 1825 } 1826 1827 const buildOptionsAlternateMode: AlternateModeDiagnostics = { 1828 diagnostic: Diagnostics.Compiler_option_0_may_not_be_used_with_build, 1829 getOptionsNameMap 1830 }; 1831 1832 const buildOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnostics = { 1833 alternateMode: buildOptionsAlternateMode, 1834 getOptionsNameMap: getBuildOptionsNameMap, 1835 optionDeclarations: buildOpts, 1836 unknownOptionDiagnostic: Diagnostics.Unknown_build_option_0, 1837 unknownDidYouMeanDiagnostic: Diagnostics.Unknown_build_option_0_Did_you_mean_1, 1838 optionTypeMismatchDiagnostic: Diagnostics.Build_option_0_requires_a_value_of_type_1 1839 }; 1840 1841 /*@internal*/ 1842 export function parseBuildCommand(args: readonly string[]): ParsedBuildCommand { 1843 const { options, watchOptions, fileNames: projects, errors } = parseCommandLineWorker( 1844 buildOptionsDidYouMeanDiagnostics, 1845 args 1846 ); 1847 const buildOptions = options as BuildOptions; 1848 1849 if (projects.length === 0) { 1850 // tsc -b invoked with no extra arguments; act as if invoked with "tsc -b ." 1851 projects.push("."); 1852 } 1853 1854 // Nonsensical combinations 1855 if (buildOptions.clean && buildOptions.force) { 1856 errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force")); 1857 } 1858 if (buildOptions.clean && buildOptions.verbose) { 1859 errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose")); 1860 } 1861 if (buildOptions.clean && buildOptions.watch) { 1862 errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch")); 1863 } 1864 if (buildOptions.watch && buildOptions.dry) { 1865 errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry")); 1866 } 1867 1868 return { buildOptions, watchOptions, projects, errors }; 1869 } 1870 1871 /* @internal */ 1872 export function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string { 1873 const diagnostic = createCompilerDiagnostic.apply(undefined, arguments); 1874 return diagnostic.messageText as string; 1875 } 1876 1877 export type DiagnosticReporter = (diagnostic: Diagnostic) => void; 1878 /** 1879 * Reports config file diagnostics 1880 */ 1881 export interface ConfigFileDiagnosticsReporter { 1882 /** 1883 * Reports unrecoverable error when parsing config file 1884 */ 1885 onUnRecoverableConfigFileDiagnostic: DiagnosticReporter; 1886 } 1887 1888 /** 1889 * Interface extending ParseConfigHost to support ParseConfigFile that reads config file and reports errors 1890 */ 1891 export interface ParseConfigFileHost extends ParseConfigHost, ConfigFileDiagnosticsReporter { 1892 getCurrentDirectory(): string; 1893 } 1894 1895 /** 1896 * Reads the config file, reports errors if any and exits if the config file cannot be found 1897 */ 1898 export function getParsedCommandLineOfConfigFile( 1899 configFileName: string, 1900 optionsToExtend: CompilerOptions | undefined, 1901 host: ParseConfigFileHost, 1902 extendedConfigCache?: Map<ExtendedConfigCacheEntry>, 1903 watchOptionsToExtend?: WatchOptions, 1904 extraFileExtensions?: readonly FileExtensionInfo[], 1905 ): ParsedCommandLine | undefined { 1906 const configFileText = tryReadFile(configFileName, fileName => host.readFile(fileName)); 1907 if (!isString(configFileText)) { 1908 host.onUnRecoverableConfigFileDiagnostic(configFileText); 1909 return undefined; 1910 } 1911 1912 const result = parseJsonText(configFileName, configFileText); 1913 const cwd = host.getCurrentDirectory(); 1914 result.path = toPath(configFileName, cwd, createGetCanonicalFileName(host.useCaseSensitiveFileNames)); 1915 result.resolvedPath = result.path; 1916 result.originalFileName = result.fileName; 1917 return parseJsonSourceFileConfigFileContent( 1918 result, 1919 host, 1920 getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), 1921 optionsToExtend, 1922 getNormalizedAbsolutePath(configFileName, cwd), 1923 /*resolutionStack*/ undefined, 1924 extraFileExtensions, 1925 extendedConfigCache, 1926 watchOptionsToExtend 1927 ); 1928 } 1929 1930 /** 1931 * Read tsconfig.json file 1932 * @param fileName The path to the config file 1933 */ 1934 export function readConfigFile(fileName: string, readFile: (path: string) => string | undefined): { config?: any; error?: Diagnostic } { 1935 const textOrDiagnostic = tryReadFile(fileName, readFile); 1936 return isString(textOrDiagnostic) ? parseConfigFileTextToJson(fileName, textOrDiagnostic) : { config: {}, error: textOrDiagnostic }; 1937 } 1938 1939 /** 1940 * Parse the text of the tsconfig.json file 1941 * @param fileName The path to the config file 1942 * @param jsonText The text of the config file 1943 */ 1944 export function parseConfigFileTextToJson(fileName: string, jsonText: string): { config?: any; error?: Diagnostic } { 1945 const jsonSourceFile = parseJsonText(fileName, jsonText); 1946 return { 1947 config: convertConfigFileToObject(jsonSourceFile, jsonSourceFile.parseDiagnostics, /*reportOptionsErrors*/ false, /*optionsIterator*/ undefined), 1948 error: jsonSourceFile.parseDiagnostics.length ? jsonSourceFile.parseDiagnostics[0] : undefined 1949 }; 1950 } 1951 1952 /** 1953 * Read tsconfig.json file 1954 * @param fileName The path to the config file 1955 */ 1956 export function readJsonConfigFile(fileName: string, readFile: (path: string) => string | undefined): TsConfigSourceFile { 1957 const textOrDiagnostic = tryReadFile(fileName, readFile); 1958 return isString(textOrDiagnostic) ? parseJsonText(fileName, textOrDiagnostic) : { fileName, parseDiagnostics: [textOrDiagnostic] } as TsConfigSourceFile; 1959 } 1960 1961 /*@internal*/ 1962 export function tryReadFile(fileName: string, readFile: (path: string) => string | undefined): string | Diagnostic { 1963 let text: string | undefined; 1964 try { 1965 text = readFile(fileName); 1966 } 1967 catch (e) { 1968 return createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message); 1969 } 1970 return text === undefined ? createCompilerDiagnostic(Diagnostics.Cannot_read_file_0, fileName) : text; 1971 } 1972 1973 function commandLineOptionsToMap(options: readonly CommandLineOption[]) { 1974 return arrayToMap(options, getOptionName); 1975 } 1976 1977 const typeAcquisitionDidYouMeanDiagnostics: DidYouMeanOptionsDiagnostics = { 1978 optionDeclarations: typeAcquisitionDeclarations, 1979 unknownOptionDiagnostic: Diagnostics.Unknown_type_acquisition_option_0, 1980 unknownDidYouMeanDiagnostic: Diagnostics.Unknown_type_acquisition_option_0_Did_you_mean_1, 1981 }; 1982 1983 let watchOptionsNameMapCache: OptionsNameMap; 1984 function getWatchOptionsNameMap(): OptionsNameMap { 1985 return watchOptionsNameMapCache || (watchOptionsNameMapCache = createOptionNameMap(optionsForWatch)); 1986 } 1987 const watchOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnostics = { 1988 getOptionsNameMap: getWatchOptionsNameMap, 1989 optionDeclarations: optionsForWatch, 1990 unknownOptionDiagnostic: Diagnostics.Unknown_watch_option_0, 1991 unknownDidYouMeanDiagnostic: Diagnostics.Unknown_watch_option_0_Did_you_mean_1, 1992 optionTypeMismatchDiagnostic: Diagnostics.Watch_option_0_requires_a_value_of_type_1 1993 }; 1994 1995 let commandLineCompilerOptionsMapCache: ESMap<string, CommandLineOption>; 1996 function getCommandLineCompilerOptionsMap() { 1997 return commandLineCompilerOptionsMapCache || (commandLineCompilerOptionsMapCache = commandLineOptionsToMap(optionDeclarations)); 1998 } 1999 let commandLineWatchOptionsMapCache: ESMap<string, CommandLineOption>; 2000 function getCommandLineWatchOptionsMap() { 2001 return commandLineWatchOptionsMapCache || (commandLineWatchOptionsMapCache = commandLineOptionsToMap(optionsForWatch)); 2002 } 2003 let commandLineTypeAcquisitionMapCache: ESMap<string, CommandLineOption>; 2004 function getCommandLineTypeAcquisitionMap() { 2005 return commandLineTypeAcquisitionMapCache || (commandLineTypeAcquisitionMapCache = commandLineOptionsToMap(typeAcquisitionDeclarations)); 2006 } 2007 2008 let _tsconfigRootOptions: TsConfigOnlyOption; 2009 function getTsconfigRootOptionsMap() { 2010 if (_tsconfigRootOptions === undefined) { 2011 _tsconfigRootOptions = { 2012 name: undefined!, // should never be needed since this is root 2013 type: "object", 2014 elementOptions: commandLineOptionsToMap([ 2015 { 2016 name: "compilerOptions", 2017 type: "object", 2018 elementOptions: getCommandLineCompilerOptionsMap(), 2019 extraKeyDiagnostics: compilerOptionsDidYouMeanDiagnostics, 2020 }, 2021 { 2022 name: "watchOptions", 2023 type: "object", 2024 elementOptions: getCommandLineWatchOptionsMap(), 2025 extraKeyDiagnostics: watchOptionsDidYouMeanDiagnostics, 2026 }, 2027 { 2028 name: "typingOptions", 2029 type: "object", 2030 elementOptions: getCommandLineTypeAcquisitionMap(), 2031 extraKeyDiagnostics: typeAcquisitionDidYouMeanDiagnostics, 2032 }, 2033 { 2034 name: "typeAcquisition", 2035 type: "object", 2036 elementOptions: getCommandLineTypeAcquisitionMap(), 2037 extraKeyDiagnostics: typeAcquisitionDidYouMeanDiagnostics 2038 }, 2039 { 2040 name: "extends", 2041 type: "string", 2042 category: Diagnostics.File_Management, 2043 }, 2044 { 2045 name: "references", 2046 type: "list", 2047 element: { 2048 name: "references", 2049 type: "object" 2050 }, 2051 category: Diagnostics.Projects, 2052 }, 2053 { 2054 name: "files", 2055 type: "list", 2056 element: { 2057 name: "files", 2058 type: "string" 2059 }, 2060 category: Diagnostics.File_Management, 2061 }, 2062 { 2063 name: "include", 2064 type: "list", 2065 element: { 2066 name: "include", 2067 type: "string" 2068 }, 2069 category: Diagnostics.File_Management, 2070 defaultValueDescription: Diagnostics.if_files_is_specified_otherwise_Asterisk_Asterisk_Slash_Asterisk 2071 }, 2072 { 2073 name: "exclude", 2074 type: "list", 2075 element: { 2076 name: "exclude", 2077 type: "string" 2078 }, 2079 category: Diagnostics.File_Management, 2080 defaultValueDescription: Diagnostics.node_modules_bower_components_jspm_packages_plus_the_value_of_outDir_if_one_is_specified 2081 }, 2082 compileOnSaveCommandLineOption 2083 ]) 2084 }; 2085 } 2086 return _tsconfigRootOptions; 2087 } 2088 2089 /*@internal*/ 2090 interface JsonConversionNotifier { 2091 /** 2092 * Notifies parent option object is being set with the optionKey and a valid optionValue 2093 * Currently it notifies only if there is element with type object (parentOption) and 2094 * has element's option declarations map associated with it 2095 * @param parentOption parent option name in which the option and value are being set 2096 * @param option option declaration which is being set with the value 2097 * @param value value of the option 2098 */ 2099 onSetValidOptionKeyValueInParent(parentOption: string, option: CommandLineOption, value: CompilerOptionsValue): void; 2100 /** 2101 * Notify when valid root key value option is being set 2102 * @param key option key 2103 * @param keyNode node corresponding to node in the source file 2104 * @param value computed value of the key 2105 * @param ValueNode node corresponding to value in the source file 2106 */ 2107 onSetValidOptionKeyValueInRoot(key: string, keyNode: PropertyName, value: CompilerOptionsValue, valueNode: Expression): void; 2108 /** 2109 * Notify when unknown root key value option is being set 2110 * @param key option key 2111 * @param keyNode node corresponding to node in the source file 2112 * @param value computed value of the key 2113 * @param ValueNode node corresponding to value in the source file 2114 */ 2115 onSetUnknownOptionKeyValueInRoot(key: string, keyNode: PropertyName, value: CompilerOptionsValue, valueNode: Expression): void; 2116 } 2117 2118 function convertConfigFileToObject(sourceFile: JsonSourceFile, errors: Push<Diagnostic>, reportOptionsErrors: boolean, optionsIterator: JsonConversionNotifier | undefined): any { 2119 const rootExpression: Expression | undefined = sourceFile.statements[0]?.expression; 2120 const knownRootOptions = reportOptionsErrors ? getTsconfigRootOptionsMap() : undefined; 2121 if (rootExpression && rootExpression.kind !== SyntaxKind.ObjectLiteralExpression) { 2122 errors.push(createDiagnosticForNodeInSourceFile( 2123 sourceFile, 2124 rootExpression, 2125 Diagnostics.The_root_value_of_a_0_file_must_be_an_object, 2126 getBaseFileName(sourceFile.fileName) === "jsconfig.json" ? "jsconfig.json" : "tsconfig.json" 2127 )); 2128 // Last-ditch error recovery. Somewhat useful because the JSON parser will recover from some parse errors by 2129 // synthesizing a top-level array literal expression. There's a reasonable chance the first element of that 2130 // array is a well-formed configuration object, made into an array element by stray characters. 2131 if (isArrayLiteralExpression(rootExpression)) { 2132 const firstObject = find(rootExpression.elements, isObjectLiteralExpression); 2133 if (firstObject) { 2134 return convertToObjectWorker(sourceFile, firstObject, errors, /*returnValue*/ true, knownRootOptions, optionsIterator); 2135 } 2136 } 2137 return {}; 2138 } 2139 return convertToObjectWorker(sourceFile, rootExpression, errors, /*returnValue*/ true, knownRootOptions, optionsIterator); 2140 } 2141 2142 /** 2143 * Convert the json syntax tree into the json value 2144 */ 2145 export function convertToObject(sourceFile: JsonSourceFile, errors: Push<Diagnostic>): any { 2146 return convertToObjectWorker(sourceFile, sourceFile.statements[0]?.expression, errors, /*returnValue*/ true, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined); 2147 } 2148 2149 /** 2150 * Convert the json syntax tree into the json value and report errors 2151 * This returns the json value (apart from checking errors) only if returnValue provided is true. 2152 * Otherwise it just checks the errors and returns undefined 2153 */ 2154 /*@internal*/ 2155 export function convertToObjectWorker( 2156 sourceFile: JsonSourceFile, 2157 rootExpression: Expression | undefined, 2158 errors: Push<Diagnostic>, 2159 returnValue: boolean, 2160 knownRootOptions: CommandLineOption | undefined, 2161 jsonConversionNotifier: JsonConversionNotifier | undefined): any { 2162 if (!rootExpression) { 2163 return returnValue ? {} : undefined; 2164 } 2165 2166 return convertPropertyValueToJson(rootExpression, knownRootOptions); 2167 2168 function isRootOptionMap(knownOptions: ESMap<string, CommandLineOption> | undefined) { 2169 return knownRootOptions && (knownRootOptions as TsConfigOnlyOption).elementOptions === knownOptions; 2170 } 2171 2172 function convertObjectLiteralExpressionToJson( 2173 node: ObjectLiteralExpression, 2174 knownOptions: ESMap<string, CommandLineOption> | undefined, 2175 extraKeyDiagnostics: DidYouMeanOptionsDiagnostics | undefined, 2176 parentOption: string | undefined 2177 ): any { 2178 const result: any = returnValue ? {} : undefined; 2179 for (const element of node.properties) { 2180 if (element.kind !== SyntaxKind.PropertyAssignment) { 2181 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element, Diagnostics.Property_assignment_expected)); 2182 continue; 2183 } 2184 2185 if (element.questionToken) { 2186 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.questionToken, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, "?")); 2187 } 2188 if (!isDoubleQuotedString(element.name)) { 2189 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.name, Diagnostics.String_literal_with_double_quotes_expected)); 2190 } 2191 2192 const textOfKey = isComputedNonLiteralName(element.name) ? undefined : getTextOfPropertyName(element.name); 2193 const keyText = textOfKey && unescapeLeadingUnderscores(textOfKey); 2194 const option = keyText && knownOptions ? knownOptions.get(keyText) : undefined; 2195 if (keyText && extraKeyDiagnostics && !option) { 2196 if (knownOptions) { 2197 errors.push(createUnknownOptionError( 2198 keyText, 2199 extraKeyDiagnostics, 2200 (message, arg0, arg1) => createDiagnosticForNodeInSourceFile(sourceFile, element.name, message, arg0, arg1) 2201 )); 2202 } 2203 else { 2204 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.name, extraKeyDiagnostics.unknownOptionDiagnostic, keyText)); 2205 } 2206 } 2207 const value = convertPropertyValueToJson(element.initializer, option); 2208 if (typeof keyText !== "undefined") { 2209 if (returnValue) { 2210 result[keyText] = value; 2211 } 2212 // Notify key value set, if user asked for it 2213 if (jsonConversionNotifier && 2214 // Current callbacks are only on known parent option or if we are setting values in the root 2215 (parentOption || isRootOptionMap(knownOptions))) { 2216 const isValidOptionValue = isCompilerOptionsValue(option, value); 2217 if (parentOption) { 2218 if (isValidOptionValue) { 2219 // Notify option set in the parent if its a valid option value 2220 jsonConversionNotifier.onSetValidOptionKeyValueInParent(parentOption, option!, value); 2221 } 2222 } 2223 else if (isRootOptionMap(knownOptions)) { 2224 if (isValidOptionValue) { 2225 // Notify about the valid root key value being set 2226 jsonConversionNotifier.onSetValidOptionKeyValueInRoot(keyText, element.name, value, element.initializer); 2227 } 2228 else if (!option) { 2229 // Notify about the unknown root key value being set 2230 jsonConversionNotifier.onSetUnknownOptionKeyValueInRoot(keyText, element.name, value, element.initializer); 2231 } 2232 } 2233 } 2234 } 2235 } 2236 return result; 2237 } 2238 2239 function convertArrayLiteralExpressionToJson( 2240 elements: NodeArray<Expression>, 2241 elementOption: CommandLineOption | undefined 2242 ) { 2243 if (!returnValue) { 2244 elements.forEach(element => convertPropertyValueToJson(element, elementOption)); 2245 return undefined; 2246 } 2247 2248 // Filter out invalid values 2249 return filter(elements.map(element => convertPropertyValueToJson(element, elementOption)), v => v !== undefined); 2250 } 2251 2252 function convertPropertyValueToJson(valueExpression: Expression, option: CommandLineOption | undefined): any { 2253 let invalidReported: boolean | undefined; 2254 switch (valueExpression.kind) { 2255 case SyntaxKind.TrueKeyword: 2256 reportInvalidOptionValue(option && option.type !== "boolean"); 2257 return validateValue(/*value*/ true); 2258 2259 case SyntaxKind.FalseKeyword: 2260 reportInvalidOptionValue(option && option.type !== "boolean"); 2261 return validateValue(/*value*/ false); 2262 2263 case SyntaxKind.NullKeyword: 2264 reportInvalidOptionValue(option && option.name === "extends"); // "extends" is the only option we don't allow null/undefined for 2265 return validateValue(/*value*/ null); // eslint-disable-line no-null/no-null 2266 2267 case SyntaxKind.StringLiteral: 2268 if (!isDoubleQuotedString(valueExpression)) { 2269 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.String_literal_with_double_quotes_expected)); 2270 } 2271 reportInvalidOptionValue(option && (isString(option.type) && option.type !== "string")); 2272 const text = (valueExpression as StringLiteral).text; 2273 if (option && !isString(option.type)) { 2274 const customOption = option as CommandLineOptionOfCustomType; 2275 // Validate custom option type 2276 if (!customOption.type.has(text.toLowerCase())) { 2277 errors.push( 2278 createDiagnosticForInvalidCustomType( 2279 customOption, 2280 (message, arg0, arg1) => createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, message, arg0, arg1) 2281 ) 2282 ); 2283 invalidReported = true; 2284 } 2285 } 2286 return validateValue(text); 2287 2288 case SyntaxKind.NumericLiteral: 2289 reportInvalidOptionValue(option && option.type !== "number"); 2290 return validateValue(Number((valueExpression as NumericLiteral).text)); 2291 2292 case SyntaxKind.PrefixUnaryExpression: 2293 if ((valueExpression as PrefixUnaryExpression).operator !== SyntaxKind.MinusToken || (valueExpression as PrefixUnaryExpression).operand.kind !== SyntaxKind.NumericLiteral) { 2294 break; // not valid JSON syntax 2295 } 2296 reportInvalidOptionValue(option && option.type !== "number"); 2297 return validateValue(-Number(((valueExpression as PrefixUnaryExpression).operand as NumericLiteral).text)); 2298 2299 case SyntaxKind.ObjectLiteralExpression: 2300 reportInvalidOptionValue(option && option.type !== "object"); 2301 const objectLiteralExpression = valueExpression as ObjectLiteralExpression; 2302 2303 // Currently having element option declaration in the tsconfig with type "object" 2304 // determines if it needs onSetValidOptionKeyValueInParent callback or not 2305 // At moment there are only "compilerOptions", "typeAcquisition" and "typingOptions" 2306 // that satifies it and need it to modify options set in them (for normalizing file paths) 2307 // vs what we set in the json 2308 // If need arises, we can modify this interface and callbacks as needed 2309 if (option) { 2310 const { elementOptions, extraKeyDiagnostics, name: optionName } = option as TsConfigOnlyOption; 2311 return validateValue(convertObjectLiteralExpressionToJson(objectLiteralExpression, 2312 elementOptions, extraKeyDiagnostics, optionName)); 2313 } 2314 else { 2315 return validateValue(convertObjectLiteralExpressionToJson( 2316 objectLiteralExpression, /* knownOptions*/ undefined, 2317 /*extraKeyDiagnosticMessage */ undefined, /*parentOption*/ undefined)); 2318 } 2319 2320 case SyntaxKind.ArrayLiteralExpression: 2321 reportInvalidOptionValue(option && option.type !== "list"); 2322 return validateValue(convertArrayLiteralExpressionToJson( 2323 (valueExpression as ArrayLiteralExpression).elements, 2324 option && (option as CommandLineOptionOfListType).element)); 2325 } 2326 2327 // Not in expected format 2328 if (option) { 2329 reportInvalidOptionValue(/*isError*/ true); 2330 } 2331 else { 2332 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.Property_value_can_only_be_string_literal_numeric_literal_true_false_null_object_literal_or_array_literal)); 2333 } 2334 2335 return undefined; 2336 2337 function validateValue(value: CompilerOptionsValue) { 2338 if (!invalidReported) { 2339 const diagnostic = option?.extraValidation?.(value); 2340 if (diagnostic) { 2341 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, ...diagnostic)); 2342 return undefined; 2343 } 2344 } 2345 return value; 2346 } 2347 2348 function reportInvalidOptionValue(isError: boolean | undefined) { 2349 if (isError) { 2350 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.Compiler_option_0_requires_a_value_of_type_1, option!.name, getCompilerOptionValueTypeString(option!))); 2351 invalidReported = true; 2352 } 2353 } 2354 } 2355 2356 function isDoubleQuotedString(node: Node): boolean { 2357 return isStringLiteral(node) && isStringDoubleQuoted(node, sourceFile); 2358 } 2359 } 2360 2361 function getCompilerOptionValueTypeString(option: CommandLineOption) { 2362 return option.type === "list" ? 2363 "Array" : 2364 isString(option.type) ? option.type : "string"; 2365 } 2366 2367 function isCompilerOptionsValue(option: CommandLineOption | undefined, value: any): value is CompilerOptionsValue { 2368 if (option) { 2369 if (isNullOrUndefined(value)) return true; // All options are undefinable/nullable 2370 if (option.type === "list") { 2371 return isArray(value); 2372 } 2373 const expectedType = isString(option.type) ? option.type : "string"; 2374 return typeof value === expectedType; 2375 } 2376 return false; 2377 } 2378 2379 /** @internal */ 2380 export interface TSConfig { 2381 compilerOptions: CompilerOptions; 2382 compileOnSave: boolean | undefined; 2383 exclude?: readonly string[]; 2384 files: readonly string[] | undefined; 2385 include?: readonly string[]; 2386 references: readonly ProjectReference[] | undefined; 2387 } 2388 2389 /** @internal */ 2390 export interface ConvertToTSConfigHost { 2391 getCurrentDirectory(): string; 2392 useCaseSensitiveFileNames: boolean; 2393 } 2394 2395 /** 2396 * Generate an uncommented, complete tsconfig for use with "--showConfig" 2397 * @param configParseResult options to be generated into tsconfig.json 2398 * @param configFileName name of the parsed config file - output paths will be generated relative to this 2399 * @param host provides current directory and case sensitivity services 2400 */ 2401 /** @internal */ 2402 export function convertToTSConfig(configParseResult: ParsedCommandLine, configFileName: string, host: ConvertToTSConfigHost): TSConfig { 2403 const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames); 2404 const files = map( 2405 filter( 2406 configParseResult.fileNames, 2407 !configParseResult.options.configFile?.configFileSpecs?.validatedIncludeSpecs ? returnTrue : matchesSpecs( 2408 configFileName, 2409 configParseResult.options.configFile.configFileSpecs.validatedIncludeSpecs, 2410 configParseResult.options.configFile.configFileSpecs.validatedExcludeSpecs, 2411 host, 2412 ) 2413 ), 2414 f => getRelativePathFromFile(getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), getNormalizedAbsolutePath(f, host.getCurrentDirectory()), getCanonicalFileName) 2415 ); 2416 const optionMap = serializeCompilerOptions(configParseResult.options, { configFilePath: getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), useCaseSensitiveFileNames: host.useCaseSensitiveFileNames }); 2417 const watchOptionMap = configParseResult.watchOptions && serializeWatchOptions(configParseResult.watchOptions); 2418 const config = { 2419 compilerOptions: { 2420 ...optionMapToObject(optionMap), 2421 showConfig: undefined, 2422 configFile: undefined, 2423 configFilePath: undefined, 2424 help: undefined, 2425 init: undefined, 2426 listFiles: undefined, 2427 listEmittedFiles: undefined, 2428 project: undefined, 2429 build: undefined, 2430 version: undefined, 2431 }, 2432 watchOptions: watchOptionMap && optionMapToObject(watchOptionMap), 2433 references: map(configParseResult.projectReferences, r => ({ ...r, path: r.originalPath ? r.originalPath : "", originalPath: undefined })), 2434 files: length(files) ? files : undefined, 2435 ...(configParseResult.options.configFile?.configFileSpecs ? { 2436 include: filterSameAsDefaultInclude(configParseResult.options.configFile.configFileSpecs.validatedIncludeSpecs), 2437 exclude: configParseResult.options.configFile.configFileSpecs.validatedExcludeSpecs 2438 } : {}), 2439 compileOnSave: !!configParseResult.compileOnSave ? true : undefined 2440 }; 2441 return config; 2442 } 2443 2444 function optionMapToObject(optionMap: ESMap<string, CompilerOptionsValue>): object { 2445 return { 2446 ...arrayFrom(optionMap.entries()).reduce((prev, cur) => ({ ...prev, [cur[0]]: cur[1] }), {}), 2447 }; 2448 } 2449 2450 function filterSameAsDefaultInclude(specs: readonly string[] | undefined) { 2451 if (!length(specs)) return undefined; 2452 if (length(specs) !== 1) return specs; 2453 if (specs![0] === defaultIncludeSpec) return undefined; 2454 return specs; 2455 } 2456 2457 function matchesSpecs(path: string, includeSpecs: readonly string[] | undefined, excludeSpecs: readonly string[] | undefined, host: ConvertToTSConfigHost): (path: string) => boolean { 2458 if (!includeSpecs) return returnTrue; 2459 const patterns = getFileMatcherPatterns(path, excludeSpecs, includeSpecs, host.useCaseSensitiveFileNames, host.getCurrentDirectory()); 2460 const excludeRe = patterns.excludePattern && getRegexFromPattern(patterns.excludePattern, host.useCaseSensitiveFileNames); 2461 const includeRe = patterns.includeFilePattern && getRegexFromPattern(patterns.includeFilePattern, host.useCaseSensitiveFileNames); 2462 if (includeRe) { 2463 if (excludeRe) { 2464 return path => !(includeRe.test(path) && !excludeRe.test(path)); 2465 } 2466 return path => !includeRe.test(path); 2467 } 2468 if (excludeRe) { 2469 return path => excludeRe.test(path); 2470 } 2471 return returnTrue; 2472 } 2473 2474 function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption): ESMap<string, string | number> | undefined { 2475 if (optionDefinition.type === "string" || optionDefinition.type === "number" || optionDefinition.type === "boolean" || optionDefinition.type === "object") { 2476 // this is of a type CommandLineOptionOfPrimitiveType 2477 return undefined; 2478 } 2479 else if (optionDefinition.type === "list") { 2480 return getCustomTypeMapOfCommandLineOption(optionDefinition.element); 2481 } 2482 else { 2483 return optionDefinition.type; 2484 } 2485 } 2486 2487 /* @internal */ 2488 export function getNameOfCompilerOptionValue(value: CompilerOptionsValue, customTypeMap: ESMap<string, string | number>): string | undefined { 2489 // There is a typeMap associated with this command-line option so use it to map value back to its name 2490 return forEachEntry(customTypeMap, (mapValue, key) => { 2491 if (mapValue === value) { 2492 return key; 2493 } 2494 }); 2495 } 2496 2497 function serializeCompilerOptions( 2498 options: CompilerOptions, 2499 pathOptions?: { configFilePath: string, useCaseSensitiveFileNames: boolean } 2500 ): ESMap<string, CompilerOptionsValue> { 2501 return serializeOptionBaseObject(options, getOptionsNameMap(), pathOptions); 2502 } 2503 2504 function serializeWatchOptions(options: WatchOptions) { 2505 return serializeOptionBaseObject(options, getWatchOptionsNameMap()); 2506 } 2507 2508 function serializeOptionBaseObject( 2509 options: OptionsBase, 2510 { optionsNameMap }: OptionsNameMap, 2511 pathOptions?: { configFilePath: string, useCaseSensitiveFileNames: boolean } 2512 ): ESMap<string, CompilerOptionsValue> { 2513 const result = new Map<string, CompilerOptionsValue>(); 2514 const getCanonicalFileName = pathOptions && createGetCanonicalFileName(pathOptions.useCaseSensitiveFileNames); 2515 2516 for (const name in options) { 2517 if (hasProperty(options, name)) { 2518 // tsconfig only options cannot be specified via command line, 2519 // so we can assume that only types that can appear here string | number | boolean 2520 if (optionsNameMap.has(name) && (optionsNameMap.get(name)!.category === Diagnostics.Command_line_Options || optionsNameMap.get(name)!.category === Diagnostics.Output_Formatting)) { 2521 continue; 2522 } 2523 const value = options[name] as CompilerOptionsValue; 2524 const optionDefinition = optionsNameMap.get(name.toLowerCase()); 2525 if (optionDefinition) { 2526 const customTypeMap = getCustomTypeMapOfCommandLineOption(optionDefinition); 2527 if (!customTypeMap) { 2528 // There is no map associated with this compiler option then use the value as-is 2529 // This is the case if the value is expect to be string, number, boolean or list of string 2530 if (pathOptions && optionDefinition.isFilePath) { 2531 result.set(name, getRelativePathFromFile(pathOptions.configFilePath, getNormalizedAbsolutePath(value as string, getDirectoryPath(pathOptions.configFilePath)), getCanonicalFileName!)); 2532 } 2533 else { 2534 result.set(name, value); 2535 } 2536 } 2537 else { 2538 if (optionDefinition.type === "list") { 2539 result.set(name, (value as readonly (string | number)[]).map(element => getNameOfCompilerOptionValue(element, customTypeMap)!)); // TODO: GH#18217 2540 } 2541 else { 2542 // There is a typeMap associated with this command-line option so use it to map value back to its name 2543 result.set(name, getNameOfCompilerOptionValue(value, customTypeMap)); 2544 } 2545 } 2546 } 2547 } 2548 } 2549 return result; 2550 } 2551 2552 /** 2553 * Generate a list of the compiler options whose value is not the default. 2554 * @param options compilerOptions to be evaluated. 2555 /** @internal */ 2556 export function getCompilerOptionsDiffValue(options: CompilerOptions, newLine: string): string { 2557 const compilerOptionsMap = getSerializedCompilerOption(options); 2558 return getOverwrittenDefaultOptions(); 2559 2560 function makePadding(paddingLength: number): string { 2561 return Array(paddingLength + 1).join(" "); 2562 } 2563 2564 function getOverwrittenDefaultOptions() { 2565 const result: string[] = []; 2566 const tab = makePadding(2); 2567 commandOptionsWithoutBuild.forEach(cmd => { 2568 if (!compilerOptionsMap.has(cmd.name)) { 2569 return; 2570 } 2571 2572 const newValue = compilerOptionsMap.get(cmd.name); 2573 const defaultValue = getDefaultValueForOption(cmd); 2574 if (newValue !== defaultValue) { 2575 result.push(`${tab}${cmd.name}: ${newValue}`); 2576 } 2577 else if (hasProperty(defaultInitCompilerOptions, cmd.name)) { 2578 result.push(`${tab}${cmd.name}: ${defaultValue}`); 2579 } 2580 }); 2581 return result.join(newLine) + newLine; 2582 } 2583 } 2584 2585 /** 2586 * Get the compiler options to be written into the tsconfig.json. 2587 * @param options commandlineOptions to be included in the compileOptions. 2588 */ 2589 function getSerializedCompilerOption(options: CompilerOptions): ESMap<string, CompilerOptionsValue> { 2590 const compilerOptions = extend(options, defaultInitCompilerOptions); 2591 return serializeCompilerOptions(compilerOptions); 2592 } 2593 /** 2594 * Generate tsconfig configuration when running command line "--init" 2595 * @param options commandlineOptions to be generated into tsconfig.json 2596 * @param fileNames array of filenames to be generated into tsconfig.json 2597 */ 2598 /* @internal */ 2599 export function generateTSConfig(options: CompilerOptions, fileNames: readonly string[], newLine: string): string { 2600 const compilerOptionsMap = getSerializedCompilerOption(options); 2601 return writeConfigurations(); 2602 2603 function makePadding(paddingLength: number): string { 2604 return Array(paddingLength + 1).join(" "); 2605 } 2606 2607 function isAllowedOptionForOutput({ category, name, isCommandLineOnly }: CommandLineOption): boolean { 2608 // Skip options which do not have a category or have categories which are more niche 2609 const categoriesToSkip = [Diagnostics.Command_line_Options, Diagnostics.Editor_Support, Diagnostics.Compiler_Diagnostics, Diagnostics.Backwards_Compatibility, Diagnostics.Watch_and_Build_Modes, Diagnostics.Output_Formatting]; 2610 return !isCommandLineOnly && category !== undefined && (!categoriesToSkip.includes(category) || compilerOptionsMap.has(name)); 2611 } 2612 2613 function writeConfigurations() { 2614 // Filter applicable options to place in the file 2615 const categorizedOptions = new Map<DiagnosticMessage, CommandLineOption[]>(); 2616 // Set allowed categories in order 2617 categorizedOptions.set(Diagnostics.Projects, []); 2618 categorizedOptions.set(Diagnostics.Language_and_Environment, []); 2619 categorizedOptions.set(Diagnostics.Modules, []); 2620 categorizedOptions.set(Diagnostics.JavaScript_Support, []); 2621 categorizedOptions.set(Diagnostics.Emit, []); 2622 categorizedOptions.set(Diagnostics.Interop_Constraints, []); 2623 categorizedOptions.set(Diagnostics.Type_Checking, []); 2624 categorizedOptions.set(Diagnostics.Completeness, []); 2625 for (const option of optionDeclarations) { 2626 if (isAllowedOptionForOutput(option)) { 2627 let listForCategory = categorizedOptions.get(option.category!); 2628 if (!listForCategory) categorizedOptions.set(option.category!, listForCategory = []); 2629 listForCategory.push(option); 2630 } 2631 } 2632 2633 // Serialize all options and their descriptions 2634 let marginLength = 0; 2635 let seenKnownKeys = 0; 2636 const entries: { value: string, description?: string }[] = []; 2637 categorizedOptions.forEach((options, category) => { 2638 if (entries.length !== 0) { 2639 entries.push({ value: "" }); 2640 } 2641 entries.push({ value: `/* ${getLocaleSpecificMessage(category)} */` }); 2642 for (const option of options) { 2643 let optionName; 2644 if (compilerOptionsMap.has(option.name)) { 2645 optionName = `"${option.name}": ${JSON.stringify(compilerOptionsMap.get(option.name))}${(seenKnownKeys += 1) === compilerOptionsMap.size ? "" : ","}`; 2646 } 2647 else { 2648 optionName = `// "${option.name}": ${JSON.stringify(getDefaultValueForOption(option))},`; 2649 } 2650 entries.push({ 2651 value: optionName, 2652 description: `/* ${option.description && getLocaleSpecificMessage(option.description) || option.name} */` 2653 }); 2654 marginLength = Math.max(optionName.length, marginLength); 2655 } 2656 }); 2657 2658 // Write the output 2659 const tab = makePadding(2); 2660 const result: string[] = []; 2661 result.push(`{`); 2662 result.push(`${tab}"compilerOptions": {`); 2663 result.push(`${tab}${tab}/* ${getLocaleSpecificMessage(Diagnostics.Visit_https_Colon_Slash_Slashaka_ms_Slashtsconfig_to_read_more_about_this_file)} */`); 2664 result.push(""); 2665 // Print out each row, aligning all the descriptions on the same column. 2666 for (const entry of entries) { 2667 const { value, description = "" } = entry; 2668 result.push(value && `${tab}${tab}${value}${description && (makePadding(marginLength - value.length + 2) + description)}`); 2669 } 2670 if (fileNames.length) { 2671 result.push(`${tab}},`); 2672 result.push(`${tab}"files": [`); 2673 for (let i = 0; i < fileNames.length; i++) { 2674 result.push(`${tab}${tab}${JSON.stringify(fileNames[i])}${i === fileNames.length - 1 ? "" : ","}`); 2675 } 2676 result.push(`${tab}]`); 2677 } 2678 else { 2679 result.push(`${tab}}`); 2680 } 2681 result.push(`}`); 2682 2683 return result.join(newLine) + newLine; 2684 } 2685 } 2686 2687 /* @internal */ 2688 export function convertToOptionsWithAbsolutePaths(options: CompilerOptions, toAbsolutePath: (path: string) => string) { 2689 const result: CompilerOptions = {}; 2690 const optionsNameMap = getOptionsNameMap().optionsNameMap; 2691 2692 for (const name in options) { 2693 if (hasProperty(options, name)) { 2694 result[name] = convertToOptionValueWithAbsolutePaths( 2695 optionsNameMap.get(name.toLowerCase()), 2696 options[name] as CompilerOptionsValue, 2697 toAbsolutePath 2698 ); 2699 } 2700 } 2701 if (result.configFilePath) { 2702 result.configFilePath = toAbsolutePath(result.configFilePath); 2703 } 2704 return result; 2705 } 2706 2707 function convertToOptionValueWithAbsolutePaths(option: CommandLineOption | undefined, value: CompilerOptionsValue, toAbsolutePath: (path: string) => string) { 2708 if (option && !isNullOrUndefined(value)) { 2709 if (option.type === "list") { 2710 const values = value as readonly (string | number)[]; 2711 if (option.element.isFilePath && values.length) { 2712 return values.map(toAbsolutePath); 2713 } 2714 } 2715 else if (option.isFilePath) { 2716 return toAbsolutePath(value as string); 2717 } 2718 } 2719 return value; 2720 } 2721 2722 /** 2723 * Parse the contents of a config file (tsconfig.json). 2724 * @param json The contents of the config file to parse 2725 * @param host Instance of ParseConfigHost used to enumerate files in folder. 2726 * @param basePath A root directory to resolve relative path entries in the config 2727 * file to. e.g. outDir 2728 */ 2729 export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: readonly FileExtensionInfo[], extendedConfigCache?: Map<ExtendedConfigCacheEntry>, existingWatchOptions?: WatchOptions): ParsedCommandLine { 2730 return parseJsonConfigFileContentWorker(json, /*sourceFile*/ undefined, host, basePath, existingOptions, existingWatchOptions, configFileName, resolutionStack, extraFileExtensions, extendedConfigCache); 2731 } 2732 2733 /** 2734 * Parse the contents of a config file (tsconfig.json). 2735 * @param jsonNode The contents of the config file to parse 2736 * @param host Instance of ParseConfigHost used to enumerate files in folder. 2737 * @param basePath A root directory to resolve relative path entries in the config 2738 * file to. e.g. outDir 2739 */ 2740 export function parseJsonSourceFileConfigFileContent(sourceFile: TsConfigSourceFile, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: readonly FileExtensionInfo[], extendedConfigCache?: Map<ExtendedConfigCacheEntry>, existingWatchOptions?: WatchOptions): ParsedCommandLine { 2741 tracing?.push(tracing.Phase.Parse, "parseJsonSourceFileConfigFileContent", { path: sourceFile.fileName }); 2742 const result = parseJsonConfigFileContentWorker(/*json*/ undefined, sourceFile, host, basePath, existingOptions, existingWatchOptions, configFileName, resolutionStack, extraFileExtensions, extendedConfigCache); 2743 tracing?.pop(); 2744 return result; 2745 } 2746 2747 /*@internal*/ 2748 export function setConfigFileInOptions(options: CompilerOptions, configFile: TsConfigSourceFile | undefined) { 2749 if (configFile) { 2750 Object.defineProperty(options, "configFile", { enumerable: false, writable: false, value: configFile }); 2751 } 2752 } 2753 2754 function isNullOrUndefined(x: any): x is null | undefined { 2755 return x === undefined || x === null; // eslint-disable-line no-null/no-null 2756 } 2757 2758 function directoryOfCombinedPath(fileName: string, basePath: string) { 2759 // Use the `getNormalizedAbsolutePath` function to avoid canonicalizing the path, as it must remain noncanonical 2760 // until consistent casing errors are reported 2761 return getDirectoryPath(getNormalizedAbsolutePath(fileName, basePath)); 2762 } 2763 2764 /*@internal*/ 2765 export const defaultIncludeSpec = "**/*"; 2766 2767 /** 2768 * Parse the contents of a config file from json or json source file (tsconfig.json). 2769 * @param json The contents of the config file to parse 2770 * @param sourceFile sourceFile corresponding to the Json 2771 * @param host Instance of ParseConfigHost used to enumerate files in folder. 2772 * @param basePath A root directory to resolve relative path entries in the config 2773 * file to. e.g. outDir 2774 * @param resolutionStack Only present for backwards-compatibility. Should be empty. 2775 */ 2776 function parseJsonConfigFileContentWorker( 2777 json: any, 2778 sourceFile: TsConfigSourceFile | undefined, 2779 host: ParseConfigHost, 2780 basePath: string, 2781 existingOptions: CompilerOptions = {}, 2782 existingWatchOptions: WatchOptions | undefined, 2783 configFileName?: string, 2784 resolutionStack: Path[] = [], 2785 extraFileExtensions: readonly FileExtensionInfo[] = [], 2786 extendedConfigCache?: ESMap<string, ExtendedConfigCacheEntry> 2787 ): ParsedCommandLine { 2788 Debug.assert((json === undefined && sourceFile !== undefined) || (json !== undefined && sourceFile === undefined)); 2789 const errors: Diagnostic[] = []; 2790 2791 const parsedConfig = parseConfig(json, sourceFile, host, basePath, configFileName, resolutionStack, errors, extendedConfigCache); 2792 const { raw } = parsedConfig; 2793 const options = extend(existingOptions, parsedConfig.options || {}); 2794 const watchOptions = existingWatchOptions && parsedConfig.watchOptions ? 2795 extend(existingWatchOptions, parsedConfig.watchOptions) : 2796 parsedConfig.watchOptions || existingWatchOptions; 2797 2798 options.configFilePath = configFileName && normalizeSlashes(configFileName); 2799 const configFileSpecs = getConfigFileSpecs(); 2800 if (sourceFile) sourceFile.configFileSpecs = configFileSpecs; 2801 setConfigFileInOptions(options, sourceFile); 2802 2803 const basePathForFileNames = normalizePath(configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath); 2804 return { 2805 options, 2806 watchOptions, 2807 fileNames: getFileNames(basePathForFileNames), 2808 projectReferences: getProjectReferences(basePathForFileNames), 2809 typeAcquisition: parsedConfig.typeAcquisition || getDefaultTypeAcquisition(), 2810 raw, 2811 errors, 2812 // Wildcard directories (provided as part of a wildcard path) are stored in a 2813 // file map that marks whether it was a regular wildcard match (with a `*` or `?` token), 2814 // or a recursive directory. This information is used by filesystem watchers to monitor for 2815 // new entries in these paths. 2816 wildcardDirectories: getWildcardDirectories(configFileSpecs, basePathForFileNames, host.useCaseSensitiveFileNames), 2817 compileOnSave: !!raw.compileOnSave, 2818 }; 2819 2820 function getConfigFileSpecs(): ConfigFileSpecs { 2821 const referencesOfRaw = getPropFromRaw<ProjectReference>("references", element => typeof element === "object", "object"); 2822 const filesSpecs = toPropValue(getSpecsFromRaw("files")); 2823 if (filesSpecs) { 2824 const hasZeroOrNoReferences = referencesOfRaw === "no-prop" || isArray(referencesOfRaw) && referencesOfRaw.length === 0; 2825 const hasExtends = hasProperty(raw, "extends"); 2826 if (filesSpecs.length === 0 && hasZeroOrNoReferences && !hasExtends) { 2827 if (sourceFile) { 2828 const fileName = configFileName || "tsconfig.json"; 2829 const diagnosticMessage = Diagnostics.The_files_list_in_config_file_0_is_empty; 2830 const nodeValue = firstDefined(getTsConfigPropArray(sourceFile, "files"), property => property.initializer); 2831 const error = nodeValue 2832 ? createDiagnosticForNodeInSourceFile(sourceFile, nodeValue, diagnosticMessage, fileName) 2833 : createCompilerDiagnostic(diagnosticMessage, fileName); 2834 errors.push(error); 2835 } 2836 else { 2837 createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json"); 2838 } 2839 } 2840 } 2841 2842 let includeSpecs = toPropValue(getSpecsFromRaw("include")); 2843 2844 const excludeOfRaw = getSpecsFromRaw("exclude"); 2845 let isDefaultIncludeSpec = false; 2846 let excludeSpecs = toPropValue(excludeOfRaw); 2847 if (excludeOfRaw === "no-prop" && raw.compilerOptions) { 2848 const outDir = raw.compilerOptions.outDir; 2849 const declarationDir = raw.compilerOptions.declarationDir; 2850 2851 if (outDir || declarationDir) { 2852 excludeSpecs = [outDir, declarationDir].filter(d => !!d); 2853 } 2854 } 2855 2856 if (filesSpecs === undefined && includeSpecs === undefined) { 2857 includeSpecs = [defaultIncludeSpec]; 2858 isDefaultIncludeSpec = true; 2859 } 2860 let validatedIncludeSpecs: readonly string[] | undefined, validatedExcludeSpecs: readonly string[] | undefined; 2861 2862 // The exclude spec list is converted into a regular expression, which allows us to quickly 2863 // test whether a file or directory should be excluded before recursively traversing the 2864 // file system. 2865 2866 if (includeSpecs) { 2867 validatedIncludeSpecs = validateSpecs(includeSpecs, errors, /*disallowTrailingRecursion*/ true, sourceFile, "include"); 2868 } 2869 2870 if (excludeSpecs) { 2871 validatedExcludeSpecs = validateSpecs(excludeSpecs, errors, /*disallowTrailingRecursion*/ false, sourceFile, "exclude"); 2872 } 2873 2874 return { 2875 filesSpecs, 2876 includeSpecs, 2877 excludeSpecs, 2878 validatedFilesSpec: filter(filesSpecs, isString), 2879 validatedIncludeSpecs, 2880 validatedExcludeSpecs, 2881 pathPatterns: undefined, // Initialized on first use 2882 isDefaultIncludeSpec, 2883 }; 2884 } 2885 2886 function getFileNames(basePath: string): string[] { 2887 const fileNames = getFileNamesFromConfigSpecs(configFileSpecs, basePath, options, host, extraFileExtensions); 2888 if (shouldReportNoInputFiles(fileNames, canJsonReportNoInputFiles(raw), resolutionStack)) { 2889 errors.push(getErrorForNoInputFiles(configFileSpecs, configFileName)); 2890 } 2891 return fileNames; 2892 } 2893 2894 function getProjectReferences(basePath: string): readonly ProjectReference[] | undefined { 2895 let projectReferences: ProjectReference[] | undefined; 2896 const referencesOfRaw = getPropFromRaw<ProjectReference>("references", element => typeof element === "object", "object"); 2897 if (isArray(referencesOfRaw)) { 2898 for (const ref of referencesOfRaw) { 2899 if (typeof ref.path !== "string") { 2900 createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "reference.path", "string"); 2901 } 2902 else { 2903 (projectReferences || (projectReferences = [])).push({ 2904 path: getNormalizedAbsolutePath(ref.path, basePath), 2905 originalPath: ref.path, 2906 prepend: ref.prepend, 2907 circular: ref.circular 2908 }); 2909 } 2910 } 2911 } 2912 return projectReferences; 2913 } 2914 2915 type PropOfRaw<T> = readonly T[] | "not-array" | "no-prop"; 2916 function toPropValue<T>(specResult: PropOfRaw<T>) { 2917 return isArray(specResult) ? specResult : undefined; 2918 } 2919 2920 function getSpecsFromRaw(prop: "files" | "include" | "exclude"): PropOfRaw<string> { 2921 return getPropFromRaw(prop, isString, "string"); 2922 } 2923 2924 function getPropFromRaw<T>(prop: "files" | "include" | "exclude" | "references", validateElement: (value: unknown) => boolean, elementTypeName: string): PropOfRaw<T> { 2925 if (hasProperty(raw, prop) && !isNullOrUndefined(raw[prop])) { 2926 if (isArray(raw[prop])) { 2927 const result = raw[prop] as T[]; 2928 if (!sourceFile && !every(result, validateElement)) { 2929 errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, prop, elementTypeName)); 2930 } 2931 return result; 2932 } 2933 else { 2934 createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, prop, "Array"); 2935 return "not-array"; 2936 } 2937 } 2938 return "no-prop"; 2939 } 2940 2941 function createCompilerDiagnosticOnlyIfJson(message: DiagnosticMessage, arg0?: string, arg1?: string) { 2942 if (!sourceFile) { 2943 errors.push(createCompilerDiagnostic(message, arg0, arg1)); 2944 } 2945 } 2946 } 2947 2948 function isErrorNoInputFiles(error: Diagnostic) { 2949 return error.code === Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code; 2950 } 2951 2952 function getErrorForNoInputFiles({ includeSpecs, excludeSpecs }: ConfigFileSpecs, configFileName: string | undefined) { 2953 return createCompilerDiagnostic( 2954 Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, 2955 configFileName || "tsconfig.json", 2956 JSON.stringify(includeSpecs || []), 2957 JSON.stringify(excludeSpecs || [])); 2958 } 2959 2960 function shouldReportNoInputFiles(fileNames: string[], canJsonReportNoInutFiles: boolean, resolutionStack?: Path[]) { 2961 return fileNames.length === 0 && canJsonReportNoInutFiles && (!resolutionStack || resolutionStack.length === 0); 2962 } 2963 2964 /*@internal*/ 2965 export function canJsonReportNoInputFiles(raw: any) { 2966 return !hasProperty(raw, "files") && !hasProperty(raw, "references"); 2967 } 2968 2969 /*@internal*/ 2970 export function updateErrorForNoInputFiles(fileNames: string[], configFileName: string, configFileSpecs: ConfigFileSpecs, configParseDiagnostics: Diagnostic[], canJsonReportNoInutFiles: boolean) { 2971 const existingErrors = configParseDiagnostics.length; 2972 if (shouldReportNoInputFiles(fileNames, canJsonReportNoInutFiles)) { 2973 configParseDiagnostics.push(getErrorForNoInputFiles(configFileSpecs, configFileName)); 2974 } 2975 else { 2976 filterMutate(configParseDiagnostics, error => !isErrorNoInputFiles(error)); 2977 } 2978 return existingErrors !== configParseDiagnostics.length; 2979 } 2980 2981 export interface ParsedTsconfig { 2982 raw: any; 2983 options?: CompilerOptions; 2984 watchOptions?: WatchOptions; 2985 typeAcquisition?: TypeAcquisition; 2986 /** 2987 * Note that the case of the config path has not yet been normalized, as no files have been imported into the project yet 2988 */ 2989 extendedConfigPath?: string; 2990 } 2991 2992 function isSuccessfulParsedTsconfig(value: ParsedTsconfig) { 2993 return !!value.options; 2994 } 2995 2996 /** 2997 * This *just* extracts options/include/exclude/files out of a config file. 2998 * It does *not* resolve the included files. 2999 */ 3000 function parseConfig( 3001 json: any, 3002 sourceFile: TsConfigSourceFile | undefined, 3003 host: ParseConfigHost, 3004 basePath: string, 3005 configFileName: string | undefined, 3006 resolutionStack: string[], 3007 errors: Push<Diagnostic>, 3008 extendedConfigCache?: ESMap<string, ExtendedConfigCacheEntry> 3009 ): ParsedTsconfig { 3010 basePath = normalizeSlashes(basePath); 3011 const resolvedPath = getNormalizedAbsolutePath(configFileName || "", basePath); 3012 3013 if (resolutionStack.indexOf(resolvedPath) >= 0) { 3014 errors.push(createCompilerDiagnostic(Diagnostics.Circularity_detected_while_resolving_configuration_Colon_0, [...resolutionStack, resolvedPath].join(" -> "))); 3015 return { raw: json || convertToObject(sourceFile!, errors) }; 3016 } 3017 3018 const ownConfig = json ? 3019 parseOwnConfigOfJson(json, host, basePath, configFileName, errors) : 3020 parseOwnConfigOfJsonSourceFile(sourceFile!, host, basePath, configFileName, errors); 3021 3022 if (ownConfig.options?.paths) { 3023 // If we end up needing to resolve relative paths from 'paths' relative to 3024 // the config file location, we'll need to know where that config file was. 3025 // Since 'paths' can be inherited from an extended config in another directory, 3026 // we wouldn't know which directory to use unless we store it here. 3027 ownConfig.options.pathsBasePath = basePath; 3028 } 3029 if (ownConfig.extendedConfigPath) { 3030 // copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios. 3031 resolutionStack = resolutionStack.concat([resolvedPath]); 3032 const extendedConfig = getExtendedConfig(sourceFile, ownConfig.extendedConfigPath, host, resolutionStack, errors, extendedConfigCache); 3033 if (extendedConfig && isSuccessfulParsedTsconfig(extendedConfig)) { 3034 const baseRaw = extendedConfig.raw; 3035 const raw = ownConfig.raw; 3036 let relativeDifference: string | undefined ; 3037 const setPropertyInRawIfNotUndefined = (propertyName: string) => { 3038 if (!raw[propertyName] && baseRaw[propertyName]) { 3039 raw[propertyName] = map(baseRaw[propertyName], (path: string) => isRootedDiskPath(path) ? path : combinePaths( 3040 relativeDifference ||= convertToRelativePath(getDirectoryPath(ownConfig.extendedConfigPath!), basePath, createGetCanonicalFileName(host.useCaseSensitiveFileNames)), 3041 path 3042 )); 3043 } 3044 }; 3045 setPropertyInRawIfNotUndefined("include"); 3046 setPropertyInRawIfNotUndefined("exclude"); 3047 setPropertyInRawIfNotUndefined("files"); 3048 if (raw.compileOnSave === undefined) { 3049 raw.compileOnSave = baseRaw.compileOnSave; 3050 } 3051 ownConfig.options = assign({}, extendedConfig.options, ownConfig.options); 3052 ownConfig.watchOptions = ownConfig.watchOptions && extendedConfig.watchOptions ? 3053 assign({}, extendedConfig.watchOptions, ownConfig.watchOptions) : 3054 ownConfig.watchOptions || extendedConfig.watchOptions; 3055 // TODO extend type typeAcquisition 3056 } 3057 } 3058 3059 return ownConfig; 3060 } 3061 3062 function parseOwnConfigOfJson( 3063 json: any, 3064 host: ParseConfigHost, 3065 basePath: string, 3066 configFileName: string | undefined, 3067 errors: Push<Diagnostic> 3068 ): ParsedTsconfig { 3069 if (hasProperty(json, "excludes")) { 3070 errors.push(createCompilerDiagnostic(Diagnostics.Unknown_option_excludes_Did_you_mean_exclude)); 3071 } 3072 3073 const options = convertCompilerOptionsFromJsonWorker(json.compilerOptions, basePath, errors, configFileName); 3074 // typingOptions has been deprecated and is only supported for backward compatibility purposes. 3075 // It should be removed in future releases - use typeAcquisition instead. 3076 const typeAcquisition = convertTypeAcquisitionFromJsonWorker(json.typeAcquisition || json.typingOptions, basePath, errors, configFileName); 3077 const watchOptions = convertWatchOptionsFromJsonWorker(json.watchOptions, basePath, errors); 3078 json.compileOnSave = convertCompileOnSaveOptionFromJson(json, basePath, errors); 3079 let extendedConfigPath: string | undefined; 3080 3081 if (json.extends) { 3082 if (!isString(json.extends)) { 3083 errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "extends", "string")); 3084 } 3085 else { 3086 const newBase = configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath; 3087 extendedConfigPath = getExtendsConfigPath(json.extends, host, newBase, errors, createCompilerDiagnostic); 3088 } 3089 } 3090 return { raw: json, options, watchOptions, typeAcquisition, extendedConfigPath }; 3091 } 3092 3093 function parseOwnConfigOfJsonSourceFile( 3094 sourceFile: TsConfigSourceFile, 3095 host: ParseConfigHost, 3096 basePath: string, 3097 configFileName: string | undefined, 3098 errors: Push<Diagnostic> 3099 ): ParsedTsconfig { 3100 const options = getDefaultCompilerOptions(configFileName); 3101 let typeAcquisition: TypeAcquisition | undefined, typingOptionstypeAcquisition: TypeAcquisition | undefined; 3102 let watchOptions: WatchOptions | undefined; 3103 let extendedConfigPath: string | undefined; 3104 let rootCompilerOptions: PropertyName[] | undefined; 3105 3106 const optionsIterator: JsonConversionNotifier = { 3107 onSetValidOptionKeyValueInParent(parentOption: string, option: CommandLineOption, value: CompilerOptionsValue) { 3108 let currentOption; 3109 switch (parentOption) { 3110 case "compilerOptions": 3111 currentOption = options; 3112 break; 3113 case "watchOptions": 3114 currentOption = (watchOptions || (watchOptions = {})); 3115 break; 3116 case "typeAcquisition": 3117 currentOption = (typeAcquisition || (typeAcquisition = getDefaultTypeAcquisition(configFileName))); 3118 break; 3119 case "typingOptions": 3120 currentOption = (typingOptionstypeAcquisition || (typingOptionstypeAcquisition = getDefaultTypeAcquisition(configFileName))); 3121 break; 3122 default: 3123 Debug.fail("Unknown option"); 3124 } 3125 3126 currentOption[option.name] = normalizeOptionValue(option, basePath, value); 3127 }, 3128 onSetValidOptionKeyValueInRoot(key: string, _keyNode: PropertyName, value: CompilerOptionsValue, valueNode: Expression) { 3129 switch (key) { 3130 case "extends": 3131 const newBase = configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath; 3132 extendedConfigPath = getExtendsConfigPath( 3133 value as string, 3134 host, 3135 newBase, 3136 errors, 3137 (message, arg0) => 3138 createDiagnosticForNodeInSourceFile(sourceFile, valueNode, message, arg0) 3139 ); 3140 return; 3141 } 3142 }, 3143 onSetUnknownOptionKeyValueInRoot(key: string, keyNode: PropertyName, _value: CompilerOptionsValue, _valueNode: Expression) { 3144 if (key === "excludes") { 3145 errors.push(createDiagnosticForNodeInSourceFile(sourceFile, keyNode, Diagnostics.Unknown_option_excludes_Did_you_mean_exclude)); 3146 } 3147 if (find(commandOptionsWithoutBuild, (opt) => opt.name === key)) { 3148 rootCompilerOptions = append(rootCompilerOptions, keyNode); 3149 } 3150 } 3151 }; 3152 const json = convertConfigFileToObject(sourceFile, errors, /*reportOptionsErrors*/ true, optionsIterator); 3153 3154 if (!typeAcquisition) { 3155 if (typingOptionstypeAcquisition) { 3156 typeAcquisition = (typingOptionstypeAcquisition.enableAutoDiscovery !== undefined) ? 3157 { 3158 enable: typingOptionstypeAcquisition.enableAutoDiscovery, 3159 include: typingOptionstypeAcquisition.include, 3160 exclude: typingOptionstypeAcquisition.exclude 3161 } : 3162 typingOptionstypeAcquisition; 3163 } 3164 else { 3165 typeAcquisition = getDefaultTypeAcquisition(configFileName); 3166 } 3167 } 3168 3169 if (rootCompilerOptions && json && json.compilerOptions === undefined) { 3170 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)); 3171 } 3172 3173 return { raw: json, options, watchOptions, typeAcquisition, extendedConfigPath }; 3174 } 3175 3176 function getExtendsConfigPath( 3177 extendedConfig: string, 3178 host: ParseConfigHost, 3179 basePath: string, 3180 errors: Push<Diagnostic>, 3181 createDiagnostic: (message: DiagnosticMessage, arg1?: string) => Diagnostic) { 3182 extendedConfig = normalizeSlashes(extendedConfig); 3183 if (isRootedDiskPath(extendedConfig) || startsWith(extendedConfig, "./") || startsWith(extendedConfig, "../")) { 3184 let extendedConfigPath = getNormalizedAbsolutePath(extendedConfig, basePath); 3185 if (!host.fileExists(extendedConfigPath) && !endsWith(extendedConfigPath, Extension.Json)) { 3186 extendedConfigPath = `${extendedConfigPath}.json`; 3187 if (!host.fileExists(extendedConfigPath)) { 3188 errors.push(createDiagnostic(Diagnostics.File_0_not_found, extendedConfig)); 3189 return undefined; 3190 } 3191 } 3192 return extendedConfigPath; 3193 } 3194 // If the path isn't a rooted or relative path, resolve like a module 3195 const resolved = nodeModuleNameResolver(extendedConfig, combinePaths(basePath, "tsconfig.json"), { moduleResolution: ModuleResolutionKind.NodeJs }, host, /*cache*/ undefined, /*projectRefs*/ undefined, /*lookupConfig*/ true); 3196 if (resolved.resolvedModule) { 3197 return resolved.resolvedModule.resolvedFileName; 3198 } 3199 errors.push(createDiagnostic(Diagnostics.File_0_not_found, extendedConfig)); 3200 return undefined; 3201 } 3202 3203 export interface ExtendedConfigCacheEntry { 3204 extendedResult: TsConfigSourceFile; 3205 extendedConfig: ParsedTsconfig | undefined; 3206 } 3207 3208 function getExtendedConfig( 3209 sourceFile: TsConfigSourceFile | undefined, 3210 extendedConfigPath: string, 3211 host: ParseConfigHost, 3212 resolutionStack: string[], 3213 errors: Push<Diagnostic>, 3214 extendedConfigCache?: ESMap<string, ExtendedConfigCacheEntry> 3215 ): ParsedTsconfig | undefined { 3216 const path = host.useCaseSensitiveFileNames ? extendedConfigPath : toFileNameLowerCase(extendedConfigPath); 3217 let value: ExtendedConfigCacheEntry | undefined; 3218 let extendedResult: TsConfigSourceFile; 3219 let extendedConfig: ParsedTsconfig | undefined; 3220 if (extendedConfigCache && (value = extendedConfigCache.get(path))) { 3221 ({ extendedResult, extendedConfig } = value); 3222 } 3223 else { 3224 extendedResult = readJsonConfigFile(extendedConfigPath, path => host.readFile(path)); 3225 if (!extendedResult.parseDiagnostics.length) { 3226 extendedConfig = parseConfig(/*json*/ undefined, extendedResult, host, getDirectoryPath(extendedConfigPath), 3227 getBaseFileName(extendedConfigPath), resolutionStack, errors, extendedConfigCache); 3228 } 3229 if (extendedConfigCache) { 3230 extendedConfigCache.set(path, { extendedResult, extendedConfig }); 3231 } 3232 } 3233 if (sourceFile) { 3234 sourceFile.extendedSourceFiles = [extendedResult.fileName]; 3235 if (extendedResult.extendedSourceFiles) { 3236 sourceFile.extendedSourceFiles.push(...extendedResult.extendedSourceFiles); 3237 } 3238 } 3239 if (extendedResult.parseDiagnostics.length) { 3240 errors.push(...extendedResult.parseDiagnostics); 3241 return undefined; 3242 } 3243 return extendedConfig!; 3244 } 3245 3246 function convertCompileOnSaveOptionFromJson(jsonOption: any, basePath: string, errors: Push<Diagnostic>): boolean { 3247 if (!hasProperty(jsonOption, compileOnSaveCommandLineOption.name)) { 3248 return false; 3249 } 3250 const result = convertJsonOption(compileOnSaveCommandLineOption, jsonOption.compileOnSave, basePath, errors); 3251 return typeof result === "boolean" && result; 3252 } 3253 3254 export function convertCompilerOptionsFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: CompilerOptions, errors: Diagnostic[] } { 3255 const errors: Diagnostic[] = []; 3256 const options = convertCompilerOptionsFromJsonWorker(jsonOptions, basePath, errors, configFileName); 3257 return { options, errors }; 3258 } 3259 3260 export function convertTypeAcquisitionFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: TypeAcquisition, errors: Diagnostic[] } { 3261 const errors: Diagnostic[] = []; 3262 const options = convertTypeAcquisitionFromJsonWorker(jsonOptions, basePath, errors, configFileName); 3263 return { options, errors }; 3264 } 3265 3266 function getDefaultCompilerOptions(configFileName?: string) { 3267 const options: CompilerOptions = configFileName && getBaseFileName(configFileName) === "jsconfig.json" 3268 ? { allowJs: true, maxNodeModuleJsDepth: 2, allowSyntheticDefaultImports: true, skipLibCheck: true, noEmit: true } 3269 : {}; 3270 return options; 3271 } 3272 3273 function convertCompilerOptionsFromJsonWorker(jsonOptions: any, 3274 basePath: string, errors: Push<Diagnostic>, configFileName?: string): CompilerOptions { 3275 3276 const options = getDefaultCompilerOptions(configFileName); 3277 convertOptionsFromJson(getCommandLineCompilerOptionsMap(), jsonOptions, basePath, options, compilerOptionsDidYouMeanDiagnostics, errors); 3278 if (configFileName) { 3279 options.configFilePath = normalizeSlashes(configFileName); 3280 } 3281 return options; 3282 } 3283 3284 function getDefaultTypeAcquisition(configFileName?: string): TypeAcquisition { 3285 return { enable: !!configFileName && getBaseFileName(configFileName) === "jsconfig.json", include: [], exclude: [] }; 3286 } 3287 3288 function convertTypeAcquisitionFromJsonWorker(jsonOptions: any, 3289 basePath: string, errors: Push<Diagnostic>, configFileName?: string): TypeAcquisition { 3290 3291 const options = getDefaultTypeAcquisition(configFileName); 3292 const typeAcquisition = convertEnableAutoDiscoveryToEnable(jsonOptions); 3293 3294 convertOptionsFromJson(getCommandLineTypeAcquisitionMap(), typeAcquisition, basePath, options, typeAcquisitionDidYouMeanDiagnostics, errors); 3295 return options; 3296 } 3297 3298 function convertWatchOptionsFromJsonWorker(jsonOptions: any, basePath: string, errors: Push<Diagnostic>): WatchOptions | undefined { 3299 return convertOptionsFromJson(getCommandLineWatchOptionsMap(), jsonOptions, basePath, /*defaultOptions*/ undefined, watchOptionsDidYouMeanDiagnostics, errors); 3300 } 3301 3302 function convertOptionsFromJson(optionsNameMap: ESMap<string, CommandLineOption>, jsonOptions: any, basePath: string, 3303 defaultOptions: undefined, diagnostics: DidYouMeanOptionsDiagnostics, errors: Push<Diagnostic>): WatchOptions | undefined; 3304 function convertOptionsFromJson(optionsNameMap: ESMap<string, CommandLineOption>, jsonOptions: any, basePath: string, 3305 defaultOptions: CompilerOptions | TypeAcquisition, diagnostics: DidYouMeanOptionsDiagnostics, errors: Push<Diagnostic>): CompilerOptions | TypeAcquisition; 3306 function convertOptionsFromJson(optionsNameMap: ESMap<string, CommandLineOption>, jsonOptions: any, basePath: string, 3307 defaultOptions: CompilerOptions | TypeAcquisition | WatchOptions | undefined, diagnostics: DidYouMeanOptionsDiagnostics, errors: Push<Diagnostic>) { 3308 3309 if (!jsonOptions) { 3310 return; 3311 } 3312 3313 for (const id in jsonOptions) { 3314 const opt = optionsNameMap.get(id); 3315 if (opt) { 3316 (defaultOptions || (defaultOptions = {}))[opt.name] = convertJsonOption(opt, jsonOptions[id], basePath, errors); 3317 } 3318 else { 3319 errors.push(createUnknownOptionError(id, diagnostics, createCompilerDiagnostic)); 3320 } 3321 } 3322 return defaultOptions; 3323 } 3324 3325 /*@internal*/ 3326 export function convertJsonOption(opt: CommandLineOption, value: any, basePath: string, errors: Push<Diagnostic>): CompilerOptionsValue { 3327 if (isCompilerOptionsValue(opt, value)) { 3328 const optType = opt.type; 3329 if (optType === "list" && isArray(value)) { 3330 return convertJsonOptionOfListType(opt , value, basePath, errors); 3331 } 3332 else if (!isString(optType)) { 3333 return convertJsonOptionOfCustomType(opt as CommandLineOptionOfCustomType, value as string, errors); 3334 } 3335 const validatedValue = validateJsonOptionValue(opt, value, errors); 3336 return isNullOrUndefined(validatedValue) ? validatedValue : normalizeNonListOptionValue(opt, basePath, validatedValue); 3337 } 3338 else { 3339 errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, opt.name, getCompilerOptionValueTypeString(opt))); 3340 } 3341 } 3342 3343 function normalizeOptionValue(option: CommandLineOption, basePath: string, value: any): CompilerOptionsValue { 3344 if (isNullOrUndefined(value)) return undefined; 3345 if (option.type === "list") { 3346 const listOption = option; 3347 if (listOption.element.isFilePath || !isString(listOption.element.type)) { 3348 return filter(map(value, v => normalizeOptionValue(listOption.element, basePath, v)), v => listOption.listPreserveFalsyValues ? true : !!v) as CompilerOptionsValue; 3349 } 3350 return value; 3351 } 3352 else if (!isString(option.type)) { 3353 return option.type.get(isString(value) ? value.toLowerCase() : value); 3354 } 3355 return normalizeNonListOptionValue(option, basePath, value); 3356 } 3357 3358 function normalizeNonListOptionValue(option: CommandLineOption, basePath: string, value: any): CompilerOptionsValue { 3359 if (option.isFilePath) { 3360 value = getNormalizedAbsolutePath(value, basePath); 3361 if (value === "") { 3362 value = "."; 3363 } 3364 } 3365 return value; 3366 } 3367 3368 function validateJsonOptionValue<T extends CompilerOptionsValue>(opt: CommandLineOption, value: T, errors: Push<Diagnostic>): T | undefined { 3369 if (isNullOrUndefined(value)) return undefined; 3370 const d = opt.extraValidation?.(value); 3371 if (!d) return value; 3372 errors.push(createCompilerDiagnostic(...d)); 3373 return undefined; 3374 } 3375 3376 function convertJsonOptionOfCustomType(opt: CommandLineOptionOfCustomType, value: string, errors: Push<Diagnostic>) { 3377 if (isNullOrUndefined(value)) return undefined; 3378 const key = value.toLowerCase(); 3379 const val = opt.type.get(key); 3380 if (val !== undefined) { 3381 return validateJsonOptionValue(opt, val, errors); 3382 } 3383 else { 3384 errors.push(createCompilerDiagnosticForInvalidCustomType(opt)); 3385 } 3386 } 3387 3388 function convertJsonOptionOfListType(option: CommandLineOptionOfListType, values: readonly any[], basePath: string, errors: Push<Diagnostic>): any[] { 3389 return filter(map(values, v => convertJsonOption(option.element, v, basePath, errors)), v => option.listPreserveFalsyValues ? true : !!v); 3390 } 3391 3392 /** 3393 * Tests for a path that ends in a recursive directory wildcard. 3394 * Matches **, \**, **\, and \**\, but not a**b. 3395 * 3396 * NOTE: used \ in place of / above to avoid issues with multiline comments. 3397 * 3398 * Breakdown: 3399 * (^|\/) # matches either the beginning of the string or a directory separator. 3400 * \*\* # matches the recursive directory wildcard "**". 3401 * \/?$ # matches an optional trailing directory separator at the end of the string. 3402 */ 3403 const invalidTrailingRecursionPattern = /(^|\/)\*\*\/?$/; 3404 3405 /** 3406 * Matches the portion of a wildcard path that does not contain wildcards. 3407 * Matches \a of \a\*, or \a\b\c of \a\b\c\?\d. 3408 * 3409 * NOTE: used \ in place of / above to avoid issues with multiline comments. 3410 * 3411 * Breakdown: 3412 * ^ # matches the beginning of the string 3413 * [^*?]* # matches any number of non-wildcard characters 3414 * (?=\/[^/]*[*?]) # lookahead that matches a directory separator followed by 3415 * # a path component that contains at least one wildcard character (* or ?). 3416 */ 3417 const wildcardDirectoryPattern = /^[^*?]*(?=\/[^/]*[*?])/; 3418 3419 /** 3420 * Gets the file names from the provided config file specs that contain, files, include, exclude and 3421 * other properties needed to resolve the file names 3422 * @param configFileSpecs The config file specs extracted with file names to include, wildcards to include/exclude and other details 3423 * @param basePath The base path for any relative file specifications. 3424 * @param options Compiler options. 3425 * @param host The host used to resolve files and directories. 3426 * @param extraFileExtensions optionaly file extra file extension information from host 3427 */ 3428 /* @internal */ 3429 export function getFileNamesFromConfigSpecs( 3430 configFileSpecs: ConfigFileSpecs, 3431 basePath: string, 3432 options: CompilerOptions, 3433 host: ParseConfigHost, 3434 extraFileExtensions: readonly FileExtensionInfo[] = emptyArray 3435 ): string[] { 3436 basePath = normalizePath(basePath); 3437 3438 const keyMapper = createGetCanonicalFileName(host.useCaseSensitiveFileNames); 3439 3440 // Literal file names (provided via the "files" array in tsconfig.json) are stored in a 3441 // file map with a possibly case insensitive key. We use this map later when when including 3442 // wildcard paths. 3443 const literalFileMap = new Map<string, string>(); 3444 3445 // Wildcard paths (provided via the "includes" array in tsconfig.json) are stored in a 3446 // file map with a possibly case insensitive key. We use this map to store paths matched 3447 // via wildcard, and to handle extension priority. 3448 const wildcardFileMap = new Map<string, string>(); 3449 3450 // Wildcard paths of json files (provided via the "includes" array in tsconfig.json) are stored in a 3451 // file map with a possibly case insensitive key. We use this map to store paths matched 3452 // via wildcard of *.json kind 3453 const wildCardJsonFileMap = new Map<string, string>(); 3454 const { validatedFilesSpec, validatedIncludeSpecs, validatedExcludeSpecs } = configFileSpecs; 3455 3456 // Rather than re-query this for each file and filespec, we query the supported extensions 3457 // once and store it on the expansion context. 3458 const supportedExtensions = getSupportedExtensions(options, extraFileExtensions); 3459 const supportedExtensionsWithJsonIfResolveJsonModule = getSupportedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions); 3460 3461 // Literal files are always included verbatim. An "include" or "exclude" specification cannot 3462 // remove a literal file. 3463 if (validatedFilesSpec) { 3464 for (const fileName of validatedFilesSpec) { 3465 const file = getNormalizedAbsolutePath(fileName, basePath); 3466 literalFileMap.set(keyMapper(file), file); 3467 } 3468 } 3469 3470 let jsonOnlyIncludeRegexes: readonly RegExp[] | undefined; 3471 if (validatedIncludeSpecs && validatedIncludeSpecs.length > 0) { 3472 for (const file of host.readDirectory(basePath, flatten(supportedExtensionsWithJsonIfResolveJsonModule), validatedExcludeSpecs, validatedIncludeSpecs, /*depth*/ undefined)) { 3473 if (fileExtensionIs(file, Extension.Json)) { 3474 // Valid only if *.json specified 3475 if (!jsonOnlyIncludeRegexes) { 3476 const includes = validatedIncludeSpecs.filter(s => endsWith(s, Extension.Json)); 3477 const includeFilePatterns = map(getRegularExpressionsForWildcards(includes, basePath, "files"), pattern => `^${pattern}$`); 3478 jsonOnlyIncludeRegexes = includeFilePatterns ? includeFilePatterns.map(pattern => getRegexFromPattern(pattern, host.useCaseSensitiveFileNames)) : emptyArray; 3479 } 3480 const includeIndex = findIndex(jsonOnlyIncludeRegexes, re => re.test(file)); 3481 if (includeIndex !== -1) { 3482 const key = keyMapper(file); 3483 if (!literalFileMap.has(key) && !wildCardJsonFileMap.has(key)) { 3484 wildCardJsonFileMap.set(key, file); 3485 } 3486 } 3487 continue; 3488 } 3489 // If we have already included a literal or wildcard path with a 3490 // higher priority extension, we should skip this file. 3491 // 3492 // This handles cases where we may encounter both <file>.ts and 3493 // <file>.d.ts (or <file>.js if "allowJs" is enabled) in the same 3494 // directory when they are compilation outputs. 3495 if (hasFileWithHigherPriorityExtension(file, literalFileMap, wildcardFileMap, supportedExtensions, keyMapper)) { 3496 continue; 3497 } 3498 3499 // We may have included a wildcard path with a lower priority 3500 // extension due to the user-defined order of entries in the 3501 // "include" array. If there is a lower priority extension in the 3502 // same directory, we should remove it. 3503 removeWildcardFilesWithLowerPriorityExtension(file, wildcardFileMap, supportedExtensions, keyMapper); 3504 3505 const key = keyMapper(file); 3506 if (!literalFileMap.has(key) && !wildcardFileMap.has(key)) { 3507 wildcardFileMap.set(key, file); 3508 } 3509 } 3510 } 3511 3512 const literalFiles = arrayFrom(literalFileMap.values()); 3513 const wildcardFiles = arrayFrom(wildcardFileMap.values()); 3514 3515 return literalFiles.concat(wildcardFiles, arrayFrom(wildCardJsonFileMap.values())); 3516 } 3517 3518 /* @internal */ 3519 export function isExcludedFile( 3520 pathToCheck: string, 3521 spec: ConfigFileSpecs, 3522 basePath: string, 3523 useCaseSensitiveFileNames: boolean, 3524 currentDirectory: string 3525 ): boolean { 3526 const { validatedFilesSpec, validatedIncludeSpecs, validatedExcludeSpecs } = spec; 3527 if (!length(validatedIncludeSpecs) || !length(validatedExcludeSpecs)) return false; 3528 3529 basePath = normalizePath(basePath); 3530 3531 const keyMapper = createGetCanonicalFileName(useCaseSensitiveFileNames); 3532 if (validatedFilesSpec) { 3533 for (const fileName of validatedFilesSpec) { 3534 if (keyMapper(getNormalizedAbsolutePath(fileName, basePath)) === pathToCheck) return false; 3535 } 3536 } 3537 3538 return matchesExcludeWorker(pathToCheck, validatedExcludeSpecs, useCaseSensitiveFileNames, currentDirectory, basePath); 3539 } 3540 3541 function invalidDotDotAfterRecursiveWildcard(s: string) { 3542 // We used to use the regex /(^|\/)\*\*\/(.*\/)?\.\.($|\/)/ to check for this case, but 3543 // in v8, that has polynomial performance because the recursive wildcard match - **/ - 3544 // can be matched in many arbitrary positions when multiple are present, resulting 3545 // in bad backtracking (and we don't care which is matched - just that some /.. segment 3546 // comes after some **/ segment). 3547 const wildcardIndex = startsWith(s, "**/") ? 0 : s.indexOf("/**/"); 3548 if (wildcardIndex === -1) { 3549 return false; 3550 } 3551 const lastDotIndex = endsWith(s, "/..") ? s.length : s.lastIndexOf("/../"); 3552 return lastDotIndex > wildcardIndex; 3553 } 3554 3555 /* @internal */ 3556 export function matchesExclude( 3557 pathToCheck: string, 3558 excludeSpecs: readonly string[] | undefined, 3559 useCaseSensitiveFileNames: boolean, 3560 currentDirectory: string 3561 ) { 3562 return matchesExcludeWorker( 3563 pathToCheck, 3564 filter(excludeSpecs, spec => !invalidDotDotAfterRecursiveWildcard(spec)), 3565 useCaseSensitiveFileNames, 3566 currentDirectory 3567 ); 3568 } 3569 3570 function matchesExcludeWorker( 3571 pathToCheck: string, 3572 excludeSpecs: readonly string[] | undefined, 3573 useCaseSensitiveFileNames: boolean, 3574 currentDirectory: string, 3575 basePath?: string 3576 ) { 3577 const excludePattern = getRegularExpressionForWildcard(excludeSpecs, combinePaths(normalizePath(currentDirectory), basePath), "exclude"); 3578 const excludeRegex = excludePattern && getRegexFromPattern(excludePattern, useCaseSensitiveFileNames); 3579 if (!excludeRegex) return false; 3580 if (excludeRegex.test(pathToCheck)) return true; 3581 return !hasExtension(pathToCheck) && excludeRegex.test(ensureTrailingDirectorySeparator(pathToCheck)); 3582 } 3583 3584 function validateSpecs(specs: readonly string[], errors: Push<Diagnostic>, disallowTrailingRecursion: boolean, jsonSourceFile: TsConfigSourceFile | undefined, specKey: string): readonly string[] { 3585 return specs.filter(spec => { 3586 if (!isString(spec)) return false; 3587 const diag = specToDiagnostic(spec, disallowTrailingRecursion); 3588 if (diag !== undefined) { 3589 errors.push(createDiagnostic(...diag)); 3590 } 3591 return diag === undefined; 3592 }); 3593 3594 function createDiagnostic(message: DiagnosticMessage, spec: string): Diagnostic { 3595 const element = getTsConfigPropArrayElementValue(jsonSourceFile, specKey, spec); 3596 return element ? 3597 createDiagnosticForNodeInSourceFile(jsonSourceFile!, element, message, spec) : 3598 createCompilerDiagnostic(message, spec); 3599 } 3600 } 3601 3602 function specToDiagnostic(spec: string, disallowTrailingRecursion?: boolean): [DiagnosticMessage, string] | undefined { 3603 if (disallowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) { 3604 return [Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec]; 3605 } 3606 else if (invalidDotDotAfterRecursiveWildcard(spec)) { 3607 return [Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec]; 3608 } 3609 } 3610 3611 /** 3612 * Gets directories in a set of include patterns that should be watched for changes. 3613 */ 3614 function getWildcardDirectories({ validatedIncludeSpecs: include, validatedExcludeSpecs: exclude }: ConfigFileSpecs, path: string, useCaseSensitiveFileNames: boolean): MapLike<WatchDirectoryFlags> { 3615 // We watch a directory recursively if it contains a wildcard anywhere in a directory segment 3616 // of the pattern: 3617 // 3618 // /a/b/**/d - Watch /a/b recursively to catch changes to any d in any subfolder recursively 3619 // /a/b/*/d - Watch /a/b recursively to catch any d in any immediate subfolder, even if a new subfolder is added 3620 // /a/b - Watch /a/b recursively to catch changes to anything in any recursive subfoler 3621 // 3622 // We watch a directory without recursion if it contains a wildcard in the file segment of 3623 // the pattern: 3624 // 3625 // /a/b/* - Watch /a/b directly to catch any new file 3626 // /a/b/a?z - Watch /a/b directly to catch any new file matching a?z 3627 const rawExcludeRegex = getRegularExpressionForWildcard(exclude, path, "exclude"); 3628 const excludeRegex = rawExcludeRegex && new RegExp(rawExcludeRegex, useCaseSensitiveFileNames ? "" : "i"); 3629 const wildcardDirectories: MapLike<WatchDirectoryFlags> = {}; 3630 if (include !== undefined) { 3631 const recursiveKeys: string[] = []; 3632 for (const file of include) { 3633 const spec = normalizePath(combinePaths(path, file)); 3634 if (excludeRegex && excludeRegex.test(spec)) { 3635 continue; 3636 } 3637 3638 const match = getWildcardDirectoryFromSpec(spec, useCaseSensitiveFileNames); 3639 if (match) { 3640 const { key, flags } = match; 3641 const existingFlags = wildcardDirectories[key]; 3642 if (existingFlags === undefined || existingFlags < flags) { 3643 wildcardDirectories[key] = flags; 3644 if (flags === WatchDirectoryFlags.Recursive) { 3645 recursiveKeys.push(key); 3646 } 3647 } 3648 } 3649 } 3650 3651 // Remove any subpaths under an existing recursively watched directory. 3652 for (const key in wildcardDirectories) { 3653 if (hasProperty(wildcardDirectories, key)) { 3654 for (const recursiveKey of recursiveKeys) { 3655 if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) { 3656 delete wildcardDirectories[key]; 3657 } 3658 } 3659 } 3660 } 3661 } 3662 3663 return wildcardDirectories; 3664 } 3665 3666 function getWildcardDirectoryFromSpec(spec: string, useCaseSensitiveFileNames: boolean): { key: string, flags: WatchDirectoryFlags } | undefined { 3667 const match = wildcardDirectoryPattern.exec(spec); 3668 if (match) { 3669 // We check this with a few `indexOf` calls because 3 `indexOf`/`lastIndexOf` calls is 3670 // less algorithmically complex (roughly O(3n) worst-case) than the regex we used to use, 3671 // \/[^/]*?[*?][^/]*\/ which was polynominal in v8, since arbitrary sequences of wildcard 3672 // characters could match any of the central patterns, resulting in bad backtracking. 3673 const questionWildcardIndex = spec.indexOf("?"); 3674 const starWildcardIndex = spec.indexOf("*"); 3675 const lastDirectorySeperatorIndex = spec.lastIndexOf(directorySeparator); 3676 return { 3677 key: useCaseSensitiveFileNames ? match[0] : toFileNameLowerCase(match[0]), 3678 flags: (questionWildcardIndex !== -1 && questionWildcardIndex < lastDirectorySeperatorIndex) 3679 || (starWildcardIndex !== -1 && starWildcardIndex < lastDirectorySeperatorIndex) 3680 ? WatchDirectoryFlags.Recursive : WatchDirectoryFlags.None 3681 }; 3682 } 3683 if (isImplicitGlob(spec.substring(spec.lastIndexOf(directorySeparator) + 1))) { 3684 return { 3685 key: removeTrailingDirectorySeparator(useCaseSensitiveFileNames ? spec : toFileNameLowerCase(spec)), 3686 flags: WatchDirectoryFlags.Recursive 3687 }; 3688 } 3689 return undefined; 3690 } 3691 3692 /** 3693 * Determines whether a literal or wildcard file has already been included that has a higher 3694 * extension priority. 3695 * 3696 * @param file The path to the file. 3697 */ 3698 function hasFileWithHigherPriorityExtension(file: string, literalFiles: ESMap<string, string>, wildcardFiles: ESMap<string, string>, extensions: readonly string[][], keyMapper: (value: string) => string) { 3699 const extensionGroup = forEach(extensions, group => fileExtensionIsOneOf(file, group) ? group : undefined); 3700 if (!extensionGroup) { 3701 return false; 3702 } 3703 for (const ext of extensionGroup) { 3704 if (fileExtensionIs(file, ext)) { 3705 return false; 3706 } 3707 const higherPriorityPath = keyMapper(changeExtension(file, ext)); 3708 if (literalFiles.has(higherPriorityPath) || wildcardFiles.has(higherPriorityPath)) { 3709 if (ext === Extension.Dts && (fileExtensionIs(file, Extension.Js) || fileExtensionIs(file, Extension.Jsx))) { 3710 // LEGACY BEHAVIOR: An off-by-one bug somewhere in the extension priority system for wildcard module loading allowed declaration 3711 // files to be loaded alongside their js(x) counterparts. We regard this as generally undesirable, but retain the behavior to 3712 // prevent breakage. 3713 continue; 3714 } 3715 return true; 3716 } 3717 } 3718 3719 return false; 3720 } 3721 3722 /** 3723 * Removes files included via wildcard expansion with a lower extension priority that have 3724 * already been included. 3725 * 3726 * @param file The path to the file. 3727 */ 3728 function removeWildcardFilesWithLowerPriorityExtension(file: string, wildcardFiles: ESMap<string, string>, extensions: readonly string[][], keyMapper: (value: string) => string) { 3729 const extensionGroup = forEach(extensions, group => fileExtensionIsOneOf(file, group) ? group : undefined); 3730 if (!extensionGroup) { 3731 return; 3732 } 3733 for (let i = extensionGroup.length - 1; i >= 0; i--) { 3734 const ext = extensionGroup[i]; 3735 if (fileExtensionIs(file, ext)) { 3736 return; 3737 } 3738 const lowerPriorityPath = keyMapper(changeExtension(file, ext)); 3739 wildcardFiles.delete(lowerPriorityPath); 3740 } 3741 } 3742 3743 /** 3744 * Produces a cleaned version of compiler options with personally identifying info (aka, paths) removed. 3745 * Also converts enum values back to strings. 3746 */ 3747 /* @internal */ 3748 export function convertCompilerOptionsForTelemetry(opts: CompilerOptions): CompilerOptions { 3749 const out: CompilerOptions = {}; 3750 for (const key in opts) { 3751 if (hasProperty(opts, key)) { 3752 const type = getOptionFromName(key); 3753 if (type !== undefined) { // Ignore unknown options 3754 out[key] = getOptionValueWithEmptyStrings(opts[key], type); 3755 } 3756 } 3757 } 3758 return out; 3759 } 3760 3761 function getOptionValueWithEmptyStrings(value: any, option: CommandLineOption): {} { 3762 switch (option.type) { 3763 case "object": // "paths". Can't get any useful information from the value since we blank out strings, so just return "". 3764 return ""; 3765 case "string": // Could be any arbitrary string -- use empty string instead. 3766 return ""; 3767 case "number": // Allow numbers, but be sure to check it's actually a number. 3768 return typeof value === "number" ? value : ""; 3769 case "boolean": 3770 return typeof value === "boolean" ? value : ""; 3771 case "list": 3772 const elementType = option.element; 3773 return isArray(value) ? value.map(v => getOptionValueWithEmptyStrings(v, elementType)) : ""; 3774 default: 3775 return forEachEntry(option.type, (optionEnumValue, optionStringValue) => { 3776 if (optionEnumValue === value) { 3777 return optionStringValue; 3778 } 3779 })!; // TODO: GH#18217 3780 } 3781 } 3782 3783 3784 function getDefaultValueForOption(option: CommandLineOption) { 3785 switch (option.type) { 3786 case "number": 3787 return 1; 3788 case "boolean": 3789 return true; 3790 case "string": 3791 const defaultValue = option.defaultValueDescription; 3792 return option.isFilePath ? `./${defaultValue && typeof defaultValue === "string" ? defaultValue : ""}` : ""; 3793 case "list": 3794 return []; 3795 case "object": 3796 return {}; 3797 default: 3798 const iterResult = option.type.keys().next(); 3799 if (!iterResult.done) return iterResult.value; 3800 return Debug.fail("Expected 'option.type' to have entries."); 3801 } 3802 } 3803} 3804