This commit is contained in:
2026-03-04 11:30:40 +08:00
parent 9ff5e028b0
commit 189dad2809
3767 changed files with 1056662 additions and 0 deletions

24
node_modules/tsutils/util/control-flow.d.ts generated vendored Normal file
View File

@@ -0,0 +1,24 @@
import * as ts from 'typescript';
export declare function endsControlFlow(statement: ts.Statement | ts.BlockLike, checker?: ts.TypeChecker): boolean;
export declare type ControlFlowStatement = ts.BreakStatement | ts.ContinueStatement | ts.ReturnStatement | ts.ThrowStatement | ts.ExpressionStatement & {
expression: ts.CallExpression;
};
export interface ControlFlowEnd {
/**
* Statements that may end control flow at this statement.
* Does not contain control flow statements that jump only inside the statement, for example a `continue` inside a nested for loop.
*/
readonly statements: ReadonlyArray<ControlFlowStatement>;
/** `true` if control flow definitely ends. */
readonly end: boolean;
}
export declare function getControlFlowEnd(statement: ts.Statement | ts.BlockLike, checker?: ts.TypeChecker): ControlFlowEnd;
export declare enum SignatureEffect {
Never = 1,
Asserts = 2
}
/**
* Dermines whether a top level CallExpression has a control flow effect according to TypeScript's rules.
* This handles functions returning `never` and `asserts`.
*/
export declare function callExpressionAffectsControlFlow(node: ts.CallExpression, checker: ts.TypeChecker): SignatureEffect | undefined;

296
node_modules/tsutils/util/control-flow.js generated vendored Normal file
View File

@@ -0,0 +1,296 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.callExpressionAffectsControlFlow = exports.SignatureEffect = exports.getControlFlowEnd = exports.endsControlFlow = void 0;
const ts = require("typescript");
const node_1 = require("../typeguard/node");
const util_1 = require("./util");
function endsControlFlow(statement, checker) {
return getControlFlowEnd(statement, checker).end;
}
exports.endsControlFlow = endsControlFlow;
const defaultControlFlowEnd = { statements: [], end: false };
function getControlFlowEnd(statement, checker) {
return node_1.isBlockLike(statement) ? handleBlock(statement, checker) : getControlFlowEndWorker(statement, checker);
}
exports.getControlFlowEnd = getControlFlowEnd;
function getControlFlowEndWorker(statement, checker) {
switch (statement.kind) {
case ts.SyntaxKind.ReturnStatement:
case ts.SyntaxKind.ThrowStatement:
case ts.SyntaxKind.ContinueStatement:
case ts.SyntaxKind.BreakStatement:
return { statements: [statement], end: true };
case ts.SyntaxKind.Block:
return handleBlock(statement, checker);
case ts.SyntaxKind.ForStatement:
case ts.SyntaxKind.WhileStatement:
return handleForAndWhileStatement(statement, checker);
case ts.SyntaxKind.ForOfStatement:
case ts.SyntaxKind.ForInStatement:
return handleForInOrOfStatement(statement, checker);
case ts.SyntaxKind.DoStatement:
return matchBreakOrContinue(getControlFlowEndWorker(statement.statement, checker), node_1.isBreakOrContinueStatement);
case ts.SyntaxKind.IfStatement:
return handleIfStatement(statement, checker);
case ts.SyntaxKind.SwitchStatement:
return matchBreakOrContinue(handleSwitchStatement(statement, checker), node_1.isBreakStatement);
case ts.SyntaxKind.TryStatement:
return handleTryStatement(statement, checker);
case ts.SyntaxKind.LabeledStatement:
return matchLabel(getControlFlowEndWorker(statement.statement, checker), statement.label);
case ts.SyntaxKind.WithStatement:
return getControlFlowEndWorker(statement.statement, checker);
case ts.SyntaxKind.ExpressionStatement:
if (checker === undefined)
return defaultControlFlowEnd;
return handleExpressionStatement(statement, checker);
default:
return defaultControlFlowEnd;
}
}
function handleBlock(statement, checker) {
const result = { statements: [], end: false };
for (const s of statement.statements) {
const current = getControlFlowEndWorker(s, checker);
result.statements.push(...current.statements);
if (current.end) {
result.end = true;
break;
}
}
return result;
}
function handleForInOrOfStatement(statement, checker) {
const end = matchBreakOrContinue(getControlFlowEndWorker(statement.statement, checker), node_1.isBreakOrContinueStatement);
end.end = false; // loop body is guaranteed to be executed
return end;
}
function handleForAndWhileStatement(statement, checker) {
const constantCondition = statement.kind === ts.SyntaxKind.WhileStatement
? getConstantCondition(statement.expression)
: statement.condition === undefined || getConstantCondition(statement.condition);
if (constantCondition === false)
return defaultControlFlowEnd; // loop body is never executed
const end = matchBreakOrContinue(getControlFlowEndWorker(statement.statement, checker), node_1.isBreakOrContinueStatement);
if (constantCondition === undefined)
end.end = false; // can't be sure that loop body is executed at all
return end;
}
/** Simply detects `true` and `false` in conditions. That matches TypeScript's behavior. */
function getConstantCondition(node) {
switch (node.kind) {
case ts.SyntaxKind.TrueKeyword:
return true;
case ts.SyntaxKind.FalseKeyword:
return false;
default:
return;
}
}
function handleIfStatement(node, checker) {
switch (getConstantCondition(node.expression)) {
case true:
// else branch is never executed
return getControlFlowEndWorker(node.thenStatement, checker);
case false:
// then branch is never executed
return node.elseStatement === undefined
? defaultControlFlowEnd
: getControlFlowEndWorker(node.elseStatement, checker);
}
const then = getControlFlowEndWorker(node.thenStatement, checker);
if (node.elseStatement === undefined)
return {
statements: then.statements,
end: false,
};
const elze = getControlFlowEndWorker(node.elseStatement, checker);
return {
statements: [...then.statements, ...elze.statements],
end: then.end && elze.end,
};
}
function handleSwitchStatement(node, checker) {
let hasDefault = false;
const result = {
statements: [],
end: false,
};
for (const clause of node.caseBlock.clauses) {
if (clause.kind === ts.SyntaxKind.DefaultClause)
hasDefault = true;
const current = handleBlock(clause, checker);
result.end = current.end;
result.statements.push(...current.statements);
}
result.end && (result.end = hasDefault || checker !== undefined && util_1.hasExhaustiveCaseClauses(node, checker));
return result;
}
function handleTryStatement(node, checker) {
let finallyResult;
if (node.finallyBlock !== undefined) {
finallyResult = handleBlock(node.finallyBlock, checker);
// if 'finally' always ends control flow, we are not interested in any jump statements from 'try' or 'catch'
if (finallyResult.end)
return finallyResult;
}
const tryResult = handleBlock(node.tryBlock, checker);
if (node.catchClause === undefined)
return { statements: finallyResult.statements.concat(tryResult.statements), end: tryResult.end };
const catchResult = handleBlock(node.catchClause.block, checker);
return {
statements: tryResult.statements
// remove all throw statements and throwing function calls from the list of control flow statements inside tryBlock
.filter((s) => s.kind !== ts.SyntaxKind.ThrowStatement && s.kind !== ts.SyntaxKind.ExpressionStatement)
.concat(catchResult.statements, finallyResult === undefined ? [] : finallyResult.statements),
end: tryResult.end && catchResult.end, // only ends control flow if try AND catch definitely end control flow
};
}
/** Dotted name as TypeScript requires it for assertion signatures to affect control flow. */
function isDottedNameWithExplicitTypeAnnotation(node, checker) {
while (true) {
switch (node.kind) {
case ts.SyntaxKind.Identifier: {
const symbol = checker.getExportSymbolOfSymbol(checker.getSymbolAtLocation(node));
return isExplicitlyTypedSymbol(util_1.isSymbolFlagSet(symbol, ts.SymbolFlags.Alias) ? checker.getAliasedSymbol(symbol) : symbol, checker);
}
case ts.SyntaxKind.ThisKeyword:
return isExplicitlyTypedThis(node);
case ts.SyntaxKind.SuperKeyword:
return true;
case ts.SyntaxKind.PropertyAccessExpression:
if (!isExplicitlyTypedSymbol(checker.getSymbolAtLocation(node), checker))
return false;
// falls through
case ts.SyntaxKind.ParenthesizedExpression:
node = node.expression;
continue;
default:
return false;
}
}
}
function isExplicitlyTypedSymbol(symbol, checker) {
if (symbol === undefined)
return false;
if (util_1.isSymbolFlagSet(symbol, ts.SymbolFlags.Function | ts.SymbolFlags.Method | ts.SymbolFlags.Class | ts.SymbolFlags.ValueModule))
return true;
if (!util_1.isSymbolFlagSet(symbol, ts.SymbolFlags.Variable | ts.SymbolFlags.Property))
return false;
if (symbol.valueDeclaration === undefined)
return false;
if (declarationHasExplicitTypeAnnotation(symbol.valueDeclaration))
return true;
return node_1.isVariableDeclaration(symbol.valueDeclaration) &&
symbol.valueDeclaration.parent.parent.kind === ts.SyntaxKind.ForOfStatement &&
isDottedNameWithExplicitTypeAnnotation(symbol.valueDeclaration.parent.parent.expression, checker);
}
function declarationHasExplicitTypeAnnotation(node) {
if (ts.isJSDocPropertyLikeTag(node))
return node.typeExpression !== undefined;
return (node_1.isVariableDeclaration(node) ||
node_1.isParameterDeclaration(node) ||
node_1.isPropertyDeclaration(node) ||
node_1.isPropertySignature(node)) && (util_1.isNodeFlagSet(node, ts.NodeFlags.JavaScriptFile)
? ts.getJSDocType(node)
: node.type) !== undefined;
}
function isExplicitlyTypedThis(node) {
var _a;
do {
node = node.parent;
if (node_1.isDecorator(node)) {
// `this` in decorators always resolves outside of the containing class
if (node.parent.kind === ts.SyntaxKind.Parameter && node_1.isClassLikeDeclaration(node.parent.parent.parent)) {
node = node.parent.parent.parent.parent;
}
else if (node_1.isClassLikeDeclaration(node.parent.parent)) {
node = node.parent.parent.parent;
}
else if (node_1.isClassLikeDeclaration(node.parent)) {
node = node.parent.parent;
}
}
} while (util_1.isFunctionScopeBoundary(node) !== 1 /* Function */ || node.kind === ts.SyntaxKind.ArrowFunction);
return util_1.isFunctionWithBody(node) &&
(util_1.isNodeFlagSet(node, ts.NodeFlags.JavaScriptFile)
? ((_a = ts.getJSDocThisTag(node)) === null || _a === void 0 ? void 0 : _a.typeExpression) !== undefined
: node.parameters.length !== 0 && util_1.isThisParameter(node.parameters[0]) && node.parameters[0].type !== undefined) ||
node_1.isClassLikeDeclaration(node.parent);
}
var SignatureEffect;
(function (SignatureEffect) {
SignatureEffect[SignatureEffect["Never"] = 1] = "Never";
SignatureEffect[SignatureEffect["Asserts"] = 2] = "Asserts";
})(SignatureEffect = exports.SignatureEffect || (exports.SignatureEffect = {}));
/**
* Dermines whether a top level CallExpression has a control flow effect according to TypeScript's rules.
* This handles functions returning `never` and `asserts`.
*/
function callExpressionAffectsControlFlow(node, checker) {
var _a, _b, _c;
if (!node_1.isExpressionStatement(node.parent) ||
ts.isOptionalChain(node) ||
!isDottedNameWithExplicitTypeAnnotation(node.expression, checker))
return;
const signature = checker.getResolvedSignature(node);
if ((signature === null || signature === void 0 ? void 0 : signature.declaration) === undefined)
return;
const typeNode = ts.isJSDocSignature(signature.declaration)
? (_b = (_a = signature.declaration.type) === null || _a === void 0 ? void 0 : _a.typeExpression) === null || _b === void 0 ? void 0 : _b.type
: (_c = signature.declaration.type) !== null && _c !== void 0 ? _c : (util_1.isNodeFlagSet(signature.declaration, ts.NodeFlags.JavaScriptFile)
? ts.getJSDocReturnType(signature.declaration)
: undefined);
if (typeNode === undefined)
return;
if (node_1.isTypePredicateNode(typeNode) && typeNode.assertsModifier !== undefined)
return 2 /* Asserts */;
return util_1.isTypeFlagSet(checker.getTypeFromTypeNode(typeNode), ts.TypeFlags.Never) ? 1 /* Never */ : undefined;
}
exports.callExpressionAffectsControlFlow = callExpressionAffectsControlFlow;
function handleExpressionStatement(node, checker) {
if (!node_1.isCallExpression(node.expression))
return defaultControlFlowEnd;
switch (callExpressionAffectsControlFlow(node.expression, checker)) {
case 2 /* Asserts */:
return { statements: [node], end: false };
case 1 /* Never */:
return { statements: [node], end: true };
case undefined:
return defaultControlFlowEnd;
}
}
function matchBreakOrContinue(current, pred) {
const result = {
statements: [],
end: current.end,
};
for (const statement of current.statements) {
if (pred(statement) && statement.label === undefined) {
result.end = false;
continue;
}
result.statements.push(statement);
}
return result;
}
function matchLabel(current, label) {
const result = {
statements: [],
end: current.end,
};
const labelText = label.text;
for (const statement of current.statements) {
switch (statement.kind) {
case ts.SyntaxKind.BreakStatement:
case ts.SyntaxKind.ContinueStatement:
if (statement.label !== undefined && statement.label.text === labelText) {
result.end = false;
continue;
}
}
result.statements.push(statement);
}
return result;
}
//# sourceMappingURL=control-flow.js.map

1
node_modules/tsutils/util/control-flow.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

33
node_modules/tsutils/util/convert-ast.d.ts generated vendored Normal file
View File

@@ -0,0 +1,33 @@
import * as ts from 'typescript';
/** Wraps an AST node. Can be used as a tree using `children` or a linked list using `next` and `skip`. */
export interface NodeWrap {
/** The real AST node. */
node: ts.Node;
/** The SyntaxKind of `node`. */
kind: ts.SyntaxKind;
/** All immediate children of `node` that would be visited by `ts.forEachChild(node, cb)`. */
children: NodeWrap[];
/** Link to the next NodeWrap, depth-first. */
next?: NodeWrap;
/** Link to the next NodeWrap skipping all children of the current node. */
skip?: NodeWrap;
/** Link to the parent NodeWrap */
parent?: NodeWrap;
}
export interface WrappedAst extends NodeWrap {
node: ts.SourceFile;
next: NodeWrap;
skip: undefined;
parent: undefined;
}
export interface ConvertedAst {
/** nodes wrapped in a data structure with useful links */
wrapped: WrappedAst;
/** depth-first array of all nodes excluding SourceFile */
flat: ReadonlyArray<ts.Node>;
}
/**
* Takes a `ts.SourceFile` and creates data structures that are easier (or more performant) to traverse.
* Note that there is only a performance gain if you can reuse these structures. It's not recommended for one-time AST walks.
*/
export declare function convertAst(sourceFile: ts.SourceFile): ConvertedAst;

79
node_modules/tsutils/util/convert-ast.js generated vendored Normal file
View File

@@ -0,0 +1,79 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertAst = void 0;
const ts = require("typescript");
const util_1 = require("./util");
/**
* Takes a `ts.SourceFile` and creates data structures that are easier (or more performant) to traverse.
* Note that there is only a performance gain if you can reuse these structures. It's not recommended for one-time AST walks.
*/
function convertAst(sourceFile) {
const wrapped = {
node: sourceFile,
parent: undefined,
kind: ts.SyntaxKind.SourceFile,
children: [],
next: undefined,
skip: undefined,
};
const flat = [];
let current = wrapped;
function collectChildren(node) {
current.children.push({
node,
parent: current,
kind: node.kind,
children: [],
next: undefined,
skip: undefined,
});
}
const stack = [];
while (true) {
if (current.children.length === 0) {
ts.forEachChild(current.node, collectChildren);
if (current.children.length === 0) {
current = current.parent; // nothing to do here, go back to parent
}
else {
// recurse into first child
const firstChild = current.children[0];
current.next = firstChild;
flat.push(firstChild.node);
if (util_1.isNodeKind(firstChild.kind))
current = firstChild;
stack.push(1); // set index in stack so we know where to continue processing children
}
}
else {
const index = stack[stack.length - 1];
if (index < current.children.length) { // handles 2nd child to the last
const currentChild = current.children[index];
flat.push(currentChild.node);
let previous = current.children[index - 1];
while (previous.children.length !== 0) {
previous.skip = currentChild;
previous = previous.children[previous.children.length - 1];
}
previous.skip = previous.next = currentChild;
++stack[stack.length - 1];
if (util_1.isNodeKind(currentChild.kind))
current = currentChild; // recurse into child
}
else {
// done on this node
if (stack.length === 1)
break;
// remove index from stack and go back to parent
stack.pop();
current = current.parent;
}
}
}
return {
wrapped,
flat,
};
}
exports.convertAst = convertAst;
//# sourceMappingURL=convert-ast.js.map

1
node_modules/tsutils/util/convert-ast.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"convert-ast.js","sourceRoot":"","sources":["convert-ast.ts"],"names":[],"mappings":";;;AAAA,iCAAiC;AACjC,iCAAoC;AAgCpC;;;GAGG;AACH,SAAgB,UAAU,CAAC,UAAyB;IAChD,MAAM,OAAO,GAAe;QACxB,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,SAAS;QACjB,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,UAAU;QAC9B,QAAQ,EAAE,EAAE;QACZ,IAAI,EAAO,SAAS;QACpB,IAAI,EAAE,SAAS;KAClB,CAAC;IACF,MAAM,IAAI,GAAc,EAAE,CAAC;IAC3B,IAAI,OAAO,GAAa,OAAO,CAAC;IAEhC,SAAS,eAAe,CAAC,IAAa;QAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;YAClB,IAAI;YACJ,MAAM,EAAE,OAAO;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,QAAQ,EAAE,EAAE;YACZ,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;SAClB,CAAC,CAAC;IACP,CAAC;IACD,MAAM,KAAK,GAAG,EAAE,CAAC;IACjB,OAAO,IAAI,EAAE;QACT,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;YAC/B,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;YAC/C,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;gBAC/B,OAAO,GAAG,OAAO,CAAC,MAAO,CAAC,CAAC,wCAAwC;aACtE;iBAAM;gBACH,2BAA2B;gBAC3B,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACvC,OAAO,CAAC,IAAI,GAAG,UAAU,CAAC;gBAC1B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBAC3B,IAAI,iBAAU,CAAC,UAAU,CAAC,IAAI,CAAC;oBAC3B,OAAO,GAAG,UAAU,CAAC;gBACzB,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,sEAAsE;aACxF;SACJ;aAAM;YACH,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACtC,IAAI,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,gCAAgC;gBACnE,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;gBAC7C,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;gBAC7B,IAAI,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;gBAC3C,OAAO,QAAQ,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;oBACnC,QAAQ,CAAC,IAAI,GAAG,YAAY,CAAC;oBAC7B,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;iBAC9D;gBACD,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,GAAG,YAAY,CAAC;gBAC7C,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAC1B,IAAI,iBAAU,CAAC,YAAY,CAAC,IAAI,CAAC;oBAC7B,OAAO,GAAG,YAAY,CAAC,CAAC,qBAAqB;aACpD;iBAAM;gBACH,oBAAoB;gBACpB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;oBAClB,MAAM;gBACV,gDAAgD;gBAChD,KAAK,CAAC,GAAG,EAAE,CAAC;gBACZ,OAAO,GAAG,OAAO,CAAC,MAAO,CAAC;aAC7B;SACJ;KACJ;IAED,OAAO;QACH,OAAO;QACP,IAAI;KACP,CAAC;AACN,CAAC;AAlED,gCAkEC"}

