UNPKG

19.4 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5}) : (function(o, m, k, k2) {
6 if (k2 === undefined) k2 = k;
7 o[k2] = m[k];
8}));
9var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10 Object.defineProperty(o, "default", { enumerable: true, value: v });
11}) : function(o, v) {
12 o["default"] = v;
13});
14var __importStar = (this && this.__importStar) || function (mod) {
15 if (mod && mod.__esModule) return mod;
16 var result = {};
17 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18 __setModuleDefault(result, mod);
19 return result;
20};
21Object.defineProperty(exports, "__esModule", { value: true });
22exports.firstDefined = exports.nodeHasTokens = exports.createError = exports.TSError = exports.convertTokens = exports.convertToken = exports.getTokenType = exports.isChildUnwrappableOptionalChain = exports.isChainExpression = exports.isOptional = exports.isComputedProperty = exports.unescapeStringLiteralText = exports.hasJSXAncestor = exports.findFirstMatchingAncestor = exports.findNextToken = exports.getTSNodeAccessibility = exports.getDeclarationKind = exports.isJSXToken = exports.isToken = exports.getRange = exports.canContainDirective = exports.getLocFor = exports.getLineAndCharacterFor = exports.getBinaryExpressionType = exports.isJSDocComment = exports.isComment = exports.isComma = exports.getLastModifier = exports.hasModifier = exports.isESTreeClassMember = exports.getTextForTokenKind = exports.isLogicalOperator = exports.isAssignmentOperator = void 0;
23const ts = __importStar(require("typescript"));
24const ts_estree_1 = require("./ts-estree");
25const xhtml_entities_1 = require("./jsx/xhtml-entities");
26const SyntaxKind = ts.SyntaxKind;
27const LOGICAL_OPERATORS = [
28 SyntaxKind.BarBarToken,
29 SyntaxKind.AmpersandAmpersandToken,
30 SyntaxKind.QuestionQuestionToken,
31];
32/**
33 * Returns true if the given ts.Token is the assignment operator
34 * @param operator the operator token
35 * @returns is assignment
36 */
37function isAssignmentOperator(operator) {
38 return (operator.kind >= SyntaxKind.FirstAssignment &&
39 operator.kind <= SyntaxKind.LastAssignment);
40}
41exports.isAssignmentOperator = isAssignmentOperator;
42/**
43 * Returns true if the given ts.Token is a logical operator
44 * @param operator the operator token
45 * @returns is a logical operator
46 */
47function isLogicalOperator(operator) {
48 return LOGICAL_OPERATORS.includes(operator.kind);
49}
50exports.isLogicalOperator = isLogicalOperator;
51/**
52 * Returns the string form of the given TSToken SyntaxKind
53 * @param kind the token's SyntaxKind
54 * @returns the token applicable token as a string
55 */
56function getTextForTokenKind(kind) {
57 return ts.tokenToString(kind);
58}
59exports.getTextForTokenKind = getTextForTokenKind;
60/**
61 * Returns true if the given ts.Node is a valid ESTree class member
62 * @param node TypeScript AST node
63 * @returns is valid ESTree class member
64 */
65function isESTreeClassMember(node) {
66 return node.kind !== SyntaxKind.SemicolonClassElement;
67}
68exports.isESTreeClassMember = isESTreeClassMember;
69/**
70 * Checks if a ts.Node has a modifier
71 * @param modifierKind TypeScript SyntaxKind modifier
72 * @param node TypeScript AST node
73 * @returns has the modifier specified
74 */
75function hasModifier(modifierKind, node) {
76 return (!!node.modifiers &&
77 !!node.modifiers.length &&
78 node.modifiers.some(modifier => modifier.kind === modifierKind));
79}
80exports.hasModifier = hasModifier;
81/**
82 * Get last last modifier in ast
83 * @param node TypeScript AST node
84 * @returns returns last modifier if present or null
85 */
86function getLastModifier(node) {
87 return ((!!node.modifiers &&
88 !!node.modifiers.length &&
89 node.modifiers[node.modifiers.length - 1]) ||
90 null);
91}
92exports.getLastModifier = getLastModifier;
93/**
94 * Returns true if the given ts.Token is a comma
95 * @param token the TypeScript token
96 * @returns is comma
97 */
98function isComma(token) {
99 return token.kind === SyntaxKind.CommaToken;
100}
101exports.isComma = isComma;
102/**
103 * Returns true if the given ts.Node is a comment
104 * @param node the TypeScript node
105 * @returns is comment
106 */
107function isComment(node) {
108 return (node.kind === SyntaxKind.SingleLineCommentTrivia ||
109 node.kind === SyntaxKind.MultiLineCommentTrivia);
110}
111exports.isComment = isComment;
112/**
113 * Returns true if the given ts.Node is a JSDoc comment
114 * @param node the TypeScript node
115 * @returns is JSDoc comment
116 */
117function isJSDocComment(node) {
118 return node.kind === SyntaxKind.JSDocComment;
119}
120exports.isJSDocComment = isJSDocComment;
121/**
122 * Returns the binary expression type of the given ts.Token
123 * @param operator the operator token
124 * @returns the binary expression type
125 */
126function getBinaryExpressionType(operator) {
127 if (isAssignmentOperator(operator)) {
128 return ts_estree_1.AST_NODE_TYPES.AssignmentExpression;
129 }
130 else if (isLogicalOperator(operator)) {
131 return ts_estree_1.AST_NODE_TYPES.LogicalExpression;
132 }
133 return ts_estree_1.AST_NODE_TYPES.BinaryExpression;
134}
135exports.getBinaryExpressionType = getBinaryExpressionType;
136/**
137 * Returns line and column data for the given positions,
138 * @param pos position to check
139 * @param ast the AST object
140 * @returns line and column
141 */
142function getLineAndCharacterFor(pos, ast) {
143 const loc = ast.getLineAndCharacterOfPosition(pos);
144 return {
145 line: loc.line + 1,
146 column: loc.character,
147 };
148}
149exports.getLineAndCharacterFor = getLineAndCharacterFor;
150/**
151 * Returns line and column data for the given start and end positions,
152 * for the given AST
153 * @param start start data
154 * @param end end data
155 * @param ast the AST object
156 * @returns the loc data
157 */
158function getLocFor(start, end, ast) {
159 return {
160 start: getLineAndCharacterFor(start, ast),
161 end: getLineAndCharacterFor(end, ast),
162 };
163}
164exports.getLocFor = getLocFor;
165/**
166 * Check whatever node can contain directive
167 * @param node
168 * @returns returns true if node can contain directive
169 */
170function canContainDirective(node) {
171 if (node.kind === ts.SyntaxKind.Block) {
172 switch (node.parent.kind) {
173 case ts.SyntaxKind.Constructor:
174 case ts.SyntaxKind.GetAccessor:
175 case ts.SyntaxKind.SetAccessor:
176 case ts.SyntaxKind.ArrowFunction:
177 case ts.SyntaxKind.FunctionExpression:
178 case ts.SyntaxKind.FunctionDeclaration:
179 case ts.SyntaxKind.MethodDeclaration:
180 return true;
181 default:
182 return false;
183 }
184 }
185 return true;
186}
187exports.canContainDirective = canContainDirective;
188/**
189 * Returns range for the given ts.Node
190 * @param node the ts.Node or ts.Token
191 * @param ast the AST object
192 * @returns the range data
193 */
194function getRange(node, ast) {
195 return [node.getStart(ast), node.getEnd()];
196}
197exports.getRange = getRange;
198/**
199 * Returns true if a given ts.Node is a token
200 * @param node the ts.Node
201 * @returns is a token
202 */
203function isToken(node) {
204 return (node.kind >= SyntaxKind.FirstToken && node.kind <= SyntaxKind.LastToken);
205}
206exports.isToken = isToken;
207/**
208 * Returns true if a given ts.Node is a JSX token
209 * @param node ts.Node to be checked
210 * @returns is a JSX token
211 */
212function isJSXToken(node) {
213 return (node.kind >= SyntaxKind.JsxElement && node.kind <= SyntaxKind.JsxAttribute);
214}
215exports.isJSXToken = isJSXToken;
216/**
217 * Returns the declaration kind of the given ts.Node
218 * @param node TypeScript AST node
219 * @returns declaration kind
220 */
221function getDeclarationKind(node) {
222 if (node.flags & ts.NodeFlags.Let) {
223 return 'let';
224 }
225 if (node.flags & ts.NodeFlags.Const) {
226 return 'const';
227 }
228 return 'var';
229}
230exports.getDeclarationKind = getDeclarationKind;
231/**
232 * Gets a ts.Node's accessibility level
233 * @param node The ts.Node
234 * @returns accessibility "public", "protected", "private", or null
235 */
236function getTSNodeAccessibility(node) {
237 const modifiers = node.modifiers;
238 if (!modifiers) {
239 return null;
240 }
241 for (let i = 0; i < modifiers.length; i++) {
242 const modifier = modifiers[i];
243 switch (modifier.kind) {
244 case SyntaxKind.PublicKeyword:
245 return 'public';
246 case SyntaxKind.ProtectedKeyword:
247 return 'protected';
248 case SyntaxKind.PrivateKeyword:
249 return 'private';
250 default:
251 break;
252 }
253 }
254 return null;
255}
256exports.getTSNodeAccessibility = getTSNodeAccessibility;
257/**
258 * Finds the next token based on the previous one and its parent
259 * Had to copy this from TS instead of using TS's version because theirs doesn't pass the ast to getChildren
260 * @param previousToken The previous TSToken
261 * @param parent The parent TSNode
262 * @param ast The TS AST
263 * @returns the next TSToken
264 */
265function findNextToken(previousToken, parent, ast) {
266 return find(parent);
267 function find(n) {
268 if (ts.isToken(n) && n.pos === previousToken.end) {
269 // this is token that starts at the end of previous token - return it
270 return n;
271 }
272 return firstDefined(n.getChildren(ast), (child) => {
273 const shouldDiveInChildNode =
274 // previous token is enclosed somewhere in the child
275 (child.pos <= previousToken.pos && child.end > previousToken.end) ||
276 // previous token ends exactly at the beginning of child
277 child.pos === previousToken.end;
278 return shouldDiveInChildNode && nodeHasTokens(child, ast)
279 ? find(child)
280 : undefined;
281 });
282 }
283}
284exports.findNextToken = findNextToken;
285/**
286 * Find the first matching ancestor based on the given predicate function.
287 * @param node The current ts.Node
288 * @param predicate The predicate function to apply to each checked ancestor
289 * @returns a matching parent ts.Node
290 */
291function findFirstMatchingAncestor(node, predicate) {
292 while (node) {
293 if (predicate(node)) {
294 return node;
295 }
296 node = node.parent;
297 }
298 return undefined;
299}
300exports.findFirstMatchingAncestor = findFirstMatchingAncestor;
301/**
302 * Returns true if a given ts.Node has a JSX token within its hierarchy
303 * @param node ts.Node to be checked
304 * @returns has JSX ancestor
305 */
306function hasJSXAncestor(node) {
307 return !!findFirstMatchingAncestor(node, isJSXToken);
308}
309exports.hasJSXAncestor = hasJSXAncestor;
310/**
311 * Unescape the text content of string literals, e.g. &amp; -> &
312 * @param text The escaped string literal text.
313 * @returns The unescaped string literal text.
314 */
315function unescapeStringLiteralText(text) {
316 return text.replace(/&(?:#\d+|#x[\da-fA-F]+|[0-9a-zA-Z]+);/g, entity => {
317 const item = entity.slice(1, -1);
318 if (item[0] === '#') {
319 const codePoint = item[1] === 'x'
320 ? parseInt(item.slice(2), 16)
321 : parseInt(item.slice(1), 10);
322 return codePoint > 0x10ffff // RangeError: Invalid code point
323 ? entity
324 : String.fromCodePoint(codePoint);
325 }
326 return xhtml_entities_1.xhtmlEntities[item] || entity;
327 });
328}
329exports.unescapeStringLiteralText = unescapeStringLiteralText;
330/**
331 * Returns true if a given ts.Node is a computed property
332 * @param node ts.Node to be checked
333 * @returns is Computed Property
334 */
335function isComputedProperty(node) {
336 return node.kind === SyntaxKind.ComputedPropertyName;
337}
338exports.isComputedProperty = isComputedProperty;
339/**
340 * Returns true if a given ts.Node is optional (has QuestionToken)
341 * @param node ts.Node to be checked
342 * @returns is Optional
343 */
344function isOptional(node) {
345 return node.questionToken
346 ? node.questionToken.kind === SyntaxKind.QuestionToken
347 : false;
348}
349exports.isOptional = isOptional;
350/**
351 * Returns true if the node is an optional chain node
352 */
353function isChainExpression(node) {
354 return node.type === ts_estree_1.AST_NODE_TYPES.ChainExpression;
355}
356exports.isChainExpression = isChainExpression;
357/**
358 * Returns true of the child of property access expression is an optional chain
359 */
360function isChildUnwrappableOptionalChain(node, child) {
361 return (isChainExpression(child) &&
362 // (x?.y).z is semantically different, and as such .z is no longer optional
363 node.expression.kind !== ts.SyntaxKind.ParenthesizedExpression);
364}
365exports.isChildUnwrappableOptionalChain = isChildUnwrappableOptionalChain;
366/**
367 * Returns the type of a given ts.Token
368 * @param token the ts.Token
369 * @returns the token type
370 */
371function getTokenType(token) {
372 if ('originalKeywordKind' in token && token.originalKeywordKind) {
373 if (token.originalKeywordKind === SyntaxKind.NullKeyword) {
374 return ts_estree_1.AST_TOKEN_TYPES.Null;
375 }
376 else if (token.originalKeywordKind >= SyntaxKind.FirstFutureReservedWord &&
377 token.originalKeywordKind <= SyntaxKind.LastKeyword) {
378 return ts_estree_1.AST_TOKEN_TYPES.Identifier;
379 }
380 return ts_estree_1.AST_TOKEN_TYPES.Keyword;
381 }
382 if (token.kind >= SyntaxKind.FirstKeyword &&
383 token.kind <= SyntaxKind.LastFutureReservedWord) {
384 if (token.kind === SyntaxKind.FalseKeyword ||
385 token.kind === SyntaxKind.TrueKeyword) {
386 return ts_estree_1.AST_TOKEN_TYPES.Boolean;
387 }
388 return ts_estree_1.AST_TOKEN_TYPES.Keyword;
389 }
390 if (token.kind >= SyntaxKind.FirstPunctuation &&
391 token.kind <= SyntaxKind.LastPunctuation) {
392 return ts_estree_1.AST_TOKEN_TYPES.Punctuator;
393 }
394 if (token.kind >= SyntaxKind.NoSubstitutionTemplateLiteral &&
395 token.kind <= SyntaxKind.TemplateTail) {
396 return ts_estree_1.AST_TOKEN_TYPES.Template;
397 }
398 switch (token.kind) {
399 case SyntaxKind.NumericLiteral:
400 return ts_estree_1.AST_TOKEN_TYPES.Numeric;
401 case SyntaxKind.JsxText:
402 return ts_estree_1.AST_TOKEN_TYPES.JSXText;
403 case SyntaxKind.StringLiteral:
404 // A TypeScript-StringLiteral token with a TypeScript-JsxAttribute or TypeScript-JsxElement parent,
405 // must actually be an ESTree-JSXText token
406 if (token.parent &&
407 (token.parent.kind === SyntaxKind.JsxAttribute ||
408 token.parent.kind === SyntaxKind.JsxElement)) {
409 return ts_estree_1.AST_TOKEN_TYPES.JSXText;
410 }
411 return ts_estree_1.AST_TOKEN_TYPES.String;
412 case SyntaxKind.RegularExpressionLiteral:
413 return ts_estree_1.AST_TOKEN_TYPES.RegularExpression;
414 case SyntaxKind.Identifier:
415 case SyntaxKind.ConstructorKeyword:
416 case SyntaxKind.GetKeyword:
417 case SyntaxKind.SetKeyword:
418 // intentional fallthrough
419 default:
420 }
421 // Some JSX tokens have to be determined based on their parent
422 if (token.parent && token.kind === SyntaxKind.Identifier) {
423 if (isJSXToken(token.parent)) {
424 return ts_estree_1.AST_TOKEN_TYPES.JSXIdentifier;
425 }
426 if (token.parent.kind === SyntaxKind.PropertyAccessExpression &&
427 hasJSXAncestor(token)) {
428 return ts_estree_1.AST_TOKEN_TYPES.JSXIdentifier;
429 }
430 }
431 return ts_estree_1.AST_TOKEN_TYPES.Identifier;
432}
433exports.getTokenType = getTokenType;
434/**
435 * Extends and formats a given ts.Token, for a given AST
436 * @param token the ts.Token
437 * @param ast the AST object
438 * @returns the converted Token
439 */
440function convertToken(token, ast) {
441 const start = token.kind === SyntaxKind.JsxText
442 ? token.getFullStart()
443 : token.getStart(ast);
444 const end = token.getEnd();
445 const value = ast.text.slice(start, end);
446 const tokenType = getTokenType(token);
447 if (tokenType === ts_estree_1.AST_TOKEN_TYPES.RegularExpression) {
448 return {
449 type: tokenType,
450 value,
451 range: [start, end],
452 loc: getLocFor(start, end, ast),
453 regex: {
454 pattern: value.slice(1, value.lastIndexOf('/')),
455 flags: value.slice(value.lastIndexOf('/') + 1),
456 },
457 };
458 }
459 else {
460 // @ts-expect-error TS is complaining about `value` not being the correct
461 // type but it is
462 return {
463 type: tokenType,
464 value,
465 range: [start, end],
466 loc: getLocFor(start, end, ast),
467 };
468 }
469}
470exports.convertToken = convertToken;
471/**
472 * Converts all tokens for the given AST
473 * @param ast the AST object
474 * @returns the converted Tokens
475 */
476function convertTokens(ast) {
477 const result = [];
478 /**
479 * @param node the ts.Node
480 */
481 function walk(node) {
482 // TypeScript generates tokens for types in JSDoc blocks. Comment tokens
483 // and their children should not be walked or added to the resulting tokens list.
484 if (isComment(node) || isJSDocComment(node)) {
485 return;
486 }
487 if (isToken(node) && node.kind !== SyntaxKind.EndOfFileToken) {
488 const converted = convertToken(node, ast);
489 if (converted) {
490 result.push(converted);
491 }
492 }
493 else {
494 node.getChildren(ast).forEach(walk);
495 }
496 }
497 walk(ast);
498 return result;
499}
500exports.convertTokens = convertTokens;
501class TSError extends Error {
502 constructor(message, fileName, index, lineNumber, column) {
503 super(message);
504 this.fileName = fileName;
505 this.index = index;
506 this.lineNumber = lineNumber;
507 this.column = column;
508 Object.defineProperty(this, 'name', {
509 value: new.target.name,
510 enumerable: false,
511 configurable: true,
512 });
513 }
514}
515exports.TSError = TSError;
516/**
517 * @param ast the AST object
518 * @param start the index at which the error starts
519 * @param message the error message
520 * @returns converted error object
521 */
522function createError(ast, start, message) {
523 const loc = ast.getLineAndCharacterOfPosition(start);
524 return new TSError(message, ast.fileName, start, loc.line + 1, loc.character);
525}
526exports.createError = createError;
527/**
528 * @param n the TSNode
529 * @param ast the TS AST
530 */
531function nodeHasTokens(n, ast) {
532 // If we have a token or node that has a non-zero width, it must have tokens.
533 // Note: getWidth() does not take trivia into account.
534 return n.kind === SyntaxKind.EndOfFileToken
535 ? !!n.jsDoc
536 : n.getWidth(ast) !== 0;
537}
538exports.nodeHasTokens = nodeHasTokens;
539/**
540 * Like `forEach`, but suitable for use with numbers and strings (which may be falsy).
541 * @template T
542 * @template U
543 * @param array
544 * @param callback
545 */
546function firstDefined(array, callback) {
547 if (array === undefined) {
548 return undefined;
549 }
550 for (let i = 0; i < array.length; i++) {
551 const result = callback(array[i], i);
552 if (result !== undefined) {
553 return result;
554 }
555 }
556 return undefined;
557}
558exports.firstDefined = firstDefined;
559//# sourceMappingURL=node-utils.js.map
\No newline at end of file