1namespace ts { 2 interface Statistic { 3 name: string; 4 value: string; 5 } 6 7 function countLines(program: Program): Map<number> { 8 const counts = getCountsMap(); 9 forEach(program.getSourceFiles(), file => { 10 const key = getCountKey(program, file); 11 const lineCount = getLineStarts(file).length; 12 counts.set(key, counts.get(key)! + lineCount); 13 }); 14 return counts; 15 } 16 17 function countNodes(program: Program): Map<number> { 18 const counts = getCountsMap(); 19 forEach(program.getSourceFiles(), file => { 20 const key = getCountKey(program, file); 21 counts.set(key, counts.get(key)! + file.nodeCount); 22 }); 23 return counts; 24 } 25 26 function getCountsMap() { 27 const counts = createMap<number>(); 28 counts.set("Library", 0); 29 counts.set("Definitions", 0); 30 counts.set("TypeScript", 0); 31 counts.set("JavaScript", 0); 32 counts.set("JSON", 0); 33 counts.set("Other", 0); 34 return counts; 35 } 36 37 function getCountKey(program: Program, file: SourceFile) { 38 if (program.isSourceFileDefaultLibrary(file)) { 39 return "Library"; 40 } 41 else if (file.isDeclarationFile) { 42 return "Definitions"; 43 } 44 45 const path = file.path; 46 if (fileExtensionIsOneOf(path, supportedTSExtensions)) { 47 return "TypeScript"; 48 } 49 else if (fileExtensionIsOneOf(path, supportedJSExtensions)) { 50 return "JavaScript"; 51 } 52 else if (fileExtensionIs(path, Extension.Json)) { 53 return "JSON"; 54 } 55 else { 56 return "Other"; 57 } 58 } 59 60 function updateReportDiagnostic( 61 sys: System, 62 existing: DiagnosticReporter, 63 options: CompilerOptions | BuildOptions 64 ): DiagnosticReporter { 65 return shouldBePretty(sys, options) ? 66 createDiagnosticReporter(sys, /*pretty*/ true) : 67 existing; 68 } 69 70 function defaultIsPretty(sys: System) { 71 return !!sys.writeOutputIsTTY && sys.writeOutputIsTTY(); 72 } 73 74 function shouldBePretty(sys: System, options: CompilerOptions | BuildOptions) { 75 if (!options || typeof options.pretty === "undefined") { 76 return defaultIsPretty(sys); 77 } 78 return options.pretty; 79 } 80 81 function getOptionsForHelp(commandLine: ParsedCommandLine) { 82 // Sort our options by their names, (e.g. "--noImplicitAny" comes before "--watch") 83 return !!commandLine.options.all ? 84 sort(optionDeclarations, (a, b) => compareStringsCaseInsensitive(a.name, b.name)) : 85 filter(optionDeclarations.slice(), v => !!v.showInSimplifiedHelpView); 86 } 87 88 function printVersion(sys: System) { 89 sys.write(getDiagnosticText(Diagnostics.Version_0, version) + sys.newLine); 90 } 91 92 function printHelp(sys: System, optionsList: readonly CommandLineOption[], syntaxPrefix = "") { 93 const output: string[] = []; 94 95 // We want to align our "syntax" and "examples" commands to a certain margin. 96 const syntaxLength = getDiagnosticText(Diagnostics.Syntax_Colon_0, "").length; 97 const examplesLength = getDiagnosticText(Diagnostics.Examples_Colon_0, "").length; 98 let marginLength = Math.max(syntaxLength, examplesLength); 99 100 // Build up the syntactic skeleton. 101 let syntax = makePadding(marginLength - syntaxLength); 102 syntax += `tsc ${syntaxPrefix}[${getDiagnosticText(Diagnostics.options)}] [${getDiagnosticText(Diagnostics.file)}...]`; 103 104 output.push(getDiagnosticText(Diagnostics.Syntax_Colon_0, syntax)); 105 output.push(sys.newLine + sys.newLine); 106 107 // Build up the list of examples. 108 const padding = makePadding(marginLength); 109 output.push(getDiagnosticText(Diagnostics.Examples_Colon_0, makePadding(marginLength - examplesLength) + "tsc hello.ts") + sys.newLine); 110 output.push(padding + "tsc --outFile file.js file.ts" + sys.newLine); 111 output.push(padding + "tsc @args.txt" + sys.newLine); 112 output.push(padding + "tsc --build tsconfig.json" + sys.newLine); 113 output.push(sys.newLine); 114 115 output.push(getDiagnosticText(Diagnostics.Options_Colon) + sys.newLine); 116 117 // We want our descriptions to align at the same column in our output, 118 // so we keep track of the longest option usage string. 119 marginLength = 0; 120 const usageColumn: string[] = []; // Things like "-d, --declaration" go in here. 121 const descriptionColumn: string[] = []; 122 123 const optionsDescriptionMap = new Map<string, string[]>(); // Map between option.description and list of option.type if it is a kind 124 125 for (const option of optionsList) { 126 // If an option lacks a description, 127 // it is not officially supported. 128 if (!option.description) { 129 continue; 130 } 131 132 let usageText = " "; 133 if (option.shortName) { 134 usageText += "-" + option.shortName; 135 usageText += getParamType(option); 136 usageText += ", "; 137 } 138 139 usageText += "--" + option.name; 140 usageText += getParamType(option); 141 142 usageColumn.push(usageText); 143 let description: string; 144 145 if (option.name === "lib") { 146 description = getDiagnosticText(option.description); 147 const element = (<CommandLineOptionOfListType>option).element; 148 const typeMap = <ESMap<string, number | string>>element.type; 149 optionsDescriptionMap.set(description, arrayFrom(typeMap.keys()).map(key => `'${key}'`)); 150 } 151 else { 152 description = getDiagnosticText(option.description); 153 } 154 155 descriptionColumn.push(description); 156 157 // Set the new margin for the description column if necessary. 158 marginLength = Math.max(usageText.length, marginLength); 159 } 160 161 // Special case that can't fit in the loop. 162 const usageText = " @<" + getDiagnosticText(Diagnostics.file) + ">"; 163 usageColumn.push(usageText); 164 descriptionColumn.push(getDiagnosticText(Diagnostics.Insert_command_line_options_and_files_from_a_file)); 165 marginLength = Math.max(usageText.length, marginLength); 166 167 // Print out each row, aligning all the descriptions on the same column. 168 for (let i = 0; i < usageColumn.length; i++) { 169 const usage = usageColumn[i]; 170 const description = descriptionColumn[i]; 171 const kindsList = optionsDescriptionMap.get(description); 172 output.push(usage + makePadding(marginLength - usage.length + 2) + description + sys.newLine); 173 174 if (kindsList) { 175 output.push(makePadding(marginLength + 4)); 176 for (const kind of kindsList) { 177 output.push(kind + " "); 178 } 179 output.push(sys.newLine); 180 } 181 } 182 183 for (const line of output) { 184 sys.write(line); 185 } 186 return; 187 188 function getParamType(option: CommandLineOption) { 189 if (option.paramType !== undefined) { 190 return " " + getDiagnosticText(option.paramType); 191 } 192 return ""; 193 } 194 195 function makePadding(paddingLength: number): string { 196 return Array(paddingLength + 1).join(" "); 197 } 198 } 199 200 function executeCommandLineWorker( 201 sys: System, 202 cb: ExecuteCommandLineCallbacks, 203 commandLine: ParsedCommandLine, 204 ) { 205 let reportDiagnostic = createDiagnosticReporter(sys); 206 if (commandLine.options.build) { 207 reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_build_must_be_the_first_command_line_argument)); 208 return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); 209 } 210 211 // Configuration file name (if any) 212 let configFileName: string | undefined; 213 if (commandLine.options.locale) { 214 validateLocaleAndSetLanguage(commandLine.options.locale, sys, commandLine.errors); 215 } 216 217 // If there are any errors due to command line parsing and/or 218 // setting up localization, report them and quit. 219 if (commandLine.errors.length > 0) { 220 commandLine.errors.forEach(reportDiagnostic); 221 return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); 222 } 223 224 if (commandLine.options.init) { 225 writeConfigFile(sys, reportDiagnostic, commandLine.options, commandLine.fileNames); 226 return sys.exit(ExitStatus.Success); 227 } 228 229 if (commandLine.options.version) { 230 printVersion(sys); 231 return sys.exit(ExitStatus.Success); 232 } 233 234 if (commandLine.options.help || commandLine.options.all) { 235 printVersion(sys); 236 printHelp(sys, getOptionsForHelp(commandLine)); 237 return sys.exit(ExitStatus.Success); 238 } 239 240 if (commandLine.options.watch && commandLine.options.listFilesOnly) { 241 reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "listFilesOnly")); 242 return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); 243 } 244 245 if (commandLine.options.project) { 246 if (commandLine.fileNames.length !== 0) { 247 reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line)); 248 return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); 249 } 250 251 const fileOrDirectory = normalizePath(commandLine.options.project); 252 if (!fileOrDirectory /* current directory "." */ || sys.directoryExists(fileOrDirectory)) { 253 configFileName = combinePaths(fileOrDirectory, "tsconfig.json"); 254 if (!sys.fileExists(configFileName)) { 255 reportDiagnostic(createCompilerDiagnostic(Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_specified_directory_Colon_0, commandLine.options.project)); 256 return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); 257 } 258 } 259 else { 260 configFileName = fileOrDirectory; 261 if (!sys.fileExists(configFileName)) { 262 reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_specified_path_does_not_exist_Colon_0, commandLine.options.project)); 263 return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); 264 } 265 } 266 } 267 else if (commandLine.fileNames.length === 0) { 268 const searchPath = normalizePath(sys.getCurrentDirectory()); 269 configFileName = findConfigFile(searchPath, fileName => sys.fileExists(fileName)); 270 } 271 272 if (commandLine.fileNames.length === 0 && !configFileName) { 273 if (commandLine.options.showConfig) { 274 reportDiagnostic(createCompilerDiagnostic(Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_current_directory_Colon_0, normalizePath(sys.getCurrentDirectory()))); 275 } 276 else { 277 printVersion(sys); 278 printHelp(sys, getOptionsForHelp(commandLine)); 279 } 280 return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); 281 } 282 283 const currentDirectory = sys.getCurrentDirectory(); 284 const commandLineOptions = convertToOptionsWithAbsolutePaths( 285 commandLine.options, 286 fileName => getNormalizedAbsolutePath(fileName, currentDirectory) 287 ); 288 if (configFileName) { 289 const configParseResult = parseConfigFileWithSystem(configFileName, commandLineOptions, commandLine.watchOptions, sys, reportDiagnostic)!; // TODO: GH#18217 290 if (commandLineOptions.showConfig) { 291 if (configParseResult.errors.length !== 0) { 292 reportDiagnostic = updateReportDiagnostic( 293 sys, 294 reportDiagnostic, 295 configParseResult.options 296 ); 297 configParseResult.errors.forEach(reportDiagnostic); 298 return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); 299 } 300 // eslint-disable-next-line no-null/no-null 301 sys.write(JSON.stringify(convertToTSConfig(configParseResult, configFileName, sys), null, 4) + sys.newLine); 302 return sys.exit(ExitStatus.Success); 303 } 304 reportDiagnostic = updateReportDiagnostic( 305 sys, 306 reportDiagnostic, 307 configParseResult.options 308 ); 309 if (isWatchSet(configParseResult.options)) { 310 if (reportWatchModeWithoutSysSupport(sys, reportDiagnostic)) return; 311 return createWatchOfConfigFile( 312 sys, 313 cb, 314 reportDiagnostic, 315 configParseResult, 316 commandLineOptions, 317 commandLine.watchOptions, 318 ); 319 } 320 else if (isIncrementalCompilation(configParseResult.options)) { 321 performIncrementalCompilation( 322 sys, 323 cb, 324 reportDiagnostic, 325 configParseResult 326 ); 327 } 328 else { 329 performCompilation( 330 sys, 331 cb, 332 reportDiagnostic, 333 configParseResult 334 ); 335 } 336 } 337 else { 338 if (commandLineOptions.showConfig) { 339 // eslint-disable-next-line no-null/no-null 340 sys.write(JSON.stringify(convertToTSConfig(commandLine, combinePaths(currentDirectory, "tsconfig.json"), sys), null, 4) + sys.newLine); 341 return sys.exit(ExitStatus.Success); 342 } 343 reportDiagnostic = updateReportDiagnostic( 344 sys, 345 reportDiagnostic, 346 commandLineOptions 347 ); 348 if (isWatchSet(commandLineOptions)) { 349 if (reportWatchModeWithoutSysSupport(sys, reportDiagnostic)) return; 350 return createWatchOfFilesAndCompilerOptions( 351 sys, 352 cb, 353 reportDiagnostic, 354 commandLine.fileNames, 355 commandLineOptions, 356 commandLine.watchOptions, 357 ); 358 } 359 else if (isIncrementalCompilation(commandLineOptions)) { 360 performIncrementalCompilation( 361 sys, 362 cb, 363 reportDiagnostic, 364 { ...commandLine, options: commandLineOptions } 365 ); 366 } 367 else { 368 performCompilation( 369 sys, 370 cb, 371 reportDiagnostic, 372 { ...commandLine, options: commandLineOptions } 373 ); 374 } 375 } 376 } 377 378 export function isBuild(commandLineArgs: readonly string[]) { 379 if (commandLineArgs.length > 0 && commandLineArgs[0].charCodeAt(0) === CharacterCodes.minus) { 380 const firstOption = commandLineArgs[0].slice(commandLineArgs[0].charCodeAt(1) === CharacterCodes.minus ? 2 : 1).toLowerCase(); 381 return firstOption === "build" || firstOption === "b"; 382 } 383 return false; 384 } 385 386 export type ExecuteCommandLineCallbacks = (program: Program | EmitAndSemanticDiagnosticsBuilderProgram | ParsedCommandLine) => void; 387 export function executeCommandLine( 388 system: System, 389 cb: ExecuteCommandLineCallbacks, 390 commandLineArgs: readonly string[], 391 ) { 392 if (isBuild(commandLineArgs)) { 393 const { buildOptions, watchOptions, projects, errors } = parseBuildCommand(commandLineArgs.slice(1)); 394 if (buildOptions.generateCpuProfile && system.enableCPUProfiler) { 395 system.enableCPUProfiler(buildOptions.generateCpuProfile, () => performBuild( 396 system, 397 cb, 398 buildOptions, 399 watchOptions, 400 projects, 401 errors 402 )); 403 } 404 else { 405 return performBuild( 406 system, 407 cb, 408 buildOptions, 409 watchOptions, 410 projects, 411 errors 412 ); 413 } 414 } 415 416 const commandLine = parseCommandLine(commandLineArgs, path => system.readFile(path)); 417 if (commandLine.options.generateCpuProfile && system.enableCPUProfiler) { 418 system.enableCPUProfiler(commandLine.options.generateCpuProfile, () => executeCommandLineWorker( 419 system, 420 cb, 421 commandLine, 422 )); 423 } 424 else { 425 return executeCommandLineWorker(system, cb, commandLine); 426 } 427 } 428 429 function reportWatchModeWithoutSysSupport(sys: System, reportDiagnostic: DiagnosticReporter) { 430 if (!sys.watchFile || !sys.watchDirectory) { 431 reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch")); 432 sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); 433 return true; 434 } 435 return false; 436 } 437 438 function performBuild( 439 sys: System, 440 cb: ExecuteCommandLineCallbacks, 441 buildOptions: BuildOptions, 442 watchOptions: WatchOptions | undefined, 443 projects: string[], 444 errors: Diagnostic[] 445 ) { 446 // Update to pretty if host supports it 447 const reportDiagnostic = updateReportDiagnostic( 448 sys, 449 createDiagnosticReporter(sys), 450 buildOptions 451 ); 452 453 if (buildOptions.locale) { 454 validateLocaleAndSetLanguage(buildOptions.locale, sys, errors); 455 } 456 457 if (errors.length > 0) { 458 errors.forEach(reportDiagnostic); 459 return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); 460 } 461 462 if (buildOptions.help) { 463 printVersion(sys); 464 printHelp(sys, buildOpts, "--build "); 465 return sys.exit(ExitStatus.Success); 466 } 467 468 if (projects.length === 0) { 469 printVersion(sys); 470 printHelp(sys, buildOpts, "--build "); 471 return sys.exit(ExitStatus.Success); 472 } 473 474 if (!sys.getModifiedTime || !sys.setModifiedTime || (buildOptions.clean && !sys.deleteFile)) { 475 reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build")); 476 return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); 477 } 478 479 if (buildOptions.watch) { 480 if (reportWatchModeWithoutSysSupport(sys, reportDiagnostic)) return; 481 const buildHost = createSolutionBuilderWithWatchHost( 482 sys, 483 /*createProgram*/ undefined, 484 reportDiagnostic, 485 createBuilderStatusReporter(sys, shouldBePretty(sys, buildOptions)), 486 createWatchStatusReporter(sys, buildOptions) 487 ); 488 updateSolutionBuilderHost(sys, cb, buildHost); 489 const builder = createSolutionBuilderWithWatch(buildHost, projects, buildOptions, watchOptions); 490 builder.build(); 491 return builder; 492 } 493 494 const buildHost = createSolutionBuilderHost( 495 sys, 496 /*createProgram*/ undefined, 497 reportDiagnostic, 498 createBuilderStatusReporter(sys, shouldBePretty(sys, buildOptions)), 499 createReportErrorSummary(sys, buildOptions) 500 ); 501 updateSolutionBuilderHost(sys, cb, buildHost); 502 const builder = createSolutionBuilder(buildHost, projects, buildOptions); 503 const exitStatus = buildOptions.clean ? builder.clean() : builder.build(); 504 tracing?.dumpLegend(); 505 return sys.exit(exitStatus); 506 } 507 508 function createReportErrorSummary(sys: System, options: CompilerOptions | BuildOptions): ReportEmitErrorSummary | undefined { 509 return shouldBePretty(sys, options) ? 510 errorCount => sys.write(getErrorSummaryText(errorCount, sys.newLine)) : 511 undefined; 512 } 513 514 function performCompilation( 515 sys: System, 516 cb: ExecuteCommandLineCallbacks, 517 reportDiagnostic: DiagnosticReporter, 518 config: ParsedCommandLine 519 ) { 520 const { fileNames, options, projectReferences } = config; 521 const host = createCompilerHostWorker(options, /*setParentPos*/ undefined, sys); 522 const currentDirectory = host.getCurrentDirectory(); 523 const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames()); 524 changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, currentDirectory, getCanonicalFileName)); 525 enableStatisticsAndTracing(sys, options, /*isBuildMode*/ false); 526 527 const programOptions: CreateProgramOptions = { 528 rootNames: fileNames, 529 options, 530 projectReferences, 531 host, 532 configFileParsingDiagnostics: getConfigFileParsingDiagnostics(config) 533 }; 534 const program = createProgram(programOptions); 535 const exitStatus = emitFilesAndReportErrorsAndGetExitStatus( 536 program, 537 reportDiagnostic, 538 s => sys.write(s + sys.newLine), 539 createReportErrorSummary(sys, options) 540 ); 541 reportStatistics(sys, program); 542 cb(program); 543 return sys.exit(exitStatus); 544 } 545 546 function performIncrementalCompilation( 547 sys: System, 548 cb: ExecuteCommandLineCallbacks, 549 reportDiagnostic: DiagnosticReporter, 550 config: ParsedCommandLine 551 ) { 552 const { options, fileNames, projectReferences } = config; 553 enableStatisticsAndTracing(sys, options, /*isBuildMode*/ false); 554 const host = createIncrementalCompilerHost(options, sys); 555 const exitStatus = ts.performIncrementalCompilation({ 556 host, 557 system: sys, 558 rootNames: fileNames, 559 options, 560 configFileParsingDiagnostics: getConfigFileParsingDiagnostics(config), 561 projectReferences, 562 reportDiagnostic, 563 reportErrorSummary: createReportErrorSummary(sys, options), 564 afterProgramEmitAndDiagnostics: builderProgram => { 565 reportStatistics(sys, builderProgram.getProgram()); 566 cb(builderProgram); 567 } 568 }); 569 return sys.exit(exitStatus); 570 } 571 572 function updateSolutionBuilderHost( 573 sys: System, 574 cb: ExecuteCommandLineCallbacks, 575 buildHost: SolutionBuilderHostBase<EmitAndSemanticDiagnosticsBuilderProgram> 576 ) { 577 updateCreateProgram(sys, buildHost); 578 buildHost.afterProgramEmitAndDiagnostics = program => { 579 reportStatistics(sys, program.getProgram()); 580 cb(program); 581 }; 582 buildHost.afterEmitBundle = cb; 583 } 584 585 function updateCreateProgram<T extends BuilderProgram>(sys: System, host: { createProgram: CreateProgram<T>; }) { 586 const compileUsingBuilder = host.createProgram; 587 host.createProgram = (rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences) => { 588 Debug.assert(rootNames !== undefined || (options === undefined && !!oldProgram)); 589 if (options !== undefined) { 590 enableStatisticsAndTracing(sys, options, /*isBuildMode*/ true); 591 } 592 return compileUsingBuilder(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences); 593 }; 594 } 595 596 function updateWatchCompilationHost( 597 sys: System, 598 cb: ExecuteCommandLineCallbacks, 599 watchCompilerHost: WatchCompilerHost<EmitAndSemanticDiagnosticsBuilderProgram>, 600 ) { 601 updateCreateProgram(sys, watchCompilerHost); 602 const emitFilesUsingBuilder = watchCompilerHost.afterProgramCreate!; // TODO: GH#18217 603 watchCompilerHost.afterProgramCreate = builderProgram => { 604 emitFilesUsingBuilder(builderProgram); 605 reportStatistics(sys, builderProgram.getProgram()); 606 cb(builderProgram); 607 }; 608 } 609 610 function createWatchStatusReporter(sys: System, options: CompilerOptions | BuildOptions) { 611 return ts.createWatchStatusReporter(sys, shouldBePretty(sys, options)); 612 } 613 614 function createWatchOfConfigFile( 615 system: System, 616 cb: ExecuteCommandLineCallbacks, 617 reportDiagnostic: DiagnosticReporter, 618 configParseResult: ParsedCommandLine, 619 optionsToExtend: CompilerOptions, 620 watchOptionsToExtend: WatchOptions | undefined, 621 ) { 622 const watchCompilerHost = createWatchCompilerHostOfConfigFile({ 623 configFileName: configParseResult.options.configFilePath!, 624 optionsToExtend, 625 watchOptionsToExtend, 626 system, 627 reportDiagnostic, 628 reportWatchStatus: createWatchStatusReporter(system, configParseResult.options) 629 }); 630 updateWatchCompilationHost(system, cb, watchCompilerHost); 631 watchCompilerHost.configFileParsingResult = configParseResult; 632 return createWatchProgram(watchCompilerHost); 633 } 634 635 function createWatchOfFilesAndCompilerOptions( 636 system: System, 637 cb: ExecuteCommandLineCallbacks, 638 reportDiagnostic: DiagnosticReporter, 639 rootFiles: string[], 640 options: CompilerOptions, 641 watchOptions: WatchOptions | undefined, 642 ) { 643 const watchCompilerHost = createWatchCompilerHostOfFilesAndCompilerOptions({ 644 rootFiles, 645 options, 646 watchOptions, 647 system, 648 reportDiagnostic, 649 reportWatchStatus: createWatchStatusReporter(system, options) 650 }); 651 updateWatchCompilationHost(system, cb, watchCompilerHost); 652 return createWatchProgram(watchCompilerHost); 653 } 654 655 function canReportDiagnostics(system: System, compilerOptions: CompilerOptions) { 656 return system === sys && (compilerOptions.diagnostics || compilerOptions.extendedDiagnostics); 657 } 658 659 function canTrace(system: System, compilerOptions: CompilerOptions) { 660 return system === sys && compilerOptions.generateTrace; 661 } 662 663 function enableStatisticsAndTracing(system: System, compilerOptions: CompilerOptions, isBuildMode: boolean) { 664 if (canReportDiagnostics(system, compilerOptions)) { 665 performance.enable(system); 666 } 667 668 if (canTrace(system, compilerOptions)) { 669 startTracing(isBuildMode ? tracingEnabled.Mode.Build : tracingEnabled.Mode.Project, 670 compilerOptions.generateTrace!, compilerOptions.configFilePath); 671 } 672 } 673 674 function reportStatistics(sys: System, program: Program) { 675 const compilerOptions = program.getCompilerOptions(); 676 677 if (canTrace(sys, compilerOptions)) { 678 tracing?.stopTracing(program.getTypeCatalog()); 679 } 680 681 let statistics: Statistic[]; 682 if (canReportDiagnostics(sys, compilerOptions)) { 683 statistics = []; 684 const memoryUsed = sys.getMemoryUsage ? sys.getMemoryUsage() : -1; 685 reportCountStatistic("Files", program.getSourceFiles().length); 686 687 const lineCounts = countLines(program); 688 const nodeCounts = countNodes(program); 689 if (compilerOptions.extendedDiagnostics) { 690 for (const key of arrayFrom(lineCounts.keys())) { 691 reportCountStatistic("Lines of " + key, lineCounts.get(key)!); 692 } 693 for (const key of arrayFrom(nodeCounts.keys())) { 694 reportCountStatistic("Nodes of " + key, nodeCounts.get(key)!); 695 } 696 } 697 else { 698 reportCountStatistic("Lines", reduceLeftIterator(lineCounts.values(), (sum, count) => sum + count, 0)); 699 reportCountStatistic("Nodes", reduceLeftIterator(nodeCounts.values(), (sum, count) => sum + count, 0)); 700 } 701 702 reportCountStatistic("Identifiers", program.getIdentifierCount()); 703 reportCountStatistic("Symbols", program.getSymbolCount()); 704 reportCountStatistic("Types", program.getTypeCount()); 705 reportCountStatistic("Instantiations", program.getInstantiationCount()); 706 707 if (memoryUsed >= 0) { 708 reportStatisticalValue("Memory used", Math.round(memoryUsed / 1000) + "K"); 709 } 710 711 const isPerformanceEnabled = performance.isEnabled(); 712 const programTime = isPerformanceEnabled ? performance.getDuration("Program") : 0; 713 const bindTime = isPerformanceEnabled ? performance.getDuration("Bind") : 0; 714 const checkTime = isPerformanceEnabled ? performance.getDuration("Check") : 0; 715 const emitTime = isPerformanceEnabled ? performance.getDuration("Emit") : 0; 716 if (compilerOptions.extendedDiagnostics) { 717 const caches = program.getRelationCacheSizes(); 718 reportCountStatistic("Assignability cache size", caches.assignable); 719 reportCountStatistic("Identity cache size", caches.identity); 720 reportCountStatistic("Subtype cache size", caches.subtype); 721 reportCountStatistic("Strict subtype cache size", caches.strictSubtype); 722 if (isPerformanceEnabled) { 723 performance.forEachMeasure((name, duration) => reportTimeStatistic(`${name} time`, duration)); 724 } 725 } 726 else if (isPerformanceEnabled) { 727 // Individual component times. 728 // Note: To match the behavior of previous versions of the compiler, the reported parse time includes 729 // I/O read time and processing time for triple-slash references and module imports, and the reported 730 // emit time includes I/O write time. We preserve this behavior so we can accurately compare times. 731 reportTimeStatistic("I/O read", performance.getDuration("I/O Read")); 732 reportTimeStatistic("I/O write", performance.getDuration("I/O Write")); 733 reportTimeStatistic("Parse time", programTime); 734 reportTimeStatistic("Bind time", bindTime); 735 reportTimeStatistic("Check time", checkTime); 736 reportTimeStatistic("Emit time", emitTime); 737 } 738 if (isPerformanceEnabled) { 739 reportTimeStatistic("Total time", programTime + bindTime + checkTime + emitTime); 740 } 741 reportStatistics(); 742 if (!isPerformanceEnabled) { 743 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"); 744 } 745 else { 746 performance.disable(); 747 } 748 } 749 750 function reportStatistics() { 751 let nameSize = 0; 752 let valueSize = 0; 753 for (const { name, value } of statistics) { 754 if (name.length > nameSize) { 755 nameSize = name.length; 756 } 757 758 if (value.length > valueSize) { 759 valueSize = value.length; 760 } 761 } 762 763 for (const { name, value } of statistics) { 764 sys.write(padRight(name + ":", nameSize + 2) + padLeft(value.toString(), valueSize) + sys.newLine); 765 } 766 } 767 768 function reportStatisticalValue(name: string, value: string) { 769 statistics.push({ name, value }); 770 } 771 772 function reportCountStatistic(name: string, count: number) { 773 reportStatisticalValue(name, "" + count); 774 } 775 776 function reportTimeStatistic(name: string, time: number) { 777 reportStatisticalValue(name, (time / 1000).toFixed(2) + "s"); 778 } 779 } 780 781 function writeConfigFile( 782 sys: System, 783 reportDiagnostic: DiagnosticReporter, 784 options: CompilerOptions, 785 fileNames: string[] 786 ) { 787 const currentDirectory = sys.getCurrentDirectory(); 788 const file = normalizePath(combinePaths(currentDirectory, "tsconfig.json")); 789 if (sys.fileExists(file)) { 790 reportDiagnostic(createCompilerDiagnostic(Diagnostics.A_tsconfig_json_file_is_already_defined_at_Colon_0, file)); 791 } 792 else { 793 sys.writeFile(file, generateTSConfig(options, fileNames, sys.newLine)); 794 reportDiagnostic(createCompilerDiagnostic(Diagnostics.Successfully_created_a_tsconfig_json_file)); 795 } 796 797 return; 798 } 799} 800