5
node_modules/tsutils/util/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
export * from './util';
export * from './usage';
export * from './control-flow';
export * from './type';
export * from './convert-ast';

9
node_modules/tsutils/util/index.js generated vendored Normal file
View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./util"), exports);
tslib_1.__exportStar(require("./usage"), exports);
tslib_1.__exportStar(require("./control-flow"), exports);
tslib_1.__exportStar(require("./type"), exports);
tslib_1.__exportStar(require("./convert-ast"), exports);
//# sourceMappingURL=index.js.map

1
node_modules/tsutils/util/index.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,iDAAuB;AACvB,kDAAwB;AACxB,yDAA+B;AAC/B,iDAAuB;AACvB,wDAA8B"}

35
node_modules/tsutils/util/type.d.ts generated vendored Normal file
View File

@@ -0,0 +1,35 @@
import * as ts from 'typescript';
import { PropertyName } from './util';
export declare function isEmptyObjectType(type: ts.Type): type is ts.ObjectType;
export declare function removeOptionalityFromType(checker: ts.TypeChecker, type: ts.Type): ts.Type;
export declare function removeOptionalChainingUndefinedMarkerType(checker: ts.TypeChecker, type: ts.Type): ts.Type;
export declare function isOptionalChainingUndefinedMarkerType(checker: ts.TypeChecker, t: ts.Type): boolean;
export declare function isTypeAssignableToNumber(checker: ts.TypeChecker, type: ts.Type): boolean;
export declare function isTypeAssignableToString(checker: ts.TypeChecker, type: ts.Type): boolean;
export declare function getCallSignaturesOfType(type: ts.Type): ReadonlyArray<ts.Signature>;
/** Returns all types of a union type or an array containing `type` itself if it's no union type. */
export declare function unionTypeParts(type: ts.Type): ts.Type[];
/** Returns all types of a intersection type or an array containing `type` itself if it's no intersection type. */
export declare function intersectionTypeParts(type: ts.Type): ts.Type[];
export declare function someTypePart(type: ts.Type, predicate: (t: ts.Type) => t is ts.UnionOrIntersectionType, cb: (t: ts.Type) => boolean): boolean;
/** Determines if a type thenable and can be used with `await`. */
export declare function isThenableType(checker: ts.TypeChecker, node: ts.Node, type: ts.Type): boolean;
/** Determines if a type thenable and can be used with `await`. */
export declare function isThenableType(checker: ts.TypeChecker, node: ts.Expression, type?: ts.Type): boolean;
/** Determine if a type is definitely falsy. This function doesn't unwrap union types. */
export declare function isFalsyType(type: ts.Type): boolean;
/** Determines whether the given type is a boolean literal type and matches the given boolean literal (true or false). */
export declare function isBooleanLiteralType(type: ts.Type, literal: boolean): boolean;
export declare function getPropertyOfType(type: ts.Type, name: ts.__String): ts.Symbol | undefined;
export declare function getWellKnownSymbolPropertyOfType(type: ts.Type, wellKnownSymbolName: string, checker: ts.TypeChecker): ts.Symbol | undefined;
/** Determines if writing to a certain property of a given type is allowed. */
export declare function isPropertyReadonlyInType(type: ts.Type, name: ts.__String, checker: ts.TypeChecker): boolean;
export declare function symbolHasReadonlyDeclaration(symbol: ts.Symbol, checker: ts.TypeChecker): boolean;
/** Returns the the literal name or unique symbol name from a given type. Doesn't unwrap union types. */
export declare function getPropertyNameFromType(type: ts.Type): PropertyName | undefined;
export declare function getSymbolOfClassLikeDeclaration(node: ts.ClassLikeDeclaration, checker: ts.TypeChecker): ts.Symbol;
export declare function getConstructorTypeOfClassLikeDeclaration(node: ts.ClassLikeDeclaration, checker: ts.TypeChecker): ts.Type;
export declare function getInstanceTypeOfClassLikeDeclaration(node: ts.ClassLikeDeclaration, checker: ts.TypeChecker): ts.Type;
export declare function getIteratorYieldResultFromIteratorResult(type: ts.Type, node: ts.Node, checker: ts.TypeChecker): ts.Type;
/** Lookup the declaration of a class member in the super class. */
export declare function getBaseClassMemberOfClassElement(node: ts.PropertyDeclaration | ts.MethodDeclaration | ts.AccessorDeclaration, checker: ts.TypeChecker): ts.Symbol | undefined;

331
node_modules/tsutils/util/type.js generated vendored Normal file
View File

@@ -0,0 +1,331 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBaseClassMemberOfClassElement = exports.getIteratorYieldResultFromIteratorResult = exports.getInstanceTypeOfClassLikeDeclaration = exports.getConstructorTypeOfClassLikeDeclaration = exports.getSymbolOfClassLikeDeclaration = exports.getPropertyNameFromType = exports.symbolHasReadonlyDeclaration = exports.isPropertyReadonlyInType = exports.getWellKnownSymbolPropertyOfType = exports.getPropertyOfType = exports.isBooleanLiteralType = exports.isFalsyType = exports.isThenableType = exports.someTypePart = exports.intersectionTypeParts = exports.unionTypeParts = exports.getCallSignaturesOfType = exports.isTypeAssignableToString = exports.isTypeAssignableToNumber = exports.isOptionalChainingUndefinedMarkerType = exports.removeOptionalChainingUndefinedMarkerType = exports.removeOptionalityFromType = exports.isEmptyObjectType = void 0;
const ts = require("typescript");
const type_1 = require("../typeguard/type");
const util_1 = require("./util");
const node_1 = require("../typeguard/node");
function isEmptyObjectType(type) {
if (type_1.isObjectType(type) &&
type.objectFlags & ts.ObjectFlags.Anonymous &&
type.getProperties().length === 0 &&
type.getCallSignatures().length === 0 &&
type.getConstructSignatures().length === 0 &&
type.getStringIndexType() === undefined &&
type.getNumberIndexType() === undefined) {
const baseTypes = type.getBaseTypes();
return baseTypes === undefined || baseTypes.every(isEmptyObjectType);
}
return false;
}
exports.isEmptyObjectType = isEmptyObjectType;
function removeOptionalityFromType(checker, type) {
if (!containsTypeWithFlag(type, ts.TypeFlags.Undefined))
return type;
const allowsNull = containsTypeWithFlag(type, ts.TypeFlags.Null);
type = checker.getNonNullableType(type);
return allowsNull ? checker.getNullableType(type, ts.TypeFlags.Null) : type;
}
exports.removeOptionalityFromType = removeOptionalityFromType;
function containsTypeWithFlag(type, flag) {
for (const t of unionTypeParts(type))
if (util_1.isTypeFlagSet(t, flag))
return true;
return false;
}
function removeOptionalChainingUndefinedMarkerType(checker, type) {
if (!type_1.isUnionType(type))
return isOptionalChainingUndefinedMarkerType(checker, type) ? type.getNonNullableType() : type;
let flags = 0;
let containsUndefinedMarker = false;
for (const t of type.types) {
if (isOptionalChainingUndefinedMarkerType(checker, t)) {
containsUndefinedMarker = true;
}
else {
flags |= t.flags;
}
}
return containsUndefinedMarker
? checker.getNullableType(type.getNonNullableType(), flags)
: type;
}
exports.removeOptionalChainingUndefinedMarkerType = removeOptionalChainingUndefinedMarkerType;
function isOptionalChainingUndefinedMarkerType(checker, t) {
return util_1.isTypeFlagSet(t, ts.TypeFlags.Undefined) && checker.getNullableType(t.getNonNullableType(), ts.TypeFlags.Undefined) !== t;
}
exports.isOptionalChainingUndefinedMarkerType = isOptionalChainingUndefinedMarkerType;
function isTypeAssignableToNumber(checker, type) {
return isTypeAssignableTo(checker, type, ts.TypeFlags.NumberLike);
}
exports.isTypeAssignableToNumber = isTypeAssignableToNumber;
function isTypeAssignableToString(checker, type) {
return isTypeAssignableTo(checker, type, ts.TypeFlags.StringLike);
}
exports.isTypeAssignableToString = isTypeAssignableToString;
function isTypeAssignableTo(checker, type, flags) {
flags |= ts.TypeFlags.Any;
let typeParametersSeen;
return (function check(t) {
if (type_1.isTypeParameter(t) && t.symbol !== undefined && t.symbol.declarations !== undefined) {
if (typeParametersSeen === undefined) {
typeParametersSeen = new Set([t]);
}
else if (!typeParametersSeen.has(t)) {
typeParametersSeen.add(t);
}
else {
return false;
}
const declaration = t.symbol.declarations[0];
if (declaration.constraint === undefined)
return true; // TODO really?
return check(checker.getTypeFromTypeNode(declaration.constraint));
}
if (type_1.isUnionType(t))
return t.types.every(check);
if (type_1.isIntersectionType(t))
return t.types.some(check);
return util_1.isTypeFlagSet(t, flags);
})(type);
}
function getCallSignaturesOfType(type) {
if (type_1.isUnionType(type)) {
const signatures = [];
for (const t of type.types)
signatures.push(...getCallSignaturesOfType(t));
return signatures;
}
if (type_1.isIntersectionType(type)) {
let signatures;
for (const t of type.types) {
const sig = getCallSignaturesOfType(t);
if (sig.length !== 0) {
if (signatures !== undefined)
return []; // if more than one type of the intersection has call signatures, none of them is useful for inference
signatures = sig;
}
}
return signatures === undefined ? [] : signatures;
}
return type.getCallSignatures();
}
exports.getCallSignaturesOfType = getCallSignaturesOfType;
/** Returns all types of a union type or an array containing `type` itself if it's no union type. */
function unionTypeParts(type) {
return type_1.isUnionType(type) ? type.types : [type];
}
exports.unionTypeParts = unionTypeParts;
/** Returns all types of a intersection type or an array containing `type` itself if it's no intersection type. */
function intersectionTypeParts(type) {
return type_1.isIntersectionType(type) ? type.types : [type];
}
exports.intersectionTypeParts = intersectionTypeParts;
function someTypePart(type, predicate, cb) {
return predicate(type) ? type.types.some(cb) : cb(type);
}
exports.someTypePart = someTypePart;
function isThenableType(checker, node, type = checker.getTypeAtLocation(node)) {
for (const ty of unionTypeParts(checker.getApparentType(type))) {
const then = ty.getProperty('then');
if (then === undefined)
continue;
const thenType = checker.getTypeOfSymbolAtLocation(then, node);
for (const t of unionTypeParts(thenType))
for (const signature of t.getCallSignatures())
if (signature.parameters.length !== 0 && isCallback(checker, signature.parameters[0], node))
return true;
}
return false;
}
exports.isThenableType = isThenableType;
function isCallback(checker, param, node) {
let type = checker.getApparentType(checker.getTypeOfSymbolAtLocation(param, node));
if (param.valueDeclaration.dotDotDotToken) {
// unwrap array type of rest parameter
type = type.getNumberIndexType();
if (type === undefined)
return false;
}
for (const t of unionTypeParts(type))
if (t.getCallSignatures().length !== 0)
return true;
return false;
}
/** Determine if a type is definitely falsy. This function doesn't unwrap union types. */
function isFalsyType(type) {
if (type.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Null | ts.TypeFlags.Void))
return true;
if (type_1.isLiteralType(type))
return !type.value;
return isBooleanLiteralType(type, false);
}
exports.isFalsyType = isFalsyType;
/** Determines whether the given type is a boolean literal type and matches the given boolean literal (true or false). */
function isBooleanLiteralType(type, literal) {
return util_1.isTypeFlagSet(type, ts.TypeFlags.BooleanLiteral) &&
type.intrinsicName === (literal ? 'true' : 'false');
}
exports.isBooleanLiteralType = isBooleanLiteralType;
function getPropertyOfType(type, name) {
if (!name.startsWith('__'))
return type.getProperty(name);
return type.getProperties().find((s) => s.escapedName === name);
}
exports.getPropertyOfType = getPropertyOfType;
function getWellKnownSymbolPropertyOfType(type, wellKnownSymbolName, checker) {
const prefix = '__@' + wellKnownSymbolName;
for (const prop of type.getProperties()) {
if (!prop.name.startsWith(prefix))
continue;
const globalSymbol = checker.getApparentType(checker.getTypeAtLocation(prop.valueDeclaration.name.expression)).symbol;
if (prop.escapedName === getPropertyNameOfWellKnownSymbol(checker, globalSymbol, wellKnownSymbolName))
return prop;
}
return;
}
exports.getWellKnownSymbolPropertyOfType = getWellKnownSymbolPropertyOfType;
function getPropertyNameOfWellKnownSymbol(checker, symbolConstructor, symbolName) {
const knownSymbol = symbolConstructor &&
checker.getTypeOfSymbolAtLocation(symbolConstructor, symbolConstructor.valueDeclaration).getProperty(symbolName);
const knownSymbolType = knownSymbol && checker.getTypeOfSymbolAtLocation(knownSymbol, knownSymbol.valueDeclaration);
if (knownSymbolType && type_1.isUniqueESSymbolType(knownSymbolType))
return knownSymbolType.escapedName;
return ('__@' + symbolName);
}
/** Determines if writing to a certain property of a given type is allowed. */
function isPropertyReadonlyInType(type, name, checker) {
let seenProperty = false;
let seenReadonlySignature = false;
for (const t of unionTypeParts(type)) {
if (getPropertyOfType(t, name) === undefined) {
// property is not present in this part of the union -> check for readonly index signature
const index = (util_1.isNumericPropertyName(name) ? checker.getIndexInfoOfType(t, ts.IndexKind.Number) : undefined) ||
checker.getIndexInfoOfType(t, ts.IndexKind.String);
if (index !== undefined && index.isReadonly) {
if (seenProperty)
return true;
seenReadonlySignature = true;
}
}
else if (seenReadonlySignature || isReadonlyPropertyIntersection(t, name, checker)) {
return true;
}
else {
seenProperty = true;
}
}
return false;
}
exports.isPropertyReadonlyInType = isPropertyReadonlyInType;
function isReadonlyPropertyIntersection(type, name, checker) {
return someTypePart(type, type_1.isIntersectionType, (t) => {
const prop = getPropertyOfType(t, name);
if (prop === undefined)
return false;
if (prop.flags & ts.SymbolFlags.Transient) {
if (/^(?:[1-9]\d*|0)$/.test(name) && type_1.isTupleTypeReference(t))
return t.target.readonly;
switch (isReadonlyPropertyFromMappedType(t, name, checker)) {
case true:
return true;
case false:
return false;
default:
// `undefined` falls through
}
}
return (
// members of namespace import
util_1.isSymbolFlagSet(prop, ts.SymbolFlags.ValueModule) ||
// we unwrapped every mapped type, now we can check the actual declarations
symbolHasReadonlyDeclaration(prop, checker));
});
}
function isReadonlyPropertyFromMappedType(type, name, checker) {
if (!type_1.isObjectType(type) || !util_1.isObjectFlagSet(type, ts.ObjectFlags.Mapped))
return;
const declaration = type.symbol.declarations[0];
// well-known symbols are not affected by mapped types
if (declaration.readonlyToken !== undefined && !/^__@[^@]+$/.test(name))
return declaration.readonlyToken.kind !== ts.SyntaxKind.MinusToken;
return isPropertyReadonlyInType(type.modifiersType, name, checker);
}
function symbolHasReadonlyDeclaration(symbol, checker) {
return (symbol.flags & ts.SymbolFlags.Accessor) === ts.SymbolFlags.GetAccessor ||
symbol.declarations !== undefined &&
symbol.declarations.some((node) => util_1.isModifierFlagSet(node, ts.ModifierFlags.Readonly) ||
node_1.isVariableDeclaration(node) && util_1.isNodeFlagSet(node.parent, ts.NodeFlags.Const) ||
node_1.isCallExpression(node) && util_1.isReadonlyAssignmentDeclaration(node, checker) ||
node_1.isEnumMember(node) ||
(node_1.isPropertyAssignment(node) || node_1.isShorthandPropertyAssignment(node)) && util_1.isInConstContext(node.parent));
}
exports.symbolHasReadonlyDeclaration = symbolHasReadonlyDeclaration;
/** Returns the the literal name or unique symbol name from a given type. Doesn't unwrap union types. */
function getPropertyNameFromType(type) {
// string or number literal. bigint is intentionally excluded
if (type.flags & (ts.TypeFlags.StringLiteral | ts.TypeFlags.NumberLiteral)) {
const value = String(type.value);
return { displayName: value, symbolName: ts.escapeLeadingUnderscores(value) };
}
if (type_1.isUniqueESSymbolType(type))
return {
displayName: `[${type.symbol
? `${isKnownSymbol(type.symbol) ? 'Symbol.' : ''}${type.symbol.name}`
: type.escapedName.replace(/^__@|@\d+$/g, '')}]`,
symbolName: type.escapedName,
};
}
exports.getPropertyNameFromType = getPropertyNameFromType;
function isKnownSymbol(symbol) {
return util_1.isSymbolFlagSet(symbol, ts.SymbolFlags.Property) &&
symbol.valueDeclaration !== undefined &&
node_1.isInterfaceDeclaration(symbol.valueDeclaration.parent) &&
symbol.valueDeclaration.parent.name.text === 'SymbolConstructor' &&
isGlobalDeclaration(symbol.valueDeclaration.parent);
}
function isGlobalDeclaration(node) {
return util_1.isNodeFlagSet(node.parent, ts.NodeFlags.GlobalAugmentation) || node_1.isSourceFile(node.parent) && !ts.isExternalModule(node.parent);
}
function getSymbolOfClassLikeDeclaration(node, checker) {
var _a;
return checker.getSymbolAtLocation((_a = node.name) !== null && _a !== void 0 ? _a : util_1.getChildOfKind(node, ts.SyntaxKind.ClassKeyword));
}
exports.getSymbolOfClassLikeDeclaration = getSymbolOfClassLikeDeclaration;
function getConstructorTypeOfClassLikeDeclaration(node, checker) {
return node.kind === ts.SyntaxKind.ClassExpression
? checker.getTypeAtLocation(node)
: checker.getTypeOfSymbolAtLocation(getSymbolOfClassLikeDeclaration(node, checker), node);
}
exports.getConstructorTypeOfClassLikeDeclaration = getConstructorTypeOfClassLikeDeclaration;
function getInstanceTypeOfClassLikeDeclaration(node, checker) {
return node.kind === ts.SyntaxKind.ClassDeclaration
? checker.getTypeAtLocation(node)
: checker.getDeclaredTypeOfSymbol(getSymbolOfClassLikeDeclaration(node, checker));
}
exports.getInstanceTypeOfClassLikeDeclaration = getInstanceTypeOfClassLikeDeclaration;
function getIteratorYieldResultFromIteratorResult(type, node, checker) {
return type_1.isUnionType(type) && type.types.find((t) => {
const done = t.getProperty('done');
return done !== undefined &&
isBooleanLiteralType(removeOptionalityFromType(checker, checker.getTypeOfSymbolAtLocation(done, node)), false);
}) || type;
}
exports.getIteratorYieldResultFromIteratorResult = getIteratorYieldResultFromIteratorResult;
/** Lookup the declaration of a class member in the super class. */
function getBaseClassMemberOfClassElement(node, checker) {
if (!node_1.isClassLikeDeclaration(node.parent))
return;
const base = util_1.getBaseOfClassLikeExpression(node.parent);
if (base === undefined)
return;
const name = util_1.getSingleLateBoundPropertyNameOfPropertyName(node.name, checker);
if (name === undefined)
return;
const baseType = checker.getTypeAtLocation(util_1.hasModifier(node.modifiers, ts.SyntaxKind.StaticKeyword)
? base.expression
: base);
return getPropertyOfType(baseType, name.symbolName);
}
exports.getBaseClassMemberOfClassElement = getBaseClassMemberOfClassElement;
//# sourceMappingURL=type.js.map

