2 Object.defineProperty(exports, "__esModule", { value: true });
\r
3 exports.isValidIdentifier = exports.getLineBreakStyle = exports.getLineRanges = exports.forEachComment = exports.forEachTokenWithTrivia = exports.forEachToken = exports.isFunctionWithBody = exports.hasOwnThisReference = exports.isBlockScopeBoundary = exports.isFunctionScopeBoundary = exports.isTypeScopeBoundary = exports.isScopeBoundary = exports.ScopeBoundarySelector = exports.ScopeBoundary = exports.isInSingleStatementContext = exports.isBlockScopedDeclarationStatement = exports.isBlockScopedVariableDeclaration = exports.isBlockScopedVariableDeclarationList = exports.getVariableDeclarationKind = exports.VariableDeclarationKind = exports.forEachDeclaredVariable = exports.forEachDestructuringIdentifier = exports.getPropertyName = exports.getWrappedNodeAtPosition = exports.getAstNodeAtPosition = exports.commentText = exports.isPositionInComment = exports.getCommentAtPosition = exports.getTokenAtPosition = exports.getNextToken = exports.getPreviousToken = exports.getNextStatement = exports.getPreviousStatement = exports.isModifierFlagSet = exports.isObjectFlagSet = exports.isSymbolFlagSet = exports.isTypeFlagSet = exports.isNodeFlagSet = exports.hasAccessModifier = exports.isParameterProperty = exports.hasModifier = exports.getModifier = exports.isThisParameter = exports.isKeywordKind = exports.isJsDocKind = exports.isTypeNodeKind = exports.isAssignmentKind = exports.isNodeKind = exports.isTokenKind = exports.getChildOfKind = void 0;
\r
4 exports.getBaseOfClassLikeExpression = exports.hasExhaustiveCaseClauses = exports.formatPseudoBigInt = exports.unwrapParentheses = exports.getSingleLateBoundPropertyNameOfPropertyName = exports.getLateBoundPropertyNamesOfPropertyName = exports.getLateBoundPropertyNames = exports.getPropertyNameOfWellKnownSymbol = exports.isWellKnownSymbolLiterally = exports.isBindableObjectDefinePropertyCall = exports.isReadonlyAssignmentDeclaration = exports.isInConstContext = exports.isConstAssertion = exports.getTsCheckDirective = exports.getCheckJsDirective = exports.isAmbientModule = exports.isCompilerOptionEnabled = exports.isStrictCompilerOptionEnabled = exports.getIIFE = exports.isAmbientModuleBlock = exports.isStatementInAmbientContext = exports.findImportLikeNodes = exports.findImports = exports.ImportKind = exports.parseJsDocOfNode = exports.getJsDoc = exports.canHaveJsDoc = exports.isReassignmentTarget = exports.getAccessKind = exports.AccessKind = exports.isExpressionValueUsed = exports.getDeclarationOfBindingElement = exports.hasSideEffects = exports.SideEffectOptions = exports.isSameLine = exports.isNumericPropertyName = exports.isValidJsxIdentifier = exports.isValidNumericLiteral = exports.isValidPropertyName = exports.isValidPropertyAccess = void 0;
\r
5 const ts = require("typescript");
\r
6 const node_1 = require("../typeguard/node");
\r
7 const _3_2_1 = require("../typeguard/3.2");
\r
8 const type_1 = require("./type");
\r
9 function getChildOfKind(node, kind, sourceFile) {
\r
10 for (const child of node.getChildren(sourceFile))
\r
11 if (child.kind === kind)
\r
14 exports.getChildOfKind = getChildOfKind;
\r
15 function isTokenKind(kind) {
\r
16 return kind >= ts.SyntaxKind.FirstToken && kind <= ts.SyntaxKind.LastToken;
\r
18 exports.isTokenKind = isTokenKind;
\r
19 function isNodeKind(kind) {
\r
20 return kind >= ts.SyntaxKind.FirstNode;
\r
22 exports.isNodeKind = isNodeKind;
\r
23 function isAssignmentKind(kind) {
\r
24 return kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment;
\r
26 exports.isAssignmentKind = isAssignmentKind;
\r
27 function isTypeNodeKind(kind) {
\r
28 return kind >= ts.SyntaxKind.FirstTypeNode && kind <= ts.SyntaxKind.LastTypeNode;
\r
30 exports.isTypeNodeKind = isTypeNodeKind;
\r
31 function isJsDocKind(kind) {
\r
32 return kind >= ts.SyntaxKind.FirstJSDocNode && kind <= ts.SyntaxKind.LastJSDocNode;
\r
34 exports.isJsDocKind = isJsDocKind;
\r
35 function isKeywordKind(kind) {
\r
36 return kind >= ts.SyntaxKind.FirstKeyword && kind <= ts.SyntaxKind.LastKeyword;
\r
38 exports.isKeywordKind = isKeywordKind;
\r
39 function isThisParameter(parameter) {
\r
40 return parameter.name.kind === ts.SyntaxKind.Identifier && parameter.name.originalKeywordKind === ts.SyntaxKind.ThisKeyword;
\r
42 exports.isThisParameter = isThisParameter;
\r
43 function getModifier(node, kind) {
\r
44 if (node.modifiers !== undefined)
\r
45 for (const modifier of node.modifiers)
\r
46 if (modifier.kind === kind)
\r
49 exports.getModifier = getModifier;
\r
50 function hasModifier(modifiers, ...kinds) {
\r
51 if (modifiers === undefined)
\r
53 for (const modifier of modifiers)
\r
54 if (kinds.includes(modifier.kind))
\r
58 exports.hasModifier = hasModifier;
\r
59 function isParameterProperty(node) {
\r
60 return hasModifier(node.modifiers, ts.SyntaxKind.PublicKeyword, ts.SyntaxKind.ProtectedKeyword, ts.SyntaxKind.PrivateKeyword, ts.SyntaxKind.ReadonlyKeyword);
\r
62 exports.isParameterProperty = isParameterProperty;
\r
63 function hasAccessModifier(node) {
\r
64 return isModifierFlagSet(node, ts.ModifierFlags.AccessibilityModifier);
\r
66 exports.hasAccessModifier = hasAccessModifier;
\r
67 function isFlagSet(obj, flag) {
\r
68 return (obj.flags & flag) !== 0;
\r
70 exports.isNodeFlagSet = isFlagSet;
\r
71 exports.isTypeFlagSet = isFlagSet;
\r
72 exports.isSymbolFlagSet = isFlagSet;
\r
73 function isObjectFlagSet(objectType, flag) {
\r
74 return (objectType.objectFlags & flag) !== 0;
\r
76 exports.isObjectFlagSet = isObjectFlagSet;
\r
77 function isModifierFlagSet(node, flag) {
\r
78 return (ts.getCombinedModifierFlags(node) & flag) !== 0;
\r
80 exports.isModifierFlagSet = isModifierFlagSet;
\r
81 function getPreviousStatement(statement) {
\r
82 const parent = statement.parent;
\r
83 if (node_1.isBlockLike(parent)) {
\r
84 const index = parent.statements.indexOf(statement);
\r
86 return parent.statements[index - 1];
\r
89 exports.getPreviousStatement = getPreviousStatement;
\r
90 function getNextStatement(statement) {
\r
91 const parent = statement.parent;
\r
92 if (node_1.isBlockLike(parent)) {
\r
93 const index = parent.statements.indexOf(statement);
\r
94 if (index < parent.statements.length)
\r
95 return parent.statements[index + 1];
\r
98 exports.getNextStatement = getNextStatement;
\r
99 /** Returns the token before the start of `node` or `undefined` if there is none. */
\r
100 function getPreviousToken(node, sourceFile) {
\r
101 const { pos } = node;
\r
105 node = node.parent;
\r
106 while (node.pos === pos);
\r
107 return getTokenAtPositionWorker(node, pos - 1, sourceFile !== null && sourceFile !== void 0 ? sourceFile : node.getSourceFile(), false);
\r
109 exports.getPreviousToken = getPreviousToken;
\r
110 /** Returns the next token that begins after the end of `node`. Returns `undefined` for SourceFile and EndOfFileToken */
\r
111 function getNextToken(node, sourceFile) {
\r
112 if (node.kind === ts.SyntaxKind.SourceFile || node.kind === ts.SyntaxKind.EndOfFileToken)
\r
114 const end = node.end;
\r
115 node = node.parent;
\r
116 while (node.end === end) {
\r
117 if (node.parent === undefined)
\r
118 return node.endOfFileToken;
\r
119 node = node.parent;
\r
121 return getTokenAtPositionWorker(node, end, sourceFile !== null && sourceFile !== void 0 ? sourceFile : node.getSourceFile(), false);
\r
123 exports.getNextToken = getNextToken;
\r
124 /** Returns the token at or following the specified position or undefined if none is found inside `parent`. */
\r
125 function getTokenAtPosition(parent, pos, sourceFile, allowJsDoc) {
\r
126 if (pos < parent.pos || pos >= parent.end)
\r
128 if (isTokenKind(parent.kind))
\r
130 return getTokenAtPositionWorker(parent, pos, sourceFile !== null && sourceFile !== void 0 ? sourceFile : parent.getSourceFile(), allowJsDoc === true);
\r
132 exports.getTokenAtPosition = getTokenAtPosition;
\r
133 function getTokenAtPositionWorker(node, pos, sourceFile, allowJsDoc) {
\r
135 // if we are not interested in JSDoc, we can skip to the deepest AST node at the given position
\r
136 node = getAstNodeAtPosition(node, pos);
\r
137 if (isTokenKind(node.kind))
\r
140 outer: while (true) {
\r
141 for (const child of node.getChildren(sourceFile)) {
\r
142 if (child.end > pos && (allowJsDoc || child.kind !== ts.SyntaxKind.JSDocComment)) {
\r
143 if (isTokenKind(child.kind))
\r
145 // next token is nested in another node
\r
154 * Return the comment at the specified position.
\r
155 * You can pass an optional `parent` to avoid some work finding the corresponding token starting at `sourceFile`.
\r
156 * If the `parent` parameter is passed, `pos` must be between `parent.pos` and `parent.end`.
\r
158 function getCommentAtPosition(sourceFile, pos, parent = sourceFile) {
\r
159 const token = getTokenAtPosition(parent, pos, sourceFile);
\r
160 if (token === undefined || token.kind === ts.SyntaxKind.JsxText || pos >= token.end - (ts.tokenToString(token.kind) || '').length)
\r
162 const startPos = token.pos === 0
\r
163 ? (ts.getShebang(sourceFile.text) || '').length
\r
165 return startPos !== 0 && ts.forEachTrailingCommentRange(sourceFile.text, startPos, commentAtPositionCallback, pos) ||
\r
166 ts.forEachLeadingCommentRange(sourceFile.text, startPos, commentAtPositionCallback, pos);
\r
168 exports.getCommentAtPosition = getCommentAtPosition;
\r
169 function commentAtPositionCallback(pos, end, kind, _nl, at) {
\r
170 return at >= pos && at < end ? { pos, end, kind } : undefined;
\r
173 * Returns whether the specified position is inside a comment.
\r
174 * You can pass an optional `parent` to avoid some work finding the corresponding token starting at `sourceFile`.
\r
175 * If the `parent` parameter is passed, `pos` must be between `parent.pos` and `parent.end`.
\r
177 function isPositionInComment(sourceFile, pos, parent) {
\r
178 return getCommentAtPosition(sourceFile, pos, parent) !== undefined;
\r
180 exports.isPositionInComment = isPositionInComment;
\r
181 function commentText(sourceText, comment) {
\r
182 return sourceText.substring(comment.pos + 2, comment.kind === ts.SyntaxKind.SingleLineCommentTrivia ? comment.end : comment.end - 2);
\r
184 exports.commentText = commentText;
\r
185 /** Returns the deepest AST Node at `pos`. Returns undefined if `pos` is outside of the range of `node` */
\r
186 function getAstNodeAtPosition(node, pos) {
\r
187 if (node.pos > pos || node.end <= pos)
\r
189 while (isNodeKind(node.kind)) {
\r
190 const nested = ts.forEachChild(node, (child) => child.pos <= pos && child.end > pos ? child : undefined);
\r
191 if (nested === undefined)
\r
197 exports.getAstNodeAtPosition = getAstNodeAtPosition;
\r
199 * Returns the NodeWrap of deepest AST node that contains `pos` between its `pos` and `end`.
\r
200 * Only returns undefined if pos is outside of `wrap`
\r
202 function getWrappedNodeAtPosition(wrap, pos) {
\r
203 if (wrap.node.pos > pos || wrap.node.end <= pos)
\r
205 outer: while (true) {
\r
206 for (const child of wrap.children) {
\r
207 if (child.node.pos > pos)
\r
209 if (child.node.end > pos) {
\r
217 exports.getWrappedNodeAtPosition = getWrappedNodeAtPosition;
\r
218 function getPropertyName(propertyName) {
\r
219 if (propertyName.kind === ts.SyntaxKind.ComputedPropertyName) {
\r
220 const expression = unwrapParentheses(propertyName.expression);
\r
221 if (node_1.isPrefixUnaryExpression(expression)) {
\r
222 let negate = false;
\r
223 switch (expression.operator) {
\r
224 case ts.SyntaxKind.MinusToken:
\r
227 case ts.SyntaxKind.PlusToken:
\r
228 return node_1.isNumericLiteral(expression.operand)
\r
229 ? `${negate ? '-' : ''}${expression.operand.text}`
\r
230 : _3_2_1.isBigIntLiteral(expression.operand)
\r
231 ? `${negate ? '-' : ''}${expression.operand.text.slice(0, -1)}`
\r
237 if (_3_2_1.isBigIntLiteral(expression))
\r
238 // handle BigInt, even though TypeScript doesn't allow BigInt as computed property name
\r
239 return expression.text.slice(0, -1);
\r
240 if (node_1.isNumericOrStringLikeLiteral(expression))
\r
241 return expression.text;
\r
244 return propertyName.kind === ts.SyntaxKind.PrivateIdentifier ? undefined : propertyName.text;
\r
246 exports.getPropertyName = getPropertyName;
\r
247 function forEachDestructuringIdentifier(pattern, fn) {
\r
248 for (const element of pattern.elements) {
\r
249 if (element.kind !== ts.SyntaxKind.BindingElement)
\r
252 if (element.name.kind === ts.SyntaxKind.Identifier) {
\r
253 result = fn(element);
\r
256 result = forEachDestructuringIdentifier(element.name, fn);
\r
262 exports.forEachDestructuringIdentifier = forEachDestructuringIdentifier;
\r
263 function forEachDeclaredVariable(declarationList, cb) {
\r
264 for (const declaration of declarationList.declarations) {
\r
266 if (declaration.name.kind === ts.SyntaxKind.Identifier) {
\r
267 result = cb(declaration);
\r
270 result = forEachDestructuringIdentifier(declaration.name, cb);
\r
276 exports.forEachDeclaredVariable = forEachDeclaredVariable;
\r
277 var VariableDeclarationKind;
\r
278 (function (VariableDeclarationKind) {
\r
279 VariableDeclarationKind[VariableDeclarationKind["Var"] = 0] = "Var";
\r
280 VariableDeclarationKind[VariableDeclarationKind["Let"] = 1] = "Let";
\r
281 VariableDeclarationKind[VariableDeclarationKind["Const"] = 2] = "Const";
\r
282 })(VariableDeclarationKind = exports.VariableDeclarationKind || (exports.VariableDeclarationKind = {}));
\r
283 function getVariableDeclarationKind(declarationList) {
\r
284 if (declarationList.flags & ts.NodeFlags.Let)
\r
285 return 1 /* Let */;
\r
286 if (declarationList.flags & ts.NodeFlags.Const)
\r
287 return 2 /* Const */;
\r
288 return 0 /* Var */;
\r
290 exports.getVariableDeclarationKind = getVariableDeclarationKind;
\r
291 function isBlockScopedVariableDeclarationList(declarationList) {
\r
292 return (declarationList.flags & ts.NodeFlags.BlockScoped) !== 0;
\r
294 exports.isBlockScopedVariableDeclarationList = isBlockScopedVariableDeclarationList;
\r
295 function isBlockScopedVariableDeclaration(declaration) {
\r
296 const parent = declaration.parent;
\r
297 return parent.kind === ts.SyntaxKind.CatchClause ||
\r
298 isBlockScopedVariableDeclarationList(parent);
\r
300 exports.isBlockScopedVariableDeclaration = isBlockScopedVariableDeclaration;
\r
301 function isBlockScopedDeclarationStatement(statement) {
\r
302 switch (statement.kind) {
\r
303 case ts.SyntaxKind.VariableStatement:
\r
304 return isBlockScopedVariableDeclarationList(statement.declarationList);
\r
305 case ts.SyntaxKind.ClassDeclaration:
\r
306 case ts.SyntaxKind.EnumDeclaration:
\r
307 case ts.SyntaxKind.InterfaceDeclaration:
\r
308 case ts.SyntaxKind.TypeAliasDeclaration:
\r
314 exports.isBlockScopedDeclarationStatement = isBlockScopedDeclarationStatement;
\r
315 function isInSingleStatementContext(statement) {
\r
316 switch (statement.parent.kind) {
\r
317 case ts.SyntaxKind.ForStatement:
\r
318 case ts.SyntaxKind.ForInStatement:
\r
319 case ts.SyntaxKind.ForOfStatement:
\r
320 case ts.SyntaxKind.WhileStatement:
\r
321 case ts.SyntaxKind.DoStatement:
\r
322 case ts.SyntaxKind.IfStatement:
\r
323 case ts.SyntaxKind.WithStatement:
\r
324 case ts.SyntaxKind.LabeledStatement:
\r
330 exports.isInSingleStatementContext = isInSingleStatementContext;
\r
332 (function (ScopeBoundary) {
\r
333 ScopeBoundary[ScopeBoundary["None"] = 0] = "None";
\r
334 ScopeBoundary[ScopeBoundary["Function"] = 1] = "Function";
\r
335 ScopeBoundary[ScopeBoundary["Block"] = 2] = "Block";
\r
336 ScopeBoundary[ScopeBoundary["Type"] = 4] = "Type";
\r
337 ScopeBoundary[ScopeBoundary["ConditionalType"] = 8] = "ConditionalType";
\r
338 })(ScopeBoundary = exports.ScopeBoundary || (exports.ScopeBoundary = {}));
\r
339 var ScopeBoundarySelector;
\r
340 (function (ScopeBoundarySelector) {
\r
341 ScopeBoundarySelector[ScopeBoundarySelector["Function"] = 1] = "Function";
\r
342 ScopeBoundarySelector[ScopeBoundarySelector["Block"] = 3] = "Block";
\r
343 ScopeBoundarySelector[ScopeBoundarySelector["Type"] = 7] = "Type";
\r
344 ScopeBoundarySelector[ScopeBoundarySelector["InferType"] = 8] = "InferType";
\r
345 })(ScopeBoundarySelector = exports.ScopeBoundarySelector || (exports.ScopeBoundarySelector = {}));
\r
346 function isScopeBoundary(node) {
\r
347 return isFunctionScopeBoundary(node) || isBlockScopeBoundary(node) || isTypeScopeBoundary(node);
\r
349 exports.isScopeBoundary = isScopeBoundary;
\r
350 function isTypeScopeBoundary(node) {
\r
351 switch (node.kind) {
\r
352 case ts.SyntaxKind.InterfaceDeclaration:
\r
353 case ts.SyntaxKind.TypeAliasDeclaration:
\r
354 case ts.SyntaxKind.MappedType:
\r
355 return 4 /* Type */;
\r
356 case ts.SyntaxKind.ConditionalType:
\r
357 return 8 /* ConditionalType */;
\r
359 return 0 /* None */;
\r
362 exports.isTypeScopeBoundary = isTypeScopeBoundary;
\r
363 function isFunctionScopeBoundary(node) {
\r
364 switch (node.kind) {
\r
365 case ts.SyntaxKind.FunctionExpression:
\r
366 case ts.SyntaxKind.ArrowFunction:
\r
367 case ts.SyntaxKind.Constructor:
\r
368 case ts.SyntaxKind.ModuleDeclaration:
\r
369 case ts.SyntaxKind.ClassDeclaration:
\r
370 case ts.SyntaxKind.ClassExpression:
\r
371 case ts.SyntaxKind.EnumDeclaration:
\r
372 case ts.SyntaxKind.MethodDeclaration:
\r
373 case ts.SyntaxKind.FunctionDeclaration:
\r
374 case ts.SyntaxKind.GetAccessor:
\r
375 case ts.SyntaxKind.SetAccessor:
\r
376 case ts.SyntaxKind.MethodSignature:
\r
377 case ts.SyntaxKind.CallSignature:
\r
378 case ts.SyntaxKind.ConstructSignature:
\r
379 case ts.SyntaxKind.ConstructorType:
\r
380 case ts.SyntaxKind.FunctionType:
\r
381 return 1 /* Function */;
\r
382 case ts.SyntaxKind.SourceFile:
\r
383 // if SourceFile is no module, it contributes to the global scope and is therefore no scope boundary
\r
384 return ts.isExternalModule(node) ? 1 /* Function */ : 0 /* None */;
\r
386 return 0 /* None */;
\r
389 exports.isFunctionScopeBoundary = isFunctionScopeBoundary;
\r
390 function isBlockScopeBoundary(node) {
\r
391 switch (node.kind) {
\r
392 case ts.SyntaxKind.Block:
\r
393 const parent = node.parent;
\r
394 return parent.kind !== ts.SyntaxKind.CatchClause &&
\r
395 // blocks inside SourceFile are block scope boundaries
\r
396 (parent.kind === ts.SyntaxKind.SourceFile ||
\r
397 // blocks that are direct children of a function scope boundary are no scope boundary
\r
398 // for example the FunctionBlock is part of the function scope of the containing function
\r
399 !isFunctionScopeBoundary(parent))
\r
402 case ts.SyntaxKind.ForStatement:
\r
403 case ts.SyntaxKind.ForInStatement:
\r
404 case ts.SyntaxKind.ForOfStatement:
\r
405 case ts.SyntaxKind.CaseBlock:
\r
406 case ts.SyntaxKind.CatchClause:
\r
407 case ts.SyntaxKind.WithStatement:
\r
408 return 2 /* Block */;
\r
410 return 0 /* None */;
\r
413 exports.isBlockScopeBoundary = isBlockScopeBoundary;
\r
414 /** Returns true for scope boundaries that have their own `this` reference instead of inheriting it from the containing scope */
\r
415 function hasOwnThisReference(node) {
\r
416 switch (node.kind) {
\r
417 case ts.SyntaxKind.ClassDeclaration:
\r
418 case ts.SyntaxKind.ClassExpression:
\r
419 case ts.SyntaxKind.FunctionExpression:
\r
421 case ts.SyntaxKind.FunctionDeclaration:
\r
422 return node.body !== undefined;
\r
423 case ts.SyntaxKind.MethodDeclaration:
\r
424 case ts.SyntaxKind.GetAccessor:
\r
425 case ts.SyntaxKind.SetAccessor:
\r
426 return node.parent.kind === ts.SyntaxKind.ObjectLiteralExpression;
\r
431 exports.hasOwnThisReference = hasOwnThisReference;
\r
432 function isFunctionWithBody(node) {
\r
433 switch (node.kind) {
\r
434 case ts.SyntaxKind.GetAccessor:
\r
435 case ts.SyntaxKind.SetAccessor:
\r
436 case ts.SyntaxKind.FunctionDeclaration:
\r
437 case ts.SyntaxKind.MethodDeclaration:
\r
438 case ts.SyntaxKind.Constructor:
\r
439 return node.body !== undefined;
\r
440 case ts.SyntaxKind.FunctionExpression:
\r
441 case ts.SyntaxKind.ArrowFunction:
\r
447 exports.isFunctionWithBody = isFunctionWithBody;
\r
449 * Iterate over all tokens of `node`
\r
451 * @param node The node whose tokens should be visited
\r
452 * @param cb Is called for every token contained in `node`
\r
454 function forEachToken(node, cb, sourceFile = node.getSourceFile()) {
\r
457 if (isTokenKind(node.kind)) {
\r
460 else if (node.kind !== ts.SyntaxKind.JSDocComment) {
\r
461 const children = node.getChildren(sourceFile);
\r
462 if (children.length === 1) {
\r
463 node = children[0];
\r
466 for (let i = children.length - 1; i >= 0; --i)
\r
467 queue.push(children[i]); // add children in reverse order, when we pop the next element from the queue, it's the first child
\r
469 if (queue.length === 0)
\r
471 node = queue.pop();
\r
474 exports.forEachToken = forEachToken;
\r
476 * Iterate over all tokens and trivia of `node`
\r
478 * @description JsDoc comments are treated like regular comments
\r
480 * @param node The node whose tokens should be visited
\r
481 * @param cb Is called for every token contained in `node` and trivia before the token
\r
483 function forEachTokenWithTrivia(node, cb, sourceFile = node.getSourceFile()) {
\r
484 const fullText = sourceFile.text;
\r
485 const scanner = ts.createScanner(sourceFile.languageVersion, false, sourceFile.languageVariant, fullText);
\r
486 return forEachToken(node, (token) => {
\r
487 const tokenStart = token.kind === ts.SyntaxKind.JsxText || token.pos === token.end ? token.pos : token.getStart(sourceFile);
\r
488 if (tokenStart !== token.pos) {
\r
489 // we only have to handle trivia before each token. whitespace at the end of the file is followed by EndOfFileToken
\r
490 scanner.setTextPos(token.pos);
\r
491 let kind = scanner.scan();
\r
492 let pos = scanner.getTokenPos();
\r
493 while (pos < tokenStart) {
\r
494 const textPos = scanner.getTextPos();
\r
495 cb(fullText, kind, { pos, end: textPos }, token.parent);
\r
496 if (textPos === tokenStart)
\r
498 kind = scanner.scan();
\r
499 pos = scanner.getTokenPos();
\r
502 return cb(fullText, token.kind, { end: token.end, pos: tokenStart }, token.parent);
\r
505 exports.forEachTokenWithTrivia = forEachTokenWithTrivia;
\r
506 /** Iterate over all comments owned by `node` or its children */
\r
507 function forEachComment(node, cb, sourceFile = node.getSourceFile()) {
\r
508 /* Visit all tokens and skip trivia.
\r
509 Comment ranges between tokens are parsed without the need of a scanner.
\r
510 forEachTokenWithWhitespace does intentionally not pay attention to the correct comment ownership of nodes as it always
\r
511 scans all trivia before each token, which could include trailing comments of the previous token.
\r
512 Comment onwership is done right in this function*/
\r
513 const fullText = sourceFile.text;
\r
514 const notJsx = sourceFile.languageVariant !== ts.LanguageVariant.JSX;
\r
515 return forEachToken(node, (token) => {
\r
516 if (token.pos === token.end)
\r
518 if (token.kind !== ts.SyntaxKind.JsxText)
\r
519 ts.forEachLeadingCommentRange(fullText,
\r
520 // skip shebang at position 0
\r
521 token.pos === 0 ? (ts.getShebang(fullText) || '').length : token.pos, commentCallback);
\r
522 if (notJsx || canHaveTrailingTrivia(token))
\r
523 return ts.forEachTrailingCommentRange(fullText, token.end, commentCallback);
\r
525 function commentCallback(pos, end, kind) {
\r
526 cb(fullText, { pos, end, kind });
\r
529 exports.forEachComment = forEachComment;
\r
530 /** Exclude trailing positions that would lead to scanning for trivia inside JsxText */
\r
531 function canHaveTrailingTrivia(token) {
\r
532 switch (token.kind) {
\r
533 case ts.SyntaxKind.CloseBraceToken:
\r
534 // after a JsxExpression inside a JsxElement's body can only be other JsxChild, but no trivia
\r
535 return token.parent.kind !== ts.SyntaxKind.JsxExpression || !isJsxElementOrFragment(token.parent.parent);
\r
536 case ts.SyntaxKind.GreaterThanToken:
\r
537 switch (token.parent.kind) {
\r
538 case ts.SyntaxKind.JsxOpeningElement:
\r
539 // if end is not equal, this is part of the type arguments list. in all other cases it would be inside the element body
\r
540 return token.end !== token.parent.end;
\r
541 case ts.SyntaxKind.JsxOpeningFragment:
\r
542 return false; // would be inside the fragment
\r
543 case ts.SyntaxKind.JsxSelfClosingElement:
\r
544 return token.end !== token.parent.end || // if end is not equal, this is part of the type arguments list
\r
545 !isJsxElementOrFragment(token.parent.parent); // there's only trailing trivia if it's the end of the top element
\r
546 case ts.SyntaxKind.JsxClosingElement:
\r
547 case ts.SyntaxKind.JsxClosingFragment:
\r
548 // there's only trailing trivia if it's the end of the top element
\r
549 return !isJsxElementOrFragment(token.parent.parent.parent);
\r
554 function isJsxElementOrFragment(node) {
\r
555 return node.kind === ts.SyntaxKind.JsxElement || node.kind === ts.SyntaxKind.JsxFragment;
\r
557 function getLineRanges(sourceFile) {
\r
558 const lineStarts = sourceFile.getLineStarts();
\r
560 const length = lineStarts.length;
\r
561 const sourceText = sourceFile.text;
\r
563 for (let i = 1; i < length; ++i) {
\r
564 const end = lineStarts[i];
\r
566 for (; lineEnd > pos; --lineEnd)
\r
567 if (!ts.isLineBreak(sourceText.charCodeAt(lineEnd - 1)))
\r
572 contentLength: lineEnd - pos,
\r
578 end: sourceFile.end,
\r
579 contentLength: sourceFile.end - pos,
\r
583 exports.getLineRanges = getLineRanges;
\r
584 /** Get the line break style used in sourceFile. This function only looks at the first line break. If there is none, \n is assumed. */
\r
585 function getLineBreakStyle(sourceFile) {
\r
586 const lineStarts = sourceFile.getLineStarts();
\r
587 return lineStarts.length === 1 || lineStarts[1] < 2 || sourceFile.text[lineStarts[1] - 2] !== '\r'
\r
591 exports.getLineBreakStyle = getLineBreakStyle;
\r
593 function scanToken(text, languageVersion) {
\r
594 if (cachedScanner === undefined) {
\r
596 cachedScanner = ts.createScanner(languageVersion, false, undefined, text);
\r
599 cachedScanner.setScriptTarget(languageVersion);
\r
600 cachedScanner.setText(text);
\r
602 cachedScanner.scan();
\r
603 return cachedScanner;
\r
606 * Determines whether the given text parses as a standalone identifier.
\r
607 * This is not a guarantee that it works in every context. The property name in PropertyAccessExpressions for example allows reserved words.
\r
608 * Depending on the context it could be parsed as contextual keyword or TypeScript keyword.
\r
610 function isValidIdentifier(text, languageVersion = ts.ScriptTarget.Latest) {
\r
611 const scan = scanToken(text, languageVersion);
\r
612 return scan.isIdentifier() && scan.getTextPos() === text.length && scan.getTokenPos() === 0;
\r
614 exports.isValidIdentifier = isValidIdentifier;
\r
615 function charSize(ch) {
\r
616 return ch >= 0x10000 ? 2 : 1;
\r
619 * Determines whether the given text can be used to access a property with a PropertyAccessExpression while preserving the property's name.
\r
621 function isValidPropertyAccess(text, languageVersion = ts.ScriptTarget.Latest) {
\r
622 if (text.length === 0)
\r
624 let ch = text.codePointAt(0);
\r
625 if (!ts.isIdentifierStart(ch, languageVersion))
\r
627 for (let i = charSize(ch); i < text.length; i += charSize(ch)) {
\r
628 ch = text.codePointAt(i);
\r
629 if (!ts.isIdentifierPart(ch, languageVersion))
\r
634 exports.isValidPropertyAccess = isValidPropertyAccess;
\r
636 * Determines whether the given text can be used as unquoted name of a property declaration while preserving the property's name.
\r
638 function isValidPropertyName(text, languageVersion = ts.ScriptTarget.Latest) {
\r
639 if (isValidPropertyAccess(text, languageVersion))
\r
641 const scan = scanToken(text, languageVersion);
\r
642 return scan.getTextPos() === text.length &&
\r
643 scan.getToken() === ts.SyntaxKind.NumericLiteral && scan.getTokenValue() === text; // ensure stringified number equals literal
\r
645 exports.isValidPropertyName = isValidPropertyName;
\r
647 * Determines whether the given text can be parsed as a numeric literal.
\r
649 function isValidNumericLiteral(text, languageVersion = ts.ScriptTarget.Latest) {
\r
650 const scan = scanToken(text, languageVersion);
\r
651 return scan.getToken() === ts.SyntaxKind.NumericLiteral && scan.getTextPos() === text.length && scan.getTokenPos() === 0;
\r
653 exports.isValidNumericLiteral = isValidNumericLiteral;
\r
655 * Determines whether the given text can be used as JSX tag or attribute name while preserving the exact name.
\r
657 function isValidJsxIdentifier(text, languageVersion = ts.ScriptTarget.Latest) {
\r
658 if (text.length === 0)
\r
660 let seenNamespaceSeparator = false;
\r
661 let ch = text.codePointAt(0);
\r
662 if (!ts.isIdentifierStart(ch, languageVersion))
\r
664 for (let i = charSize(ch); i < text.length; i += charSize(ch)) {
\r
665 ch = text.codePointAt(i);
\r
666 if (!ts.isIdentifierPart(ch, languageVersion) && ch !== 45 /* minus */) {
\r
667 if (!seenNamespaceSeparator && ch === 58 /* colon */ && i + charSize(ch) !== text.length) {
\r
668 seenNamespaceSeparator = true;
\r
677 exports.isValidJsxIdentifier = isValidJsxIdentifier;
\r
678 function isNumericPropertyName(name) {
\r
679 return String(+name) === name;
\r
681 exports.isNumericPropertyName = isNumericPropertyName;
\r
682 function isSameLine(sourceFile, pos1, pos2) {
\r
683 return ts.getLineAndCharacterOfPosition(sourceFile, pos1).line === ts.getLineAndCharacterOfPosition(sourceFile, pos2).line;
\r
685 exports.isSameLine = isSameLine;
\r
686 var SideEffectOptions;
\r
687 (function (SideEffectOptions) {
\r
688 SideEffectOptions[SideEffectOptions["None"] = 0] = "None";
\r
689 SideEffectOptions[SideEffectOptions["TaggedTemplate"] = 1] = "TaggedTemplate";
\r
690 SideEffectOptions[SideEffectOptions["Constructor"] = 2] = "Constructor";
\r
691 SideEffectOptions[SideEffectOptions["JsxElement"] = 4] = "JsxElement";
\r
692 })(SideEffectOptions = exports.SideEffectOptions || (exports.SideEffectOptions = {}));
\r
693 function hasSideEffects(node, options) {
\r
697 switch (node.kind) {
\r
698 case ts.SyntaxKind.CallExpression:
\r
699 case ts.SyntaxKind.PostfixUnaryExpression:
\r
700 case ts.SyntaxKind.AwaitExpression:
\r
701 case ts.SyntaxKind.YieldExpression:
\r
702 case ts.SyntaxKind.DeleteExpression:
\r
704 case ts.SyntaxKind.TypeAssertionExpression:
\r
705 case ts.SyntaxKind.AsExpression:
\r
706 case ts.SyntaxKind.ParenthesizedExpression:
\r
707 case ts.SyntaxKind.NonNullExpression:
\r
708 case ts.SyntaxKind.VoidExpression:
\r
709 case ts.SyntaxKind.TypeOfExpression:
\r
710 case ts.SyntaxKind.PropertyAccessExpression:
\r
711 case ts.SyntaxKind.SpreadElement:
\r
712 case ts.SyntaxKind.PartiallyEmittedExpression:
\r
713 node = node.expression;
\r
715 case ts.SyntaxKind.BinaryExpression:
\r
716 if (isAssignmentKind(node.operatorToken.kind))
\r
718 queue.push(node.right);
\r
721 case ts.SyntaxKind.PrefixUnaryExpression:
\r
722 switch (node.operator) {
\r
723 case ts.SyntaxKind.PlusPlusToken:
\r
724 case ts.SyntaxKind.MinusMinusToken:
\r
727 node = node.operand;
\r
730 case ts.SyntaxKind.ElementAccessExpression:
\r
731 if (node.argumentExpression !== undefined) // for compatibility with typescript@<2.9.0
\r
732 queue.push(node.argumentExpression);
\r
733 node = node.expression;
\r
735 case ts.SyntaxKind.ConditionalExpression:
\r
736 queue.push(node.whenTrue, node.whenFalse);
\r
737 node = node.condition;
\r
739 case ts.SyntaxKind.NewExpression:
\r
740 if (options & 2 /* Constructor */)
\r
742 if (node.arguments !== undefined)
\r
743 queue.push(...node.arguments);
\r
744 node = node.expression;
\r
746 case ts.SyntaxKind.TaggedTemplateExpression:
\r
747 if (options & 1 /* TaggedTemplate */)
\r
749 queue.push(node.tag);
\r
750 node = node.template;
\r
751 if (node.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral)
\r
754 case ts.SyntaxKind.TemplateExpression:
\r
755 for (const child of node.templateSpans)
\r
756 queue.push(child.expression);
\r
758 case ts.SyntaxKind.ClassExpression: {
\r
759 if (node.decorators !== undefined)
\r
761 for (const child of node.members) {
\r
762 if (child.decorators !== undefined)
\r
764 if (!hasModifier(child.modifiers, ts.SyntaxKind.DeclareKeyword)) {
\r
765 if (((_a = child.name) === null || _a === void 0 ? void 0 : _a.kind) === ts.SyntaxKind.ComputedPropertyName)
\r
766 queue.push(child.name.expression);
\r
767 if (node_1.isMethodDeclaration(child)) {
\r
768 for (const p of child.parameters)
\r
769 if (p.decorators !== undefined)
\r
772 else if (node_1.isPropertyDeclaration(child) &&
\r
773 child.initializer !== undefined &&
\r
774 hasModifier(child.modifiers, ts.SyntaxKind.StaticKeyword)) {
\r
775 queue.push(child.initializer);
\r
779 const base = getBaseOfClassLikeExpression(node);
\r
780 if (base === undefined)
\r
782 node = base.expression;
\r
785 case ts.SyntaxKind.ArrayLiteralExpression:
\r
786 queue.push(...node.elements);
\r
788 case ts.SyntaxKind.ObjectLiteralExpression:
\r
789 for (const child of node.properties) {
\r
790 if (((_b = child.name) === null || _b === void 0 ? void 0 : _b.kind) === ts.SyntaxKind.ComputedPropertyName)
\r
791 queue.push(child.name.expression);
\r
792 switch (child.kind) {
\r
793 case ts.SyntaxKind.PropertyAssignment:
\r
794 queue.push(child.initializer);
\r
796 case ts.SyntaxKind.SpreadAssignment:
\r
797 queue.push(child.expression);
\r
801 case ts.SyntaxKind.JsxExpression:
\r
802 if (node.expression === undefined)
\r
804 node = node.expression;
\r
806 case ts.SyntaxKind.JsxElement:
\r
807 case ts.SyntaxKind.JsxFragment:
\r
808 for (const child of node.children)
\r
809 if (child.kind !== ts.SyntaxKind.JsxText)
\r
811 if (node.kind === ts.SyntaxKind.JsxFragment)
\r
813 node = node.openingElement;
\r
815 case ts.SyntaxKind.JsxSelfClosingElement:
\r
816 case ts.SyntaxKind.JsxOpeningElement:
\r
817 if (options & 4 /* JsxElement */)
\r
819 for (const child of node.attributes.properties) {
\r
820 if (child.kind === ts.SyntaxKind.JsxSpreadAttribute) {
\r
821 queue.push(child.expression);
\r
823 else if (child.initializer !== undefined) {
\r
824 queue.push(child.initializer);
\r
828 case ts.SyntaxKind.CommaListExpression:
\r
829 queue.push(...node.elements);
\r
831 if (queue.length === 0)
\r
833 node = queue.pop();
\r
836 exports.hasSideEffects = hasSideEffects;
\r
837 /** Returns the VariableDeclaration or ParameterDeclaration that contains the BindingElement */
\r
838 function getDeclarationOfBindingElement(node) {
\r
839 let parent = node.parent.parent;
\r
840 while (parent.kind === ts.SyntaxKind.BindingElement)
\r
841 parent = parent.parent.parent;
\r
844 exports.getDeclarationOfBindingElement = getDeclarationOfBindingElement;
\r
845 function isExpressionValueUsed(node) {
\r
847 const parent = node.parent;
\r
848 switch (parent.kind) {
\r
849 case ts.SyntaxKind.CallExpression:
\r
850 case ts.SyntaxKind.NewExpression:
\r
851 case ts.SyntaxKind.ElementAccessExpression:
\r
852 case ts.SyntaxKind.WhileStatement:
\r
853 case ts.SyntaxKind.DoStatement:
\r
854 case ts.SyntaxKind.WithStatement:
\r
855 case ts.SyntaxKind.ThrowStatement:
\r
856 case ts.SyntaxKind.ReturnStatement:
\r
857 case ts.SyntaxKind.JsxExpression:
\r
858 case ts.SyntaxKind.JsxSpreadAttribute:
\r
859 case ts.SyntaxKind.JsxElement:
\r
860 case ts.SyntaxKind.JsxFragment:
\r
861 case ts.SyntaxKind.JsxSelfClosingElement:
\r
862 case ts.SyntaxKind.ComputedPropertyName:
\r
863 case ts.SyntaxKind.ArrowFunction:
\r
864 case ts.SyntaxKind.ExportSpecifier:
\r
865 case ts.SyntaxKind.ExportAssignment:
\r
866 case ts.SyntaxKind.ImportDeclaration:
\r
867 case ts.SyntaxKind.ExternalModuleReference:
\r
868 case ts.SyntaxKind.Decorator:
\r
869 case ts.SyntaxKind.TaggedTemplateExpression:
\r
870 case ts.SyntaxKind.TemplateSpan:
\r
871 case ts.SyntaxKind.ExpressionWithTypeArguments:
\r
872 case ts.SyntaxKind.TypeOfExpression:
\r
873 case ts.SyntaxKind.AwaitExpression:
\r
874 case ts.SyntaxKind.YieldExpression:
\r
875 case ts.SyntaxKind.LiteralType:
\r
876 case ts.SyntaxKind.JsxAttributes:
\r
877 case ts.SyntaxKind.JsxOpeningElement:
\r
878 case ts.SyntaxKind.JsxClosingElement:
\r
879 case ts.SyntaxKind.IfStatement:
\r
880 case ts.SyntaxKind.CaseClause:
\r
881 case ts.SyntaxKind.SwitchStatement:
\r
883 case ts.SyntaxKind.PropertyAccessExpression:
\r
884 return parent.expression === node;
\r
885 case ts.SyntaxKind.QualifiedName:
\r
886 return parent.left === node;
\r
887 case ts.SyntaxKind.ShorthandPropertyAssignment:
\r
888 return parent.objectAssignmentInitializer === node ||
\r
889 !isInDestructuringAssignment(parent);
\r
890 case ts.SyntaxKind.PropertyAssignment:
\r
891 return parent.initializer === node && !isInDestructuringAssignment(parent);
\r
892 case ts.SyntaxKind.SpreadAssignment:
\r
893 case ts.SyntaxKind.SpreadElement:
\r
894 case ts.SyntaxKind.ArrayLiteralExpression:
\r
895 return !isInDestructuringAssignment(parent);
\r
896 case ts.SyntaxKind.ParenthesizedExpression:
\r
897 case ts.SyntaxKind.AsExpression:
\r
898 case ts.SyntaxKind.TypeAssertionExpression:
\r
899 case ts.SyntaxKind.PostfixUnaryExpression:
\r
900 case ts.SyntaxKind.PrefixUnaryExpression:
\r
901 case ts.SyntaxKind.NonNullExpression:
\r
904 case ts.SyntaxKind.ForStatement:
\r
905 return parent.condition === node;
\r
906 case ts.SyntaxKind.ForInStatement:
\r
907 case ts.SyntaxKind.ForOfStatement:
\r
908 return parent.expression === node;
\r
909 case ts.SyntaxKind.ConditionalExpression:
\r
910 if (parent.condition === node)
\r
914 case ts.SyntaxKind.PropertyDeclaration:
\r
915 case ts.SyntaxKind.BindingElement:
\r
916 case ts.SyntaxKind.VariableDeclaration:
\r
917 case ts.SyntaxKind.Parameter:
\r
918 case ts.SyntaxKind.EnumMember:
\r
919 return parent.initializer === node;
\r
920 case ts.SyntaxKind.ImportEqualsDeclaration:
\r
921 return parent.moduleReference === node;
\r
922 case ts.SyntaxKind.CommaListExpression:
\r
923 if (parent.elements[parent.elements.length - 1] !== node)
\r
927 case ts.SyntaxKind.BinaryExpression:
\r
928 if (parent.right === node) {
\r
929 if (parent.operatorToken.kind === ts.SyntaxKind.CommaToken) {
\r
935 switch (parent.operatorToken.kind) {
\r
936 case ts.SyntaxKind.CommaToken:
\r
937 case ts.SyntaxKind.EqualsToken:
\r
939 case ts.SyntaxKind.EqualsEqualsEqualsToken:
\r
940 case ts.SyntaxKind.EqualsEqualsToken:
\r
941 case ts.SyntaxKind.ExclamationEqualsEqualsToken:
\r
942 case ts.SyntaxKind.ExclamationEqualsToken:
\r
943 case ts.SyntaxKind.InstanceOfKeyword:
\r
944 case ts.SyntaxKind.PlusToken:
\r
945 case ts.SyntaxKind.MinusToken:
\r
946 case ts.SyntaxKind.AsteriskToken:
\r
947 case ts.SyntaxKind.SlashToken:
\r
948 case ts.SyntaxKind.PercentToken:
\r
949 case ts.SyntaxKind.AsteriskAsteriskToken:
\r
950 case ts.SyntaxKind.GreaterThanToken:
\r
951 case ts.SyntaxKind.GreaterThanGreaterThanToken:
\r
952 case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
\r
953 case ts.SyntaxKind.GreaterThanEqualsToken:
\r
954 case ts.SyntaxKind.LessThanToken:
\r
955 case ts.SyntaxKind.LessThanLessThanToken:
\r
956 case ts.SyntaxKind.LessThanEqualsToken:
\r
957 case ts.SyntaxKind.AmpersandToken:
\r
958 case ts.SyntaxKind.BarToken:
\r
959 case ts.SyntaxKind.CaretToken:
\r
960 case ts.SyntaxKind.BarBarToken:
\r
961 case ts.SyntaxKind.AmpersandAmpersandToken:
\r
962 case ts.SyntaxKind.QuestionQuestionToken:
\r
963 case ts.SyntaxKind.InKeyword:
\r
964 case ts.SyntaxKind.QuestionQuestionEqualsToken:
\r
965 case ts.SyntaxKind.AmpersandAmpersandEqualsToken:
\r
966 case ts.SyntaxKind.BarBarEqualsToken:
\r
977 exports.isExpressionValueUsed = isExpressionValueUsed;
\r
978 function isInDestructuringAssignment(node) {
\r
979 switch (node.kind) {
\r
980 case ts.SyntaxKind.ShorthandPropertyAssignment:
\r
981 if (node.objectAssignmentInitializer !== undefined)
\r
984 case ts.SyntaxKind.PropertyAssignment:
\r
985 case ts.SyntaxKind.SpreadAssignment:
\r
986 node = node.parent;
\r
988 case ts.SyntaxKind.SpreadElement:
\r
989 if (node.parent.kind !== ts.SyntaxKind.ArrayLiteralExpression)
\r
991 node = node.parent;
\r
994 switch (node.parent.kind) {
\r
995 case ts.SyntaxKind.BinaryExpression:
\r
996 return node.parent.left === node &&
\r
997 node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken;
\r
998 case ts.SyntaxKind.ForOfStatement:
\r
999 return node.parent.initializer === node;
\r
1000 case ts.SyntaxKind.ArrayLiteralExpression:
\r
1001 case ts.SyntaxKind.ObjectLiteralExpression:
\r
1002 node = node.parent;
\r
1004 case ts.SyntaxKind.SpreadAssignment:
\r
1005 case ts.SyntaxKind.PropertyAssignment:
\r
1006 node = node.parent.parent;
\r
1008 case ts.SyntaxKind.SpreadElement:
\r
1009 if (node.parent.parent.kind !== ts.SyntaxKind.ArrayLiteralExpression)
\r
1011 node = node.parent.parent;
\r
1019 (function (AccessKind) {
\r
1020 AccessKind[AccessKind["None"] = 0] = "None";
\r
1021 AccessKind[AccessKind["Read"] = 1] = "Read";
\r
1022 AccessKind[AccessKind["Write"] = 2] = "Write";
\r
1023 AccessKind[AccessKind["Delete"] = 4] = "Delete";
\r
1024 AccessKind[AccessKind["ReadWrite"] = 3] = "ReadWrite";
\r
1025 AccessKind[AccessKind["Modification"] = 6] = "Modification";
\r
1026 })(AccessKind = exports.AccessKind || (exports.AccessKind = {}));
\r
1027 function getAccessKind(node) {
\r
1028 const parent = node.parent;
\r
1029 switch (parent.kind) {
\r
1030 case ts.SyntaxKind.DeleteExpression:
\r
1031 return 4 /* Delete */;
\r
1032 case ts.SyntaxKind.PostfixUnaryExpression:
\r
1033 return 3 /* ReadWrite */;
\r
1034 case ts.SyntaxKind.PrefixUnaryExpression:
\r
1035 return parent.operator === ts.SyntaxKind.PlusPlusToken ||
\r
1036 parent.operator === ts.SyntaxKind.MinusMinusToken
\r
1037 ? 3 /* ReadWrite */
\r
1039 case ts.SyntaxKind.BinaryExpression:
\r
1040 return parent.right === node
\r
1042 : !isAssignmentKind(parent.operatorToken.kind)
\r
1044 : parent.operatorToken.kind === ts.SyntaxKind.EqualsToken
\r
1046 : 3 /* ReadWrite */;
\r
1047 case ts.SyntaxKind.ShorthandPropertyAssignment:
\r
1048 return parent.objectAssignmentInitializer === node
\r
1050 : isInDestructuringAssignment(parent)
\r
1053 case ts.SyntaxKind.PropertyAssignment:
\r
1054 return parent.name === node
\r
1056 : isInDestructuringAssignment(parent)
\r
1059 case ts.SyntaxKind.ArrayLiteralExpression:
\r
1060 case ts.SyntaxKind.SpreadElement:
\r
1061 case ts.SyntaxKind.SpreadAssignment:
\r
1062 return isInDestructuringAssignment(parent)
\r
1065 case ts.SyntaxKind.ParenthesizedExpression:
\r
1066 case ts.SyntaxKind.NonNullExpression:
\r
1067 case ts.SyntaxKind.TypeAssertionExpression:
\r
1068 case ts.SyntaxKind.AsExpression:
\r
1069 // (<number>foo! as {})++
\r
1070 return getAccessKind(parent);
\r
1071 case ts.SyntaxKind.ForOfStatement:
\r
1072 case ts.SyntaxKind.ForInStatement:
\r
1073 return parent.initializer === node
\r
1076 case ts.SyntaxKind.ExpressionWithTypeArguments:
\r
1077 return parent.parent.token === ts.SyntaxKind.ExtendsKeyword &&
\r
1078 parent.parent.parent.kind !== ts.SyntaxKind.InterfaceDeclaration
\r
1081 case ts.SyntaxKind.ComputedPropertyName:
\r
1082 case ts.SyntaxKind.ExpressionStatement:
\r
1083 case ts.SyntaxKind.TypeOfExpression:
\r
1084 case ts.SyntaxKind.ElementAccessExpression:
\r
1085 case ts.SyntaxKind.ForStatement:
\r
1086 case ts.SyntaxKind.IfStatement:
\r
1087 case ts.SyntaxKind.DoStatement:
\r
1088 case ts.SyntaxKind.WhileStatement:
\r
1089 case ts.SyntaxKind.SwitchStatement:
\r
1090 case ts.SyntaxKind.WithStatement:
\r
1091 case ts.SyntaxKind.ThrowStatement:
\r
1092 case ts.SyntaxKind.CallExpression:
\r
1093 case ts.SyntaxKind.NewExpression:
\r
1094 case ts.SyntaxKind.TaggedTemplateExpression:
\r
1095 case ts.SyntaxKind.JsxExpression:
\r
1096 case ts.SyntaxKind.Decorator:
\r
1097 case ts.SyntaxKind.TemplateSpan:
\r
1098 case ts.SyntaxKind.JsxOpeningElement:
\r
1099 case ts.SyntaxKind.JsxSelfClosingElement:
\r
1100 case ts.SyntaxKind.JsxSpreadAttribute:
\r
1101 case ts.SyntaxKind.VoidExpression:
\r
1102 case ts.SyntaxKind.ReturnStatement:
\r
1103 case ts.SyntaxKind.AwaitExpression:
\r
1104 case ts.SyntaxKind.YieldExpression:
\r
1105 case ts.SyntaxKind.ConditionalExpression:
\r
1106 case ts.SyntaxKind.CaseClause:
\r
1107 case ts.SyntaxKind.JsxElement:
\r
1108 return 1 /* Read */;
\r
1109 case ts.SyntaxKind.ArrowFunction:
\r
1110 return parent.body === node
\r
1113 case ts.SyntaxKind.PropertyDeclaration:
\r
1114 case ts.SyntaxKind.VariableDeclaration:
\r
1115 case ts.SyntaxKind.Parameter:
\r
1116 case ts.SyntaxKind.EnumMember:
\r
1117 case ts.SyntaxKind.BindingElement:
\r
1118 case ts.SyntaxKind.JsxAttribute:
\r
1119 return parent.initializer === node
\r
1122 case ts.SyntaxKind.PropertyAccessExpression:
\r
1123 return parent.expression === node
\r
1126 case ts.SyntaxKind.ExportAssignment:
\r
1127 return parent.isExportEquals
\r
1131 return 0 /* None */;
\r
1133 exports.getAccessKind = getAccessKind;
\r
1134 function isReassignmentTarget(node) {
\r
1135 return (getAccessKind(node) & 2 /* Write */) !== 0;
\r
1137 exports.isReassignmentTarget = isReassignmentTarget;
\r
1138 function canHaveJsDoc(node) {
\r
1139 const kind = node.kind;
\r
1141 case ts.SyntaxKind.Parameter:
\r
1142 case ts.SyntaxKind.CallSignature:
\r
1143 case ts.SyntaxKind.ConstructSignature:
\r
1144 case ts.SyntaxKind.MethodSignature:
\r
1145 case ts.SyntaxKind.PropertySignature:
\r
1146 case ts.SyntaxKind.ArrowFunction:
\r
1147 case ts.SyntaxKind.ParenthesizedExpression:
\r
1148 case ts.SyntaxKind.SpreadAssignment:
\r
1149 case ts.SyntaxKind.ShorthandPropertyAssignment:
\r
1150 case ts.SyntaxKind.PropertyAssignment:
\r
1151 case ts.SyntaxKind.FunctionExpression:
\r
1152 case ts.SyntaxKind.LabeledStatement:
\r
1153 case ts.SyntaxKind.ExpressionStatement:
\r
1154 case ts.SyntaxKind.VariableStatement:
\r
1155 case ts.SyntaxKind.FunctionDeclaration:
\r
1156 case ts.SyntaxKind.Constructor:
\r
1157 case ts.SyntaxKind.MethodDeclaration:
\r
1158 case ts.SyntaxKind.PropertyDeclaration:
\r
1159 case ts.SyntaxKind.GetAccessor:
\r
1160 case ts.SyntaxKind.SetAccessor:
\r
1161 case ts.SyntaxKind.ClassDeclaration:
\r
1162 case ts.SyntaxKind.ClassExpression:
\r
1163 case ts.SyntaxKind.InterfaceDeclaration:
\r
1164 case ts.SyntaxKind.TypeAliasDeclaration:
\r
1165 case ts.SyntaxKind.EnumMember:
\r
1166 case ts.SyntaxKind.EnumDeclaration:
\r
1167 case ts.SyntaxKind.ModuleDeclaration:
\r
1168 case ts.SyntaxKind.ImportEqualsDeclaration:
\r
1169 case ts.SyntaxKind.ImportDeclaration:
\r
1170 case ts.SyntaxKind.NamespaceExportDeclaration:
\r
1171 case ts.SyntaxKind.ExportAssignment:
\r
1172 case ts.SyntaxKind.IndexSignature:
\r
1173 case ts.SyntaxKind.FunctionType:
\r
1174 case ts.SyntaxKind.ConstructorType:
\r
1175 case ts.SyntaxKind.JSDocFunctionType:
\r
1176 case ts.SyntaxKind.ExportDeclaration:
\r
1177 case ts.SyntaxKind.NamedTupleMember:
\r
1178 case ts.SyntaxKind.EndOfFileToken:
\r
1184 exports.canHaveJsDoc = canHaveJsDoc;
\r
1185 /** Gets the JSDoc of a node. For performance reasons this function should only be called when `canHaveJsDoc` returns true. */
\r
1186 function getJsDoc(node, sourceFile) {
\r
1187 const result = [];
\r
1188 for (const child of node.getChildren(sourceFile)) {
\r
1189 if (!node_1.isJsDoc(child))
\r
1191 result.push(child);
\r
1195 exports.getJsDoc = getJsDoc;
\r
1197 * Parses the JsDoc of any node. This function is made for nodes that don't get their JsDoc parsed by the TypeScript parser.
\r
1199 * @param considerTrailingComments When set to `true` this function uses the trailing comments if the node starts on the same line
\r
1200 * as the previous node ends.
\r
1202 function parseJsDocOfNode(node, considerTrailingComments, sourceFile = node.getSourceFile()) {
\r
1203 if (canHaveJsDoc(node) && node.kind !== ts.SyntaxKind.EndOfFileToken) {
\r
1204 const result = getJsDoc(node, sourceFile);
\r
1205 if (result.length !== 0 || !considerTrailingComments)
\r
1208 return parseJsDocWorker(node, node.getStart(sourceFile), sourceFile, considerTrailingComments);
\r
1210 exports.parseJsDocOfNode = parseJsDocOfNode;
\r
1211 function parseJsDocWorker(node, nodeStart, sourceFile, considerTrailingComments) {
\r
1212 const start = ts[considerTrailingComments && isSameLine(sourceFile, node.pos, nodeStart)
\r
1213 ? 'forEachTrailingCommentRange'
\r
1214 : 'forEachLeadingCommentRange'](sourceFile.text, node.pos,
\r
1215 // return object to make `0` a truthy value
\r
1216 (pos, _end, kind) => kind === ts.SyntaxKind.MultiLineCommentTrivia && sourceFile.text[pos + 2] === '*' ? { pos } : undefined);
\r
1217 if (start === undefined)
\r
1219 const startPos = start.pos;
\r
1220 const text = sourceFile.text.slice(startPos, nodeStart);
\r
1221 const newSourceFile = ts.createSourceFile('jsdoc.ts', `${text}var a;`, sourceFile.languageVersion);
\r
1222 const result = getJsDoc(newSourceFile.statements[0], newSourceFile);
\r
1223 for (const doc of result)
\r
1224 updateNode(doc, node);
\r
1226 function updateNode(n, parent) {
\r
1227 n.pos += startPos;
\r
1228 n.end += startPos;
\r
1229 n.parent = parent;
\r
1230 return ts.forEachChild(n, (child) => updateNode(child, n), (children) => {
\r
1231 children.pos += startPos;
\r
1232 children.end += startPos;
\r
1233 for (const child of children)
\r
1234 updateNode(child, n);
\r
1239 (function (ImportKind) {
\r
1240 ImportKind[ImportKind["ImportDeclaration"] = 1] = "ImportDeclaration";
\r
1241 ImportKind[ImportKind["ImportEquals"] = 2] = "ImportEquals";
\r
1242 ImportKind[ImportKind["ExportFrom"] = 4] = "ExportFrom";
\r
1243 ImportKind[ImportKind["DynamicImport"] = 8] = "DynamicImport";
\r
1244 ImportKind[ImportKind["Require"] = 16] = "Require";
\r
1245 ImportKind[ImportKind["ImportType"] = 32] = "ImportType";
\r
1246 ImportKind[ImportKind["All"] = 63] = "All";
\r
1247 ImportKind[ImportKind["AllImports"] = 59] = "AllImports";
\r
1248 ImportKind[ImportKind["AllStaticImports"] = 3] = "AllStaticImports";
\r
1249 ImportKind[ImportKind["AllImportExpressions"] = 24] = "AllImportExpressions";
\r
1250 ImportKind[ImportKind["AllRequireLike"] = 18] = "AllRequireLike";
\r
1252 ImportKind[ImportKind["AllNestedImports"] = 56] = "AllNestedImports";
\r
1254 ImportKind[ImportKind["AllTopLevelImports"] = 7] = "AllTopLevelImports";
\r
1255 })(ImportKind = exports.ImportKind || (exports.ImportKind = {}));
\r
1256 function findImports(sourceFile, kinds, ignoreFileName = true) {
\r
1257 const result = [];
\r
1258 for (const node of findImportLikeNodes(sourceFile, kinds, ignoreFileName)) {
\r
1259 switch (node.kind) {
\r
1260 case ts.SyntaxKind.ImportDeclaration:
\r
1261 addIfTextualLiteral(node.moduleSpecifier);
\r
1263 case ts.SyntaxKind.ImportEqualsDeclaration:
\r
1264 addIfTextualLiteral(node.moduleReference.expression);
\r
1266 case ts.SyntaxKind.ExportDeclaration:
\r
1267 addIfTextualLiteral(node.moduleSpecifier);
\r
1269 case ts.SyntaxKind.CallExpression:
\r
1270 addIfTextualLiteral(node.arguments[0]);
\r
1272 case ts.SyntaxKind.ImportType:
\r
1273 if (node_1.isLiteralTypeNode(node.argument))
\r
1274 addIfTextualLiteral(node.argument.literal);
\r
1277 throw new Error('unexpected node');
\r
1281 function addIfTextualLiteral(node) {
\r
1282 if (node_1.isTextualLiteral(node))
\r
1283 result.push(node);
\r
1286 exports.findImports = findImports;
\r
1287 function findImportLikeNodes(sourceFile, kinds, ignoreFileName = true) {
\r
1288 return new ImportFinder(sourceFile, kinds, ignoreFileName).find();
\r
1290 exports.findImportLikeNodes = findImportLikeNodes;
\r
1291 class ImportFinder {
\r
1292 constructor(_sourceFile, _options, _ignoreFileName) {
\r
1293 this._sourceFile = _sourceFile;
\r
1294 this._options = _options;
\r
1295 this._ignoreFileName = _ignoreFileName;
\r
1296 this._result = [];
\r
1299 if (this._sourceFile.isDeclarationFile)
\r
1300 this._options &= ~24 /* AllImportExpressions */;
\r
1301 if (this._options & 7 /* AllTopLevelImports */)
\r
1302 this._findImports(this._sourceFile.statements);
\r
1303 if (this._options & 56 /* AllNestedImports */)
\r
1304 this._findNestedImports();
\r
1305 return this._result;
\r
1307 _findImports(statements) {
\r
1308 for (const statement of statements) {
\r
1309 if (node_1.isImportDeclaration(statement)) {
\r
1310 if (this._options & 1 /* ImportDeclaration */)
\r
1311 this._result.push(statement);
\r
1313 else if (node_1.isImportEqualsDeclaration(statement)) {
\r
1314 if (this._options & 2 /* ImportEquals */ &&
\r
1315 statement.moduleReference.kind === ts.SyntaxKind.ExternalModuleReference)
\r
1316 this._result.push(statement);
\r
1318 else if (node_1.isExportDeclaration(statement)) {
\r
1319 if (statement.moduleSpecifier !== undefined && this._options & 4 /* ExportFrom */)
\r
1320 this._result.push(statement);
\r
1322 else if (node_1.isModuleDeclaration(statement)) {
\r
1323 this._findImportsInModule(statement);
\r
1327 _findImportsInModule(declaration) {
\r
1328 if (declaration.body === undefined)
\r
1330 if (declaration.body.kind === ts.SyntaxKind.ModuleDeclaration)
\r
1331 return this._findImportsInModule(declaration.body);
\r
1332 this._findImports(declaration.body.statements);
\r
1334 _findNestedImports() {
\r
1335 const isJavaScriptFile = this._ignoreFileName || (this._sourceFile.flags & ts.NodeFlags.JavaScriptFile) !== 0;
\r
1338 if ((this._options & 56 /* AllNestedImports */) === 16 /* Require */) {
\r
1339 if (!isJavaScriptFile)
\r
1340 return; // don't look for 'require' in TS files
\r
1341 re = /\brequire\s*[</(]/g;
\r
1342 includeJsDoc = false;
\r
1344 else if (this._options & 16 /* Require */ && isJavaScriptFile) {
\r
1345 re = /\b(?:import|require)\s*[</(]/g;
\r
1346 includeJsDoc = (this._options & 32 /* ImportType */) !== 0;
\r
1349 re = /\bimport\s*[</(]/g;
\r
1350 includeJsDoc = isJavaScriptFile && (this._options & 32 /* ImportType */) !== 0;
\r
1352 for (let match = re.exec(this._sourceFile.text); match !== null; match = re.exec(this._sourceFile.text)) {
\r
1353 const token = getTokenAtPositionWorker(this._sourceFile, match.index, this._sourceFile,
\r
1354 // only look for ImportTypeNode within JSDoc in JS files
\r
1355 match[0][0] === 'i' && includeJsDoc);
\r
1356 if (token.kind === ts.SyntaxKind.ImportKeyword) {
\r
1357 if (token.end - 'import'.length !== match.index)
\r
1359 switch (token.parent.kind) {
\r
1360 case ts.SyntaxKind.ImportType:
\r
1361 this._result.push(token.parent);
\r
1363 case ts.SyntaxKind.CallExpression:
\r
1364 if (token.parent.arguments.length > 1)
\r
1365 this._result.push(token.parent);
\r
1368 else if (token.kind === ts.SyntaxKind.Identifier &&
\r
1369 token.end - 'require'.length === match.index &&
\r
1370 token.parent.kind === ts.SyntaxKind.CallExpression &&
\r
1371 token.parent.expression === token &&
\r
1372 token.parent.arguments.length === 1) {
\r
1373 this._result.push(token.parent);
\r
1379 * Ambient context means the statement itself has the `declare` keyword
\r
1380 * or is inside a `declare namespace`, `delcare module` or `declare global`.
\r
1382 function isStatementInAmbientContext(node) {
\r
1383 while (node.flags & ts.NodeFlags.NestedNamespace)
\r
1384 node = node.parent;
\r
1385 return hasModifier(node.modifiers, ts.SyntaxKind.DeclareKeyword) || isAmbientModuleBlock(node.parent);
\r
1387 exports.isStatementInAmbientContext = isStatementInAmbientContext;
\r
1388 /** Includes `declare namespace`, `declare module` and `declare global` and namespace nested in one of the aforementioned. */
\r
1389 function isAmbientModuleBlock(node) {
\r
1390 while (node.kind === ts.SyntaxKind.ModuleBlock) {
\r
1392 node = node.parent;
\r
1393 while (node.flags & ts.NodeFlags.NestedNamespace);
\r
1394 if (hasModifier(node.modifiers, ts.SyntaxKind.DeclareKeyword))
\r
1396 node = node.parent;
\r
1400 exports.isAmbientModuleBlock = isAmbientModuleBlock;
\r
1401 function getIIFE(func) {
\r
1402 let node = func.parent;
\r
1403 while (node.kind === ts.SyntaxKind.ParenthesizedExpression)
\r
1404 node = node.parent;
\r
1405 return node_1.isCallExpression(node) && func.end <= node.expression.end ? node : undefined;
\r
1407 exports.getIIFE = getIIFE;
\r
1408 function isStrictCompilerOptionEnabled(options, option) {
\r
1409 return (options.strict ? options[option] !== false : options[option] === true) &&
\r
1410 (option !== 'strictPropertyInitialization' || isStrictCompilerOptionEnabled(options, 'strictNullChecks'));
\r
1412 exports.isStrictCompilerOptionEnabled = isStrictCompilerOptionEnabled;
\r
1413 // https://github.com/ajafff/tslint-consistent-codestyle/issues/85
\r
1415 * Checks if a given compiler option is enabled.
\r
1416 * It handles dependencies of options, e.g. `declaration` is implicitly enabled by `composite` or `strictNullChecks` is enabled by `strict`.
\r
1417 * However, it does not check dependencies that are already checked and reported as errors, e.g. `checkJs` without `allowJs`.
\r
1418 * This function only handles boolean flags.
\r
1420 function isCompilerOptionEnabled(options, option) {
\r
1422 case 'stripInternal':
\r
1423 case 'declarationMap':
\r
1424 case 'emitDeclarationOnly':
\r
1425 return options[option] === true && isCompilerOptionEnabled(options, 'declaration');
\r
1426 case 'declaration':
\r
1427 return options.declaration || isCompilerOptionEnabled(options, 'composite');
\r
1428 case 'incremental':
\r
1429 return options.incremental === undefined ? isCompilerOptionEnabled(options, 'composite') : options.incremental;
\r
1430 case 'skipDefaultLibCheck':
\r
1431 return options.skipDefaultLibCheck || isCompilerOptionEnabled(options, 'skipLibCheck');
\r
1432 case 'suppressImplicitAnyIndexErrors':
\r
1433 return options.suppressImplicitAnyIndexErrors === true && isCompilerOptionEnabled(options, 'noImplicitAny');
\r
1434 case 'allowSyntheticDefaultImports':
\r
1435 return options.allowSyntheticDefaultImports !== undefined
\r
1436 ? options.allowSyntheticDefaultImports
\r
1437 : isCompilerOptionEnabled(options, 'esModuleInterop') || options.module === ts.ModuleKind.System;
\r
1438 case 'noUncheckedIndexedAccess':
\r
1439 return options.noUncheckedIndexedAccess === true && isCompilerOptionEnabled(options, 'strictNullChecks');
\r
1441 return options.allowJs === undefined ? isCompilerOptionEnabled(options, 'checkJs') : options.allowJs;
\r
1442 case 'noImplicitAny':
\r
1443 case 'noImplicitThis':
\r
1444 case 'strictNullChecks':
\r
1445 case 'strictFunctionTypes':
\r
1446 case 'strictPropertyInitialization':
\r
1447 case 'alwaysStrict':
\r
1448 case 'strictBindCallApply':
\r
1449 return isStrictCompilerOptionEnabled(options, option);
\r
1451 return options[option] === true;
\r
1453 exports.isCompilerOptionEnabled = isCompilerOptionEnabled;
\r
1455 * Has nothing to do with `isAmbientModuleBlock`.
\r
1457 * @returns `true` if it's a global augmentation or has a string name.
\r
1459 function isAmbientModule(node) {
\r
1460 return node.name.kind === ts.SyntaxKind.StringLiteral || (node.flags & ts.NodeFlags.GlobalAugmentation) !== 0;
\r
1462 exports.isAmbientModule = isAmbientModule;
\r
1464 * @deprecated use `getTsCheckDirective` instead since `// @ts-nocheck` is no longer restricted to JS files.
\r
1465 * @returns the last `// @ts-check` or `// @ts-nocheck` directive in the given file.
\r
1467 function getCheckJsDirective(source) {
\r
1468 return getTsCheckDirective(source);
\r
1470 exports.getCheckJsDirective = getCheckJsDirective;
\r
1471 /** @returns the last `// @ts-check` or `// @ts-nocheck` directive in the given file. */
\r
1472 function getTsCheckDirective(source) {
\r
1474 // needs to work around a shebang issue until https://github.com/Microsoft/TypeScript/issues/28477 is resolved
\r
1475 ts.forEachLeadingCommentRange(source, (ts.getShebang(source) || '').length, (pos, end, kind) => {
\r
1476 if (kind === ts.SyntaxKind.SingleLineCommentTrivia) {
\r
1477 const text = source.slice(pos, end);
\r
1478 const match = /^\/{2,3}\s*@ts-(no)?check(?:\s|$)/i.exec(text);
\r
1479 if (match !== null)
\r
1480 directive = { pos, end, enabled: match[1] === undefined };
\r
1485 exports.getTsCheckDirective = getTsCheckDirective;
\r
1486 function isConstAssertion(node) {
\r
1487 return node_1.isTypeReferenceNode(node.type) &&
\r
1488 node.type.typeName.kind === ts.SyntaxKind.Identifier &&
\r
1489 node.type.typeName.escapedText === 'const';
\r
1491 exports.isConstAssertion = isConstAssertion;
\r
1492 /** Detects whether an expression is affected by an enclosing 'as const' assertion and therefore treated literally. */
\r
1493 function isInConstContext(node) {
\r
1494 let current = node;
\r
1496 const parent = current.parent;
\r
1497 outer: switch (parent.kind) {
\r
1498 case ts.SyntaxKind.TypeAssertionExpression:
\r
1499 case ts.SyntaxKind.AsExpression:
\r
1500 return isConstAssertion(parent);
\r
1501 case ts.SyntaxKind.PrefixUnaryExpression:
\r
1502 if (current.kind !== ts.SyntaxKind.NumericLiteral)
\r
1504 switch (parent.operator) {
\r
1505 case ts.SyntaxKind.PlusToken:
\r
1506 case ts.SyntaxKind.MinusToken:
\r
1512 case ts.SyntaxKind.PropertyAssignment:
\r
1513 if (parent.initializer !== current)
\r
1515 current = parent.parent;
\r
1517 case ts.SyntaxKind.ShorthandPropertyAssignment:
\r
1518 current = parent.parent;
\r
1520 case ts.SyntaxKind.ParenthesizedExpression:
\r
1521 case ts.SyntaxKind.ArrayLiteralExpression:
\r
1522 case ts.SyntaxKind.ObjectLiteralExpression:
\r
1523 case ts.SyntaxKind.TemplateExpression:
\r
1531 exports.isInConstContext = isInConstContext;
\r
1532 /** Returns true for `Object.defineProperty(o, 'prop', {value, writable: false})` and `Object.defineProperty(o, 'prop', {get: () => 1})`*/
\r
1533 function isReadonlyAssignmentDeclaration(node, checker) {
\r
1534 if (!isBindableObjectDefinePropertyCall(node))
\r
1536 const descriptorType = checker.getTypeAtLocation(node.arguments[2]);
\r
1537 if (descriptorType.getProperty('value') === undefined)
\r
1538 return descriptorType.getProperty('set') === undefined;
\r
1539 const writableProp = descriptorType.getProperty('writable');
\r
1540 if (writableProp === undefined)
\r
1542 const writableType = writableProp.valueDeclaration !== undefined && node_1.isPropertyAssignment(writableProp.valueDeclaration)
\r
1543 ? checker.getTypeAtLocation(writableProp.valueDeclaration.initializer)
\r
1544 : checker.getTypeOfSymbolAtLocation(writableProp, node.arguments[2]);
\r
1545 return type_1.isBooleanLiteralType(writableType, false);
\r
1547 exports.isReadonlyAssignmentDeclaration = isReadonlyAssignmentDeclaration;
\r
1548 /** Determines whether a call to `Object.defineProperty` is statically analyzable. */
\r
1549 function isBindableObjectDefinePropertyCall(node) {
\r
1550 return node.arguments.length === 3 &&
\r
1551 node_1.isEntityNameExpression(node.arguments[0]) &&
\r
1552 node_1.isNumericOrStringLikeLiteral(node.arguments[1]) &&
\r
1553 node_1.isPropertyAccessExpression(node.expression) &&
\r
1554 node.expression.name.escapedText === 'defineProperty' &&
\r
1555 node_1.isIdentifier(node.expression.expression) &&
\r
1556 node.expression.expression.escapedText === 'Object';
\r
1558 exports.isBindableObjectDefinePropertyCall = isBindableObjectDefinePropertyCall;
\r
1559 function isWellKnownSymbolLiterally(node) {
\r
1560 return ts.isPropertyAccessExpression(node) &&
\r
1561 ts.isIdentifier(node.expression) &&
\r
1562 node.expression.escapedText === 'Symbol';
\r
1564 exports.isWellKnownSymbolLiterally = isWellKnownSymbolLiterally;
\r
1565 /** @deprecated typescript 4.3 removed the concept of literal well known symbols. Use `getPropertyNameFromType` instead. */
\r
1566 function getPropertyNameOfWellKnownSymbol(node) {
\r
1568 displayName: `[Symbol.${node.name.text}]`,
\r
1569 symbolName: ('__@' + node.name.text),
\r
1572 exports.getPropertyNameOfWellKnownSymbol = getPropertyNameOfWellKnownSymbol;
\r
1573 const isTsBefore43 = (([major, minor]) => major < '4' || major === '4' && minor < '3')(ts.versionMajorMinor.split('.'));
\r
1574 function getLateBoundPropertyNames(node, checker) {
\r
1579 node = unwrapParentheses(node);
\r
1580 if (isTsBefore43 && isWellKnownSymbolLiterally(node)) {
\r
1581 result.names.push(getPropertyNameOfWellKnownSymbol(node)); // wotan-disable-line no-unstable-api-use
\r
1584 const type = checker.getTypeAtLocation(node);
\r
1585 for (const key of type_1.unionTypeParts(checker.getBaseConstraintOfType(type) || type)) {
\r
1586 const propertyName = type_1.getPropertyNameFromType(key);
\r
1587 if (propertyName) {
\r
1588 result.names.push(propertyName);
\r
1591 result.known = false;
\r
1597 exports.getLateBoundPropertyNames = getLateBoundPropertyNames;
\r
1598 function getLateBoundPropertyNamesOfPropertyName(node, checker) {
\r
1599 const staticName = getPropertyName(node);
\r
1600 return staticName !== undefined
\r
1601 ? { known: true, names: [{ displayName: staticName, symbolName: ts.escapeLeadingUnderscores(staticName) }] }
\r
1602 : node.kind === ts.SyntaxKind.PrivateIdentifier
\r
1603 ? { known: true, names: [{ displayName: node.text, symbolName: checker.getSymbolAtLocation(node).escapedName }] }
\r
1604 : getLateBoundPropertyNames(node.expression, checker);
\r
1606 exports.getLateBoundPropertyNamesOfPropertyName = getLateBoundPropertyNamesOfPropertyName;
\r
1607 /** Most declarations demand there to be only one statically known name, e.g. class members with computed name. */
\r
1608 function getSingleLateBoundPropertyNameOfPropertyName(node, checker) {
\r
1609 const staticName = getPropertyName(node);
\r
1610 if (staticName !== undefined)
\r
1611 return { displayName: staticName, symbolName: ts.escapeLeadingUnderscores(staticName) };
\r
1612 if (node.kind === ts.SyntaxKind.PrivateIdentifier)
\r
1613 return { displayName: node.text, symbolName: checker.getSymbolAtLocation(node).escapedName };
\r
1614 const { expression } = node;
\r
1615 return isTsBefore43 && isWellKnownSymbolLiterally(expression)
\r
1616 ? getPropertyNameOfWellKnownSymbol(expression) // wotan-disable-line no-unstable-api-use
\r
1617 : type_1.getPropertyNameFromType(checker.getTypeAtLocation(expression));
\r
1619 exports.getSingleLateBoundPropertyNameOfPropertyName = getSingleLateBoundPropertyNameOfPropertyName;
\r
1620 function unwrapParentheses(node) {
\r
1621 while (node.kind === ts.SyntaxKind.ParenthesizedExpression)
\r
1622 node = node.expression;
\r
1625 exports.unwrapParentheses = unwrapParentheses;
\r
1626 function formatPseudoBigInt(v) {
\r
1627 return `${v.negative ? '-' : ''}${v.base10Value}n`;
\r
1629 exports.formatPseudoBigInt = formatPseudoBigInt;
\r
1631 * Determines whether the given `SwitchStatement`'s `case` clauses cover every possible value of the switched expression.
\r
1632 * The logic is the same as TypeScript's control flow analysis.
\r
1633 * This does **not** check whether all `case` clauses do a certain action like assign a variable or return a value.
\r
1634 * This function ignores the `default` clause if present.
\r
1636 function hasExhaustiveCaseClauses(node, checker) {
\r
1637 const caseClauses = node.caseBlock.clauses.filter(node_1.isCaseClause);
\r
1638 if (caseClauses.length === 0)
\r
1640 const typeParts = type_1.unionTypeParts(checker.getTypeAtLocation(node.expression));
\r
1641 if (typeParts.length > caseClauses.length)
\r
1643 const types = new Set(typeParts.map(getPrimitiveLiteralFromType));
\r
1644 if (types.has(undefined))
\r
1646 const seen = new Set();
\r
1647 for (const clause of caseClauses) {
\r
1648 const expressionType = checker.getTypeAtLocation(clause.expression);
\r
1649 if (exports.isTypeFlagSet(expressionType, ts.TypeFlags.Never))
\r
1650 continue; // additional case clause with 'never' is always allowed
\r
1651 const type = getPrimitiveLiteralFromType(expressionType);
\r
1652 if (types.has(type)) {
\r
1655 else if (type !== 'null' && type !== 'undefined') { // additional case clauses with 'null' and 'undefined' are always allowed
\r
1659 return types.size === seen.size;
\r
1661 exports.hasExhaustiveCaseClauses = hasExhaustiveCaseClauses;
\r
1662 function getPrimitiveLiteralFromType(t) {
\r
1663 if (exports.isTypeFlagSet(t, ts.TypeFlags.Null))
\r
1665 if (exports.isTypeFlagSet(t, ts.TypeFlags.Undefined))
\r
1666 return 'undefined';
\r
1667 if (exports.isTypeFlagSet(t, ts.TypeFlags.NumberLiteral))
\r
1668 return `${exports.isTypeFlagSet(t, ts.TypeFlags.EnumLiteral) ? 'enum:' : ''}${t.value}`;
\r
1669 if (exports.isTypeFlagSet(t, ts.TypeFlags.StringLiteral))
\r
1670 return `${exports.isTypeFlagSet(t, ts.TypeFlags.EnumLiteral) ? 'enum:' : ''}string:${t.value}`;
\r
1671 if (exports.isTypeFlagSet(t, ts.TypeFlags.BigIntLiteral))
\r
1672 return formatPseudoBigInt(t.value);
\r
1673 if (_3_2_1.isUniqueESSymbolType(t))
\r
1674 return t.escapedName;
\r
1675 if (type_1.isBooleanLiteralType(t, true))
\r
1677 if (type_1.isBooleanLiteralType(t, false))
\r
1680 function getBaseOfClassLikeExpression(node) {
\r
1682 if (((_a = node.heritageClauses) === null || _a === void 0 ? void 0 : _a[0].token) === ts.SyntaxKind.ExtendsKeyword)
\r
1683 return node.heritageClauses[0].types[0];
\r
1685 exports.getBaseOfClassLikeExpression = getBaseOfClassLikeExpression;
\r
1686 //# sourceMappingURL=util.js.map