| "use strict"; |
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { |
| if (k2 === undefined) k2 = k; |
| Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); |
| }) : (function(o, m, k, k2) { |
| if (k2 === undefined) k2 = k; |
| o[k2] = m[k]; |
| })); |
| var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { |
| Object.defineProperty(o, "default", { enumerable: true, value: v }); |
| }) : function(o, v) { |
| o["default"] = v; |
| }); |
| var __importStar = (this && this.__importStar) || function (mod) { |
| if (mod && mod.__esModule) return mod; |
| var result = {}; |
| if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); |
| __setModuleDefault(result, mod); |
| return result; |
| }; |
| var __importDefault = (this && this.__importDefault) || function (mod) { |
| return (mod && mod.__esModule) ? mod : { "default": mod }; |
| }; |
| Object.defineProperty(exports, "__esModule", { value: true }); |
| exports.getContextualType = exports.isUnsafeAssignment = exports.isAnyOrAnyArrayTypeDiscriminated = exports.isTypeUnknownArrayType = exports.isTypeAnyArrayType = exports.isTypeAnyType = exports.isTypeUnknownType = exports.getTypeArguments = exports.getEqualsKind = exports.getTokenAtPosition = exports.getSourceFileOfNode = exports.typeIsOrHasBaseType = exports.isTypeFlagSet = exports.getTypeFlags = exports.getDeclaration = exports.isNullableType = exports.getConstrainedTypeAtLocation = exports.getTypeName = exports.containsAllTypesByName = exports.isTypeArrayTypeOrUnionOfArrayTypes = void 0; |
| const debug_1 = __importDefault(require("debug")); |
| const tsutils_1 = require("tsutils"); |
| const ts = __importStar(require("typescript")); |
| const log = debug_1.default('typescript-eslint:eslint-plugin:utils:types'); |
| /** |
| * Checks if the given type is either an array type, |
| * or a union made up solely of array types. |
| */ |
| function isTypeArrayTypeOrUnionOfArrayTypes(type, checker) { |
| for (const t of tsutils_1.unionTypeParts(type)) { |
| if (!checker.isArrayType(t)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| exports.isTypeArrayTypeOrUnionOfArrayTypes = isTypeArrayTypeOrUnionOfArrayTypes; |
| /** |
| * @param type Type being checked by name. |
| * @param allowedNames Symbol names checking on the type. |
| * @returns Whether the type is, extends, or contains all of the allowed names. |
| */ |
| function containsAllTypesByName(type, allowAny, allowedNames) { |
| if (isTypeFlagSet(type, ts.TypeFlags.Any | ts.TypeFlags.Unknown)) { |
| return !allowAny; |
| } |
| if (tsutils_1.isTypeReference(type)) { |
| type = type.target; |
| } |
| const symbol = type.getSymbol(); |
| if (symbol && allowedNames.has(symbol.name)) { |
| return true; |
| } |
| if (tsutils_1.isUnionOrIntersectionType(type)) { |
| return type.types.every(t => containsAllTypesByName(t, allowAny, allowedNames)); |
| } |
| const bases = type.getBaseTypes(); |
| return (typeof bases !== 'undefined' && |
| bases.length > 0 && |
| bases.every(t => containsAllTypesByName(t, allowAny, allowedNames))); |
| } |
| exports.containsAllTypesByName = containsAllTypesByName; |
| /** |
| * Get the type name of a given type. |
| * @param typeChecker The context sensitive TypeScript TypeChecker. |
| * @param type The type to get the name of. |
| */ |
| function getTypeName(typeChecker, type) { |
| // It handles `string` and string literal types as string. |
| if ((type.flags & ts.TypeFlags.StringLike) !== 0) { |
| return 'string'; |
| } |
| // If the type is a type parameter which extends primitive string types, |
| // but it was not recognized as a string like. So check the constraint |
| // type of the type parameter. |
| if ((type.flags & ts.TypeFlags.TypeParameter) !== 0) { |
| // `type.getConstraint()` method doesn't return the constraint type of |
| // the type parameter for some reason. So this gets the constraint type |
| // via AST. |
| const symbol = type.getSymbol(); |
| const decls = symbol === null || symbol === void 0 ? void 0 : symbol.getDeclarations(); |
| const typeParamDecl = decls === null || decls === void 0 ? void 0 : decls[0]; |
| if (ts.isTypeParameterDeclaration(typeParamDecl) && |
| typeParamDecl.constraint != null) { |
| return getTypeName(typeChecker, typeChecker.getTypeFromTypeNode(typeParamDecl.constraint)); |
| } |
| } |
| // If the type is a union and all types in the union are string like, |
| // return `string`. For example: |
| // - `"a" | "b"` is string. |
| // - `string | string[]` is not string. |
| if (type.isUnion() && |
| type.types |
| .map(value => getTypeName(typeChecker, value)) |
| .every(t => t === 'string')) { |
| return 'string'; |
| } |
| // If the type is an intersection and a type in the intersection is string |
| // like, return `string`. For example: `string & {__htmlEscaped: void}` |
| if (type.isIntersection() && |
| type.types |
| .map(value => getTypeName(typeChecker, value)) |
| .some(t => t === 'string')) { |
| return 'string'; |
| } |
| return typeChecker.typeToString(type); |
| } |
| exports.getTypeName = getTypeName; |
| /** |
| * Resolves the given node's type. Will resolve to the type's generic constraint, if it has one. |
| */ |
| function getConstrainedTypeAtLocation(checker, node) { |
| const nodeType = checker.getTypeAtLocation(node); |
| const constrained = checker.getBaseConstraintOfType(nodeType); |
| return constrained !== null && constrained !== void 0 ? constrained : nodeType; |
| } |
| exports.getConstrainedTypeAtLocation = getConstrainedTypeAtLocation; |
| /** |
| * Checks if the given type is (or accepts) nullable |
| * @param isReceiver true if the type is a receiving type (i.e. the type of a called function's parameter) |
| */ |
| function isNullableType(type, { isReceiver = false, allowUndefined = true, } = {}) { |
| const flags = getTypeFlags(type); |
| if (isReceiver && flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) { |
| return true; |
| } |
| if (allowUndefined) { |
| return (flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined)) !== 0; |
| } |
| else { |
| return (flags & ts.TypeFlags.Null) !== 0; |
| } |
| } |
| exports.isNullableType = isNullableType; |
| /** |
| * Gets the declaration for the given variable |
| */ |
| function getDeclaration(checker, node) { |
| var _a; |
| const symbol = checker.getSymbolAtLocation(node); |
| if (!symbol) { |
| return null; |
| } |
| const declarations = symbol.getDeclarations(); |
| return (_a = declarations === null || declarations === void 0 ? void 0 : declarations[0]) !== null && _a !== void 0 ? _a : null; |
| } |
| exports.getDeclaration = getDeclaration; |
| /** |
| * Gets all of the type flags in a type, iterating through unions automatically |
| */ |
| function getTypeFlags(type) { |
| let flags = 0; |
| for (const t of tsutils_1.unionTypeParts(type)) { |
| flags |= t.flags; |
| } |
| return flags; |
| } |
| exports.getTypeFlags = getTypeFlags; |
| /** |
| * Checks if the given type is (or accepts) the given flags |
| * @param isReceiver true if the type is a receiving type (i.e. the type of a called function's parameter) |
| */ |
| function isTypeFlagSet(type, flagsToCheck, isReceiver) { |
| const flags = getTypeFlags(type); |
| if (isReceiver && flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) { |
| return true; |
| } |
| return (flags & flagsToCheck) !== 0; |
| } |
| exports.isTypeFlagSet = isTypeFlagSet; |
| /** |
| * @returns Whether a type is an instance of the parent type, including for the parent's base types. |
| */ |
| function typeIsOrHasBaseType(type, parentType) { |
| const parentSymbol = parentType.getSymbol(); |
| if (!type.getSymbol() || !parentSymbol) { |
| return false; |
| } |
| const typeAndBaseTypes = [type]; |
| const ancestorTypes = type.getBaseTypes(); |
| if (ancestorTypes) { |
| typeAndBaseTypes.push(...ancestorTypes); |
| } |
| for (const baseType of typeAndBaseTypes) { |
| const baseSymbol = baseType.getSymbol(); |
| if (baseSymbol && baseSymbol.name === parentSymbol.name) { |
| return true; |
| } |
| } |
| return false; |
| } |
| exports.typeIsOrHasBaseType = typeIsOrHasBaseType; |
| /** |
| * Gets the source file for a given node |
| */ |
| function getSourceFileOfNode(node) { |
| while (node && node.kind !== ts.SyntaxKind.SourceFile) { |
| node = node.parent; |
| } |
| return node; |
| } |
| exports.getSourceFileOfNode = getSourceFileOfNode; |
| function getTokenAtPosition(sourceFile, position) { |
| const queue = [sourceFile]; |
| let current; |
| while (queue.length > 0) { |
| current = queue.shift(); |
| // find the child that contains 'position' |
| for (const child of current.getChildren(sourceFile)) { |
| const start = child.getFullStart(); |
| if (start > position) { |
| // If this child begins after position, then all subsequent children will as well. |
| return current; |
| } |
| const end = child.getEnd(); |
| if (position < end || |
| (position === end && child.kind === ts.SyntaxKind.EndOfFileToken)) { |
| queue.push(child); |
| break; |
| } |
| } |
| } |
| return current; |
| } |
| exports.getTokenAtPosition = getTokenAtPosition; |
| function getEqualsKind(operator) { |
| switch (operator) { |
| case '==': |
| return { |
| isPositive: true, |
| isStrict: false, |
| }; |
| case '===': |
| return { |
| isPositive: true, |
| isStrict: true, |
| }; |
| case '!=': |
| return { |
| isPositive: false, |
| isStrict: false, |
| }; |
| case '!==': |
| return { |
| isPositive: false, |
| isStrict: true, |
| }; |
| default: |
| return undefined; |
| } |
| } |
| exports.getEqualsKind = getEqualsKind; |
| function getTypeArguments(type, checker) { |
| var _a; |
| // getTypeArguments was only added in TS3.7 |
| if (checker.getTypeArguments) { |
| return checker.getTypeArguments(type); |
| } |
| return (_a = type.typeArguments) !== null && _a !== void 0 ? _a : []; |
| } |
| exports.getTypeArguments = getTypeArguments; |
| /** |
| * @returns true if the type is `unknown` |
| */ |
| function isTypeUnknownType(type) { |
| return isTypeFlagSet(type, ts.TypeFlags.Unknown); |
| } |
| exports.isTypeUnknownType = isTypeUnknownType; |
| /** |
| * @returns true if the type is `any` |
| */ |
| function isTypeAnyType(type) { |
| if (isTypeFlagSet(type, ts.TypeFlags.Any)) { |
| if (type.intrinsicName === 'error') { |
| log('Found an "error" any type'); |
| } |
| return true; |
| } |
| return false; |
| } |
| exports.isTypeAnyType = isTypeAnyType; |
| /** |
| * @returns true if the type is `any[]` |
| */ |
| function isTypeAnyArrayType(type, checker) { |
| return (checker.isArrayType(type) && |
| isTypeAnyType( |
| // getTypeArguments was only added in TS3.7 |
| getTypeArguments(type, checker)[0])); |
| } |
| exports.isTypeAnyArrayType = isTypeAnyArrayType; |
| /** |
| * @returns true if the type is `unknown[]` |
| */ |
| function isTypeUnknownArrayType(type, checker) { |
| return (checker.isArrayType(type) && |
| isTypeUnknownType( |
| // getTypeArguments was only added in TS3.7 |
| getTypeArguments(type, checker)[0])); |
| } |
| exports.isTypeUnknownArrayType = isTypeUnknownArrayType; |
| /** |
| * @returns `AnyType.Any` if the type is `any`, `AnyType.AnyArray` if the type is `any[]` or `readonly any[]`, |
| * otherwise it returns `AnyType.Safe`. |
| */ |
| function isAnyOrAnyArrayTypeDiscriminated(node, checker) { |
| const type = checker.getTypeAtLocation(node); |
| if (isTypeAnyType(type)) { |
| return 0 /* Any */; |
| } |
| if (isTypeAnyArrayType(type, checker)) { |
| return 1 /* AnyArray */; |
| } |
| return 2 /* Safe */; |
| } |
| exports.isAnyOrAnyArrayTypeDiscriminated = isAnyOrAnyArrayTypeDiscriminated; |
| /** |
| * Does a simple check to see if there is an any being assigned to a non-any type. |
| * |
| * This also checks generic positions to ensure there's no unsafe sub-assignments. |
| * Note: in the case of generic positions, it makes the assumption that the two types are the same. |
| * |
| * @example See tests for examples |
| * |
| * @returns false if it's safe, or an object with the two types if it's unsafe |
| */ |
| function isUnsafeAssignment(type, receiver, checker) { |
| var _a, _b; |
| if (isTypeAnyType(type)) { |
| // Allow assignment of any ==> unknown. |
| if (isTypeUnknownType(receiver)) { |
| return false; |
| } |
| if (!isTypeAnyType(receiver)) { |
| return { sender: type, receiver }; |
| } |
| } |
| if (tsutils_1.isTypeReference(type) && tsutils_1.isTypeReference(receiver)) { |
| // TODO - figure out how to handle cases like this, |
| // where the types are assignable, but not the same type |
| /* |
| function foo(): ReadonlySet<number> { return new Set<any>(); } |
| |
| // and |
| |
| type Test<T> = { prop: T } |
| type Test2 = { prop: string } |
| declare const a: Test<any>; |
| const b: Test2 = a; |
| */ |
| if (type.target !== receiver.target) { |
| // if the type references are different, assume safe, as we won't know how to compare the two types |
| // the generic positions might not be equivalent for both types |
| return false; |
| } |
| const typeArguments = (_a = type.typeArguments) !== null && _a !== void 0 ? _a : []; |
| const receiverTypeArguments = (_b = receiver.typeArguments) !== null && _b !== void 0 ? _b : []; |
| for (let i = 0; i < typeArguments.length; i += 1) { |
| const arg = typeArguments[i]; |
| const receiverArg = receiverTypeArguments[i]; |
| const unsafe = isUnsafeAssignment(arg, receiverArg, checker); |
| if (unsafe) { |
| return { sender: type, receiver }; |
| } |
| } |
| return false; |
| } |
| return false; |
| } |
| exports.isUnsafeAssignment = isUnsafeAssignment; |
| /** |
| * Returns the contextual type of a given node. |
| * Contextual type is the type of the target the node is going into. |
| * i.e. the type of a called function's parameter, or the defined type of a variable declaration |
| */ |
| function getContextualType(checker, node) { |
| const parent = node.parent; |
| if (!parent) { |
| return; |
| } |
| if (tsutils_1.isCallExpression(parent) || tsutils_1.isNewExpression(parent)) { |
| if (node === parent.expression) { |
| // is the callee, so has no contextual type |
| return; |
| } |
| } |
| else if (tsutils_1.isVariableDeclaration(parent) || |
| tsutils_1.isPropertyDeclaration(parent) || |
| tsutils_1.isParameterDeclaration(parent)) { |
| return parent.type ? checker.getTypeFromTypeNode(parent.type) : undefined; |
| } |
| else if (tsutils_1.isJsxExpression(parent)) { |
| return checker.getContextualType(parent); |
| } |
| else if (tsutils_1.isPropertyAssignment(parent) && tsutils_1.isIdentifier(node)) { |
| return checker.getContextualType(node); |
| } |
| else if (![ts.SyntaxKind.TemplateSpan, ts.SyntaxKind.JsxExpression].includes(parent.kind)) { |
| // parent is not something we know we can get the contextual type of |
| return; |
| } |
| // TODO - support return statement checking |
| return checker.getContextualType(node); |
| } |
| exports.getContextualType = getContextualType; |
| //# sourceMappingURL=types.js.map |