1
node_modules/tsutils/util/type.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

30
node_modules/tsutils/util/usage.d.ts generated vendored Normal file
View File

@@ -0,0 +1,30 @@
import * as ts from 'typescript';
export interface VariableInfo {
domain: DeclarationDomain;
exported: boolean;
uses: VariableUse[];
inGlobalScope: boolean;
declarations: ts.Identifier[];
}
export interface VariableUse {
domain: UsageDomain;
location: ts.Identifier;
}
export declare enum DeclarationDomain {
Namespace = 1,
Type = 2,
Value = 4,
Import = 8,
Any = 7
}
export declare enum UsageDomain {
Namespace = 1,
Type = 2,
Value = 4,
ValueOrNamespace = 5,
Any = 7,
TypeQuery = 8
}
export declare function getUsageDomain(node: ts.Identifier): UsageDomain | undefined;
export declare function getDeclarationDomain(node: ts.Identifier): DeclarationDomain | undefined;
export declare function collectVariableUsage(sourceFile: ts.SourceFile): Map<ts.Identifier, VariableInfo>;

658
node_modules/tsutils/util/usage.js generated vendored Normal file
View File

@@ -0,0 +1,658 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.collectVariableUsage = exports.getDeclarationDomain = exports.getUsageDomain = exports.UsageDomain = exports.DeclarationDomain = void 0;
const util_1 = require("./util");
const ts = require("typescript");
var DeclarationDomain;
(function (DeclarationDomain) {
DeclarationDomain[DeclarationDomain["Namespace"] = 1] = "Namespace";
DeclarationDomain[DeclarationDomain["Type"] = 2] = "Type";
DeclarationDomain[DeclarationDomain["Value"] = 4] = "Value";
DeclarationDomain[DeclarationDomain["Import"] = 8] = "Import";
DeclarationDomain[DeclarationDomain["Any"] = 7] = "Any";
})(DeclarationDomain = exports.DeclarationDomain || (exports.DeclarationDomain = {}));
var UsageDomain;
(function (UsageDomain) {
UsageDomain[UsageDomain["Namespace"] = 1] = "Namespace";
UsageDomain[UsageDomain["Type"] = 2] = "Type";
UsageDomain[UsageDomain["Value"] = 4] = "Value";
UsageDomain[UsageDomain["ValueOrNamespace"] = 5] = "ValueOrNamespace";
UsageDomain[UsageDomain["Any"] = 7] = "Any";
UsageDomain[UsageDomain["TypeQuery"] = 8] = "TypeQuery";
})(UsageDomain = exports.UsageDomain || (exports.UsageDomain = {}));
// TODO handle cases where values are used only for their types, e.g. `declare [propSymbol]: number`
function getUsageDomain(node) {
const parent = node.parent;
switch (parent.kind) {
case ts.SyntaxKind.TypeReference:
return node.originalKeywordKind !== ts.SyntaxKind.ConstKeyword ? 2 /* Type */ : undefined;
case ts.SyntaxKind.ExpressionWithTypeArguments:
return parent.parent.token === ts.SyntaxKind.ImplementsKeyword ||
parent.parent.parent.kind === ts.SyntaxKind.InterfaceDeclaration
? 2 /* Type */
: 4 /* Value */;
case ts.SyntaxKind.TypeQuery:
return 5 /* ValueOrNamespace */ | 8 /* TypeQuery */;
case ts.SyntaxKind.QualifiedName:
if (parent.left === node) {
if (getEntityNameParent(parent).kind === ts.SyntaxKind.TypeQuery)
return 1 /* Namespace */ | 8 /* TypeQuery */;
return 1 /* Namespace */;
}
break;
case ts.SyntaxKind.ExportSpecifier:
// either {name} or {propertyName as name}
if (parent.propertyName === undefined ||
parent.propertyName === node)
return 7 /* Any */; // TODO handle type-only exports
break;
case ts.SyntaxKind.ExportAssignment:
return 7 /* Any */;
// Value
case ts.SyntaxKind.BindingElement:
if (parent.initializer === node)
return 5 /* ValueOrNamespace */;
break;
case ts.SyntaxKind.Parameter:
case ts.SyntaxKind.EnumMember:
case ts.SyntaxKind.PropertyDeclaration:
case ts.SyntaxKind.VariableDeclaration:
case ts.SyntaxKind.PropertyAssignment:
case ts.SyntaxKind.PropertyAccessExpression:
case ts.SyntaxKind.ImportEqualsDeclaration:
if (parent.name !== node)
return 5 /* ValueOrNamespace */; // TODO handle type-only imports
break;
case ts.SyntaxKind.JsxAttribute:
case ts.SyntaxKind.FunctionDeclaration:
case ts.SyntaxKind.FunctionExpression:
case ts.SyntaxKind.NamespaceImport:
case ts.SyntaxKind.ClassDeclaration:
case ts.SyntaxKind.ClassExpression:
case ts.SyntaxKind.ModuleDeclaration:
case ts.SyntaxKind.MethodDeclaration:
case ts.SyntaxKind.EnumDeclaration:
case ts.SyntaxKind.GetAccessor:
case ts.SyntaxKind.SetAccessor:
case ts.SyntaxKind.LabeledStatement:
case ts.SyntaxKind.BreakStatement:
case ts.SyntaxKind.ContinueStatement:
case ts.SyntaxKind.ImportClause:
case ts.SyntaxKind.ImportSpecifier:
case ts.SyntaxKind.TypePredicate: // TODO this actually references a parameter
case ts.SyntaxKind.MethodSignature:
case ts.SyntaxKind.PropertySignature:
case ts.SyntaxKind.NamespaceExportDeclaration:
case ts.SyntaxKind.NamespaceExport:
case ts.SyntaxKind.InterfaceDeclaration:
case ts.SyntaxKind.TypeAliasDeclaration:
case ts.SyntaxKind.TypeParameter:
case ts.SyntaxKind.NamedTupleMember:
break;
default:
return 5 /* ValueOrNamespace */;
}
}
exports.getUsageDomain = getUsageDomain;
function getDeclarationDomain(node) {
switch (node.parent.kind) {
case ts.SyntaxKind.TypeParameter:
case ts.SyntaxKind.InterfaceDeclaration:
case ts.SyntaxKind.TypeAliasDeclaration:
return 2 /* Type */;
case ts.SyntaxKind.ClassDeclaration:
case ts.SyntaxKind.ClassExpression:
return 2 /* Type */ | 4 /* Value */;
case ts.SyntaxKind.EnumDeclaration:
return 7 /* Any */;
case ts.SyntaxKind.NamespaceImport:
case ts.SyntaxKind.ImportClause:
return 7 /* Any */ | 8 /* Import */; // TODO handle type-only imports
case ts.SyntaxKind.ImportEqualsDeclaration:
case ts.SyntaxKind.ImportSpecifier:
return node.parent.name === node
? 7 /* Any */ | 8 /* Import */ // TODO handle type-only imports
: undefined;
case ts.SyntaxKind.ModuleDeclaration:
return 1 /* Namespace */;
case ts.SyntaxKind.Parameter:
if (node.parent.parent.kind === ts.SyntaxKind.IndexSignature || node.originalKeywordKind === ts.SyntaxKind.ThisKeyword)
return;
// falls through
case ts.SyntaxKind.BindingElement:
case ts.SyntaxKind.VariableDeclaration:
return node.parent.name === node ? 4 /* Value */ : undefined;
case ts.SyntaxKind.FunctionDeclaration:
case ts.SyntaxKind.FunctionExpression:
return 4 /* Value */;
}
}
exports.getDeclarationDomain = getDeclarationDomain;
function collectVariableUsage(sourceFile) {
return new UsageWalker().getUsage(sourceFile);
}
exports.collectVariableUsage = collectVariableUsage;
class AbstractScope {
constructor(_global) {
this._global = _global;
this._variables = new Map();
this._uses = [];
this._namespaceScopes = undefined;
this._enumScopes = undefined;
}
addVariable(identifier, name, selector, exported, domain) {
const variables = this.getDestinationScope(selector).getVariables();
const declaration = {
domain,
exported,
declaration: name,
};
const variable = variables.get(identifier);
if (variable === undefined) {
variables.set(identifier, {
domain,
declarations: [declaration],
uses: [],
});
}
else {
variable.domain |= domain;
variable.declarations.push(declaration);
}
}
addUse(use) {
this._uses.push(use);
}
getVariables() {
return this._variables;
}
getFunctionScope() {
return this;
}
end(cb) {
if (this._namespaceScopes !== undefined)
this._namespaceScopes.forEach((value) => value.finish(cb));
this._namespaceScopes = this._enumScopes = undefined;
this._applyUses();
this._variables.forEach((variable) => {
for (const declaration of variable.declarations) {
const result = {
declarations: [],
domain: declaration.domain,
exported: declaration.exported,
inGlobalScope: this._global,
uses: [],
};
for (const other of variable.declarations)
if (other.domain & declaration.domain)
result.declarations.push(other.declaration);
for (const use of variable.uses)
if (use.domain & declaration.domain)
result.uses.push(use);
cb(result, declaration.declaration, this);
}
});
}
// tslint:disable-next-line:prefer-function-over-method
markExported(_name) { } // only relevant for the root scope
createOrReuseNamespaceScope(name, _exported, ambient, hasExportStatement) {
let scope;
if (this._namespaceScopes === undefined) {
this._namespaceScopes = new Map();
}
else {
scope = this._namespaceScopes.get(name);
}
if (scope === undefined) {
scope = new NamespaceScope(ambient, hasExportStatement, this);
this._namespaceScopes.set(name, scope);
}
else {
scope.refresh(ambient, hasExportStatement);
}
return scope;
}
createOrReuseEnumScope(name, _exported) {
let scope;
if (this._enumScopes === undefined) {
this._enumScopes = new Map();
}
else {
scope = this._enumScopes.get(name);
}
if (scope === undefined) {
scope = new EnumScope(this);
this._enumScopes.set(name, scope);
}
return scope;
}
_applyUses() {
for (const use of this._uses)
if (!this._applyUse(use))
this._addUseToParent(use);
this._uses = [];
}
_applyUse(use, variables = this._variables) {
const variable = variables.get(use.location.text);
if (variable === undefined || (variable.domain & use.domain) === 0)
return false;
variable.uses.push(use);
return true;
}
_addUseToParent(_use) { } // tslint:disable-line:prefer-function-over-method
}
class RootScope extends AbstractScope {
constructor(_exportAll, global) {
super(global);
this._exportAll = _exportAll;
this._exports = undefined;
this._innerScope = new NonRootScope(this, 1 /* Function */);
}
addVariable(identifier, name, selector, exported, domain) {
if (domain & 8 /* Import */)
return super.addVariable(identifier, name, selector, exported, domain);
return this._innerScope.addVariable(identifier, name, selector, exported, domain);
}
addUse(use, origin) {
if (origin === this._innerScope)
return super.addUse(use);
return this._innerScope.addUse(use);
}
markExported(id) {
if (this._exports === undefined) {
this._exports = [id.text];
}
else {
this._exports.push(id.text);
}
}
end(cb) {
this._innerScope.end((value, key) => {
value.exported = value.exported || this._exportAll
|| this._exports !== undefined && this._exports.includes(key.text);
value.inGlobalScope = this._global;
return cb(value, key, this);
});
return super.end((value, key, scope) => {
value.exported = value.exported || scope === this
&& this._exports !== undefined && this._exports.includes(key.text);
return cb(value, key, scope);
});
}
getDestinationScope() {
return this;
}
}
class NonRootScope extends AbstractScope {
constructor(_parent, _boundary) {
super(false);
this._parent = _parent;
this._boundary = _boundary;
}
_addUseToParent(use) {
return this._parent.addUse(use, this);
}
getDestinationScope(selector) {
return this._boundary & selector
? this
: this._parent.getDestinationScope(selector);
}
}
class EnumScope extends NonRootScope {
constructor(parent) {
super(parent, 1 /* Function */);
}
end() {
this._applyUses();
}
}
class ConditionalTypeScope extends NonRootScope {
constructor(parent) {
super(parent, 8 /* ConditionalType */);
this._state = 0 /* Initial */;
}
updateState(newState) {
this._state = newState;
}
addUse(use) {
if (this._state === 2 /* TrueType */)
return void this._uses.push(use);
return this._parent.addUse(use, this);
}
}
class FunctionScope extends NonRootScope {
constructor(parent) {
super(parent, 1 /* Function */);
}
beginBody() {
this._applyUses();
}
}
class AbstractNamedExpressionScope extends NonRootScope {
constructor(_name, _domain, parent) {
super(parent, 1 /* Function */);
this._name = _name;
this._domain = _domain;
}
end(cb) {
this._innerScope.end(cb);
return cb({
declarations: [this._name],
domain: this._domain,
exported: false,
uses: this._uses,
inGlobalScope: false,
}, this._name, this);
}
addUse(use, source) {
if (source !== this._innerScope)
return this._innerScope.addUse(use);
if (use.domain & this._domain && use.location.text === this._name.text) {
this._uses.push(use);
}
else {
return this._parent.addUse(use, this);
}
}
getFunctionScope() {
return this._innerScope;
}
getDestinationScope() {
return this._innerScope;
}
}
class FunctionExpressionScope extends AbstractNamedExpressionScope {
constructor(name, parent) {
super(name, 4 /* Value */, parent);
this._innerScope = new FunctionScope(this);
}
beginBody() {
return this._innerScope.beginBody();
}
}
class ClassExpressionScope extends AbstractNamedExpressionScope {
constructor(name, parent) {
super(name, 4 /* Value */ | 2 /* Type */, parent);
this._innerScope = new NonRootScope(this, 1 /* Function */);
}
}
class BlockScope extends NonRootScope {
constructor(_functionScope, parent) {
super(parent, 2 /* Block */);
this._functionScope = _functionScope;
}
getFunctionScope() {
return this._functionScope;
}
}
function mapDeclaration(declaration) {
return {
declaration,
exported: true,
domain: getDeclarationDomain(declaration),
};
}
class NamespaceScope extends NonRootScope {
constructor(_ambient, _hasExport, parent) {
super(parent, 1 /* Function */);
this._ambient = _ambient;
this._hasExport = _hasExport;
this._innerScope = new NonRootScope(this, 1 /* Function */);
this._exports = undefined;
}
finish(cb) {
return super.end(cb);
}
end(cb) {
this._innerScope.end((variable, key, scope) => {
if (scope !== this._innerScope ||
!variable.exported && (!this._ambient || this._exports !== undefined && !this._exports.has(key.text)))
return cb(variable, key, scope);
const namespaceVar = this._variables.get(key.text);
if (namespaceVar === undefined) {
this._variables.set(key.text, {
declarations: variable.declarations.map(mapDeclaration),
domain: variable.domain,
uses: [...variable.uses],
});
}
else {
outer: for (const declaration of variable.declarations) {
for (const existing of namespaceVar.declarations)
if (existing.declaration === declaration)
continue outer;
namespaceVar.declarations.push(mapDeclaration(declaration));
}
namespaceVar.domain |= variable.domain;
for (const use of variable.uses) {
if (namespaceVar.uses.includes(use))
continue;
namespaceVar.uses.push(use);
}
}
});
this._applyUses();
this._innerScope = new NonRootScope(this, 1 /* Function */);
}
createOrReuseNamespaceScope(name, exported, ambient, hasExportStatement) {
if (!exported && (!this._ambient || this._hasExport))
return this._innerScope.createOrReuseNamespaceScope(name, exported, ambient || this._ambient, hasExportStatement);
return super.createOrReuseNamespaceScope(name, exported, ambient || this._ambient, hasExportStatement);
}
createOrReuseEnumScope(name, exported) {
if (!exported && (!this._ambient || this._hasExport))
return this._innerScope.createOrReuseEnumScope(name, exported);
return super.createOrReuseEnumScope(name, exported);
}
addUse(use, source) {
if (source !== this._innerScope)
return this._innerScope.addUse(use);
this._uses.push(use);
}
refresh(ambient, hasExport) {
this._ambient = ambient;
this._hasExport = hasExport;
}
markExported(name, _as) {
if (this._exports === undefined)
this._exports = new Set();
this._exports.add(name.text);
}
getDestinationScope() {
return this._innerScope;
}
}
function getEntityNameParent(name) {
let parent = name.parent;
while (parent.kind === ts.SyntaxKind.QualifiedName)
parent = parent.parent;
return parent;
}
// TODO class decorators resolve outside of class, element and parameter decorator resolve inside/at the class
// TODO computed property name resolves inside/at the cass
// TODO this and super in all of them are resolved outside of the class
class UsageWalker {
constructor() {
this._result = new Map();
}
getUsage(sourceFile) {
const variableCallback = (variable, key) => {
this._result.set(key, variable);
};
const isModule = ts.isExternalModule(sourceFile);
this._scope = new RootScope(sourceFile.isDeclarationFile && isModule && !containsExportStatement(sourceFile), !isModule);
const cb = (node) => {
if (util_1.isBlockScopeBoundary(node))
return continueWithScope(node, new BlockScope(this._scope.getFunctionScope(), this._scope), handleBlockScope);
switch (node.kind) {
case ts.SyntaxKind.ClassExpression:
return continueWithScope(node, node.name !== undefined
? new ClassExpressionScope(node.name, this._scope)
: new NonRootScope(this._scope, 1 /* Function */));
case ts.SyntaxKind.ClassDeclaration:
this._handleDeclaration(node, true, 4 /* Value */ | 2 /* Type */);
return continueWithScope(node, new NonRootScope(this._scope, 1 /* Function */));
case ts.SyntaxKind.InterfaceDeclaration:
case ts.SyntaxKind.TypeAliasDeclaration:
this._handleDeclaration(node, true, 2 /* Type */);
return continueWithScope(node, new NonRootScope(this._scope, 4 /* Type */));
case ts.SyntaxKind.EnumDeclaration:
this._handleDeclaration(node, true, 7 /* Any */);
return continueWithScope(node, this._scope.createOrReuseEnumScope(node.name.text, util_1.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword)));
case ts.SyntaxKind.ModuleDeclaration:
return this._handleModule(node, continueWithScope);
case ts.SyntaxKind.MappedType:
return continueWithScope(node, new NonRootScope(this._scope, 4 /* Type */));
case ts.SyntaxKind.FunctionExpression:
case ts.SyntaxKind.ArrowFunction:
case ts.SyntaxKind.Constructor:
case ts.SyntaxKind.MethodDeclaration:
case ts.SyntaxKind.FunctionDeclaration:
case ts.SyntaxKind.GetAccessor:
case ts.SyntaxKind.SetAccessor:
case ts.SyntaxKind.MethodSignature:
case ts.SyntaxKind.CallSignature:
case ts.SyntaxKind.ConstructSignature:
case ts.SyntaxKind.ConstructorType:
case ts.SyntaxKind.FunctionType:
return this._handleFunctionLikeDeclaration(node, cb, variableCallback);
case ts.SyntaxKind.ConditionalType:
return this._handleConditionalType(node, cb, variableCallback);
// End of Scope specific handling
case ts.SyntaxKind.VariableDeclarationList:
this._handleVariableDeclaration(node);
break;
case ts.SyntaxKind.Parameter:
if (node.parent.kind !== ts.SyntaxKind.IndexSignature &&
(node.name.kind !== ts.SyntaxKind.Identifier ||
node.name.originalKeywordKind !== ts.SyntaxKind.ThisKeyword))
this._handleBindingName(node.name, false, false);
break;
case ts.SyntaxKind.EnumMember:
this._scope.addVariable(util_1.getPropertyName(node.name), node.name, 1 /* Function */, true, 4 /* Value */);
break;
case ts.SyntaxKind.ImportClause:
case ts.SyntaxKind.ImportSpecifier:
case ts.SyntaxKind.NamespaceImport:
case ts.SyntaxKind.ImportEqualsDeclaration:
this._handleDeclaration(node, false, 7 /* Any */ | 8 /* Import */);
break;
case ts.SyntaxKind.TypeParameter:
this._scope.addVariable(node.name.text, node.name, node.parent.kind === ts.SyntaxKind.InferType ? 8 /* InferType */ : 7 /* Type */, false, 2 /* Type */);
break;
case ts.SyntaxKind.ExportSpecifier:
if (node.propertyName !== undefined)
return this._scope.markExported(node.propertyName, node.name);
return this._scope.markExported(node.name);
case ts.SyntaxKind.ExportAssignment:
if (node.expression.kind === ts.SyntaxKind.Identifier)
return this._scope.markExported(node.expression);
break;
case ts.SyntaxKind.Identifier:
const domain = getUsageDomain(node);
if (domain !== undefined)
this._scope.addUse({ domain, location: node });
return;
}
return ts.forEachChild(node, cb);
};
const continueWithScope = (node, scope, next = forEachChild) => {
const savedScope = this._scope;
this._scope = scope;
next(node);
this._scope.end(variableCallback);
this._scope = savedScope;
};
const handleBlockScope = (node) => {
if (node.kind === ts.SyntaxKind.CatchClause && node.variableDeclaration !== undefined)
this._handleBindingName(node.variableDeclaration.name, true, false);
return ts.forEachChild(node, cb);
};
ts.forEachChild(sourceFile, cb);
this._scope.end(variableCallback);
return this._result;
function forEachChild(node) {
return ts.forEachChild(node, cb);
}
}
_handleConditionalType(node, cb, varCb) {
const savedScope = this._scope;
const scope = this._scope = new ConditionalTypeScope(savedScope);
cb(node.checkType);
scope.updateState(1 /* Extends */);
cb(node.extendsType);
scope.updateState(2 /* TrueType */);
cb(node.trueType);
scope.updateState(3 /* FalseType */);
cb(node.falseType);
scope.end(varCb);
this._scope = savedScope;
}
_handleFunctionLikeDeclaration(node, cb, varCb) {
if (node.decorators !== undefined)
node.decorators.forEach(cb);
const savedScope = this._scope;
if (node.kind === ts.SyntaxKind.FunctionDeclaration)
this._handleDeclaration(node, false, 4 /* Value */);
const scope = this._scope = node.kind === ts.SyntaxKind.FunctionExpression && node.name !== undefined
? new FunctionExpressionScope(node.name, savedScope)
: new FunctionScope(savedScope);
if (node.name !== undefined)
cb(node.name);
if (node.typeParameters !== undefined)
node.typeParameters.forEach(cb);
node.parameters.forEach(cb);
if (node.type !== undefined)
cb(node.type);
if (node.body !== undefined) {
scope.beginBody();
cb(node.body);
}
scope.end(varCb);
this._scope = savedScope;
}
_handleModule(node, next) {
if (node.flags & ts.NodeFlags.GlobalAugmentation)
return next(node, this._scope.createOrReuseNamespaceScope('-global', false, true, false));
if (node.name.kind === ts.SyntaxKind.Identifier) {
const exported = isNamespaceExported(node);
this._scope.addVariable(node.name.text, node.name, 1 /* Function */, exported, 1 /* Namespace */ | 4 /* Value */);
const ambient = util_1.hasModifier(node.modifiers, ts.SyntaxKind.DeclareKeyword);
return next(node, this._scope.createOrReuseNamespaceScope(node.name.text, exported, ambient, ambient && namespaceHasExportStatement(node)));
}
return next(node, this._scope.createOrReuseNamespaceScope(`"${node.name.text}"`, false, true, namespaceHasExportStatement(node)));
}
_handleDeclaration(node, blockScoped, domain) {
if (node.name !== undefined)
this._scope.addVariable(node.name.text, node.name, blockScoped ? 3 /* Block */ : 1 /* Function */, util_1.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword), domain);
}
_handleBindingName(name, blockScoped, exported) {
if (name.kind === ts.SyntaxKind.Identifier)
return this._scope.addVariable(name.text, name, blockScoped ? 3 /* Block */ : 1 /* Function */, exported, 4 /* Value */);
util_1.forEachDestructuringIdentifier(name, (declaration) => {
this._scope.addVariable(declaration.name.text, declaration.name, blockScoped ? 3 /* Block */ : 1 /* Function */, exported, 4 /* Value */);
});
}
_handleVariableDeclaration(declarationList) {
const blockScoped = util_1.isBlockScopedVariableDeclarationList(declarationList);
const exported = declarationList.parent.kind === ts.SyntaxKind.VariableStatement &&
util_1.hasModifier(declarationList.parent.modifiers, ts.SyntaxKind.ExportKeyword);
for (const declaration of declarationList.declarations)
this._handleBindingName(declaration.name, blockScoped, exported);
}
}
function isNamespaceExported(node) {
return node.parent.kind === ts.SyntaxKind.ModuleDeclaration || util_1.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword);
}
function namespaceHasExportStatement(ns) {
if (ns.body === undefined || ns.body.kind !== ts.SyntaxKind.ModuleBlock)
return false;
return containsExportStatement(ns.body);
}
function containsExportStatement(block) {
for (const statement of block.statements)
if (statement.kind === ts.SyntaxKind.ExportDeclaration || statement.kind === ts.SyntaxKind.ExportAssignment)
return true;
return false;
}
//# sourceMappingURL=usage.js.map

