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