+19
-0
@@ -0,1 +1,20 @@ | ||
| # 3.11.0 | ||
| **Features:** | ||
| * typeguards: `isNumericOrStringLikeLiteral`, `isTupleTypeReference` | ||
| * `intersectionTypeParts` as counterpart to `unionTypeParts` | ||
| * `someTypePart` to execute a callback for each union or intersection constituent until the callback returns true | ||
| * `getPropertyOfType` looks up a property by its escaped name | ||
| * `isPropertyReadonlyInType` determines whether a property in a given type cannot be written to | ||
| * `symbolHasReadonlyDeclaration` determines if a Symbol has any readonly or constant declaration | ||
| * `isNumericPropertyName` determines whether a property name would match an index signature | ||
| * `isBindableObjectDefinePropertyCall` returns true for statically analyzable forms of `Object.defineProperty(o, 'p', {value, writable})` | ||
| * `isReadonlyAssignmentDeclaration` determines whether an `Object.defineProperty` call is known to result in a readonly property | ||
| * `getLateBoundPropertyNames` returns all known property names of an expression | ||
| * `getPropertyNameFromType` extracts the property name of literal types | ||
| * `isWellKnownSymbolLiterally` to recognize expressions in the form of `Symbol.<name>` | ||
| * `getPropertyNameOfWellKnownSymbol` returns the escaped name for a well known symbol literal | ||
| * `unwrapParentheses` returns the first child expression that is not a `ParenthesizedExpression` | ||
| # 3.10.0 | ||
@@ -2,0 +21,0 @@ |
+3
-3
| { | ||
| "name": "tsutils", | ||
| "version": "3.10.0", | ||
| "version": "3.11.0", | ||
| "description": "utilities for working with typescript's AST", | ||
@@ -50,6 +50,6 @@ "scripts": { | ||
| "ttypescript": "^1.5.5", | ||
| "typescript": "^3.4.1" | ||
| "typescript": "^3.4.5" | ||
| }, | ||
| "peerDependencies": { | ||
| "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev" | ||
| "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev" | ||
| }, | ||
@@ -56,0 +56,0 @@ "dependencies": { |
@@ -108,2 +108,3 @@ import * as ts from 'typescript'; | ||
| export declare function isNumericLiteral(node: ts.Node): node is ts.NumericLiteral; | ||
| export declare function isNumericOrStringLikeLiteral(node: ts.Node): node is ts.NumericLiteral | ts.StringLiteral | ts.NoSubstitutionTemplateLiteral; | ||
| export declare function isObjectBindingPattern(node: ts.Node): node is ts.ObjectBindingPattern; | ||
@@ -110,0 +111,0 @@ export declare function isObjectLiteralExpression(node: ts.Node): node is ts.ObjectLiteralExpression; |
@@ -509,2 +509,13 @@ "use strict"; | ||
| exports.isNumericLiteral = isNumericLiteral; | ||
| function isNumericOrStringLikeLiteral(node) { | ||
| switch (node.kind) { | ||
| case ts.SyntaxKind.StringLiteral: | ||
| case ts.SyntaxKind.NumericLiteral: | ||
| case ts.SyntaxKind.NoSubstitutionTemplateLiteral: | ||
| return true; | ||
| default: | ||
| return false; | ||
| } | ||
| } | ||
| exports.isNumericOrStringLikeLiteral = isNumericOrStringLikeLiteral; | ||
| function isObjectBindingPattern(node) { | ||
@@ -511,0 +522,0 @@ return node.kind === ts.SyntaxKind.ObjectBindingPattern; |
| export * from '../2.9/type'; | ||
| import * as ts from 'typescript'; | ||
| export declare function isTupleType(type: ts.Type): type is ts.TupleType; | ||
| export declare function isTupleTypeReference(type: ts.Type): type is ts.TypeReference & { | ||
| target: ts.TupleType; | ||
| }; |
@@ -6,2 +6,3 @@ "use strict"; | ||
| const ts = require("typescript"); | ||
| const _3_2_1 = require("../3.2"); | ||
| function isTupleType(type) { | ||
@@ -11,1 +12,5 @@ return (type.flags & ts.TypeFlags.Object && type.objectFlags & ts.ObjectFlags.Tuple) !== 0; | ||
| exports.isTupleType = isTupleType; | ||
| function isTupleTypeReference(type) { | ||
| return _3_2_1.isTypeReference(type) && isTupleType(type.target); | ||
| } | ||
| exports.isTupleTypeReference = isTupleTypeReference; |
+8
-0
| import * as ts from 'typescript'; | ||
| import { PropertyName } from './util'; | ||
| export declare function isEmptyObjectType(type: ts.Type): type is ts.ObjectType; | ||
@@ -8,4 +9,11 @@ export declare function removeOptionalityFromType(checker: ts.TypeChecker, type: ts.Type): ts.Type; | ||
| export declare function unionTypeParts(type: ts.Type): ts.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; | ||
| export declare function isThenableType(checker: ts.TypeChecker, node: ts.Node, type: ts.Type): boolean; | ||
| export declare function isThenableType(checker: ts.TypeChecker, node: ts.Expression, type?: ts.Type): boolean; | ||
| export declare function isFalsyType(type: ts.Type): boolean; | ||
| 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 isPropertyReadonlyInType(type: ts.Type, name: ts.__String, checker: ts.TypeChecker): boolean; | ||
| export declare function symbolHasReadonlyDeclaration(symbol: ts.Symbol, checker: ts.TypeChecker): boolean; | ||
| export declare function getPropertyNameFromType(type: ts.Type): PropertyName | undefined; |
+92
-3
@@ -6,2 +6,3 @@ "use strict"; | ||
| const util_1 = require("./util"); | ||
| const node_1 = require("../typeguard/node"); | ||
| function isEmptyObjectType(type) { | ||
@@ -95,2 +96,10 @@ if (type_1.isObjectType(type) && | ||
| exports.unionTypeParts = unionTypeParts; | ||
| 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)) { | ||
@@ -127,6 +136,86 @@ for (const ty of unionTypeParts(checker.getApparentType(type))) { | ||
| return !type.value; | ||
| if (type.flags & ts.TypeFlags.BooleanLiteral) | ||
| return type.intrinsicName === 'false'; | ||
| return isBooleanLiteralType(type, false); | ||
| } | ||
| exports.isFalsyType = isFalsyType; | ||
| function isBooleanLiteralType(type, literal) { | ||
| return util_1.isTypeFlagSet(type, ts.TypeFlags.BooleanLiteral) && | ||
| type.intrinsicName === (literal ? 'true' : 'false'); | ||
| } | ||
| exports.isBooleanLiteralType = isBooleanLiteralType; | ||
| function getPropertyOfType(type, name) { | ||
| return type.getProperties().find((s) => s.escapedName === name); | ||
| } | ||
| exports.getPropertyOfType = getPropertyOfType; | ||
| function isPropertyReadonlyInType(type, name, checker) { | ||
| let seenProperty = false; | ||
| let seenReadonlySignature = false; | ||
| for (const t of unionTypeParts(type)) { | ||
| if (getPropertyOfType(t, name) === undefined) { | ||
| 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.isFalsyType = isFalsyType; | ||
| 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: | ||
| } | ||
| } | ||
| return (util_1.isSymbolFlagSet(prop, ts.SymbolFlags.ValueModule) || | ||
| 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]; | ||
| 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; | ||
| function getPropertyNameFromType(type) { | ||
| 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 ? type.symbol.name : type.escapedName.replace(/^__@|@\d+$/g, '')}]`, | ||
| symbolName: type.escapedName, | ||
| }; | ||
| } | ||
| exports.getPropertyNameFromType = getPropertyNameFromType; |
+21
-0
@@ -82,2 +82,3 @@ import * as ts from 'typescript'; | ||
| export declare function isValidJsxIdentifier(text: string): boolean; | ||
| export declare function isNumericPropertyName(name: string | ts.__String): boolean; | ||
| export declare function isSameLine(sourceFile: ts.SourceFile, pos1: number, pos2: number): boolean; | ||
@@ -137,1 +138,21 @@ export declare enum SideEffectOptions { | ||
| export declare function isInConstContext(node: ts.Expression): boolean; | ||
| export declare function isReadonlyAssignmentDeclaration(node: ts.CallExpression, checker: ts.TypeChecker): boolean; | ||
| 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; | ||
| } | ||
| export declare function getPropertyNameOfWellKnownSymbol(node: WellKnownSymbolLiteral): PropertyName; | ||
| export interface LateBoundPropertyNames { | ||
| known: boolean; | ||
| names: PropertyName[]; | ||
| } | ||
| export declare function getLateBoundPropertyNames(node: ts.Expression, checker: ts.TypeChecker): LateBoundPropertyNames; | ||
| export declare function unwrapParentheses(node: ts.Expression): ts.Expression; |
+73
-0
@@ -6,2 +6,3 @@ "use strict"; | ||
| const _3_2_1 = require("../typeguard/3.2"); | ||
| const type_1 = require("./type"); | ||
| function getChildOfKind(node, kind, sourceFile) { | ||
@@ -547,2 +548,6 @@ for (const child of node.getChildren(sourceFile)) | ||
| exports.isValidJsxIdentifier = isValidJsxIdentifier; | ||
| function isNumericPropertyName(name) { | ||
| return String(+name) === name; | ||
| } | ||
| exports.isNumericPropertyName = isNumericPropertyName; | ||
| function isSameLine(sourceFile, pos1, pos2) { | ||
@@ -1226,1 +1231,69 @@ return ts.getLineAndCharacterOfPosition(sourceFile, pos1).line === ts.getLineAndCharacterOfPosition(sourceFile, pos2).line; | ||
| exports.isInConstContext = isInConstContext; | ||
| 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; | ||
| 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; | ||
| function getPropertyNameOfWellKnownSymbol(node) { | ||
| return { | ||
| displayName: `[Symbol.${node.name.text}]`, | ||
| symbolName: ('__@' + node.name.text), | ||
| }; | ||
| } | ||
| exports.getPropertyNameOfWellKnownSymbol = getPropertyNameOfWellKnownSymbol; | ||
| function getLateBoundPropertyNames(node, checker) { | ||
| const result = { | ||
| known: true, | ||
| names: [], | ||
| }; | ||
| node = unwrapParentheses(node); | ||
| if (isWellKnownSymbolLiterally(node)) { | ||
| result.names.push(getPropertyNameOfWellKnownSymbol(node)); | ||
| } | ||
| 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 unwrapParentheses(node) { | ||
| while (node.kind === ts.SyntaxKind.ParenthesizedExpression) | ||
| node = node.expression; | ||
| return node; | ||
| } | ||
| exports.unwrapParentheses = unwrapParentheses; |
Sorry, the diff of this file is too big to display
3724
6.01%184110
-37.93%57
-1.72%