diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 00920325721..f1dd4093956 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -815,10 +815,11 @@ namespace ts { } function getOptionNameMap(): OptionNameMap { - if (optionNameMapCache) { - return optionNameMapCache; - } + return optionNameMapCache || (optionNameMapCache = createOptionNameMap(optionDeclarations)); + } + /*@internal*/ + export function createOptionNameMap(optionDeclarations: ReadonlyArray): OptionNameMap { const optionNameMap = createMap(); const shortOptionNames = createMap(); forEach(optionDeclarations, option => { @@ -828,8 +829,7 @@ namespace ts { } }); - optionNameMapCache = { optionNameMap, shortOptionNames }; - return optionNameMapCache; + return { optionNameMap, shortOptionNames }; } /* @internal */ @@ -979,7 +979,12 @@ namespace ts { } /** @internal */ - export function getOptionFromName(optionName: string, allowShort = false): CommandLineOption | undefined { + 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 { optionName = optionName.toLowerCase(); const { optionNameMap, shortOptionNames } = getOptionNameMap(); // Try to translate short option names to their full equivalents. diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 6000c48de4d..6c517709f4f 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2900,6 +2900,11 @@ "category": "Error", "code": 5071 }, + "Unknown build option '{0}'.": { + "category": "Error", + "code": 5072 + }, + "Generates a sourcemap for each corresponding '.d.ts' file.": { "category": "Message", diff --git a/src/compiler/tsbuild.ts b/src/compiler/tsbuild.ts index 87dcb0e2b57..54737d470e7 100644 --- a/src/compiler/tsbuild.ts +++ b/src/compiler/tsbuild.ts @@ -47,10 +47,13 @@ namespace ts { dependencyMap: Mapper; } - interface BuildOptions { - dry: boolean; - force: boolean; - verbose: boolean; + export interface BuildOptions { + dry?: boolean; + force?: boolean; + verbose?: boolean; + /*@internal*/ clean?: boolean; + /*@internal*/ watch?: boolean; + /*@internal*/ help?: boolean; } enum BuildResultFlags { diff --git a/src/tsc/tsc.ts b/src/tsc/tsc.ts index f6f0db6e9aa..a863c684931 100644 --- a/src/tsc/tsc.ts +++ b/src/tsc/tsc.ts @@ -62,7 +62,7 @@ namespace ts { message: report, errorDiagnostic: d => reportDiag(d) }; - const result = performBuild(args.slice(1), createCompilerHost({}), buildHost, sys); + const result = performBuild(args.slice(1), createCompilerHost({}), buildHost); // undefined = in watch mode, do not exit if (result !== undefined) { return sys.exit(result); @@ -172,96 +172,94 @@ namespace ts { } } - const buildOpts: CommandLineOption[] = [ - { - name: "verbose", - shortName: "v", - category: Diagnostics.Command_line_Options, - description: Diagnostics.Enable_verbose_logging, - type: "boolean" - }, - { - name: "dry", - shortName: "d", - category: Diagnostics.Command_line_Options, - description: Diagnostics.Show_what_would_be_built_or_deleted_if_specified_with_clean, - type: "boolean" - }, - { - name: "force", - shortName: "f", - category: Diagnostics.Command_line_Options, - description: Diagnostics.Build_all_projects_including_those_that_appear_to_be_up_to_date, - type: "boolean" - }, - { - name: "clean", - category: Diagnostics.Command_line_Options, - description: Diagnostics.Delete_the_outputs_of_all_projects, - type: "boolean" - }, - { - name: "watch", - category: Diagnostics.Command_line_Options, - description: Diagnostics.Watch_input_files, - type: "boolean" - } - ]; - - function performBuild(args: string[], compilerHost: CompilerHost, buildHost: BuildHost, system?: System): number | undefined { - let verbose = false; - let dry = false; - let force = false; - let clean = false; - let watch = false; + function performBuild(args: string[], compilerHost: CompilerHost, buildHost: BuildHost): number | undefined { + const buildOpts: CommandLineOption[] = [ + { + name: "help", + shortName: "h", + type: "boolean", + showInSimplifiedHelpView: true, + category: Diagnostics.Command_line_Options, + description: Diagnostics.Print_this_message, + }, + { + name: "help", + shortName: "?", + type: "boolean" + }, + { + name: "verbose", + shortName: "v", + category: Diagnostics.Command_line_Options, + description: Diagnostics.Enable_verbose_logging, + type: "boolean" + }, + { + name: "dry", + shortName: "d", + category: Diagnostics.Command_line_Options, + description: Diagnostics.Show_what_would_be_built_or_deleted_if_specified_with_clean, + type: "boolean" + }, + { + name: "force", + shortName: "f", + category: Diagnostics.Command_line_Options, + description: Diagnostics.Build_all_projects_including_those_that_appear_to_be_up_to_date, + type: "boolean" + }, + { + name: "clean", + category: Diagnostics.Command_line_Options, + description: Diagnostics.Delete_the_outputs_of_all_projects, + type: "boolean" + }, + { + name: "watch", + category: Diagnostics.Command_line_Options, + description: Diagnostics.Watch_input_files, + type: "boolean" + } + ]; + let buildOptionNameMap: OptionNameMap | undefined; + const returnBuildOptionNameMap = () => (buildOptionNameMap || (buildOptionNameMap = createOptionNameMap(buildOpts))); + const buildOptions: BuildOptions = {}; const projects: string[] = []; for (const arg of args) { - switch (arg.toLowerCase()) { - case "-v": - case "--verbose": - verbose = true; - continue; - case "-d": - case "--dry": - dry = true; - continue; - case "-f": - case "--force": - force = true; - continue; - case "--clean": - clean = true; - continue; - case "--watch": - case "-w": - watch = true; - continue; - - case "--?": - case "-?": - case "--help": - printHelp(buildOpts, "--build "); - return ExitStatus.Success; + 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 { + reportDiagnostic(createCompilerDiagnostic(Diagnostics.Unknown_build_option_0, arg)); + } } - // Not a flag, parse as filename - addProject(arg); + else { + // Not a flag, parse as filename + addProject(arg); + } + } + + if (buildOptions.help) { + printHelp(buildOpts, "--build "); return ExitStatus.Success; } // Nonsensical combinations - if (clean && force) { + if (buildOptions.clean && buildOptions.force) { buildHost.error(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force"); return ExitStatus.DiagnosticsPresent_OutputsSkipped; } - if (clean && verbose) { + if (buildOptions.clean && buildOptions.verbose) { buildHost.error(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose"); return ExitStatus.DiagnosticsPresent_OutputsSkipped; } - if (clean && watch) { + if (buildOptions.clean && buildOptions.watch) { buildHost.error(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch"); return ExitStatus.DiagnosticsPresent_OutputsSkipped; } - if (watch && dry) { + if (buildOptions.watch && buildOptions.dry) { buildHost.error(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry"); return ExitStatus.DiagnosticsPresent_OutputsSkipped; } @@ -271,12 +269,12 @@ namespace ts { addProject("."); } - const builder = createSolutionBuilder(compilerHost, buildHost, projects, { dry, force, verbose }, system); - if (clean) { + const builder = createSolutionBuilder(compilerHost, buildHost, projects, buildOptions); + if (buildOptions.clean) { return builder.cleanAllProjects(); } - if (watch) { + if (buildOptions.watch) { builder.buildAllProjects(); builder.startWatching(); return undefined;