Skip to content

Instantly share code, notes, and snippets.

@davidgomes
Created January 27, 2020 22:49
Show Gist options
  • Save davidgomes/5cb71342b6d2cf95ffa05a767eb802c7 to your computer and use it in GitHub Desktop.
Save davidgomes/5cb71342b6d2cf95ffa05a767eb802c7 to your computer and use it in GitHub Desktop.
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