UNPKG

4.79 kBJavaScriptView Raw
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"use strict";
9
10//------------------------------------------------------------------------------
11// Requirements
12//------------------------------------------------------------------------------
13
14const 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 */
32function 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 */
60function 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 */
83module.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 */
95function 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}