1
node_modules/tsutils/util/usage.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

265
node_modules/tsutils/util/util.d.ts generated vendored Normal file
View File

@@ -0,0 +1,265 @@
import * as ts from 'typescript';
import { NodeWrap } from './convert-ast';
export declare function getChildOfKind<T extends ts.SyntaxKind>(node: ts.Node, kind: T, sourceFile?: ts.SourceFile): ts.Token<T> | undefined;
export declare function isTokenKind(kind: ts.SyntaxKind): boolean;
export declare function isNodeKind(kind: ts.SyntaxKind): boolean;
export declare function isAssignmentKind(kind: ts.SyntaxKind): boolean;
export declare function isTypeNodeKind(kind: ts.SyntaxKind): boolean;
export declare function isJsDocKind(kind: ts.SyntaxKind): boolean;
export declare function isKeywordKind(kind: ts.SyntaxKind): boolean;
export declare function isThisParameter(parameter: ts.ParameterDeclaration): boolean;
export declare function getModifier(node: ts.Node, kind: ts.Modifier['kind']): ts.Modifier | undefined;
export declare function hasModifier(modifiers: ts.ModifiersArray | undefined, ...kinds: Array<ts.Modifier['kind']>): boolean;
export declare function isParameterProperty(node: ts.ParameterDeclaration): boolean;
export declare function hasAccessModifier(node: ts.ClassElement | ts.ParameterDeclaration): boolean;
export declare const isNodeFlagSet: (node: ts.Node, flag: ts.NodeFlags) => boolean;
export declare const isTypeFlagSet: (type: ts.Type, flag: ts.TypeFlags) => boolean;
export declare const isSymbolFlagSet: (symbol: ts.Symbol, flag: ts.SymbolFlags) => boolean;
export declare function isObjectFlagSet(objectType: ts.ObjectType, flag: ts.ObjectFlags): boolean;
export declare function isModifierFlagSet(node: ts.Node, flag: ts.ModifierFlags): boolean;
export declare function getPreviousStatement(statement: ts.Statement): ts.Statement | undefined;
export declare function getNextStatement(statement: ts.Statement): ts.Statement | undefined;
/** Returns the token before the start of `node` or `undefined` if there is none. */
export declare function getPreviousToken(node: ts.Node, sourceFile?: ts.SourceFile): ts.Node | undefined;
/** Returns the next token that begins after the end of `node`. Returns `undefined` for SourceFile and EndOfFileToken */
export declare function getNextToken(node: ts.Node, sourceFile?: ts.SourceFile): ts.Node | undefined;
/** Returns the token at or following the specified position or undefined if none is found inside `parent`. */
export declare function getTokenAtPosition(parent: ts.Node, pos: number, sourceFile?: ts.SourceFile, allowJsDoc?: boolean): ts.Node | undefined;
/**
* Return the comment at the specified position.
* You can pass an optional `parent` to avoid some work finding the corresponding token starting at `sourceFile`.
* If the `parent` parameter is passed, `pos` must be between `parent.pos` and `parent.end`.
*/
export declare function getCommentAtPosition(sourceFile: ts.SourceFile, pos: number, parent?: ts.Node): ts.CommentRange | undefined;
/**
* Returns whether the specified position is inside a comment.
* You can pass an optional `parent` to avoid some work finding the corresponding token starting at `sourceFile`.
* If the `parent` parameter is passed, `pos` must be between `parent.pos` and `parent.end`.
*/
export declare function isPositionInComment(sourceFile: ts.SourceFile, pos: number, parent?: ts.Node): boolean;
export declare function commentText(sourceText: string, comment: ts.CommentRange): string;
/** Returns the deepest AST Node at `pos`. Returns undefined if `pos` is outside of the range of `node` */
export declare function getAstNodeAtPosition(node: ts.Node, pos: number): ts.Node | undefined;
/**
* Returns the NodeWrap of deepest AST node that contains `pos` between its `pos` and `end`.
* Only returns undefined if pos is outside of `wrap`
*/
export declare function getWrappedNodeAtPosition(wrap: NodeWrap, pos: number): NodeWrap | undefined;
export declare function getPropertyName(propertyName: ts.PropertyName): string | undefined;
export declare function forEachDestructuringIdentifier<T>(pattern: ts.BindingPattern, fn: (element: ts.BindingElement & {
name: ts.Identifier;
}) => T): T | undefined;
export declare function forEachDeclaredVariable<T>(declarationList: ts.VariableDeclarationList, cb: (element: (ts.VariableDeclaration | ts.BindingElement) & {
name: ts.Identifier;
}) => T): T | undefined;
export declare enum VariableDeclarationKind {
Var = 0,
Let = 1,
Const = 2
}
export declare function getVariableDeclarationKind(declarationList: ts.VariableDeclarationList): VariableDeclarationKind;
export declare function isBlockScopedVariableDeclarationList(declarationList: ts.VariableDeclarationList): boolean;
export declare function isBlockScopedVariableDeclaration(declaration: ts.VariableDeclaration): boolean;
export declare function isBlockScopedDeclarationStatement(statement: ts.Statement): statement is ts.DeclarationStatement;
export declare function isInSingleStatementContext(statement: ts.Statement): boolean;
export declare enum ScopeBoundary {
None = 0,
Function = 1,
Block = 2,
Type = 4,
ConditionalType = 8
}
export declare enum ScopeBoundarySelector {
Function = 1,
Block = 3,
Type = 7,
InferType = 8
}
export declare function isScopeBoundary(node: ts.Node): ScopeBoundary;
export declare function isTypeScopeBoundary(node: ts.Node): ScopeBoundary;
export declare function isFunctionScopeBoundary(node: ts.Node): ScopeBoundary;
export declare function isBlockScopeBoundary(node: ts.Node): ScopeBoundary;
/** Returns true for scope boundaries that have their own `this` reference instead of inheriting it from the containing scope */
export declare function hasOwnThisReference(node: ts.Node): boolean;
export declare function isFunctionWithBody(node: ts.Node): node is ts.FunctionLikeDeclaration & {
body: {};
};
/**
* Iterate over all tokens of `node`
*
* @param node The node whose tokens should be visited
* @param cb Is called for every token contained in `node`
*/
export declare function forEachToken(node: ts.Node, cb: (node: ts.Node) => void, sourceFile?: ts.SourceFile): void;
export declare type ForEachTokenCallback = (fullText: string, kind: ts.SyntaxKind, range: ts.TextRange, parent: ts.Node) => void;
/**
* Iterate over all tokens and trivia of `node`
*
* @description JsDoc comments are treated like regular comments
*
* @param node The node whose tokens should be visited
* @param cb Is called for every token contained in `node` and trivia before the token
*/
export declare function forEachTokenWithTrivia(node: ts.Node, cb: ForEachTokenCallback, sourceFile?: ts.SourceFile): void;
export declare type ForEachCommentCallback = (fullText: string, comment: ts.CommentRange) => void;
/** Iterate over all comments owned by `node` or its children */
export declare function forEachComment(node: ts.Node, cb: ForEachCommentCallback, sourceFile?: ts.SourceFile): void;
export interface LineRange extends ts.TextRange {
contentLength: number;
}
export declare function getLineRanges(sourceFile: ts.SourceFile): LineRange[];
/** Get the line break style used in sourceFile. This function only looks at the first line break. If there is none, \n is assumed. */
export declare function getLineBreakStyle(sourceFile: ts.SourceFile): "\n" | "\r\n";
/**
* Determines whether the given text parses as a standalone identifier.
* This is not a guarantee that it works in every context. The property name in PropertyAccessExpressions for example allows reserved words.
* Depending on the context it could be parsed as contextual keyword or TypeScript keyword.
*/
export declare function isValidIdentifier(text: string, languageVersion?: ts.ScriptTarget): boolean;
/**
* Determines whether the given text can be used to access a property with a PropertyAccessExpression while preserving the property's name.
*/
export declare function isValidPropertyAccess(text: string, languageVersion?: ts.ScriptTarget): boolean;
/**
* Determines whether the given text can be used as unquoted name of a property declaration while preserving the property's name.
*/
export declare function isValidPropertyName(text: string, languageVersion?: ts.ScriptTarget): boolean;
/**
* Determines whether the given text can be parsed as a numeric literal.
*/
export declare function isValidNumericLiteral(text: string, languageVersion?: ts.ScriptTarget): boolean;
/**
* Determines whether the given text can be used as JSX tag or attribute name while preserving the exact name.
*/
export declare function isValidJsxIdentifier(text: string, languageVersion?: ts.ScriptTarget): boolean;
export declare function isNumericPropertyName(name: string | ts.__String): boolean;
export declare function isSameLine(sourceFile: ts.SourceFile, pos1: number, pos2: number): boolean;
export declare enum SideEffectOptions {
None = 0,
TaggedTemplate = 1,
Constructor = 2,
JsxElement = 4
}
export declare function hasSideEffects(node: ts.Expression, options?: SideEffectOptions): boolean;
/** Returns the VariableDeclaration or ParameterDeclaration that contains the BindingElement */
export declare function getDeclarationOfBindingElement(node: ts.BindingElement): ts.VariableDeclaration | ts.ParameterDeclaration;
export declare function isExpressionValueUsed(node: ts.Expression): boolean;
export declare enum AccessKind {
None = 0,
Read = 1,
Write = 2,
Delete = 4,
ReadWrite = 3,
Modification = 6
}
export declare function getAccessKind(node: ts.Node): AccessKind;
export declare function isReassignmentTarget(node: ts.Expression): boolean;
export declare function canHaveJsDoc(node: ts.Node): node is ts.HasJSDoc;
/** Gets the JSDoc of a node. For performance reasons this function should only be called when `canHaveJsDoc` returns true. */
export declare function getJsDoc(node: ts.Node, sourceFile?: ts.SourceFile): ts.JSDoc[];
/**
* Parses the JsDoc of any node. This function is made for nodes that don't get their JsDoc parsed by the TypeScript parser.
*
* @param considerTrailingComments When set to `true` this function uses the trailing comments if the node starts on the same line
* as the previous node ends.
*/
export declare function parseJsDocOfNode(node: ts.Node, considerTrailingComments?: boolean, sourceFile?: ts.SourceFile): ts.JSDoc[];
export declare enum ImportKind {
ImportDeclaration = 1,
ImportEquals = 2,
ExportFrom = 4,
DynamicImport = 8,
Require = 16,
ImportType = 32,
All = 63,
AllImports = 59,
AllStaticImports = 3,
AllImportExpressions = 24,
AllRequireLike = 18
}
export declare function findImports(sourceFile: ts.SourceFile, kinds: ImportKind, ignoreFileName?: boolean): (ts.StringLiteral | ts.NoSubstitutionTemplateLiteral)[];
export declare type ImportLike = ts.ImportDeclaration | ts.ImportEqualsDeclaration & {
moduleReference: ts.ExternalModuleReference;
} | ts.ExportDeclaration & {
moduleSpecifier: {};
} | ts.CallExpression & {
expression: ts.Token<ts.SyntaxKind.ImportKeyword> | ts.Identifier & {
text: 'require';
};
arguments: [ts.Expression, ...ts.Expression[]];
} | ts.ImportTypeNode;
export declare function findImportLikeNodes(sourceFile: ts.SourceFile, kinds: ImportKind, ignoreFileName?: boolean): ImportLike[];
/**
* Ambient context means the statement itself has the `declare` keyword
* or is inside a `declare namespace`, `delcare module` or `declare global`.
*/
export declare function isStatementInAmbientContext(node: ts.Statement): boolean;
/** Includes `declare namespace`, `declare module` and `declare global` and namespace nested in one of the aforementioned. */
export declare function isAmbientModuleBlock(node: ts.Node): node is ts.ModuleBlock;
export declare function getIIFE(func: ts.FunctionExpression | ts.ArrowFunction): ts.CallExpression | undefined;
export declare type StrictCompilerOption = 'noImplicitAny' | 'noImplicitThis' | 'strictNullChecks' | 'strictFunctionTypes' | 'strictPropertyInitialization' | 'alwaysStrict' | 'strictBindCallApply';
export declare function isStrictCompilerOptionEnabled(options: ts.CompilerOptions, option: StrictCompilerOption): boolean;
export declare type BooleanCompilerOptions = {
[K in keyof ts.CompilerOptions]: NonNullable<ts.CompilerOptions[K]> extends boolean ? K : never;
} extends {
[_ in keyof ts.CompilerOptions]: infer U;
} ? U : never;
/**
* Checks if a given compiler option is enabled.
* It handles dependencies of options, e.g. `declaration` is implicitly enabled by `composite` or `strictNullChecks` is enabled by `strict`.
* However, it does not check dependencies that are already checked and reported as errors, e.g. `checkJs` without `allowJs`.
* This function only handles boolean flags.
*/
export declare function isCompilerOptionEnabled(options: ts.CompilerOptions, option: BooleanCompilerOptions | 'stripInternal'): boolean;
/**
* Has nothing to do with `isAmbientModuleBlock`.
*
* @returns `true` if it's a global augmentation or has a string name.
*/
export declare function isAmbientModule(node: ts.ModuleDeclaration): boolean;
/**
* @deprecated use `getTsCheckDirective` instead since `// @ts-nocheck` is no longer restricted to JS files.
* @returns the last `// @ts-check` or `// @ts-nocheck` directive in the given file.
*/
export declare function getCheckJsDirective(source: string): ts.CheckJsDirective | undefined;
/** @returns the last `// @ts-check` or `// @ts-nocheck` directive in the given file. */
export declare function getTsCheckDirective(source: string): ts.CheckJsDirective | undefined;
export declare function isConstAssertion(node: ts.AssertionExpression): boolean;
/** Detects whether an expression is affected by an enclosing 'as const' assertion and therefore treated literally. */
export declare function isInConstContext(node: ts.Expression): boolean;
/** Returns true for `Object.defineProperty(o, 'prop', {value, writable: false})` and `Object.defineProperty(o, 'prop', {get: () => 1})`*/
export declare function isReadonlyAssignmentDeclaration(node: ts.CallExpression, checker: ts.TypeChecker): boolean;
/** Determines whether a call to `Object.defineProperty` is statically analyzable. */
export declare function isBindableObjectDefinePropertyCall(node: ts.CallExpression): boolean;
export interface WellKnownSymbolLiteral extends ts.PropertyAccessExpression {
expression: ts.Identifier & {
text: 'Symbol';
escapedText: 'symbol';
};
}
export declare function isWellKnownSymbolLiterally(node: ts.Expression): node is WellKnownSymbolLiteral;
export interface PropertyName {
displayName: string;
symbolName: ts.__String;
}
/** @deprecated typescript 4.3 removed the concept of literal well known symbols. Use `getPropertyNameFromType` instead. */
export declare function getPropertyNameOfWellKnownSymbol(node: WellKnownSymbolLiteral): PropertyName;
export interface LateBoundPropertyNames {
/** Whether all constituents are literal names. */
known: boolean;
names: PropertyName[];
}
export declare function getLateBoundPropertyNames(node: ts.Expression, checker: ts.TypeChecker): LateBoundPropertyNames;
export declare function getLateBoundPropertyNamesOfPropertyName(node: ts.PropertyName, checker: ts.TypeChecker): LateBoundPropertyNames;
/** Most declarations demand there to be only one statically known name, e.g. class members with computed name. */
export declare function getSingleLateBoundPropertyNameOfPropertyName(node: ts.PropertyName, checker: ts.TypeChecker): PropertyName | undefined;
export declare function unwrapParentheses(node: ts.Expression): ts.Expression;
export declare function formatPseudoBigInt(v: ts.PseudoBigInt): `${string}n` | `-${string}n`;
/**
* Determines whether the given `SwitchStatement`'s `case` clauses cover every possible value of the switched expression.
* The logic is the same as TypeScript's control flow analysis.
* This does **not** check whether all `case` clauses do a certain action like assign a variable or return a value.
* This function ignores the `default` clause if present.
*/
export declare function hasExhaustiveCaseClauses(node: ts.SwitchStatement, checker: ts.TypeChecker): boolean;
export declare function getBaseOfClassLikeExpression(node: ts.ClassLikeDeclaration): ts.ExpressionWithTypeArguments | undefined;

