• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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