UNPKG

@sourcegraph/eslint-plugin-sourcegraph

Version:
300 lines 10.9 kB
"use strict"; 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 tslib_1 = require("tslib"); const experimental_utils_1 = require("@typescript-eslint/experimental-utils"); const debug_1 = (0, tslib_1.__importDefault)(require("debug")); const tsutils_1 = require("tsutils"); const ts = (0, tslib_1.__importStar)(require("typescript")); const log = (0, debug_1.default)('typescript-eslint:eslint-plugin:utils:types'); function isTypeArrayTypeOrUnionOfArrayTypes(type, checker) { for (const t of (0, tsutils_1.unionTypeParts)(type)) { if (!checker.isArrayType(t)) { return false; } } return true; } exports.isTypeArrayTypeOrUnionOfArrayTypes = isTypeArrayTypeOrUnionOfArrayTypes; function containsAllTypesByName(type, allowAny, allowedNames) { if (isTypeFlagSet(type, ts.TypeFlags.Any | ts.TypeFlags.Unknown)) { return !allowAny; } if ((0, tsutils_1.isTypeReference)(type)) { type = type.target; } const symbol = type.getSymbol(); if (symbol && allowedNames.has(symbol.name)) { return true; } if ((0, tsutils_1.isUnionOrIntersectionType)(type)) { return type.types.every(t => { return containsAllTypesByName(t, allowAny, allowedNames); }); } const bases = type.getBaseTypes(); return (typeof bases !== 'undefined' && bases.length > 0 && bases.every(t => { return containsAllTypesByName(t, allowAny, allowedNames); })); } exports.containsAllTypesByName = containsAllTypesByName; function getTypeName(typeChecker, type) { if ((type.flags & ts.TypeFlags.StringLike) !== 0) { return 'string'; } if ((type.flags & ts.TypeFlags.TypeParameter) !== 0) { const symbol = type.getSymbol(); const decls = symbol?.getDeclarations(); const typeParameterDecl = decls?.[0]; if (ts.isTypeParameterDeclaration(typeParameterDecl) && typeParameterDecl.constraint) { return getTypeName(typeChecker, typeChecker.getTypeFromTypeNode(typeParameterDecl.constraint)); } } if (type.isUnion() && type.types .map(value => { return getTypeName(typeChecker, value); }) .every(t => { return t === 'string'; })) { return 'string'; } if (type.isIntersection() && type.types .map(value => { return getTypeName(typeChecker, value); }) .some(t => { return t === 'string'; })) { return 'string'; } return typeChecker.typeToString(type); } exports.getTypeName = getTypeName; function getConstrainedTypeAtLocation(checker, node) { const nodeType = checker.getTypeAtLocation(node); const constrained = checker.getBaseConstraintOfType(nodeType); return constrained ?? nodeType; } exports.getConstrainedTypeAtLocation = getConstrainedTypeAtLocation; 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; } return (flags & ts.TypeFlags.Null) !== 0; } exports.isNullableType = isNullableType; function getDeclaration(checker, node) { const symbol = checker.getSymbolAtLocation(node); if (!symbol) { return null; } const declarations = symbol.getDeclarations(); return declarations?.[0] ?? null; } exports.getDeclaration = getDeclaration; function getTypeFlags(type) { let flags = 0; for (const t of (0, tsutils_1.unionTypeParts)(type)) { flags |= t.flags; } return flags; } exports.getTypeFlags = getTypeFlags; 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; 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; 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(); for (const child of current.getChildren(sourceFile)) { const start = child.getFullStart(); if (start > position) { 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) { if (checker.getTypeArguments) { return checker.getTypeArguments(type); } return type.typeArguments ?? []; } exports.getTypeArguments = getTypeArguments; function isTypeUnknownType(type) { return isTypeFlagSet(type, ts.TypeFlags.Unknown); } exports.isTypeUnknownType = isTypeUnknownType; 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; function isTypeAnyArrayType(type, checker) { return (checker.isArrayType(type) && isTypeAnyType(getTypeArguments(type, checker)[0])); } exports.isTypeAnyArrayType = isTypeAnyArrayType; function isTypeUnknownArrayType(type, checker) { return (checker.isArrayType(type) && isTypeUnknownType(getTypeArguments(type, checker)[0])); } exports.isTypeUnknownArrayType = isTypeUnknownArrayType; function isAnyOrAnyArrayTypeDiscriminated(node, checker) { const type = checker.getTypeAtLocation(node); if (isTypeAnyType(type)) { return 0; } if (isTypeAnyArrayType(type, checker)) { return 1; } return 2; } exports.isAnyOrAnyArrayTypeDiscriminated = isAnyOrAnyArrayTypeDiscriminated; function isUnsafeAssignment(type, receiver, checker, senderNode) { if (isTypeAnyType(type)) { if (isTypeUnknownType(receiver)) { return false; } if (!isTypeAnyType(receiver)) { return { sender: type, receiver }; } } if ((0, tsutils_1.isTypeReference)(type) && (0, tsutils_1.isTypeReference)(receiver)) { if (type.target !== receiver.target) { return false; } if (senderNode?.type === experimental_utils_1.AST_NODE_TYPES.NewExpression && senderNode.callee.type === experimental_utils_1.AST_NODE_TYPES.Identifier && senderNode.callee.name === 'Map' && senderNode.arguments.length === 0 && (senderNode.typeParameters === null || senderNode.typeParameters === undefined)) { return false; } const typeArguments = type.typeArguments ?? []; const receiverTypeArguments = receiver.typeArguments ?? []; for (let index = 0; index < typeArguments.length; index += 1) { const argument = typeArguments[index]; const receiverArgument = receiverTypeArguments[index]; const unsafe = isUnsafeAssignment(argument, receiverArgument, checker, senderNode); if (unsafe) { return { sender: type, receiver }; } } return false; } return false; } exports.isUnsafeAssignment = isUnsafeAssignment; function getContextualType(checker, node) { const parent = node.parent; if (!parent) { return; } if ((0, tsutils_1.isCallExpression)(parent) || (0, tsutils_1.isNewExpression)(parent)) { if (node === parent.expression) { return; } } else if ((0, tsutils_1.isVariableDeclaration)(parent) || (0, tsutils_1.isPropertyDeclaration)(parent) || (0, tsutils_1.isParameterDeclaration)(parent)) { return parent.type ? checker.getTypeFromTypeNode(parent.type) : undefined; } else if ((0, tsutils_1.isJsxExpression)(parent)) { return checker.getContextualType(parent); } else if ((0, tsutils_1.isPropertyAssignment)(parent) && (0, tsutils_1.isIdentifier)(node)) { return checker.getContextualType(node); } else if ((0, tsutils_1.isBinaryExpression)(parent) && parent.operatorToken.kind === ts.SyntaxKind.EqualsToken && parent.right === node) { return checker.getTypeAtLocation(parent.left); } else if (![ts.SyntaxKind.TemplateSpan, ts.SyntaxKind.JsxExpression].includes(parent.kind)) { return; } return checker.getContextualType(node); } exports.getContextualType = getContextualType; //# sourceMappingURL=types.js.map