Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c44a057
Type Inference for Regular Expressions
graphemecluster Oct 17, 2024
c435526
Fix Incorrect Disjunction Alternative Visibility
graphemecluster Nov 4, 2024
24c16f9
Add Test Cases for Duplicate Capturing Group Name
graphemecluster Nov 4, 2024
13cfe15
Performance optimization: Reduce type creation
graphemecluster Nov 6, 2024
6aeac05
Fix incorrect type for `/{0?/` etc. in non-Unicode mode
graphemecluster Nov 7, 2024
b828249
Fix: `i` modifier is not removed if no flags are added
graphemecluster Nov 7, 2024
bd74623
Remove more redundant literals esp. `"" | string`
graphemecluster Nov 7, 2024
a6e0b98
Fix: Incorrect characters included for `/\c/` & `/[\c]/` in Annex B
graphemecluster Nov 8, 2024
a31ddcb
Refactor: Rename variables and modify type of reduced union
graphemecluster Nov 8, 2024
42a6568
Refactor: Fast path character classes
graphemecluster Nov 9, 2024
9ce54aa
Refine types for cases where the cross product size is too large
graphemecluster Nov 9, 2024
bb0e808
Refactor: Type `RegularExpressionAnyString` as a unique symbol for be…
graphemecluster Nov 9, 2024
524f291
Expand test cases in `regularExpressionLiteralTypes.ts`
graphemecluster Nov 9, 2024
48f86ff
Fix: missing `"-"` in `/[+-]/`
graphemecluster Nov 9, 2024
3ddc5da
Mark `RegExpDigits` as character class (for fast path)
graphemecluster Nov 9, 2024
9dc953c
Correct lib types & Refine type checking test case
graphemecluster Nov 10, 2024
0cf763d
Separate type checking test case into 2 files which tests for differe…
graphemecluster Nov 10, 2024
53425e5
Add test case for `String#matchAll`
graphemecluster Nov 10, 2024
12e875b
Collapse consecutive string types in template literals
graphemecluster Nov 10, 2024
5dfdb56
Merge remote-tracking branch 'upstream/main' into regex-type-infer
graphemecluster Nov 10, 2024
09ad9c3
Fix up all baselines
graphemecluster Nov 10, 2024
61fc428
Fix up all self check errors
graphemecluster Nov 10, 2024
402760c
Separate the type checking test case further
graphemecluster Nov 10, 2024
99355c0
Temporarily exclude `RegExp` & `RegExpExecArray` from `checkNoTypeArg…
graphemecluster Nov 10, 2024
80dd5d0
Revert "Temporarily exclude `RegExp` & `RegExpExecArray` from `checkN…
graphemecluster Nov 10, 2024
b251992
Fix self check in a more ugly way due to build issue
graphemecluster Nov 10, 2024
5bd7951
Temporarily slience a few `no-unnecessary-type-assertion` lint lines …
graphemecluster Nov 10, 2024
037ef8e
Fix minor incorrect fix in self check
graphemecluster Nov 10, 2024
e51e144
Temporarily shrink type checking test case due to timeout
graphemecluster Nov 10, 2024
2989429
Inline `RegularExpressionAnyString` to avoid `export` keywords in `ty…
graphemecluster Nov 12, 2024
8cc6840
Keep `RegularExpressionAnyString` but export as internal
graphemecluster Nov 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix up all self check errors
  • Loading branch information
graphemecluster committed Nov 10, 2024
commit 61fc428906e39f2cffed3a7b7df971b41fcad7d5
8 changes: 4 additions & 4 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10689,9 +10689,9 @@ function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, te
return; // Missing required argument, don't parse
}
else if (matchResult) {
const value = matchResult[2] || matchResult[3];
const value = (matchResult[2] || matchResult[3])!;
if (arg.captureSpan) {
const startPos = range.pos + matchResult.index + matchResult[1].length + 1;
const startPos = range.pos + matchResult.index + matchResult[1]!.length + 1;
argument[arg.name] = {
value,
pos: startPos,
Expand All @@ -10718,14 +10718,14 @@ function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, te

if (range.kind === SyntaxKind.MultiLineCommentTrivia) {
const multiLinePragmaRegEx = /@(\S+)(\s+(?:\S.*)?)?$/gm; // Defined inline since it uses the "g" flag, which keeps a persistent index (for iterating)
let multiLineMatch: RegExpExecArray | null; // eslint-disable-line no-restricted-syntax
let multiLineMatch: RegExpExecArray<[string, string, string | undefined]> | null; // eslint-disable-line no-restricted-syntax
while (multiLineMatch = multiLinePragmaRegEx.exec(text)) {
addPragmaForMatch(pragmas, range, PragmaKindFlags.MultiLine, multiLineMatch);
}
}
}

function addPragmaForMatch(pragmas: PragmaPseudoMapEntry[], range: CommentRange, kind: PragmaKindFlags, match: RegExpExecArray) {
function addPragmaForMatch(pragmas: PragmaPseudoMapEntry[], range: CommentRange, kind: PragmaKindFlags, match: RegExpExecArray<[string, string, string | undefined]>) {
if (!match) return;
const name = match[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so they below check to make it safe typechecks
const pragma = commentPragmas[name] as PragmaDefinition;
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/semver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ function parseHyphen(left: string, right: string, comparators: Comparator[]) {
return true;
}

function parseComparator(operator: string, text: string, comparators: Comparator[]) {
function parseComparator(operator: string | undefined, text: string, comparators: Comparator[]) {
const result = parsePartial(text);
if (!result) return false;

Expand Down
6 changes: 3 additions & 3 deletions src/compiler/sourcemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,12 +360,12 @@ export function createSourceMapGenerator(host: EmitHost, file: string, sourceRoo

// Sometimes tools can see the following line as a source mapping url comment, so we mangle it a bit (the [M])
/** @internal */
export const sourceMapCommentRegExpDontCareLineStart: RegExp = /\/\/[@#] source[M]appingURL=(.+)\r?\n?$/; // eslint-disable-line regexp/no-useless-character-class
export const sourceMapCommentRegExpDontCareLineStart: RegExp<[string, string]> = /\/\/[@#] source[M]appingURL=(.+)\r?\n?$/; // eslint-disable-line regexp/no-useless-character-class
/** @internal */
export const sourceMapCommentRegExp: RegExp = /^\/\/[@#] source[M]appingURL=(.+)\r?\n?$/; // eslint-disable-line regexp/no-useless-character-class
export const sourceMapCommentRegExp: RegExp<[string, string]> = /^\/\/[@#] source[M]appingURL=(.+)\r?\n?$/; // eslint-disable-line regexp/no-useless-character-class

/** @internal */
export const whitespaceOrMapCommentRegExp: RegExp = /^\s*(\/\/[@#] .*)?$/;
export const whitespaceOrMapCommentRegExp: RegExp<[string, string | undefined]> = /^\s*(\/\/[@#] .*)?$/;

/** @internal */
export interface LineInfo {
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/transformers/jsx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -619,15 +619,15 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B
* See https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
*/
function decodeEntities(text: string): string {
return text.replace(/&((#((\d+)|x([\da-fA-F]+)))|(\w+));/g, (match, _all, _number, _digits, decimal, hex, word) => {
return text.replace(/&(?:(#(?:\d+|x([\da-fA-F]+)))|(\w+));/g, (match, decimal, hex, word) => {
if (decimal) {
return utf16EncodeAsString(parseInt(decimal, 10));
}
else if (hex) {
return utf16EncodeAsString(parseInt(hex, 16));
}
else {
const ch = entities.get(word);
const ch = entities.get(word || "");
// If this is not a valid entity, then just use `match` (replace it with itself, i.e. don't replace)
return ch ? utf16EncodeAsString(ch) : match;
}
Expand Down
10 changes: 5 additions & 5 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6063,10 +6063,10 @@ export function hasInvalidEscape(template: TemplateLiteral): boolean {
// the language service. These characters should be escaped when printing, and if any characters are added,
// the map below must be updated. Note that this regexp *does not* include the 'delete' character.
// There is no reason for this other than that JSON.stringify does not handle it either.
const doubleQuoteEscapedCharsRegExp = /[\\"\u0000-\u001f\u2028\u2029\u0085]/g;
const singleQuoteEscapedCharsRegExp = /[\\'\u0000-\u001f\u2028\u2029\u0085]/g;
const doubleQuoteEscapedCharsRegExp: RegExp<[string]> = /[\\"\u0000-\u001f\u2028\u2029\u0085]/g;
const singleQuoteEscapedCharsRegExp: RegExp<[string]> = /[\\'\u0000-\u001f\u2028\u2029\u0085]/g;
// Template strings preserve simple LF newlines, still encode CRLF (or CR)
const backtickQuoteEscapedCharsRegExp = /\r\n|[\\`\u0000-\u0009\u000b-\u001f\u2028\u2029\u0085]/g;
const backtickQuoteEscapedCharsRegExp: RegExp<[string]> = /\r\n|[\\`\u0000-\u0009\u000b-\u001f\u2028\u2029\u0085]/g;
const escapedCharsMap = new Map(Object.entries({
"\t": "\\t",
"\v": "\\v",
Expand Down Expand Up @@ -6132,8 +6132,8 @@ export function escapeNonAsciiString(s: string, quoteChar?: CharacterCodes.doubl
// paragraphSeparator, and nextLine. The latter three are just desirable to suppress new lines in
// the language service. These characters should be escaped when printing, and if any characters are added,
// the map below must be updated.
const jsxDoubleQuoteEscapedCharsRegExp = /["\u0000-\u001f\u2028\u2029\u0085]/g;
const jsxSingleQuoteEscapedCharsRegExp = /['\u0000-\u001f\u2028\u2029\u0085]/g;
const jsxDoubleQuoteEscapedCharsRegExp: RegExp<[string]> = /["\u0000-\u001f\u2028\u2029\u0085]/g;
const jsxSingleQuoteEscapedCharsRegExp: RegExp<[string]> = /['\u0000-\u001f\u2028\u2029\u0085]/g;
const jsxEscapedCharsMap = new Map(Object.entries({
'"': "&quot;",
"'": "&apos;",
Expand Down
4 changes: 2 additions & 2 deletions src/harness/harnessIO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,7 @@ export namespace TestCaseParser {
export function extractCompilerSettings(content: string): CompilerSettings {
const opts: CompilerSettings = {};

let match: RegExpExecArray | null; // eslint-disable-line no-restricted-syntax
let match: RegExpExecArray<[string, string, string]> | null; // eslint-disable-line no-restricted-syntax
while ((match = optionRegex.exec(content)) !== null) { // eslint-disable-line no-restricted-syntax
opts[match[1]] = match[2].trim();
}
Expand Down Expand Up @@ -1319,7 +1319,7 @@ export namespace TestCaseParser {
let symlinks: vfs.FileSet | undefined;

for (const line of lines) {
let testMetaData: RegExpExecArray | null; // eslint-disable-line no-restricted-syntax
let testMetaData: RegExpExecArray<[string, string, string]> | null; // eslint-disable-line no-restricted-syntax
const possiblySymlinks = parseSymlinkFromTest(line, symlinks, vfs.srcFolder);
if (possiblySymlinks) {
symlinks = possiblySymlinks;
Expand Down
2 changes: 1 addition & 1 deletion src/harness/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function createDiagnosticMessageReplacer<R extends (messageArgs: string[], ...ar
const messageParts = diagnosticMessage.message.split(/\{\d+\}/);
const regExp = new RegExp(`^(?:${messageParts.map(ts.regExpEscape).join("(.*?)")})$`);
type Args<R> = R extends (messageArgs: string[], ...args: infer A) => string[] ? A : [];
return (text: string, ...args: Args<R>) => text.replace(regExp, (_, ...fixedArgs) => ts.formatStringFromArgs(diagnosticMessage.message, replacer(fixedArgs, ...args)));
return (text: string, ...args: Args<R>) => text.replace(regExp, (_, ...fixedArgs) => ts.formatStringFromArgs(diagnosticMessage.message, replacer(fixedArgs as string[], ...args)));
}

const replaceTypesVersionsMessage = createDiagnosticMessageReplacer(
Expand Down
6 changes: 3 additions & 3 deletions src/server/editorServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5249,18 +5249,18 @@ export class ProjectService {

if (rule.exclude) {
for (const exclude of rule.exclude) {
const processedRule = root.replace(rule.match, (...groups: string[]) => {
const processedRule = root.replace(rule.match, (...groups) => {
return exclude.map(groupNumberOrString => {
// RegExp group numbers are 1-based, but the first element in groups
// is actually the original string, so it all works out in the end.
if (typeof groupNumberOrString === "number") {
if (!isString(groups[groupNumberOrString])) {
if (!isString((groups as string[])[groupNumberOrString])) {
// Specification was wrong - exclude nothing!
this.logger.info(`Incorrect RegExp specification in safelist rule ${name} - not enough groups`);
// * can't appear in a filename; escape it because it's feeding into a RegExp
return "\\*";
}
return ProjectService.escapeFilenameForRegex(groups[groupNumberOrString]);
return ProjectService.escapeFilenameForRegex((groups as string[])[groupNumberOrString]);
}
return groupNumberOrString;
}).join("");
Expand Down
4 changes: 2 additions & 2 deletions src/services/classifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -957,7 +957,7 @@ export function getEncodedSyntacticClassifications(cancellationToken: Cancellati
pushClassification(pos, match[3].length, ClassificationType.jsxSelfClosingTagName); // element name
pos += match[3].length;

const attrText = match[4];
const attrText = match[4] || "";
let attrPos = pos;
while (true) {
const attrMatch = attributeRegex.exec(attrText);
Expand Down Expand Up @@ -991,7 +991,7 @@ export function getEncodedSyntacticClassifications(cancellationToken: Cancellati
attrPos += attrMatch[6].length;
}

pos += match[4].length;
pos += attrText.length;

if (pos > attrPos) {
pushCommentRange(attrPos, pos - attrPos);
Expand Down
2 changes: 1 addition & 1 deletion src/services/codefixes/fixAddMissingConstraint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ function addMissingConstraint(changes: textChanges.ChangeTracker, program: Progr

function tryGetConstraintFromDiagnosticMessage(messageText: string | DiagnosticMessageChain) {
const [, constraint] = flattenDiagnosticMessageText(messageText, "\n", 0).match(/`extends (.*)`/) || [];
return constraint;
return constraint || "";
}

function tryGetConstraintType(checker: TypeChecker, node: Node) {
Expand Down
2 changes: 1 addition & 1 deletion src/services/codefixes/fixNaNEquality.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,5 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, ar

function getSuggestion(messageText: string | DiagnosticMessageChain) {
const [, suggestion] = flattenDiagnosticMessageText(messageText, "\n", 0).match(/'(.*)'/) || [];
return suggestion;
return suggestion || "";
}
4 changes: 2 additions & 2 deletions src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3153,7 +3153,7 @@ export function createLanguageService(
const firstDescriptorCaptureIndex = 3;
Debug.assert(matchArray.length === descriptors.length + firstDescriptorCaptureIndex);

const preamble = matchArray[1];
const preamble = matchArray[1]!;
const matchPosition = matchArray.index + preamble.length;

// OK, we have found a match in the file. This is only an acceptable match if
Expand All @@ -3176,7 +3176,7 @@ export function createLanguageService(
continue;
}

const message = matchArray[2];
const message = matchArray[2]!;
result.push({ descriptor, message, position: matchPosition });
}
}
Expand Down