| "use strict"; |
| Object.defineProperty(exports, "__esModule", { value: true }); |
| 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 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; |
| 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 []; |
| signatures = sig; |
| } |
| } |
| return signatures === undefined ? [] : signatures; |
| } |
| return type.getCallSignatures(); |
| } |
| exports.getCallSignaturesOfType = getCallSignaturesOfType; |
| function unionTypeParts(type) { |
| return type_1.isUnionType(type) ? type.types : [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)) { |
| 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) { |
| type = type.getNumberIndexType(); |
| if (type === undefined) |
| return false; |
| } |
| for (const t of unionTypeParts(type)) |
| if (t.getCallSignatures().length !== 0) |
| return true; |
| return false; |
| } |
| 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; |
| 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 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.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; |
| function getConstructorTypeOfClassLikeDeclaration(node, checker) { |
| return checker.getDeclaredTypeOfSymbol(node.name !== undefined ? checker.getSymbolAtLocation(node.name) : checker.getTypeAtLocation(node).symbol); |
| } |
| exports.getConstructorTypeOfClassLikeDeclaration = getConstructorTypeOfClassLikeDeclaration; |
| function getInstanceTypeOfClassLikeDeclaration(node, checker) { |
| return node.kind === ts.SyntaxKind.ClassDeclaration |
| ? checker.getTypeAtLocation(node) |
| : checker.getTypeOfSymbolAtLocation(checker.getTypeAtLocation(node).getProperty('prototype'), node); |
| } |
| exports.getInstanceTypeOfClassLikeDeclaration = getInstanceTypeOfClassLikeDeclaration; |