Skip to content

Commit

Permalink
Updates to --build parsing on command line (#59874)
Browse files Browse the repository at this point in the history
  • Loading branch information
sheetalkamat committed Sep 6, 2024
1 parent ea69909 commit 31afb98
Show file tree
Hide file tree
Showing 18 changed files with 1,112 additions and 50 deletions.
40 changes: 25 additions & 15 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -639,15 +639,6 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
paramType: Diagnostics.FILE_OR_DIRECTORY,
description: Diagnostics.Compile_the_project_given_the_path_to_its_configuration_file_or_to_a_folder_with_a_tsconfig_json,
},
{
name: "build",
type: "boolean",
shortName: "b",
showInSimplifiedHelpView: true,
category: Diagnostics.Command_line_Options,
description: Diagnostics.Build_one_or_more_projects_and_their_dependencies_if_out_of_date,
defaultValueDescription: false,
},
{
name: "showConfig",
type: "boolean",
Expand Down Expand Up @@ -1662,9 +1653,21 @@ function isCommandLineOptionOfCustomType(option: CommandLineOption): option is C
return !isString(option.type);
}

/** @internal */
export const tscBuildOption: CommandLineOption = {
name: "build",
type: "boolean",
shortName: "b",
showInSimplifiedHelpView: true,
category: Diagnostics.Command_line_Options,
description: Diagnostics.Build_one_or_more_projects_and_their_dependencies_if_out_of_date,
defaultValueDescription: false,
};

