• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    interface Statistic {
3        name: string;
4        value: number;
5        type: StatisticType;
6    }
7
8    export enum StatisticType {
9        time,
10        count,
11        memory,
12    }
13
14    function countLines(program: Program): Map<number> {
15        const counts = getCountsMap();
16        forEach(program.getSourceFiles(), file => {
17            const key = getCountKey(program, file);
18            const lineCount = getLineStarts(file).length;
19            counts.set(key, counts.get(key)! + lineCount);
20        });
21        return counts;
22    }
23
24    function getCountsMap() {
25        const counts = new Map<string, number>();
26        counts.set("Library", 0);
27        counts.set("Definitions", 0);
28        counts.set("TypeScript", 0);
29        counts.set("JavaScript", 0);
30        counts.set("JSON", 0);
31        counts.set("Other", 0);
32        return counts;
33    }
34
35    function getCountKey(program: Program, file: SourceFile) {
36        if (program.isSourceFileDefaultLibrary(file)) {
37            return "Library";
38        }
39        else if (file.isDeclarationFile) {
40            return "Definitions";
41        }
42
43        const path = file.path;
44        if (fileExtensionIsOneOf(path, supportedTSExtensionsFlat)) {
45            return "TypeScript";
46        }
47        else if (fileExtensionIsOneOf(path, supportedJSExtensionsFlat)) {
48            return "JavaScript";
49        }
50        else if (fileExtensionIs(path, Extension.Json)) {
51            return "JSON";
52        }
53        else {
54            return "Other";
55        }
56    }
57
58    function updateReportDiagnostic(
59        sys: System,
60        existing: DiagnosticReporter,
61        options: CompilerOptions | BuildOptions
62    ): DiagnosticReporter {
63        return shouldBePretty(sys, options) ?
64            createDiagnosticReporter(sys, /*pretty*/ true) :
65            existing;
66    }
67
68    function defaultIsPretty(sys: System) {
69        return !!sys.writeOutputIsTTY && sys.writeOutputIsTTY() && !sys.getEnvironmentVariable("NO_COLOR");
70    }
71
72    function shouldBePretty(sys: System, options: CompilerOptions | BuildOptions) {
73        if (!options || typeof options.pretty === "undefined") {
74            return defaultIsPretty(sys);
75        }
76        return options.pretty;
77    }
78
79    function getOptionsForHelp(commandLine: ParsedCommandLine) {
80        // Sort our options by their names, (e.g. "--noImplicitAny" comes before "--watch")
81        return !!commandLine.options.all ?
82            sort(optionDeclarations, (a, b) => compareStringsCaseInsensitive(a.name, b.name)) :
83            filter(optionDeclarations.slice(), v => !!v.showInSimplifiedHelpView);
84    }
85
86    function printVersion(sys: System) {
87        sys.write(getDiagnosticText(Diagnostics.Version_0, version) + sys.newLine);
88    }
89
90    function createColors(sys: System) {
91        const showColors = defaultIsPretty(sys);
92        if (!showColors) {
93            return {
94                bold: (str: string) => str,
95                blue: (str: string) => str,
96                blueBackground: (str: string) => str,
97                brightWhite: (str: string) => str
98            };
99        }
100
101        function bold(str: string) {
102            return `\x1b[1m${str}\x1b[22m`;
103        }
104
105        const isWindows = sys.getEnvironmentVariable("OS") && stringContains(sys.getEnvironmentVariable("OS").toLowerCase(), "windows");
106        const isWindowsTerminal = sys.getEnvironmentVariable("WT_SESSION");
107        const isVSCode = sys.getEnvironmentVariable("TERM_PROGRAM") && sys.getEnvironmentVariable("TERM_PROGRAM") === "vscode";
108
109        function blue(str: string) {
110            // Effectively Powershell and Command prompt users use cyan instead
111            // of blue because the default theme doesn't show blue with enough contrast.
112            if (isWindows && !isWindowsTerminal && !isVSCode) {
113                return brightWhite(str);
114            }
115
116            return `\x1b[94m${str}\x1b[39m`;
117        }
118
119        // There are ~3 types of terminal color support: 16 colors, 256 and 16m colors
120        // If there is richer color support, e.g. 256+ we can use extended ANSI codes which are not just generic 'blue'
121        // but a 'lighter blue' which is closer to the blue in the TS logo.
122        const supportsRicherColors = sys.getEnvironmentVariable("COLORTERM") === "truecolor" || sys.getEnvironmentVariable("TERM") === "xterm-256color";
123        function blueBackground(str: string) {
124            if (supportsRicherColors) {
125                return `\x1B[48;5;68m${str}\x1B[39;49m`;
126            }
127            else {
128                return `\x1b[44m${str}\x1B[39;49m`;
129            }
130        }
131        function brightWhite(str: string) {
132            return `\x1b[97m${str}\x1b[39m`;
133        }
134        return {
135            bold,
136            blue,
137            brightWhite,
138            blueBackground
139        };
140    }
141
142    function getDisplayNameTextOfOption(option: CommandLineOption) {
143        return `--${option.name}${option.shortName ? `, -${option.shortName}` : ""}`;
144    }
145
146    function generateOptionOutput(sys: System, option: CommandLineOption, rightAlignOfLeft: number, leftAlignOfRight: number) {
147        interface ValueCandidate {
148            // "one or more" or "any of"
149            valueType: string;
150            possibleValues: string;
151        }
152
153        const text: string[] = [];
154        const colors = createColors(sys);
155
156        // name and description
157        const name = getDisplayNameTextOfOption(option);
158
159        // value type and possible value
160        const valueCandidates = getValueCandidate(option);
161        const defaultValueDescription =
162            typeof option.defaultValueDescription === "object"
163                ? getDiagnosticText(option.defaultValueDescription)
164                : formatDefaultValue(
165                      option.defaultValueDescription,
166                      option.type === "list" ? option.element.type : option.type
167                  );
168        const terminalWidth = sys.getWidthOfTerminal?.() ?? 0;
169
170        // Note: child_process might return `terminalWidth` as undefined.
171        if (terminalWidth >= 80) {
172            let description = "";
173            if (option.description) {
174                description = getDiagnosticText(option.description);
175            }
176            text.push(...getPrettyOutput(name, description, rightAlignOfLeft, leftAlignOfRight, terminalWidth, /*colorLeft*/ true), sys.newLine);
177            if (showAdditionalInfoOutput(valueCandidates, option)) {
178                if (valueCandidates) {
179                    text.push(...getPrettyOutput(valueCandidates.valueType, valueCandidates.possibleValues, rightAlignOfLeft, leftAlignOfRight, terminalWidth, /*colorLeft*/ false), sys.newLine);
180                }
181                if (defaultValueDescription) {
182                    text.push(...getPrettyOutput(getDiagnosticText(Diagnostics.default_Colon), defaultValueDescription, rightAlignOfLeft, leftAlignOfRight, terminalWidth, /*colorLeft*/ false), sys.newLine);
183                }
184            }
185            text.push(sys.newLine);
186        }
187        else {
188            text.push(colors.blue(name), sys.newLine);
189            if (option.description) {
190                const description = getDiagnosticText(option.description);
191                text.push(description);
192            }
193            text.push(sys.newLine);
194            if (showAdditionalInfoOutput(valueCandidates, option)) {
195                if (valueCandidates) {
196                    text.push(`${valueCandidates.valueType} ${valueCandidates.possibleValues}`);
197                }
198                if (defaultValueDescription) {
199                    if (valueCandidates) text.push(sys.newLine);
200                    const diagType = getDiagnosticText(Diagnostics.default_Colon);
201                    text.push(`${diagType} ${defaultValueDescription}`);
202                }
203
204                text.push(sys.newLine);
205            }
206            text.push(sys.newLine);
207        }
208        return text;
209
210        function formatDefaultValue(
211            defaultValue: CommandLineOption["defaultValueDescription"],
212            type: CommandLineOption["type"]
213        ) {
214            return defaultValue !== undefined && typeof type === "object"
215                // e.g. ScriptTarget.ES2015 -> "es6/es2015"
216                ? arrayFrom(type.entries())
217                      .filter(([, value]) => value === defaultValue)
218                      .map(([name]) => name)
219                      .join("/")
220                : String(defaultValue);
221        }
222
223        function showAdditionalInfoOutput(valueCandidates: ValueCandidate | undefined, option: CommandLineOption): boolean {
224            const ignoreValues = ["string"];
225            const ignoredDescriptions = [undefined, "false", "n/a"];
226            const defaultValueDescription = option.defaultValueDescription;
227            if (option.category === Diagnostics.Command_line_Options) return false;
228
229            if (contains(ignoreValues, valueCandidates?.possibleValues) && contains(ignoredDescriptions, defaultValueDescription)) {
230                return false;
231            }
232            return true;
233        }
234
235        function getPrettyOutput(left: string, right: string, rightAlignOfLeft: number, leftAlignOfRight: number, terminalWidth: number, colorLeft: boolean) {
236            const res = [];
237            let isFirstLine = true;
238            let remainRight = right;
239            const rightCharacterNumber = terminalWidth - leftAlignOfRight;
240            while (remainRight.length > 0) {
241                let curLeft = "";
242                if (isFirstLine) {
243                    curLeft = padLeft(left, rightAlignOfLeft);
244                    curLeft = padRight(curLeft, leftAlignOfRight);
245                    curLeft = colorLeft ? colors.blue(curLeft) : curLeft;
246                }
247                else {
248                    curLeft = padLeft("", leftAlignOfRight);
249                }
250
251                const curRight = remainRight.substr(0, rightCharacterNumber);
252                remainRight = remainRight.slice(rightCharacterNumber);
253                res.push(`${curLeft}${curRight}`);
254                isFirstLine = false;
255            }
256            return res;
257        }
258
259        function getValueCandidate(option: CommandLineOption): ValueCandidate | undefined {
260            // option.type might be "string" | "number" | "boolean" | "object" | "list" | ESMap<string, number | string>
261            // string -- any of: string
262            // number -- any of: number
263            // boolean -- any of: boolean
264            // object -- null
265            // list -- one or more: , content depends on `option.element.type`, the same as others
266            // ESMap<string, number | string> -- any of: key1, key2, ....
267            if (option.type === "object") {
268                return undefined;
269            }
270
271            return {
272                valueType: getValueType(option),
273                possibleValues: getPossibleValues(option)
274            };
275
276            function getValueType(option: CommandLineOption) {
277                switch (option.type) {
278                    case "string":
279                    case "number":
280                    case "boolean":
281                        return getDiagnosticText(Diagnostics.type_Colon);
282                    case "list":
283                        return getDiagnosticText(Diagnostics.one_or_more_Colon);
284                    default:
285                        return getDiagnosticText(Diagnostics.one_of_Colon);
286                }
287            }
288
289            function getPossibleValues(option: CommandLineOption) {
290                let possibleValues: string;
291                switch (option.type) {
292                    case "string":
293                    case "number":
294                    case "boolean":
295                        possibleValues = option.type;
296                        break;
297                    case "list":
298                        // TODO: check infinite loop
299                        possibleValues = getPossibleValues(option.element);
300                        break;
301                    case "object":
302                        possibleValues = "";
303                        break;
304                    default:
305                        // ESMap<string, number | string>
306                        // Group synonyms: es6/es2015
307                        const inverted: { [value: string]: string[] } = {};
308                        option.type.forEach((value, name) => {
309                            (inverted[value] ||= []).push(name);
310                        });
311                        return getEntries(inverted)
312                            .map(([, synonyms]) => synonyms.join("/"))
313                            .join(", ");
314                }
315                return possibleValues;
316            }
317        }
318    }
319
320    function generateGroupOptionOutput(sys: System, optionsList: readonly CommandLineOption[]) {
321        let maxLength = 0;
322        for (const option of optionsList) {
323            const curLength = getDisplayNameTextOfOption(option).length;
324            maxLength = maxLength > curLength ? maxLength : curLength;
325        }
326
327        // left part should be right align, right part should be left align
328
329        // assume 2 space between left margin and left part.
330        const rightAlignOfLeftPart = maxLength + 2;
331        // assume 2 space between left and right part
332        const leftAlignOfRightPart = rightAlignOfLeftPart + 2;
333        let lines: string[] = [];
334        for (const option of optionsList) {
335            const tmp = generateOptionOutput(sys, option, rightAlignOfLeftPart, leftAlignOfRightPart);
336            lines = [...lines, ...tmp];
337        }
338        // make sure always a blank line in the end.
339        if (lines[lines.length - 2] !== sys.newLine) {
340            lines.push(sys.newLine);
341        }
342        return lines;
343    }
344
345    function generateSectionOptionsOutput(sys: System, sectionName: string, options: readonly CommandLineOption[], subCategory: boolean, beforeOptionsDescription?: string, afterOptionsDescription?: string) {
346        let res: string[] = [];
347        res.push(createColors(sys).bold(sectionName) + sys.newLine + sys.newLine);
348        if (beforeOptionsDescription) {
349            res.push(beforeOptionsDescription + sys.newLine + sys.newLine);
350        }
351        if (!subCategory) {
352            res = [...res, ...generateGroupOptionOutput(sys, options)];
353            if (afterOptionsDescription) {
354                res.push(afterOptionsDescription + sys.newLine + sys.newLine);
355            }
356            return res;
357        }
358        const categoryMap = new Map<string, CommandLineOption[]>();
359        for (const option of options) {
360            if (!option.category) {
361                continue;
362            }
363            const curCategory = getDiagnosticText(option.category);
364            const optionsOfCurCategory = categoryMap.get(curCategory) ?? [];
365            optionsOfCurCategory.push(option);
366            categoryMap.set(curCategory, optionsOfCurCategory);
367        }
368        categoryMap.forEach((value, key) => {
369            res.push(`### ${key}${sys.newLine}${sys.newLine}`);
370            res = [...res, ...generateGroupOptionOutput(sys, value)];
371        });
372        if (afterOptionsDescription) {
373            res.push(afterOptionsDescription + sys.newLine + sys.newLine);
374        }
375        return res;
376    }
377
378    function printEasyHelp(sys: System, simpleOptions: readonly CommandLineOption[]) {
379        const colors = createColors(sys);
380        let output: string[] = [...getHeader(sys,`${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${getDiagnosticText(Diagnostics.Version_0, version)}`)];
381        output.push(colors.bold(getDiagnosticText(Diagnostics.COMMON_COMMANDS)) + sys.newLine + sys.newLine);
382
383        example("tsc", Diagnostics.Compiles_the_current_project_tsconfig_json_in_the_working_directory);
384        example("tsc app.ts util.ts", Diagnostics.Ignoring_tsconfig_json_compiles_the_specified_files_with_default_compiler_options);
385        example("tsc -b", Diagnostics.Build_a_composite_project_in_the_working_directory);
386        example("tsc --init", Diagnostics.Creates_a_tsconfig_json_with_the_recommended_settings_in_the_working_directory);
387        example("tsc -p ./path/to/tsconfig.json", Diagnostics.Compiles_the_TypeScript_project_located_at_the_specified_path);
388        example("tsc --help --all", Diagnostics.An_expanded_version_of_this_information_showing_all_possible_compiler_options);
389        example(["tsc --noEmit", "tsc --target esnext"], Diagnostics.Compiles_the_current_project_with_additional_settings);
390
391        const cliCommands = simpleOptions.filter(opt => opt.isCommandLineOnly || opt.category === Diagnostics.Command_line_Options);
392        const configOpts = simpleOptions.filter(opt => !contains(cliCommands, opt));
393
394        output = [
395            ...output,
396            ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.COMMAND_LINE_FLAGS), cliCommands, /*subCategory*/ false, /* beforeOptionsDescription */ undefined, /* afterOptionsDescription*/ undefined),
397            ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.COMMON_COMPILER_OPTIONS), configOpts, /*subCategory*/ false, /* beforeOptionsDescription */ undefined, formatMessage(/*_dummy*/ undefined, Diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0, "https://aka.ms/tsc"))
398        ];
399
400        for (const line of output) {
401            sys.write(line);
402        }
403
404        function example(ex: string | string[], desc: DiagnosticMessage) {
405            const examples = typeof ex === "string" ? [ex] : ex;
406            for (const example of examples) {
407                output.push("  " + colors.blue(example) + sys.newLine);
408            }
409            output.push("  " + getDiagnosticText(desc) + sys.newLine + sys.newLine);
410        }
411    }
412
413    function printAllHelp(sys: System, compilerOptions: readonly CommandLineOption[], buildOptions: readonly CommandLineOption[], watchOptions: readonly CommandLineOption[]) {
414        let output: string[] = [...getHeader(sys,`${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${getDiagnosticText(Diagnostics.Version_0, version)}`)];
415        output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.ALL_COMPILER_OPTIONS), compilerOptions, /*subCategory*/ true, /* beforeOptionsDescription */ undefined, formatMessage(/*_dummy*/ undefined, Diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0, "https://aka.ms/tsc"))];
416        output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.WATCH_OPTIONS), watchOptions, /*subCategory*/ false, getDiagnosticText(Diagnostics.Including_watch_w_will_start_watching_the_current_project_for_the_file_changes_Once_set_you_can_config_watch_mode_with_Colon))];
417        output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.BUILD_OPTIONS), buildOptions, /*subCategory*/ false, formatMessage(/*_dummy*/ undefined, Diagnostics.Using_build_b_will_make_tsc_behave_more_like_a_build_orchestrator_than_a_compiler_This_is_used_to_trigger_building_composite_projects_which_you_can_learn_more_about_at_0, "https://aka.ms/tsc-composite-builds"))];
418        for (const line of output) {
419            sys.write(line);
420        }
421    }
422
423    function printBuildHelp(sys: System, buildOptions: readonly CommandLineOption[]) {
424        let output: string[] = [...getHeader(sys,`${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${getDiagnosticText(Diagnostics.Version_0, version)}`)];
425        output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.BUILD_OPTIONS), buildOptions, /*subCategory*/ false, formatMessage(/*_dummy*/ undefined, Diagnostics.Using_build_b_will_make_tsc_behave_more_like_a_build_orchestrator_than_a_compiler_This_is_used_to_trigger_building_composite_projects_which_you_can_learn_more_about_at_0, "https://aka.ms/tsc-composite-builds"))];
426        for (const line of output) {
427            sys.write(line);
428        }
429    }
430
431    function getHeader(sys: System, message: string) {
432        const colors = createColors(sys);
433        const header: string[] = [];
434        const terminalWidth = sys.getWidthOfTerminal?.() ?? 0;
435        const tsIconLength = 5;
436
437        const tsIconFirstLine = colors.blueBackground(padLeft("", tsIconLength));
438        const tsIconSecondLine = colors.blueBackground(colors.brightWhite(padLeft("TS ", tsIconLength)));
439        // If we have enough space, print TS icon.
440        if (terminalWidth >= message.length + tsIconLength) {
441            // right align of the icon is 120 at most.
442            const rightAlign = terminalWidth > 120 ? 120 : terminalWidth;
443            const leftAlign = rightAlign - tsIconLength;
444            header.push(padRight(message, leftAlign) + tsIconFirstLine + sys.newLine);
445            header.push(padLeft("", leftAlign) + tsIconSecondLine + sys.newLine);
446        }
447        else {
448            header.push(message + sys.newLine);
449            header.push(sys.newLine);
450        }
451        return header;
452    }
453
454    function printHelp(sys: System, commandLine: ParsedCommandLine) {
455        if (!commandLine.options.all) {
456            printEasyHelp(sys, getOptionsForHelp(commandLine));
457        }
458        else {
459            printAllHelp(sys, getOptionsForHelp(commandLine), optionsForBuild, optionsForWatch);
460        }
461    }
462
463    function executeCommandLineWorker(
464        sys: System,
465        cb: ExecuteCommandLineCallbacks,
466        commandLine: ParsedCommandLine,
467    ) {
468        let reportDiagnostic = createDiagnosticReporter(sys);
469        if (commandLine.options.build) {
470            reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_build_must_be_the_first_command_line_argument));
471            return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
472        }
473
474        // Configuration file name (if any)
475        let configFileName: string | undefined;
476        if (commandLine.options.locale) {
477            validateLocaleAndSetLanguage(commandLine.options.locale, sys, commandLine.errors);
478        }
479
480        // If there are any errors due to command line parsing and/or
481        // setting up localization, report them and quit.
482        if (commandLine.errors.length > 0) {
483            commandLine.errors.forEach(reportDiagnostic);
484            return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
485        }
486
487        if (commandLine.options.init) {
488            writeConfigFile(sys, reportDiagnostic, commandLine.options, commandLine.fileNames);
489            return sys.exit(ExitStatus.Success);
490        }
491
492        if (commandLine.options.version) {
493            printVersion(sys);
494            return sys.exit(ExitStatus.Success);
495        }
496
497        if (commandLine.options.help || commandLine.options.all) {
498            printHelp(sys, commandLine);
499            return sys.exit(ExitStatus.Success);
500        }
501
502        if (commandLine.options.watch && commandLine.options.listFilesOnly) {
503            reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "listFilesOnly"));
504            return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
505        }
506
507        if (commandLine.options.project) {
508            if (commandLine.fileNames.length !== 0) {
509                reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line));
510                return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
511            }
512
513            const fileOrDirectory = normalizePath(commandLine.options.project);
514            if (!fileOrDirectory /* current directory "." */ || sys.directoryExists(fileOrDirectory)) {
515                configFileName = combinePaths(fileOrDirectory, "tsconfig.json");
516                if (!sys.fileExists(configFileName)) {
517                    reportDiagnostic(createCompilerDiagnostic(Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_specified_directory_Colon_0, commandLine.options.project));
518                    return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
519                }
520            }
521            else {
522                configFileName = fileOrDirectory;
523                if (!sys.fileExists(configFileName)) {
524                    reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_specified_path_does_not_exist_Colon_0, commandLine.options.project));
525                    return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
526                }
527            }
528        }
529        else if (commandLine.fileNames.length === 0) {
530            const searchPath = normalizePath(sys.getCurrentDirectory());
531            configFileName = findConfigFile(searchPath, fileName => sys.fileExists(fileName));
532        }
533
534        if (commandLine.fileNames.length === 0 && !configFileName) {
535            if (commandLine.options.showConfig) {
536                reportDiagnostic(createCompilerDiagnostic(Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_current_directory_Colon_0, normalizePath(sys.getCurrentDirectory())));
537            }
538            else {
539                printVersion(sys);
540                printHelp(sys, commandLine);
541            }
542            return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
543        }
544
545        const currentDirectory = sys.getCurrentDirectory();
546        const commandLineOptions = convertToOptionsWithAbsolutePaths(
547            commandLine.options,
548            fileName => getNormalizedAbsolutePath(fileName, currentDirectory)
549        );
550        if (configFileName) {
551            const extendedConfigCache = new Map<string, ExtendedConfigCacheEntry>();
552            const configParseResult = parseConfigFileWithSystem(configFileName, commandLineOptions, extendedConfigCache, commandLine.watchOptions, sys, reportDiagnostic)!; // TODO: GH#18217
553            if (commandLineOptions.showConfig) {
554                if (configParseResult.errors.length !== 0) {
555                    reportDiagnostic = updateReportDiagnostic(
556                        sys,
557                        reportDiagnostic,
558                        configParseResult.options
559                    );
560                    configParseResult.errors.forEach(reportDiagnostic);
561                    return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
562                }
563                // eslint-disable-next-line no-null/no-null
564                sys.write(JSON.stringify(convertToTSConfig(configParseResult, configFileName, sys), null, 4) + sys.newLine);
565                return sys.exit(ExitStatus.Success);
566            }
567            reportDiagnostic = updateReportDiagnostic(
568                sys,
569                reportDiagnostic,
570                configParseResult.options
571            );
572            if (isWatchSet(configParseResult.options)) {
573                if (reportWatchModeWithoutSysSupport(sys, reportDiagnostic)) return;
574                return createWatchOfConfigFile(
575                    sys,
576                    cb,
577                    reportDiagnostic,
578                    configParseResult,
579                    commandLineOptions,
580                    commandLine.watchOptions,
581                    extendedConfigCache,
582                );
583            }
584            else if (isIncrementalCompilation(configParseResult.options)) {
585                performIncrementalCompilation(
586                    sys,
587                    cb,
588                    reportDiagnostic,
589                    configParseResult
590                );
591            }
592            else {
593                performCompilation(
594                    sys,
595                    cb,
596                    reportDiagnostic,
597                    configParseResult
598                );
599            }
600        }
601        else {
602            if (commandLineOptions.showConfig) {
603                // eslint-disable-next-line no-null/no-null
604                sys.write(JSON.stringify(convertToTSConfig(commandLine, combinePaths(currentDirectory, "tsconfig.json"), sys), null, 4) + sys.newLine);
605                return sys.exit(ExitStatus.Success);
606            }
607            reportDiagnostic = updateReportDiagnostic(
608                sys,
609                reportDiagnostic,
610                commandLineOptions
611            );
612            if (isWatchSet(commandLineOptions)) {
613                if (reportWatchModeWithoutSysSupport(sys, reportDiagnostic)) return;
614                return createWatchOfFilesAndCompilerOptions(
615                    sys,
616                    cb,
617                    reportDiagnostic,
618                    commandLine.fileNames,
619                    commandLineOptions,
620                    commandLine.watchOptions,
621                );
622            }
623            else if (isIncrementalCompilation(commandLineOptions)) {
624                performIncrementalCompilation(
625                    sys,
626                    cb,
627                    reportDiagnostic,
628                    { ...commandLine, options: commandLineOptions }
629                );
630            }
631            else {
632                performCompilation(
633                    sys,
634                    cb,
635                    reportDiagnostic,
636                    { ...commandLine, options: commandLineOptions }
637                );
638            }
639        }
640    }
641
642    export function isBuild(commandLineArgs: readonly string[]) {
643        if (commandLineArgs.length > 0 && commandLineArgs[0].charCodeAt(0) === CharacterCodes.minus) {
644            const firstOption = commandLineArgs[0].slice(commandLineArgs[0].charCodeAt(1) === CharacterCodes.minus ? 2 : 1).toLowerCase();
645            return firstOption === "build" || firstOption === "b";
646        }
647        return false;
648    }
649
650    export type ExecuteCommandLineCallbacks = (program: Program | BuilderProgram | ParsedCommandLine) => void;
651    export function executeCommandLine(
652        system: System,
653        cb: ExecuteCommandLineCallbacks,
654        commandLineArgs: readonly string[],
655    ) {
656        if (isBuild(commandLineArgs)) {
657            const { buildOptions, watchOptions, projects, errors } = parseBuildCommand(commandLineArgs.slice(1));
658            if (buildOptions.generateCpuProfile && system.enableCPUProfiler) {
659                system.enableCPUProfiler(buildOptions.generateCpuProfile, () => performBuild(
660                    system,
661                    cb,
662                    buildOptions,
663                    watchOptions,
664                    projects,
665                    errors
666                ));
667            }
668            else {
669                return performBuild(
670                    system,
671                    cb,
672                    buildOptions,
673                    watchOptions,
674                    projects,
675                    errors
676                );
677            }
678        }
679
680        const commandLine = parseCommandLine(commandLineArgs, path => system.readFile(path));
681        if (commandLine.options.generateCpuProfile && system.enableCPUProfiler) {
682            system.enableCPUProfiler(commandLine.options.generateCpuProfile, () => executeCommandLineWorker(
683                system,
684                cb,
685                commandLine,
686            ));
687        }
688        else {
689            return executeCommandLineWorker(system, cb, commandLine);
690        }
691    }
692
693    function reportWatchModeWithoutSysSupport(sys: System, reportDiagnostic: DiagnosticReporter) {
694        if (!sys.watchFile || !sys.watchDirectory) {
695            reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"));
696            sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
697            return true;
698        }
699        return false;
700    }
701
702    function performBuild(
703        sys: System,
704        cb: ExecuteCommandLineCallbacks,
705        buildOptions: BuildOptions,
706        watchOptions: WatchOptions | undefined,
707        projects: string[],
708        errors: Diagnostic[]
709    ) {
710        // Update to pretty if host supports it
711        const reportDiagnostic = updateReportDiagnostic(
712            sys,
713            createDiagnosticReporter(sys),
714            buildOptions
715        );
716
717        if (buildOptions.locale) {
718            validateLocaleAndSetLanguage(buildOptions.locale, sys, errors);
719        }
720
721        if (errors.length > 0) {
722            errors.forEach(reportDiagnostic);
723            return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
724        }
725
726        if (buildOptions.help) {
727            printVersion(sys);
728            printBuildHelp(sys, buildOpts);
729            return sys.exit(ExitStatus.Success);
730        }
731
732        if (projects.length === 0) {
733            printVersion(sys);
734            printBuildHelp(sys, buildOpts);
735            return sys.exit(ExitStatus.Success);
736        }
737
738        if (!sys.getModifiedTime || !sys.setModifiedTime || (buildOptions.clean && !sys.deleteFile)) {
739            reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build"));
740            return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
741        }
742
743        if (buildOptions.watch) {
744            if (reportWatchModeWithoutSysSupport(sys, reportDiagnostic)) return;
745            const buildHost = createSolutionBuilderWithWatchHost(
746                sys,
747                /*createProgram*/ undefined,
748                reportDiagnostic,
749                createBuilderStatusReporter(sys, shouldBePretty(sys, buildOptions)),
750                createWatchStatusReporter(sys, buildOptions)
751            );
752            const solutionPerformance = enableSolutionPerformance(sys, buildOptions);
753            updateSolutionBuilderHost(sys, cb, buildHost, solutionPerformance);
754            const onWatchStatusChange = buildHost.onWatchStatusChange;
755            buildHost.onWatchStatusChange = (d, newLine, options, errorCount) => {
756                onWatchStatusChange?.(d, newLine, options, errorCount);
757                if (d.code === Diagnostics.Found_0_errors_Watching_for_file_changes.code ||
758                    d.code === Diagnostics.Found_1_error_Watching_for_file_changes.code) {
759                    reportSolutionBuilderTimes(builder, solutionPerformance);
760                }
761            };
762            const builder = createSolutionBuilderWithWatch(buildHost, projects, buildOptions, watchOptions);
763            builder.build();
764            return builder;
765        }
766
767        const buildHost = createSolutionBuilderHost(
768            sys,
769            /*createProgram*/ undefined,
770            reportDiagnostic,
771            createBuilderStatusReporter(sys, shouldBePretty(sys, buildOptions)),
772            createReportErrorSummary(sys, buildOptions)
773        );
774        const solutionPerformance = enableSolutionPerformance(sys, buildOptions);
775        updateSolutionBuilderHost(sys, cb, buildHost, solutionPerformance);
776        const builder = createSolutionBuilder(buildHost, projects, buildOptions);
777        const exitStatus = buildOptions.clean ? builder.clean() : builder.build();
778        reportSolutionBuilderTimes(builder, solutionPerformance);
779        dumpTracingLegend(); // Will no-op if there hasn't been any tracing
780        return sys.exit(exitStatus);
781    }
782
783    function createReportErrorSummary(sys: System, options: CompilerOptions | BuildOptions): ReportEmitErrorSummary | undefined {
784        return shouldBePretty(sys, options) ?
785            (errorCount, filesInError) => sys.write(getErrorSummaryText(errorCount, filesInError, sys.newLine, sys)) :
786            undefined;
787    }
788
789    function performCompilation(
790        sys: System,
791        cb: ExecuteCommandLineCallbacks,
792        reportDiagnostic: DiagnosticReporter,
793        config: ParsedCommandLine
794    ) {
795        const { fileNames, options, projectReferences } = config;
796        const host = createCompilerHostWorker(options, /*setParentPos*/ undefined, sys);
797        const currentDirectory = host.getCurrentDirectory();
798        const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames());
799        changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, currentDirectory, getCanonicalFileName));
800        enableStatisticsAndTracing(sys, options, /*isBuildMode*/ false);
801
802        const programOptions: CreateProgramOptions = {
803            rootNames: fileNames,
804            options,
805            projectReferences,
806            host,
807            configFileParsingDiagnostics: getConfigFileParsingDiagnostics(config)
808        };
809        const program = createProgram(programOptions);
810        const exitStatus = emitFilesAndReportErrorsAndGetExitStatus(
811            program,
812            reportDiagnostic,
813            s => sys.write(s + sys.newLine),
814            createReportErrorSummary(sys, options)
815        );
816        reportStatistics(sys, program, /*builder*/ undefined);
817        cb(program);
818        return sys.exit(exitStatus);
819    }
820
821    function performIncrementalCompilation(
822        sys: System,
823        cb: ExecuteCommandLineCallbacks,
824        reportDiagnostic: DiagnosticReporter,
825        config: ParsedCommandLine
826    ) {
827        const { options, fileNames, projectReferences } = config;
828        enableStatisticsAndTracing(sys, options, /*isBuildMode*/ false);
829        const host = createIncrementalCompilerHost(options, sys);
830        const exitStatus = ts.performIncrementalCompilation({
831            host,
832            system: sys,
833            rootNames: fileNames,
834            options,
835            configFileParsingDiagnostics: getConfigFileParsingDiagnostics(config),
836            projectReferences,
837            reportDiagnostic,
838            reportErrorSummary: createReportErrorSummary(sys, options),
839            afterProgramEmitAndDiagnostics: builderProgram => {
840                reportStatistics(sys, builderProgram.getProgram(), /*builder*/ undefined);
841                cb(builderProgram);
842            }
843        });
844        return sys.exit(exitStatus);
845    }
846
847    function updateSolutionBuilderHost(
848        sys: System,
849        cb: ExecuteCommandLineCallbacks,
850        buildHost: SolutionBuilderHostBase<EmitAndSemanticDiagnosticsBuilderProgram>,
851        solutionPerformance: SolutionPerformance | undefined,
852    ) {
853        updateCreateProgram(sys, buildHost, /*isBuildMode*/ true);
854        buildHost.afterProgramEmitAndDiagnostics = program => {
855            reportStatistics(sys, program.getProgram(), solutionPerformance);
856            cb(program);
857        };
858        buildHost.afterEmitBundle = cb;
859    }
860
861    function updateCreateProgram<T extends BuilderProgram>(sys: System, host: { createProgram: CreateProgram<T>; }, isBuildMode: boolean) {
862        const compileUsingBuilder = host.createProgram;
863        host.createProgram = (rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences) => {
864            Debug.assert(rootNames !== undefined || (options === undefined && !!oldProgram));
865            if (options !== undefined) {
866                enableStatisticsAndTracing(sys, options, isBuildMode);
867            }
868            return compileUsingBuilder(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences);
869        };
870    }
871
872    function updateWatchCompilationHost(
873        sys: System,
874        cb: ExecuteCommandLineCallbacks,
875        watchCompilerHost: WatchCompilerHost<EmitAndSemanticDiagnosticsBuilderProgram>,
876    ) {
877        updateCreateProgram(sys, watchCompilerHost, /*isBuildMode*/ false);
878        const emitFilesUsingBuilder = watchCompilerHost.afterProgramCreate!; // TODO: GH#18217
879        watchCompilerHost.afterProgramCreate = builderProgram => {
880            emitFilesUsingBuilder(builderProgram);
881            reportStatistics(sys, builderProgram.getProgram(), /*builder*/ undefined);
882            cb(builderProgram);
883        };
884    }
885
886    function createWatchStatusReporter(sys: System, options: CompilerOptions | BuildOptions) {
887        return ts.createWatchStatusReporter(sys, shouldBePretty(sys, options));
888    }
889
890    function createWatchOfConfigFile(
891        system: System,
892        cb: ExecuteCommandLineCallbacks,
893        reportDiagnostic: DiagnosticReporter,
894        configParseResult: ParsedCommandLine,
895        optionsToExtend: CompilerOptions,
896        watchOptionsToExtend: WatchOptions | undefined,
897        extendedConfigCache: Map<ExtendedConfigCacheEntry>,
898    ) {
899        const watchCompilerHost = createWatchCompilerHostOfConfigFile({
900            configFileName: configParseResult.options.configFilePath!,
901            optionsToExtend,
902            watchOptionsToExtend,
903            system,
904            reportDiagnostic,
905            reportWatchStatus: createWatchStatusReporter(system, configParseResult.options)
906        });
907        updateWatchCompilationHost(system, cb, watchCompilerHost);
908        watchCompilerHost.configFileParsingResult = configParseResult;
909        watchCompilerHost.extendedConfigCache = extendedConfigCache;
910        return createWatchProgram(watchCompilerHost);
911    }
912
913    function createWatchOfFilesAndCompilerOptions(
914        system: System,
915        cb: ExecuteCommandLineCallbacks,
916        reportDiagnostic: DiagnosticReporter,
917        rootFiles: string[],
918        options: CompilerOptions,
919        watchOptions: WatchOptions | undefined,
920    ) {
921        const watchCompilerHost = createWatchCompilerHostOfFilesAndCompilerOptions({
922            rootFiles,
923            options,
924            watchOptions,
925            system,
926            reportDiagnostic,
927            reportWatchStatus: createWatchStatusReporter(system, options)
928        });
929        updateWatchCompilationHost(system, cb, watchCompilerHost);
930        return createWatchProgram(watchCompilerHost);
931    }
932
933    interface SolutionPerformance {
934        addAggregateStatistic(s: Statistic): void;
935        forEachAggregateStatistics(cb: (s: Statistic) => void): void;
936        clear(): void;
937    }
938
939    function enableSolutionPerformance(system: System, options: BuildOptions) {
940        if (system === sys && options.extendedDiagnostics) {
941            performance.enable();
942            return createSolutionPerfomrance();
943        }
944    }
945
946    function createSolutionPerfomrance(): SolutionPerformance {
947        let statistics: ESMap<string, Statistic> | undefined;
948        return {
949            addAggregateStatistic,
950            forEachAggregateStatistics: forEachAggreateStatistics,
951            clear,
952        };
953
954        function addAggregateStatistic(s: Statistic) {
955            const existing = statistics?.get(s.name);
956            if (existing) {
957                if (existing.type === StatisticType.memory) existing.value = Math.max(existing.value, s.value);
958                else existing.value += s.value;
959            }
960            else {
961                (statistics ??= new Map()).set(s.name, s);
962            }
963        }
964
965        function forEachAggreateStatistics(cb: (s: Statistic) => void) {
966            statistics?.forEach(cb);
967        }
968
969        function clear() {
970            statistics = undefined;
971        }
972    }
973
974    function reportSolutionBuilderTimes(
975        builder: SolutionBuilder<EmitAndSemanticDiagnosticsBuilderProgram>,
976        solutionPerformance: SolutionPerformance | undefined) {
977        if (!solutionPerformance) return;
978
979        if (!performance.isEnabled()) {
980            sys.write(Diagnostics.Performance_timings_for_diagnostics_or_extendedDiagnostics_are_not_available_in_this_session_A_native_implementation_of_the_Web_Performance_API_could_not_be_found.message + "\n");
981            return;
982        }
983
984        const statistics: Statistic[] = [];
985        statistics.push(
986            { name: "Projects in scope", value: getBuildOrderFromAnyBuildOrder(builder.getBuildOrder()).length, type: StatisticType.count },
987        );
988        reportSolutionBuilderCountStatistic("SolutionBuilder::Projects built");
989        reportSolutionBuilderCountStatistic("SolutionBuilder::Timestamps only updates");
990        reportSolutionBuilderCountStatistic("SolutionBuilder::Bundles updated");
991        solutionPerformance.forEachAggregateStatistics(s => {
992            s.name = `Aggregate ${s.name}`;
993            statistics.push(s);
994        });
995        performance.forEachMeasure((name, duration) => {
996            if (isSolutionMarkOrMeasure(name)) statistics.push({ name: `${getNameFromSolutionBuilderMarkOrMeasure(name)} time`, value: duration, type: StatisticType.time });
997        });
998        performance.disable();
999        performance.enable();
1000
1001        reportAllStatistics(sys, statistics);
1002
1003        function reportSolutionBuilderCountStatistic(name: string) {
1004            const value = performance.getCount(name);
1005            if (value) {
1006                statistics.push({ name: getNameFromSolutionBuilderMarkOrMeasure(name), value, type: StatisticType.count });
1007            }
1008        }
1009
1010        function getNameFromSolutionBuilderMarkOrMeasure(name: string) {
1011            return name.replace("SolutionBuilder::", "");
1012        }
1013    }
1014
1015    function canReportDiagnostics(system: System, compilerOptions: CompilerOptions) {
1016        return system === sys && (compilerOptions.diagnostics || compilerOptions.extendedDiagnostics);
1017    }
1018
1019    function canTrace(system: System, compilerOptions: CompilerOptions) {
1020        return system === sys && compilerOptions.generateTrace;
1021    }
1022
1023    function enableStatisticsAndTracing(system: System, compilerOptions: CompilerOptions, isBuildMode: boolean) {
1024        if (canReportDiagnostics(system, compilerOptions)) {
1025            performance.enable(system);
1026        }
1027
1028        if (canTrace(system, compilerOptions)) {
1029            startTracing(isBuildMode ? "build" : "project",
1030                compilerOptions.generateTrace!, compilerOptions.configFilePath);
1031        }
1032    }
1033
1034    function isSolutionMarkOrMeasure(name: string) {
1035        return startsWith(name, "SolutionBuilder::");
1036    }
1037
1038    function reportStatistics(sys: System, program: Program, solutionPerformance: SolutionPerformance | undefined) {
1039        const compilerOptions = program.getCompilerOptions();
1040
1041        if (canTrace(sys, compilerOptions)) {
1042            tracing?.stopTracing();
1043        }
1044
1045        let statistics: Statistic[];
1046        if (canReportDiagnostics(sys, compilerOptions)) {
1047            statistics = [];
1048            const memoryUsed = sys.getMemoryUsage ? sys.getMemoryUsage() : -1;
1049            reportCountStatistic("Files", program.getSourceFiles().length);
1050
1051            const lineCounts = countLines(program);
1052            if (compilerOptions.extendedDiagnostics) {
1053                for (const key of arrayFrom(lineCounts.keys())) {
1054                    reportCountStatistic("Lines of " + key, lineCounts.get(key)!);
1055                }
1056            }
1057            else {
1058                reportCountStatistic("Lines", reduceLeftIterator(lineCounts.values(), (sum, count) => sum + count, 0));
1059            }
1060
1061            reportCountStatistic("Identifiers", program.getIdentifierCount());
1062            reportCountStatistic("Symbols", program.getSymbolCount());
1063            reportCountStatistic("Types", program.getTypeCount());
1064            reportCountStatistic("Instantiations", program.getInstantiationCount());
1065
1066            if (memoryUsed >= 0) {
1067                reportStatisticalValue({ name: "Memory used", value: memoryUsed, type: StatisticType.memory }, /*aggregate*/ true);
1068            }
1069
1070            const isPerformanceEnabled = performance.isEnabled();
1071            const programTime = isPerformanceEnabled ? performance.getDuration("Program") : 0;
1072            const bindTime = isPerformanceEnabled ? performance.getDuration("Bind") : 0;
1073            const checkTime = isPerformanceEnabled ? performance.getDuration("Check") : 0;
1074            const emitTime = isPerformanceEnabled ? performance.getDuration("Emit") : 0;
1075            if (compilerOptions.extendedDiagnostics) {
1076                const caches = program.getRelationCacheSizes();
1077                reportCountStatistic("Assignability cache size", caches.assignable);
1078                reportCountStatistic("Identity cache size", caches.identity);
1079                reportCountStatistic("Subtype cache size", caches.subtype);
1080                reportCountStatistic("Strict subtype cache size", caches.strictSubtype);
1081                if (isPerformanceEnabled) {
1082                    performance.forEachMeasure((name, duration) => {
1083                        if (!isSolutionMarkOrMeasure(name)) reportTimeStatistic(`${name} time`, duration, /*aggregate*/ true);
1084                    });
1085                }
1086            }
1087            else if (isPerformanceEnabled) {
1088                // Individual component times.
1089                // Note: To match the behavior of previous versions of the compiler, the reported parse time includes
1090                // I/O read time and processing time for triple-slash references and module imports, and the reported
1091                // emit time includes I/O write time. We preserve this behavior so we can accurately compare times.
1092                reportTimeStatistic("I/O read", performance.getDuration("I/O Read"), /*aggregate*/ true);
1093                reportTimeStatistic("I/O write", performance.getDuration("I/O Write"), /*aggregate*/ true);
1094                reportTimeStatistic("Parse time", programTime, /*aggregate*/ true);
1095                reportTimeStatistic("Bind time", bindTime, /*aggregate*/ true);
1096                reportTimeStatistic("Check time", checkTime, /*aggregate*/ true);
1097                reportTimeStatistic("Emit time", emitTime, /*aggregate*/ true);
1098            }
1099            if (isPerformanceEnabled) {
1100                reportTimeStatistic("Total time", programTime + bindTime + checkTime + emitTime, /*aggregate*/ false);
1101            }
1102            reportAllStatistics(sys, statistics);
1103            if (!isPerformanceEnabled) {
1104                sys.write(Diagnostics.Performance_timings_for_diagnostics_or_extendedDiagnostics_are_not_available_in_this_session_A_native_implementation_of_the_Web_Performance_API_could_not_be_found.message + "\n");
1105            }
1106            else {
1107                if (solutionPerformance) {
1108                    // Clear selected marks and measures
1109                    performance.forEachMeasure(name => {
1110                        if (!isSolutionMarkOrMeasure(name)) performance.clearMeasures(name);
1111                    });
1112                    performance.forEachMark(name => {
1113                        if (!isSolutionMarkOrMeasure(name)) performance.clearMarks(name);
1114                    });
1115                }
1116                else {
1117                    performance.disable();
1118                }
1119            }
1120        }
1121
1122        function reportStatisticalValue(s: Statistic, aggregate: boolean) {
1123            statistics.push(s);
1124            if (aggregate) solutionPerformance?.addAggregateStatistic(s);
1125        }
1126
1127        function reportCountStatistic(name: string, count: number) {
1128            reportStatisticalValue({ name, value: count, type: StatisticType.count }, /*aggregate*/ true);
1129        }
1130
1131        function reportTimeStatistic(name: string, time: number, aggregate: boolean) {
1132            reportStatisticalValue({ name, value: time, type: StatisticType.time }, aggregate);
1133        }
1134    }
1135
1136    function reportAllStatistics(sys: System, statistics: Statistic[]) {
1137        let nameSize = 0;
1138        let valueSize = 0;
1139        for (const s of statistics) {
1140            if (s.name.length > nameSize) {
1141                nameSize = s.name.length;
1142            }
1143
1144            const value = statisticValue(s);
1145            if (value.length > valueSize) {
1146                valueSize = value.length;
1147            }
1148        }
1149
1150        for (const s of statistics) {
1151            sys.write(padRight(s.name + ":", nameSize + 2) + padLeft(statisticValue(s).toString(), valueSize) + sys.newLine);
1152        }
1153    }
1154
1155    function statisticValue(s: Statistic) {
1156        switch (s.type) {
1157            case StatisticType.count:
1158                return "" + s.value;
1159            case StatisticType.time:
1160                return (s.value / 1000).toFixed(2) + "s";
1161            case StatisticType.memory:
1162                return Math.round(s.value / 1000) + "K";
1163            default:
1164                Debug.assertNever(s.type);
1165        }
1166    }
1167
1168    function writeConfigFile(
1169        sys: System,
1170        reportDiagnostic: DiagnosticReporter,
1171        options: CompilerOptions,
1172        fileNames: string[]
1173    ) {
1174        const currentDirectory = sys.getCurrentDirectory();
1175        const file = normalizePath(combinePaths(currentDirectory, "tsconfig.json"));
1176        if (sys.fileExists(file)) {
1177            reportDiagnostic(createCompilerDiagnostic(Diagnostics.A_tsconfig_json_file_is_already_defined_at_Colon_0, file));
1178        }
1179        else {
1180            sys.writeFile(file, generateTSConfig(options, fileNames, sys.newLine));
1181            const output: string[] = [sys.newLine, ...getHeader(sys,"Created a new tsconfig.json with:")];
1182            output.push(getCompilerOptionsDiffValue(options, sys.newLine) + sys.newLine + sys.newLine);
1183            output.push(`You can learn more at https://aka.ms/tsconfig` + sys.newLine);
1184            for (const line of output) {
1185                sys.write(line);
1186            }
1187        }
1188
1189        return;
1190    }
1191}
1192