Skip to content
This repository was archived by the owner on Jan 19, 2019. It is now read-only.

Commit 416b85e

Browse files
committed
Fix: Allow comment scanner to rescan tokens (fixes #216)
Template strings and regex patterns need to be rescaned to not scan tokens as comments
1 parent cefdfc2 commit 416b85e

39 files changed

+2040
-122
lines changed

Diff for: lib/ast-converter.js

+153-21
Original file line numberDiff line numberDiff line change
@@ -191,20 +191,6 @@ function getLocFor(start, end, ast) {
191191
*/
192192
function getLoc(nodeOrToken, ast) {
193193
return getLocFor(nodeOrToken.getStart(), nodeOrToken.end, ast);
194-
// var start = nodeOrToken.getStart(),
195-
// startLoc = ast.getLineAndCharacterOfPosition(start),
196-
// endLoc = ast.getLineAndCharacterOfPosition(nodeOrToken.end);
197-
198-
// return {
199-
// start: {
200-
// line: startLoc.line + 1,
201-
// column: startLoc.character
202-
// },
203-
// end: {
204-
// line: endLoc.line + 1,
205-
// column: endLoc.character
206-
// }
207-
// };
208194
}
209195

210196
/**
@@ -451,6 +437,157 @@ function convertTokens(ast) {
451437
return result;
452438
}
453439

440+
441+
/**
442+
* Converts a TypeScript comment to an Esprima comment.
443+
* @param {boolean} block True if it's a block comment, false if not.
444+
* @param {string} text The text of the comment.
445+
* @param {int} start The index at which the comment starts.
446+
* @param {int} end The index at which the comment ends.
447+
* @param {Location} startLoc The location at which the comment starts.
448+
* @param {Location} endLoc The location at which the comment ends.
449+
* @returns {Object} The comment object.
450+
* @private
451+
*/
452+
function convertTypeScriptCommentToEsprimaComment(block, text, start, end, startLoc, endLoc) {
453+
var comment = {
454+
type: block ? "Block" : "Line",
455+
value: text
456+
};
457+
458+
if (typeof start === "number") {
459+
comment.range = [start, end];
460+
}
461+
462+
if (typeof startLoc === "object") {
463+
comment.loc = {
464+
start: startLoc,
465+
end: endLoc
466+
};
467+
}
468+
469+
return comment;
470+
}
471+
472+
/**
473+
* Convert comment from TypeScript Triva Scanner.
474+
* @param {Object} triviaScanner TS Scanner
475+
* @param {Object} ast the AST object
476+
* @param {string} code TypeScript code
477+
* @returns {ESTreeComment} the converted ESTreeComment
478+
* @private
479+
*/
480+
function getCommentFromTriviaScanner(triviaScanner, ast, code) {
481+
var kind = triviaScanner.getToken();
482+
var isBlock = (kind === ts.SyntaxKind.MultiLineCommentTrivia);
483+
var range = {
484+
pos: triviaScanner.getTokenPos(),
485+
end: triviaScanner.getTextPos(),
486+
kind: triviaScanner.getToken()
487+
};
488+
489+
var comment = code.substring(range.pos, range.end);
490+
var text = comment.replace("//", "").replace("/*", "").replace("*/", "");
491+
var loc = getLocFor(range.pos, range.end, ast);
492+
493+
var esprimaComment = convertTypeScriptCommentToEsprimaComment(isBlock, text, range.pos, range.end, loc.start, loc.end);
494+
495+
return esprimaComment;
496+
}
497+
498+
499+
/**
500+
* Get container token node between range
501+
* @param {Object} ast the AST object
502+
* @param {int} start The index at which the comment starts.
503+
* @param {int} end The index at which the comment ends.
504+
* @returns {TSToken} typescript container token
505+
* @private
506+
*/
507+
function getNodeContainer(ast, start, end) {
508+
var container = null;
509+
510+
/**
511+
* @param {TSNode} node the TSNode
512+
* @returns {undefined}
513+
*/
514+
function walk(node) {
515+
var nodeStart = node.pos;
516+
var nodeEnd = node.end;
517+
518+
if (start >= nodeStart && end <= nodeEnd) {
519+
if (isToken(node)) {
520+
container = node;
521+
} else {
522+
node.getChildren().forEach(walk);
523+
}
524+
}
525+
}
526+
walk(ast);
527+
528+
return container;
529+
}
530+
531+
/**
532+
* Convert all comments for the given AST.
533+
* @param {Object} ast the AST object
534+
* @param {string} code the TypeScript code
535+
* @returns {ESTreeComment[]} the converted ESTreeComment
536+
* @private
537+
*/
538+
function convertComments(ast, code) {
539+
var comments = [];
540+
541+
/**
542+
* Create a TypeScript Scanner, with skipTrivia set to false so that
543+
* we can parse the comments
544+
*/
545+
var triviaScanner = ts.createScanner(ast.languageVersion, false, 0, code);
546+
547+
var kind = triviaScanner.scan();
548+
while (kind !== ts.SyntaxKind.EndOfFileToken) {
549+
var start = triviaScanner.getTokenPos();
550+
var end = triviaScanner.getTextPos();
551+
552+
var container = null;
553+
switch (kind) {
554+
case ts.SyntaxKind.SingleLineCommentTrivia:
555+
case ts.SyntaxKind.MultiLineCommentTrivia:
556+
var comment = getCommentFromTriviaScanner(triviaScanner, ast, code);
557+
558+
comments.push(comment);
559+
break;
560+
case ts.SyntaxKind.CloseBraceToken:
561+
container = getNodeContainer(ast, start, end);
562+
563+
if (
564+
container.kind === ts.SyntaxKind.TemplateMiddle
565+
|| container.kind === ts.SyntaxKind.TemplateTail
566+
) {
567+
kind = triviaScanner.reScanTemplateToken();
568+
continue;
569+
}
570+
break;
571+
case ts.SyntaxKind.SlashToken:
572+
case ts.SyntaxKind.SlashEqualsToken:
573+
container = getNodeContainer(ast, start, end);
574+
575+
if (
576+
container.kind === ts.SyntaxKind.RegularExpressionLiteral
577+
) {
578+
kind = triviaScanner.reScanSlashToken();
579+
continue;
580+
}
581+
break;
582+
default:
583+
break;
584+
}
585+
kind = triviaScanner.scan();
586+
}
587+
588+
return comments;
589+
}
590+
454591
//------------------------------------------------------------------------------
455592
// Public
456593
//------------------------------------------------------------------------------
@@ -2088,13 +2225,8 @@ module.exports = function(ast, extra) {
20882225
estree.tokens = convertTokens(ast);
20892226
}
20902227

2091-
/**
2092-
* Add the comment nodes to the AST (that were parsed separately in parser.js)
2093-
* TODO: Track the progress of https://github.com/eslint/eslint/issues/6724
2094-
* regarding ESLint itself becoming responsible for attributing comment nodes
2095-
*/
2096-
if (extra.comment || extra.attachComment) {
2097-
estree.comments = extra.comments || [];
2228+
if (extra.comment) {
2229+
estree.comments = convertComments(ast, extra.code);
20982230
}
20992231

21002232
return estree;

Diff for: parser.js

+3-96
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"use strict";
1010

1111
var astNodeTypes = require("./lib/ast-node-types"),
12-
ts = require("typescript");
12+
ts = require("typescript"),
13+
convert = require("./lib/ast-converter");
1314

1415
var extra;
1516

@@ -31,61 +32,6 @@ function resetExtra() {
3132
};
3233
}
3334

34-
/**
35-
* Converts a TypeScript comment to an Esprima comment.
36-
* @param {boolean} block True if it's a block comment, false if not.
37-
* @param {string} text The text of the comment.
38-
* @param {int} start The index at which the comment starts.
39-
* @param {int} end The index at which the comment ends.
40-
* @param {Location} startLoc The location at which the comment starts.
41-
* @param {Location} endLoc The location at which the comment ends.
42-
* @returns {Object} The comment object.
43-
* @private
44-
*/
45-
function convertTypeScriptCommentToEsprimaComment(block, text, start, end, startLoc, endLoc) {
46-
var comment = {
47-
type: block ? "Block" : "Line",
48-
value: text
49-
};
50-
51-
if (typeof start === "number") {
52-
comment.range = [start, end];
53-
}
54-
55-
if (typeof startLoc === "object") {
56-
comment.loc = {
57-
start: startLoc,
58-
end: endLoc
59-
};
60-
}
61-
62-
return comment;
63-
}
64-
65-
/**
66-
* Returns line and column data for the given start and end positions,
67-
* for the given AST
68-
* @param {Object} start start data
69-
* @param {Object} end end data
70-
* @param {Object} ast the AST object
71-
* @returns {Object} the loc data
72-
*/
73-
function getLocFor(start, end, ast) {
74-
var startLoc = ast.getLineAndCharacterOfPosition(start),
75-
endLoc = ast.getLineAndCharacterOfPosition(end);
76-
77-
return {
78-
start: {
79-
line: startLoc.line + 1,
80-
column: startLoc.character
81-
},
82-
end: {
83-
line: endLoc.line + 1,
84-
column: endLoc.character
85-
}
86-
};
87-
}
88-
8935
//------------------------------------------------------------------------------
9036
// Parser
9137
//------------------------------------------------------------------------------
@@ -110,7 +56,6 @@ function parse(code, options) {
11056
if (typeof options !== "undefined") {
11157
extra.range = (typeof options.range === "boolean") && options.range;
11258
extra.loc = (typeof options.loc === "boolean") && options.loc;
113-
extra.attachComment = (typeof options.attachComment === "boolean") && options.attachComment;
11459

11560
if (extra.loc && options.source !== null && options.source !== undefined) {
11661
extra.source = toString(options.source);
@@ -126,10 +71,6 @@ function parse(code, options) {
12671
if (typeof options.tolerant === "boolean" && options.tolerant) {
12772
extra.errors = [];
12873
}
129-
if (extra.attachComment) {
130-
extra.range = true;
131-
extra.comments = [];
132-
}
13374

13475
if (options.ecmaFeatures && typeof options.ecmaFeatures === "object") {
13576
// pass through jsx option
@@ -181,41 +122,7 @@ function parse(code, options) {
181122

182123
var ast = program.getSourceFile(FILENAME);
183124

184-
if (extra.attachComment || extra.comment) {
185-
/**
186-
* Create a TypeScript Scanner, with skipTrivia set to false so that
187-
* we can parse the comments
188-
*/
189-
var triviaScanner = ts.createScanner(ast.languageVersion, false, 0, code);
190-
191-
var kind = triviaScanner.scan();
192-
while (kind !== ts.SyntaxKind.EndOfFileToken) {
193-
if (kind !== ts.SyntaxKind.SingleLineCommentTrivia && kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
194-
kind = triviaScanner.scan();
195-
continue;
196-
}
197-
198-
var isBlock = (kind === ts.SyntaxKind.MultiLineCommentTrivia);
199-
var range = {
200-
pos: triviaScanner.getTokenPos(),
201-
end: triviaScanner.getTextPos(),
202-
kind: triviaScanner.getToken()
203-
};
204-
205-
var comment = code.substring(range.pos, range.end);
206-
var text = comment.replace("//", "").replace("/*", "").replace("*/", "");
207-
var loc = getLocFor(range.pos, range.end, ast);
208-
209-
var esprimaComment = convertTypeScriptCommentToEsprimaComment(isBlock, text, range.pos, range.end, loc.start, loc.end);
210-
extra.comments.push(esprimaComment);
211-
212-
kind = triviaScanner.scan();
213-
}
214-
215-
}
216-
217-
var convert = require("./lib/ast-converter");
218-
125+
extra.code = code;
219126
return convert(ast, extra);
220127
}
221128

0 commit comments

Comments
 (0)