Skip to content

Commit 18ea3ec

Browse files
Provide Spelling Suggestions for Unicode Property Value Expressions
1 parent 2ac41f4 commit 18ea3ec

8 files changed

+64
-3
lines changed

src/compiler/core.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2322,7 +2322,7 @@ export function compareBooleans(a: boolean, b: boolean): Comparison {
23222322
*
23232323
* @internal
23242324
*/
2325-
export function getSpellingSuggestion<T>(name: string, candidates: T[], getName: (candidate: T) => string | undefined): T | undefined {
2325+
export function getSpellingSuggestion<T>(name: string, candidates: Iterable<T>, getName: (candidate: T) => string | undefined): T | undefined {
23262326
const maximumLengthDifference = Math.max(2, Math.floor(name.length * 0.34));
23272327
let bestDistance = Math.floor(name.length * 0.4) + 1; // If the best result is worse than this, don't bother.
23282328
let bestCandidate: T | undefined;

src/compiler/parser.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import {
6464
DeleteExpression,
6565
Diagnostic,
6666
DiagnosticArguments,
67+
DiagnosticCategory,
6768
DiagnosticMessage,
6869
Diagnostics,
6970
DiagnosticWithDetachedLocation,
@@ -115,6 +116,7 @@ import {
115116
HasModifiers,
116117
HeritageClause,
117118
Identifier,
119+
identity,
118120
idText,
119121
IfStatement,
120122
ImportClause,
@@ -2114,7 +2116,11 @@ namespace Parser {
21142116
// Don't report another error if it would just be at the same position as the last error.
21152117
const lastError = lastOrUndefined(parseDiagnostics);
21162118
let result: DiagnosticWithDetachedLocation | undefined;
2117-
if (!lastError || start !== lastError.start) {
2119+
if (message.category === DiagnosticCategory.Message && lastError && start === lastError.start && length === lastError.length) {
2120+
result = createDetachedDiagnostic(fileName, sourceText, start, length, message, ...args);
2121+
addRelatedInfo(lastError, result);
2122+
}
2123+
else if (!lastError || start !== lastError.start) {
21182124
result = createDetachedDiagnostic(fileName, sourceText, start, length, message, ...args);
21192125
parseDiagnostics.push(result);
21202126
}
@@ -2370,7 +2376,7 @@ namespace Parser {
23702376
}
23712377

23722378
// The user alternatively might have misspelled or forgotten to add a space after a common keyword.
2373-
const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, n => n) ?? getSpaceSuggestion(expressionText);
2379+
const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, identity) ?? getSpaceSuggestion(expressionText);
23742380
if (suggestion) {
23752381
parseErrorAt(pos, node.end, Diagnostics.Unknown_keyword_or_identifier_Did_you_mean_0, suggestion);
23762382
return;

src/compiler/scanner.ts

+13
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
DiagnosticMessage,
1313
Diagnostics,
1414
forEach,
15+
getSpellingSuggestion,
1516
identity,
1617
JSDocSyntaxKind,
1718
JsxTokenSyntaxKind,
@@ -3302,6 +3303,10 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
33023303
}
33033304
else if (propertyName === undefined) {
33043305
error(Diagnostics.Unknown_Unicode_property_name, propertyNameOrValueStart, pos - propertyNameOrValueStart);
3306+
const suggestion = getSpellingSuggestion(propertyNameOrValue, nonBinaryUnicodeProperties.keys(), identity);
3307+
if (suggestion) {
3308+
error(Diagnostics.Did_you_mean_0, propertyNameOrValueStart, pos - propertyNameOrValueStart, suggestion);
3309+
}
33053310
}
33063311
pos++;
33073312
const propertyValueStart = pos;
@@ -3311,6 +3316,10 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
33113316
}
33123317
else if (propertyName !== undefined && !valuesOfNonBinaryUnicodeProperties[propertyName].has(propertyValue)) {
33133318
error(Diagnostics.Unknown_Unicode_property_value, propertyValueStart, pos - propertyValueStart);
3319+
const suggestion = getSpellingSuggestion(propertyValue, valuesOfNonBinaryUnicodeProperties[propertyName], identity);
3320+
if (suggestion) {
3321+
error(Diagnostics.Did_you_mean_0, propertyValueStart, pos - propertyValueStart, suggestion);
3322+
}
33143323
}
33153324
}
33163325
else {
@@ -3330,6 +3339,10 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
33303339
}
33313340
else if (!valuesOfNonBinaryUnicodeProperties.General_Category.has(propertyNameOrValue) && !binaryUnicodeProperties.has(propertyNameOrValue)) {
33323341
error(Diagnostics.Unknown_Unicode_property_name_or_value, propertyNameOrValueStart, pos - propertyNameOrValueStart);
3342+
const suggestion = getSpellingSuggestion(propertyNameOrValue, [...valuesOfNonBinaryUnicodeProperties.General_Category, ...binaryUnicodeProperties, ...binaryUnicodePropertiesOfStrings], identity);
3343+
if (suggestion) {
3344+
error(Diagnostics.Did_you_mean_0, propertyNameOrValueStart, pos - propertyNameOrValueStart, suggestion);
3345+
}
33333346
}
33343347
}
33353348
scanExpectedChar(CharacterCodes.closeBrace);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
regularExpressionUnicodePropertyValueExpressionSuggestions.ts(1,19): error TS1527: Unknown Unicode property name or value.
2+
regularExpressionUnicodePropertyValueExpressionSuggestions.ts(1,28): error TS1522: Unknown Unicode property name.
3+
regularExpressionUnicodePropertyValueExpressionSuggestions.ts(1,45): error TS1524: Unknown Unicode property value.
4+
regularExpressionUnicodePropertyValueExpressionSuggestions.ts(1,55): error TS1499: This regular expression flag is only available when targeting 'ES2015' or later.
5+
6+
7+
==== regularExpressionUnicodePropertyValueExpressionSuggestions.ts (4 errors) ====
8+
const regex = /\p{ascii}\p{Sc=Unknown}\p{sc=unknownX}/u;
9+
~~~~~
10+
!!! error TS1527: Unknown Unicode property name or value.
11+
!!! related TS1369 regularExpressionUnicodePropertyValueExpressionSuggestions.ts:1:19: Did you mean 'ASCII'?
12+
~~
13+
!!! error TS1522: Unknown Unicode property name.
14+
!!! related TS1369 regularExpressionUnicodePropertyValueExpressionSuggestions.ts:1:28: Did you mean 'sc'?
15+
~~~~~~~~
16+
!!! error TS1524: Unknown Unicode property value.
17+
!!! related TS1369 regularExpressionUnicodePropertyValueExpressionSuggestions.ts:1:45: Did you mean 'Unknown'?
18+
~
19+
!!! error TS1499: This regular expression flag is only available when targeting 'ES2015' or later.
20+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//// [tests/cases/compiler/regularExpressionUnicodePropertyValueExpressionSuggestions.ts] ////
2+
3+
//// [regularExpressionUnicodePropertyValueExpressionSuggestions.ts]
4+
const regex = /\p{ascii}\p{Sc=Unknown}\p{sc=unknownX}/u;
5+
6+
7+
//// [regularExpressionUnicodePropertyValueExpressionSuggestions.js]
8+
var regex = /\p{ascii}\p{Sc=Unknown}\p{sc=unknownX}/u;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//// [tests/cases/compiler/regularExpressionUnicodePropertyValueExpressionSuggestions.ts] ////
2+
3+
=== regularExpressionUnicodePropertyValueExpressionSuggestions.ts ===
4+
const regex = /\p{ascii}\p{Sc=Unknown}\p{sc=unknownX}/u;
5+
>regex : Symbol(regex, Decl(regularExpressionUnicodePropertyValueExpressionSuggestions.ts, 0, 5))
6+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//// [tests/cases/compiler/regularExpressionUnicodePropertyValueExpressionSuggestions.ts] ////
2+
3+
=== regularExpressionUnicodePropertyValueExpressionSuggestions.ts ===
4+
const regex = /\p{ascii}\p{Sc=Unknown}\p{sc=unknownX}/u;
5+
>regex : RegExp
6+
>/\p{ascii}\p{Sc=Unknown}\p{sc=unknownX}/u : RegExp
7+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
const regex = /\p{ascii}\p{Sc=Unknown}\p{sc=unknownX}/u;

0 commit comments

Comments
 (0)