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