@vue-vine/compiler
Version:
Compiler for Vue Vine
1,307 lines (1,295 loc) • 142 kB
JavaScript
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