1 | /**
|
2 | * @fileoverview Convert comment using TypeScript token scanner
|
3 | * @author James Henry <https://github.com/JamesHenry>
|
4 | * @copyright jQuery Foundation and other contributors, https://jquery.org/
|
5 | * MIT License
|
6 | */
|
7 |
|
8 | ;
|
9 |
|
10 | //------------------------------------------------------------------------------
|
11 | // Requirements
|
12 | //------------------------------------------------------------------------------
|
13 |
|
14 | const ts = require("typescript"),
|
15 | nodeUtils = require("./node-utils");
|
16 |
|
17 | //------------------------------------------------------------------------------
|
18 | // Private
|
19 | //------------------------------------------------------------------------------
|
20 |
|
21 | /**
|
22 | * Converts a TypeScript comment to an Esprima comment.
|
23 | * @param {boolean} block True if it's a block comment, false if not.
|
24 | * @param {string} text The text of the comment.
|
25 | * @param {int} start The index at which the comment starts.
|
26 | * @param {int} end The index at which the comment ends.
|
27 | * @param {Location} startLoc The location at which the comment starts.
|
28 | * @param {Location} endLoc The location at which the comment ends.
|
29 | * @returns {Object} The comment object.
|
30 | * @private
|
31 | */
|
32 | function convertTypeScriptCommentToEsprimaComment(block, text, start, end, startLoc, endLoc) {
|
33 | const comment = {
|
34 | type: block ? "Block" : "Line",
|
35 | value: text
|
36 | };
|
37 |
|
38 | if (typeof start === "number") {
|
39 | comment.range = [start, end];
|
40 | }
|
41 |
|
42 | if (typeof startLoc === "object") {
|
43 | comment.loc = {
|
44 | start: startLoc,
|
45 | end: endLoc
|
46 | };
|
47 | }
|
48 |
|
49 | return comment;
|
50 | }
|
51 |
|
52 | /**
|
53 | * Convert comment from TypeScript Triva Scanner.
|
54 | * @param {Object} triviaScanner TS Scanner
|
55 | * @param {Object} ast the AST object
|
56 | * @param {string} code TypeScript code
|
57 | * @returns {ESTreeComment} the converted ESTreeComment
|
58 | * @private
|
59 | */
|
60 | function getCommentFromTriviaScanner(triviaScanner, ast, code) {
|
61 | const kind = triviaScanner.getToken();
|
62 | const isBlock = (kind === ts.SyntaxKind.MultiLineCommentTrivia);
|
63 | const range = {
|
64 | pos: triviaScanner.getTokenPos(),
|
65 | end: triviaScanner.getTextPos(),
|
66 | kind: triviaScanner.getToken()
|
67 | };
|
68 |
|
69 | const comment = code.substring(range.pos, range.end);
|
70 | const text = (isBlock) ? comment.replace(/^\/\*/, "").replace(/\*\/$/, "") : comment.replace(/^\/\//, "");
|
71 | const loc = nodeUtils.getLocFor(range.pos, range.end, ast);
|
72 |
|
73 | const esprimaComment = convertTypeScriptCommentToEsprimaComment(isBlock, text, range.pos, range.end, loc.start, loc.end);
|
74 |
|
75 | return esprimaComment;
|
76 | }
|
77 |
|
78 | //------------------------------------------------------------------------------
|
79 | // Public
|
80 | //------------------------------------------------------------------------------
|
81 |
|
82 | /* eslint-disable no-use-before-define */
|
83 | module.exports = {
|
84 | convertComments
|
85 | };
|
86 |
|
87 |
|
88 | /**
|
89 | * Convert all comments for the given AST.
|
90 | * @param {Object} ast the AST object
|
91 | * @param {string} code the TypeScript code
|
92 | * @returns {ESTreeComment[]} the converted ESTreeComment
|
93 | * @private
|
94 | */
|
95 | function convertComments(ast, code) {
|
96 | const comments = [];
|
97 |
|
98 | /**
|
99 | * Create a TypeScript Scanner, with skipTrivia set to false so that
|
100 | * we can parse the comments
|
101 | */
|
102 | const triviaScanner = ts.createScanner(ast.languageVersion, false, 0, code);
|
103 |
|
104 | let kind = triviaScanner.scan();
|
105 | while (kind !== ts.SyntaxKind.EndOfFileToken) {
|
106 | const start = triviaScanner.getTokenPos();
|
107 | const end = triviaScanner.getTextPos();
|
108 |
|
109 | let container = null;
|
110 | switch (kind) {
|
111 | case ts.SyntaxKind.SingleLineCommentTrivia:
|
112 | case ts.SyntaxKind.MultiLineCommentTrivia: {
|
113 | const comment = getCommentFromTriviaScanner(triviaScanner, ast, code);
|
114 |
|
115 | comments.push(comment);
|
116 | break;
|
117 | }
|
118 | case ts.SyntaxKind.CloseBraceToken:
|
119 | container = nodeUtils.getNodeContainer(ast, start, end);
|
120 |
|
121 | if (
|
122 | container.kind === ts.SyntaxKind.TemplateMiddle ||
|
123 | container.kind === ts.SyntaxKind.TemplateTail
|
124 | ) {
|
125 | kind = triviaScanner.reScanTemplateToken();
|
126 | continue;
|
127 | }
|
128 | break;
|
129 | case ts.SyntaxKind.SlashToken:
|
130 | case ts.SyntaxKind.SlashEqualsToken:
|
131 | container = nodeUtils.getNodeContainer(ast, start, end);
|
132 |
|
133 | if (
|
134 | container.kind === ts.SyntaxKind.RegularExpressionLiteral
|
135 | ) {
|
136 | kind = triviaScanner.reScanSlashToken();
|
137 | continue;
|
138 | }
|
139 | break;
|
140 | default:
|
141 | break;
|
142 | }
|
143 | kind = triviaScanner.scan();
|
144 | }
|
145 |
|
146 | return comments;
|
147 | }
|