diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 055bccbb2ad..05113f812db 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -62,7 +62,8 @@ namespace ts { /* @internal */ export const libMap = createMapFromEntries(libEntries); - const commonOptionsWithBuild: CommandLineOption[] = [ + /* @internal */ + export const commonOptionsWithBuild: CommandLineOption[] = [ { name: "help", shortName: "h", @@ -83,6 +84,18 @@ namespace ts { category: Diagnostics.Command_line_Options, description: Diagnostics.Whether_to_keep_outdated_console_output_in_watch_mode_instead_of_clearing_the_screen, }, + { + name: "listFiles", + type: "boolean", + category: Diagnostics.Advanced_Options, + description: Diagnostics.Print_names_of_files_part_of_the_compilation + }, + { + name: "listEmittedFiles", + type: "boolean", + category: Diagnostics.Advanced_Options, + description: Diagnostics.Print_names_of_generated_files_part_of_the_compilation + }, { name: "watch", shortName: "w", @@ -561,18 +574,6 @@ namespace ts { category: Diagnostics.Advanced_Options, description: Diagnostics.Include_modules_imported_with_json_extension }, - { - name: "listFiles", - type: "boolean", - category: Diagnostics.Advanced_Options, - description: Diagnostics.Print_names_of_files_part_of_the_compilation - }, - { - name: "listEmittedFiles", - type: "boolean", - category: Diagnostics.Advanced_Options, - description: Diagnostics.Print_names_of_generated_files_part_of_the_compilation - }, { name: "out", @@ -903,17 +904,27 @@ namespace ts { } } - export function parseCommandLine(commandLine: ReadonlyArray, readFile?: (path: string) => string | undefined): ParsedCommandLine { - const options: CompilerOptions = {}; + /* @internal */ + export interface OptionsBase { + [option: string]: CompilerOptionsValue | undefined; + } + + /** Tuple with error messages for 'unknown compiler option', 'option requires type' */ + type ParseCommandLineWorkerDiagnostics = [DiagnosticMessage, DiagnosticMessage]; + + function parseCommandLineWorker( + getOptionNameMap: () => OptionNameMap, + [unknownOptionDiagnostic, optionTypeMismatchDiagnostic]: ParseCommandLineWorkerDiagnostics, + commandLine: ReadonlyArray, + readFile?: (path: string) => string | undefined) { + const options = {} as OptionsBase; const fileNames: string[] = []; - const projectReferences: ProjectReference[] | undefined = undefined; const errors: Diagnostic[] = []; parseStrings(commandLine); return { options, fileNames, - projectReferences, errors }; @@ -926,7 +937,7 @@ namespace ts { parseResponseFile(s.slice(1)); } else if (s.charCodeAt(0) === CharacterCodes.minus) { - const opt = getOptionFromName(s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true); + const opt = getOptionDeclarationFromName(getOptionNameMap, s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true); if (opt) { if (opt.isTSConfigOnly) { errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file, opt.name)); @@ -934,7 +945,7 @@ namespace ts { else { // Check to see if no argument was provided (e.g. "--locale" is the last command-line argument). if (!args[i] && opt.type !== "boolean") { - errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_expects_an_argument, opt.name)); + errors.push(createCompilerDiagnostic(optionTypeMismatchDiagnostic, opt.name)); } switch (opt.type) { @@ -971,7 +982,7 @@ namespace ts { } } else { - errors.push(createCompilerDiagnostic(Diagnostics.Unknown_compiler_option_0, s)); + errors.push(createCompilerDiagnostic(unknownOptionDiagnostic, s)); } } else { @@ -1014,13 +1025,19 @@ namespace ts { } } + export function parseCommandLine(commandLine: ReadonlyArray, readFile?: (path: string) => string | undefined): ParsedCommandLine { + return parseCommandLineWorker(getOptionNameMap, [ + Diagnostics.Unknown_compiler_option_0, + Diagnostics.Compiler_option_0_expects_an_argument + ], commandLine, readFile); + } + /** @internal */ export function getOptionFromName(optionName: string, allowShort?: boolean): CommandLineOption | undefined { return getOptionDeclarationFromName(getOptionNameMap, optionName, allowShort); } - /*@internal*/ - export function getOptionDeclarationFromName(getOptionNameMap: () => OptionNameMap, optionName: string, allowShort = false): CommandLineOption | undefined { + function getOptionDeclarationFromName(getOptionNameMap: () => OptionNameMap, optionName: string, allowShort = false): CommandLineOption | undefined { optionName = optionName.toLowerCase(); const { optionNameMap, shortOptionNames } = getOptionNameMap(); // Try to translate short option names to their full equivalents. @@ -1044,25 +1061,11 @@ namespace ts { export function parseBuildCommand(args: string[]): ParsedBuildCommand { let buildOptionNameMap: OptionNameMap | undefined; const returnBuildOptionNameMap = () => (buildOptionNameMap || (buildOptionNameMap = createOptionNameMap(buildOpts))); - - const buildOptions: BuildOptions = {}; - const projects: string[] = []; - let errors: Diagnostic[] | undefined; - for (const arg of args) { - if (arg.charCodeAt(0) === CharacterCodes.minus) { - const opt = getOptionDeclarationFromName(returnBuildOptionNameMap, arg.slice(arg.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true); - if (opt) { - buildOptions[opt.name as keyof BuildOptions] = true; - } - else { - (errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Unknown_build_option_0, arg)); - } - } - else { - // Not a flag, parse as filename - projects.push(arg); - } - } + const { options, fileNames: projects, errors } = parseCommandLineWorker(returnBuildOptionNameMap, [ + Diagnostics.Unknown_build_option_0, + Diagnostics.Build_option_0_requires_a_value_of_type_1 + ], args); + const buildOptions = options as BuildOptions; if (projects.length === 0) { // tsc -b invoked with no extra arguments; act as if invoked with "tsc -b ." @@ -1071,19 +1074,19 @@ namespace ts { // Nonsensical combinations if (buildOptions.clean && buildOptions.force) { - (errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force")); + errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force")); } if (buildOptions.clean && buildOptions.verbose) { - (errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose")); + errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose")); } if (buildOptions.clean && buildOptions.watch) { - (errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch")); + errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch")); } if (buildOptions.watch && buildOptions.dry) { - (errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry")); + errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry")); } - return { buildOptions, projects, errors: errors || emptyArray }; + return { buildOptions, projects, errors }; } function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 778e60919f0..e88130c7876 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2948,7 +2948,10 @@ "category": "Error", "code": 5072 }, - + "Build option '{0}' requires a value of type {1}.": { + "category": "Error", + "code": 5073 + }, "Generates a sourcemap for each corresponding '.d.ts' file.": { "category": "Message", @@ -4640,7 +4643,7 @@ "category": "Message", "code": 95062 }, - + "Add missing enum member '{0}'": { "category": "Message", "code": 95063 @@ -4649,12 +4652,12 @@ "category": "Message", "code": 95064 }, - "Convert to async function":{ + "Convert to async function": { "category": "Message", - "code": 95065 + "code": 95065 }, "Convert all to async functions": { - "category": "Message", - "code": 95066 + "category": "Message", + "code": 95066 } } diff --git a/src/compiler/tsbuild.ts b/src/compiler/tsbuild.ts index 269e8b80185..069aedff751 100644 --- a/src/compiler/tsbuild.ts +++ b/src/compiler/tsbuild.ts @@ -17,14 +17,18 @@ namespace ts { referencingProjectsMap: ConfigFileMap>; } - export interface BuildOptions { + export interface BuildOptions extends OptionsBase { dry?: boolean; force?: boolean; verbose?: boolean; + /*@internal*/ clean?: boolean; /*@internal*/ watch?: boolean; /*@internal*/ help?: boolean; + preserveWatchOutput?: boolean; + listEmittedFiles?: boolean; + listFiles?: boolean; } enum BuildResultFlags { @@ -44,8 +48,9 @@ namespace ts { SyntaxErrors = 1 << 3, TypeErrors = 1 << 4, DeclarationEmitErrors = 1 << 5, + EmitErrors = 1 << 6, - AnyErrors = ConfigFileErrors | SyntaxErrors | TypeErrors | DeclarationEmitErrors + AnyErrors = ConfigFileErrors | SyntaxErrors | TypeErrors | DeclarationEmitErrors | EmitErrors } export enum UpToDateStatusType { @@ -370,6 +375,14 @@ namespace ts { return host; } + function getCompilerOptionsOfBuildOptions(buildOptions: BuildOptions): CompilerOptions { + const result = {} as CompilerOptions; + commonOptionsWithBuild.forEach(option => { + result[option.name] = buildOptions[option.name]; + }); + return result; + } + /** * A SolutionBuilder has an immutable set of rootNames that are the "entry point" projects, but * can dynamically add/remove other projects based on changes on the rootNames' references @@ -384,6 +397,7 @@ namespace ts { // State of the solution let options = defaultOptions; + let baseCompilerOptions = getCompilerOptionsOfBuildOptions(options); type ConfigFileCacheEntry = ParsedCommandLine | Diagnostic; const configFileCache = createFileMap(toPath); /** Map from output file name to its pre-build timestamp */ @@ -392,6 +406,7 @@ namespace ts { const projectStatus = createFileMap(toPath); const missingRoots = createMap(); let globalDependencyGraph: DependencyGraph | undefined; + const writeFileName = (s: string) => host.trace && host.trace(s); // Watch state const diagnostics = createFileMap>(toPath); @@ -430,6 +445,7 @@ namespace ts { function resetBuildContext(opts = defaultOptions) { options = opts; + baseCompilerOptions = getCompilerOptionsOfBuildOptions(options); configFileCache.clear(); unchangedOutputs.clear(); projectStatus.clear(); @@ -463,7 +479,7 @@ namespace ts { let diagnostic: Diagnostic | undefined; parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = d => diagnostic = d; - const parsed = getParsedCommandLineOfConfigFile(configFilePath, {}, parseConfigFileHost); + const parsed = getParsedCommandLineOfConfigFile(configFilePath, baseCompilerOptions, parseConfigFileHost); parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = noop; configFileCache.setValue(configFilePath, parsed || diagnostic!); return parsed; @@ -475,7 +491,7 @@ namespace ts { function reportWatchStatus(message: DiagnosticMessage, ...args: (string | number | undefined)[]) { if (hostWithWatch.onWatchStatusChange) { - hostWithWatch.onWatchStatusChange(createCompilerDiagnostic(message, ...args), host.getNewLine(), { preserveWatchOutput: options.preserveWatchOutput }); + hostWithWatch.onWatchStatusChange(createCompilerDiagnostic(message, ...args), host.getNewLine(), baseCompilerOptions); } } @@ -1004,35 +1020,28 @@ namespace ts { ...program.getConfigFileParsingDiagnostics(), ...program.getSyntacticDiagnostics()]; if (syntaxDiagnostics.length) { - resultFlags |= BuildResultFlags.SyntaxErrors; - reportAndStoreErrors(proj, syntaxDiagnostics); - projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: "Syntactic errors" }); - return resultFlags; + return buildErrors(syntaxDiagnostics, BuildResultFlags.SyntaxErrors, "Syntactic"); } // Don't emit .d.ts if there are decl file errors if (getEmitDeclarations(program.getCompilerOptions())) { const declDiagnostics = program.getDeclarationDiagnostics(); if (declDiagnostics.length) { - resultFlags |= BuildResultFlags.DeclarationEmitErrors; - reportAndStoreErrors(proj, declDiagnostics); - projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: "Declaration file errors" }); - return resultFlags; + return buildErrors(declDiagnostics, BuildResultFlags.DeclarationEmitErrors, "Declaration file"); } } // Same as above but now for semantic diagnostics const semanticDiagnostics = program.getSemanticDiagnostics(); if (semanticDiagnostics.length) { - resultFlags |= BuildResultFlags.TypeErrors; - reportAndStoreErrors(proj, semanticDiagnostics); - projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: "Semantic errors" }); - return resultFlags; + return buildErrors(semanticDiagnostics, BuildResultFlags.TypeErrors, "Semantic"); } let newestDeclarationFileContentChangedTime = minimumDate; let anyDtsChanged = false; - program.emit(/*targetSourceFile*/ undefined, (fileName, content, writeBom, onError) => { + let emitDiagnostics: Diagnostic[] | undefined; + const reportEmitDiagnostic = (d: Diagnostic) => (emitDiagnostics || (emitDiagnostics = [])).push(d); + emitFilesAndReportErrors(program, reportEmitDiagnostic, writeFileName, /*reportSummary*/ undefined, (fileName, content, writeBom, onError) => { let priorChangeTime: Date | undefined; if (!anyDtsChanged && isDeclarationFile(fileName)) { // Check for unchanged .d.ts files @@ -1052,12 +1061,23 @@ namespace ts { } }); + if (emitDiagnostics) { + return buildErrors(emitDiagnostics, BuildResultFlags.EmitErrors, "Emit"); + } + const status: UpToDateStatus = { type: UpToDateStatusType.UpToDate, newestDeclarationFileContentChangedTime: anyDtsChanged ? maximumDate : newestDeclarationFileContentChangedTime }; projectStatus.setValue(proj, status); return resultFlags; + + function buildErrors(diagnostics: ReadonlyArray, errorFlags: BuildResultFlags, errorType: string) { + resultFlags |= errorFlags; + reportAndStoreErrors(proj, diagnostics); + projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: `${errorType} errors` }); + return resultFlags; + } } function updateOutputTimestamps(proj: ParsedCommandLine) { diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index c091ad5c30c..f442a1a88e8 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -101,7 +101,7 @@ namespace ts { getGlobalDiagnostics(): ReadonlyArray; getSemanticDiagnostics(): ReadonlyArray; getConfigFileParsingDiagnostics(): ReadonlyArray; - emit(): EmitResult; + emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback): EmitResult; } export type ReportEmitErrorSummary = (errorCount: number) => void; @@ -109,7 +109,7 @@ namespace ts { /** * Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options */ - export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void, reportSummary?: ReportEmitErrorSummary) { + export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void, reportSummary?: ReportEmitErrorSummary, writeFile?: WriteFileCallback) { // First get and report any syntactic errors. const diagnostics = program.getConfigFileParsingDiagnostics().slice(); const configFileParsingDiagnosticsLength = diagnostics.length; @@ -128,7 +128,7 @@ namespace ts { } // Emit and report any errors we ran into. - const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit(); + const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit(/*targetSourceFile*/ undefined, writeFile); addRange(diagnostics, emitDiagnostics); if (reportSemanticDiagnostics) { diff --git a/src/testRunner/unittests/tsbuild.ts b/src/testRunner/unittests/tsbuild.ts index 6ddd6d069f7..f54e3c93215 100644 --- a/src/testRunner/unittests/tsbuild.ts +++ b/src/testRunner/unittests/tsbuild.ts @@ -264,6 +264,63 @@ export class cNew {}`); verifyProjectWithResolveJsonModule("/src/tests/tsconfig_withIncludeAndFiles.json"); }); }); + + describe("tsbuild - lists files", () => { + it("listFiles", () => { + const fs = projFs.shadow(); + const host = new fakes.SolutionBuilderHost(fs); + const builder = createSolutionBuilder(host, ["/src/tests"], { listFiles: true }); + builder.buildAllProjects(); + assert.deepEqual(host.traces, [ + ...getLibs(), + "/src/core/anotherModule.ts", + "/src/core/index.ts", + "/src/core/some_decl.d.ts", + ...getLibs(), + ...getCoreOutputs(), + "/src/logic/index.ts", + ...getLibs(), + ...getCoreOutputs(), + "/src/logic/index.d.ts", + "/src/tests/index.ts" + ]); + + function getLibs() { + return [ + "/lib/lib.d.ts", + "/lib/lib.es5.d.ts", + "/lib/lib.dom.d.ts", + "/lib/lib.webworker.importscripts.d.ts", + "/lib/lib.scripthost.d.ts" + ]; + } + + function getCoreOutputs() { + return [ + "/src/core/index.d.ts", + "/src/core/anotherModule.d.ts" + ]; + } + }); + + it("listEmittedFiles", () => { + const fs = projFs.shadow(); + const host = new fakes.SolutionBuilderHost(fs); + const builder = createSolutionBuilder(host, ["/src/tests"], { listEmittedFiles: true }); + builder.buildAllProjects(); + assert.deepEqual(host.traces, [ + "TSFILE: /src/core/anotherModule.js", + "TSFILE: /src/core/anotherModule.d.ts", + "TSFILE: /src/core/index.js", + "TSFILE: /src/core/index.d.ts", + "TSFILE: /src/logic/index.js", + "TSFILE: /src/logic/index.js.map", + "TSFILE: /src/logic/index.d.ts", + "TSFILE: /src/tests/index.js", + "TSFILE: /src/tests/index.d.ts", + ]); + }); + }); } export namespace OutFile { diff --git a/src/testRunner/unittests/tsbuildWatchMode.ts b/src/testRunner/unittests/tsbuildWatchMode.ts index d9dcda94bff..563200b1cf5 100644 --- a/src/testRunner/unittests/tsbuildWatchMode.ts +++ b/src/testRunner/unittests/tsbuildWatchMode.ts @@ -2,7 +2,7 @@ namespace ts.tscWatch { export import libFile = TestFSWithWatch.libFile; function createSolutionBuilder(system: WatchedSystem, rootNames: ReadonlyArray, defaultOptions?: BuildOptions) { const host = createSolutionBuilderWithWatchHost(system); - return ts.createSolutionBuilder(host, rootNames, defaultOptions || { dry: false, force: false, verbose: false, watch: true }); + return ts.createSolutionBuilder(host, rootNames, defaultOptions || { watch: true }); } function createSolutionBuilderWithWatch(host: WatchedSystem, rootNames: ReadonlyArray, defaultOptions?: BuildOptions) { @@ -95,11 +95,11 @@ namespace ts.tscWatch { const allFiles: ReadonlyArray = [libFile, ...core, ...logic, ...tests, ...ui]; const testProjectExpectedWatchedFiles = [core[0], core[1], core[2], ...logic, ...tests].map(f => f.path); - function createSolutionInWatchMode(allFiles: ReadonlyArray) { + function createSolutionInWatchMode(allFiles: ReadonlyArray, defaultOptions?: BuildOptions, disableConsoleClears?: boolean) { const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation }); - createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`]); + createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`], defaultOptions); verifyWatches(host); - checkOutputErrorsInitial(host, emptyArray); + checkOutputErrorsInitial(host, emptyArray, disableConsoleClears); const outputFileStamps = getOutputFileStamps(host); for (const stamp of outputFileStamps) { assert.isDefined(stamp[1], `${stamp[0]} expected to be present`); @@ -351,32 +351,42 @@ function myFunc() { return 100; }`); } }); - it("reports errors in all projects on incremental compile", () => { - const host = createSolutionInWatchMode(allFiles); - const outputFileStamps = getOutputFileStamps(host); + describe("reports errors in all projects on incremental compile", () => { + function verifyIncrementalErrors(defaultBuildOptions?: BuildOptions, disabledConsoleClear?: boolean) { + const host = createSolutionInWatchMode(allFiles, defaultBuildOptions, disabledConsoleClear); + const outputFileStamps = getOutputFileStamps(host); - host.writeFile(logic[1].path, `${logic[1].content} + host.writeFile(logic[1].path, `${logic[1].content} let y: string = 10;`); - host.checkTimeoutQueueLengthAndRun(1); // Builds logic - const changedLogic = getOutputFileStamps(host); - verifyChangedFiles(changedLogic, outputFileStamps, emptyArray); - host.checkTimeoutQueueLength(0); - checkOutputErrorsIncremental(host, [ - `sample1/logic/index.ts(8,5): error TS2322: Type '10' is not assignable to type 'string'.\n` - ]); + host.checkTimeoutQueueLengthAndRun(1); // Builds logic + const changedLogic = getOutputFileStamps(host); + verifyChangedFiles(changedLogic, outputFileStamps, emptyArray); + host.checkTimeoutQueueLength(0); + checkOutputErrorsIncremental(host, [ + `sample1/logic/index.ts(8,5): error TS2322: Type '10' is not assignable to type 'string'.\n` + ], disabledConsoleClear); - host.writeFile(core[1].path, `${core[1].content} + host.writeFile(core[1].path, `${core[1].content} let x: string = 10;`); - host.checkTimeoutQueueLengthAndRun(1); // Builds core - const changedCore = getOutputFileStamps(host); - verifyChangedFiles(changedCore, changedLogic, emptyArray); - host.checkTimeoutQueueLength(0); - checkOutputErrorsIncremental(host, [ - `sample1/core/index.ts(5,5): error TS2322: Type '10' is not assignable to type 'string'.\n`, - `sample1/logic/index.ts(8,5): error TS2322: Type '10' is not assignable to type 'string'.\n` - ]); + host.checkTimeoutQueueLengthAndRun(1); // Builds core + const changedCore = getOutputFileStamps(host); + verifyChangedFiles(changedCore, changedLogic, emptyArray); + host.checkTimeoutQueueLength(0); + checkOutputErrorsIncremental(host, [ + `sample1/core/index.ts(5,5): error TS2322: Type '10' is not assignable to type 'string'.\n`, + `sample1/logic/index.ts(8,5): error TS2322: Type '10' is not assignable to type 'string'.\n` + ], disabledConsoleClear); + } + + it("when preserveWatchOutput is not used", () => { + verifyIncrementalErrors(); + }); + + it("when preserveWatchOutput is passed on command line", () => { + verifyIncrementalErrors({ preserveWatchOutput: true, watch: true }, /*disabledConsoleClear*/ true); + }); }); // TODO: write tests reporting errors but that will have more involved work since file }); diff --git a/src/tsc/tsc.ts b/src/tsc/tsc.ts index 523fcefd88c..29cac24fdd0 100644 --- a/src/tsc/tsc.ts +++ b/src/tsc/tsc.ts @@ -53,14 +53,10 @@ namespace ts { } export function executeCommandLine(args: string[]): void { - if (args.length > 0 && ((args[0].toLowerCase() === "--build") || (args[0].toLowerCase() === "-b"))) { - const result = performBuild(args.slice(1)); - // undefined = in watch mode, do not exit - if (result !== undefined) { - return sys.exit(result); - } - else { - return; + if (args.length > 0 && args[0].charCodeAt(0) === CharacterCodes.minus) { + const firstOption = args[0].slice(args[0].charCodeAt(1) === CharacterCodes.minus ? 2 : 1).toLowerCase(); + if (firstOption === "build" || firstOption === "b") { + return performBuild(args.slice(1)); } } @@ -164,17 +160,17 @@ namespace ts { } } - function performBuild(args: string[]): number | undefined { + function performBuild(args: string[]) { const { buildOptions, projects, errors } = parseBuildCommand(args); if (errors.length > 0) { errors.forEach(reportDiagnostic); - return ExitStatus.DiagnosticsPresent_OutputsSkipped; + return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } if (buildOptions.help) { printVersion(); printHelp(buildOpts, "--build "); - return ExitStatus.Success; + return sys.exit(ExitStatus.Success); } // Update to pretty if host supports it @@ -182,12 +178,12 @@ namespace ts { if (projects.length === 0) { printVersion(); printHelp(buildOpts, "--build "); - return ExitStatus.Success; + return sys.exit(ExitStatus.Success); } if (!sys.getModifiedTime || !sys.setModifiedTime || (buildOptions.clean && !sys.deleteFile)) { reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build")); - return ExitStatus.DiagnosticsPresent_OutputsSkipped; + return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } if (buildOptions.watch) { reportWatchModeWithoutSysSupport(); @@ -196,16 +192,15 @@ namespace ts { // TODO: change this to host if watch => watchHost otherwiue without wathc const builder = createSolutionBuilder(createSolutionBuilderWithWatchHost(sys, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty()), createWatchStatusReporter()), projects, buildOptions); if (buildOptions.clean) { - return builder.cleanAllProjects(); + return sys.exit(builder.cleanAllProjects()); } if (buildOptions.watch) { builder.buildAllProjects(); - builder.startWatching(); - return undefined; + return builder.startWatching(); } - return builder.buildAllProjects(); + return sys.exit(builder.buildAllProjects()); } function performCompilation(rootNames: string[], projectReferences: ReadonlyArray | undefined, options: CompilerOptions, configFileParsingDiagnostics?: ReadonlyArray) {