Comparing version 3.17.1 to 3.18.0
@@ -0,1 +1,35 @@ | ||
# 3.18.0 | ||
**Features:** | ||
* Source maps for easier debugging | ||
* JSDoc is preserved in declaration files | ||
* Comments are presered in transpiled code | ||
* Everything you need to handle the control flow changes of TypeScript@3.7 | ||
* `callExpressionAffectsControlFlow` to determine whether a CallExpression affects control flow by returning `never` or `asserts` | ||
* `hasExhaustiveCaseClauses` to determine whether a SwitchStatement's CaseClauses handle every possible value | ||
* `endsControlFlow` and `getControlFlowEnd` take an optional `checker` parameter to recognize exhaustive SwitchStatements and control flow effects of CallExpressions | ||
* `formatPseudoBigInt` converts TypeScript's representation of a BigInt to its literal representation as you would write it in your source code | ||
* `getAstNodeAtPosition` similar to `getTokenAtPosition`, but only operates on AST Nodes | ||
* `removeOptionalChainingUndefinedMarkerType` and `isOptionalChainingUndefinedMarkerType` to handle types originating in an optional chain | ||
* `findImports` and `findImportLikeNodes`: prepare for import assertions | ||
* `getTsCheckDirective` as new name for `getCheckJsDirective` | ||
* `getCheckJsDirective` is now deprecated | ||
**Bugfixes:** | ||
* `getUsageDomain`: handles NamespaceExport and NamedTupleMember | ||
* `getPropertyName`: handles parentheses and negative numeric literals, excludes RegExp literals and private identifiers | ||
* `getSingleLateBoundPropertyNameOfPropertyName` and `getLateBoundPropertyNamesOfPropertyName`: handles private identifiers | ||
* `hasAccessModifier`: handles JSDoc access modifier | ||
* `hasSideEffects`: correctly determines side effects of (static) property initializers | ||
* `isExpressionValueUsed`: handle nullish coalescing and conditional assignment operators | ||
* `canHaveJsDoc`: aligned with upstream changes in TypeScript | ||
* `isCompilerOptionEnabled`: | ||
* `noUncheckedIndexedAccess` requires `strictNullChecks` | ||
* `checkJs` implies `allowJs` | ||
* `emitDeclarationOnly` requires `declaration` | ||
* `isInConstContext`: handle template string interpolations | ||
* excluded unnecessary files from npm package | ||
# 3.17.1 | ||
@@ -2,0 +36,0 @@ |
export * from './typeguard'; | ||
export * from './util'; |
@@ -6,1 +6,2 @@ "use strict"; | ||
tslib_1.__exportStar(require("./util"), exports); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "tsutils", | ||
"version": "3.17.1", | ||
"version": "3.18.0", | ||
"description": "utilities for working with typescript's AST", | ||
"scripts": { | ||
"compile": "rm -rf {,util,typeguard,test/**}/*.js; ttsc -p .", | ||
"precompile": "rimraf \"{,util,typeguard,test{,/rules}/*.{js,d.ts,js.map}\"", | ||
"compile": "ttsc -p .", | ||
"lint:tslint": "wotan -m @fimbul/valtyr", | ||
@@ -15,3 +16,3 @@ "lint:wotan": "wotan", | ||
"report-coverage": "cat ./coverage/lcov.info | coveralls", | ||
"github-release": "GITHUB_TOKEN=$(cat ~/github_token.txt) github-release-from-changelog", | ||
"github-release": "node ./scripts/github-release.js", | ||
"postpublish": "git push origin master --tags; run-s github-release" | ||
@@ -35,5 +36,5 @@ }, | ||
"devDependencies": { | ||
"@fimbul/mithotyn": "^0.17.0", | ||
"@fimbul/valtyr": "^0.20.0", | ||
"@fimbul/wotan": "^0.20.0", | ||
"@fimbul/mithotyn": "^0.21.0", | ||
"@fimbul/valtyr": "^0.22.0", | ||
"@fimbul/wotan": "^0.22.0", | ||
"@types/chai": "^4.0.10", | ||
@@ -48,2 +49,3 @@ "@types/mocha": "^5.0.0", | ||
"nyc": "^13.3.0", | ||
"rimraf": "^3.0.2", | ||
"ts-transform-const-enum": "^0.0.1", | ||
@@ -53,3 +55,3 @@ "tslint": "^5.8.0", | ||
"ttypescript": "^1.5.5", | ||
"typescript": "^3.6.0-dev.20190804" | ||
"typescript": "4.2.0-dev.20201230" | ||
}, | ||
@@ -56,0 +58,0 @@ "peerDependencies": { |
@@ -0,0 +0,0 @@ # Utility functions for working with typescript's AST |
export * from './node'; | ||
export * from './type'; |
@@ -6,1 +6,2 @@ "use strict"; | ||
tslib_1.__exportStar(require("./type"), exports); | ||
//# sourceMappingURL=index.js.map |
@@ -0,0 +0,0 @@ import * as ts from 'typescript'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isExpressionStatement = exports.isExpression = exports.isExportSpecifier = exports.isExportDeclaration = exports.isExportAssignment = exports.isEnumMember = exports.isEnumDeclaration = exports.isEntityNameExpression = exports.isEntityName = exports.isEmptyStatement = exports.isElementAccessExpression = exports.isDoStatement = exports.isDeleteExpression = exports.isDefaultClause = exports.isDecorator = exports.isDebuggerStatement = exports.isComputedPropertyName = exports.isContinueStatement = exports.isConstructSignatureDeclaration = exports.isConstructorTypeNode = exports.isConstructorDeclaration = exports.isConditionalTypeNode = exports.isConditionalExpression = exports.isCommaListExpression = exports.isClassLikeDeclaration = exports.isClassExpression = exports.isClassDeclaration = exports.isCatchClause = exports.isCaseOrDefaultClause = exports.isCaseClause = exports.isCaseBlock = exports.isCallSignatureDeclaration = exports.isCallLikeExpression = exports.isCallExpression = exports.isBreakStatement = exports.isBreakOrContinueStatement = exports.isBooleanLiteral = exports.isBlockLike = exports.isBlock = exports.isBindingPattern = exports.isBindingElement = exports.isBinaryExpression = exports.isAwaitExpression = exports.isAssertionExpression = exports.isAsExpression = exports.isArrowFunction = exports.isArrayTypeNode = exports.isArrayLiteralExpression = exports.isArrayBindingPattern = exports.isAccessorDeclaration = void 0; | ||
exports.isNamespaceImport = exports.isNamespaceDeclaration = exports.isNamedImports = exports.isNamedExports = exports.isModuleDeclaration = exports.isModuleBlock = exports.isMethodSignature = exports.isMethodDeclaration = exports.isMetaProperty = exports.isMappedTypeNode = exports.isLiteralTypeNode = exports.isLiteralExpression = exports.isLabeledStatement = exports.isJsxText = exports.isJsxSpreadAttribute = exports.isJsxSelfClosingElement = exports.isJsxOpeningLikeElement = exports.isJsxOpeningFragment = exports.isJsxOpeningElement = exports.isJsxFragment = exports.isJsxExpression = exports.isJsxElement = exports.isJsxClosingFragment = exports.isJsxClosingElement = exports.isJsxAttributes = exports.isJsxAttributeLike = exports.isJsxAttribute = exports.isJsDoc = exports.isIterationStatement = exports.isIntersectionTypeNode = exports.isInterfaceDeclaration = exports.isInferTypeNode = exports.isIndexSignatureDeclaration = exports.isIndexedAccessTypeNode = exports.isImportSpecifier = exports.isImportEqualsDeclaration = exports.isImportDeclaration = exports.isImportClause = exports.isIfStatement = exports.isIdentifier = exports.isGetAccessorDeclaration = exports.isFunctionTypeNode = exports.isFunctionExpression = exports.isFunctionDeclaration = exports.isForStatement = exports.isForOfStatement = exports.isForInOrOfStatement = exports.isForInStatement = exports.isExternalModuleReference = exports.isExpressionWithTypeArguments = void 0; | ||
exports.isVariableStatement = exports.isVariableDeclaration = exports.isUnionTypeNode = exports.isTypeQueryNode = exports.isTypeReferenceNode = exports.isTypePredicateNode = exports.isTypeParameterDeclaration = exports.isTypeOperatorNode = exports.isTypeOfExpression = exports.isTypeLiteralNode = exports.isTypeAssertion = exports.isTypeAliasDeclaration = exports.isTupleTypeNode = exports.isTryStatement = exports.isThrowStatement = exports.isTextualLiteral = exports.isTemplateLiteral = exports.isTemplateExpression = exports.isTaggedTemplateExpression = exports.isSyntaxList = exports.isSwitchStatement = exports.isStringLiteral = exports.isSpreadElement = exports.isSpreadAssignment = exports.isSourceFile = exports.isSignatureDeclaration = exports.isShorthandPropertyAssignment = exports.isSetAccessorDeclaration = exports.isReturnStatement = exports.isRegularExpressionLiteral = exports.isQualifiedName = exports.isPropertySignature = exports.isPropertyDeclaration = exports.isPropertyAssignment = exports.isPropertyAccessExpression = exports.isPrefixUnaryExpression = exports.isPostfixUnaryExpression = exports.isParenthesizedTypeNode = exports.isParenthesizedExpression = exports.isParameterDeclaration = exports.isOmittedExpression = exports.isObjectLiteralExpression = exports.isObjectBindingPattern = exports.isNumericOrStringLikeLiteral = exports.isNumericLiteral = exports.isNullLiteral = exports.isNoSubstitutionTemplateLiteral = exports.isNonNullExpression = exports.isNewExpression = exports.isNamespaceExportDeclaration = void 0; | ||
exports.isWithStatement = exports.isWhileStatement = exports.isVoidExpression = exports.isVariableDeclarationList = void 0; | ||
const ts = require("typescript"); | ||
@@ -710,1 +714,2 @@ function isAccessorDeclaration(node) { | ||
exports.isWithStatement = isWithStatement; | ||
//# sourceMappingURL=node.js.map |
@@ -0,0 +0,0 @@ import * as ts from 'typescript'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isUniqueESSymbolType = exports.isUnionType = exports.isUnionOrIntersectionType = exports.isTypeVariable = exports.isTypeReference = exports.isTypeParameter = exports.isSubstitutionType = exports.isObjectType = exports.isLiteralType = exports.isIntersectionType = exports.isInterfaceType = exports.isInstantiableType = exports.isIndexedAccessype = exports.isIndexedAccessType = exports.isGenericType = exports.isEnumType = exports.isConditionalType = void 0; | ||
const ts = require("typescript"); | ||
@@ -76,1 +77,2 @@ function isConditionalType(type) { | ||
exports.isUniqueESSymbolType = isUniqueESSymbolType; | ||
//# sourceMappingURL=type.js.map |
export * from './node'; | ||
export * from './type'; |
@@ -6,1 +6,2 @@ "use strict"; | ||
tslib_1.__exportStar(require("./type"), exports); | ||
//# sourceMappingURL=index.js.map |
export * from '../2.8/node'; | ||
import * as ts from 'typescript'; | ||
export declare function isImportTypeNode(node: ts.Node): node is ts.ImportTypeNode; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isImportTypeNode = void 0; | ||
const tslib_1 = require("tslib"); | ||
@@ -10,1 +11,2 @@ tslib_1.__exportStar(require("../2.8/node"), exports); | ||
exports.isImportTypeNode = isImportTypeNode; | ||
//# sourceMappingURL=node.js.map |
export * from '../2.8/type'; |
@@ -5,1 +5,2 @@ "use strict"; | ||
tslib_1.__exportStar(require("../2.8/type"), exports); | ||
//# sourceMappingURL=type.js.map |
export * from './node'; | ||
export * from './type'; |
@@ -6,1 +6,2 @@ "use strict"; | ||
tslib_1.__exportStar(require("./type"), exports); | ||
//# sourceMappingURL=index.js.map |
@@ -0,0 +0,0 @@ export * from '../2.9/node'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isSyntheticExpression = exports.isRestTypeNode = exports.isOptionalTypeNode = void 0; | ||
const tslib_1 = require("tslib"); | ||
@@ -18,1 +19,2 @@ tslib_1.__exportStar(require("../2.9/node"), exports); | ||
exports.isSyntheticExpression = isSyntheticExpression; | ||
//# sourceMappingURL=node.js.map |
@@ -0,0 +0,0 @@ export * from '../2.9/type'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isTupleTypeReference = exports.isTupleType = void 0; | ||
const tslib_1 = require("tslib"); | ||
@@ -15,1 +16,2 @@ tslib_1.__exportStar(require("../2.9/type"), exports); | ||
exports.isTupleTypeReference = isTupleTypeReference; | ||
//# sourceMappingURL=type.js.map |
export * from './node'; | ||
export * from './type'; |
@@ -6,1 +6,2 @@ "use strict"; | ||
tslib_1.__exportStar(require("./type"), exports); | ||
//# sourceMappingURL=index.js.map |
export * from '../3.0/node'; | ||
import * as ts from 'typescript'; | ||
export declare function isBigIntLiteral(node: ts.Node): node is ts.BigIntLiteral; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isBigIntLiteral = void 0; | ||
const tslib_1 = require("tslib"); | ||
@@ -10,1 +11,2 @@ tslib_1.__exportStar(require("../3.0/node"), exports); | ||
exports.isBigIntLiteral = isBigIntLiteral; | ||
//# sourceMappingURL=node.js.map |
export * from '../3.0/type'; |
@@ -5,1 +5,2 @@ "use strict"; | ||
tslib_1.__exportStar(require("../3.0/type"), exports); | ||
//# sourceMappingURL=type.js.map |
export * from './node'; | ||
export * from './type'; |
@@ -6,1 +6,2 @@ "use strict"; | ||
tslib_1.__exportStar(require("./type"), exports); | ||
//# sourceMappingURL=index.js.map |
export * from './node'; | ||
export * from './type'; |
@@ -6,1 +6,2 @@ "use strict"; | ||
tslib_1.__exportStar(require("./type"), exports); | ||
//# sourceMappingURL=index.js.map |
export * from '../3.2/node'; |
@@ -5,1 +5,2 @@ "use strict"; | ||
tslib_1.__exportStar(require("../3.2/node"), exports); | ||
//# sourceMappingURL=node.js.map |
export * from '../3.2/type'; |
@@ -5,1 +5,2 @@ "use strict"; | ||
tslib_1.__exportStar(require("../3.2/type"), exports); | ||
//# sourceMappingURL=type.js.map |
export * from './3.2/node'; |
@@ -5,1 +5,2 @@ "use strict"; | ||
tslib_1.__exportStar(require("./3.2/node"), exports); | ||
//# sourceMappingURL=node.js.map |
export * from './3.2/type'; |
@@ -5,1 +5,2 @@ "use strict"; | ||
tslib_1.__exportStar(require("./3.2/type"), exports); | ||
//# sourceMappingURL=type.js.map |
import * as ts from 'typescript'; | ||
export declare function endsControlFlow(statement: ts.Statement | ts.BlockLike): boolean; | ||
export declare type ControlFlowStatement = ts.BreakStatement | ts.ContinueStatement | ts.ReturnStatement | ts.ThrowStatement; | ||
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): ControlFlowEnd; | ||
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; |
"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"); | ||
function endsControlFlow(statement) { | ||
return getControlFlowEnd(statement).end; | ||
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) { | ||
return node_1.isBlockLike(statement) ? handleBlock(statement) : getControlFlowEndWorker(statement); | ||
function getControlFlowEnd(statement, checker) { | ||
return node_1.isBlockLike(statement) ? handleBlock(statement, checker) : getControlFlowEndWorker(statement, checker); | ||
} | ||
exports.getControlFlowEnd = getControlFlowEnd; | ||
function getControlFlowEndWorker(statement) { | ||
function getControlFlowEndWorker(statement, checker) { | ||
switch (statement.kind) { | ||
@@ -22,21 +24,25 @@ case ts.SyntaxKind.ReturnStatement: | ||
case ts.SyntaxKind.Block: | ||
return handleBlock(statement); | ||
return handleBlock(statement, checker); | ||
case ts.SyntaxKind.ForStatement: | ||
case ts.SyntaxKind.WhileStatement: | ||
return handleForAndWhileStatement(statement); | ||
return handleForAndWhileStatement(statement, checker); | ||
case ts.SyntaxKind.ForOfStatement: | ||
case ts.SyntaxKind.ForInStatement: | ||
return handleForInOrOfStatement(statement); | ||
return handleForInOrOfStatement(statement, checker); | ||
case ts.SyntaxKind.DoStatement: | ||
return matchBreakOrContinue(getControlFlowEndWorker(statement.statement), node_1.isBreakOrContinueStatement); | ||
return matchBreakOrContinue(getControlFlowEndWorker(statement.statement, checker), node_1.isBreakOrContinueStatement); | ||
case ts.SyntaxKind.IfStatement: | ||
return handleIfStatement(statement); | ||
return handleIfStatement(statement, checker); | ||
case ts.SyntaxKind.SwitchStatement: | ||
return matchBreakOrContinue(handleSwitchStatement(statement), node_1.isBreakStatement); | ||
return matchBreakOrContinue(handleSwitchStatement(statement, checker), node_1.isBreakStatement); | ||
case ts.SyntaxKind.TryStatement: | ||
return handleTryStatement(statement); | ||
return handleTryStatement(statement, checker); | ||
case ts.SyntaxKind.LabeledStatement: | ||
return matchLabel(getControlFlowEndWorker(statement.statement), statement.label); | ||
return matchLabel(getControlFlowEndWorker(statement.statement, checker), statement.label); | ||
case ts.SyntaxKind.WithStatement: | ||
return getControlFlowEndWorker(statement.statement); | ||
return getControlFlowEndWorker(statement.statement, checker); | ||
case ts.SyntaxKind.ExpressionStatement: | ||
if (checker === undefined) | ||
return defaultControlFlowEnd; | ||
return handleExpressionStatement(statement, checker); | ||
default: | ||
@@ -46,6 +52,6 @@ return defaultControlFlowEnd; | ||
} | ||
function handleBlock(statement) { | ||
function handleBlock(statement, checker) { | ||
const result = { statements: [], end: false }; | ||
for (const s of statement.statements) { | ||
const current = getControlFlowEndWorker(s); | ||
const current = getControlFlowEndWorker(s, checker); | ||
result.statements.push(...current.statements); | ||
@@ -59,8 +65,8 @@ if (current.end) { | ||
} | ||
function handleForInOrOfStatement(statement) { | ||
const end = matchBreakOrContinue(getControlFlowEndWorker(statement.statement), node_1.isBreakOrContinueStatement); | ||
end.end = false; | ||
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) { | ||
function handleForAndWhileStatement(statement, checker) { | ||
const constantCondition = statement.kind === ts.SyntaxKind.WhileStatement | ||
@@ -70,8 +76,9 @@ ? getConstantCondition(statement.expression) | ||
if (constantCondition === false) | ||
return defaultControlFlowEnd; | ||
const end = matchBreakOrContinue(getControlFlowEndWorker(statement.statement), node_1.isBreakOrContinueStatement); | ||
return defaultControlFlowEnd; // loop body is never executed | ||
const end = matchBreakOrContinue(getControlFlowEndWorker(statement.statement, checker), node_1.isBreakOrContinueStatement); | ||
if (constantCondition === undefined) | ||
end.end = false; | ||
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) { | ||
@@ -87,12 +94,14 @@ switch (node.kind) { | ||
} | ||
function handleIfStatement(node) { | ||
function handleIfStatement(node, checker) { | ||
switch (getConstantCondition(node.expression)) { | ||
case true: | ||
return getControlFlowEndWorker(node.thenStatement); | ||
// 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); | ||
: getControlFlowEndWorker(node.elseStatement, checker); | ||
} | ||
const then = getControlFlowEndWorker(node.thenStatement); | ||
const then = getControlFlowEndWorker(node.thenStatement, checker); | ||
if (node.elseStatement === undefined) | ||
@@ -103,3 +112,3 @@ return { | ||
}; | ||
const elze = getControlFlowEndWorker(node.elseStatement); | ||
const elze = getControlFlowEndWorker(node.elseStatement, checker); | ||
return { | ||
@@ -110,3 +119,3 @@ statements: [...then.statements, ...elze.statements], | ||
} | ||
function handleSwitchStatement(node) { | ||
function handleSwitchStatement(node, checker) { | ||
let hasDefault = false; | ||
@@ -120,28 +129,143 @@ const result = { | ||
hasDefault = true; | ||
const current = handleBlock(clause); | ||
const current = handleBlock(clause, checker); | ||
result.end = current.end; | ||
result.statements.push(...current.statements); | ||
} | ||
if (!hasDefault) | ||
result.end = false; | ||
result.end && (result.end = hasDefault || checker !== undefined && util_1.hasExhaustiveCaseClauses(node, checker)); | ||
return result; | ||
} | ||
function handleTryStatement(node) { | ||
function handleTryStatement(node, checker) { | ||
let finallyResult; | ||
if (node.finallyBlock !== undefined) { | ||
finallyResult = handleBlock(node.finallyBlock); | ||
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); | ||
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); | ||
const catchResult = handleBlock(node.catchClause.block, checker); | ||
return { | ||
statements: tryResult.statements | ||
.filter((s) => s.kind !== ts.SyntaxKind.ThrowStatement) | ||
// 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, | ||
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) { | ||
@@ -180,1 +304,2 @@ const result = { | ||
} | ||
//# sourceMappingURL=control-flow.js.map |
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; | ||
@@ -17,5 +24,11 @@ } | ||
export interface ConvertedAst { | ||
/** nodes wrapped in a data structure with useful links */ | ||
wrapped: WrappedAst; | ||
/** depth-first array of all nodes */ | ||
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; |
"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) { | ||
@@ -48,1 +53,2 @@ const wrapped = { | ||
} | ||
//# sourceMappingURL=convert-ast.js.map |
@@ -0,0 +0,0 @@ export * from './util'; |
@@ -9,1 +9,2 @@ "use strict"; | ||
tslib_1.__exportStar(require("./convert-ast"), exports); | ||
//# sourceMappingURL=index.js.map |
@@ -5,15 +5,25 @@ import * as ts from 'typescript'; | ||
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; | ||
/** 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; | ||
@@ -20,0 +30,0 @@ export declare function getConstructorTypeOfClassLikeDeclaration(node: ts.ClassLikeDeclaration, checker: ts.TypeChecker): ts.Type; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getIteratorYieldResultFromIteratorResult = exports.getInstanceTypeOfClassLikeDeclaration = exports.getConstructorTypeOfClassLikeDeclaration = exports.getPropertyNameFromType = exports.symbolHasReadonlyDeclaration = exports.isPropertyReadonlyInType = 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"); | ||
@@ -35,2 +36,24 @@ const type_1 = require("../typeguard/type"); | ||
} | ||
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) { | ||
@@ -83,3 +106,3 @@ return isTypeAssignableTo(checker, type, ts.TypeFlags.NumberLike); | ||
if (signatures !== undefined) | ||
return []; | ||
return []; // if more than one type of the intersection has call signatures, none of them is useful for inference | ||
signatures = sig; | ||
@@ -93,2 +116,3 @@ } | ||
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) { | ||
@@ -98,2 +122,3 @@ 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) { | ||
@@ -124,2 +149,3 @@ return type_1.isIntersectionType(type) ? type.types : [type]; | ||
if (param.valueDeclaration.dotDotDotToken) { | ||
// unwrap array type of rest parameter | ||
type = type.getNumberIndexType(); | ||
@@ -134,2 +160,3 @@ if (type === undefined) | ||
} | ||
/** Determine if a type is definitely falsy. This function doesn't unwrap union types. */ | ||
function isFalsyType(type) { | ||
@@ -143,2 +170,3 @@ if (type.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Null | ts.TypeFlags.Void)) | ||
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) { | ||
@@ -155,2 +183,3 @@ return util_1.isTypeFlagSet(type, ts.TypeFlags.BooleanLiteral) && | ||
exports.getPropertyOfType = getPropertyOfType; | ||
/** Determines if writing to a certain property of a given type is allowed. */ | ||
function isPropertyReadonlyInType(type, name, checker) { | ||
@@ -161,2 +190,3 @@ let seenProperty = false; | ||
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) || | ||
@@ -194,5 +224,9 @@ checker.getIndexInfoOfType(t, ts.IndexKind.String); | ||
default: | ||
// `undefined` falls through | ||
} | ||
} | ||
return (util_1.isSymbolFlagSet(prop, ts.SymbolFlags.ValueModule) || | ||
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)); | ||
@@ -205,2 +239,3 @@ }); | ||
const declaration = type.symbol.declarations[0]; | ||
// well-known symbols are not affected by mapped types | ||
if (declaration.readonlyToken !== undefined && !/^__@[^@]+$/.test(name)) | ||
@@ -220,3 +255,5 @@ return declaration.readonlyToken.kind !== ts.SyntaxKind.MinusToken; | ||
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)) { | ||
@@ -251,1 +288,2 @@ const value = String(type.value); | ||
exports.getIteratorYieldResultFromIteratorResult = getIteratorYieldResultFromIteratorResult; | ||
//# sourceMappingURL=type.js.map |
@@ -0,0 +0,0 @@ import * as ts from 'typescript'; |
"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"); | ||
@@ -22,2 +23,3 @@ const ts = require("typescript"); | ||
})(UsageDomain = exports.UsageDomain || (exports.UsageDomain = {})); | ||
// TODO handle cases where values are used only for their types, e.g. `declare [propSymbol]: number` | ||
function getUsageDomain(node) { | ||
@@ -27,27 +29,29 @@ const parent = node.parent; | ||
case ts.SyntaxKind.TypeReference: | ||
return node.originalKeywordKind !== ts.SyntaxKind.ConstKeyword ? 2 : undefined; | ||
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 | ||
: 4; | ||
? 2 /* Type */ | ||
: 4 /* Value */; | ||
case ts.SyntaxKind.TypeQuery: | ||
return 5 | 8; | ||
return 5 /* ValueOrNamespace */ | 8 /* TypeQuery */; | ||
case ts.SyntaxKind.QualifiedName: | ||
if (parent.left === node) { | ||
if (getEntityNameParent(parent).kind === ts.SyntaxKind.TypeQuery) | ||
return 1 | 8; | ||
return 1; | ||
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; | ||
return 7 /* Any */; // TODO handle type-only exports | ||
break; | ||
case ts.SyntaxKind.ExportAssignment: | ||
return 7; | ||
return 7 /* Any */; | ||
// Value | ||
case ts.SyntaxKind.BindingElement: | ||
if (parent.initializer === node) | ||
return 5; | ||
return 5 /* ValueOrNamespace */; | ||
break; | ||
@@ -62,3 +66,3 @@ case ts.SyntaxKind.Parameter: | ||
if (parent.name !== node) | ||
return 5; | ||
return 5 /* ValueOrNamespace */; // TODO handle type-only imports | ||
break; | ||
@@ -81,12 +85,14 @@ case ts.SyntaxKind.JsxAttribute: | ||
case ts.SyntaxKind.ImportSpecifier: | ||
case ts.SyntaxKind.TypePredicate: | ||
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; | ||
return 5 /* ValueOrNamespace */; | ||
} | ||
@@ -100,27 +106,28 @@ } | ||
case ts.SyntaxKind.TypeAliasDeclaration: | ||
return 2; | ||
return 2 /* Type */; | ||
case ts.SyntaxKind.ClassDeclaration: | ||
case ts.SyntaxKind.ClassExpression: | ||
return 2 | 4; | ||
return 2 /* Type */ | 4 /* Value */; | ||
case ts.SyntaxKind.EnumDeclaration: | ||
return 7; | ||
return 7 /* Any */; | ||
case ts.SyntaxKind.NamespaceImport: | ||
case ts.SyntaxKind.ImportClause: | ||
return 7 | 8; | ||
return 7 /* Any */ | 8 /* Import */; // TODO handle type-only imports | ||
case ts.SyntaxKind.ImportEqualsDeclaration: | ||
case ts.SyntaxKind.ImportSpecifier: | ||
return node.parent.name === node | ||
? 7 | 8 | ||
? 7 /* Any */ | 8 /* Import */ // TODO handle type-only imports | ||
: undefined; | ||
case ts.SyntaxKind.ModuleDeclaration: | ||
return 1; | ||
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 : undefined; | ||
return node.parent.name === node ? 4 /* Value */ : undefined; | ||
case ts.SyntaxKind.FunctionDeclaration: | ||
case ts.SyntaxKind.FunctionExpression: | ||
return 4; | ||
return 4 /* Value */; | ||
} | ||
@@ -194,3 +201,4 @@ } | ||
} | ||
markExported(_name) { } | ||
// tslint:disable-next-line:prefer-function-over-method | ||
markExported(_name) { } // only relevant for the root scope | ||
createOrReuseNamespaceScope(name, _exported, ambient, hasExportStatement) { | ||
@@ -240,3 +248,3 @@ let scope; | ||
} | ||
_addUseToParent(_use) { } | ||
_addUseToParent(_use) { } // tslint:disable-line:prefer-function-over-method | ||
} | ||
@@ -248,6 +256,6 @@ class RootScope extends AbstractScope { | ||
this._exports = undefined; | ||
this._innerScope = new NonRootScope(this, 1); | ||
this._innerScope = new NonRootScope(this, 1 /* Function */); | ||
} | ||
addVariable(identifier, name, selector, exported, domain) { | ||
if (domain & 8) | ||
if (domain & 8 /* Import */) | ||
return super.addVariable(identifier, name, selector, exported, domain); | ||
@@ -303,3 +311,3 @@ return this._innerScope.addVariable(identifier, name, selector, exported, domain); | ||
constructor(parent) { | ||
super(parent, 1); | ||
super(parent, 1 /* Function */); | ||
} | ||
@@ -312,4 +320,4 @@ end() { | ||
constructor(parent) { | ||
super(parent, 8); | ||
this._state = 0; | ||
super(parent, 8 /* ConditionalType */); | ||
this._state = 0 /* Initial */; | ||
} | ||
@@ -320,3 +328,3 @@ updateState(newState) { | ||
addUse(use) { | ||
if (this._state === 2) | ||
if (this._state === 2 /* TrueType */) | ||
return void this._uses.push(use); | ||
@@ -328,3 +336,3 @@ return this._parent.addUse(use, this); | ||
constructor(parent) { | ||
super(parent, 1); | ||
super(parent, 1 /* Function */); | ||
} | ||
@@ -337,3 +345,3 @@ beginBody() { | ||
constructor(_name, _domain, parent) { | ||
super(parent, 1); | ||
super(parent, 1 /* Function */); | ||
this._name = _name; | ||
@@ -371,3 +379,3 @@ this._domain = _domain; | ||
constructor(name, parent) { | ||
super(name, 4, parent); | ||
super(name, 4 /* Value */, parent); | ||
this._innerScope = new FunctionScope(this); | ||
@@ -381,4 +389,4 @@ } | ||
constructor(name, parent) { | ||
super(name, 4 | 2, parent); | ||
this._innerScope = new NonRootScope(this, 1); | ||
super(name, 4 /* Value */ | 2 /* Type */, parent); | ||
this._innerScope = new NonRootScope(this, 1 /* Function */); | ||
} | ||
@@ -388,3 +396,3 @@ } | ||
constructor(_functionScope, parent) { | ||
super(parent, 2); | ||
super(parent, 2 /* Block */); | ||
this._functionScope = _functionScope; | ||
@@ -405,6 +413,6 @@ } | ||
constructor(_ambient, _hasExport, parent) { | ||
super(parent, 1); | ||
super(parent, 1 /* Function */); | ||
this._ambient = _ambient; | ||
this._hasExport = _hasExport; | ||
this._innerScope = new NonRootScope(this, 1); | ||
this._innerScope = new NonRootScope(this, 1 /* Function */); | ||
this._exports = undefined; | ||
@@ -444,3 +452,3 @@ } | ||
this._applyUses(); | ||
this._innerScope = new NonRootScope(this, 1); | ||
this._innerScope = new NonRootScope(this, 1 /* Function */); | ||
} | ||
@@ -498,12 +506,12 @@ createOrReuseNamespaceScope(name, exported, ambient, hasExportStatement) { | ||
? new ClassExpressionScope(node.name, this._scope) | ||
: new NonRootScope(this._scope, 1)); | ||
: new NonRootScope(this._scope, 1 /* Function */)); | ||
case ts.SyntaxKind.ClassDeclaration: | ||
this._handleDeclaration(node, true, 4 | 2); | ||
return continueWithScope(node, new NonRootScope(this._scope, 1)); | ||
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); | ||
return continueWithScope(node, new NonRootScope(this._scope, 4)); | ||
this._handleDeclaration(node, true, 2 /* Type */); | ||
return continueWithScope(node, new NonRootScope(this._scope, 4 /* Type */)); | ||
case ts.SyntaxKind.EnumDeclaration: | ||
this._handleDeclaration(node, true, 7); | ||
this._handleDeclaration(node, true, 7 /* Any */); | ||
return continueWithScope(node, this._scope.createOrReuseEnumScope(node.name.text, util_1.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword))); | ||
@@ -513,3 +521,3 @@ case ts.SyntaxKind.ModuleDeclaration: | ||
case ts.SyntaxKind.MappedType: | ||
return continueWithScope(node, new NonRootScope(this._scope, 4)); | ||
return continueWithScope(node, new NonRootScope(this._scope, 4 /* Type */)); | ||
case ts.SyntaxKind.FunctionExpression: | ||
@@ -530,2 +538,3 @@ case ts.SyntaxKind.ArrowFunction: | ||
return this._handleConditionalType(node, cb, variableCallback); | ||
// End of Scope specific handling | ||
case ts.SyntaxKind.VariableDeclarationList: | ||
@@ -541,3 +550,3 @@ this._handleVariableDeclaration(node); | ||
case ts.SyntaxKind.EnumMember: | ||
this._scope.addVariable(util_1.getPropertyName(node.name), node.name, 1, true, 4); | ||
this._scope.addVariable(util_1.getPropertyName(node.name), node.name, 1 /* Function */, true, 4 /* Value */); | ||
break; | ||
@@ -548,6 +557,6 @@ case ts.SyntaxKind.ImportClause: | ||
case ts.SyntaxKind.ImportEqualsDeclaration: | ||
this._handleDeclaration(node, false, 7 | 8); | ||
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 : 7, false, 2); | ||
this._scope.addVariable(node.name.text, node.name, node.parent.kind === ts.SyntaxKind.InferType ? 8 /* InferType */ : 7 /* Type */, false, 2 /* Type */); | ||
break; | ||
@@ -593,7 +602,7 @@ case ts.SyntaxKind.ExportSpecifier: | ||
cb(node.checkType); | ||
scope.updateState(1); | ||
scope.updateState(1 /* Extends */); | ||
cb(node.extendsType); | ||
scope.updateState(2); | ||
scope.updateState(2 /* TrueType */); | ||
cb(node.trueType); | ||
scope.updateState(3); | ||
scope.updateState(3 /* FalseType */); | ||
cb(node.falseType); | ||
@@ -608,3 +617,3 @@ scope.end(varCb); | ||
if (node.kind === ts.SyntaxKind.FunctionDeclaration) | ||
this._handleDeclaration(node, false, 4); | ||
this._handleDeclaration(node, false, 4 /* Value */); | ||
const scope = this._scope = node.kind === ts.SyntaxKind.FunctionExpression && node.name !== undefined | ||
@@ -632,3 +641,3 @@ ? new FunctionExpressionScope(node.name, savedScope) | ||
const exported = isNamespaceExported(node); | ||
this._scope.addVariable(node.name.text, node.name, 1, exported, 1 | 4); | ||
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); | ||
@@ -641,9 +650,9 @@ return next(node, this._scope.createOrReuseNamespaceScope(node.name.text, exported, ambient, ambient && namespaceHasExportStatement(node))); | ||
if (node.name !== undefined) | ||
this._scope.addVariable(node.name.text, node.name, blockScoped ? 3 : 1, util_1.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword), domain); | ||
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 : 1, exported, 4); | ||
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 : 1, exported, 4); | ||
this._scope.addVariable(declaration.name.text, declaration.name, blockScoped ? 3 /* Block */ : 1 /* Function */, exported, 4 /* Value */); | ||
}); | ||
@@ -673,1 +682,2 @@ } | ||
} | ||
//# sourceMappingURL=usage.js.map |
@@ -22,8 +22,27 @@ import * as ts from 'typescript'; | ||
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; | ||
@@ -64,2 +83,3 @@ export declare function getPropertyName(propertyName: ts.PropertyName): string | undefined; | ||
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; | ||
@@ -69,6 +89,21 @@ export declare function isFunctionWithBody(node: ts.Node): node is ts.FunctionLikeDeclaration & { | ||
}; | ||
/** | ||
* 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; | ||
@@ -79,7 +114,25 @@ export interface LineRange extends ts.TextRange { | ||
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; | ||
@@ -95,2 +148,3 @@ export declare function isNumericPropertyName(name: string | ts.__String): boolean; | ||
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; | ||
@@ -109,3 +163,10 @@ export declare function isExpressionValueUsed(node: ts.Expression): boolean; | ||
export declare function canHaveJsDoc(node: ts.Node): node is ts.HasJSDoc; | ||
/** Gets the JSDoc of any 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[]; | ||
@@ -126,14 +187,19 @@ export declare enum ImportKind { | ||
export declare function findImports(sourceFile: ts.SourceFile, kinds: ImportKind): (ts.StringLiteral | ts.NoSubstitutionTemplateLiteral)[]; | ||
export declare type ImportLike = ts.ImportDeclaration | (ts.ImportEqualsDeclaration & { | ||
export declare type ImportLike = ts.ImportDeclaration | ts.ImportEqualsDeclaration & { | ||
moduleReference: ts.ExternalModuleReference; | ||
}) | (ts.ExportDeclaration & { | ||
} | ts.ExportDeclaration & { | ||
moduleSpecifier: {}; | ||
}) | (ts.CallExpression & { | ||
expression: ts.Token<ts.SyntaxKind.ImportKeyword> | (ts.Identifier & { | ||
} | ts.CallExpression & { | ||
expression: ts.Token<ts.SyntaxKind.ImportKeyword> | ts.Identifier & { | ||
text: 'require'; | ||
}); | ||
arguments: [ts.Expression]; | ||
}) | ts.ImportTypeNode; | ||
}; | ||
arguments: [ts.Expression, ...ts.Expression[]]; | ||
} | ts.ImportTypeNode; | ||
export declare function findImportLikeNodes(sourceFile: ts.SourceFile, kinds: ImportKind): 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; | ||
@@ -148,8 +214,28 @@ export declare function getIIFE(func: ts.FunctionExpression | ts.ArrowFunction): ts.CallExpression | undefined; | ||
} ? 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; | ||
@@ -169,2 +255,3 @@ export interface WellKnownSymbolLiteral extends ts.PropertyAccessExpression { | ||
export interface LateBoundPropertyNames { | ||
/** Whether all constituents are literal names. */ | ||
known: boolean; | ||
@@ -175,3 +262,12 @@ names: PropertyName[]; | ||
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; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
369320
79
4445
18