Skip to content

Commit

Permalink
Provide Spelling Suggestions for Unicode Property Value Expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
graphemecluster committed Sep 1, 2023
1 parent fefcf29 commit 1a5228d
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2322,7 +2322,7 @@ export function compareBooleans(a: boolean, b: boolean): Comparison {
*
* @internal
*/
export function getSpellingSuggestion<T>(name: string, candidates: T[], getName: (candidate: T) => string | undefined): T | undefined {
export function getSpellingSuggestion<T>(name: string, candidates: Iterable<T>, getName: (candidate: T) => string | undefined): T | undefined {
const maximumLengthDifference = Math.max(2, Math.floor(name.length * 0.34));
let bestDistance = Math.floor(name.length * 0.4) + 1; // If the best result is worse than this, don't bother.
let bestCandidate: T | undefined;
Expand Down
10 changes: 8 additions & 2 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import {
DeleteExpression,
Diagnostic,
DiagnosticArguments,
DiagnosticCategory,
DiagnosticMessage,
Diagnostics,
DiagnosticWithDetachedLocation,
Expand Down Expand Up @@ -115,6 +116,7 @@ import {
HasModifiers,
HeritageClause,
Identifier,
identity,
idText,
IfStatement,
ImportClause,
Expand Down Expand Up @@ -2114,7 +2116,11 @@ namespace Parser {
// Don't report another error if it would just be at the same position as the last error.
const lastError = lastOrUndefined(parseDiagnostics);
let result: DiagnosticWithDetachedLocation | undefined;
if (!lastError || start !== lastError.start) {
if (message.category === DiagnosticCategory.Message && lastError && start === lastError.start && length === lastError.length) {
result = createDetachedDiagnostic(fileName, sourceText, start, length, message, ...args);
addRelatedInfo(lastError, result);
}
else if (!lastError || start !== lastError.start) {
result = createDetachedDiagnostic(fileName, sourceText, start, length, message, ...args);
parseDiagnostics.push(result);
}
Expand Down Expand Up @@ -2370,7 +2376,7 @@ namespace Parser {
}

// The user alternatively might have misspelled or forgotten to add a space after a common keyword.
const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, n => n) ?? getSpaceSuggestion(expressionText);
const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, identity) ?? getSpaceSuggestion(expressionText);
if (suggestion) {
parseErrorAt(pos, node.end, Diagnostics.Unknown_keyword_or_identifier_Did_you_mean_0, suggestion);
return;
Expand Down
13 changes: 13 additions & 0 deletions src/compiler/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
DiagnosticMessage,
Diagnostics,
forEach,
getSpellingSuggestion,
identity,
JSDocSyntaxKind,
JsxTokenSyntaxKind,
Expand Down Expand Up @@ -3302,6 +3303,10 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
}
else if (propertyName === undefined) {
error(Diagnostics.Unknown_Unicode_property_name, propertyNameOrValueStart, pos - propertyNameOrValueStart);
const suggestion = getSpellingSuggestion(propertyNameOrValue, nonBinaryUnicodeProperties.keys(), identity);
if (suggestion) {
error(Diagnostics.Did_you_mean_0, propertyNameOrValueStart, pos - propertyNameOrValueStart, suggestion);
}
}
pos++;
const propertyValueStart = pos;
Expand All @@ -3311,6 +3316,10 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
}
else if (propertyName !== undefined && !valuesOfNonBinaryUnicodeProperties[propertyName].has(propertyValue)) {
error(Diagnostics.Unknown_Unicode_property_value, propertyValueStart, pos - propertyValueStart);
const suggestion = getSpellingSuggestion(propertyValue, valuesOfNonBinaryUnicodeProperties[propertyName], identity);
if (suggestion) {
error(Diagnostics.Did_you_mean_0, propertyValueStart, pos - propertyValueStart, suggestion);
}
}
}
else {
Expand All @@ -3330,6 +3339,10 @@ export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean
}
else if (!valuesOfNonBinaryUnicodeProperties.General_Category.has(propertyNameOrValue) && !binaryUnicodeProperties.has(propertyNameOrValue)) {
error(Diagnostics.Unknown_Unicode_property_name_or_value, propertyNameOrValueStart, pos - propertyNameOrValueStart);
const suggestion = getSpellingSuggestion(propertyNameOrValue, [...valuesOfNonBinaryUnicodeProperties.General_Category, ...binaryUnicodeProperties, ...binaryUnicodePropertiesOfStrings], identity);
if (suggestion) {
error(Diagnostics.Did_you_mean_0, propertyNameOrValueStart, pos - propertyNameOrValueStart, suggestion);
}
}
}
scanExpectedChar(CharacterCodes.closeBrace);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
regularExpressionUnicodePropertyValueExpressionSuggestions.ts(1,19): error TS1527: Unknown Unicode property name or value.
regularExpressionUnicodePropertyValueExpressionSuggestions.ts(1,28): error TS1522: Unknown Unicode property name.
regularExpressionUnicodePropertyValueExpressionSuggestions.ts(1,45): error TS1524: Unknown Unicode property value.
regularExpressionUnicodePropertyValueExpressionSuggestions.ts(1,55): error TS1499: This regular expression flag is only available when targeting 'ES2015' or later.


==== regularExpressionUnicodePropertyValueExpressionSuggestions.ts (4 errors) ====
const regex = /\p{ascii}\p{Sc=Unknown}\p{sc=unknownX}/u;
~~~~~
!!! error TS1527: Unknown Unicode property name or value.
!!! related TS1369 regularExpressionUnicodePropertyValueExpressionSuggestions.ts:1:19: Did you mean 'ASCII'?
~~
!!! error TS1522: Unknown Unicode property name.
!!! related TS1369 regularExpressionUnicodePropertyValueExpressionSuggestions.ts:1:28: Did you mean 'sc'?
~~~~~~~~
!!! error TS1524: Unknown Unicode property value.
!!! related TS1369 regularExpressionUnicodePropertyValueExpressionSuggestions.ts:1:45: Did you mean 'Unknown'?
~
!!! error TS1499: This regular expression flag is only available when targeting 'ES2015' or later.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//// [tests/cases/compiler/regularExpressionUnicodePropertyValueExpressionSuggestions.ts] ////

//// [regularExpressionUnicodePropertyValueExpressionSuggestions.ts]
const regex = /\p{ascii}\p{Sc=Unknown}\p{sc=unknownX}/u;


//// [regularExpressionUnicodePropertyValueExpressionSuggestions.js]
var regex = /\p{ascii}\p{Sc=Unknown}\p{sc=unknownX}/u;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//// [tests/cases/compiler/regularExpressionUnicodePropertyValueExpressionSuggestions.ts] ////

=== regularExpressionUnicodePropertyValueExpressionSuggestions.ts ===
const regex = /\p{ascii}\p{Sc=Unknown}\p{sc=unknownX}/u;
>regex : Symbol(regex, Decl(regularExpressionUnicodePropertyValueExpressionSuggestions.ts, 0, 5))

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//// [tests/cases/compiler/regularExpressionUnicodePropertyValueExpressionSuggestions.ts] ////

=== regularExpressionUnicodePropertyValueExpressionSuggestions.ts ===
const regex = /\p{ascii}\p{Sc=Unknown}\p{sc=unknownX}/u;
>regex : RegExp
>/\p{ascii}\p{Sc=Unknown}\p{sc=unknownX}/u : RegExp

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const regex = /\p{ascii}\p{Sc=Unknown}\p{sc=unknownX}/u;

0 comments on commit 1a5228d

Please sign in to comment.