Skip to content

Commit fe4a670

Browse files
author
Josh Goldberg
authored
Specified diagnostic for CLI flags mismatched with/out --build (microsoft#43199)
* Specified diagnostic for CLI flags missing a required --build * Switched to an alternateMode member * Added --build-incompatible flags too * Small fixups to remove a hardcoding * Switched to ||= factories * Not a function * I think I get it now
1 parent 2f82d02 commit fe4a670

File tree

4 files changed

+87
-13
lines changed

4 files changed

+87
-13
lines changed

src/compiler/commandLineParser.ts

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -306,10 +306,8 @@ namespace ts {
306306
description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_ES2015_ES2016_ES2017_ES2018_ES2019_ES2020_ES2021_or_ESNEXT,
307307
};
308308

309-
/* @internal */
310-
export const optionDeclarations: CommandLineOption[] = [
309+
const commandOptionsWithoutBuild: CommandLineOption[] = [
311310
// CommandLine only options
312-
...commonOptionsWithBuild,
313311
{
314312
name: "all",
315313
type: "boolean",
@@ -1106,6 +1104,12 @@ namespace ts {
11061104
},
11071105
];
11081106

1107+
/* @internal */
1108+
export const optionDeclarations: CommandLineOption[] = [
1109+
...commonOptionsWithBuild,
1110+
...commandOptionsWithoutBuild,
1111+
];
1112+
11091113
/* @internal */
11101114
export const semanticDiagnosticsOptionDeclarations: readonly CommandLineOption[] =
11111115
optionDeclarations.filter(option => !!option.affectsSemanticDiagnostics);
@@ -1126,9 +1130,7 @@ namespace ts {
11261130
export const transpileOptionValueCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option =>
11271131
hasProperty(option, "transpileOptionValue"));
11281132

1129-
/* @internal */
1130-
export const buildOpts: CommandLineOption[] = [
1131-
...commonOptionsWithBuild,
1133+
const commandOptionsOnlyBuild: CommandLineOption[] = [
11321134
{
11331135
name: "verbose",
11341136
shortName: "v",
@@ -1158,6 +1160,12 @@ namespace ts {
11581160
}
11591161
];
11601162

1163+
/* @internal */
1164+
export const buildOpts: CommandLineOption[] = [
1165+
...commonOptionsWithBuild,
1166+
...commandOptionsOnlyBuild,
1167+
];
1168+
11611169
/* @internal */
11621170
export const typeAcquisitionDeclarations: CommandLineOption[] = [
11631171
{
@@ -1217,9 +1225,14 @@ namespace ts {
12171225

12181226
/* @internal */
12191227
export function getOptionsNameMap(): OptionsNameMap {
1220-
return optionsNameMapCache || (optionsNameMapCache = createOptionNameMap(optionDeclarations));
1228+
return optionsNameMapCache ||= createOptionNameMap(optionDeclarations);
12211229
}
12221230

1231+
const compilerOptionsAlternateMode: AlternateModeDiagnostics = {
1232+
diagnostic: Diagnostics.Compiler_option_0_may_only_be_used_with_build,
1233+
getOptionsNameMap: getBuildOptionsNameMap
1234+
};
1235+
12231236
/* @internal */
12241237
export const defaultInitCompilerOptions: CompilerOptions = {
12251238
module: ModuleKind.CommonJS,
@@ -1299,6 +1312,10 @@ namespace ts {
12991312
createDiagnostics: (message: DiagnosticMessage, arg0: string, arg1?: string) => Diagnostic,
13001313
unknownOptionErrorText?: string
13011314
) {
1315+
if (diagnostics.alternateMode?.getOptionsNameMap().optionsNameMap.has(unknownOption.toLowerCase())) {
1316+
return createDiagnostics(diagnostics.alternateMode.diagnostic, unknownOption);
1317+
}
1318+
13021319
const possibleOption = getSpellingSuggestion(unknownOption, diagnostics.optionDeclarations, getOptionName);
13031320
return possibleOption ?
13041321
createDiagnostics(diagnostics.unknownDidYouMeanDiagnostic, unknownOptionErrorText || unknownOption, possibleOption.name) :
@@ -1464,6 +1481,7 @@ namespace ts {
14641481

14651482
/*@internal*/
14661483
export const compilerOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnostics = {
1484+
alternateMode: compilerOptionsAlternateMode,
14671485
getOptionsNameMap,
14681486
optionDeclarations,
14691487
unknownOptionDiagnostic: Diagnostics.Unknown_compiler_option_0,
@@ -1505,7 +1523,13 @@ namespace ts {
15051523
return buildOptionsNameMapCache || (buildOptionsNameMapCache = createOptionNameMap(buildOpts));
15061524
}
15071525

1526+
const buildOptionsAlternateMode: AlternateModeDiagnostics = {
1527+
diagnostic: Diagnostics.Compiler_option_0_may_not_be_used_with_build,
1528+
getOptionsNameMap
1529+
};
1530+
15081531
const buildOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnostics = {
1532+
alternateMode: buildOptionsAlternateMode,
15091533
getOptionsNameMap: getBuildOptionsNameMap,
15101534
optionDeclarations: buildOpts,
15111535
unknownOptionDiagnostic: Diagnostics.Unknown_build_option_0,

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3938,6 +3938,14 @@
39383938
"category": "Error",
39393939
"code": 5092
39403940
},
3941+
"Compiler option '--{0}' may only be used with '--build'.": {
3942+
"category": "Error",
3943+
"code": 5093
3944+
},
3945+
"Compiler option '--{0}' may not be used with '--build'.": {
3946+
"category": "Error",
3947+
"code": 5094
3948+
},
39413949

39423950
"Generates a sourcemap for each corresponding '.d.ts' file.": {
39433951
"category": "Message",

src/compiler/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6165,8 +6165,15 @@ namespace ts {
61656165
type: ESMap<string, number | string>; // an object literal mapping named values to actual values
61666166
}
61676167

6168+
/* @internal */
6169+
export interface AlternateModeDiagnostics {
6170+
diagnostic: DiagnosticMessage;
6171+
getOptionsNameMap: () => OptionsNameMap;
6172+
}
6173+
61686174
/* @internal */
61696175
export interface DidYouMeanOptionsDiagnostics {
6176+
alternateMode?: AlternateModeDiagnostics;
61706177
optionDeclarations: CommandLineOption[];
61716178
unknownOptionDiagnostic: DiagnosticMessage,
61726179
unknownDidYouMeanDiagnostic: DiagnosticMessage,

src/testRunner/unittests/config/commandLineParsing.ts

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,23 @@ namespace ts {
4646
});
4747
});
4848

49+
it("Handles 'may only be used with --build' flags", () => {
50+
const buildFlags = ["--clean", "--dry", "--force", "--verbose"];
51+
52+
assertParseResult(buildFlags, {
53+
errors: buildFlags.map(buildFlag => ({
54+
messageText: `Compiler option '${buildFlag}' may only be used with '--build'.`,
55+
category: Diagnostics.Compiler_option_0_may_only_be_used_with_build.category,
56+
code: Diagnostics.Compiler_option_0_may_only_be_used_with_build.code,
57+
file: undefined,
58+
start: undefined,
59+
length: undefined
60+
})),
61+
fileNames: [],
62+
options: {}
63+
});
64+
});
65+
4966
it("Handles 'did you mean?' for misspelt flags", () => {
5067
// --declarations --allowTS
5168
assertParseResult(["--declarations", "--allowTS"], {
@@ -790,9 +807,9 @@ namespace ts {
790807
assertParseResult(["--listFilesOnly"],
791808
{
792809
errors: [{
793-
messageText: "Unknown build option '--listFilesOnly'.",
794-
category: Diagnostics.Unknown_build_option_0.category,
795-
code: Diagnostics.Unknown_build_option_0.code,
810+
messageText: "Compiler option '--listFilesOnly' may not be used with '--build'.",
811+
category: Diagnostics.Compiler_option_0_may_not_be_used_with_build.category,
812+
code: Diagnostics.Compiler_option_0_may_not_be_used_with_build.code,
796813
file: undefined,
797814
start: undefined,
798815
length: undefined,
@@ -863,9 +880,9 @@ namespace ts {
863880
assertParseResult(["--tsBuildInfoFile", "build.tsbuildinfo", "tests"],
864881
{
865882
errors: [{
866-
messageText: "Unknown build option '--tsBuildInfoFile'.",
867-
category: Diagnostics.Unknown_build_option_0.category,
868-
code: Diagnostics.Unknown_build_option_0.code,
883+
messageText: "Compiler option '--tsBuildInfoFile' may not be used with '--build'.",
884+
category: Diagnostics.Compiler_option_0_may_not_be_used_with_build.category,
885+
code: Diagnostics.Compiler_option_0_may_not_be_used_with_build.code,
869886
file: undefined,
870887
start: undefined,
871888
length: undefined
@@ -876,6 +893,24 @@ namespace ts {
876893
});
877894
});
878895

896+
it("reports other common 'may not be used with --build' flags", () => {
897+
const buildFlags = ["--declaration", "--strict"];
898+
899+
assertParseResult(buildFlags, {
900+
errors: buildFlags.map(buildFlag => ({
901+
messageText: `Compiler option '${buildFlag}' may not be used with '--build'.`,
902+
category: Diagnostics.Compiler_option_0_may_not_be_used_with_build.category,
903+
code: Diagnostics.Compiler_option_0_may_not_be_used_with_build.code,
904+
file: undefined,
905+
start: undefined,
906+
length: undefined
907+
})),
908+
buildOptions: {},
909+
projects: ["."],
910+
watchOptions: undefined,
911+
});
912+
});
913+
879914
describe("Combining options that make no sense together", () => {
880915
function verifyInvalidCombination(flag1: keyof BuildOptions, flag2: keyof BuildOptions) {
881916
it(`--${flag1} and --${flag2} together is invalid`, () => {

0 commit comments

Comments
 (0)