Skip to content

Commit 170042c

Browse files
committed
Move to the scanner
1 parent 481a7dd commit 170042c

File tree

2 files changed

+30
-17
lines changed

2 files changed

+30
-17
lines changed

src/compiler/parser.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,8 +1532,6 @@ namespace Parser {
15321532
// Note: any errors at the end of the file that do not precede a regular node, should get
15331533
// attached to the EOF token.
15341534
var parseErrorBeforeNextFinishedNode = false;
1535-
1536-
var skipJSDoc = false;
15371535
/* eslint-enable no-var */
15381536

15391537
export function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: IncrementalParser.SyntaxCursor | undefined, setParentNodes = false, scriptKind?: ScriptKind, setExternalModuleIndicatorOverride?: (file: SourceFile) => void, skipJSDoc = false): SourceFile {
@@ -1672,7 +1670,6 @@ namespace Parser {
16721670
syntaxCursor = _syntaxCursor;
16731671
scriptKind = _scriptKind;
16741672
languageVariant = getLanguageVariant(_scriptKind);
1675-
skipJSDoc = _skipJSDoc;
16761673

16771674
parseDiagnostics = [];
16781675
parsingContext = 0;
@@ -1701,13 +1698,15 @@ namespace Parser {
17011698
scanner.setOnError(scanError);
17021699
scanner.setScriptTarget(languageVersion);
17031700
scanner.setLanguageVariant(languageVariant);
1701+
scanner.setSkipJSDoc(_skipJSDoc && !!(contextFlags & NodeFlags.JavaScriptFile));
17041702
}
17051703

17061704
function clearState() {
17071705
// Clear out the text the scanner is pointing at, so it doesn't keep anything alive unnecessarily.
17081706
scanner.clearCommentDirectives();
17091707
scanner.setText("");
17101708
scanner.setOnError(undefined);
1709+
scanner.setSkipJSDoc(false);
17111710

17121711
// Clear any data. We don't want to accidentally hold onto it for too long.
17131712
sourceText = undefined!;
@@ -1722,7 +1721,6 @@ namespace Parser {
17221721
identifiers = undefined!;
17231722
notParenthesizedArrow = undefined;
17241723
topLevel = true;
1725-
skipJSDoc = false;
17261724
}
17271725

17281726
function parseSourceFileWorker(languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind, setExternalModuleIndicator: (file: SourceFile) => void): SourceFile {
@@ -1739,6 +1737,8 @@ namespace Parser {
17391737
const statements = parseList(ParsingContext.SourceElements, parseStatement);
17401738
Debug.assert(token() === SyntaxKind.EndOfFileToken);
17411739
const endOfFileToken = addJSDocComment(parseTokenNode<EndOfFileToken>());
1740+
// TODO(jakebailey): this should really be the following, but why isn't the flag set?
1741+
// const endOfFileToken = withJSDoc(parseTokenNode<EndOfFileToken>(), hasPrecedingJSDocComment());
17421742

17431743
const sourceFile = createSourceFile(fileName, languageVersion, scriptKind, isDeclarationFile, statements, endOfFileToken, sourceFlags, setExternalModuleIndicator);
17441744

@@ -1770,18 +1770,15 @@ namespace Parser {
17701770
return hasJSDoc ? addJSDocComment(node) : node;
17711771
}
17721772

1773-
const seeLink = /@(?:see|link)/;
1774-
function shouldParseJSDoc<T extends HasJSDoc>(node: T, comment: ts.CommentRange) {
1775-
if (!skipJSDoc) return true;
1776-
if (node.flags & NodeFlags.JavaScriptFile) return true;
1777-
if (seeLink.test(sourceText.slice(comment.pos, comment.end))) return true;
1778-
return undefined;
1779-
}
1780-
17811773
let hasDeprecatedTag = false;
1774+
/**
1775+
* Adds a JSDoc comment to a node, if any exist.
1776+
*
1777+
* Avoid calling this directly; use {@see withJSDoc} instead.
1778+
*/
17821779
function addJSDocComment<T extends HasJSDoc>(node: T): T {
17831780
Debug.assert(!node.jsDoc); // Should only be called once per node
1784-
const jsDoc = mapDefined(getJSDocCommentRanges(node, sourceText), comment => shouldParseJSDoc(node, comment) && JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos));
1781+
const jsDoc = mapDefined(getJSDocCommentRanges(node, sourceText), comment => JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos));
17851782
if (jsDoc.length) node.jsDoc = jsDoc;
17861783
if (hasDeprecatedTag) {
17871784
hasDeprecatedTag = false;
@@ -5072,7 +5069,7 @@ namespace Parser {
50725069
const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken);
50735070
const body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier, allowReturnTypeInArrowFunction);
50745071
const node = factory.createArrowFunction(asyncModifier, /*typeParameters*/ undefined, parameters, /*type*/ undefined, equalsGreaterThanToken, body);
5075-
return addJSDocComment(finishNode(node, pos));
5072+
return finishNode(node, pos);
50765073
}
50775074

50785075
function tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): Expression | undefined {

src/compiler/scanner.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ export interface Scanner {
103103
// callback returns something truthy, then the scanner state is not rolled back. The result
104104
// of invoking the callback is returned from this function.
105105
tryScan<T>(callback: () => T): T;
106+
/** @internal */
107+
setSkipJSDoc(skip: boolean): void;
106108
}
107109

108110
/** @internal */
@@ -325,6 +327,11 @@ const commentDirectiveRegExSingleLine = /^\/\/\/?\s*@(ts-expect-error|ts-ignore)
325327
*/
326328
const commentDirectiveRegExMultiLine = /^(?:\/|\*)*\s*@(ts-expect-error|ts-ignore)/;
327329

330+
/**
331+
* Test for whether a comment contains a JSDoc tag needed by the checker when run in tsc.
332+
*/
333+
const semanticJSDocTagRegEx = /@(?:see|link)/i;
334+
328335
function lookupInUnicodeMap(code: number, map: readonly number[]): boolean {
329336
// Bail out quickly if it couldn't possibly be in the map.
330337
if (code < map[0]) {
@@ -984,6 +991,8 @@ export function createScanner(languageVersion: ScriptTarget,
984991
var commentDirectives: CommentDirective[] | undefined;
985992
var inJSDocType = 0;
986993

994+
var skipJSDoc = false;
995+
987996
setText(text, start, length);
988997

989998
var scanner: Scanner = {
@@ -1030,6 +1039,7 @@ export function createScanner(languageVersion: ScriptTarget,
10301039
tryScan,
10311040
lookAhead,
10321041
scanRange,
1042+
setSkipJSDoc,
10331043
};
10341044
/* eslint-enable no-var */
10351045

@@ -1823,9 +1833,7 @@ export function createScanner(languageVersion: ScriptTarget,
18231833
// Multi-line comment
18241834
if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) {
18251835
pos += 2;
1826-
if (text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) !== CharacterCodes.slash) {
1827-
tokenFlags |= TokenFlags.PrecedingJSDocComment;
1828-
}
1836+
const isJSDoc = text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) !== CharacterCodes.slash;
18291837

18301838
let commentClosed = false;
18311839
let lastLineStart = tokenPos;
@@ -1846,6 +1854,10 @@ export function createScanner(languageVersion: ScriptTarget,
18461854
}
18471855
}
18481856

1857+
if (isJSDoc && (!skipJSDoc || semanticJSDocTagRegEx.test(text.slice(tokenPos, pos)))) {
1858+
tokenFlags |= TokenFlags.PrecedingJSDocComment;
1859+
}
1860+
18491861
commentDirectives = appendIfCommentDirective(commentDirectives, text.slice(lastLineStart, pos), commentDirectiveRegExMultiLine, lastLineStart);
18501862

18511863
if (!commentClosed) {
@@ -2621,6 +2633,10 @@ export function createScanner(languageVersion: ScriptTarget,
26212633
languageVariant = variant;
26222634
}
26232635

2636+
function setSkipJSDoc(skip: boolean) {
2637+
skipJSDoc = skip;
2638+
}
2639+
26242640
function setTextPos(textPos: number) {
26252641
Debug.assert(textPos >= 0);
26262642
pos = textPos;

0 commit comments

Comments
 (0)