From af7e232a97e129f7ebcf15a078f0780f3a011f4c Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Tue, 12 Nov 2019 15:05:38 -0500 Subject: [PATCH 1/4] Adds did you mean to the CLI args parser --- src/compiler/commandLineParser.ts | 14 +++++++++++--- src/compiler/diagnosticMessages.json | 4 ++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index c9517440ac6ed..a1ac78a6a7a9e 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -1088,11 +1088,11 @@ namespace ts { } /** Tuple with error messages for 'unknown compiler option', 'option requires type' */ - type ParseCommandLineWorkerDiagnostics = [DiagnosticMessage, DiagnosticMessage]; + type ParseCommandLineWorkerDiagnostics = [DiagnosticMessage, DiagnosticMessage, DiagnosticMessage]; function parseCommandLineWorker( getOptionNameMap: () => OptionNameMap, - [unknownOptionDiagnostic, optionTypeMismatchDiagnostic]: ParseCommandLineWorkerDiagnostics, + [unknownOptionDiagnostic, unknownDidYouMeanDiagnostic, optionTypeMismatchDiagnostic]: ParseCommandLineWorkerDiagnostics, commandLine: readonly string[], readFile?: (path: string) => string | undefined) { const options = {} as OptionsBase; @@ -1160,7 +1160,13 @@ namespace ts { } } else { - errors.push(createCompilerDiagnostic(unknownOptionDiagnostic, s)); + const possibleOption = getSpellingSuggestion(s, optionDeclarations, opt => `--${opt.name}`); + if (possibleOption) { + errors.push(createCompilerDiagnostic(unknownDidYouMeanDiagnostic, s, possibleOption.name)); + } + else { + errors.push(createCompilerDiagnostic(unknownOptionDiagnostic, s)); + } } } else { @@ -1206,6 +1212,7 @@ namespace ts { export function parseCommandLine(commandLine: readonly string[], readFile?: (path: string) => string | undefined): ParsedCommandLine { return parseCommandLineWorker(getOptionNameMap, [ Diagnostics.Unknown_compiler_option_0, + Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, Diagnostics.Compiler_option_0_expects_an_argument ], commandLine, readFile); } @@ -1241,6 +1248,7 @@ namespace ts { const returnBuildOptionNameMap = () => (buildOptionNameMap || (buildOptionNameMap = createOptionNameMap(buildOpts))); const { options, fileNames: projects, errors } = parseCommandLineWorker(returnBuildOptionNameMap, [ Diagnostics.Unknown_build_option_0, + Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, Diagnostics.Build_option_0_requires_a_value_of_type_1 ], args); const buildOptions = options as BuildOptions; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index cf2bdfb8ceca5..475c809cbbf7d 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3177,6 +3177,10 @@ "category": "Error", "code": 5024 }, + "Unknown compiler option '{0}'. Did you mean '{1}'?": { + "category": "Error", + "code": 5025 + }, "Could not write file '{0}': {1}.": { "category": "Error", "code": 5033 From 37820defaeeae460b508b231ada5dd6c6337be17 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Tue, 12 Nov 2019 15:30:12 -0500 Subject: [PATCH 2/4] Adds test coverage for the did you mean on CLI args --- .../unittests/config/commandLineParsing.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/testRunner/unittests/config/commandLineParsing.ts b/src/testRunner/unittests/config/commandLineParsing.ts index 5792ee1a39c40..6ad786fbfc4fd 100644 --- a/src/testRunner/unittests/config/commandLineParsing.ts +++ b/src/testRunner/unittests/config/commandLineParsing.ts @@ -40,6 +40,33 @@ namespace ts { }); }); + it("Handles 'did you mean?' for misspelt flags", () => { + // --declarations --allowTS + assertParseResult(["--declarations", "--allowTS"], { + errors: [ + { + messageText:"Unknown compiler option '--declarations'. Did you mean 'declaration'?", + category: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1.category, + code: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1.code, + file: undefined, + start: undefined, + length: undefined + }, + { + messageText: "Unknown compiler option '--allowTS'. Did you mean 'allowJs'?", + category: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1.category, + code: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1.code, + file: undefined, + start: undefined, + length: undefined + } + ], + fileNames: [], + options: {} + }); + }); + + it("Parse multiple options of library flags ", () => { // --lib es5,es2015.symbol.wellknown 0.ts assertParseResult(["--lib", "es5,es2015.symbol.wellknown", "0.ts"], @@ -556,4 +583,6 @@ namespace ts { verifyInvalidCombination("watch", "dry"); }); }); + + } From ae167deee8b47f66ba94610693109d83d27b8a66 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Wed, 13 Nov 2019 13:05:14 -0500 Subject: [PATCH 3/4] Adds did you mean to convertOptionsFromJson --- src/compiler/commandLineParser.ts | 67 ++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index a1ac78a6a7a9e..7a64d3a2c0b5b 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -1087,12 +1087,15 @@ namespace ts { [option: string]: CompilerOptionsValue | undefined; } - /** Tuple with error messages for 'unknown compiler option', 'option requires type' */ - type ParseCommandLineWorkerDiagnostics = [DiagnosticMessage, DiagnosticMessage, DiagnosticMessage]; + interface ParseCommandLineWorkerDiagnostics { + unknownOptionDiagnostic: DiagnosticMessage, + unknownDidYouMeanDiagnostic: DiagnosticMessage, + optionTypeMismatchDiagnostic: DiagnosticMessage + } function parseCommandLineWorker( getOptionNameMap: () => OptionNameMap, - [unknownOptionDiagnostic, unknownDidYouMeanDiagnostic, optionTypeMismatchDiagnostic]: ParseCommandLineWorkerDiagnostics, + diagnostics: ParseCommandLineWorkerDiagnostics, commandLine: readonly string[], readFile?: (path: string) => string | undefined) { const options = {} as OptionsBase; @@ -1123,7 +1126,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(optionTypeMismatchDiagnostic, opt.name)); + errors.push(createCompilerDiagnostic(diagnostics.optionTypeMismatchDiagnostic, opt.name)); } switch (opt.type) { @@ -1162,10 +1165,10 @@ namespace ts { else { const possibleOption = getSpellingSuggestion(s, optionDeclarations, opt => `--${opt.name}`); if (possibleOption) { - errors.push(createCompilerDiagnostic(unknownDidYouMeanDiagnostic, s, possibleOption.name)); + errors.push(createCompilerDiagnostic(diagnostics.unknownDidYouMeanDiagnostic, s, possibleOption.name)); } else { - errors.push(createCompilerDiagnostic(unknownOptionDiagnostic, s)); + errors.push(createCompilerDiagnostic(diagnostics.unknownOptionDiagnostic, s)); } } } @@ -1209,12 +1212,13 @@ namespace ts { } } + const defaultDiagnostics = { + unknownOptionDiagnostic: Diagnostics.Unknown_compiler_option_0, + unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, + optionTypeMismatchDiagnostic: Diagnostics.Compiler_option_0_expects_an_argument + }; export function parseCommandLine(commandLine: readonly string[], readFile?: (path: string) => string | undefined): ParsedCommandLine { - return parseCommandLineWorker(getOptionNameMap, [ - Diagnostics.Unknown_compiler_option_0, - Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, - Diagnostics.Compiler_option_0_expects_an_argument - ], commandLine, readFile); + return parseCommandLineWorker(getOptionNameMap, defaultDiagnostics, commandLine, readFile); } /** @internal */ @@ -1246,11 +1250,11 @@ namespace ts { export function parseBuildCommand(args: readonly string[]): ParsedBuildCommand { let buildOptionNameMap: OptionNameMap | undefined; const returnBuildOptionNameMap = () => (buildOptionNameMap || (buildOptionNameMap = createOptionNameMap(buildOpts))); - const { options, fileNames: projects, errors } = parseCommandLineWorker(returnBuildOptionNameMap, [ - Diagnostics.Unknown_build_option_0, - Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, - Diagnostics.Build_option_0_requires_a_value_of_type_1 - ], args); + const { options, fileNames: projects, errors } = parseCommandLineWorker(returnBuildOptionNameMap, { + unknownOptionDiagnostic: Diagnostics.Unknown_build_option_0, + unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, + optionTypeMismatchDiagnostic: Diagnostics.Build_option_0_requires_a_value_of_type_1 + }, args); const buildOptions = options as BuildOptions; if (projects.length === 0) { @@ -2476,7 +2480,12 @@ namespace ts { basePath: string, errors: Push, configFileName?: string): CompilerOptions { const options = getDefaultCompilerOptions(configFileName); - convertOptionsFromJson(optionDeclarations, jsonOptions, basePath, options, Diagnostics.Unknown_compiler_option_0, errors); + + const diagnostics = { + unknownOptionDiagnostic: Diagnostics.Unknown_compiler_option_0, + unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1 , + }; + convertOptionsFromJson(optionDeclarations, jsonOptions, basePath, options, diagnostics, errors); if (configFileName) { options.configFilePath = normalizeSlashes(configFileName); } @@ -2492,13 +2501,25 @@ namespace ts { const options = getDefaultTypeAcquisition(configFileName); const typeAcquisition = convertEnableAutoDiscoveryToEnable(jsonOptions); - convertOptionsFromJson(typeAcquisitionDeclarations, typeAcquisition, basePath, options, Diagnostics.Unknown_type_acquisition_option_0, errors); + + const diagnostics = { + unknownOptionDiagnostic: Diagnostics.Unknown_compiler_option_0, + unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1 , + }; + convertOptionsFromJson(typeAcquisitionDeclarations, typeAcquisition, basePath, options, diagnostics, errors); return options; } + + interface ConvertOptionsDiagnostics { + unknownOptionDiagnostic: DiagnosticMessage, + unknownDidYouMeanDiagnostic: DiagnosticMessage, + } + + function convertOptionsFromJson(optionDeclarations: readonly CommandLineOption[], jsonOptions: any, basePath: string, - defaultOptions: CompilerOptions | TypeAcquisition, diagnosticMessage: DiagnosticMessage, errors: Push) { + defaultOptions: CompilerOptions | TypeAcquisition, diagnostics: ConvertOptionsDiagnostics, errors: Push) { if (!jsonOptions) { return; @@ -2512,7 +2533,13 @@ namespace ts { defaultOptions[opt.name] = convertJsonOption(opt, jsonOptions[id], basePath, errors); } else { - errors.push(createCompilerDiagnostic(diagnosticMessage, id)); + const possibleOption = getSpellingSuggestion(id, optionDeclarations, opt => opt.name); + if (possibleOption) { + errors.push(createCompilerDiagnostic(diagnostics.unknownDidYouMeanDiagnostic, id, possibleOption.name)); + } + else { + errors.push(createCompilerDiagnostic(diagnostics.unknownOptionDiagnostic, id)); + } } } } From 63e5b9eab9f21fac8f1812fc68dd7439e0e3efec Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Wed, 13 Nov 2019 16:01:09 -0500 Subject: [PATCH 4/4] Ensure tsconfig compiler flags also get 'did you mean?' --- src/compiler/commandLineParser.ts | 61 +++++++++++-------- src/compiler/diagnosticMessages.json | 9 ++- src/compiler/types.ts | 8 ++- .../config/convertTypeAcquisitionFromJson.ts | 8 +-- src/testRunner/unittests/tscWatch/helpers.ts | 5 ++ .../unittests/tscWatch/programUpdates.ts | 2 +- .../unittests/tsserver/projectErrors.ts | 8 +-- 7 files changed, 64 insertions(+), 37 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 7a64d3a2c0b5b..4bcc1e48c8f19 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -1212,13 +1212,13 @@ namespace ts { } } - const defaultDiagnostics = { + const compilerOptionsDefaultDiagnostics = { unknownOptionDiagnostic: Diagnostics.Unknown_compiler_option_0, unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, optionTypeMismatchDiagnostic: Diagnostics.Compiler_option_0_expects_an_argument }; export function parseCommandLine(commandLine: readonly string[], readFile?: (path: string) => string | undefined): ParsedCommandLine { - return parseCommandLineWorker(getOptionNameMap, defaultDiagnostics, commandLine, readFile); + return parseCommandLineWorker(getOptionNameMap, compilerOptionsDefaultDiagnostics, commandLine, readFile); } /** @internal */ @@ -1252,7 +1252,7 @@ namespace ts { const returnBuildOptionNameMap = () => (buildOptionNameMap || (buildOptionNameMap = createOptionNameMap(buildOpts))); const { options, fileNames: projects, errors } = parseCommandLineWorker(returnBuildOptionNameMap, { unknownOptionDiagnostic: Diagnostics.Unknown_build_option_0, - unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, + unknownDidYouMeanDiagnostic: Diagnostics.Unknown_build_option_0_Did_you_mean_1, optionTypeMismatchDiagnostic: Diagnostics.Build_option_0_requires_a_value_of_type_1 }, args); const buildOptions = options as BuildOptions; @@ -1401,19 +1401,28 @@ namespace ts { name: "compilerOptions", type: "object", elementOptions: commandLineOptionsToMap(optionDeclarations), - extraKeyDiagnosticMessage: Diagnostics.Unknown_compiler_option_0 + extraKeyDiagnostics: { + unknownOptionDiagnostic: Diagnostics.Unknown_compiler_option_0, + unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1 + }, }, { name: "typingOptions", type: "object", elementOptions: commandLineOptionsToMap(typeAcquisitionDeclarations), - extraKeyDiagnosticMessage: Diagnostics.Unknown_type_acquisition_option_0 + extraKeyDiagnostics: { + unknownOptionDiagnostic: Diagnostics.Unknown_type_acquisition_option_0, + unknownDidYouMeanDiagnostic: Diagnostics.Unknown_type_acquisition_option_0_Did_you_mean_1 + }, }, { name: "typeAcquisition", type: "object", elementOptions: commandLineOptionsToMap(typeAcquisitionDeclarations), - extraKeyDiagnosticMessage: Diagnostics.Unknown_type_acquisition_option_0 + extraKeyDiagnostics: { + unknownOptionDiagnostic: Diagnostics.Unknown_type_acquisition_option_0, + unknownDidYouMeanDiagnostic: Diagnostics.Unknown_type_acquisition_option_0_Did_you_mean_1 + } }, { name: "extends", @@ -1519,7 +1528,7 @@ namespace ts { function convertObjectLiteralExpressionToJson( node: ObjectLiteralExpression, knownOptions: Map | undefined, - extraKeyDiagnosticMessage: DiagnosticMessage | undefined, + extraKeyDiagnostics: DidYouMeanOptionalDiagnostics | undefined, parentOption: string | undefined ): any { const result: any = returnValue ? {} : undefined; @@ -1539,8 +1548,19 @@ namespace ts { const textOfKey = getTextOfPropertyName(element.name); const keyText = textOfKey && unescapeLeadingUnderscores(textOfKey); const option = keyText && knownOptions ? knownOptions.get(keyText) : undefined; - if (keyText && extraKeyDiagnosticMessage && !option) { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.name, extraKeyDiagnosticMessage, keyText)); + if (keyText && extraKeyDiagnostics && !option) { + if (knownOptions) { + const possibleOption = getSpellingSuggestion(keyText, arrayFrom(knownOptions.keys()), identity); + if (possibleOption) { + errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.name, extraKeyDiagnostics.unknownDidYouMeanDiagnostic, keyText, possibleOption)); + } + else { + errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.name, extraKeyDiagnostics.unknownOptionDiagnostic, keyText)); + } + } + else { + errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.name, extraKeyDiagnostics.unknownOptionDiagnostic, keyText)); + } } const value = convertPropertyValueToJson(element.initializer, option); if (typeof keyText !== "undefined") { @@ -1642,9 +1662,9 @@ namespace ts { // vs what we set in the json // If need arises, we can modify this interface and callbacks as needed if (option) { - const { elementOptions, extraKeyDiagnosticMessage, name: optionName } = option; + const { elementOptions, extraKeyDiagnostics, name: optionName } = option; return convertObjectLiteralExpressionToJson(objectLiteralExpression, - elementOptions, extraKeyDiagnosticMessage, optionName); + elementOptions, extraKeyDiagnostics, optionName); } else { return convertObjectLiteralExpressionToJson( @@ -2480,12 +2500,7 @@ namespace ts { basePath: string, errors: Push, configFileName?: string): CompilerOptions { const options = getDefaultCompilerOptions(configFileName); - - const diagnostics = { - unknownOptionDiagnostic: Diagnostics.Unknown_compiler_option_0, - unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1 , - }; - convertOptionsFromJson(optionDeclarations, jsonOptions, basePath, options, diagnostics, errors); + convertOptionsFromJson(optionDeclarations, jsonOptions, basePath, options, compilerOptionsDefaultDiagnostics, errors); if (configFileName) { options.configFilePath = normalizeSlashes(configFileName); } @@ -2503,8 +2518,8 @@ namespace ts { const typeAcquisition = convertEnableAutoDiscoveryToEnable(jsonOptions); const diagnostics = { - unknownOptionDiagnostic: Diagnostics.Unknown_compiler_option_0, - unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1 , + unknownOptionDiagnostic: Diagnostics.Unknown_type_acquisition_option_0, + unknownDidYouMeanDiagnostic: Diagnostics.Unknown_type_acquisition_option_0_Did_you_mean_1 , }; convertOptionsFromJson(typeAcquisitionDeclarations, typeAcquisition, basePath, options, diagnostics, errors); @@ -2512,14 +2527,8 @@ namespace ts { } - interface ConvertOptionsDiagnostics { - unknownOptionDiagnostic: DiagnosticMessage, - unknownDidYouMeanDiagnostic: DiagnosticMessage, - } - - function convertOptionsFromJson(optionDeclarations: readonly CommandLineOption[], jsonOptions: any, basePath: string, - defaultOptions: CompilerOptions | TypeAcquisition, diagnostics: ConvertOptionsDiagnostics, errors: Push) { + defaultOptions: CompilerOptions | TypeAcquisition, diagnostics: DidYouMeanOptionalDiagnostics, errors: Push) { if (!jsonOptions) { return; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 475c809cbbf7d..d93b725c01b19 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3301,6 +3301,10 @@ "category": "Error", "code": 5076 }, + "Unknown build option '{0}'. Did you mean '{1}'?": { + "category": "Error", + "code": 5077 + }, "Generates a sourcemap for each corresponding '.d.ts' file.": { "category": "Message", @@ -4751,7 +4755,10 @@ "category": "Error", "code": 17017 }, - + "Unknown type acquisition option '{0}'. Did you mean '{1}'?": { + "category": "Error", + "code": 17018 + }, "Circularity detected while resolving configuration: {0}": { "category": "Error", "code": 18000 diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3b387d6ec1e41..9aef31dda4ea3 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5199,11 +5199,17 @@ namespace ts { type: Map; // an object literal mapping named values to actual values } + /* @internal */ + export interface DidYouMeanOptionalDiagnostics { + unknownOptionDiagnostic: DiagnosticMessage, + unknownDidYouMeanDiagnostic: DiagnosticMessage, + } + /* @internal */ export interface TsConfigOnlyOption extends CommandLineOptionBase { type: "object"; elementOptions?: Map; - extraKeyDiagnosticMessage?: DiagnosticMessage; + extraKeyDiagnostics?: DidYouMeanOptionalDiagnostics; } /* @internal */ diff --git a/src/testRunner/unittests/config/convertTypeAcquisitionFromJson.ts b/src/testRunner/unittests/config/convertTypeAcquisitionFromJson.ts index 0c0b953209f40..e8ca5f15d69d9 100644 --- a/src/testRunner/unittests/config/convertTypeAcquisitionFromJson.ts +++ b/src/testRunner/unittests/config/convertTypeAcquisitionFromJson.ts @@ -111,8 +111,8 @@ namespace ts { }, errors: [ { - category: Diagnostics.Unknown_type_acquisition_option_0.category, - code: Diagnostics.Unknown_type_acquisition_option_0.code, + category: Diagnostics.Unknown_type_acquisition_option_0_Did_you_mean_1.category, + code: Diagnostics.Unknown_type_acquisition_option_0_Did_you_mean_1.code, file: undefined, start: 0, length: 0, @@ -206,8 +206,8 @@ namespace ts { }, errors: [ { - category: Diagnostics.Unknown_type_acquisition_option_0.category, - code: Diagnostics.Unknown_type_acquisition_option_0.code, + category: Diagnostics.Unknown_type_acquisition_option_0_Did_you_mean_1.category, + code: Diagnostics.Unknown_type_acquisition_option_0_Did_you_mean_1.code, file: undefined, start: 0, length: 0, diff --git a/src/testRunner/unittests/tscWatch/helpers.ts b/src/testRunner/unittests/tscWatch/helpers.ts index 1ab49cec139a4..7f6a69aa48d7e 100644 --- a/src/testRunner/unittests/tscWatch/helpers.ts +++ b/src/testRunner/unittests/tscWatch/helpers.ts @@ -273,6 +273,11 @@ namespace ts.tscWatch { return getDiagnosticOfFile(program.getCompilerOptions().configFile!, configFile.content.indexOf(quotedOption), quotedOption.length, Diagnostics.Unknown_compiler_option_0, option); } + export function getUnknownDidYouMeanCompilerOption(program: Program, configFile: File, option: string, didYouMean: string) { + const quotedOption = `"${option}"`; + return getDiagnosticOfFile(program.getCompilerOptions().configFile!, configFile.content.indexOf(quotedOption), quotedOption.length, Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, option, didYouMean); + } + export function getDiagnosticModuleNotFoundOfFile(program: Program, file: File, moduleName: string) { const quotedModuleName = `"${moduleName}"`; return getDiagnosticOfFileFromProgram(program, file.path, file.content.indexOf(quotedModuleName), quotedModuleName.length, Diagnostics.Cannot_find_module_0, moduleName); diff --git a/src/testRunner/unittests/tscWatch/programUpdates.ts b/src/testRunner/unittests/tscWatch/programUpdates.ts index 0b9cc883b85d1..e6f09c2628af6 100644 --- a/src/testRunner/unittests/tscWatch/programUpdates.ts +++ b/src/testRunner/unittests/tscWatch/programUpdates.ts @@ -757,7 +757,7 @@ namespace ts.tscWatch { const watch = createWatchOfConfigFile(configFile.path, host); checkOutputErrorsInitial(host, [ getUnknownCompilerOption(watch(), configFile, "foo"), - getUnknownCompilerOption(watch(), configFile, "allowJS") + getUnknownDidYouMeanCompilerOption(watch(), configFile, "allowJS", "allowJs") ]); }); diff --git a/src/testRunner/unittests/tsserver/projectErrors.ts b/src/testRunner/unittests/tsserver/projectErrors.ts index 64c07c77010f2..41eea1de9e7d6 100644 --- a/src/testRunner/unittests/tsserver/projectErrors.ts +++ b/src/testRunner/unittests/tsserver/projectErrors.ts @@ -496,14 +496,14 @@ declare module '@custom/plugin' { }); describe("unittests:: tsserver:: Project Errors for Configure file diagnostics events", () => { - function getUnknownCompilerOptionDiagnostic(configFile: File, prop: string): ConfigFileDiagnostic { - const d = Diagnostics.Unknown_compiler_option_0; + function getUnknownCompilerOptionDiagnostic(configFile: File, prop: string, didYouMean?: string): ConfigFileDiagnostic { + const d = didYouMean ? Diagnostics.Unknown_compiler_option_0_Did_you_mean_1 : Diagnostics.Unknown_compiler_option_0; const start = configFile.content.indexOf(prop) - 1; // start at "prop" return { fileName: configFile.path, start, length: prop.length + 2, - messageText: formatStringFromArgs(d.message, [prop]), + messageText: formatStringFromArgs(d.message, didYouMean ? [prop, didYouMean] : [prop]), category: d.category, code: d.code, reportsUnnecessary: undefined @@ -543,7 +543,7 @@ declare module '@custom/plugin' { openFilesForSession([file], serverEventManager.session); serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path, [ getUnknownCompilerOptionDiagnostic(configFile, "foo"), - getUnknownCompilerOptionDiagnostic(configFile, "allowJS") + getUnknownCompilerOptionDiagnostic(configFile, "allowJS", "allowJs") ]); });