UNPKG

@vue-jsx-vapor/macros

Version:
521 lines (507 loc) 25.5 kB
const require_chunk = require('./chunk-CUT6urMc.cjs'); let __vue_macros_common = require("@vue-macros/common"); __vue_macros_common = require_chunk.__toESM(__vue_macros_common); let hash_sum = require("hash-sum"); hash_sum = require_chunk.__toESM(hash_sum); //#region src/core/helper/use-model.ts?raw var use_model_default = "import { customRef, watchSyncEffect } from \"vue\";\nexport function useModel(props, name, options = {}) {\n const res = customRef((track, trigger) => {\n let localValue = options && options.default;\n let prevEmittedValue;\n watchSyncEffect(() => {\n const propValue = props[name];\n if (!Object.is(prevEmittedValue, propValue)) {\n localValue = propValue;\n trigger();\n }\n });\n return {\n get() {\n track();\n return options.get ? options.get(localValue) : localValue;\n },\n set(value) {\n if (Object.is(value, localValue)) return;\n localValue = value;\n trigger();\n const emittedValue = prevEmittedValue = options.set ? options.set(value) : value;\n for (const emit of [props[`onUpdate:${name}`]].flat()) {\n if (typeof emit === \"function\") emit(emittedValue);\n }\n }\n };\n });\n res[Symbol.iterator] = () => {\n let i = 0;\n return {\n next() {\n if (i < 2) {\n return {\n value: i++ ? props[`${name}Modifiers`] || {} : res,\n done: false\n };\n } else {\n return { done: true };\n }\n }\n };\n };\n return res;\n}\n"; //#endregion //#region src/core/helper/with-defaults.ts?raw var with_defaults_default = "function resolveDefaultProps(paths) {\n const result = {};\n for (const path of Object.keys(paths)) {\n const segments = path.split(/[.?[\\]]/).filter(Boolean);\n let current = result;\n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i];\n if (i === segments.length - 1) {\n current[segment] = paths[path];\n } else {\n if (!current[segment]) {\n current[segment] = Number.isNaN(Number(segments[i + 1])) ? {} : [];\n }\n current = current[segment];\n }\n }\n }\n return result;\n}\nexport function createPropsDefaultProxy(props, defaults) {\n const defaultProps = resolveDefaultProps(defaults);\n const result = {};\n for (const key of [\n .../* @__PURE__ */ new Set([...Object.keys(props), ...Object.keys(defaultProps)])\n ]) {\n Object.defineProperty(result, key, {\n enumerable: true,\n get: () => props[key] === void 0 ? defaultProps[key] : props[key]\n });\n }\n return result;\n}\n"; //#endregion //#region src/core/helper/index.ts const helperPrefix = "/vue-jsx-vapor/macros"; const useModelHelperId = `${helperPrefix}/use-model`; const withDefaultsHelperId = `${helperPrefix}/with-defaults`; //#endregion //#region src/core/utils.ts function prependFunctionalNode(node, s, result) { const isBlockStatement = node.body.type === "BlockStatement"; const start = node.body.extra?.parenthesized ? node.body.extra.parenStart : node.body.start; s.appendRight(start + (isBlockStatement ? 1 : 0), `${result};${!isBlockStatement ? "return " : ""}`); if (!isBlockStatement) { s.appendLeft(start, "{"); s.appendRight(node.end, "}"); } } function isFunctionalNode(node) { return !!(node && (node.type === "ArrowFunctionExpression" || node.type === "FunctionDeclaration" || node.type === "FunctionExpression")); } function getParamsStart(node, code) { return node.params[0] ? node.params[0].start : node.start + (code.slice(node.start, node.body.start).match(/\(\s*\)/)?.index || 0) + 1; } function getDefaultValue(node) { if (node.type === "TSNonNullExpression") return getDefaultValue(node.expression); if (node.type === "TSAsExpression") return getDefaultValue(node.expression); return node; } //#endregion //#region src/core/restructure.ts function restructure(s, node, options = {}) { let index = 0; const propList = []; for (const param of node.params) { const path = `${__vue_macros_common.HELPER_PREFIX}props${index++ || ""}`; const props = getProps(s, options, param, path); if (props) { s.overwrite(param.start, param.end, path); propList.push(...props); } } if (propList.length) { const defaultValues = {}; const rests = []; for (const prop of propList) { if (prop.isRest) rests.push(prop); if (prop.defaultValue) { const paths = prop.path.split(/\.|\[/); if (!options.skipDefaultProps || paths.length !== 1) (defaultValues[paths[0]] ??= []).push(prop); } } for (const [index$1, rest] of rests.entries()) prependFunctionalNode(node, s, options.generateRestProps?.(rest.name, index$1, rests) ?? `\nconst ${rest.name} = ${(0, __vue_macros_common.importHelperFn)(s, 0, "createPropsRestProxy")}(${rest.path}, [${rest.value}])`); for (const [path, values] of Object.entries(defaultValues)) prependFunctionalNode(node, s, `\n${path} = ${(0, __vue_macros_common.importHelperFn)(s, 0, "createPropsDefaultProxy", void 0, options.withDefaultsFrom ?? withDefaultsHelperId)}(${path}, {${values.map((i) => `'${i.path.replace(path, "")}${i.value}': ${i.defaultValue}`).join(", ")}})`); (0, __vue_macros_common.walkIdentifiers)(node.body, (id, parent) => { const prop = propList.find((i) => i.name === id.name); if (prop && !prop.isRest) s.overwrite(id.start, id.end, `${parent?.type === "ObjectProperty" && parent.shorthand ? `${id.name}: ` : ""}${prop.path}${prop.value}`); }, false); } return propList; } function getProps(s, options, node, path = "", props = []) { const properties = node.type === "ObjectPattern" ? node.properties : node.type === "ArrayPattern" ? node.elements : []; if (!properties.length) return; const propNames = []; properties.forEach((prop, index) => { if (prop?.type === "Identifier") { props.push({ name: prop.name, path, value: `[${index}]` }); propNames.push(`'${prop.name}'`); } else if (prop?.type === "AssignmentPattern" && prop.left.type === "Identifier") { props.push({ path, name: prop.left.name, value: `[${index}]`, defaultValue: s.sliceNode(getDefaultValue(prop.right)) }); propNames.push(`'${prop.left.name}'`); } else if (prop?.type === "ObjectProperty" && prop.key.type === "Identifier") { if (prop.value.type === "AssignmentPattern") if (prop.value.left.type === "Identifier") props.push({ path, name: prop.value.left.name, value: `.${prop.key.name}`, defaultValue: s.sliceNode(getDefaultValue(prop.value.right)) }); else getProps(s, options, prop.value.left, `${path}.${prop.key.name}`, props); else if (!getProps(s, options, prop.value, `${path}.${prop.key.name}`, props)) { const name = prop.value.type === "Identifier" ? prop.value.name : prop.key.name; props.push({ path, name, value: `.${prop.key.name}` }); } propNames.push(`'${prop.key.name}'`); } else if (prop?.type === "RestElement" && prop.argument.type === "Identifier" && !prop.argument.name.startsWith(`${__vue_macros_common.HELPER_PREFIX}props`)) props.push({ path, name: prop.argument.name, value: propNames.join(", "), isRest: true }); else if (prop) getProps(s, options, prop, `${path}[${index}]`, props); }); return props.length ? props : void 0; } //#endregion //#region src/core/define-component/await.ts function transformAwait(root, s) { if (root.body.type !== "BlockStatement") return; let hasAwait = false; for (const node of root.body.body) if (node.type === "VariableDeclaration" && !node.declare || node.type.endsWith("Statement")) { const scope = [root.body.body]; (0, __vue_macros_common.walkAST)(node, { enter(child, parent) { if ((0, __vue_macros_common.isFunctionType)(child)) this.skip(); if (child.type === "BlockStatement") scope.push(child.body); if (child.type === "AwaitExpression") { hasAwait = true; processAwait(s, child, !!scope.at(-1)?.some((n, i) => { return (scope.length === 1 || i > 0) && n.type === "ExpressionStatement" && n.start === child.start; }), parent.type === "ExpressionStatement"); } }, leave(node$1) { if (node$1.type === "BlockStatement") scope.pop(); } }); } if (hasAwait) s.prependLeft(root.body.start + 1, `\nlet __temp, __restore\n`); } function processAwait(s, node, needSemi, isStatement) { const argumentStart = node.argument.extra && node.argument.extra.parenthesized ? node.argument.extra.parenStart : node.argument.start; const argumentStr = s.slice(argumentStart, node.argument.end); const containsNestedAwait = /\bawait\b/.test(argumentStr); s.overwrite(node.start, argumentStart, `${needSemi ? `;` : ``}(\n ([__temp,__restore] = ${(0, __vue_macros_common.importHelperFn)(s, 0, `withAsyncContext`)}(${containsNestedAwait ? `async ` : ``}() => `); s.appendLeft(node.end, `)),\n ${isStatement ? `` : `__temp = `}await __temp,\n __restore()${isStatement ? `` : `,\n __temp`}\n)`); } //#endregion //#region src/core/define-component/return.ts function transformReturn(root, s) { const node = root.body.type === "BlockStatement" ? root.body.body.find((node$1) => node$1.type === "ReturnStatement")?.argument : root.body; if (!node || isFunctionalNode(node)) return; s.appendRight(node.extra?.parenthesized ? node.extra.parenStart : node.start, "() => "); } //#endregion //#region src/core/define-component/index.ts function transformDefineComponent(root, propsName, macros, s, autoReturnFunction = false) { if (!macros.defineComponent) return; const defineComponentName = s.sliceNode(macros.defineComponent.callee); if (defineComponentName && !["defineComponent", "defineVaporComponent"].includes(defineComponentName)) (0, __vue_macros_common.importHelperFn)(s, 0, "defineComponent", defineComponentName); let hasRestProp = false; const props = {}; if (root.params[0]) { if (root.params[0].type === "Identifier") { getWalkedIds(root, propsName).forEach((id) => props[id] = null); prependFunctionalNode(root, s, `const ${propsName} = ${(0, __vue_macros_common.importHelperFn)(s, 0, "useFullProps", void 0, "vue-jsx-vapor")}()`); s.overwrite(root.params[0].start, root.params[0].end, root.params.length > 1 ? `${__vue_macros_common.HELPER_PREFIX}props` : root.start === root.params[0].start ? "()" : ""); } else if (root.params[0].type === "ObjectPattern") { const restructuredProps = root.params[0]; for (const prop of restructuredProps.properties) { if (prop.type !== "ObjectProperty" || prop.key.type !== "Identifier") continue; const propName = prop.key.name; if (prop.value.type !== "AssignmentPattern") { props[propName] = null; continue; } const defaultValue = getDefaultValue(prop.value.right); let isRequired = false; (0, __vue_macros_common.walkAST)(prop.value.right, { enter(node) { if (node.type === "TSNonNullExpression") { isRequired = true; this.skip(); } } }); const propOptions = []; if (isRequired) propOptions.push("required: true"); if (defaultValue) { const { value, type, skipFactory } = getTypeAndValue(s, defaultValue); if (type) propOptions.push(`type: ${type}`); if (value) propOptions.push(`default: ${value}`); if (skipFactory) propOptions.push("skipFactory: true"); } if (propOptions.length) props[propName] = `{ ${propOptions.join(", ")} }`; else props[propName] = null; } restructure(s, root, { skipDefaultProps: true, generateRestProps: (restPropsName, index, list) => { if (index === list.length - 1) { hasRestProp = true; return `const ${restPropsName} = ${(0, __vue_macros_common.importHelperFn)(s, 0, "useAttrs")}()`; } } }); } } transformDefineModel$1(s, macros.defineModel, props); const propsString = Object.entries(props).map(([key, value]) => `'${key}': ${value}`).join(", \n"); if (propsString) { const resolvedPropsString = `${hasRestProp ? "inheritAttrs: false, " : ""}props: {\n${propsString}\n}`; const compOptions = macros.defineComponent.arguments[1]; if (!compOptions) s.appendRight(root.end, `, { ${resolvedPropsString} }`); else if (compOptions.type === "ObjectExpression") { s.appendLeft(compOptions.start, `{ ${resolvedPropsString}, ...`); s.appendRight(compOptions.end, " }"); } } transformAwait(root, s); if (autoReturnFunction) transformReturn(root, s); } function getWalkedIds(root, propsName) { const walkedIds = /* @__PURE__ */ new Set(); (0, __vue_macros_common.walkIdentifiers)(root.body, (id, parent) => { if (id.name === propsName && (parent?.type === "MemberExpression" || parent?.type === "JSXMemberExpression" || parent?.type === "OptionalMemberExpression")) { const prop = parent.property.type === "Identifier" || parent.property.type === "JSXIdentifier" ? parent.property.name : parent.property.type === "StringLiteral" ? parent.property.value : ""; if (prop) walkedIds.add(prop); } }); return walkedIds; } function transformDefineModel$1(s, defineModel, props) { for (const { expression, isRequired } of defineModel || []) { const modelOptions = expression.arguments[0]?.type === "ObjectExpression" ? expression.arguments[0] : expression.arguments[1]?.type === "ObjectExpression" ? expression.arguments[1] : void 0; const options = {}; if (isRequired) options.required = true; let defaultValueNode; for (const prop of modelOptions?.properties || []) if (prop.type === "ObjectProperty" && prop.key.type === "Identifier" && [ "validator", "type", "required", "default" ].includes(prop.key.name)) { if (prop.key.name === "default") defaultValueNode = prop.value; options[prop.key.name] = s.sliceNode(prop.value); } if (defaultValueNode && !options.type) { const { value, type, skipFactory } = getTypeAndValue(s, defaultValueNode); if (type) options.type = type; if (value) options.default = value; if (skipFactory) options.skipFactory = "true"; } const propName = expression.arguments[0]?.type === "StringLiteral" ? expression.arguments[0].value : "modelValue"; props[propName] = Object.keys(options).length ? `{ ${Object.entries(options).map(([key, value]) => `${key}: ${value}`).join(", ")} }` : null; props[`onUpdate:${propName}`] = null; props[`${propName === "modelValue" ? "model" : propName}Modifiers`] = null; } } function getTypeAndValue(s, node) { let value = ""; let type = ""; let skipFactory = false; if (node.type === "StringLiteral") { type = "String"; value = `'${node.value}'`; } else if (node.type === "BooleanLiteral") { type = "Boolean"; value = String(node.value); } else if (node.type === "NumericLiteral") { type = "Number"; value = String(node.value); } else if (node.type === "ObjectExpression") { type = "Object"; value = `() => (${s.sliceNode(node)})`; } else if (node.type === "ArrayExpression") { type = "Array"; value = `() => (${s.sliceNode(node)})`; } else if (isFunctionalNode(node)) { type = "Function"; value = s.sliceNode(node); } else if (node.type === "Identifier") if (node.name === "undefined") value = "undefined"; else { skipFactory = true; value = s.sliceNode(node); } else if (node.type === "NullLiteral") value = "null"; return { value, type, skipFactory }; } //#endregion //#region src/core/define-expose.ts function transformDefineExpose(node, s) { s.overwriteNode(node.callee, ";"); s.appendRight(node.arguments[0]?.start || node.end - 1, `${(0, __vue_macros_common.importHelperFn)(s, 0, "getCurrentInstance", void 0, "vue-jsx-vapor")}().exposed = `); } //#endregion //#region src/core/define-model.ts function transformDefineModel(node, propsName, s) { s.overwriteNode(node.callee, (0, __vue_macros_common.importHelperFn)(s, 0, "useModel", void 0, useModelHelperId)); s.appendRight(node.arguments[0]?.start || node.end - 1, `${propsName}, ${node.arguments[0]?.type !== "StringLiteral" ? `'modelValue',` : ""}`); } //#endregion //#region src/core/define-slots.ts function transformDefineSlots(node, s) { s.overwrite(node.start, node.arguments[0]?.start && node.arguments[0].start - 1 || node.typeArguments?.end || node.callee.end, `Object.assign`); const slots = `${(0, __vue_macros_common.importHelperFn)(s, 0, "useSlots")}()`; s.appendLeft(node.end - 1, `${node.arguments[0] ? "," : "{}, "}${slots}`); } //#endregion //#region src/core/define-style.ts function transformDefineStyle(defineStyle, index, root, s, importMap, { defineSlots }) { const { expression, lang, isCssModules } = defineStyle; if (expression.arguments[0]?.type !== "TemplateLiteral") return; let css = s.sliceNode(expression.arguments[0]).slice(1, -1); const scopeId = (0, hash_sum.default)(css); const vars = /* @__PURE__ */ new Map(); expression.arguments[0].expressions.forEach((exp) => { const cssVar = s.sliceNode(exp); const cssVarId = toCssVarId(cssVar, `--${scopeId}-`); s.overwrite(exp.start - 2, exp.end + 1, `var(${cssVarId})`); vars.set(cssVarId, cssVar); }); let returnExpression = root && getReturnStatement(root); if (isFunctionalNode(returnExpression)) returnExpression = getReturnStatement(returnExpression); if (vars.size && returnExpression) { const children = returnExpression.type === "JSXElement" ? [returnExpression] : returnExpression.type === "JSXFragment" ? returnExpression.children : []; const varString = Array.from(vars.entries()).map(([key, value]) => `'${key}': ${value}`).join(", "); for (const child of children) if (child.type === "JSXElement") s.appendRight(child.openingElement.name.end, ` {...{style:{${varString}}}}`); } let scoped = !!root; if (expression.arguments[1]?.type === "ObjectExpression") { for (const prop of expression.arguments[1].properties) if (prop.type === "ObjectProperty" && prop.key.type === "Identifier" && prop.key.name === "scoped" && prop.value.type === "BooleanLiteral") scoped = prop.value.value; } if (scoped && root) { const slotNames = defineSlots?.id ? defineSlots.id.type === "Identifier" ? defineSlots.id.name : defineSlots.id.type === "ObjectPattern" ? defineSlots.id.properties.map((prop) => s.sliceNode(prop.type === "RestElement" ? prop.argument : prop.value)) : [] : []; (0, __vue_macros_common.walkAST)(root, { enter(node) { if (node.type === "JSXElement" && s.sliceNode(node.openingElement.name) !== "template") { let subfix = ""; if (slotNames.length) { const name = s.sliceNode(node.openingElement.name.type === "JSXMemberExpression" ? node.openingElement.name.object : node.openingElement.name); subfix = slotNames.includes(name) ? "-s" : ""; } s.appendRight(node.openingElement.name.end, ` data-v-${scopeId}${subfix}=""`); } } }); } css = s.sliceNode(expression.arguments[0]).slice(1, -1).replaceAll(/\/\/(.*)(?=\n)/g, "/*$1*/"); const importId = `${helperPrefix}/define-style/${index}?scopeId=${scopeId}&scoped=${scoped}&lang.${isCssModules ? "module." : ""}${lang}`; importMap.set(importId, css); s.appendLeft(0, isCssModules ? `import style${index} from "${importId}";` : `import "${importId}";`); s.overwriteNode(expression, isCssModules ? `style${index}` : ""); } function getReturnStatement(root) { if (root.body.type === "BlockStatement") { const returnStatement = root.body.body.find((node) => node.type === "ReturnStatement"); if (returnStatement) return returnStatement.argument; } else return root.body; } function toCssVarId(name, prefix = "") { return prefix + name.replaceAll(/\W/g, (searchValue, replaceValue) => { return searchValue === "." ? "-" : name.charCodeAt(replaceValue).toString(); }); } //#endregion //#region src/core/index.ts function transformJsxMacros(code, id, importMap, options) { const s = new __vue_macros_common.MagicStringAST(code); const lang = (0, __vue_macros_common.getLang)(id); if (lang === "dts") return; const rootMap = getRootMap((0, __vue_macros_common.babelParse)(s.original, lang), s, options); let defineStyleIndex = 0; for (const [root, macros] of rootMap) { macros.defineStyle?.forEach((defineStyle) => { transformDefineStyle(defineStyle, defineStyleIndex++, root, s, importMap, macros); }); if (root === void 0) continue; let propsName = `${__vue_macros_common.HELPER_PREFIX}props`; if (root.params[0]) { if (root.params[0].type === "Identifier") propsName = root.params[0].name; else if (root.params[0].type === "ObjectPattern") { const lastProp = root.params[0].properties.at(-1); if (!macros.defineComponent && lastProp?.type === "RestElement" && lastProp.argument.type === "Identifier") propsName = lastProp.argument.name; else s.appendRight(root.params[0].extra?.trailingComma ? root.params[0].extra?.trailingComma + 1 : lastProp?.end || root.params[0].end - 1, `${!root.params[0].extra?.trailingComma && root.params[0].properties.length ? "," : ""} ...${__vue_macros_common.HELPER_PREFIX}props`); } } else if (macros.defineModel?.length) s.appendRight(getParamsStart(root, s.original), propsName); if (macros.defineComponent) transformDefineComponent(root, propsName, macros, s, options.defineComponent?.autoReturnFunction); if (macros.defineModel?.length) macros.defineModel.forEach(({ expression }) => { transformDefineModel(expression, propsName, s); }); if (macros.defineSlots) transformDefineSlots(macros.defineSlots.expression, s); if (macros.defineExpose) transformDefineExpose(macros.defineExpose, s); } return (0, __vue_macros_common.generateTransform)(s, id); } function getRootMap(ast, s, options) { const parents = []; const rootMap = /* @__PURE__ */ new Map(); (0, __vue_macros_common.walkAST)(ast, { enter(node, parent) { parents.unshift(parent); const root = isFunctionalNode(parents[1]) ? parents[1] : void 0; if (root && parents[2]?.type === "CallExpression" && options.defineComponent.alias.includes(s.sliceNode(parents[2].callee))) { if (!rootMap.has(root)) rootMap.set(root, {}); if (!rootMap.get(root).defineComponent) rootMap.get(root).defineComponent = parents[2]; } const expression = node.type === "VariableDeclaration" ? node.declarations[0].init?.type === "CallExpression" && s.sliceNode(node.declarations[0].init.callee) === "$" ? node.declarations[0].init.arguments[0] : node.declarations[0].init : node.type === "ExpressionStatement" ? node.expression : void 0; if (!expression) return; const macroExpression = getMacroExpression(expression, options); if (!macroExpression) return; if (!rootMap.has(root)) rootMap.set(root, {}); const macroName = s.sliceNode(macroExpression.callee.type === "MemberExpression" ? macroExpression.callee.object : macroExpression.callee); if (macroName) { if (options.defineModel.alias.includes(macroName)) (rootMap.get(root).defineModel ??= []).push({ expression: macroExpression, isRequired: expression.type === "TSNonNullExpression" }); else if (options.defineStyle.alias.includes(macroName)) { const lang = macroExpression.callee.type === "MemberExpression" && macroExpression.callee.property.type === "Identifier" ? macroExpression.callee.property.name : "css"; (rootMap.get(root).defineStyle ??= []).push({ expression: macroExpression, isCssModules: node.type === "VariableDeclaration", lang }); } else if (options.defineSlots.alias.includes(macroName)) rootMap.get(root).defineSlots = { expression: macroExpression, id: node.type === "VariableDeclaration" ? node.declarations[0].id : void 0 }; else if (options.defineExpose.alias.includes(macroName)) rootMap.get(root).defineExpose = macroExpression; } }, leave() { parents.shift(); } }); return rootMap; } function getMacroExpression(node, options) { if (node.type === "TSNonNullExpression") node = node.expression; if (node.type === "CallExpression") { if (node.callee.type === "MemberExpression" && node.callee.object.type === "Identifier" && node.callee.object.name === "defineStyle") return node; else if (node.callee.type === "Identifier" && [ ...options.defineComponent.alias, ...options.defineSlots.alias, ...options.defineModel.alias, ...options.defineExpose.alias, ...options.defineStyle.alias ].includes(node.callee.name)) return node; } } //#endregion Object.defineProperty(exports, 'getMacroExpression', { enumerable: true, get: function () { return getMacroExpression; } }); Object.defineProperty(exports, 'helperPrefix', { enumerable: true, get: function () { return helperPrefix; } }); Object.defineProperty(exports, 'isFunctionalNode', { enumerable: true, get: function () { return isFunctionalNode; } }); Object.defineProperty(exports, 'restructure', { enumerable: true, get: function () { return restructure; } }); Object.defineProperty(exports, 'transformJsxMacros', { enumerable: true, get: function () { return transformJsxMacros; } }); Object.defineProperty(exports, 'useModelHelperId', { enumerable: true, get: function () { return useModelHelperId; } }); Object.defineProperty(exports, 'use_model_default', { enumerable: true, get: function () { return use_model_default; } }); Object.defineProperty(exports, 'withDefaultsHelperId', { enumerable: true, get: function () { return withDefaultsHelperId; } }); Object.defineProperty(exports, 'with_defaults_default', { enumerable: true, get: function () { return with_defaults_default; } });