// Build related options
/** @internal */
export const optionsForBuild: CommandLineOption[] = [
tscBuildOption,
{
name: "verbose",
shortName: "v",
Expand Down Expand Up @@ -1849,8 +1852,16 @@ function createUnknownOptionError(
node?: PropertyName,
sourceFile?: TsConfigSourceFile,
) {
if (diagnostics.alternateMode?.getOptionsNameMap().optionsNameMap.has(unknownOption.toLowerCase())) {
return createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, node, diagnostics.alternateMode.diagnostic, unknownOption);
const otherOption = diagnostics.alternateMode?.getOptionsNameMap().optionsNameMap.get(unknownOption.toLowerCase());
if (otherOption) {
return createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(
sourceFile,
node,
otherOption !== tscBuildOption ?
diagnostics.alternateMode!.diagnostic :
Diagnostics.Option_build_must_be_the_first_command_line_argument,
unknownOption,
);
}

const possibleOption = getSpellingSuggestion(unknownOption, diagnostics.optionDeclarations, getOptionName);
Expand Down Expand Up @@ -2051,7 +2062,7 @@ function getOptionDeclarationFromName(getOptionNameMap: () => OptionsNameMap, op
return optionsNameMap.get(optionName);
}

/** @internal */
/** Parsed command line for build */
export interface ParsedBuildCommand {
buildOptions: BuildOptions;
watchOptions: WatchOptions | undefined;
Expand All @@ -2078,11 +2089,10 @@ const buildOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnostics = {
optionTypeMismatchDiagnostic: Diagnostics.Build_option_0_requires_a_value_of_type_1,
};

/** @internal */
export function parseBuildCommand(args: readonly string[]): ParsedBuildCommand {
export function parseBuildCommand(commandLine: readonly string[]): ParsedBuildCommand {
const { options, watchOptions, fileNames: projects, errors } = parseCommandLineWorker(
buildOptionsDidYouMeanDiagnostics,
args,
commandLine,
);
const buildOptions = options as BuildOptions;

Expand Down
24 changes: 10 additions & 14 deletions src/compiler/executeCommandLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ import {
toPath,
toSorted,
tracing,
tscBuildOption,
validateLocaleAndSetLanguage,
version,
WatchCompilerHost,
Expand Down Expand Up @@ -170,8 +171,8 @@ function shouldBePretty(sys: System, options: CompilerOptions | BuildOptions) {
function getOptionsForHelp(commandLine: ParsedCommandLine) {
// Sort our options by their names, (e.g. "--noImplicitAny" comes before "--watch")
return !!commandLine.options.all ?
toSorted(optionDeclarations, (a, b) => compareStringsCaseInsensitive(a.name, b.name)) :
filter(optionDeclarations.slice(), v => !!v.showInSimplifiedHelpView);
toSorted(optionDeclarations.concat(tscBuildOption), (a, b) => compareStringsCaseInsensitive(a.name, b.name)) :
filter(optionDeclarations.concat(tscBuildOption), v => !!v.showInSimplifiedHelpView);
}

function printVersion(sys: System) {
Expand Down Expand Up @@ -507,15 +508,15 @@ function printAllHelp(sys: System, compilerOptions: readonly CommandLineOption[]
let output: string[] = [...getHeader(sys, `${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${getDiagnosticText(Diagnostics.Version_0, version)}`)];
output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.ALL_COMPILER_OPTIONS), compilerOptions, /*subCategory*/ true, /*beforeOptionsDescription*/ undefined, formatMessage(Diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0, "https://aka.ms/tsc"))];
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))];
output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.BUILD_OPTIONS), buildOptions, /*subCategory*/ false, formatMessage(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"))];
output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.BUILD_OPTIONS), filter(buildOptions, option => option !== tscBuildOption), /*subCategory*/ false, formatMessage(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"))];
for (const line of output) {
sys.write(line);
}
}

function printBuildHelp(sys: System, buildOptions: readonly CommandLineOption[]) {
let output: string[] = [...getHeader(sys, `${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${getDiagnosticText(Diagnostics.Version_0, version)}`)];
output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.BUILD_OPTIONS), buildOptions, /*subCategory*/ false, formatMessage(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"))];
output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.BUILD_OPTIONS), filter(buildOptions, option => option !== tscBuildOption), /*subCategory*/ false, formatMessage(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"))];
for (const line of output) {
sys.write(line);
}
Expand Down Expand Up @@ -559,11 +560,6 @@ function executeCommandLineWorker(
commandLine: ParsedCommandLine,
) {
let reportDiagnostic = createDiagnosticReporter(sys);
if (commandLine.options.build) {
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_build_must_be_the_first_command_line_argument));
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
}

// Configuration file name (if any)
let configFileName: string | undefined;
if (commandLine.options.locale) {
Expand Down Expand Up @@ -732,11 +728,11 @@ function executeCommandLineWorker(
}
}

/** @internal */
export function isBuild(commandLineArgs: readonly string[]) {
/** Returns true if commandline is --build and needs to be parsed useing parseBuildCommand */
export function isBuildCommand(commandLineArgs: readonly string[]) {
if (commandLineArgs.length > 0 && commandLineArgs[0].charCodeAt(0) === CharacterCodes.minus) {
const firstOption = commandLineArgs[0].slice(commandLineArgs[0].charCodeAt(1) === CharacterCodes.minus ? 2 : 1).toLowerCase();
return firstOption === "build" || firstOption === "b";
return firstOption === tscBuildOption.name || firstOption === tscBuildOption.shortName;
}
return false;
}
Expand All @@ -749,8 +745,8 @@ export function executeCommandLine(
cb: ExecuteCommandLineCallbacks,
commandLineArgs: readonly string[],
): void | SolutionBuilder<EmitAndSemanticDiagnosticsBuilderProgram> | WatchOfConfigFile<EmitAndSemanticDiagnosticsBuilderProgram> {
if (isBuild(commandLineArgs)) {
const { buildOptions, watchOptions, projects, errors } = parseBuildCommand(commandLineArgs.slice(1));
if (isBuildCommand(commandLineArgs)) {
const { buildOptions, watchOptions, projects, errors } = parseBuildCommand(commandLineArgs);
if (buildOptions.generateCpuProfile && system.enableCPUProfiler) {
system.enableCPUProfiler(buildOptions.generateCpuProfile, () =>
performBuild(
Expand Down
2 changes: 1 addition & 1 deletion src/testRunner/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export * from "./unittests/tsbuildWatch/reexport.js";
export * from "./unittests/tsbuildWatch/roots.js";
export * from "./unittests/tsbuildWatch/watchEnvironment.js";
export * from "./unittests/tsc/cancellationToken.js";
export * from "./unittests/tsc/commandLine.js";
export * from "./unittests/tsc/composite.js";
export * from "./unittests/tsc/declarationEmit.js";
export * from "./unittests/tsc/extends.js";
Expand All @@ -128,7 +129,6 @@ export * from "./unittests/tsc/noEmitOnError.js";
export * from "./unittests/tsc/projectReferences.js";
export * from "./unittests/tsc/projectReferencesConfig.js";
export * from "./unittests/tsc/redirect.js";
export * from "./unittests/tsc/runWithoutArgs.js";
export * from "./unittests/tscWatch/consoleClearing.js";
export * from "./unittests/tscWatch/emit.js";
export * from "./unittests/tscWatch/emitAndErrorUpdates.js";
Expand Down
2 changes: 1 addition & 1 deletion src/testRunner/unittests/config/commandLineParsing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe("unittests:: config:: commandLineParsing:: parseCommandLine", () => {

// --lib es6 0.ts
assertParseResult("Parse single option of library flag", ["--lib", "es6", "0.ts"]);
assertParseResult("Handles may only be used with --build flags", ["--clean", "--dry", "--force", "--verbose"]);
assertParseResult("Handles may only be used with --build flags", ["--build", "--clean", "--dry", "--force", "--verbose"]);
// --declarations --allowTS
assertParseResult("Handles did you mean for misspelt flags", ["--declarations", "--allowTS"]);
// --lib es5,es2015.symbol.wellknown 0.ts
Expand Down
2 changes: 1 addition & 1 deletion src/testRunner/unittests/helpers/baseline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,5 +525,5 @@ export function baselineAfterTscCompile(
}

export function tscBaselineName(scenario: string, subScenario: string, commandLineArgs: readonly string[], suffix?: string) {
return `${ts.isBuild(commandLineArgs) ? "tsbuild" : "tsc"}${isWatch(commandLineArgs) ? "Watch" : ""}/${scenario}/${subScenario.split(" ").join("-")}${suffix ? suffix : ""}.js`;
return `${ts.isBuildCommand(commandLineArgs) ? "tsbuild" : "tsc"}${isWatch(commandLineArgs) ? "Watch" : ""}/${scenario}/${subScenario.split(" ").join("-")}${suffix ? suffix : ""}.js`;
}
7 changes: 7 additions & 0 deletions src/testRunner/unittests/tsbuild/commandLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,4 +299,11 @@ describe("unittests:: tsbuild:: commandLine::", () => {
verifyNonIncremental({});
verifyNonIncremental({ outFile: "../outFile.js", module: ts.ModuleKind.AMD });
});

verifyTsc({
scenario: "commandLine",
subScenario: "help",
sys: () => TestServerHost.createWatchedSystem(ts.emptyArray),
commandLineArgs: ["--build", "--help"],
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { emptyArray } from "../../_namespaces/ts.js";
import { verifyTsc } from "../helpers/tsc.js";
import { TestServerHost } from "../helpers/virtualFileSystemWithWatch.js";

describe("unittests:: tsc:: runWithoutArgs::", () => {
describe("unittests:: tsc:: commandLine::", () => {
verifyTsc({
scenario: "runWithoutArgs",
scenario: "commandLine",
subScenario: "show help with ExitStatus.DiagnosticsPresent_OutputsSkipped",
sys: () =>
TestServerHost.createWatchedSystem(emptyArray, {
Expand All @@ -14,19 +14,40 @@ describe("unittests:: tsc:: runWithoutArgs::", () => {
});

verifyTsc({
scenario: "runWithoutArgs",
scenario: "commandLine",
subScenario: "show help with ExitStatus.DiagnosticsPresent_OutputsSkipped when host can't provide terminal width",
sys: () => TestServerHost.createWatchedSystem(emptyArray),
commandLineArgs: emptyArray,
});

verifyTsc({
scenario: "runWithoutArgs",
scenario: "commandLine",
subScenario: "does not add color when NO_COLOR is set",
sys: () =>
TestServerHost.createWatchedSystem(emptyArray, {
environmentVariables: new Map([["NO_COLOR", "true"]]),
}),
commandLineArgs: emptyArray,
});

verifyTsc({
scenario: "commandLine",
subScenario: "when build not first argument",
sys: () => TestServerHost.createWatchedSystem(emptyArray),
commandLineArgs: ["--verbose", "--build"],
});

verifyTsc({
scenario: "commandLine",
subScenario: "help",
sys: () => TestServerHost.createWatchedSystem(emptyArray),
commandLineArgs: ["--help"],
});

verifyTsc({
scenario: "commandLine",
subScenario: "help all",
sys: () => TestServerHost.createWatchedSystem(emptyArray),
commandLineArgs: ["--help", "--all"],
});
});
2 changes: 1 addition & 1 deletion src/testRunner/unittests/tscWatch/incremental.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe("unittests:: tscWatch:: incremental:: emit file --incremental", () => {
build();
}

Baseline.runBaseline(`${ts.isBuild(argsToPass) ? "tsbuild/watchMode" : "tscWatch"}/incremental/${subScenario.split(" ").join("-")}-${incremental ? "incremental" : "watch"}.js`, baseline.join("\r\n"));
Baseline.runBaseline(`${ts.isBuildCommand(argsToPass) ? "tsbuild/watchMode" : "tscWatch"}/incremental/${subScenario.split(" ").join("-")}-${incremental ? "incremental" : "watch"}.js`, baseline.join("\r\n"));

function build() {
const closer = ts.executeCommandLine(
Expand Down
10 changes: 10 additions & 0 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9123,6 +9123,7 @@ declare namespace ts {
jsDocParsingMode?: JSDocParsingMode;
}
function parseCommandLine(commandLine: readonly string[], readFile?: (path: string) => string | undefined): ParsedCommandLine;
function parseBuildCommand(commandLine: readonly string[]): ParsedBuildCommand;
/**
* Reads the config file, reports errors if any and exits if the config file cannot be found
*/
Expand Down Expand Up @@ -9177,6 +9178,13 @@ declare namespace ts {
options: TypeAcquisition;
errors: Diagnostic[];
};
/** Parsed command line for build */
interface ParsedBuildCommand {
buildOptions: BuildOptions;
watchOptions: WatchOptions | undefined;
projects: string[];
errors: Diagnostic[];
}
type DiagnosticReporter = (diagnostic: Diagnostic) => void;
/**
* Reports config file diagnostics
Expand Down Expand Up @@ -9904,6 +9912,8 @@ declare namespace ts {
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult | undefined;
}
type InvalidatedProject<T extends BuilderProgram> = UpdateOutputFileStampsProject | BuildInvalidedProject<T>;
/** Returns true if commandline is --build and needs to be parsed useing parseBuildCommand */
function isBuildCommand(commandLineArgs: readonly string[]): boolean;
function getDefaultFormatCodeSettings(newLineCharacter?: string): FormatCodeSettings;
/**
* Represents an immutable snapshot of a script at a specified time.Once acquired, the
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
--clean --dry --force --verbose
--build --clean --dry --force --verbose
CompilerOptions::
{}
WatchOptions::

FileNames::

Errors::
error TS6369: Option '--build' must be the first command line argument.
error TS5093: Compiler option '--clean' may only be used with '--build'.
error TS5093: Compiler option '--dry' may only be used with '--build'.
error TS5093: Compiler option '--force' may only be used with '--build'.
Expand Down

This file was deleted.

Loading

0 comments on commit 31afb98

Please sign in to comment.