UNPKG

@vue-vine/compiler

Version:
1,307 lines (1,295 loc) 142 kB
import { createRequire } from "node:module"; import MagicString from "magic-string"; import { isArrayExpression, isArrayPattern, isArrowFunctionExpression, isAssignmentPattern, isAwaitExpression, isBlockStatement, isBooleanLiteral, isCallExpression, isClassDeclaration, isDeclaration, isExportDefaultDeclaration, isExportNamedDeclaration, isExpressionStatement, isFunctionDeclaration, isFunctionExpression, isIdentifier, isImportDeclaration, isImportDefaultSpecifier, isImportNamespaceSpecifier, isImportSpecifier, isMemberExpression, isNode, isObjectExpression, isObjectMethod, isObjectPattern, isObjectProperty, isRestElement, isReturnStatement, isStringLiteral, isTSEnumDeclaration, isTSFunctionType, isTSMethodSignature, isTSPropertySignature, isTSTypeAnnotation, isTSTypeLiteral, isTaggedTemplateExpression, isTemplateLiteral, isVariableDeclaration, isVariableDeclarator, traverse } from "@babel/types"; import { ConstantTypes, ElementTypes, NodeTypes, TS_NODE_TYPES, compile, createSimpleExpression, extractIdentifiers, isFunctionType, isInDestructureAssignment, isReferencedIdentifier, isStaticProperty, parse, parserOptions, unwrapTSNode, walkFunctionParams, walkIdentifiers } from "@vue/compiler-dom"; import hashId from "hash-sum"; import { camelize, capitalize, isBuiltInDirective, isString } from "@vue/shared"; import { LRUCache } from "lru-cache"; import { Node as Node$1, Project } from "ts-morph"; import { parse as parse$1 } from "@babel/parser"; import { compile as compile$1 } from "@vue/compiler-ssr"; import lineColumn from "line-column"; import { parse as parse$2 } from "node:url"; import process from "node:process"; import postcss from "postcss"; import merge from "merge-source-map"; import selectorParser from "postcss-selector-parser"; import { dirname, isAbsolute, resolve } from "node:path"; import { getTsconfig } from "get-tsconfig"; //#region rolldown:runtime var __require = /* @__PURE__ */ createRequire(import.meta.url); //#endregion //#region src/constants.ts const DEFINE_COMPONENT_HELPER = "defineComponent"; const DEFINE_CUSTOM_ELEMENT_HELPER = "defineCustomElement"; const USE_DEFAULTS_HELPER = "useDefaults"; const TO_REFS_HELPER = "toRefs"; const USE_MODEL_HELPER = "useModel"; const CSS_VARS_HELPER = "useCssVars"; const USE_SLOT_HELPER = "useSlots"; const UN_REF_HELPER = "unref"; const DEFAULT_MODEL_MODIFIERS_NAME = "modelModifiers"; const WITH_ASYNC_CONTEXT_HELPER = "withAsyncContext"; const CREATE_PROPS_REST_PROXY_HELPER = "createPropsRestProxy"; /** * These macros can't be inside other expressions but just called directly. */ const BARE_CALL_MACROS = [ "vineExpose", "vineOptions", "vineStyle", "vineStyle.scoped", "vineStyle.import", "vineStyle.import.scoped", "vineCustomElement", "vineValidators" ]; const DECLARATION_MACROS = [ "vineProp", "vineProp.optional", "vineProp.withDefault", "vineEmits", "vineSlots", "vineModel" ]; const VINE_MACROS = [...DECLARATION_MACROS, ...BARE_CALL_MACROS]; const CAN_BE_CALLED_MULTI_TIMES_MACROS = ["vineModel", "vineStyle"]; const SUPPORTED_CSS_LANGS = [ "css", "scss", "sass", "less", "stylus", "postcss" ]; const SUPPORTED_STYLE_FILE_EXTS = [ ".css", ".scss", ".sass", ".less", ".styl" ]; /** This is derived from `@vue/compiler-core` */ const VineBindingTypes = { PROPS: "props", PROPS_ALIASED: "props-aliased", SETUP_LET: "setup-let", SETUP_CONST: "setup-const", SETUP_REACTIVE_CONST: "setup-reactive-const", SETUP_MAYBE_REF: "setup-maybe-ref", SETUP_REF: "setup-ref", LITERAL_CONST: "literal-const", DESTRUCTURED_PROP: "destructured-prop" }; const EXPECTED_ERROR = "expected_error"; //#endregion //#region src/utils/index.ts const camelizeRE = /-(\w)/g; function cacheStringFunction(fn) { const cache = Object.create(null); return (str) => { const hit = cache[str]; return hit || (cache[str] = fn(str)); }; } function showIf(condition, s, not) { return condition ? s : not ?? ""; } function filterJoin(arr, join) { return arr.filter(Boolean).join(join); } function getStyleLangFileExt(styleLang) { if (styleLang === "postcss") return "css"; else if (styleLang === "stylus") return "styl"; return styleLang; } function appendToMapArray(storeMap, key, value) { const arr = storeMap.get(key); if (!arr) storeMap.set(key, [value]); else arr.push(value); } const camelize$1 = cacheStringFunction((str) => { return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : ""); }); const capitalize$1 = cacheStringFunction((str) => str.charAt(0).toUpperCase() + str.slice(1)); var ExitTraverseError = class extends Error { constructor() { super("ExitTraverse"); } }; const exitTraverse = new ExitTraverseError(); const _breakableTraverse = (node, handlers) => { try { return traverse(node, handlers); } catch (e) { if (e instanceof ExitTraverseError) return; throw e; } }; function isBasicBoolTypeNames(type) { return [ "boolean", "Boolean", "true", "false" ].includes(type); } function createLinkedCodeTag(side, itemLength) { return `/* __LINKED_CODE_${side.toUpperCase()}__#${itemLength} */`; } //#endregion //#region src/babel-helpers/ast.ts function isVineCompFnDecl(target) { if ((isExportNamedDeclaration(target) || isExportDefaultDeclaration(target)) && target.declaration) target = target.declaration; if (isFunctionDeclaration(target)) { const returnStmt = target.body?.body.find((node) => isReturnStatement(node)); if (!returnStmt) return false; return !!(returnStmt.argument && isVineTaggedTemplateString(returnStmt.argument)); } if (isVariableDeclaration(target)) { const declValue = target.declarations[0].init; if (!declValue) return false; if (isFunctionExpression(declValue)) { const returnStmt = declValue.body?.body.find((node) => isReturnStatement(node)); if (!returnStmt) return false; return !!(returnStmt.argument && isVineTaggedTemplateString(returnStmt.argument)); } if (isArrowFunctionExpression(declValue)) { const arrowFnReturns = isBlockStatement(declValue.body) ? declValue.body.body.find((node) => isReturnStatement(node)) : declValue.body; if (isReturnStatement(arrowFnReturns)) return !!(arrowFnReturns.argument && isVineTaggedTemplateString(arrowFnReturns.argument)); return isVineTaggedTemplateString(arrowFnReturns); } return false; } return false; } function findVineCompFnDecls(root) { const vineFnComps = []; for (const stmt of root.program.body) if (isVineCompFnDecl(stmt)) vineFnComps.push(stmt); return vineFnComps; } function isBabelFunctionTypes(node) { return isFunctionDeclaration(node) || isFunctionExpression(node) || isArrowFunctionExpression(node); } function isDescendant(node, potentialDescendant) { const stack = [node]; while (stack.length) { const currentNode = stack.pop(); if (currentNode === potentialDescendant) return true; const children = Object.values(currentNode).filter((child) => Array.isArray(child) ? child.every(isNode) : isNode(child)); for (const child of children) if (Array.isArray(child)) stack.push(...child); else stack.push(child); } return false; } function isVineTaggedTemplateString(node) { return isTaggedTemplateExpression(node) && isIdentifier(node.tag) && node.tag.name === "vine"; } function isVineMacroCallExpression(node) { if (isCallExpression(node)) { const calleeName = getVineMacroCalleeName(node); return VINE_MACROS.includes(calleeName); } return false; } function getVineMacroCalleeName(node) { const callee = node.callee; if (isIdentifier(callee)) return callee.name; if (isMemberExpression(callee)) { const buildMemberPath = (node$1) => { if (isIdentifier(node$1)) return node$1.name; if (isMemberExpression(node$1)) { const objPath = buildMemberPath(node$1.object); if (isIdentifier(node$1.property)) return `${objPath}.${node$1.property.name}`; } return ""; }; return buildMemberPath(callee); } return ""; } function getVinePropCallTypeParams(node) { return node.typeParameters?.params?.[0]; } /** * Check if it belongs to a certain category of macro instead of directly checking callee name * @param name - The name of the macro or an array of macro names */ function isVineMacroOf(name) { return (node) => { if (!isCallExpression(node)) return false; const macroCalleeName = getVineMacroCalleeName(node); return Array.isArray(name) ? name.includes(macroCalleeName) : macroCalleeName.includes(name); }; } const isVineProp = isVineMacroOf("vineProp"); const isVineSlots = isVineMacroOf("vineSlots"); const isVineEmits = isVineMacroOf("vineEmits"); const isVineModel = isVineMacroOf("vineModel"); const isVineStyle = isVineMacroOf([ "vineStyle", "vineStyle.scoped", "vineStyle.import", "vineStyle.import.scoped" ]); const isVineCustomElement = isVineMacroOf("vineCustomElement"); const isVineValidators = isVineMacroOf("vineValidators"); function isUseTemplateRefCall(node) { return isCallOf(node, "useTemplateRef"); } function isStatementContainsVineMacroCall(node) { let result = false; _breakableTraverse(node, (descendant) => { if (isVineMacroCallExpression(descendant)) { result = true; throw exitTraverse; } }); return result; } function isTagTemplateStringContainsInterpolation(tagTmplNode) { return tagTmplNode.quasi.expressions.length > 0; } function getFunctionParams(fnItselfNode) { const params = []; if (isFunctionDeclaration(fnItselfNode)) params.push(...fnItselfNode.params); else if (isFunctionExpression(fnItselfNode) || isArrowFunctionExpression(fnItselfNode)) params.push(...fnItselfNode.params); return params; } function getFunctionPickedInfos(fnDecl) { const pickedInfo = []; let target = fnDecl; if ((isExportNamedDeclaration(target) || isExportDefaultDeclaration(target)) && target.declaration) target = target.declaration; if (isVariableDeclaration(target)) { target.declarations.forEach((decl) => { if ((isFunctionExpression(decl.init) || isArrowFunctionExpression(decl.init)) && isIdentifier(decl.id)) pickedInfo.push({ fnDeclNode: fnDecl, fnItselfNode: decl.init, fnName: decl.id.name }); }); return pickedInfo; } if (isFunctionDeclaration(target)) pickedInfo.push({ fnDeclNode: fnDecl, fnItselfNode: target, fnName: target.id?.name ?? "" }); return pickedInfo; } function findVineTagTemplateStringReturn(node) { let templateReturn; let templateStringNode; traverse(node, (descendant) => { if (isReturnStatement(descendant)) { templateReturn = descendant; if (isVineTaggedTemplateString(descendant.argument)) templateStringNode = descendant.argument; } }); return { templateReturn, templateStringNode }; } function getImportStatements(root) { const importStmts = []; for (const stmt of root.program.body) if (isImportDeclaration(stmt)) importStmts.push(stmt); return importStmts; } function getTSTypeLiteralPropertySignatureName(tsTypeLit) { return isIdentifier(tsTypeLit.key) ? tsTypeLit.key.name : isStringLiteral(tsTypeLit.key) ? tsTypeLit.key.value : ""; } function getAllVinePropMacroCall(fnItselfNode) { const allVinePropMacroCalls = []; traverse(fnItselfNode.body, { enter(node, parent) { if (!isVineMacroOf("vineProp")(node)) return; const statement = parent.find((ancestor) => isVariableDeclaration(ancestor.node)); const propVarDeclarator = parent.find((ancestor) => isVariableDeclarator(ancestor.node) && isIdentifier(ancestor.node.id)); if (!propVarDeclarator) return; const propVarIdentifier = propVarDeclarator.node.id; allVinePropMacroCalls.push({ macroCall: node, identifier: propVarIdentifier, jsDocComments: statement?.node.leadingComments?.filter((comment) => comment.type === "CommentBlock") ?? [] }); } }); return allVinePropMacroCalls; } function unwrapTSNode$1(node) { if (TS_NODE_TYPES.includes(node.type)) return unwrapTSNode$1(node.expression); else return node; } function isStaticNode(node) { node = unwrapTSNode$1(node); switch (node.type) { case "UnaryExpression": return isStaticNode(node.argument); case "LogicalExpression": case "BinaryExpression": return isStaticNode(node.left) && isStaticNode(node.right); case "ConditionalExpression": return isStaticNode(node.test) && isStaticNode(node.consequent) && isStaticNode(node.alternate); case "SequenceExpression": case "TemplateLiteral": return node.expressions.every((expr) => isStaticNode(expr)); case "ParenthesizedExpression": return isStaticNode(node.expression); case "StringLiteral": case "NumericLiteral": case "BooleanLiteral": case "NullLiteral": case "BigIntLiteral": return true; } return false; } function isCallOf(node, test) { return !!(node && test && node.type === "CallExpression" && node.callee.type === "Identifier" && (typeof test === "string" ? node.callee.name === test : test(node.callee.name))); } function isLiteralNode(node) { return node.type.endsWith("Literal"); } function canNeverBeRef(node, userReactiveImport) { if (isCallOf(node, userReactiveImport)) return true; switch (node.type) { case "UnaryExpression": case "BinaryExpression": case "ArrayExpression": case "ObjectExpression": case "FunctionExpression": case "ArrowFunctionExpression": case "UpdateExpression": case "ClassExpression": case "TaggedTemplateExpression": return true; case "SequenceExpression": return canNeverBeRef(node.expressions[node.expressions.length - 1], userReactiveImport); default: if (isLiteralNode(node)) return true; return false; } } function tryInferExpressionTSType(node) { switch (node.type) { case "BooleanLiteral": return "boolean"; case "NumericLiteral": return "number"; case "BigIntLiteral": return "bigint"; case "StringLiteral": return "string"; case "NullLiteral": return "null"; case "Identifier": return node.name === "undefined" ? "undefined" : `typeof ${node.name}`; default: return "any"; } } function findAllExportNamedDeclarations(root) { const exportNamedDeclarations = []; for (const stmt of root.program.body) if (isExportNamedDeclaration(stmt)) exportNamedDeclarations.push(stmt); return exportNamedDeclarations; } function fineAllExplicitExports(exportNamedDeclarations) { const explicitExports = []; for (const exportDecl of exportNamedDeclarations) for (const specifier of exportDecl.specifiers) if (isIdentifier(specifier.exported)) explicitExports.push(specifier.exported.name); return explicitExports; } //#endregion //#region src/utils/color-string.ts const colorMap = { bold: "1", italic: "3", underline: "4", inverse: "7", strikethrough: "9", white: "37", grey: "90", black: "30", blue: "34", cyan: "36", green: "32", magenta: "35", red: "31", yellow: "33", bgWhite: "47", bgGrey: "49", bgBlack: "40", bgBlue: "44", bgCyan: "46", bgGreen: "42", bgMagenta: "45", bgRed: "41", bgYellow: "43" }; /** * Transform a string to ascii colorful string. * * ## Example * ```typescript * import { colorful } from 'my-pearls' * * colorful('This is red', ['red']) * colorful('This is green background', ['bgGreen']) * colorful('This is cyan and bold', ['cyan', 'bold']) * ``` * * @param str String to be colored. * @param options Colorful options. * @returns Ascii colorful string. */ function colorful(str, options = []) { const colors = options.map((option) => { return colorMap[option]; }).join(";"); return `\u001B[${colors}m${str}\u001B[0m`; } function createColorful(options) { return (str) => colorful(str, options); } /** * Colorful string creator functions map. * * ## Example * ```typescript * import { Colorful } from 'my-pearls' * * Colorful.red('This is red') * Colorful.bgGreen('This is green background') * Colorful.bold('This is bold') * ``` */ const Colorful = Object.keys(colorMap).reduce((acc, key) => { acc[key] = createColorful([key]); return acc; }, {}); //#endregion //#region src/diagnostics.ts const whiteFgRedBg = createColorful(["white", "bgRed"]); const whiteFgYellowBg = createColorful(["white", "bgYellow"]); const redFgBold = createColorful(["red", "bold"]); const ErrorLabel = whiteFgRedBg(" Error "); const WarningLabel = whiteFgYellowBg(" Warning "); function makeDiagnostic(label, { msg, fileId, location, msgColorful }) { const pos = location?.start; const posString = pos ? `${pos.line}:${pos.column}` : ""; return ` ${label} File: ${fileId} ${posString} ${msgColorful(msg)} `; } function vineErr({ vineFileCtx, vineCompFnCtx }, { msg, location, rawVueTemplateLocation }) { const full = makeDiagnostic(ErrorLabel, { msg, location, fileId: vineFileCtx.fileId, msgColorful: redFgBold }); return { full, msg, location, rawVueTemplateLocation, vineCompFnCtx }; } function vineWarn({ vineFileCtx, vineCompFnCtx }, { msg, location, rawVueTemplateLocation }) { const full = makeDiagnostic(WarningLabel, { msg, location, fileId: vineFileCtx.fileId, msgColorful: whiteFgYellowBg }); return { full, msg, location, rawVueTemplateLocation, vineCompFnCtx }; } //#endregion //#region src/style/analyze-css-vars.ts /** * Implementation from vue * https://github.com/vuejs/core/blob/main/packages/compiler-sfc/src/style/cssVars.ts */ var LexerState = /* @__PURE__ */ function(LexerState$1) { LexerState$1[LexerState$1["inParens"] = 1] = "inParens"; LexerState$1[LexerState$1["inSingleQuoteString"] = 2] = "inSingleQuoteString"; LexerState$1[LexerState$1["inDoubleQuoteString"] = 3] = "inDoubleQuoteString"; return LexerState$1; }(LexerState || {}); function lexBinding(content, start) { let state = LexerState.inParens; let parenDepth = 0; for (let i = start; i < content.length; i++) { const char = content.charAt(i); switch (state) { case LexerState.inParens: if (char === "'") state = LexerState.inSingleQuoteString; else if (char === "\"") state = LexerState.inDoubleQuoteString; else if (char === "(") parenDepth++; else if (char === ")") if (parenDepth > 0) parenDepth--; else return i; break; case LexerState.inSingleQuoteString: if (char === "'") state = LexerState.inParens; break; case LexerState.inDoubleQuoteString: if (char === "\"") state = LexerState.inParens; break; } } return null; } function normalizeExpression(exp) { exp = exp.trim(); if (exp[0] === "'" && exp[exp.length - 1] === "'" || exp[0] === "\"" && exp[exp.length - 1] === "\"") return exp.slice(1, -1); return exp; } const vBindRE = /v-bind\s*\(/g; function parseCssVars(styles, hook) { const vars = []; styles.forEach((style) => { let match = null; const content = style.replace(/\/\*([\s\S]*?)\*\//g, ""); for (match = vBindRE.exec(content); match; match = vBindRE.exec(content)) { const start = match.index + match[0].length; const end = lexBinding(content, start); if (end !== null) { hook?.getIndex(start, end); const variable = normalizeExpression(content.slice(start, end)); if (!vars.includes(variable)) vars.push(variable); } } }); return vars; } //#endregion //#region src/template/cache.ts function createCache(max = 500) { return new LRUCache({ max }); } //#endregion //#region src/template/import-usage-check.ts const templateUsageCheckCache = createCache(); /** * Check if an import is used in the SFC's template. This is used to determine * the properties that should be included in the object returned from setup() * when not using inline mode. */ function isImportUsed(vineCompFnCtx, local) { return resolveTemplateUsedIdentifiers(vineCompFnCtx).has(local); } function resolveTemplateUsedIdentifiers(vineCompFnCtx) { const { templateSource, templateParsedAst } = vineCompFnCtx; const cached = templateUsageCheckCache.get(templateSource); if (cached) return cached; const ids = /* @__PURE__ */ new Set(); templateParsedAst.children.forEach(walk$1); function walk$1(node) { switch (node.type) { case NodeTypes.ELEMENT: { let tag = node.tag; if (tag.includes(".")) tag = tag.split(".")[0].trim(); if (!parserOptions.isNativeTag(tag) && !parserOptions.isBuiltInComponent(tag)) { ids.add(camelize(tag)); ids.add(capitalize(camelize(tag))); } for (let i = 0; i < node.props.length; i++) { const prop = node.props[i]; if (prop.type === NodeTypes.DIRECTIVE) { if (!isBuiltInDirective(prop.name)) ids.add(`v${capitalize(camelize(prop.name))}`); if (prop.arg && !prop.arg.isStatic) extractIdentifiers$1(ids, prop.arg); if (prop.name === "for") extractIdentifiers$1(ids, prop.forParseResult.source); else if (prop.exp) extractIdentifiers$1(ids, prop.exp); else if (prop.name === "bind" && !prop.exp) ids.add(camelize(prop.arg.content)); } if (prop.type === NodeTypes.ATTRIBUTE && prop.name === "ref" && prop.value?.content) ids.add(prop.value.content); } node.children.forEach(walk$1); break; } case NodeTypes.INTERPOLATION: extractIdentifiers$1(ids, node.content); break; } } templateUsageCheckCache.set(templateSource, ids); return ids; } function extractIdentifiers$1(ids, node) { if (node.ast) walkIdentifiers(node.ast, (n) => ids.add(n.name)); else if (node.ast === null) ids.add(node.content); } //#endregion //#region src/ts-morph/resolve-type.ts function isBooleanType(typeChecker, type) { if (type.isBoolean() || type.isBooleanLiteral() || type.isLiteral() && (type.getLiteralValue() === "true" || type.getLiteralValue() === "false")) return true; if (type.isUnion()) return type.getUnionTypes().some((t) => isBooleanType(typeChecker, t)); if (type.isIntersection()) return type.getIntersectionTypes().some((t) => isBooleanType(typeChecker, t)); if (type.isTypeParameter()) { const actualType = type.getConstraint(); if (actualType) return isBooleanType(typeChecker, actualType); } const aliasSymbol = type.getAliasSymbol(); if (aliasSymbol) { const aliasType = typeChecker.getDeclaredTypeOfSymbol(aliasSymbol); return isBooleanType(typeChecker, aliasType); } return false; } function tsAstFindVineCompFn(vineCompFnName) { return (node) => { if (!Node$1.isFunctionDeclaration(node)) { if (!Node$1.isVariableDeclaration(node) || !node.getInitializer() || !Node$1.isFunctionExpression(node.getInitializer()) && !Node$1.isArrowFunction(node.getInitializer())) return false; } const body = Node$1.isFunctionDeclaration(node) ? node.getBody() : node.getInitializer().getBody(); if (!body) return false; const returnStatement = body.getFirstDescendant((nodeInReturnStmt) => Node$1.isReturnStatement(nodeInReturnStmt) && Node$1.isTaggedTemplateExpression(nodeInReturnStmt.getExpression()) && nodeInReturnStmt.getExpression()?.getTag().getText() === "vine"); const fnName = Node$1.isFunctionDeclaration(node) ? node.getName() : node.getNameNode()?.getText(); return !!returnStatement && fnName === vineCompFnName; }; } function resolveVineCompFnProps(params) { const { tsMorphCache, vineCompFnCtx, defaultsFromDestructuredProps } = params; const { typeChecker, project } = tsMorphCache; const sourceFile = project.getSourceFile(vineCompFnCtx.fileCtx.fileId); if (!sourceFile) return {}; const propsInfo = {}; const targetFn = sourceFile.getFirstDescendant(tsAstFindVineCompFn(vineCompFnCtx.fnName)); if (!targetFn) return propsInfo; const propsParams = (Node$1.isFunctionDeclaration(targetFn) ? targetFn.getParameters() : targetFn.getInitializer()?.getParameters())?.[0]; if (!propsParams) return propsInfo; const propsIdentifier = propsParams.getNameNode(); const propsType = propsIdentifier.getType(); for (const prop of propsType.getProperties()) { const propType = typeChecker.getTypeOfSymbolAtLocation(prop, propsIdentifier); const propName = prop.getName(); propsInfo[propName] = { isFromMacroDefine: false, isRequired: !prop.isOptional(), isMaybeBool: isBooleanType(typeChecker, propType) }; if (defaultsFromDestructuredProps[propName]) propsInfo[propName].default = defaultsFromDestructuredProps[propName]; } return propsInfo; } function checkForBoolean(param) { const { propName, tsMorphCache, vineCompilerHooks, vineCompFnCtx, babelNode } = param; const { typeChecker, project } = tsMorphCache; const sourceFile = project.getSourceFileOrThrow(vineCompFnCtx.fileCtx.fileId); const tsAstNode = sourceFile.getDescendantAtStartWithWidth(babelNode.start, babelNode.end - babelNode.start); if (!tsAstNode) return false; try { const tsAstNodeType = typeChecker.getTypeAtLocation(tsAstNode); return isBooleanType(typeChecker, tsAstNodeType); } catch (err) { vineCompilerHooks.onError(vineErr({ vineFileCtx: vineCompFnCtx.fileCtx, vineCompFnCtx }, { msg: `Failed to check boolean type of prop "${propName}". ${err}`, location: babelNode.loc })); return false; } } //#endregion //#region src/types.ts const VinePropsDefinitionBy = { typeLiteral: 1, typeReference: 2, macro: 3 }; //#endregion //#region src/analyze.ts function storeTheOnlyMacroCallArg(macroName, callback) { const findMacroCallNode = (fnItselfNode) => { let vineExposeMacroCall; _breakableTraverse(fnItselfNode, { enter(descendant) { if (isVineMacroOf(macroName)(descendant)) { vineExposeMacroCall = descendant; throw exitTraverse; } } }); return vineExposeMacroCall; }; return (analyzeCtx, fnItselfNode) => { const macroCall = findMacroCallNode(fnItselfNode); if (!macroCall) return; const macroCallArg = macroCall.arguments[0]; if (!macroCallArg) return; callback(analyzeCtx, macroCall, macroCallArg); }; } const analyzeVineExpose = storeTheOnlyMacroCallArg("vineExpose", ({ vineCompFnCtx }, macroCall, macroCallArg) => { vineCompFnCtx.expose = { macroCall, paramObj: macroCallArg }; vineCompFnCtx.macrosInfoForVolar.push({ macroCall, macroType: "vineExpose" }); }); const analyzeVineOptions = storeTheOnlyMacroCallArg("vineOptions", ({ vineCompFnCtx }, _, macroCallArg) => { vineCompFnCtx.options = macroCallArg; }); function registerBinding(bindings, node, type) { bindings[node.name] = type; } function walkPattern(node, bindings, isConst) { if (node.type === "Identifier") { const type = isConst ? VineBindingTypes.SETUP_MAYBE_REF : VineBindingTypes.SETUP_LET; registerBinding(bindings, node, type); } else if (node.type === "RestElement") { const type = isConst ? VineBindingTypes.SETUP_CONST : VineBindingTypes.SETUP_LET; registerBinding(bindings, node.argument, type); } else if (node.type === "ObjectPattern") walkObjectPattern(node, bindings, isConst); else if (node.type === "ArrayPattern") walkArrayPattern(node, bindings, isConst); else if (node.type === "AssignmentPattern") if (node.left.type === "Identifier") { const type = isConst ? VineBindingTypes.SETUP_MAYBE_REF : VineBindingTypes.SETUP_LET; registerBinding(bindings, node.left, type); } else walkPattern(node.left, bindings, isConst); } function walkArrayPattern(node, bindings, isConst) { for (const e of node.elements) { if (!e) continue; walkPattern(e, bindings, isConst); } } function walkObjectPattern(node, bindings, isConst) { for (const p of node.properties) if (p.type === "ObjectProperty") if (p.key.type === "Identifier" && p.key === p.value) { const type = isConst ? VineBindingTypes.SETUP_MAYBE_REF : VineBindingTypes.SETUP_LET; registerBinding(bindings, p.key, type); } else walkPattern(p.value, bindings, isConst); else { const type = isConst ? VineBindingTypes.SETUP_CONST : VineBindingTypes.SETUP_LET; registerBinding(bindings, p.argument, type); } } function analyzeVariableDeclarationForBindings({ vineFileCtx, vineCompFnCtx }, stmt) { const userImportAliases = { ...vineFileCtx.vueImportAliases }; const userReactiveBinding = userImportAliases.reactive; const allDeclarators = stmt.declarations; const isConst = stmt.kind === "const"; const isAllLiteral = isConst && allDeclarators.every((decl) => isIdentifier(decl.id) && decl.init && isStaticNode(decl.init)); for (const varDecl of allDeclarators) if (isIdentifier(varDecl.id) && varDecl.init) { let bindingType; if (isAllLiteral || isConst && isStaticNode(varDecl.init)) bindingType = VineBindingTypes.LITERAL_CONST; else if (isCallOf(varDecl.init, userReactiveBinding)) bindingType = isConst ? VineBindingTypes.SETUP_REACTIVE_CONST : VineBindingTypes.SETUP_LET; else if (isConst && canNeverBeRef(varDecl.init, userReactiveBinding)) bindingType = VineBindingTypes.SETUP_CONST; else if (isConst) if (isCallOf(varDecl.init, (m) => m === userImportAliases.ref || m === userImportAliases.computed || m === userImportAliases.shallowRef || m === userImportAliases.customRef || m === userImportAliases.toRef)) bindingType = VineBindingTypes.SETUP_REF; else bindingType = VineBindingTypes.SETUP_MAYBE_REF; else bindingType = VineBindingTypes.SETUP_LET; registerBinding(vineCompFnCtx.bindings, varDecl.id, bindingType); } else if (isObjectPattern(varDecl.id)) walkObjectPattern(varDecl.id, vineCompFnCtx.bindings, isConst); else if (isArrayPattern(varDecl.id)) walkArrayPattern(varDecl.id, vineCompFnCtx.bindings, isConst); return isAllLiteral; } function analyzeVineFnBodyStmtForBindings(analyzeCtx, stmt) { const { vineCompFnCtx } = analyzeCtx; let isAllLiteral = false; switch (stmt.type) { case "VariableDeclaration": isAllLiteral = analyzeVariableDeclarationForBindings(analyzeCtx, stmt); break; case "TSEnumDeclaration": vineCompFnCtx.bindings[stmt.id.name] = VineBindingTypes.LITERAL_CONST; break; case "FunctionDeclaration": case "ClassDeclaration": vineCompFnCtx.bindings[stmt.id.name] = VineBindingTypes.SETUP_CONST; break; default: break; } return isAllLiteral; } function getVineStyleSource(vineStyleArg) { let styleLang = "css"; let styleSource = ""; let range; if (isTaggedTemplateExpression(vineStyleArg)) { const { tag } = vineStyleArg; if (isIdentifier(tag)) { styleLang = tag.name; const styleSourceNode = vineStyleArg.quasi.quasis[0]; styleSource = styleSourceNode.value.raw; range = [styleSourceNode.start, styleSourceNode.end]; } } else if (isStringLiteral(vineStyleArg)) { styleSource = vineStyleArg.value; range = [vineStyleArg.start, vineStyleArg.end]; } else if (isTemplateLiteral(vineStyleArg)) { const styleSourceNode = vineStyleArg.quasis[0]; styleSource = styleSourceNode.value.raw; range = [styleSourceNode.start, styleSourceNode.end]; } return { styleSource, styleLang, range }; } function getTsMorph(vineCompilerHooks) { const isTsMorphDisabled = vineCompilerHooks.getCompilerCtx().options.tsMorphOptions?.disabled; if (isTsMorphDisabled) return; if (!vineCompilerHooks.getTsMorph) return; return vineCompilerHooks.getTsMorph(); } const analyzeVineProps = ({ vineCompilerHooks, vineCompFnCtx, vineFileCtx }, fnItselfNode) => { const formalParams = getFunctionParams(fnItselfNode); if (formalParams.length === 1) { const propsFormalParam = formalParams[0]; const defaultsFromDestructuredProps = {}; if (isObjectPattern(propsFormalParam)) { for (const property of propsFormalParam.properties) if (isRestElement(property)) { const restProp = property.argument; vineCompFnCtx.propsDestructuredNames[restProp.name] = { node: restProp, isRest: true }; } else if (isObjectProperty(property)) { const propItemKey = property.key; const propItemName = isIdentifier(propItemKey) ? propItemKey.name : propItemKey.value; const data = { node: propItemKey, isRest: false }; if (isIdentifier(property.value) && property.value.name !== propItemName) data.alias = property.value.name; else if (isAssignmentPattern(property.value)) { data.default = property.value.right; defaultsFromDestructuredProps[propItemName] = property.value.right; } vineCompFnCtx.bindings[propItemName] = VineBindingTypes.SETUP_REF; vineCompFnCtx.propsDestructuredNames[propItemName] = data; } } else vineCompFnCtx.propsAlias = propsFormalParam.name; const propsTypeAnnotation = propsFormalParam.typeAnnotation; if (!isTSTypeAnnotation(propsTypeAnnotation)) return; const { typeAnnotation } = propsTypeAnnotation; vineCompFnCtx.propsFormalParamType = typeAnnotation; const isTypeLiteralProps = isTSTypeLiteral(typeAnnotation); const isContainsGenericTypeParams = fnItselfNode.typeParameters ? fnItselfNode.typeParameters.params.length > 0 : false; const isTsMorphDisabled = vineCompilerHooks.getCompilerCtx().options.tsMorphOptions?.disabled; let tsMorphAnalyzedPropsInfo; let tsMorphCache; if (!isTypeLiteralProps || isContainsGenericTypeParams) { vineCompFnCtx.propsDefinitionBy = VinePropsDefinitionBy.typeReference; tsMorphCache = getTsMorph(vineCompilerHooks); if (tsMorphCache) tsMorphAnalyzedPropsInfo = resolveVineCompFnProps({ tsMorphCache, vineCompFnCtx, defaultsFromDestructuredProps }); } if (isTypeLiteralProps) typeAnnotation.members?.forEach((member) => { if (!isIdentifier(member.key) && !isStringLiteral(member.key) || !member.typeAnnotation) return; const propName = isIdentifier(member.key) ? member.key.name : member.key.value; const propType = vineFileCtx.getAstNodeContent(member.typeAnnotation.typeAnnotation); const propMeta = { isFromMacroDefine: false, isRequired: member.optional === void 0 ? true : !member.optional, isMaybeBool: isBasicBoolTypeNames(propType) || Boolean(tsMorphAnalyzedPropsInfo?.[propName]?.isMaybeBool), typeAnnotationRaw: propType }; vineCompFnCtx.props[propName] = propMeta; vineCompFnCtx.bindings[propName] ??= VineBindingTypes.PROPS; if (defaultsFromDestructuredProps[propName]) vineCompFnCtx.props[propName].default = defaultsFromDestructuredProps[propName]; if (!isIdentifier(member.key)) vineCompFnCtx.props[propName].nameNeedQuoted = true; }); else if (tsMorphCache && tsMorphAnalyzedPropsInfo) vineCompFnCtx.props = tsMorphAnalyzedPropsInfo; else if (!isTsMorphDisabled) vineCompilerHooks.onError(vineErr({ vineFileCtx, vineCompFnCtx }, { msg: `Failed to analyze props type info of '${vineCompFnCtx.fnName}'`, location: vineCompFnCtx.fnItselfNode?.loc })); } else if (formalParams.length === 0) { vineCompFnCtx.propsDefinitionBy = VinePropsDefinitionBy.macro; const allVinePropMacroCalls = getAllVinePropMacroCall(fnItselfNode); allVinePropMacroCalls.forEach(({ macroCall, identifier: propVarIdentifier, jsDocComments }) => { const propName = propVarIdentifier.name; const macroCalleeName = getVineMacroCalleeName(macroCall); const propMeta = { isFromMacroDefine: true, isRequired: macroCalleeName !== "vineProp.optional", isMaybeBool: false, typeAnnotationRaw: "any", macroDeclaredIdentifier: propVarIdentifier, jsDocComments: jsDocComments ?? [] }; vineCompFnCtx.props[propName] = propMeta; vineCompFnCtx.bindings[propName] = VineBindingTypes.SETUP_REF; vineCompFnCtx.macrosInfoForVolar.push({ macroCall, macroType: "vineProp", macroMeta: propMeta }); const tsMorphCache = getTsMorph(vineCompilerHooks); if (macroCalleeName === "vineProp.withDefault") { propMeta.default = macroCall.arguments[0]; if (!propMeta.default) return; propMeta.validator = macroCall.arguments[1]; propMeta.isMaybeBool = tsMorphCache ? checkForBoolean({ propName, tsMorphCache, vineCompilerHooks, vineCompFnCtx, babelNode: propMeta.default }) : isBooleanLiteral(propMeta.default); propMeta.isRequired = false; const inferredType = tryInferExpressionTSType(propMeta.default); propMeta.typeAnnotationRaw = inferredType; } else propMeta.validator = macroCall.arguments[0]; const macroCallTypeParamNode = getVinePropCallTypeParams(macroCall); if (macroCallTypeParamNode) { const macroCallTypeParam = vineFileCtx.getAstNodeContent(macroCallTypeParamNode); propMeta.isMaybeBool = tsMorphCache ? checkForBoolean({ propName, tsMorphCache, vineCompilerHooks, vineCompFnCtx, babelNode: macroCallTypeParamNode }) : macroCallTypeParam === "boolean"; propMeta.typeAnnotationRaw = macroCallTypeParam; } }); } }; const analyzeVineValidators = ({ vineCompilerHooks, vineCompFnCtx, vineFileCtx }, fnItselfNode) => { let vineValidatorsMacroCall; _breakableTraverse(fnItselfNode, (node) => { if (isVineValidators(node)) { vineValidatorsMacroCall = node; throw exitTraverse; } }); if (!vineValidatorsMacroCall || !vineValidatorsMacroCall.arguments[0] || !isObjectExpression(vineValidatorsMacroCall.arguments[0])) return; if (vineCompFnCtx.propsDefinitionBy === VinePropsDefinitionBy.macro) { vineCompilerHooks.onError(vineErr({ vineFileCtx, vineCompFnCtx }, { msg: "vineValidators macro call can only be used when props are defined by annotation", location: vineCompFnCtx.fnItselfNode?.loc })); return; } const validators = vineValidatorsMacroCall.arguments[0]; for (const validatorDef of validators.properties) if (isObjectProperty(validatorDef)) { const { key, value } = validatorDef; if (!isStringLiteral(key) && !isIdentifier(key)) continue; if (!isBabelFunctionTypes(value)) continue; const propName = isStringLiteral(key) ? key.value : key.name; const validatorFn = value; const propsDef = vineCompFnCtx.props[propName]; if (!propsDef) continue; propsDef.validator = validatorFn; } else if (isObjectMethod(validatorDef)) vineCompilerHooks.onError(vineErr({ vineFileCtx, vineCompFnCtx }, { msg: "Please use function expression to define validator instead of an object method", location: validatorDef.loc })); vineCompFnCtx.macrosInfoForVolar.push({ macroType: "vineValidators", macroCall: vineValidatorsMacroCall }); }; const analyzeVineEmits = (analyzeCtx, fnItselfNode) => { const { vineCompFnCtx } = analyzeCtx; let vineEmitsMacroCall; let parentVarDecl; _breakableTraverse(fnItselfNode, { enter(descendant, parent) { if (isVineEmits(descendant)) { vineEmitsMacroCall = descendant; const foundVarDeclAncestor = parent.find((ancestor) => isVariableDeclarator(ancestor.node)); parentVarDecl = foundVarDeclAncestor?.node; vineCompFnCtx.macrosInfoForVolar.push({ macroType: "vineEmits", macroCall: vineEmitsMacroCall }); throw exitTraverse; } } }); if (!vineEmitsMacroCall) return; const typeParam = vineEmitsMacroCall.typeParameters?.params[0]; const callArg = vineEmitsMacroCall.arguments[0]; if (typeParam && isTSTypeLiteral(typeParam)) { vineCompFnCtx.emitsTypeParam = typeParam; const emitsTypeLiteralProps = typeParam.members; emitsTypeLiteralProps.forEach((prop) => { const propName = getTSTypeLiteralPropertySignatureName(prop); vineCompFnCtx.emits.push(propName); }); } else if (isArrayExpression(callArg)) { vineCompFnCtx.emitsDefinitionByNames = true; callArg.elements.forEach((el) => { if (isStringLiteral(el)) vineCompFnCtx.emits.push(el.value); }); } if (parentVarDecl) { const emitsAlias = parentVarDecl.id.name; vineCompFnCtx.emitsAlias = emitsAlias; vineCompFnCtx.bindings[emitsAlias] = VineBindingTypes.SETUP_CONST; } }; const analyzeVineBindings = (analyzeCtx, fnItselfNode) => { const { vineFileCtx, vineCompFnCtx } = analyzeCtx; const notContainsMacroStatements = []; const fnBody = fnItselfNode.body; if (!isBlockStatement(fnBody)) return; for (const stmt of fnBody.body) { let hasMacroCall = false; _breakableTraverse(stmt, (node) => { if (isVineMacroCallExpression(node)) { hasMacroCall = true; throw exitTraverse; } }); if (!hasMacroCall) notContainsMacroStatements.push(stmt); } for (const stmt of notContainsMacroStatements) { const isAllLiteral = analyzeVineFnBodyStmtForBindings(analyzeCtx, stmt); if (isAllLiteral) vineCompFnCtx.hoistSetupStmts.push(stmt); } for (const [importName, { isType, isNamespace, isDefault, source }] of Object.entries(vineFileCtx.userImports)) { if (isType) continue; const isSetupConst = isNamespace || isDefault && source.endsWith(".vue") || source === "vue"; vineCompFnCtx.bindings[importName] = isSetupConst ? VineBindingTypes.SETUP_CONST : VineBindingTypes.SETUP_MAYBE_REF; } const allTopLevelDeclStmts = vineFileCtx.root.program.body.filter((stmt) => isDeclaration(stmt)); for (let declStmt of allTopLevelDeclStmts) { if (isVineCompFnDecl(declStmt)) { const pickedInfos = getFunctionPickedInfos(declStmt); pickedInfos.forEach(({ fnName }) => { vineCompFnCtx.bindings[fnName] = VineBindingTypes.SETUP_CONST; }); continue; } if ((isExportDefaultDeclaration(declStmt) || isExportNamedDeclaration(declStmt)) && isDeclaration(declStmt.declaration)) declStmt = declStmt.declaration; if (isVariableDeclaration(declStmt)) { for (const decl of declStmt.declarations) if (isVariableDeclarator(decl)) { if (isIdentifier(decl.id)) { const name = decl.id.name; vineCompFnCtx.bindings[name] ??= declStmt.kind === "const" ? VineBindingTypes.LITERAL_CONST : VineBindingTypes.SETUP_LET; } else if (isObjectPattern(decl.id)) { for (const p of decl.id.properties) if (p.type === "ObjectProperty" && isIdentifier(p.key)) { const name = p.key.name; vineCompFnCtx.bindings[name] ??= declStmt.kind === "const" ? VineBindingTypes.LITERAL_CONST : VineBindingTypes.SETUP_LET; } else if (p.type === "RestElement" && isIdentifier(p.argument)) { const name = p.argument.name; vineCompFnCtx.bindings[name] ??= declStmt.kind === "const" ? VineBindingTypes.LITERAL_CONST : VineBindingTypes.SETUP_LET; } } else if (isArrayPattern(decl.id)) decl.id.elements.forEach((el) => { if (el && el.type === "Identifier") { const name = el.name; vineCompFnCtx.bindings[name] ??= declStmt.kind === "const" ? VineBindingTypes.LITERAL_CONST : VineBindingTypes.SETUP_LET; } }); } } else if ((isFunctionDeclaration(declStmt) || isClassDeclaration(declStmt)) && declStmt.id) vineCompFnCtx.bindings[declStmt.id.name] = VineBindingTypes.LITERAL_CONST; else if (isTSEnumDeclaration(declStmt)) vineCompFnCtx.bindings[declStmt.id.name] ??= VineBindingTypes.LITERAL_CONST; } }; const analyzeVineStyle = ({ vineFileCtx, vineCompFnCtx, vineCompilerHooks }, fnItselfNode) => { let vineStyleMacroCalls = []; _breakableTraverse(fnItselfNode, (node) => { if (isVineStyle(node)) vineStyleMacroCalls.push(node); }); if (!vineStyleMacroCalls.length) return; for (const vineStyleMacroCall of vineStyleMacroCalls) { const macroCalleeName = getVineMacroCalleeName(vineStyleMacroCall); const vineStyleArg = vineStyleMacroCall.arguments[0]; if (!vineStyleArg) return; const { styleLang, styleSource, range } = getVineStyleSource(vineStyleArg); const isExternalFilePathSource = macroCalleeName === "vineStyle.import" || macroCalleeName === "vineStyle.import.scoped"; const scoped = macroCalleeName === "vineStyle.scoped" || macroCalleeName === "vineStyle.import.scoped"; const styleMeta = { lang: styleLang, source: styleSource, isExternalFilePathSource, range, scoped, fileCtx: vineFileCtx, compCtx: vineCompFnCtx }; vineCompFnCtx.macrosInfoForVolar.push({ macroType: "vineStyle", macroCall: vineStyleMacroCall }); if (isExternalFilePathSource) { vineCompFnCtx.externalStyleFilePaths.push(styleSource); const fileExt = SUPPORTED_STYLE_FILE_EXTS.find((ext) => styleSource.endsWith(ext)); if (fileExt) styleMeta.lang = fileExt.slice(1); else vineCompilerHooks.onError(vineErr({ vineFileCtx, vineCompFnCtx }, { msg: "Invalid external style file", location: vineStyleArg.loc })); } if (vineCompFnCtx.scopeId) { vineFileCtx.styleDefine[vineCompFnCtx.scopeId] ??= []; vineFileCtx.styleDefine[vineCompFnCtx.scopeId].push(styleMeta); } if (isExternalFilePathSource) continue; const cssvarsValueList = parseCssVars([styleSource]); if (cssvarsValueList.length > 0) { vineCompFnCtx.cssBindings ??= {}; cssvarsValueList.forEach((value) => { vineCompFnCtx.cssBindings[value] = hashId(`${vineCompFnCtx.fnName}__${value}`); }); } } }; const analyzeVineCustomElement = ({ vineCompFnCtx }, fnItselfNode) => { _breakableTraverse(fnItselfNode, (node) => { if (isVineCustomElement(node)) { vineCompFnCtx.isCustomElement = true; throw exitTraverse; } }); }; const analyzeVineSlots = ({ vineCompFnCtx }, fnItselfNode) => { let vineSlotsMacroCall; let parentVarDecl; _breakableTraverse(fnItselfNode, (node, parent) => { if (isVineSlots(node)) { vineSlotsMacroCall = node; const foundVarDeclAncestor = parent.find((ancestor) => isVariableDeclarator(ancestor.node)); parentVarDecl = foundVarDeclAncestor?.node; vineCompFnCtx.macrosInfoForVolar.push({ macroType: "vineSlots", macroCall: node }); throw exitTraverse; } }); if (!vineSlotsMacroCall) return; const typeParam = vineSlotsMacroCall.typeParameters?.params[0]; if (!typeParam) return; const slotsTypeLiteralProps = typeParam.members; for (const prop of slotsTypeLiteralProps) if (isTSPropertySignature(prop) && isIdentifier(prop.key)) { const fnFirstParamType = ((prop.typeAnnotation?.typeAnnotation)?.parameters?.[0]?.typeAnnotation)?.typeAnnotation; if (fnFirstParamType) vineCompFnCtx.slots[prop.key.name] = { props: fnFirstParamType }; } else if (isTSMethodSignature(prop) && isIdentifier(prop.key)) { const fnFirstParamType = prop.parameters[0].typeAnnotation.typeAnnotation; vineCompFnCtx.slots[prop.key.name] = { props: fnFirstParamType }; } if (parentVarDecl && isIdentifier(parentVarDecl.id)) vineCompFnCtx.slotsAlias = parentVarDecl.id.name; }; const analyzeVineModel = ({ vineCompFnCtx }, fnItselfNode) => { const vineModelMacroCalls = []; _breakableTraverse(fnItselfNode, (node, parent) => { if (isVineModel(node)) { const foundVarDeclAncestor = parent.find((ancestor) => isVariableDeclarator(ancestor.node)); vineModelMacroCalls.push({ macroCall: node, parentVarDecl: foundVarDeclAncestor?.node }); } }); for (const { macroCall, parentVarDecl } of vineModelMacroCalls) { if (!parentVarDecl || !isIdentifier(parentVarDecl.id)) continue; const varName = parentVarDecl.id.name; const typeParameter = macroCall.typeParameters?.params[0]; if (!macroCall.arguments.length) { vineCompFnCtx.vineModels.modelValue = { varName, modelModifiersName: DEFAULT_MODEL_MODIFIERS_NAME, modelOptions: null, typeParameter }; continue; } else if (macroCall.arguments.length === 1) if (isStringLiteral(macroCall.arguments[0])) { const modelName = macroCall.arguments[0].value; vineCompFnCtx.vineModels[modelName] = { varName, modelModifiersName: `${modelName}Modifiers`, modelOptions: null, typeParameter }; } else vineCompFnCtx.vineModels.modelValue = { varName, modelModifiersName: DEFAULT_MODEL_MODIFIERS_NAME, modelOptions: macroCall.arguments[0], typeParameter }; else { const modelName = macroCall.arguments[0].value; vineCompFnCtx.vineModels[modelName] = { varName, modelModifiersName: `${modelName}Modifiers`, modelOptions: macroCall.arguments[1] }; } } for (const [modelName, modelDef] of Object.entries(vineCompFnCtx.vineModels)) { vineCompFnCtx.bindings[modelName] = VineBindingTypes.PROPS; vineCompFnCtx.bindings[modelDef.varName] = VineBindingTypes.SETUP_REF; } }; const analyzeUseTemplateRef = ({ vineCompFnCtx }, fnItselfNode) => { const useTemplateRefMacroCalls = []; _breakableTraverse(fnItselfNode, (node) => { if (isUseTemplateRefCall(node)) useTemplateRefMacroCalls.push(node); }); if (!useTemplateRefMacroCalls.length) return; vineCompFnCtx.macrosInfoForVolar.push(...useTemplateRefMacroCalls.map((useTemplateRefCall) => ({ macroType: "useTemplateRef", macroCall: useTemplateRefCall }))); }; const analyzeRunners = [ analyzeVineProps, analyzeVineValidators, analyzeVineEmits, analyzeVineExpose, analyzeVineSlots, analyzeVineModel, analyzeVineOptions, analyzeVineBindings, analyzeVineStyle, analyzeVineCustomElement, analyzeUseTemplateRef ]; function analyzeDifferentKindVineFunctionDecls(analyzeCtx) { const { vineCompFnCtx } = analyzeCtx; const { fnItselfNode } = vineCompFnCtx; if (!fnItselfNode) return; analyzeRunners.forEach((exec) => exec(analyzeCtx, fnItselfNode)); } function analyzeFileImportStmts(vineFileCtx) { const { root } = vineFileCtx; const fileImportStmts = getImportStatements(root); if (!fileImportStmts.length) return; for (const importStmt of fileImportStmts) { const source = importStmt.source.value; const isImportTypeStmt = importStmt.importKind === "type"; const allSpecifiers = importStmt.specifiers; for (const spec of allSpecifiers) { const importMeta = { source, isType: isImportTypeStmt }; if (isImportSpecifier(spec)) { const importedName = isStringLiteral(spec.imported) ? spec.imported.value : spec.imported.name; const localName = spec.local.name; if (spec.importKind === "type") importMeta.isType = true; else if (importedName === "default") importMeta.isDefault = true; if (source === "vue") vineFileCtx.vueImportAliases[importedName] = localName || importedName; vineFileCtx.userImports[localName] = importMeta; } else if (isImportNamespaceSpecifier(spec)) { importMeta.isNamespace = true; vineFileCtx.userImports[spec.local.name] = importMeta; } else if (isImportDefaultSpecifier(spec)) { importMeta.isDefault = true; vineFileCtx.userImports[spec.local.name] = importMeta; } const specLocalName = spec.local.name; importMeta.isUsedInTemplate = (compFnCtx) => isImportUsed(compFnCtx, specLocalName); } } const lastImportStmt = fileImportStmts[fileImportStmts.length - 1]; vineFileCtx.importsLastLine = lastImportStmt.loc; } function buildVineCompFnCtx(vineCompilerHooks, vineFileCtx, vineFnInfo) { const { fnDeclNode, fnName, fnItselfNode } = vineFnInfo; const { templateReturn, templateStringNode } = findVineTagTemplateStringReturn(fnDeclNode); const scopeId = hashId(`${vineFileCtx.fileId}:${fnName}`); const templateStringQuasiNode = templateStringNode?.quasi.quasis[0]; const templateSource = templateStringQuasiNode?.value.raw