vue-jsx-vapor
Version:
Vapor Mode of Vue JSX
820 lines (815 loc) • 35.5 kB
JavaScript
import jsxMacros from "@vue-jsx-vapor/macros/volar";
import { allCodeFeatures, createPlugin } from "ts-macro";
import { isHTMLTag, isSVGTag } from "@vue/shared";
//#region ../../node_modules/.pnpm/@vue-macros+volar@3.1.4_patch_hash=79e6492c51b3afca57b92023dd1aae9ddd57140efa1cf2cdf74d_8f0003e9f6556da391a8e0b33526761a/node_modules/@vue-macros/volar/dist/jsx-directive-w2gUTWdx.js
function getDirectiveArgs(attribute, options) {
const { ts, ast } = options;
const attributeName = attribute.name.getText(ast);
let isDynamic = false;
let argument = "";
let [name, ...modifiers] = attributeName.split(/\s/)[0].replace(/\$([^$]+)\$/, (_, $1) => {
isDynamic = true;
return $1.replaceAll("_", ".");
}).split("_");
if (name.includes(":")) [name, argument] = name.split(":");
const initializer = attribute.initializer;
let modifiersCode;
let valueCode;
let argumentCode;
if (initializer && initializer.kind === ts.SyntaxKind.JsxExpression && initializer.expression && ts.isArrayLiteralExpression(initializer.expression)) {
const elements = initializer.expression.elements;
if (elements[0]) valueCode = [elements[0].getText(ast), elements[0].getStart(ast)];
if (elements[1] && ts.isArrayLiteralExpression(elements[1])) modifiersCode = [elements[1].getText(ast), elements[1].getStart(ast)];
else {
if (!argument && elements[1]) {
isDynamic ||= !ts.isStringLiteral(elements[1]);
argumentCode = [elements[1].getText(ast), elements[1].getStart(ast)];
}
if (elements[2] && ts.isArrayLiteralExpression(elements[2])) modifiersCode = [elements[2].getText(ast), elements[2].getStart(ast)];
}
} else if (initializer) valueCode = [ts.isStringLiteral(attribute.initializer) ? attribute.initializer.getText(ast) : attribute.initializer.getText(ast).slice(1, -1), attribute.initializer.getStart(ast) + (ts.isStringLiteral(attribute.initializer) ? 0 : 1)];
return {
name,
valueCode,
argumentCode,
modifiersCode,
isDynamic,
argument,
modifiers
};
}
const getModifierPropName = (name) => {
return `${name === "modelValue" || name === "model-value" ? "model" : name}Modifiers${name === "model" ? "$" : ""}`;
};
function resolveCtxMap(ctxNodeMap, options) {
if (ctxNodeMap.size) options.codes.push(`
type __VLS_IsAny<T> = 0 extends 1 & T ? true : false;
type __VLS_PickNotAny<A, B> = __VLS_IsAny<A> extends true ? B : A;
type __VLS_PrettifyGlobal<T> = { [K in keyof T as K]: T[K] } & {};
declare function __VLS_asFunctionalComponent<
T,
K = T extends new (...args: any) => any ? InstanceType<T> : unknown,
>(
t: T,
): T extends new (...args: any) => any
? (
props: (K extends { $props: infer Props }
? Props
: K extends { props: infer Props }
? Props
: any),
ctx?: any,
) => JSX.Element & {
__ctx: {
attrs: Record<string, any>,
props: (K extends { $props: infer Props }
? Props
: K extends { props: infer Props }
? Props
: any),
slots: K extends { $slots: infer Slots }
? Slots
: K extends { slots: infer Slots }
? Slots
: any
emit: K extends { $emit: infer Emit }
? Emit
: K extends { emit: infer Emit }
? Emit
: any
expose: (
exposed: K extends { exposeProxy: infer Exposed }
? string extends keyof NonNullable<Exposed>
? K
: Exposed
: K,
) => void
}
}
: T extends () => any
? (props: {}, ctx?: any) => ReturnType<T>
: T extends (...args: any) => any
? T
: (_: {}, ctx?: any) => {
__ctx: {
attrs?: any
expose?: any
slots?: any
emit?: any
}
};
const __VLS_nativeElements = {
...{} as SVGElementTagNameMap,
...{} as HTMLElementTagNameMap,
};
declare function __VLS_getFunctionalComponentCtx<T, K, const S>(
comp: T,
compInstance: K,
s: S,
): S extends keyof typeof __VLS_nativeElements
? { expose: (exposed: (typeof __VLS_nativeElements)[S]) => any }
: '__ctx' extends keyof __VLS_PickNotAny<K, {}>
? K extends { __ctx?: infer Ctx } ? Ctx : never
: T extends (props: infer P, ctx: { expose: (exposed: infer Exposed) => void } & infer Ctx) => any
? Ctx & {
props: P,
expose: (
exposed: __VLS_PrettifyGlobal<
import('vue').ShallowUnwrapRef<Exposed>
>,
) => void,
}
: {};\n`);
return new Map(Array.from(ctxNodeMap).map(([node, root], index) => [node, transformCtx(node, root, index, options)]));
}
function transformCtx(node, root, index, options) {
const { ts, ast, codes, prefix } = options;
const openingElement = getOpeningElement(node, options);
if (!openingElement) return "";
let props = "";
let refValue;
for (const prop of openingElement.attributes.properties) {
if (!ts.isJsxAttribute(prop)) continue;
let name = prop.name.getText(ast);
if (name === "ref" && prop.initializer && ts.isJsxExpression(prop.initializer) && prop.initializer.expression) {
refValue = getRefValue(prop.initializer.expression, options);
continue;
}
const prefixModel = `${prefix}model`;
if (name.startsWith(prefixModel)) {
const dir = getDirectiveArgs(prop, options);
if (dir.valueCode && !dir.isDynamic) props += `'${dir.argument || dir.argumentCode?.[0].slice(1, -1) || "modelValue"}': ${dir.valueCode[0]},`;
continue;
} else if (name.includes("_")) name = name.split("_")[0];
else if (prefix && name.startsWith(prefix)) continue;
if (!name) continue;
const value = prop.initializer ? ts.isJsxExpression(prop.initializer) && prop.initializer.expression ? prop.initializer.expression.getText(ast) : prop.initializer.getText(ast) : "true";
props += `'${name}': ${value},`;
}
const ctxName = `__VLS_ctx_${refValue || index}`;
let tagName = "";
const originTagName = tagName = getTagName(node, options);
if (isHTMLTag(tagName) || isSVGTag(tagName) || tagName.includes("-")) tagName = `{}`;
else {
let types = "";
if (openingElement.typeArguments?.length) {
types = `<${openingElement.typeArguments.map((argument) => argument.getText(ast)).join(", ")}>`;
tagName += types;
}
}
const result = `\nconst ${ctxName} = __VLS_getFunctionalComponentCtx(${tagName}, __VLS_asFunctionalComponent(${tagName})({${props}}), '${originTagName}');\n`;
if (root) codes.replaceRange(root.end - 1, root.end - 1, result);
else addCode(codes, result);
return ctxName;
}
function addCode(codes, ...args) {
const index = codes.findIndex((code) => code.includes("__VLS_setup = (async () => {"));
codes.splice(index === -1 ? codes.length : index + 1, 0, ...args);
}
function getRefValue(expression, options) {
const { ts, ast } = options;
if (ts.isIdentifier(expression)) return expression.getText(ast);
else if (ts.isFunctionLike(expression)) {
let left;
if (ts.isBinaryExpression(expression.body)) left = expression.body.left;
ts.forEachChild(expression.body, (node) => {
if (ts.isBinaryExpression(node)) left = node.left;
else if (ts.isExpressionStatement(node) && ts.isBinaryExpression(node.expression)) left = node.expression.left;
});
return left && (ts.isPropertyAccessExpression(left) || ts.isElementAccessExpression(left) ? left.expression : left).getText(ast);
} else if (ts.isCallExpression(expression) && expression.arguments[0] && ts.isIdentifier(expression.arguments[0])) return expression.arguments[0].getText(ast);
}
function transformCustomDirective(attributes, options) {
if (!attributes.length) return;
attributes.forEach((attribute) => transform$1(attribute, options));
options.codes.push(`
type __VLS_ResolveDirective<T> = T extends import('vue').Directive<
any,
infer Value,
infer Modifiers extends string,
infer Argument extends string
>
? [Value, Argument, Array<Modifiers>]
: any;
`);
}
function transform$1(attribute, options) {
const { codes, ast } = options;
const { name, modifiersCode, argument, modifiers, argumentCode, valueCode, isDynamic } = getDirectiveArgs(attribute, options);
const start = attribute.getStart(ast);
codes.replaceRange(start, attribute.end, [
ast.text.slice(start, start + name.length),
start,
{ verification: true }
], `={[`, valueCode || "{} as any", ",", ...argument ? [
...isDynamic && !argument.includes("-") ? [] : [[
`'`,
start + name.length + 1,
{ verification: true }
]],
[argument, start + name.length + 1 + (isDynamic ? 1 : 0)],
...isDynamic && !argument.includes("-") ? [] : [[
`'`,
start + name.length + argument.length,
{ verification: true }
]]
] : argumentCode ? [argumentCode] : ["{} as any"], ",", ...modifiersCode ? [modifiersCode] : modifiers.length ? [
"[",
...modifiers.flatMap((modify, index) => {
const offset = start + name.length + (argument ? argument.length + 1 : 0) + (argument && isDynamic ? 2 : 0) + 1 + (index ? modifiers.slice(0, index).join("").length + index : 0);
return [
[`'`, offset],
[modify, offset],
[`'`, offset + modify.length - 1],
","
];
}),
"]"
] : ["{} as any"], `] satisfies __VLS_ResolveDirective<typeof `, [
`v`,
start,
{
...allCodeFeatures,
verification: false
}
], [
name[2].toUpperCase() + name.slice(3),
start + 2,
{
...allCodeFeatures,
verification: false
}
], `>}`);
}
function transformRef$1(nodes, ctxMap, options) {
const { codes, ts, ast } = options;
for (const { node, attribute } of nodes) if (attribute.initializer && ts.isJsxExpression(attribute.initializer) && attribute.initializer.expression && (ts.isFunctionExpression(attribute.initializer.expression) || ts.isArrowFunction(attribute.initializer.expression))) codes.replaceRange(attribute.getStart(ast), attribute.end, "{...({ ", ["ref", attribute.name.getStart(ast)], ": ", [attribute.initializer.expression.getText(ast), attribute.initializer.expression.getStart(ast)], `} satisfies { ref: (e: Parameters<typeof ${ctxMap.get(node)}.expose>[0]) => any }) as {}}`);
}
function transformVBind(nodes, options) {
if (nodes.length === 0) return;
const { codes, ast } = options;
for (const { attribute } of nodes) {
const attributeName = attribute.name.getText(ast);
const start = attribute.name.getStart(ast);
const end = attribute.name.end;
if (attributeName.includes("_")) codes.replaceRange(start + attributeName.indexOf("_"), end);
}
}
function resolveVFor(attribute, options) {
const { ts, ast } = options;
const result = [];
if (attribute.initializer && ts.isJsxExpression(attribute.initializer) && attribute.initializer.expression && ts.isBinaryExpression(attribute.initializer.expression)) {
let index;
let objectIndex;
let item = attribute.initializer.expression.left;
const list = attribute.initializer.expression.right;
if (ts.isParenthesizedExpression(item)) if (ts.isBinaryExpression(item.expression)) if (ts.isBinaryExpression(item.expression.left)) {
index = item.expression.left.right;
objectIndex = item.expression.right;
item = item.expression.left.left;
} else {
index = item.expression.right;
item = item.expression.left;
}
else item = item.expression;
if (item && list) result.push("__VLS_getVForSourceType(", [ast.text.slice(list.getStart(ast), list.end), list.getStart(ast)], ").map(([", [String(ast.text.slice(item.getStart(ast), item.end)), item.getStart(ast)], ", ", index ? [String(ast.text.slice(index.getStart(ast), index.end)), index.getStart(ast)] : objectIndex ? "undefined" : "", ...objectIndex ? [", ", [String(ast?.text.slice(objectIndex.getStart(ast), objectIndex.end)), objectIndex.getStart(ast)]] : "", "]) => ");
}
return result;
}
function transformVFor(nodes, options, hasVForAttribute) {
if (!nodes.length && !hasVForAttribute) return;
const { codes, ast } = options;
nodes.forEach(({ attribute, node, parent }) => {
const result = resolveVFor(attribute, options);
if (parent) result.unshift("{");
codes.replaceRange(node.getStart(ast), node.getStart(ast), ...result);
codes.replaceRange(node.end - 1, node.end, `>)${parent ? "}" : ""}`);
codes.replaceRange(attribute.getStart(ast), attribute.end);
});
codes.push(`
// @ts-ignore
function __VLS_getVForSourceType<T extends number | string | any[] | Iterable<any>>(source: T): [
item: T extends number ? number
: T extends string ? string
: T extends any[] ? T[number]
: T extends Iterable<infer T1> ? T1
: any,
index: number,
][];
// @ts-ignore
function __VLS_getVForSourceType<T>(source: T): [
item: T[keyof T],
key: keyof T,
index: number,
][];
`);
}
function transformVIf(nodes, options) {
const { codes, ts, prefix, ast } = options;
nodes.forEach(({ node, attribute, parent }, index) => {
if (!ts.isIdentifier(attribute.name)) return;
if ([`${prefix}if`, `${prefix}else-if`].includes(attribute.name.getText(ast)) && attribute.initializer && ts.isJsxExpression(attribute.initializer) && attribute.initializer.expression) {
const hasScope = parent && attribute.name.text === `${prefix}if`;
codes.replaceRange(node.getStart(ast), node.getStart(ast), `${hasScope ? "{" : ""}(`, [attribute.initializer.expression.getText(ast), attribute.initializer.expression.getStart(ast)], ") ? ");
const nextAttribute = nodes[index + 1]?.attribute;
const nextNodeHasElse = nextAttribute && ts.isIdentifier(nextAttribute.name) ? String(nextAttribute.name.text).startsWith(`${prefix}else`) : false;
codes.replaceRange(node.end, node.end, nextNodeHasElse ? " : " : ` : null${parent ? "}" : ""}`);
} else if (attribute.name.text === `${prefix}else`) codes.replaceRange(node.end, node.end, parent ? "}" : "");
codes.replaceRange(attribute.getStart(ast), attribute.end);
});
}
const isNativeFormElement = (tag) => {
return [
"input",
"select",
"textarea"
].includes(tag);
};
function transformVModel(nodeMap, ctxMap, options) {
if (!nodeMap.size) return;
for (const [, nodes] of nodeMap) transform(nodes, ctxMap, options);
getModelsType(options.codes);
}
function transform(nodes, ctxMap, options) {
const { codes, ast } = options;
let firstNamespacedNode;
const result = [];
const emitsResult = [];
const modifiersResult = [];
for (const { attribute, node } of nodes) {
const isNative = isNativeFormElement(getTagName(node, options));
const modelValue = isNative ? "value" : "modelValue";
const { name, argument, argumentCode, isDynamic, modifiers, modifiersCode, valueCode } = getDirectiveArgs(attribute, options);
if (!valueCode) continue;
const start = attribute.name.getStart(ast);
const resolvedArgument = argument || argumentCode?.[0].slice(1, -1) || modelValue;
const modifierProps = isDynamic ? "Record<string, true>" : `__VLS_GetModifierProps<typeof ${ctxMap.get(node)}.props, '${getModifierPropName(resolvedArgument)}'>`;
if (!argument && !argumentCode) {
const result$1 = [];
result$1.push(...isNative ? isRadioOrCheckbox(node, options) ? "v-model" : [[modelValue, start + 2]] : [[modelValue.slice(0, 3), start], [modelValue.slice(3), start]]);
if (modifiers.length || modifiersCode) result$1.unshift(`{...`, ...modifiersCode ? [modifiersCode] : modifiers.length ? [
"{",
...modifiers.flatMap((modify, index) => [
modify ? modify.includes("-") ? `'` : "" : `'`,
[modify, start + name.length + 1 + (index ? modifiers.slice(0, index).join("").length + index : 0)],
modify ? `${modify.includes("-") ? `'` : ""}: true, ` : `'`
]),
"}"
] : [], ` satisfies `, isNative ? modifiersCode ? `('trim' | 'number' | 'lazy')[]` : `{ trim?: true, number?: true, lazy?: true }` : modifiersCode ? `(keyof ${modifierProps})[]` : modifierProps, "} ");
if (!isNative) result$1.unshift(`{...{'onUpdate:${modelValue}': () => {} }} `);
codes.replaceRange(start, attribute.end, ...result$1, "={", valueCode, "}");
} else {
if (firstNamespacedNode) {
codes.replaceRange(attribute.getStart(ast), attribute.end);
result.push(",");
} else firstNamespacedNode = {
attribute,
node
};
result.push(isDynamic ? "[" : "", ...argument ? [
argument.includes("-") ? [
`'`,
start + name.length + 1,
{ verification: true }
] : "",
[argument, start + name.length + 1 + (isDynamic ? 1 : 0)],
argument.includes("-") ? [
`'`,
start + name.length + argument.length,
{ verification: true }
] : ""
] : argumentCode ? [argumentCode] : [modelValue], isDynamic ? "]" : "", ":", valueCode);
if (modifiersCode) modifiersResult.push(` {...`, modifiersCode, ` satisfies (keyof ${modifierProps})[]}`);
else if (modifiers.length) modifiersResult.push(` {...{`, ...modifiers.flatMap((modify, index) => [
modify ? modify.includes("-") ? `'` : "" : `'`,
[modify, start + name.length + (argument ? argument.length : -1) + (argument && isDynamic ? 4 : 2) + (index ? modifiers.slice(0, index).join("").length + index : 0)],
modify ? `${modify.includes("-") ? `'` : ""}: true, ` : `'`
]), "} satisfies ", modifierProps, "}");
if (!isDynamic) emitsResult.push(`'onUpdate:${resolvedArgument}': () => {}, `);
}
}
if (firstNamespacedNode) {
const { attribute, node } = firstNamespacedNode;
codes.replaceRange(attribute.getStart(ast), attribute.end, `{...{`, ...result, `} satisfies __VLS_GetModels<__VLS_NormalizeProps<typeof ${ctxMap.get(node)}.props>>}`, ...modifiersResult, ` {...{`, ...emitsResult, `}}`);
}
}
function isRadioOrCheckbox(node, options) {
const { ts, ast } = options;
const openingElement = getOpeningElement(node, options);
if (!openingElement) return false;
return openingElement.tagName.getText(ast) === "input" && openingElement.attributes.properties.some((attr) => {
return ts.isJsxAttribute(attr) && attr.name.getText(ast) === "type" && attr.initializer && ts.isStringLiteral(attr.initializer) && (attr.initializer.text === "radio" || attr.initializer.text === "checkbox");
});
}
function getModelsType(codes) {
codes.push(`
type __VLS_NormalizeProps<T> = T extends object
? {
[K in keyof T as {} extends Record<K, 1>
? never
: K extends keyof import('vue').VNodeProps | 'class' | 'style'
? never
: K]: T[K]
}
: never;
type __VLS_CamelCase<S extends string> = S extends \`\${infer F}-\${infer RF}\${infer R}\`
? \`\${F}\${Uppercase<RF>}\${__VLS_CamelCase<R>}\`
: S;
type __VLS_PropsToEmits<T> = T extends object
? {
[K in keyof T as K extends \`onUpdate:\${infer R}\`
? R extends 'modelValue'
? never
: __VLS_CamelCase<R>
: never]: T[K]
}
: never
type __VLS_GetModels<P, E = __VLS_PropsToEmits<P>> = P extends object
? {
[K in keyof P as K extends keyof E
? K
: never]: K extends keyof P ? P[K] : never
}
: {};
type __VLS_GetModifierProps<T, K extends string> = K extends keyof T
? NonNullable<T[K]>
: Record<symbol, never>;
`);
}
function transformVOn(nodes, ctxMap, options) {
if (nodes.length === 0) return;
const { codes, ast } = options;
for (const { node, attribute } of nodes) {
codes.replaceRange(attribute.getStart(ast), attribute.name.end + 2, "{...");
codes.replaceRange(attribute.end - 1, attribute.end - 1, ` satisfies __VLS_NormalizeEmits<typeof ${ctxMap.get(node)}.emit>`);
}
codes.push(`
type __VLS_UnionToIntersection<U> = (U extends unknown ? (arg: U) => unknown : never) extends ((arg: infer P) => unknown) ? P : never;
type __VLS_OverloadUnionInner<T, U = unknown> = U & T extends (...args: infer A) => infer R
? U extends T
? never
: __VLS_OverloadUnionInner<T, Pick<T, keyof T> & U & ((...args: A) => R)> | ((...args: A) => R)
: never;
type __VLS_OverloadUnion<T> = Exclude<
__VLS_OverloadUnionInner<(() => never) & T>,
T extends () => never ? never : () => never
>;
type __VLS_ConstructorOverloads<T> = __VLS_OverloadUnion<T> extends infer F
? F extends (event: infer E, ...args: infer A) => any
? { [K in E & string]: (...args: A) => void; }
: never
: never;
type __VLS_NormalizeEmits<T> = __VLS_PrettifyGlobal<
__VLS_UnionToIntersection<
__VLS_ConstructorOverloads<T> & {
[K in keyof T]: T[K] extends any[] ? { (...args: T[K]): void } : never
}
>
>;\n`);
}
function transformOnWithModifiers(nodes, options) {
const { codes, ast, ts } = options;
for (const { attribute } of nodes) {
const attributeName = attribute.name.getText(ast).split("_")[0];
const start = attribute.name.getStart(ast);
const end = attribute.name.end;
codes.replaceRange(start, end, "{...{", [attributeName, start]);
if (!attribute.initializer) codes.replaceRange(end, end, ": () => {}}}");
else if (ts.isJsxExpression(attribute.initializer) && attribute.initializer.expression) {
codes.replaceRange(end, attribute.initializer.expression.getStart(ast), ": ");
codes.replaceRange(attribute.end, attribute.end, "}");
}
}
}
function transformVSlot(nodeMap, ctxMap, options) {
if (nodeMap.size === 0) return;
const { codes, ts, ast, prefix } = options;
nodeMap.forEach(({ attributeMap, vSlotAttribute }, node) => {
const result = [" v-slots={{"];
const attributes = Array.from(attributeMap);
attributes.forEach(([attribute, { children, vIfAttribute, vForAttribute }], index) => {
if (!attribute) return;
let vIfAttributeName;
if (vIfAttribute && (vIfAttributeName = vIfAttribute.name.getText(ast))) {
if (`${prefix}if` === vIfAttributeName) result.push("...");
if ([`${prefix}if`, `${prefix}else-if`].includes(vIfAttributeName) && vIfAttribute.initializer && ts.isJsxExpression(vIfAttribute.initializer) && vIfAttribute.initializer.expression) result.push("(", [vIfAttribute.initializer.expression.getText(ast), vIfAttribute.initializer.expression.getStart(ast)], ") ? {");
else if (`${prefix}else` === vIfAttributeName) result.push("{");
}
if (vForAttribute) result.push("...", ...resolveVFor(vForAttribute, options), "({");
const { name, argument, argumentCode, valueCode, isDynamic } = getDirectiveArgs(attribute, options);
const offset = attribute.getStart(ast) + name.length;
result.push(isDynamic ? "[" : "", ...argument ? [
argument.includes("-") ? [
`'`,
offset + 1,
{ verification: true }
] : "",
[argument, offset + 1 + (isDynamic ? 1 : 0)],
argument.includes("-") ? [
`'`,
offset + argument.length,
{ verification: true }
] : ""
] : [argumentCode || "default"], isDynamic ? "]" : "", `: (`, ...valueCode ? [valueCode, isDynamic ? ": any" : ""] : [], ") => <>", ...children.map((child) => {
codes.replaceRange(child.pos, child.end);
const isSlotTemplate = getTagName(child, options) === "template" && !vSlotAttribute;
const node$1 = isSlotTemplate && ts.isJsxElement(child) ? child.children : child;
return isSlotTemplate && ts.isJsxSelfClosingElement(child) ? "" : [ast.text.slice(node$1.pos, node$1.end), node$1.pos];
}), "</>,");
if (vForAttribute) result.push("})) as any,");
if (vIfAttribute && vIfAttributeName) {
if ([`${prefix}if`, `${prefix}else-if`].includes(vIfAttributeName)) {
const nextAttribute = attributes[index + (attributes[index + 1]?.[0] ? 1 : 2)]?.[1].vIfAttribute;
result.push("}", nextAttribute && nextAttribute.name.getText(ast).startsWith(`${prefix}else`) ? " : " : " : null,");
} else if (`${prefix}else` === vIfAttributeName) result.push("},");
}
});
const slotType = `} satisfies typeof ${ctxMap.get(node)}.slots as Record<string, any>}`;
if (attributeMap.has(null)) result.push("default: () => <>");
else result.push(slotType);
if (vSlotAttribute) codes.replaceRange(vSlotAttribute.getStart(ast), vSlotAttribute.end, ...result);
else if (ts.isJsxElement(node)) {
codes.replaceRange(node.openingElement.end - 1, node.openingElement.end, ...result);
codes.replaceRange(node.closingElement.pos, node.closingElement.pos, attributeMap.has(null) ? `</>${slotType}>` : ">");
}
});
}
function transformVSlots(nodes, ctxMap, options) {
const { codes, ts } = options;
for (const { node, attribute: { initializer } } of nodes) if (initializer && ts.isJsxExpression(initializer) && initializer.expression) {
if (ts.isObjectLiteralExpression(initializer.expression)) codes.replaceRange(initializer.expression.end, initializer.expression.end, ` satisfies typeof ${ctxMap.get(node)}.slots`);
else if (ts.isFunctionExpression(initializer.expression) || ts.isArrowFunction(initializer.expression)) {
codes.replaceRange(initializer.expression.pos, initializer.expression.pos, "(");
codes.replaceRange(initializer.expression.end, initializer.expression.end, `) satisfies typeof ${ctxMap.get(node)}.slots.default`);
}
}
}
function transformJsxDirective(options) {
const { ast, ts, prefix, codes } = options;
const resolvedPrefix = prefix.replaceAll("$", String.raw`\$`);
const slotRegex = /* @__PURE__ */ new RegExp(`^${resolvedPrefix}slot(?=:|$)`);
const modelRegex = /* @__PURE__ */ new RegExp(`^${resolvedPrefix}model(?=[:_]|$)`);
const bindRegex = /* @__PURE__ */ new RegExp(`^(?!${resolvedPrefix}|on[A-Z])\\S+_\\S+`);
const onWithModifiersRegex = /^on[A-Z]\S*_\S+/;
const vIfMap = /* @__PURE__ */ new Map();
const vForNodes = [];
const vSlotMap = /* @__PURE__ */ new Map();
const vModelMap = /* @__PURE__ */ new Map();
const vOnNodes = [];
const onWithModifiers = [];
const vBindNodes = [];
const refNodes = [];
const vSlots = [];
const customDirectives = [];
const ctxNodeMap = /* @__PURE__ */ new Map();
let hasVForAttribute = false;
function walkJsxDirective(node, parent, parents = []) {
const tagName = getTagName(node, options);
const properties = getOpeningElement(node, options);
let ctxNode;
let vIfAttribute;
let vForAttribute;
let vSlotAttribute;
for (const attribute of properties?.attributes.properties || []) {
if (!ts.isJsxAttribute(attribute)) continue;
const attributeName = attribute.name.getText(ast);
if ([
`${prefix}if`,
`${prefix}else-if`,
`${prefix}else`
].includes(attributeName)) vIfAttribute = attribute;
else if (attributeName === `${prefix}for`) {
vForAttribute = attribute;
hasVForAttribute = true;
} else if (slotRegex.test(attributeName)) vSlotAttribute = attribute;
else if (modelRegex.test(attributeName)) {
vModelMap.has(node) || vModelMap.set(node, []);
vModelMap.get(node).push({
node,
attribute
});
if (!isNativeFormElement(tagName)) ctxNode = node;
} else if (attributeName === `${prefix}on`) {
vOnNodes.push({
node,
attribute
});
ctxNode = node;
} else if (onWithModifiersRegex.test(attributeName)) onWithModifiers.push({
node,
attribute
});
else if (bindRegex.test(attributeName)) vBindNodes.push({
node,
attribute
});
else if (attributeName === "ref") {
refNodes.push({
node,
attribute
});
ctxNode = node;
} else if (attributeName === `${prefix}slots`) {
ctxNode = node;
vSlots.push({
node,
attribute
});
} else if ([
`${prefix}html`,
`${prefix}memo`,
`${prefix}once`
].includes(attributeName)) codes.replaceRange(attribute.pos, attribute.end);
else if (attributeName.startsWith("v-")) customDirectives.push(attribute);
}
if (ts.isJsxExpression(node) && node.expression && (ts.isObjectLiteralExpression(node.expression) || ts.isArrowFunction(node.expression) || ts.isFunctionExpression(node.expression)) && parent && ts.isJsxElement(parent) && !parent.children.every((child) => child !== node && (ts.isJsxText(child) ? child.getText(ast).trim() : true))) {
ctxNode = parent;
vSlots.push({
node: parent,
attribute: { initializer: {
kind: ts.SyntaxKind.JsxExpression,
expression: node.expression
} }
});
}
if (!vSlotAttribute || tagName !== "template") {
if (vIfAttribute) {
vIfMap.has(parent) || vIfMap.set(parent, []);
vIfMap.get(parent).push({
node,
attribute: vIfAttribute,
parent
});
}
if (vForAttribute) vForNodes.push({
node,
attribute: vForAttribute,
parent: vIfAttribute ? void 0 : parent
});
}
if (vSlotAttribute) {
const slotNode = tagName === "template" ? parent : node;
if (!slotNode) return;
ctxNode = slotNode;
const attributeMap = vSlotMap.get(slotNode)?.attributeMap || vSlotMap.set(slotNode, {
vSlotAttribute: tagName === "template" ? void 0 : vSlotAttribute,
attributeMap: /* @__PURE__ */ new Map()
}).get(slotNode).attributeMap;
const children = attributeMap.get(vSlotAttribute)?.children || attributeMap.set(vSlotAttribute, {
children: [],
...tagName === "template" ? {
vIfAttribute,
vForAttribute
} : {}
}).get(vSlotAttribute).children;
if (slotNode === parent && ts.isJsxElement(parent)) {
children.push(node);
if (attributeMap.get(null)) return;
for (const child of parent.children) {
if (getTagName(child, options) === "template" || ts.isJsxText(child) && !child.getText(ast).trim()) continue;
(attributeMap.get(null)?.children || attributeMap.set(null, { children: [] }).get(null).children).push(child);
}
} else if (ts.isJsxElement(node)) children.push(...node.children);
}
if (ctxNode) ctxNodeMap.set(ctxNode, parents.find(ts.isBlock));
node.forEachChild((child) => {
parents.unshift(node);
walkJsxDirective(child, ts.isJsxElement(node) || ts.isJsxFragment(node) ? node : void 0, parents);
parents.shift();
});
}
ast.forEachChild(walkJsxDirective);
const ctxMap = resolveCtxMap(ctxNodeMap, options);
transformVSlot(vSlotMap, ctxMap, options);
transformVFor(vForNodes, options, hasVForAttribute);
vIfMap.forEach((nodes) => transformVIf(nodes, options));
transformVModel(vModelMap, ctxMap, options);
transformVOn(vOnNodes, ctxMap, options);
transformOnWithModifiers(onWithModifiers, options);
transformVBind(vBindNodes, options);
transformRef$1(refNodes, ctxMap, options);
transformVSlots(vSlots, ctxMap, options);
transformCustomDirective(customDirectives, options);
}
function getOpeningElement(node, options) {
const { ts } = options;
return ts.isJsxSelfClosingElement(node) ? node : ts.isJsxElement(node) ? node.openingElement : void 0;
}
function getTagName(node, options) {
const openingElement = getOpeningElement(node, options);
if (!openingElement) return "";
return openingElement.tagName.getText(options.ast);
}
const plugin$2 = createPlugin(({ ts, vueCompilerOptions }, options = vueCompilerOptions?.vueMacros?.jsxDirective === true ? {} : vueCompilerOptions?.vueMacros?.jsxDirective ?? {}) => {
if (!options) return [];
return {
name: "vue-macros-jsx-directive",
resolveVirtualCode({ ast, codes, lang }) {
if (!["jsx", "tsx"].includes(lang)) return;
transformJsxDirective({
codes,
ast,
ts,
prefix: options.prefix ?? "v-"
});
}
};
});
var jsx_directive_default = plugin$2;
//#endregion
//#region ../../node_modules/.pnpm/@vue-macros+volar@3.1.4_patch_hash=79e6492c51b3afca57b92023dd1aae9ddd57140efa1cf2cdf74d_8f0003e9f6556da391a8e0b33526761a/node_modules/@vue-macros/volar/dist/jsx-ref-DZlb-F7c.js
function transformRef({ nodes, codes, ts }) {
for (const { name, initializer } of nodes) if (ts.isCallExpression(initializer)) codes.replaceRange(initializer.expression.end, initializer.expression.end, `<Parameters<typeof __VLS_ctx_${name.text}['expose']>[0] | null>`);
}
function getRefNodes(ts, sourceFile, alias) {
function isRefCall(node) {
return ts.isCallExpression(node) && ts.isIdentifier(node.expression) && !node.typeArguments?.length && alias.includes(node.expression.text);
}
const result = [];
function walk(node) {
if (ts.isVariableStatement(node)) ts.forEachChild(node.declarationList, (decl) => {
if (ts.isVariableDeclaration(decl) && ts.isIdentifier(decl.name) && decl.initializer && ts.isCallExpression(decl.initializer) && ts.isIdentifier(decl.initializer.expression)) {
const initializer = decl.initializer.expression.text === "$" ? decl.initializer.arguments[0] : decl.initializer;
if (isRefCall(initializer)) result.push({
name: decl.name,
initializer
});
}
});
ts.forEachChild(node, walk);
}
ts.forEachChild(sourceFile, walk);
return result;
}
const plugin$1 = createPlugin(({ ts, vueCompilerOptions }, options = vueCompilerOptions?.vueMacros?.jsxRef === true ? {} : vueCompilerOptions?.vueMacros?.jsxRef ?? {}) => {
if (!options) return [];
const alias = options.alias || ["useRef"];
return {
name: "vue-macros-jsx-ref",
resolveVirtualCode({ ast, codes, source, lang }) {
if (!["jsx", "tsx"].includes(lang)) return;
const nodes = getRefNodes(ts, ast, alias);
if (nodes.length) transformRef({
nodes,
codes,
ts,
source
});
}
};
});
var jsx_ref_default = plugin$1;
//#endregion
//#region src/volar/jsx-element.ts
var jsx_element_default = createPlugin(({ ts }) => {
return {
name: "@vue-jsx-vapor/jsx-element",
resolveVirtualCode({ ast, codes }) {
let transformed = false;
ast.forEachChild(function walk(node, parent = ast) {
if (!ts.isJsxElement(parent) && !ts.isJsxFragment(parent) && !ts.isJsxExpression(parent) && !(parent.parent ? isConditionalExpression(ts, parent) : false)) {
const openingElement = ts.isJsxElement(node) ? node.openingElement : ts.isJsxSelfClosingElement(node) ? node : null;
if (openingElement) {
const tagName = openingElement.tagName.getText(ast);
if (!tagName.includes("-") && tagName !== "slot") {
transformed = true;
codes.replaceRange(node.getStart(ast), node.getStart(ast) + 1, "(<");
codes.replaceRange(node.end, node.end, " as unknown as __InferJsxElement<", isHTMLTag(tagName) || isSVGTag(tagName) ? `'${tagName}'` : `typeof ${tagName}`, ">)");
}
}
}
if (!ts.isCallExpression(node) || node.expression.getText(ast) !== "defineSlots") node.forEachChild((child) => walk(child, node));
});
transformed && codes.push(`
type __InferJsxElement<T> = T extends keyof HTMLElementTagNameMap
? HTMLElementTagNameMap[T]
: T extends keyof SVGElementTagNameMap
? SVGElementTagNameMap[T]
: T extends (props: infer Props extends Record<string, any>, ctx: { slots: infer Slots extends Record<string, any>, expose: (exposed: infer Exposed extends Record<string, any>) => void, attrs: any, emit: any }) => infer TypeBlock
? TypeBlock extends import('vue').Block
? import('vue').VaporComponentInstance<Props, {}, Slots, Exposed, TypeBlock>
: TypeBlock
: T extends { new (...args: any[]): infer Instance }
? Instance extends { $: any }
? import('vue').VNode
: Instance
: JSX.Element
`);
}
};
});
function isConditionalExpression(ts, node) {
return !!(node && (ts.isBinaryExpression(node) || ts.isConditionalExpression(node)) && node.parent && (ts.isJsxExpression(node.parent) || isConditionalExpression(ts, node.parent)));
}
//#endregion
//#region src/volar.ts
const plugin = createPlugin((ctx, options = ctx.vueCompilerOptions?.["vue-jsx-vapor"]) => {
return [
jsx_directive_default()(ctx),
options?.ref === false ? [] : jsx_ref_default(options?.ref === true ? void 0 : options?.ref)(ctx),
options?.macros === false ? [] : options?.macros ? jsxMacros(options.macros === true ? void 0 : options.macros)(ctx) : [],
options?.interop ? [] : jsx_element_default()(ctx)
].flat();
});
//#endregion
export { plugin as default, plugin as "module.exports" };