1686
node_modules/tsutils/util/util.js generated vendored Normal file
View File

@@ -0,0 +1,1686 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
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;
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;
const ts = require("typescript");
const node_1 = require("../typeguard/node");
const _3_2_1 = require("../typeguard/3.2");
const type_1 = require("./type");
function getChildOfKind(node, kind, sourceFile) {
for (const child of node.getChildren(sourceFile))
if (child.kind === kind)
return child;
}
exports.getChildOfKind = getChildOfKind;
function isTokenKind(kind) {
return kind >= ts.SyntaxKind.FirstToken && kind <= ts.SyntaxKind.LastToken;
}
exports.isTokenKind = isTokenKind;
function isNodeKind(kind) {
return kind >= ts.SyntaxKind.FirstNode;
}
exports.isNodeKind = isNodeKind;
function isAssignmentKind(kind) {
return kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment;
}
exports.isAssignmentKind = isAssignmentKind;
function isTypeNodeKind(kind) {
return kind >= ts.SyntaxKind.FirstTypeNode && kind <= ts.SyntaxKind.LastTypeNode;
}
exports.isTypeNodeKind = isTypeNodeKind;
function isJsDocKind(kind) {
return kind >= ts.SyntaxKind.FirstJSDocNode && kind <= ts.SyntaxKind.LastJSDocNode;
}
exports.isJsDocKind = isJsDocKind;
function isKeywordKind(kind) {
return kind >= ts.SyntaxKind.FirstKeyword && kind <= ts.SyntaxKind.LastKeyword;
}
exports.isKeywordKind = isKeywordKind;
function isThisParameter(parameter) {
return parameter.name.kind === ts.SyntaxKind.Identifier && parameter.name.originalKeywordKind === ts.SyntaxKind.ThisKeyword;
}
exports.isThisParameter = isThisParameter;
function getModifier(node, kind) {
if (node.modifiers !== undefined)
for (const modifier of node.modifiers)
if (modifier.kind === kind)
return modifier;
}
exports.getModifier = getModifier;
function hasModifier(modifiers, ...kinds) {
if (modifiers === undefined)
return false;
for (const modifier of modifiers)
if (kinds.includes(modifier.kind))
return true;
return false;
}
exports.hasModifier = hasModifier;
function isParameterProperty(node) {
return hasModifier(node.modifiers, ts.SyntaxKind.PublicKeyword, ts.SyntaxKind.ProtectedKeyword, ts.SyntaxKind.PrivateKeyword, ts.SyntaxKind.ReadonlyKeyword);
}
exports.isParameterProperty = isParameterProperty;
function hasAccessModifier(node) {
return isModifierFlagSet(node, ts.ModifierFlags.AccessibilityModifier);
}
exports.hasAccessModifier = hasAccessModifier;
function isFlagSet(obj, flag) {
return (obj.flags & flag) !== 0;
}
exports.isNodeFlagSet = isFlagSet;
exports.isTypeFlagSet = isFlagSet;
exports.isSymbolFlagSet = isFlagSet;
function isObjectFlagSet(objectType, flag) {
return (objectType.objectFlags & flag) !== 0;
}
exports.isObjectFlagSet = isObjectFlagSet;
function isModifierFlagSet(node, flag) {
return (ts.getCombinedModifierFlags(node) & flag) !== 0;
}
exports.isModifierFlagSet = isModifierFlagSet;
function getPreviousStatement(statement) {
const parent = statement.parent;
if (node_1.isBlockLike(parent)) {
const index = parent.statements.indexOf(statement);
if (index > 0)
return parent.statements[index - 1];
}
}
exports.getPreviousStatement = getPreviousStatement;
function getNextStatement(statement) {
const parent = statement.parent;
if (node_1.isBlockLike(parent)) {
const index = parent.statements.indexOf(statement);
if (index < parent.statements.length)
return parent.statements[index + 1];
}
}
exports.getNextStatement = getNextStatement;
/** Returns the token before the start of `node` or `undefined` if there is none. */
function getPreviousToken(node, sourceFile) {
const { pos } = node;
if (pos === 0)
return;
do
node = node.parent;
while (node.pos === pos);
return getTokenAtPositionWorker(node, pos - 1, sourceFile !== null && sourceFile !== void 0 ? sourceFile : node.getSourceFile(), false);
}
exports.getPreviousToken = getPreviousToken;
/** Returns the next token that begins after the end of `node`. Returns `undefined` for SourceFile and EndOfFileToken */
function getNextToken(node, sourceFile) {
if (node.kind === ts.SyntaxKind.SourceFile || node.kind === ts.SyntaxKind.EndOfFileToken)
return;
const end = node.end;
node = node.parent;
while (node.end === end) {
if (node.parent === undefined)
return node.endOfFileToken;
node = node.parent;
}
return getTokenAtPositionWorker(node, end, sourceFile !== null && sourceFile !== void 0 ? sourceFile : node.getSourceFile(), false);
}
exports.getNextToken = getNextToken;
/** Returns the token at or following the specified position or undefined if none is found inside `parent`. */
function getTokenAtPosition(parent, pos, sourceFile, allowJsDoc) {
if (pos < parent.pos || pos >= parent.end)
return;
if (isTokenKind(parent.kind))
return parent;
return getTokenAtPositionWorker(parent, pos, sourceFile !== null && sourceFile !== void 0 ? sourceFile : parent.getSourceFile(), allowJsDoc === true);
}
exports.getTokenAtPosition = getTokenAtPosition;
function getTokenAtPositionWorker(node, pos, sourceFile, allowJsDoc) {
if (!allowJsDoc) {
// if we are not interested in JSDoc, we can skip to the deepest AST node at the given position
node = getAstNodeAtPosition(node, pos);
if (isTokenKind(node.kind))
return node;
}
outer: while (true) {
for (const child of node.getChildren(sourceFile)) {
if (child.end > pos && (allowJsDoc || child.kind !== ts.SyntaxKind.JSDocComment)) {
if (isTokenKind(child.kind))
return child;
// next token is nested in another node
node = child;
continue outer;
}
}
return;
}
}
/**
* Return the comment at the specified position.
* You can pass an optional `parent` to avoid some work finding the corresponding token starting at `sourceFile`.
* If the `parent` parameter is passed, `pos` must be between `parent.pos` and `parent.end`.
*/
function getCommentAtPosition(sourceFile, pos, parent = sourceFile) {
const token = getTokenAtPosition(parent, pos, sourceFile);
if (token === undefined || token.kind === ts.SyntaxKind.JsxText || pos >= token.end - (ts.tokenToString(token.kind) || '').length)
return;
const startPos = token.pos === 0
? (ts.getShebang(sourceFile.text) || '').length
: token.pos;
return startPos !== 0 && ts.forEachTrailingCommentRange(sourceFile.text, startPos, commentAtPositionCallback, pos) ||
ts.forEachLeadingCommentRange(sourceFile.text, startPos, commentAtPositionCallback, pos);
}
exports.getCommentAtPosition = getCommentAtPosition;
function commentAtPositionCallback(pos, end, kind, _nl, at) {
return at >= pos && at < end ? { pos, end, kind } : undefined;
}
/**
* Returns whether the specified position is inside a comment.
* You can pass an optional `parent` to avoid some work finding the corresponding token starting at `sourceFile`.
* If the `parent` parameter is passed, `pos` must be between `parent.pos` and `parent.end`.
*/
function isPositionInComment(sourceFile, pos, parent) {
return getCommentAtPosition(sourceFile, pos, parent) !== undefined;
}
exports.isPositionInComment = isPositionInComment;
function commentText(sourceText, comment) {
return sourceText.substring(comment.pos + 2, comment.kind === ts.SyntaxKind.SingleLineCommentTrivia ? comment.end : comment.end - 2);
}
exports.commentText = commentText;
/** Returns the deepest AST Node at `pos`. Returns undefined if `pos` is outside of the range of `node` */
function getAstNodeAtPosition(node, pos) {
if (node.pos > pos || node.end <= pos)
return;
while (isNodeKind(node.kind)) {
const nested = ts.forEachChild(node, (child) => child.pos <= pos && child.end > pos ? child : undefined);
if (nested === undefined)
break;
node = nested;
}
return node;
}
exports.getAstNodeAtPosition = getAstNodeAtPosition;
/**
* Returns the NodeWrap of deepest AST node that contains `pos` between its `pos` and `end`.
* Only returns undefined if pos is outside of `wrap`
*/
function getWrappedNodeAtPosition(wrap, pos) {
if (wrap.node.pos > pos || wrap.node.end <= pos)
return;
outer: while (true) {
for (const child of wrap.children) {
if (child.node.pos > pos)
return wrap;
if (child.node.end > pos) {
wrap = child;
continue outer;
}
}
return wrap;
}
}
exports.getWrappedNodeAtPosition = getWrappedNodeAtPosition;
function getPropertyName(propertyName) {
if (propertyName.kind === ts.SyntaxKind.ComputedPropertyName) {
const expression = unwrapParentheses(propertyName.expression);
if (node_1.isPrefixUnaryExpression(expression)) {
let negate = false;
switch (expression.operator) {
case ts.SyntaxKind.MinusToken:
negate = true;
// falls through
case ts.SyntaxKind.PlusToken:
return node_1.isNumericLiteral(expression.operand)
? `${negate ? '-' : ''}${expression.operand.text}`
: _3_2_1.isBigIntLiteral(expression.operand)
? `${negate ? '-' : ''}${expression.operand.text.slice(0, -1)}`
: undefined;
default:
return;
}
}
if (_3_2_1.isBigIntLiteral(expression))
// handle BigInt, even though TypeScript doesn't allow BigInt as computed property name
return expression.text.slice(0, -1);
if (node_1.isNumericOrStringLikeLiteral(expression))
return expression.text;
return;
}
return propertyName.kind === ts.SyntaxKind.PrivateIdentifier ? undefined : propertyName.text;
}
exports.getPropertyName = getPropertyName;
function forEachDestructuringIdentifier(pattern, fn) {
for (const element of pattern.elements) {
if (element.kind !== ts.SyntaxKind.BindingElement)
continue;
let result;
if (element.name.kind === ts.SyntaxKind.Identifier) {
result = fn(element);
}
else {
result = forEachDestructuringIdentifier(element.name, fn);
}
if (result)
return result;
}
}
exports.forEachDestructuringIdentifier = forEachDestructuringIdentifier;
function forEachDeclaredVariable(declarationList, cb) {
for (const declaration of declarationList.declarations) {
let result;
if (declaration.name.kind === ts.SyntaxKind.Identifier) {
result = cb(declaration);
}
else {
result = forEachDestructuringIdentifier(declaration.name, cb);
}
if (result)
return result;
}
}
exports.forEachDeclaredVariable = forEachDeclaredVariable;
var VariableDeclarationKind;
(function (VariableDeclarationKind) {
VariableDeclarationKind[VariableDeclarationKind["Var"] = 0] = "Var";
VariableDeclarationKind[VariableDeclarationKind["Let"] = 1] = "Let";
VariableDeclarationKind[VariableDeclarationKind["Const"] = 2] = "Const";
})(VariableDeclarationKind = exports.VariableDeclarationKind || (exports.VariableDeclarationKind = {}));
function getVariableDeclarationKind(declarationList) {
if (declarationList.flags & ts.NodeFlags.Let)
return 1 /* Let */;
if (declarationList.flags & ts.NodeFlags.Const)
return 2 /* Const */;
return 0 /* Var */;
}
exports.getVariableDeclarationKind = getVariableDeclarationKind;
function isBlockScopedVariableDeclarationList(declarationList) {
return (declarationList.flags & ts.NodeFlags.BlockScoped) !== 0;
}
exports.isBlockScopedVariableDeclarationList = isBlockScopedVariableDeclarationList;
function isBlockScopedVariableDeclaration(declaration) {
const parent = declaration.parent;
return parent.kind === ts.SyntaxKind.CatchClause ||
isBlockScopedVariableDeclarationList(parent);
}
exports.isBlockScopedVariableDeclaration = isBlockScopedVariableDeclaration;
function isBlockScopedDeclarationStatement(statement) {
switch (statement.kind) {
case ts.SyntaxKind.VariableStatement:
return isBlockScopedVariableDeclarationList(statement.declarationList);
case ts.SyntaxKind.ClassDeclaration:
case ts.SyntaxKind.EnumDeclaration:
case ts.SyntaxKind.InterfaceDeclaration:
case ts.SyntaxKind.TypeAliasDeclaration:
return true;
default:
return false;
}
}
exports.isBlockScopedDeclarationStatement = isBlockScopedDeclarationStatement;
function isInSingleStatementContext(statement) {
switch (statement.parent.kind) {
case ts.SyntaxKind.ForStatement:
case ts.SyntaxKind.ForInStatement:
case ts.SyntaxKind.ForOfStatement:
case ts.SyntaxKind.WhileStatement:
case ts.SyntaxKind.DoStatement:
case ts.SyntaxKind.IfStatement:
case ts.SyntaxKind.WithStatement:
case ts.SyntaxKind.LabeledStatement:
return true;
default:
return false;
}
}
exports.isInSingleStatementContext = isInSingleStatementContext;
var ScopeBoundary;
(function (ScopeBoundary) {
ScopeBoundary[ScopeBoundary["None"] = 0] = "None";
ScopeBoundary[ScopeBoundary["Function"] = 1] = "Function";
ScopeBoundary[ScopeBoundary["Block"] = 2] = "Block";
ScopeBoundary[ScopeBoundary["Type"] = 4] = "Type";
ScopeBoundary[ScopeBoundary["ConditionalType"] = 8] = "ConditionalType";
})(ScopeBoundary = exports.ScopeBoundary || (exports.ScopeBoundary = {}));
var ScopeBoundarySelector;
(function (ScopeBoundarySelector) {
ScopeBoundarySelector[ScopeBoundarySelector["Function"] = 1] = "Function";
ScopeBoundarySelector[ScopeBoundarySelector["Block"] = 3] = "Block";
ScopeBoundarySelector[ScopeBoundarySelector["Type"] = 7] = "Type";
ScopeBoundarySelector[ScopeBoundarySelector["InferType"] = 8] = "InferType";
})(ScopeBoundarySelector = exports.ScopeBoundarySelector || (exports.ScopeBoundarySelector = {}));
function isScopeBoundary(node) {
return isFunctionScopeBoundary(node) || isBlockScopeBoundary(node) || isTypeScopeBoundary(node);
}
exports.isScopeBoundary = isScopeBoundary;
function isTypeScopeBoundary(node) {
switch (node.kind) {
case ts.SyntaxKind.InterfaceDeclaration:
case ts.SyntaxKind.TypeAliasDeclaration:
case ts.SyntaxKind.MappedType:
return 4 /* Type */;
case ts.SyntaxKind.ConditionalType:
return 8 /* ConditionalType */;
default:
return 0 /* None */;
}
}
exports.isTypeScopeBoundary = isTypeScopeBoundary;
function isFunctionScopeBoundary(node) {
switch (node.kind) {
case ts.SyntaxKind.FunctionExpression:
case ts.SyntaxKind.ArrowFunction:
case ts.SyntaxKind.Constructor:
case ts.SyntaxKind.ModuleDeclaration:
case ts.SyntaxKind.ClassDeclaration:
case ts.SyntaxKind.ClassExpression:
case ts.SyntaxKind.EnumDeclaration:
case ts.SyntaxKind.MethodDeclaration:
case ts.SyntaxKind.FunctionDeclaration:
case ts.SyntaxKind.GetAccessor:
case ts.SyntaxKind.SetAccessor:
case ts.SyntaxKind.MethodSignature:
case ts.SyntaxKind.CallSignature:
case ts.SyntaxKind.ConstructSignature:
case ts.SyntaxKind.ConstructorType:
case ts.SyntaxKind.FunctionType:
return 1 /* Function */;
case ts.SyntaxKind.SourceFile:
// if SourceFile is no module, it contributes to the global scope and is therefore no scope boundary
return ts.isExternalModule(node) ? 1 /* Function */ : 0 /* None */;
default:
return 0 /* None */;
}
}
exports.isFunctionScopeBoundary = isFunctionScopeBoundary;
function isBlockScopeBoundary(node) {
switch (node.kind) {
case ts.SyntaxKind.Block:
const parent = node.parent;
return parent.kind !== ts.SyntaxKind.CatchClause &&
// blocks inside SourceFile are block scope boundaries
(parent.kind === ts.SyntaxKind.SourceFile ||
// blocks that are direct children of a function scope boundary are no scope boundary
// for example the FunctionBlock is part of the function scope of the containing function
!isFunctionScopeBoundary(parent))
? 2 /* Block */
: 0 /* None */;
case ts.SyntaxKind.ForStatement:
case ts.SyntaxKind.ForInStatement:
case ts.SyntaxKind.ForOfStatement:
case ts.SyntaxKind.CaseBlock:
case ts.SyntaxKind.CatchClause:
case ts.SyntaxKind.WithStatement:
return 2 /* Block */;
default:
return 0 /* None */;
}
}
exports.isBlockScopeBoundary = isBlockScopeBoundary;
/** Returns true for scope boundaries that have their own `this` reference instead of inheriting it from the containing scope */
function hasOwnThisReference(node) {
switch (node.kind) {
case ts.SyntaxKind.ClassDeclaration:
case ts.SyntaxKind.ClassExpression:
case ts.SyntaxKind.FunctionExpression:
return true;
case ts.SyntaxKind.FunctionDeclaration:
return node.body !== undefined;
case ts.SyntaxKind.MethodDeclaration:
case ts.SyntaxKind.GetAccessor:
case ts.SyntaxKind.SetAccessor:
return node.parent.kind === ts.SyntaxKind.ObjectLiteralExpression;
default:
return false;
}
}
exports.hasOwnThisReference = hasOwnThisReference;
function isFunctionWithBody(node) {
switch (node.kind) {
case ts.SyntaxKind.GetAccessor:
case ts.SyntaxKind.SetAccessor:
case ts.SyntaxKind.FunctionDeclaration:
case ts.SyntaxKind.MethodDeclaration:
case ts.SyntaxKind.Constructor:
return node.body !== undefined;
case ts.SyntaxKind.FunctionExpression:
case ts.SyntaxKind.ArrowFunction:
return true;
default:
return false;
}
}
exports.isFunctionWithBody = isFunctionWithBody;
/**
* Iterate over all tokens of `node`
*
* @param node The node whose tokens should be visited
* @param cb Is called for every token contained in `node`
*/
function forEachToken(node, cb, sourceFile = node.getSourceFile()) {
const queue = [];
while (true) {
if (isTokenKind(node.kind)) {
cb(node);
}
else if (node.kind !== ts.SyntaxKind.JSDocComment) {
const children = node.getChildren(sourceFile);
if (children.length === 1) {
node = children[0];
continue;
}
for (let i = children.length - 1; i >= 0; --i)
queue.push(children[i]); // add children in reverse order, when we pop the next element from the queue, it's the first child
}
if (queue.length === 0)
break;
node = queue.pop();
}
}
exports.forEachToken = forEachToken;
/**
* Iterate over all tokens and trivia of `node`
*
* @description JsDoc comments are treated like regular comments
*
* @param node The node whose tokens should be visited
* @param cb Is called for every token contained in `node` and trivia before the token
*/
function forEachTokenWithTrivia(node, cb, sourceFile = node.getSourceFile()) {
const fullText = sourceFile.text;
const scanner = ts.createScanner(sourceFile.languageVersion, false, sourceFile.languageVariant, fullText);
return forEachToken(node, (token) => {
const tokenStart = token.kind === ts.SyntaxKind.JsxText || token.pos === token.end ? token.pos : token.getStart(sourceFile);
if (tokenStart !== token.pos) {
// we only have to handle trivia before each token. whitespace at the end of the file is followed by EndOfFileToken
scanner.setTextPos(token.pos);
let kind = scanner.scan();
let pos = scanner.getTokenPos();
while (pos < tokenStart) {
const textPos = scanner.getTextPos();
cb(fullText, kind, { pos, end: textPos }, token.parent);
if (textPos === tokenStart)
break;
kind = scanner.scan();
pos = scanner.getTokenPos();
}
}
return cb(fullText, token.kind, { end: token.end, pos: tokenStart }, token.parent);
}, sourceFile);
}
exports.forEachTokenWithTrivia = forEachTokenWithTrivia;
/** Iterate over all comments owned by `node` or its children */
function forEachComment(node, cb, sourceFile = node.getSourceFile()) {
/* Visit all tokens and skip trivia.
Comment ranges between tokens are parsed without the need of a scanner.
forEachTokenWithWhitespace does intentionally not pay attention to the correct comment ownership of nodes as it always
scans all trivia before each token, which could include trailing comments of the previous token.
Comment onwership is done right in this function*/
const fullText = sourceFile.text;
const notJsx = sourceFile.languageVariant !== ts.LanguageVariant.JSX;
return forEachToken(node, (token) => {
if (token.pos === token.end)
return;
if (token.kind !== ts.SyntaxKind.JsxText)
ts.forEachLeadingCommentRange(fullText,
// skip shebang at position 0
token.pos === 0 ? (ts.getShebang(fullText) || '').length : token.pos, commentCallback);
if (notJsx || canHaveTrailingTrivia(token))
return ts.forEachTrailingCommentRange(fullText, token.end, commentCallback);
}, sourceFile);
function commentCallback(pos, end, kind) {
cb(fullText, { pos, end, kind });
}
}
exports.forEachComment = forEachComment;
/** Exclude trailing positions that would lead to scanning for trivia inside JsxText */
function canHaveTrailingTrivia(token) {
switch (token.kind) {
case ts.SyntaxKind.CloseBraceToken:
// after a JsxExpression inside a JsxElement's body can only be other JsxChild, but no trivia
return token.parent.kind !== ts.SyntaxKind.JsxExpression || !isJsxElementOrFragment(token.parent.parent);
case ts.SyntaxKind.GreaterThanToken:
switch (token.parent.kind) {
case ts.SyntaxKind.JsxOpeningElement:
// if end is not equal, this is part of the type arguments list. in all other cases it would be inside the element body
return token.end !== token.parent.end;
case ts.SyntaxKind.JsxOpeningFragment:
return false; // would be inside the fragment
case ts.SyntaxKind.JsxSelfClosingElement:
return token.end !== token.parent.end || // if end is not equal, this is part of the type arguments list
!isJsxElementOrFragment(token.parent.parent); // there's only trailing trivia if it's the end of the top element
case ts.SyntaxKind.JsxClosingElement:
case ts.SyntaxKind.JsxClosingFragment:
// there's only trailing trivia if it's the end of the top element
return !isJsxElementOrFragment(token.parent.parent.parent);
}
}
return true;
}
function isJsxElementOrFragment(node) {
return node.kind === ts.SyntaxKind.JsxElement || node.kind === ts.SyntaxKind.JsxFragment;
}
function getLineRanges(sourceFile) {
const lineStarts = sourceFile.getLineStarts();
const result = [];
const length = lineStarts.length;
const sourceText = sourceFile.text;
let pos = 0;
for (let i = 1; i < length; ++i) {
const end = lineStarts[i];
let lineEnd = end;
for (; lineEnd > pos; --lineEnd)
if (!ts.isLineBreak(sourceText.charCodeAt(lineEnd - 1)))
break;
result.push({
pos,
end,
contentLength: lineEnd - pos,
});
pos = end;
}
result.push({
pos,
end: sourceFile.end,
contentLength: sourceFile.end - pos,
});
return result;
}
exports.getLineRanges = getLineRanges;
/** Get the line break style used in sourceFile. This function only looks at the first line break. If there is none, \n is assumed. */
function getLineBreakStyle(sourceFile) {
const lineStarts = sourceFile.getLineStarts();
return lineStarts.length === 1 || lineStarts[1] < 2 || sourceFile.text[lineStarts[1] - 2] !== '\r'
? '\n'
: '\r\n';
}
exports.getLineBreakStyle = getLineBreakStyle;
let cachedScanner;
function scanToken(text, languageVersion) {
if (cachedScanner === undefined) {
// cache scanner
cachedScanner = ts.createScanner(languageVersion, false, undefined, text);
}
else {
cachedScanner.setScriptTarget(languageVersion);
cachedScanner.setText(text);
}
cachedScanner.scan();
return cachedScanner;
}
/**
* Determines whether the given text parses as a standalone identifier.
* This is not a guarantee that it works in every context. The property name in PropertyAccessExpressions for example allows reserved words.
* Depending on the context it could be parsed as contextual keyword or TypeScript keyword.
*/
function isValidIdentifier(text, languageVersion = ts.ScriptTarget.Latest) {
const scan = scanToken(text, languageVersion);
return scan.isIdentifier() && scan.getTextPos() === text.length && scan.getTokenPos() === 0;
}
exports.isValidIdentifier = isValidIdentifier;
function charSize(ch) {
return ch >= 0x10000 ? 2 : 1;
}
/**
* Determines whether the given text can be used to access a property with a PropertyAccessExpression while preserving the property's name.
*/
function isValidPropertyAccess(text, languageVersion = ts.ScriptTarget.Latest) {
if (text.length === 0)
return false;
let ch = text.codePointAt(0);
if (!ts.isIdentifierStart(ch, languageVersion))
return false;
for (let i = charSize(ch); i < text.length; i += charSize(ch)) {
ch = text.codePointAt(i);
if (!ts.isIdentifierPart(ch, languageVersion))
return false;
}
return true;
}
exports.isValidPropertyAccess = isValidPropertyAccess;
/**
* Determines whether the given text can be used as unquoted name of a property declaration while preserving the property's name.
*/
function isValidPropertyName(text, languageVersion = ts.ScriptTarget.Latest) {
if (isValidPropertyAccess(text, languageVersion))
return true;
const scan = scanToken(text, languageVersion);
return scan.getTextPos() === text.length &&
scan.getToken() === ts.SyntaxKind.NumericLiteral && scan.getTokenValue() === text; // ensure stringified number equals literal
}
exports.isValidPropertyName = isValidPropertyName;
/**
* Determines whether the given text can be parsed as a numeric literal.
*/
function isValidNumericLiteral(text, languageVersion = ts.ScriptTarget.Latest) {
const scan = scanToken(text, languageVersion);
return scan.getToken() === ts.SyntaxKind.NumericLiteral && scan.getTextPos() === text.length && scan.getTokenPos() === 0;
}
exports.isValidNumericLiteral = isValidNumericLiteral;
/**
* Determines whether the given text can be used as JSX tag or attribute name while preserving the exact name.
*/
function isValidJsxIdentifier(text, languageVersion = ts.ScriptTarget.Latest) {
if (text.length === 0)
return false;
let seenNamespaceSeparator = false;
let ch = text.codePointAt(0);
if (!ts.isIdentifierStart(ch, languageVersion))
return false;
for (let i = charSize(ch); i < text.length; i += charSize(ch)) {
ch = text.codePointAt(i);
if (!ts.isIdentifierPart(ch, languageVersion) && ch !== 45 /* minus */) {
if (!seenNamespaceSeparator && ch === 58 /* colon */ && i + charSize(ch) !== text.length) {
seenNamespaceSeparator = true;
}
else {
return false;
}
}
}
return true;
}
exports.isValidJsxIdentifier = isValidJsxIdentifier;
function isNumericPropertyName(name) {
return String(+name) === name;
}
exports.isNumericPropertyName = isNumericPropertyName;
function isSameLine(sourceFile, pos1, pos2) {
return ts.getLineAndCharacterOfPosition(sourceFile, pos1).line === ts.getLineAndCharacterOfPosition(sourceFile, pos2).line;
}
exports.isSameLine = isSameLine;
var SideEffectOptions;
(function (SideEffectOptions) {
SideEffectOptions[SideEffectOptions["None"] = 0] = "None";
SideEffectOptions[SideEffectOptions["TaggedTemplate"] = 1] = "TaggedTemplate";
SideEffectOptions[SideEffectOptions["Constructor"] = 2] = "Constructor";
SideEffectOptions[SideEffectOptions["JsxElement"] = 4] = "JsxElement";
})(SideEffectOptions = exports.SideEffectOptions || (exports.SideEffectOptions = {}));
function hasSideEffects(node, options) {
var _a, _b;
const queue = [];
while (true) {
switch (node.kind) {
case ts.SyntaxKind.CallExpression:
case ts.SyntaxKind.PostfixUnaryExpression:
case ts.SyntaxKind.AwaitExpression:
case ts.SyntaxKind.YieldExpression:
case ts.SyntaxKind.DeleteExpression:
return true;
case ts.SyntaxKind.TypeAssertionExpression:
case ts.SyntaxKind.AsExpression:
case ts.SyntaxKind.ParenthesizedExpression:
case ts.SyntaxKind.NonNullExpression:
case ts.SyntaxKind.VoidExpression:
case ts.SyntaxKind.TypeOfExpression:
case ts.SyntaxKind.PropertyAccessExpression:
case ts.SyntaxKind.SpreadElement:
case ts.SyntaxKind.PartiallyEmittedExpression:
node = node.expression;
continue;
case ts.SyntaxKind.BinaryExpression:
if (isAssignmentKind(node.operatorToken.kind))
return true;
queue.push(node.right);
node = node.left;
continue;
case ts.SyntaxKind.PrefixUnaryExpression:
switch (node.operator) {
case ts.SyntaxKind.PlusPlusToken:
case ts.SyntaxKind.MinusMinusToken:
return true;
default:
node = node.operand;
continue;
}
case ts.SyntaxKind.ElementAccessExpression:
if (node.argumentExpression !== undefined) // for compatibility with typescript@<2.9.0
queue.push(node.argumentExpression);
node = node.expression;
continue;
case ts.SyntaxKind.ConditionalExpression:
queue.push(node.whenTrue, node.whenFalse);
node = node.condition;
continue;
case ts.SyntaxKind.NewExpression:
if (options & 2 /* Constructor */)
return true;
if (node.arguments !== undefined)
queue.push(...node.arguments);
node = node.expression;
continue;
case ts.SyntaxKind.TaggedTemplateExpression:
if (options & 1 /* TaggedTemplate */)
return true;
queue.push(node.tag);
node = node.template;
if (node.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral)
break;
// falls through
case ts.SyntaxKind.TemplateExpression:
for (const child of node.templateSpans)
queue.push(child.expression);
break;
case ts.SyntaxKind.ClassExpression: {
if (node.decorators !== undefined)
return true;
for (const child of node.members) {
if (child.decorators !== undefined)
return true;
if (!hasModifier(child.modifiers, ts.SyntaxKind.DeclareKeyword)) {
if (((_a = child.name) === null || _a === void 0 ? void 0 : _a.kind) === ts.SyntaxKind.ComputedPropertyName)
queue.push(child.name.expression);
if (node_1.isMethodDeclaration(child)) {
for (const p of child.parameters)
if (p.decorators !== undefined)
return true;
}
else if (node_1.isPropertyDeclaration(child) &&
child.initializer !== undefined &&
hasModifier(child.modifiers, ts.SyntaxKind.StaticKeyword)) {
queue.push(child.initializer);
}
}
}
const base = getBaseOfClassLikeExpression(node);
if (base === undefined)
break;
node = base.expression;
continue;
}
case ts.SyntaxKind.ArrayLiteralExpression:
queue.push(...node.elements);
break;
case ts.SyntaxKind.ObjectLiteralExpression:
for (const child of node.properties) {
if (((_b = child.name) === null || _b === void 0 ? void 0 : _b.kind) === ts.SyntaxKind.ComputedPropertyName)
queue.push(child.name.expression);
switch (child.kind) {
case ts.SyntaxKind.PropertyAssignment:
queue.push(child.initializer);
break;
case ts.SyntaxKind.SpreadAssignment:
queue.push(child.expression);
}
}
break;
case ts.SyntaxKind.JsxExpression:
if (node.expression === undefined)
break;
node = node.expression;
continue;
case ts.SyntaxKind.JsxElement:
case ts.SyntaxKind.JsxFragment:
for (const child of node.children)
if (child.kind !== ts.SyntaxKind.JsxText)
queue.push(child);
if (node.kind === ts.SyntaxKind.JsxFragment)
break;
node = node.openingElement;
// falls through
case ts.SyntaxKind.JsxSelfClosingElement:
case ts.SyntaxKind.JsxOpeningElement:
if (options & 4 /* JsxElement */)
return true;
for (const child of node.attributes.properties) {
if (child.kind === ts.SyntaxKind.JsxSpreadAttribute) {
queue.push(child.expression);
}
else if (child.initializer !== undefined) {
queue.push(child.initializer);
}
}
break;
case ts.SyntaxKind.CommaListExpression:
queue.push(...node.elements);
}
if (queue.length === 0)
return false;
node = queue.pop();
}
}
exports.hasSideEffects = hasSideEffects;
/** Returns the VariableDeclaration or ParameterDeclaration that contains the BindingElement */
function getDeclarationOfBindingElement(node) {
let parent = node.parent.parent;
while (parent.kind === ts.SyntaxKind.BindingElement)
parent = parent.parent.parent;
return parent;
}
exports.getDeclarationOfBindingElement = getDeclarationOfBindingElement;
function isExpressionValueUsed(node) {
while (true) {
const parent = node.parent;
switch (parent.kind) {
case ts.SyntaxKind.CallExpression:
case ts.SyntaxKind.NewExpression:
case ts.SyntaxKind.ElementAccessExpression:
case ts.SyntaxKind.WhileStatement:
case ts.SyntaxKind.DoStatement:
case ts.SyntaxKind.WithStatement:
case ts.SyntaxKind.ThrowStatement:
case ts.SyntaxKind.ReturnStatement:
case ts.SyntaxKind.JsxExpression:
case ts.SyntaxKind.JsxSpreadAttribute:
case ts.SyntaxKind.JsxElement:
case ts.SyntaxKind.JsxFragment:
case ts.SyntaxKind.JsxSelfClosingElement:
case ts.SyntaxKind.ComputedPropertyName:
case ts.SyntaxKind.ArrowFunction:
case ts.SyntaxKind.ExportSpecifier:
case ts.SyntaxKind.ExportAssignment:
case ts.SyntaxKind.ImportDeclaration:
case ts.SyntaxKind.ExternalModuleReference:
case ts.SyntaxKind.Decorator:
case ts.SyntaxKind.TaggedTemplateExpression:
case ts.SyntaxKind.TemplateSpan:
case ts.SyntaxKind.ExpressionWithTypeArguments:
case ts.SyntaxKind.TypeOfExpression:
case ts.SyntaxKind.AwaitExpression:
case ts.SyntaxKind.YieldExpression:
case ts.SyntaxKind.LiteralType:
case ts.SyntaxKind.JsxAttributes:
case ts.SyntaxKind.JsxOpeningElement:
case ts.SyntaxKind.JsxClosingElement:
case ts.SyntaxKind.IfStatement:
case ts.SyntaxKind.CaseClause:
case ts.SyntaxKind.SwitchStatement:
return true;
case ts.SyntaxKind.PropertyAccessExpression:
return parent.expression === node;
case ts.SyntaxKind.QualifiedName:
return parent.left === node;
case ts.SyntaxKind.ShorthandPropertyAssignment:
return parent.objectAssignmentInitializer === node ||
!isInDestructuringAssignment(parent);
case ts.SyntaxKind.PropertyAssignment:
return parent.initializer === node && !isInDestructuringAssignment(parent);
case ts.SyntaxKind.SpreadAssignment:
case ts.SyntaxKind.SpreadElement:
case ts.SyntaxKind.ArrayLiteralExpression:
return !isInDestructuringAssignment(parent);
case ts.SyntaxKind.ParenthesizedExpression:
case ts.SyntaxKind.AsExpression:
case ts.SyntaxKind.TypeAssertionExpression:
case ts.SyntaxKind.PostfixUnaryExpression:
case ts.SyntaxKind.PrefixUnaryExpression:
case ts.SyntaxKind.NonNullExpression:
node = parent;
continue;
case ts.SyntaxKind.ForStatement:
return parent.condition === node;
case ts.SyntaxKind.ForInStatement:
case ts.SyntaxKind.ForOfStatement:
return parent.expression === node;
case ts.SyntaxKind.ConditionalExpression:
if (parent.condition === node)
return true;
node = parent;
break;
case ts.SyntaxKind.PropertyDeclaration:
case ts.SyntaxKind.BindingElement:
case ts.SyntaxKind.VariableDeclaration:
case ts.SyntaxKind.Parameter:
case ts.SyntaxKind.EnumMember:
return parent.initializer === node;
case ts.SyntaxKind.ImportEqualsDeclaration:
return parent.moduleReference === node;
case ts.SyntaxKind.CommaListExpression:
if (parent.elements[parent.elements.length - 1] !== node)
return false;
node = parent;
break;
case ts.SyntaxKind.BinaryExpression:
if (parent.right === node) {
if (parent.operatorToken.kind === ts.SyntaxKind.CommaToken) {
node = parent;
break;
}
return true;
}
switch (parent.operatorToken.kind) {
case ts.SyntaxKind.CommaToken:
case ts.SyntaxKind.EqualsToken:
return false;
case ts.SyntaxKind.EqualsEqualsEqualsToken:
case ts.SyntaxKind.EqualsEqualsToken:
case ts.SyntaxKind.ExclamationEqualsEqualsToken:
case ts.SyntaxKind.ExclamationEqualsToken:
case ts.SyntaxKind.InstanceOfKeyword:
case ts.SyntaxKind.PlusToken:
case ts.SyntaxKind.MinusToken:
case ts.SyntaxKind.AsteriskToken:
case ts.SyntaxKind.SlashToken:
case ts.SyntaxKind.PercentToken:
case ts.SyntaxKind.AsteriskAsteriskToken:
case ts.SyntaxKind.GreaterThanToken:
case ts.SyntaxKind.GreaterThanGreaterThanToken:
case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
case ts.SyntaxKind.GreaterThanEqualsToken:
case ts.SyntaxKind.LessThanToken:
case ts.SyntaxKind.LessThanLessThanToken:
case ts.SyntaxKind.LessThanEqualsToken:
case ts.SyntaxKind.AmpersandToken:
case ts.SyntaxKind.BarToken:
case ts.SyntaxKind.CaretToken:
case ts.SyntaxKind.BarBarToken:
case ts.SyntaxKind.AmpersandAmpersandToken:
case ts.SyntaxKind.QuestionQuestionToken:
case ts.SyntaxKind.InKeyword:
case ts.SyntaxKind.QuestionQuestionEqualsToken:
case ts.SyntaxKind.AmpersandAmpersandEqualsToken:
case ts.SyntaxKind.BarBarEqualsToken:
return true;
default:
node = parent;
}
break;
default:
return false;
}
}
}
exports.isExpressionValueUsed = isExpressionValueUsed;
function isInDestructuringAssignment(node) {
switch (node.kind) {
case ts.SyntaxKind.ShorthandPropertyAssignment:
if (node.objectAssignmentInitializer !== undefined)
return true;
// falls through
case ts.SyntaxKind.PropertyAssignment:
case ts.SyntaxKind.SpreadAssignment:
node = node.parent;
break;
case ts.SyntaxKind.SpreadElement:
if (node.parent.kind !== ts.SyntaxKind.ArrayLiteralExpression)
return false;
node = node.parent;
}
while (true) {
switch (node.parent.kind) {
case ts.SyntaxKind.BinaryExpression:
return node.parent.left === node &&
node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken;
case ts.SyntaxKind.ForOfStatement:
return node.parent.initializer === node;
case ts.SyntaxKind.ArrayLiteralExpression:
case ts.SyntaxKind.ObjectLiteralExpression:
node = node.parent;
break;
case ts.SyntaxKind.SpreadAssignment:
case ts.SyntaxKind.PropertyAssignment:
node = node.parent.parent;
break;
case ts.SyntaxKind.SpreadElement:
if (node.parent.parent.kind !== ts.SyntaxKind.ArrayLiteralExpression)
return false;
node = node.parent.parent;
break;
default:
return false;
}
}
}
var AccessKind;
(function (AccessKind) {
AccessKind[AccessKind["None"] = 0] = "None";
AccessKind[AccessKind["Read"] = 1] = "Read";
AccessKind[AccessKind["Write"] = 2] = "Write";
AccessKind[AccessKind["Delete"] = 4] = "Delete";
AccessKind[AccessKind["ReadWrite"] = 3] = "ReadWrite";
AccessKind[AccessKind["Modification"] = 6] = "Modification";
})(AccessKind = exports.AccessKind || (exports.AccessKind = {}));
function getAccessKind(node) {
const parent = node.parent;
switch (parent.kind) {
case ts.SyntaxKind.DeleteExpression:
return 4 /* Delete */;
case ts.SyntaxKind.PostfixUnaryExpression:
return 3 /* ReadWrite */;
case ts.SyntaxKind.PrefixUnaryExpression:
return parent.operator === ts.SyntaxKind.PlusPlusToken ||
parent.operator === ts.SyntaxKind.MinusMinusToken
? 3 /* ReadWrite */
: 1 /* Read */;
case ts.SyntaxKind.BinaryExpression:
return parent.right === node
? 1 /* Read */
: !isAssignmentKind(parent.operatorToken.kind)
? 1 /* Read */
: parent.operatorToken.kind === ts.SyntaxKind.EqualsToken
? 2 /* Write */
: 3 /* ReadWrite */;
case ts.SyntaxKind.ShorthandPropertyAssignment:
return parent.objectAssignmentInitializer === node
? 1 /* Read */
: isInDestructuringAssignment(parent)
? 2 /* Write */
: 1 /* Read */;
case ts.SyntaxKind.PropertyAssignment:
return parent.name === node
? 0 /* None */
: isInDestructuringAssignment(parent)
? 2 /* Write */
: 1 /* Read */;
case ts.SyntaxKind.ArrayLiteralExpression:
case ts.SyntaxKind.SpreadElement:
case ts.SyntaxKind.SpreadAssignment:
return isInDestructuringAssignment(parent)
? 2 /* Write */
: 1 /* Read */;
case ts.SyntaxKind.ParenthesizedExpression:
case ts.SyntaxKind.NonNullExpression:
case ts.SyntaxKind.TypeAssertionExpression:
case ts.SyntaxKind.AsExpression:
// (<number>foo! as {})++
return getAccessKind(parent);
case ts.SyntaxKind.ForOfStatement:
case ts.SyntaxKind.ForInStatement:
return parent.initializer === node
? 2 /* Write */
: 1 /* Read */;
case ts.SyntaxKind.ExpressionWithTypeArguments:
return parent.parent.token === ts.SyntaxKind.ExtendsKeyword &&
parent.parent.parent.kind !== ts.SyntaxKind.InterfaceDeclaration
? 1 /* Read */
: 0 /* None */;
case ts.SyntaxKind.ComputedPropertyName:
case ts.SyntaxKind.ExpressionStatement:
case ts.SyntaxKind.TypeOfExpression:
case ts.SyntaxKind.ElementAccessExpression:
case ts.SyntaxKind.ForStatement:
case ts.SyntaxKind.IfStatement:
case ts.SyntaxKind.DoStatement:
case ts.SyntaxKind.WhileStatement:
case ts.SyntaxKind.SwitchStatement:
case ts.SyntaxKind.WithStatement:
case ts.SyntaxKind.ThrowStatement:
case ts.SyntaxKind.CallExpression:
case ts.SyntaxKind.NewExpression:
case ts.SyntaxKind.TaggedTemplateExpression:
case ts.SyntaxKind.JsxExpression:
case ts.SyntaxKind.Decorator:
case ts.SyntaxKind.TemplateSpan:
case ts.SyntaxKind.JsxOpeningElement:
case ts.SyntaxKind.JsxSelfClosingElement:
case ts.SyntaxKind.JsxSpreadAttribute:
case ts.SyntaxKind.VoidExpression:
case ts.SyntaxKind.ReturnStatement:
case ts.SyntaxKind.AwaitExpression:
case ts.SyntaxKind.YieldExpression:
case ts.SyntaxKind.ConditionalExpression:
case ts.SyntaxKind.CaseClause:
case ts.SyntaxKind.JsxElement:
return 1 /* Read */;
case ts.SyntaxKind.ArrowFunction:
return parent.body === node
? 1 /* Read */
: 2 /* Write */;
case ts.SyntaxKind.PropertyDeclaration:
case ts.SyntaxKind.VariableDeclaration:
case ts.SyntaxKind.Parameter:
case ts.SyntaxKind.EnumMember:
case ts.SyntaxKind.BindingElement:
case ts.SyntaxKind.JsxAttribute:
return parent.initializer === node
? 1 /* Read */
: 0 /* None */;
case ts.SyntaxKind.PropertyAccessExpression:
return parent.expression === node
? 1 /* Read */
: 0 /* None */;
case ts.SyntaxKind.ExportAssignment:
return parent.isExportEquals
? 1 /* Read */
: 0 /* None */;
}
return 0 /* None */;
}
exports.getAccessKind = getAccessKind;
function isReassignmentTarget(node) {
return (getAccessKind(node) & 2 /* Write */) !== 0;
}
exports.isReassignmentTarget = isReassignmentTarget;
function canHaveJsDoc(node) {
const kind = node.kind;
switch (kind) {
case ts.SyntaxKind.Parameter:
case ts.SyntaxKind.CallSignature:
case ts.SyntaxKind.ConstructSignature:
case ts.SyntaxKind.MethodSignature:
case ts.SyntaxKind.PropertySignature:
case ts.SyntaxKind.ArrowFunction:
case ts.SyntaxKind.ParenthesizedExpression:
case ts.SyntaxKind.SpreadAssignment:
case ts.SyntaxKind.ShorthandPropertyAssignment:
case ts.SyntaxKind.PropertyAssignment:
case ts.SyntaxKind.FunctionExpression:
case ts.SyntaxKind.LabeledStatement:
case ts.SyntaxKind.ExpressionStatement:
case ts.SyntaxKind.VariableStatement:
case ts.SyntaxKind.FunctionDeclaration:
case ts.SyntaxKind.Constructor:
case ts.SyntaxKind.MethodDeclaration:
case ts.SyntaxKind.PropertyDeclaration:
case ts.SyntaxKind.GetAccessor:
case ts.SyntaxKind.SetAccessor:
case ts.SyntaxKind.ClassDeclaration:
case ts.SyntaxKind.ClassExpression:
case ts.SyntaxKind.InterfaceDeclaration:
case ts.SyntaxKind.TypeAliasDeclaration:
case ts.SyntaxKind.EnumMember:
case ts.SyntaxKind.EnumDeclaration:
case ts.SyntaxKind.ModuleDeclaration:
case ts.SyntaxKind.ImportEqualsDeclaration:
case ts.SyntaxKind.ImportDeclaration:
case ts.SyntaxKind.NamespaceExportDeclaration:
case ts.SyntaxKind.ExportAssignment:
case ts.SyntaxKind.IndexSignature:
case ts.SyntaxKind.FunctionType:
case ts.SyntaxKind.ConstructorType:
case ts.SyntaxKind.JSDocFunctionType:
case ts.SyntaxKind.ExportDeclaration:
case ts.SyntaxKind.NamedTupleMember:
case ts.SyntaxKind.EndOfFileToken:
return true;
default:
return false;
}
}
exports.canHaveJsDoc = canHaveJsDoc;
/** Gets the JSDoc of a node. For performance reasons this function should only be called when `canHaveJsDoc` returns true. */
function getJsDoc(node, sourceFile) {
const result = [];
for (const child of node.getChildren(sourceFile)) {
if (!node_1.isJsDoc(child))
break;
result.push(child);
}
return result;
}
exports.getJsDoc = getJsDoc;
/**
* Parses the JsDoc of any node. This function is made for nodes that don't get their JsDoc parsed by the TypeScript parser.
*
* @param considerTrailingComments When set to `true` this function uses the trailing comments if the node starts on the same line
* as the previous node ends.
*/
function parseJsDocOfNode(node, considerTrailingComments, sourceFile = node.getSourceFile()) {
if (canHaveJsDoc(node) && node.kind !== ts.SyntaxKind.EndOfFileToken) {
const result = getJsDoc(node, sourceFile);
if (result.length !== 0 || !considerTrailingComments)
return result;
}
return parseJsDocWorker(node, node.getStart(sourceFile), sourceFile, considerTrailingComments);
}
exports.parseJsDocOfNode = parseJsDocOfNode;
function parseJsDocWorker(node, nodeStart, sourceFile, considerTrailingComments) {
const start = ts[considerTrailingComments && isSameLine(sourceFile, node.pos, nodeStart)
? 'forEachTrailingCommentRange'
: 'forEachLeadingCommentRange'](sourceFile.text, node.pos,
// return object to make `0` a truthy value
(pos, _end, kind) => kind === ts.SyntaxKind.MultiLineCommentTrivia && sourceFile.text[pos + 2] === '*' ? { pos } : undefined);
if (start === undefined)
return [];
const startPos = start.pos;
const text = sourceFile.text.slice(startPos, nodeStart);
const newSourceFile = ts.createSourceFile('jsdoc.ts', `${text}var a;`, sourceFile.languageVersion);
const result = getJsDoc(newSourceFile.statements[0], newSourceFile);
for (const doc of result)
updateNode(doc, node);
return result;
function updateNode(n, parent) {
n.pos += startPos;
n.end += startPos;
n.parent = parent;
return ts.forEachChild(n, (child) => updateNode(child, n), (children) => {
children.pos += startPos;
children.end += startPos;
for (const child of children)
updateNode(child, n);
});
}
}
var ImportKind;
(function (ImportKind) {
ImportKind[ImportKind["ImportDeclaration"] = 1] = "ImportDeclaration";
ImportKind[ImportKind["ImportEquals"] = 2] = "ImportEquals";
ImportKind[ImportKind["ExportFrom"] = 4] = "ExportFrom";
ImportKind[ImportKind["DynamicImport"] = 8] = "DynamicImport";
ImportKind[ImportKind["Require"] = 16] = "Require";
ImportKind[ImportKind["ImportType"] = 32] = "ImportType";
ImportKind[ImportKind["All"] = 63] = "All";
ImportKind[ImportKind["AllImports"] = 59] = "AllImports";
ImportKind[ImportKind["AllStaticImports"] = 3] = "AllStaticImports";
ImportKind[ImportKind["AllImportExpressions"] = 24] = "AllImportExpressions";
ImportKind[ImportKind["AllRequireLike"] = 18] = "AllRequireLike";
// @internal
ImportKind[ImportKind["AllNestedImports"] = 56] = "AllNestedImports";
// @internal
ImportKind[ImportKind["AllTopLevelImports"] = 7] = "AllTopLevelImports";
})(ImportKind = exports.ImportKind || (exports.ImportKind = {}));
function findImports(sourceFile, kinds, ignoreFileName = true) {
const result = [];
for (const node of findImportLikeNodes(sourceFile, kinds, ignoreFileName)) {
switch (node.kind) {
case ts.SyntaxKind.ImportDeclaration:
addIfTextualLiteral(node.moduleSpecifier);
break;
case ts.SyntaxKind.ImportEqualsDeclaration:
addIfTextualLiteral(node.moduleReference.expression);
break;
case ts.SyntaxKind.ExportDeclaration:
addIfTextualLiteral(node.moduleSpecifier);
break;
case ts.SyntaxKind.CallExpression:
addIfTextualLiteral(node.arguments[0]);
break;
case ts.SyntaxKind.ImportType:
if (node_1.isLiteralTypeNode(node.argument))
addIfTextualLiteral(node.argument.literal);
break;
default:
throw new Error('unexpected node');
}
}
return result;
function addIfTextualLiteral(node) {
if (node_1.isTextualLiteral(node))
result.push(node);
}
}
exports.findImports = findImports;
function findImportLikeNodes(sourceFile, kinds, ignoreFileName = true) {
return new ImportFinder(sourceFile, kinds, ignoreFileName).find();
}
exports.findImportLikeNodes = findImportLikeNodes;
class ImportFinder {
constructor(_sourceFile, _options, _ignoreFileName) {
this._sourceFile = _sourceFile;
this._options = _options;
this._ignoreFileName = _ignoreFileName;
this._result = [];
}
find() {
if (this._sourceFile.isDeclarationFile)
this._options &= ~24 /* AllImportExpressions */;
if (this._options & 7 /* AllTopLevelImports */)
this._findImports(this._sourceFile.statements);
if (this._options & 56 /* AllNestedImports */)
this._findNestedImports();
return this._result;
}
_findImports(statements) {
for (const statement of statements) {
if (node_1.isImportDeclaration(statement)) {
if (this._options & 1 /* ImportDeclaration */)
this._result.push(statement);
}
else if (node_1.isImportEqualsDeclaration(statement)) {
if (this._options & 2 /* ImportEquals */ &&
statement.moduleReference.kind === ts.SyntaxKind.ExternalModuleReference)
this._result.push(statement);
}
else if (node_1.isExportDeclaration(statement)) {
if (statement.moduleSpecifier !== undefined && this._options & 4 /* ExportFrom */)
this._result.push(statement);
}
else if (node_1.isModuleDeclaration(statement)) {
this._findImportsInModule(statement);
}
}
}
_findImportsInModule(declaration) {
if (declaration.body === undefined)
return;
if (declaration.body.kind === ts.SyntaxKind.ModuleDeclaration)
return this._findImportsInModule(declaration.body);
this._findImports(declaration.body.statements);
}
_findNestedImports() {
const isJavaScriptFile = this._ignoreFileName || (this._sourceFile.flags & ts.NodeFlags.JavaScriptFile) !== 0;
let re;
let includeJsDoc;
if ((this._options & 56 /* AllNestedImports */) === 16 /* Require */) {
if (!isJavaScriptFile)
return; // don't look for 'require' in TS files
re = /\brequire\s*[</(]/g;
includeJsDoc = false;
}
else if (this._options & 16 /* Require */ && isJavaScriptFile) {
re = /\b(?:import|require)\s*[</(]/g;
includeJsDoc = (this._options & 32 /* ImportType */) !== 0;
}
else {
re = /\bimport\s*[</(]/g;
includeJsDoc = isJavaScriptFile && (this._options & 32 /* ImportType */) !== 0;
}
for (let match = re.exec(this._sourceFile.text); match !== null; match = re.exec(this._sourceFile.text)) {
const token = getTokenAtPositionWorker(this._sourceFile, match.index, this._sourceFile,
// only look for ImportTypeNode within JSDoc in JS files
match[0][0] === 'i' && includeJsDoc);
if (token.kind === ts.SyntaxKind.ImportKeyword) {
if (token.end - 'import'.length !== match.index)
continue;
switch (token.parent.kind) {
case ts.SyntaxKind.ImportType:
this._result.push(token.parent);
break;
case ts.SyntaxKind.CallExpression:
if (token.parent.arguments.length > 1)
this._result.push(token.parent);
}
}
else if (token.kind === ts.SyntaxKind.Identifier &&
token.end - 'require'.length === match.index &&
token.parent.kind === ts.SyntaxKind.CallExpression &&
token.parent.expression === token &&
token.parent.arguments.length === 1) {
this._result.push(token.parent);
}
}
}
}
/**
* Ambient context means the statement itself has the `declare` keyword
* or is inside a `declare namespace`, `delcare module` or `declare global`.
*/
function isStatementInAmbientContext(node) {
while (node.flags & ts.NodeFlags.NestedNamespace)
node = node.parent;
return hasModifier(node.modifiers, ts.SyntaxKind.DeclareKeyword) || isAmbientModuleBlock(node.parent);
}
exports.isStatementInAmbientContext = isStatementInAmbientContext;
/** Includes `declare namespace`, `declare module` and `declare global` and namespace nested in one of the aforementioned. */
function isAmbientModuleBlock(node) {
while (node.kind === ts.SyntaxKind.ModuleBlock) {
do
node = node.parent;
while (node.flags & ts.NodeFlags.NestedNamespace);
if (hasModifier(node.modifiers, ts.SyntaxKind.DeclareKeyword))
return true;
node = node.parent;
}
return false;
}
exports.isAmbientModuleBlock = isAmbientModuleBlock;
function getIIFE(func) {
let node = func.parent;
while (node.kind === ts.SyntaxKind.ParenthesizedExpression)
node = node.parent;
return node_1.isCallExpression(node) && func.end <= node.expression.end ? node : undefined;
}
exports.getIIFE = getIIFE;
function isStrictCompilerOptionEnabled(options, option) {
return (options.strict ? options[option] !== false : options[option] === true) &&
(option !== 'strictPropertyInitialization' || isStrictCompilerOptionEnabled(options, 'strictNullChecks'));
}
exports.isStrictCompilerOptionEnabled = isStrictCompilerOptionEnabled;
// https://github.com/ajafff/tslint-consistent-codestyle/issues/85
/**
* Checks if a given compiler option is enabled.
* It handles dependencies of options, e.g. `declaration` is implicitly enabled by `composite` or `strictNullChecks` is enabled by `strict`.
* However, it does not check dependencies that are already checked and reported as errors, e.g. `checkJs` without `allowJs`.
* This function only handles boolean flags.
*/
function isCompilerOptionEnabled(options, option) {
switch (option) {
case 'stripInternal':
case 'declarationMap':
case 'emitDeclarationOnly':
return options[option] === true && isCompilerOptionEnabled(options, 'declaration');
case 'declaration':
return options.declaration || isCompilerOptionEnabled(options, 'composite');
case 'incremental':
return options.incremental === undefined ? isCompilerOptionEnabled(options, 'composite') : options.incremental;
case 'skipDefaultLibCheck':
return options.skipDefaultLibCheck || isCompilerOptionEnabled(options, 'skipLibCheck');
case 'suppressImplicitAnyIndexErrors':
return options.suppressImplicitAnyIndexErrors === true && isCompilerOptionEnabled(options, 'noImplicitAny');
case 'allowSyntheticDefaultImports':
return options.allowSyntheticDefaultImports !== undefined
? options.allowSyntheticDefaultImports
: isCompilerOptionEnabled(options, 'esModuleInterop') || options.module === ts.ModuleKind.System;
case 'noUncheckedIndexedAccess':
return options.noUncheckedIndexedAccess === true && isCompilerOptionEnabled(options, 'strictNullChecks');
case 'allowJs':
return options.allowJs === undefined ? isCompilerOptionEnabled(options, 'checkJs') : options.allowJs;
case 'noImplicitAny':
case 'noImplicitThis':
case 'strictNullChecks':
case 'strictFunctionTypes':
case 'strictPropertyInitialization':
case 'alwaysStrict':
case 'strictBindCallApply':
return isStrictCompilerOptionEnabled(options, option);
}
return options[option] === true;
}
exports.isCompilerOptionEnabled = isCompilerOptionEnabled;
/**
* Has nothing to do with `isAmbientModuleBlock`.
*
* @returns `true` if it's a global augmentation or has a string name.
*/
function isAmbientModule(node) {
return node.name.kind === ts.SyntaxKind.StringLiteral || (node.flags & ts.NodeFlags.GlobalAugmentation) !== 0;
}
exports.isAmbientModule = isAmbientModule;
/**
* @deprecated use `getTsCheckDirective` instead since `// @ts-nocheck` is no longer restricted to JS files.
* @returns the last `// @ts-check` or `// @ts-nocheck` directive in the given file.
*/
function getCheckJsDirective(source) {
return getTsCheckDirective(source);
}
exports.getCheckJsDirective = getCheckJsDirective;
/** @returns the last `// @ts-check` or `// @ts-nocheck` directive in the given file. */
function getTsCheckDirective(source) {
let directive;
// needs to work around a shebang issue until https://github.com/Microsoft/TypeScript/issues/28477 is resolved
ts.forEachLeadingCommentRange(source, (ts.getShebang(source) || '').length, (pos, end, kind) => {
if (kind === ts.SyntaxKind.SingleLineCommentTrivia) {
const text = source.slice(pos, end);
const match = /^\/{2,3}\s*@ts-(no)?check(?:\s|$)/i.exec(text);
if (match !== null)
directive = { pos, end, enabled: match[1] === undefined };
}
});
return directive;
}
exports.getTsCheckDirective = getTsCheckDirective;
function isConstAssertion(node) {
return node_1.isTypeReferenceNode(node.type) &&
node.type.typeName.kind === ts.SyntaxKind.Identifier &&
node.type.typeName.escapedText === 'const';
}
exports.isConstAssertion = isConstAssertion;
/** Detects whether an expression is affected by an enclosing 'as const' assertion and therefore treated literally. */
function isInConstContext(node) {
let current = node;
while (true) {
const parent = current.parent;
outer: switch (parent.kind) {
case ts.SyntaxKind.TypeAssertionExpression:
case ts.SyntaxKind.AsExpression:
return isConstAssertion(parent);
case ts.SyntaxKind.PrefixUnaryExpression:
if (current.kind !== ts.SyntaxKind.NumericLiteral)
return false;
switch (parent.operator) {
case ts.SyntaxKind.PlusToken:
case ts.SyntaxKind.MinusToken:
current = parent;
break outer;
default:
return false;
}
case ts.SyntaxKind.PropertyAssignment:
if (parent.initializer !== current)
return false;
current = parent.parent;
break;
case ts.SyntaxKind.ShorthandPropertyAssignment:
current = parent.parent;
break;
case ts.SyntaxKind.ParenthesizedExpression:
case ts.SyntaxKind.ArrayLiteralExpression:
case ts.SyntaxKind.ObjectLiteralExpression:
case ts.SyntaxKind.TemplateExpression:
current = parent;
break;
default:
return false;
}
}
}
exports.isInConstContext = isInConstContext;
/** Returns true for `Object.defineProperty(o, 'prop', {value, writable: false})` and `Object.defineProperty(o, 'prop', {get: () => 1})`*/
function isReadonlyAssignmentDeclaration(node, checker) {
if (!isBindableObjectDefinePropertyCall(node))
return false;
const descriptorType = checker.getTypeAtLocation(node.arguments[2]);
if (descriptorType.getProperty('value') === undefined)
return descriptorType.getProperty('set') === undefined;
const writableProp = descriptorType.getProperty('writable');
if (writableProp === undefined)
return false;
const writableType = writableProp.valueDeclaration !== undefined && node_1.isPropertyAssignment(writableProp.valueDeclaration)
? checker.getTypeAtLocation(writableProp.valueDeclaration.initializer)
: checker.getTypeOfSymbolAtLocation(writableProp, node.arguments[2]);
return type_1.isBooleanLiteralType(writableType, false);
}
exports.isReadonlyAssignmentDeclaration = isReadonlyAssignmentDeclaration;
/** Determines whether a call to `Object.defineProperty` is statically analyzable. */
function isBindableObjectDefinePropertyCall(node) {
return node.arguments.length === 3 &&
node_1.isEntityNameExpression(node.arguments[0]) &&
node_1.isNumericOrStringLikeLiteral(node.arguments[1]) &&
node_1.isPropertyAccessExpression(node.expression) &&
node.expression.name.escapedText === 'defineProperty' &&
node_1.isIdentifier(node.expression.expression) &&
node.expression.expression.escapedText === 'Object';
}
exports.isBindableObjectDefinePropertyCall = isBindableObjectDefinePropertyCall;
function isWellKnownSymbolLiterally(node) {
return ts.isPropertyAccessExpression(node) &&
ts.isIdentifier(node.expression) &&
node.expression.escapedText === 'Symbol';
}
exports.isWellKnownSymbolLiterally = isWellKnownSymbolLiterally;
/** @deprecated typescript 4.3 removed the concept of literal well known symbols. Use `getPropertyNameFromType` instead. */
function getPropertyNameOfWellKnownSymbol(node) {
return {
displayName: `[Symbol.${node.name.text}]`,
symbolName: ('__@' + node.name.text),
};
}
exports.getPropertyNameOfWellKnownSymbol = getPropertyNameOfWellKnownSymbol;
const isTsBefore43 = (([major, minor]) => major < '4' || major === '4' && minor < '3')(ts.versionMajorMinor.split('.'));
function getLateBoundPropertyNames(node, checker) {
const result = {
known: true,
names: [],
};
node = unwrapParentheses(node);
if (isTsBefore43 && isWellKnownSymbolLiterally(node)) {
result.names.push(getPropertyNameOfWellKnownSymbol(node)); // wotan-disable-line no-unstable-api-use
}
else {
const type = checker.getTypeAtLocation(node);
for (const key of type_1.unionTypeParts(checker.getBaseConstraintOfType(type) || type)) {
const propertyName = type_1.getPropertyNameFromType(key);
if (propertyName) {
result.names.push(propertyName);
}
else {
result.known = false;
}
}
}
return result;
}
exports.getLateBoundPropertyNames = getLateBoundPropertyNames;
function getLateBoundPropertyNamesOfPropertyName(node, checker) {
const staticName = getPropertyName(node);
return staticName !== undefined
? { known: true, names: [{ displayName: staticName, symbolName: ts.escapeLeadingUnderscores(staticName) }] }
: node.kind === ts.SyntaxKind.PrivateIdentifier
? { known: true, names: [{ displayName: node.text, symbolName: checker.getSymbolAtLocation(node).escapedName }] }
: getLateBoundPropertyNames(node.expression, checker);
}
exports.getLateBoundPropertyNamesOfPropertyName = getLateBoundPropertyNamesOfPropertyName;
/** Most declarations demand there to be only one statically known name, e.g. class members with computed name. */
function getSingleLateBoundPropertyNameOfPropertyName(node, checker) {
const staticName = getPropertyName(node);
if (staticName !== undefined)
return { displayName: staticName, symbolName: ts.escapeLeadingUnderscores(staticName) };
if (node.kind === ts.SyntaxKind.PrivateIdentifier)
return { displayName: node.text, symbolName: checker.getSymbolAtLocation(node).escapedName };
const { expression } = node;
return isTsBefore43 && isWellKnownSymbolLiterally(expression)
? getPropertyNameOfWellKnownSymbol(expression) // wotan-disable-line no-unstable-api-use
: type_1.getPropertyNameFromType(checker.getTypeAtLocation(expression));
}
exports.getSingleLateBoundPropertyNameOfPropertyName = getSingleLateBoundPropertyNameOfPropertyName;
function unwrapParentheses(node) {
while (node.kind === ts.SyntaxKind.ParenthesizedExpression)
node = node.expression;
return node;
}
exports.unwrapParentheses = unwrapParentheses;
function formatPseudoBigInt(v) {
return `${v.negative ? '-' : ''}${v.base10Value}n`;
}
exports.formatPseudoBigInt = formatPseudoBigInt;
/**
* Determines whether the given `SwitchStatement`'s `case` clauses cover every possible value of the switched expression.
* The logic is the same as TypeScript's control flow analysis.
* This does **not** check whether all `case` clauses do a certain action like assign a variable or return a value.
* This function ignores the `default` clause if present.
*/
function hasExhaustiveCaseClauses(node, checker) {
const caseClauses = node.caseBlock.clauses.filter(node_1.isCaseClause);
if (caseClauses.length === 0)
return false;
const typeParts = type_1.unionTypeParts(checker.getTypeAtLocation(node.expression));
if (typeParts.length > caseClauses.length)
return false;
const types = new Set(typeParts.map(getPrimitiveLiteralFromType));
if (types.has(undefined))
return false;
const seen = new Set();
for (const clause of caseClauses) {
const expressionType = checker.getTypeAtLocation(clause.expression);
if (exports.isTypeFlagSet(expressionType, ts.TypeFlags.Never))
continue; // additional case clause with 'never' is always allowed
const type = getPrimitiveLiteralFromType(expressionType);
if (types.has(type)) {
seen.add(type);
}
else if (type !== 'null' && type !== 'undefined') { // additional case clauses with 'null' and 'undefined' are always allowed
return false;
}
}
return types.size === seen.size;
}
exports.hasExhaustiveCaseClauses = hasExhaustiveCaseClauses;
function getPrimitiveLiteralFromType(t) {
if (exports.isTypeFlagSet(t, ts.TypeFlags.Null))
return 'null';
if (exports.isTypeFlagSet(t, ts.TypeFlags.Undefined))
return 'undefined';
if (exports.isTypeFlagSet(t, ts.TypeFlags.NumberLiteral))
return `${exports.isTypeFlagSet(t, ts.TypeFlags.EnumLiteral) ? 'enum:' : ''}${t.value}`;
if (exports.isTypeFlagSet(t, ts.TypeFlags.StringLiteral))
return `${exports.isTypeFlagSet(t, ts.TypeFlags.EnumLiteral) ? 'enum:' : ''}string:${t.value}`;
if (exports.isTypeFlagSet(t, ts.TypeFlags.BigIntLiteral))
return formatPseudoBigInt(t.value);
if (_3_2_1.isUniqueESSymbolType(t))
return t.escapedName;
if (type_1.isBooleanLiteralType(t, true))
return 'true';
if (type_1.isBooleanLiteralType(t, false))
return 'false';
}
function getBaseOfClassLikeExpression(node) {
var _a;
if (((_a = node.heritageClauses) === null || _a === void 0 ? void 0 : _a[0].token) === ts.SyntaxKind.ExtendsKeyword)
return node.heritageClauses[0].types[0];
}
exports.getBaseOfClassLikeExpression = getBaseOfClassLikeExpression;
//# sourceMappingURL=util.js.map

1
node_modules/tsutils/util/util.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long