-
-
Save davidgomes/5cb71342b6d2cf95ffa05a767eb802c7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts | |
index a10c2cbd6d..10a9ae5f1a 100644 | |
--- a/src/compiler/parser.ts | |
+++ b/src/compiler/parser.ts | |
@@ -8190,9 +8190,14 @@ namespace ts { | |
for (const range of getLeadingCommentRanges(sourceText, 0) || emptyArray) { | |
const comment = sourceText.substring(range.pos, range.end); | |
- extractPragmas(pragmas, range, comment); | |
+ extractPragmas(pragmas, range, comment, PragmaKindFlags.TripleSlashXML | PragmaKindFlags.SingleLine | PragmaKindFlags.MultiLine); | |
} | |
+ iterateAllCommentRanges(sourceText, (range) => { | |
+ const comment = sourceText.substring(range.pos, range.end); | |
+ extractPragmas(pragmas, range, comment, PragmaKindFlags.AnySingleLine); | |
+ }); | |
+ | |
context.pragmas = createMap() as PragmaMap; | |
for (const pragma of pragmas) { | |
if (context.pragmas.has(pragma.name)) { | |
@@ -8284,6 +8289,14 @@ namespace ts { | |
break; | |
} | |
case "jsx": return; // Accessed directly | |
+ case "ts-expect-error": { | |
+ console.log("parser.ts"); | |
+ console.log(entryOrList); | |
+ console.log(key); | |
+ console.log("found ts-expect-error"); | |
+ console.log("parser.ts over"); | |
+ break; | |
+ } | |
default: Debug.fail("Unhandled pragma kind"); // Can this be made into an assertNever in the future? | |
} | |
}); | |
@@ -8301,12 +8314,12 @@ namespace ts { | |
const tripleSlashXMLCommentStartRegEx = /^\/\/\/\s*<(\S+)\s.*?\/>/im; | |
const singleLinePragmaRegEx = /^\/\/\/?\s*@(\S+)\s*(.*)\s*$/im; | |
- function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, text: string) { | |
+ function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, text: string, kind: PragmaKindFlags) { | |
const tripleSlash = range.kind === SyntaxKind.SingleLineCommentTrivia && tripleSlashXMLCommentStartRegEx.exec(text); | |
if (tripleSlash) { | |
const name = tripleSlash[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so the below check to make it safe typechecks | |
const pragma = commentPragmas[name] as PragmaDefinition; | |
- if (!pragma || !(pragma.kind! & PragmaKindFlags.TripleSlashXML)) { | |
+ if (!pragma || !(pragma.kind! & PragmaKindFlags.TripleSlashXML) || !(pragma.kind! & kind)) { | |
return; | |
} | |
if (pragma.args) { | |
@@ -8341,7 +8354,11 @@ namespace ts { | |
const singleLine = range.kind === SyntaxKind.SingleLineCommentTrivia && singleLinePragmaRegEx.exec(text); | |
if (singleLine) { | |
- return addPragmaForMatch(pragmas, range, PragmaKindFlags.SingleLine, singleLine); | |
+ if (kind & PragmaKindFlags.SingleLine) { | |
+ return addPragmaForMatch(pragmas, range, PragmaKindFlags.SingleLine, singleLine); | |
+ } else if (kind & PragmaKindFlags.AnySingleLine) { | |
+ return addPragmaForMatch(pragmas, range, PragmaKindFlags.AnySingleLine, singleLine); | |
+ } | |
} | |
if (range.kind === SyntaxKind.MultiLineCommentTrivia) { | |
diff --git a/src/compiler/program.ts b/src/compiler/program.ts | |
index fc6b855225..68924e6beb 100644 | |
--- a/src/compiler/program.ts | |
+++ b/src/compiler/program.ts | |
@@ -1654,13 +1654,31 @@ namespace ts { | |
for (const diags of [fileProcessingDiagnosticsInFile, programDiagnosticsInFile]) { | |
if (diags) { | |
for (const diag of diags) { | |
+ console.log(diag); | |
if (shouldReportDiagnostic(diag)) { | |
diagnostics = append(diagnostics, diag); | |
} | |
} | |
} | |
} | |
- return diagnostics || emptyArray; | |
+ | |
+ diagnostics = diagnostics || emptyArray; | |
+ | |
+ const expectedErrors = sourceFile.pragmas.get("ts-expect-error") as PragmaPseudoMap["ts-expect-error"][] | undefined; | |
+ if (expectedErrors) { | |
+ console.log("getProgramDianostics"); | |
+ console.log(sourceFile.fileName); | |
+ console.log(diagnostics); | |
+ | |
+ for (const expectedError of expectedErrors) { | |
+ console.log(expectedError); | |
+ findExpectedError(expectedError, sourceFile, diagnostics); | |
+ } | |
+ } | |
+ | |
+ console.log(diagnostics); | |
+ | |
+ return diagnostics; | |
} | |
function getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[] { | |
@@ -1762,6 +1780,8 @@ namespace ts { | |
* Skip errors if previous line start with '// @ts-ignore' comment, not counting non-empty non-comment lines | |
*/ | |
function shouldReportDiagnostic(diagnostic: Diagnostic) { | |
+ // console.log(diagnostic); | |
+ // return true; | |
const { file, start } = diagnostic; | |
if (file) { | |
const lineStarts = getLineStarts(file); | |
@@ -1783,6 +1803,25 @@ namespace ts { | |
return true; | |
} | |
+ // Ideas: create a map of diagnostics to line and then go line by line or just index the | |
+ // map directly. | |
+ function findExpectedError(expectedError: PragmaPseudoMap["ts-expect-error"], file: SourceFile, diagnostics: Diagnostic[]) { | |
+ const { pos } = expectedError.range; | |
+ | |
+ console.log(diagnostics); | |
+ | |
+ const lineStarts = getLineStarts(file); | |
+ let { line } = computeLineAndCharacterOfPosition(lineStarts, pos!); | |
+ console.log(file.lineMap.length); | |
+ while (line < file.lineMap.length) { | |
+ console.log(line); | |
+ line++; | |
+ } | |
+ | |
+ // If things don't go as we expect, we return `true`. | |
+ return true; | |
+ } | |
+ | |
function getJSSyntacticDiagnosticsForFile(sourceFile: SourceFile): DiagnosticWithLocation[] { | |
return runWithCancellationToken(() => { | |
const diagnostics: DiagnosticWithLocation[] = []; | |
diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts | |
index 2ccc8ef270..f2cdd05d5c 100644 | |
--- a/src/compiler/scanner.ts | |
+++ b/src/compiler/scanner.ts | |
@@ -654,6 +654,106 @@ namespace ts { | |
return pos; | |
} | |
+ /*@internal*/ | |
+ export function iterateAllCommentRanges(text: string, cb: (range: CommentRange) => void) { | |
+ let pendingPos!: number; | |
+ let pendingEnd!: number; | |
+ let pendingKind!: CommentKind; | |
+ let pendingHasTrailingNewLine!: boolean; | |
+ let hasPendingCommentRange = false; | |
+ let pos = 0; | |
+ const shebang = getShebang(text); | |
+ if (shebang) { | |
+ pos = shebang.length; | |
+ } | |
+ while (pos >= 0 && pos < text.length) { | |
+ const ch = text.charCodeAt(pos); | |
+ switch (ch) { | |
+ case CharacterCodes.carriageReturn: | |
+ if (text.charCodeAt(pos + 1) === CharacterCodes.lineFeed) { | |
+ pos++; | |
+ } | |
+ // falls through | |
+ case CharacterCodes.lineFeed: | |
+ pos++; | |
+ | |
+ if (hasPendingCommentRange) { | |
+ pendingHasTrailingNewLine = true; | |
+ } | |
+ | |
+ continue; | |
+ case CharacterCodes.tab: | |
+ case CharacterCodes.verticalTab: | |
+ case CharacterCodes.formFeed: | |
+ case CharacterCodes.space: | |
+ pos++; | |
+ continue; | |
+ case CharacterCodes.slash: | |
+ const nextChar = text.charCodeAt(pos + 1); | |
+ let hasTrailingNewLine = false; | |
+ if (nextChar === CharacterCodes.slash || nextChar === CharacterCodes.asterisk) { | |
+ const kind = nextChar === CharacterCodes.slash ? SyntaxKind.SingleLineCommentTrivia : SyntaxKind.MultiLineCommentTrivia; | |
+ const startPos = pos; | |
+ pos += 2; | |
+ if (nextChar === CharacterCodes.slash) { | |
+ while (pos < text.length) { | |
+ if (isLineBreak(text.charCodeAt(pos))) { | |
+ hasTrailingNewLine = true; | |
+ break; | |
+ } | |
+ pos++; | |
+ } | |
+ } | |
+ else { | |
+ while (pos < text.length) { | |
+ if (text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) { | |
+ pos += 2; | |
+ break; | |
+ } | |
+ pos++; | |
+ } | |
+ } | |
+ | |
+ if (hasPendingCommentRange) { | |
+ cb({ | |
+ pos: pendingPos, | |
+ end: pendingEnd, | |
+ kind: pendingKind, | |
+ hasTrailingNewLine: pendingHasTrailingNewLine, | |
+ }); | |
+ } | |
+ | |
+ pendingPos = startPos; | |
+ pendingEnd = pos; | |
+ pendingKind = kind; | |
+ pendingHasTrailingNewLine = hasTrailingNewLine; | |
+ hasPendingCommentRange = true; | |
+ | |
+ continue; | |
+ } | |
+ default: | |
+ if (ch > CharacterCodes.maxAsciiCharacter && (isWhiteSpaceLike(ch))) { | |
+ if (hasPendingCommentRange && isLineBreak(ch)) { | |
+ pendingHasTrailingNewLine = true; | |
+ } | |
+ pos++; | |
+ continue; | |
+ } | |
+ | |
+ pos++; | |
+ } | |
+ } | |
+ | |
+ if (hasPendingCommentRange) { | |
+ cb({ | |
+ pos: pendingPos, | |
+ end: pendingEnd, | |
+ kind: pendingKind, | |
+ hasTrailingNewLine: pendingHasTrailingNewLine, | |
+ }); | |
+ } | |
+ } | |
+ | |
/** | |
* Invokes a callback for each comment range following the provided position. | |
* | |
diff --git a/src/compiler/types.ts b/src/compiler/types.ts | |
index 1009e75fa8..140e9c1ec1 100644 | |
--- a/src/compiler/types.ts | |
+++ b/src/compiler/types.ts | |
@@ -6470,7 +6470,15 @@ namespace ts { | |
* /* @pragma-name argval1 argval2 * / | |
*/ | |
MultiLine = 1 << 2, | |
- All = TripleSlashXML | SingleLine | MultiLine, | |
+ /** | |
+ * Single line comment of the form | |
+ * // @pragma-name | |
+ * or | |
+ * /// @pragma-name | |
+ * that can go on any line of a file | |
+ */ | |
+ AnySingleLine = 1 << 3, | |
+ All = TripleSlashXML | SingleLine | MultiLine | AnySingleLine, | |
Default = All, | |
} | |
@@ -6523,6 +6531,9 @@ namespace ts { | |
args: [{ name: "factory" }], | |
kind: PragmaKindFlags.MultiLine | |
}, | |
+ "ts-expect-error": { | |
+ kind: PragmaKindFlags.AnySingleLine | |
+ } | |
} as const; | |
/* @internal */ | |
diff --git a/tests/baselines/reference/tsExpectError.js b/tests/baselines/reference/tsExpectError.js | |
new file mode 100644 | |
index 0000000000..e0354964a5 | |
--- /dev/null | |
+++ b/tests/baselines/reference/tsExpectError.js | |
@@ -0,0 +1,11 @@ | |
+//// [tsExpectError.ts] | |
+// @ts-expect-error | |
+function f(x: number) { | |
+ return 5; | |
+} | |
+ | |
+//// [tsExpectError.js] | |
+// @ts-expect-error | |
+function f(x) { | |
+ return 5; | |
+} | |
diff --git a/tests/baselines/reference/tsExpectError.symbols b/tests/baselines/reference/tsExpectError.symbols | |
new file mode 100644 | |
index 0000000000..d33bfbaf6d | |
--- /dev/null | |
+++ b/tests/baselines/reference/tsExpectError.symbols | |
@@ -0,0 +1,8 @@ | |
+=== tests/cases/compiler/tsExpectError.ts === | |
+// @ts-expect-error | |
+function f(x: number) { | |
+>f : Symbol(f, Decl(tsExpectError.ts, 0, 0)) | |
+>x : Symbol(x, Decl(tsExpectError.ts, 1, 11)) | |
+ | |
+ return 5; | |
+} | |
diff --git a/tests/baselines/reference/tsExpectError.types b/tests/baselines/reference/tsExpectError.types | |
new file mode 100644 | |
index 0000000000..0230d60a8d | |
--- /dev/null | |
+++ b/tests/baselines/reference/tsExpectError.types | |
@@ -0,0 +1,9 @@ | |
+=== tests/cases/compiler/tsExpectError.ts === | |
+// @ts-expect-error | |
+function f(x: number) { | |
+>f : (x: number) => number | |
+>x : number | |
+ | |
+ return 5; | |
+>5 : 5 | |
+} | |
diff --git a/tests/cases/compiler/tsExpectError.ts b/tests/cases/compiler/tsExpectError.ts | |
new file mode 100644 | |
index 0000000000..105c878a2f | |
--- /dev/null | |
+++ b/tests/cases/compiler/tsExpectError.ts | |
@@ -0,0 +1,13 @@ | |
+// @ts-expect-error | |
+ | |
+// @fileName: tsExpectError.ts | |
+ | |
+function f(x: number): number { | |
+ // @ts-expect-error | |
+ return 5; | |
+} | |
+ | |
+function g(x: string): number { | |
+ // @ts-expect-error | |
+ return "7"; | |
+} | |
\ No newline at end of file |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment