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

Commit 68fcf34

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 68fcf34

39 files changed

+2035
-122
lines changed

Diff for: lib/ast-converter.js

+145-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,149 @@ 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+
function getNodeContainer(ast, start, end) {
500+
var container = null;
501+
502+
/**
503+
* @param {TSNode} node the TSNode
504+
* @returns {undefined}
505+
*/
506+
function walk(node) {
507+
var nodeStart = node.pos;
508+
var nodeEnd = node.end;
509+
510+
if (start >= nodeStart && end <= nodeEnd) {
511+
if (isToken(node)) {
512+
container = node;
513+
} else {
514+
node.getChildren().forEach(walk);
515+
}
516+
}
517+
}
518+
walk(ast);
519+
520+
return container;
521+
}
522+
523+
/**
524+
* Convert all comments for the given AST.
525+
* @param {Object} ast the AST object
526+
* @param {string} code the TypeScript code
527+
* @returns {ESTreeComment[]} the converted ESTreeComment
528+
* @private
529+
*/
530+
function convertComments(ast, code) {
531+
var comments = [];
532+
533+
/**
534+
* Create a TypeScript Scanner, with skipTrivia set to false so that
535+
* we can parse the comments
536+
*/
537+
var triviaScanner = ts.createScanner(ast.languageVersion, false, 0, code);
538+
539+
var kind = triviaScanner.scan();
540+
while (kind !== ts.SyntaxKind.EndOfFileToken) {
541+
var start = triviaScanner.getTokenPos();
542+
var end = triviaScanner.getTextPos();
543+
544+
var container = null;
545+
switch (kind) {
546+
case ts.SyntaxKind.SingleLineCommentTrivia:
547+
case ts.SyntaxKind.MultiLineCommentTrivia:
548+
var comment = getCommentFromTriviaScanner(triviaScanner, ast, code);
549+
550+
comments.push(comment);
551+
break;
552+
case ts.SyntaxKind.CloseBraceToken:
553+
container = getNodeContainer(ast, start, end);
554+
555+
if (
556+
container.kind === ts.SyntaxKind.TemplateMiddle
557+
|| container.kind === ts.SyntaxKind.TemplateTail
558+
) {
559+
kind = triviaScanner.reScanTemplateToken();
560+
continue;
561+
}
562+
break;
563+
case ts.SyntaxKind.SlashToken:
564+
case ts.SyntaxKind.SlashEqualsToken:
565+
container = getNodeContainer(ast, start, end);
566+
567+
if (
568+
container.kind === ts.SyntaxKind.RegularExpressionLiteral
569+
) {
570+
kind = triviaScanner.reScanSlashToken();
571+
continue;
572+
}
573+
break;
574+
default:
575+
break;
576+
}
577+
kind = triviaScanner.scan();
578+
}
579+
580+
return comments;
581+
}
582+
454583
//------------------------------------------------------------------------------
455584
// Public
456585
//------------------------------------------------------------------------------
@@ -2088,13 +2217,8 @@ module.exports = function(ast, extra) {
20882217
estree.tokens = convertTokens(ast);
20892218
}
20902219

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 || [];
2220+
if (extra.comment) {
2221+
estree.comments = convertComments(ast, extra.code);
20982222
}
20992223

21002224
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)