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