UNPKG

eslint-plugin-vue

Version:

Official ESLint plugin for Vue.js

231 lines (229 loc) 8.7 kB
const require_runtime = require('../../_virtual/_rolldown/runtime.js'); const require_typescript$1 = require('./typescript.js'); //#region lib/utils/ts-utils/ts-types.js var require_ts_types = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => { const { getTypeScript, isAny, isUnknown, isNever, isNull, isObject, isFunction, isStringLike, isNumberLike, isBooleanLike, isBigIntLike, isArrayLikeObject, isReferenceObject } = require_typescript$1.default; /** * @typedef {import('@typescript-eslint/types').TSESTree.Node} TSESTreeNode * @typedef {import('typescript').Type} Type * @typedef {import('typescript').TypeChecker} TypeChecker * @typedef {import('typescript').Node} TypeScriptNode */ /** * @typedef {import('../index').ComponentInferTypeProp} ComponentInferTypeProp * @typedef {import('../index').ComponentUnknownProp} ComponentUnknownProp * @typedef {import('../index').ComponentInferTypeEmit} ComponentInferTypeEmit * @typedef {import('../index').ComponentUnknownEmit} ComponentUnknownEmit * @typedef {import('../index').ComponentInferTypeSlot} ComponentInferTypeSlot * @typedef {import('../index').ComponentUnknownSlot} ComponentUnknownSlot */ module.exports = { getComponentPropsFromTypeDefineTypes, getComponentEmitsFromTypeDefineTypes, getComponentSlotsFromTypeDefineTypes, inferRuntimeTypeFromTypeNode }; /** * @typedef {object} Services * @property {typeof import("typescript")} ts * @property {Map<ESNode | TSNode | TSESTreeNode, TypeScriptNode>} tsNodeMap * @property {import('typescript').TypeChecker} checker */ /** * Get TypeScript parser services. * @param {RuleContext} context The ESLint rule context object. * @returns {Services|null} */ function getTSParserServices(context) { const sourceCode = context.sourceCode; const tsNodeMap = sourceCode.parserServices.esTreeNodeToTSNodeMap; if (!tsNodeMap) return null; const checker = sourceCode.parserServices.hasFullTypeInformation !== false && sourceCode.parserServices.program && sourceCode.parserServices.program.getTypeChecker() || null; if (!checker) return null; const ts = getTypeScript(); if (!ts) return null; return { ts, tsNodeMap, checker }; } /** * Get all props by looking at all component's properties * @param {RuleContext} context The ESLint rule context object. * @param {TypeNode} propsNode Type with props definition * @return {(ComponentInferTypeProp|ComponentUnknownProp)[]} Array of component props */ function getComponentPropsFromTypeDefineTypes(context, propsNode) { const services = getTSParserServices(context); const tsNode = services && services.tsNodeMap.get(propsNode); const type = tsNode && services.checker.getTypeAtLocation(tsNode); if (!type || isAny(type) || isUnknown(type) || isNever(type) || isNull(type)) return [{ type: "unknown", propName: null, node: propsNode }]; return [...extractRuntimeProps(type, tsNode, propsNode, services)]; } /** * Get all emits by looking at all component's properties * @param {RuleContext} context The ESLint rule context object. * @param {TypeNode} emitsNode Type with emits definition * @return {(ComponentInferTypeEmit|ComponentUnknownEmit)[]} Array of component emits */ function getComponentEmitsFromTypeDefineTypes(context, emitsNode) { const services = getTSParserServices(context); const tsNode = services && services.tsNodeMap.get(emitsNode); const type = tsNode && services.checker.getTypeAtLocation(tsNode); if (!type || isAny(type) || isUnknown(type) || isNever(type) || isNull(type)) return [{ type: "unknown", emitName: null, node: emitsNode }]; return [...extractRuntimeEmits(type, tsNode, emitsNode, services)]; } /** * Get all slots by looking at all component's properties * @param {RuleContext} context The ESLint rule context object. * @param {TypeNode} slotsNode Type with slots definition * @return {(ComponentInferTypeSlot|ComponentUnknownSlot)[]} Array of component slots */ function getComponentSlotsFromTypeDefineTypes(context, slotsNode) { const services = getTSParserServices(context); const tsNode = services && services.tsNodeMap.get(slotsNode); const type = tsNode && services.checker.getTypeAtLocation(tsNode); if (!type || isAny(type) || isUnknown(type) || isNever(type) || isNull(type)) return [{ type: "unknown", slotName: null, node: slotsNode }]; return [...extractRuntimeSlots(type, slotsNode)]; } /** * @param {RuleContext} context The ESLint rule context object. * @param {TypeNode|Expression} node * @returns {string[]} */ function inferRuntimeTypeFromTypeNode(context, node) { const services = getTSParserServices(context); const tsNode = services && services.tsNodeMap.get(node); const type = tsNode && services.checker.getTypeAtLocation(tsNode); if (!type) return ["null"]; return inferRuntimeTypeInternal(type, services); } /** * @param {Type} type * @param {TypeScriptNode} tsNode * @param {TypeNode} propsNode Type with props definition * @param {Services} services * @returns {IterableIterator<ComponentInferTypeProp>} */ function* extractRuntimeProps(type, tsNode, propsNode, services) { const { ts, checker } = services; for (const property of type.getProperties()) { const isOptional = (property.flags & ts.SymbolFlags.Optional) !== 0; const name = property.getName(); const type = checker.getTypeOfSymbolAtLocation(property, tsNode); yield { type: "infer-type", propName: name, required: !isOptional, node: propsNode, types: inferRuntimeTypeInternal(type, services) }; } } /** * @param {Type} type * @param {Services} services * @returns {string[]} */ function inferRuntimeTypeInternal(type, services) { const { checker } = services; /** @type {Set<string>} */ const types = /* @__PURE__ */ new Set(); if (type.isTypeParameter()) { const constraint = type.getConstraint(); if (constraint) for (const t of inferRuntimeTypeInternal(constraint, services)) types.add(t); return [...types]; } for (const targetType of iterateTypes(checker.getNonNullableType(type))) if (isAny(targetType) || isUnknown(targetType) || isNever(targetType) || isNull(targetType)) types.add("null"); else if (isStringLike(targetType)) types.add("String"); else if (isNumberLike(targetType) || isBigIntLike(targetType)) types.add("Number"); else if (isBooleanLike(targetType)) types.add("Boolean"); else if (isFunction(targetType)) types.add("Function"); else if (isArrayLikeObject(targetType) || targetType.isClassOrInterface() && ["Array", "ReadonlyArray"].includes(checker.getFullyQualifiedName(targetType.symbol))) types.add("Array"); else if (isObject(targetType)) types.add("Object"); if (types.size <= 0) types.add("null"); return [...types]; } /** * @param {Type} type * @param {TypeScriptNode} tsNode * @param {TypeNode} emitsNode Type with emits definition * @param {Services} services * @returns {IterableIterator<ComponentInferTypeEmit|ComponentUnknownEmit>} */ function* extractRuntimeEmits(type, tsNode, emitsNode, services) { const { checker } = services; if (isFunction(type)) for (const signature of type.getCallSignatures()) { const param = signature.getParameters()[0]; if (!param) { yield { type: "unknown", emitName: null, node: emitsNode }; continue; } const type = checker.getTypeOfSymbolAtLocation(param, tsNode); for (const targetType of iterateTypes(type)) yield targetType.isStringLiteral() ? { type: "infer-type", emitName: targetType.value, node: emitsNode } : { type: "unknown", emitName: null, node: emitsNode }; } else if (isObject(type)) for (const property of type.getProperties()) yield { type: "infer-type", emitName: property.getName(), node: emitsNode }; else yield { type: "unknown", emitName: null, node: emitsNode }; } /** * @param {Type} type * @param {TypeNode} slotsNode Type with slots definition * @returns {IterableIterator<ComponentInferTypeSlot>} */ function* extractRuntimeSlots(type, slotsNode) { for (const property of type.getProperties()) yield { type: "infer-type", slotName: property.getName(), node: slotsNode }; } /** * @param {Type} type * @returns {Iterable<Type>} */ function* iterateTypes(type) { if (isReferenceObject(type) && type.target !== type) yield* iterateTypes(type.target); else if (type.isUnion() && !isBooleanLike(type)) for (const t of type.types) yield* iterateTypes(t); else yield type; } })); //#endregion Object.defineProperty(exports, 'default', { enumerable: true, get: function () { return require_ts_types(); } });