Specified diagnostic for CLI flags mismatched with/out --build (#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
This commit is contained in:
Josh Goldberg 2021-04-07 19:03:17 -04:00 committed by GitHub
parent 2f82d02361
commit fe4a6709da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 87 additions and 13 deletions

View File

@ -306,10 +306,8 @@ namespace ts {
description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_ES2015_ES2016_ES2017_ES2018_ES2019_ES2020_ES2021_or_ESNEXT,
};
/* @internal */
export const optionDeclarations: CommandLineOption[] = [
const commandOptionsWithoutBuild: CommandLineOption[] = [
// CommandLine only options
...commonOptionsWithBuild,
{
name: "all",
type: "boolean",
@ -1106,6 +1104,12 @@ namespace ts {
},
];
/* @internal */
export const optionDeclarations: CommandLineOption[] = [
...commonOptionsWithBuild,
...commandOptionsWithoutBuild,
];
/* @internal */
export const semanticDiagnosticsOptionDeclarations: readonly CommandLineOption[] =
optionDeclarations.filter(option => !!option.affectsSemanticDiagnostics);
@ -1126,9 +1130,7 @@ namespace ts {
export const transpileOptionValueCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option =>
hasProperty(option, "transpileOptionValue"));
/* @internal */
export const buildOpts: CommandLineOption[] = [
...commonOptionsWithBuild,
const commandOptionsOnlyBuild: CommandLineOption[] = [
{
name: "verbose",
shortName: "v",
@ -1158,6 +1160,12 @@ namespace ts {
}
];
/* @internal */
export const buildOpts: CommandLineOption[] = [
...commonOptionsWithBuild,
...commandOptionsOnlyBuild,
];
/* @internal */
export const typeAcquisitionDeclarations: CommandLineOption[] = [
{
@ -1217,9 +1225,14 @@ namespace ts {
/* @internal */
export function getOptionsNameMap(): OptionsNameMap {
return optionsNameMapCache || (optionsNameMapCache = createOptionNameMap(optionDeclarations));
return optionsNameMapCache ||= createOptionNameMap(optionDeclarations);
}
const compilerOptionsAlternateMode: AlternateModeDiagnostics = {
diagnostic: Diagnostics.Compiler_option_0_may_only_be_used_with_build,
getOptionsNameMap: getBuildOptionsNameMap
};
/* @internal */
export const defaultInitCompilerOptions: CompilerOptions = {
module: ModuleKind.CommonJS,
@ -1299,6 +1312,10 @@ namespace ts {
createDiagnostics: (message: DiagnosticMessage, arg0: string, arg1?: string) => Diagnostic,
unknownOptionErrorText?: string
) {
if (diagnostics.alternateMode?.getOptionsNameMap().optionsNameMap.has(unknownOption.toLowerCase())) {
return createDiagnostics(diagnostics.alternateMode.diagnostic, unknownOption);
}
const possibleOption = getSpellingSuggestion(unknownOption, diagnostics.optionDeclarations, getOptionName);
return possibleOption ?
createDiagnostics(diagnostics.unknownDidYouMeanDiagnostic, unknownOptionErrorText || unknownOption, possibleOption.name) :
@ -1464,6 +1481,7 @@ namespace ts {
/*@internal*/
export const compilerOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnostics = {
alternateMode: compilerOptionsAlternateMode,
getOptionsNameMap,
optionDeclarations,
unknownOptionDiagnostic: Diagnostics.Unknown_compiler_option_0,
@ -1505,7 +1523,13 @@ namespace ts {
return buildOptionsNameMapCache || (buildOptionsNameMapCache = createOptionNameMap(buildOpts));
}
const buildOptionsAlternateMode: AlternateModeDiagnostics = {
diagnostic: Diagnostics.Compiler_option_0_may_not_be_used_with_build,
getOptionsNameMap
};
const buildOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnostics = {
alternateMode: buildOptionsAlternateMode,
getOptionsNameMap: getBuildOptionsNameMap,
optionDeclarations: buildOpts,
unknownOptionDiagnostic: Diagnostics.Unknown_build_option_0,

View File

@ -3938,6 +3938,14 @@
"category": "Error",
"code": 5092
},
"Compiler option '--{0}' may only be used with '--build'.": {
"category": "Error",
"code": 5093
},
"Compiler option '--{0}' may not be used with '--build'.": {
"category": "Error",
"code": 5094
},
"Generates a sourcemap for each corresponding '.d.ts' file.": {
"category": "Message",

View File

@ -6165,8 +6165,15 @@ namespace ts {
type: ESMap<string, number | string>; // an object literal mapping named values to actual values
}
/* @internal */
export interface AlternateModeDiagnostics {
diagnostic: DiagnosticMessage;
getOptionsNameMap: () => OptionsNameMap;
}
/* @internal */
export interface DidYouMeanOptionsDiagnostics {
alternateMode?: AlternateModeDiagnostics;
optionDeclarations: CommandLineOption[];
unknownOptionDiagnostic: DiagnosticMessage,
unknownDidYouMeanDiagnostic: DiagnosticMessage,

View File

@ -46,6 +46,23 @@ namespace ts {
});
});
it("Handles 'may only be used with --build' flags", () => {
const buildFlags = ["--clean", "--dry", "--force", "--verbose"];
assertParseResult(buildFlags, {
errors: buildFlags.map(buildFlag => ({
messageText: `Compiler option '${buildFlag}' may only be used with '--build'.`,
category: Diagnostics.Compiler_option_0_may_only_be_used_with_build.category,
code: Diagnostics.Compiler_option_0_may_only_be_used_with_build.code,
file: undefined,
start: undefined,
length: undefined
})),
fileNames: [],
options: {}
});
});
it("Handles 'did you mean?' for misspelt flags", () => {
// --declarations --allowTS
assertParseResult(["--declarations", "--allowTS"], {
@ -790,9 +807,9 @@ namespace ts {
assertParseResult(["--listFilesOnly"],
{
errors: [{
messageText: "Unknown build option '--listFilesOnly'.",
category: Diagnostics.Unknown_build_option_0.category,
code: Diagnostics.Unknown_build_option_0.code,
messageText: "Compiler option '--listFilesOnly' may not be used with '--build'.",
category: Diagnostics.Compiler_option_0_may_not_be_used_with_build.category,
code: Diagnostics.Compiler_option_0_may_not_be_used_with_build.code,
file: undefined,
start: undefined,
length: undefined,
@ -863,9 +880,9 @@ namespace ts {
assertParseResult(["--tsBuildInfoFile", "build.tsbuildinfo", "tests"],
{
errors: [{
messageText: "Unknown build option '--tsBuildInfoFile'.",
category: Diagnostics.Unknown_build_option_0.category,
code: Diagnostics.Unknown_build_option_0.code,
messageText: "Compiler option '--tsBuildInfoFile' may not be used with '--build'.",
category: Diagnostics.Compiler_option_0_may_not_be_used_with_build.category,
code: Diagnostics.Compiler_option_0_may_not_be_used_with_build.code,
file: undefined,
start: undefined,
length: undefined
@ -876,6 +893,24 @@ namespace ts {
});
});
it("reports other common 'may not be used with --build' flags", () => {
const buildFlags = ["--declaration", "--strict"];
assertParseResult(buildFlags, {
errors: buildFlags.map(buildFlag => ({
messageText: `Compiler option '${buildFlag}' may not be used with '--build'.`,
category: Diagnostics.Compiler_option_0_may_not_be_used_with_build.category,
code: Diagnostics.Compiler_option_0_may_not_be_used_with_build.code,
file: undefined,
start: undefined,
length: undefined
})),
buildOptions: {},
projects: ["."],
watchOptions: undefined,
});
});
describe("Combining options that make no sense together", () => {
function verifyInvalidCombination(flag1: keyof BuildOptions, flag2: keyof BuildOptions) {
it(`--${flag1} and --${flag2} together is invalid`, () => {