Skip to content

Commit

Permalink
Provide Syntax Checking for Regular Expressions (#55600)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>
Co-authored-by: Jake Bailey <5341706+jakebailey@users.noreply.github.com>
  • Loading branch information
3 people authored Apr 19, 2024
1 parent 8e8c1b6 commit 42f238b
Show file tree
Hide file tree
Showing 1,100 changed files with 8,941 additions and 4,333 deletions.
2 changes: 1 addition & 1 deletion src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2289,7 +2289,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
148 changes: 148 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1649,6 +1649,154 @@
"category": "Error",
"code": 1498
},
"Unknown regular expression flag.": {
"category": "Error",
"code": 1499
},
"Duplicate regular expression flag.": {
"category": "Error",
"code": 1500
},
"This regular expression flag is only available when targeting '{0}' or later.": {
"category": "Error",
"code": 1501
},
"The Unicode (u) flag and the Unicode Sets (v) flag cannot be set simultaneously.": {
"category": "Error",
"code": 1502
},
"Named capturing groups are only available when targeting 'ES2018' or later.": {
"category": "Error",
"code": 1503
},
"Subpattern flags must be present when there is a minus sign.": {
"category": "Error",
"code": 1504
},
"Incomplete quantifier. Digit expected.": {
"category": "Error",
"code": 1505
},
"Numbers out of order in quantifier.": {
"category": "Error",
"code": 1506
},
"There is nothing available for repetition.": {
"category": "Error",
"code": 1507
},
"Unexpected '{0}'. Did you mean to escape it with backslash?": {
"category": "Error",
"code": 1508
},
"This regular expression flag cannot be toggled within a subpattern.": {
"category": "Error",
"code": 1509
},
"'\\k' must be followed by a capturing group name enclosed in angle brackets.": {
"category": "Error",
"code": 1510
},
"'\\q' is only available inside character class.": {
"category": "Error",
"code": 1511
},
"'\\c' must be followed by an ASCII letter.": {
"category": "Error",
"code": 1512
},
"Undetermined character escape.": {
"category": "Error",
"code": 1513
},
"Expected a capturing group name.": {
"category": "Error",
"code": 1514
},
"Named capturing groups with the same name must be mutually exclusive to each other.": {
"category": "Error",
"code": 1515
},
"A character class range must not be bounded by another character class.": {
"category": "Error",
"code": 1516
},
"Range out of order in character class.": {
"category": "Error",
"code": 1517
},
"Anything that would possibly match more than a single character is invalid inside a negated character class.": {
"category": "Error",
"code": 1518
},
"Operators must not be mixed within a character class. Wrap it in a nested class instead.": {
"category": "Error",
"code": 1519
},
"Expected a class set oprand.": {
"category": "Error",
"code": 1520
},
"'\\q' must be followed by string alternatives enclosed in braces.": {
"category": "Error",
"code": 1521
},
"A character class must not contain a reserved double punctuator. Did you mean to escape it with backslash?": {
"category": "Error",
"code": 1522
},
"Expected a Unicode property name.": {
"category": "Error",
"code": 1523
},
"Unknown Unicode property name.": {
"category": "Error",
"code": 1524
},
"Expected a Unicode property value.": {
"category": "Error",
"code": 1525
},
"Unknown Unicode property value.": {
"category": "Error",
"code": 1526
},
"Expected a Unicode property name or value.": {
"category": "Error",
"code": 1527
},
"Any Unicode property that would possibly match more than a single character is only available when the Unicode Sets (v) flag is set.": {
"category": "Error",
"code": 1528
},
"Unknown Unicode property name or value.": {
"category": "Error",
"code": 1529
},
"Unicode property value expressions are only available when the Unicode (u) flag or the Unicode Sets (v) flag is set.": {
"category": "Error",
"code": 1530
},
"'\\{0}' must be followed by a Unicode property value expression enclosed in braces.": {
"category": "Error",
"code": 1531
},
"There is no capturing group named '{0}' in this regular expression.": {
"category": "Error",
"code": 1532
},
"A decimal escape must refer to an existent capturing group. There are only {0} capturing groups in this regular expression.": {
"category": "Error",
"code": 1533
},
"Decimal escapes are invalid when there are no capturing groups in a regular expression.": {
"category": "Error",
"code": 1534
},
"This character cannot be escaped in a regular expression.": {
"category": "Error",
"code": 1535
},

"The types of '{0}' are incompatible between these types.": {
"category": "Error",
Expand Down
10 changes: 8 additions & 2 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import {
DeleteExpression,
Diagnostic,
DiagnosticArguments,
DiagnosticCategory,
DiagnosticMessage,
Diagnostics,
DiagnosticWithDetachedLocation,
Expand Down Expand Up @@ -113,6 +114,7 @@ import {
HasModifiers,
HeritageClause,
Identifier,
identity,
idText,
IfStatement,
ImportAttribute,
Expand Down Expand Up @@ -2142,7 +2144,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 @@ -2398,7 +2404,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
4 changes: 2 additions & 2 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ import {
getLineStarts,
getMatchedFileSpec,
getMatchedIncludeSpec,
getNameOfScriptTarget,
getNewLineCharacter,
getNormalizedAbsolutePath,
getNormalizedAbsolutePathWithoutRoot,
Expand Down Expand Up @@ -307,7 +308,6 @@ import {
SyntaxKind,
sys,
System,
targetOptionDeclaration,
toFileNameLowerCase,
tokenToString,
toPath as ts_toPath,
Expand Down Expand Up @@ -4780,7 +4780,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
message = Diagnostics.File_is_library_specified_here;
break;
}
const target = forEachEntry(targetOptionDeclaration.type, (value, key) => value === getEmitScriptTarget(options) ? key : undefined);
const target = getNameOfScriptTarget(getEmitScriptTarget(options));
configFileNode = target ? getOptionsSyntaxByValue("target", target) : undefined;
message = Diagnostics.File_is_default_library_for_target_specified_here;
break;
Expand Down
Loading

0 comments on commit 42f238b

Please sign in to comment.