5354 lines
201 KiB
JavaScript
5354 lines
201 KiB
JavaScript
/**
|
|||
|
|
* @vue/compiler-vapor v3.6.0-rc.10
|
||
|
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
||
|
|
* @license MIT
|
||
|
|
**/
|
||
|
|
Object.defineProperties(exports, {
|
||
|
|
__esModule: { value: true },
|
||
|
|
[Symbol.toStringTag]: { value: "Module" }
|
||
|
|
});
|
||
|
|
let _vue_compiler_dom = require("@vue/compiler-dom");
|
||
|
|
let _vue_shared = require("@vue/shared");
|
||
|
|
let source_map_js = require("source-map-js");
|
||
|
|
let _babel_parser = require("@babel/parser");
|
||
|
|
let estree_walker = require("estree-walker");
|
||
|
|
//#region packages/compiler-vapor/src/ir/component.ts
|
||
|
|
const IRDynamicPropsKind = {
|
||
|
|
"EXPRESSION": 0,
|
||
|
|
"0": "EXPRESSION",
|
||
|
|
"ATTRIBUTE": 1,
|
||
|
|
"1": "ATTRIBUTE"
|
||
|
|
};
|
||
|
|
const IRSlotType = {
|
||
|
|
"STATIC": 0,
|
||
|
|
"0": "STATIC",
|
||
|
|
"DYNAMIC": 1,
|
||
|
|
"1": "DYNAMIC",
|
||
|
|
"LOOP": 2,
|
||
|
|
"2": "LOOP",
|
||
|
|
"CONDITIONAL": 3,
|
||
|
|
"3": "CONDITIONAL",
|
||
|
|
"EXPRESSION": 4,
|
||
|
|
"4": "EXPRESSION"
|
||
|
|
};
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/ir/index.ts
|
||
|
|
const IRNodeTypes = {
|
||
|
|
"ROOT": 0,
|
||
|
|
"0": "ROOT",
|
||
|
|
"BLOCK": 1,
|
||
|
|
"1": "BLOCK",
|
||
|
|
"SET_BLOCK_KEY": 2,
|
||
|
|
"2": "SET_BLOCK_KEY",
|
||
|
|
"SET_PROP": 3,
|
||
|
|
"3": "SET_PROP",
|
||
|
|
"SET_DYNAMIC_PROPS": 4,
|
||
|
|
"4": "SET_DYNAMIC_PROPS",
|
||
|
|
"SET_TEXT": 5,
|
||
|
|
"5": "SET_TEXT",
|
||
|
|
"SET_EVENT": 6,
|
||
|
|
"6": "SET_EVENT",
|
||
|
|
"SET_DYNAMIC_EVENTS": 7,
|
||
|
|
"7": "SET_DYNAMIC_EVENTS",
|
||
|
|
"SET_HTML": 8,
|
||
|
|
"8": "SET_HTML",
|
||
|
|
"SET_TEMPLATE_REF": 9,
|
||
|
|
"9": "SET_TEMPLATE_REF",
|
||
|
|
"INSERT_NODE": 10,
|
||
|
|
"10": "INSERT_NODE",
|
||
|
|
"CREATE_COMPONENT_NODE": 11,
|
||
|
|
"11": "CREATE_COMPONENT_NODE",
|
||
|
|
"SLOT_OUTLET_NODE": 12,
|
||
|
|
"12": "SLOT_OUTLET_NODE",
|
||
|
|
"DIRECTIVE": 13,
|
||
|
|
"13": "DIRECTIVE",
|
||
|
|
"IF": 14,
|
||
|
|
"14": "IF",
|
||
|
|
"FOR": 15,
|
||
|
|
"15": "FOR",
|
||
|
|
"KEY": 16,
|
||
|
|
"16": "KEY",
|
||
|
|
"GET_TEXT_CHILD": 17,
|
||
|
|
"17": "GET_TEXT_CHILD"
|
||
|
|
};
|
||
|
|
var TemplateRegistry = class {
|
||
|
|
constructor() {
|
||
|
|
this.entries = [];
|
||
|
|
}
|
||
|
|
keys() {
|
||
|
|
return this.entries.map(({ content }) => content);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const DynamicFlag = {
|
||
|
|
"NONE": 0,
|
||
|
|
"0": "NONE",
|
||
|
|
"REFERENCED": 1,
|
||
|
|
"1": "REFERENCED",
|
||
|
|
"NON_TEMPLATE": 2,
|
||
|
|
"2": "NON_TEMPLATE",
|
||
|
|
"INSERT": 4,
|
||
|
|
"4": "INSERT"
|
||
|
|
};
|
||
|
|
function isBlockOperation(op) {
|
||
|
|
const type = op.type;
|
||
|
|
return type === 11 || type === 12 || type === 14 || type === 16 || type === 15;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/utils.ts
|
||
|
|
const newDynamic = () => ({
|
||
|
|
flags: 1,
|
||
|
|
children: []
|
||
|
|
});
|
||
|
|
const newBlock = (node) => ({
|
||
|
|
type: 1,
|
||
|
|
node,
|
||
|
|
dynamic: newDynamic(),
|
||
|
|
effect: [],
|
||
|
|
operation: [],
|
||
|
|
returns: [],
|
||
|
|
tempId: 0
|
||
|
|
});
|
||
|
|
function wrapTemplate(node, dirs) {
|
||
|
|
if (node.tagType === 3) {
|
||
|
|
const otherStructuralDirs = [
|
||
|
|
"if",
|
||
|
|
"else-if",
|
||
|
|
"else",
|
||
|
|
"for"
|
||
|
|
];
|
||
|
|
if (!node.props.some((prop) => prop.type === 7 && otherStructuralDirs.includes(prop.name) && !dirs.includes(prop.name))) return node;
|
||
|
|
const reserved = [];
|
||
|
|
const pass = [];
|
||
|
|
node.props.forEach((prop) => {
|
||
|
|
if (prop.type === 7 && dirs.includes(prop.name)) reserved.push(prop);
|
||
|
|
else pass.push(prop);
|
||
|
|
});
|
||
|
|
return (0, _vue_shared.extend)({}, node, {
|
||
|
|
type: 1,
|
||
|
|
tag: "template",
|
||
|
|
props: reserved,
|
||
|
|
tagType: 3,
|
||
|
|
children: [(0, _vue_shared.extend)({}, node, { props: pass })]
|
||
|
|
});
|
||
|
|
}
|
||
|
|
const reserved = [];
|
||
|
|
const pass = [];
|
||
|
|
node.props.forEach((prop) => {
|
||
|
|
if (prop.type === 7 && (dirs.includes(prop.name) || prop.name === "bind" && prop.arg && prop.arg.type === 4 && prop.arg.content === "key" && dirs.includes("key"))) reserved.push(prop);
|
||
|
|
else pass.push(prop);
|
||
|
|
});
|
||
|
|
return (0, _vue_shared.extend)({}, node, {
|
||
|
|
type: 1,
|
||
|
|
tag: "template",
|
||
|
|
props: reserved,
|
||
|
|
tagType: 3,
|
||
|
|
children: [(0, _vue_shared.extend)({}, node, { props: pass })]
|
||
|
|
});
|
||
|
|
}
|
||
|
|
const EMPTY_EXPRESSION = (0, _vue_compiler_dom.createSimpleExpression)("", true);
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/utils.ts
|
||
|
|
const findProp$1 = _vue_compiler_dom.findProp;
|
||
|
|
/** find directive */
|
||
|
|
const findDir$5 = _vue_compiler_dom.findDir;
|
||
|
|
function propToExpression(prop) {
|
||
|
|
return prop.type === 6 ? prop.value ? (0, _vue_compiler_dom.createSimpleExpression)(prop.value.content, true, prop.value.loc) : EMPTY_EXPRESSION : prop.exp;
|
||
|
|
}
|
||
|
|
function isConstantExpression(exp) {
|
||
|
|
return (0, _vue_compiler_dom.isLiteralWhitelisted)(exp.content) || (0, _vue_shared.isGloballyAllowed)(exp.content) || getLiteralExpressionValue(exp) !== null;
|
||
|
|
}
|
||
|
|
function isConstantBinding$1(exp, bindings) {
|
||
|
|
return isConstantExpression(exp) || isStaticExpression(exp, bindings);
|
||
|
|
}
|
||
|
|
function isStaticExpression(node, bindings) {
|
||
|
|
if (node.ast) return (0, _vue_compiler_dom.isConstantNode)(node.ast, bindings);
|
||
|
|
else if (node.ast === null) {
|
||
|
|
if (!node.isStatic && (node.content === "true" || node.content === "false" || node.content === "null")) return true;
|
||
|
|
return bindings[node.content] === "literal-const";
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
function resolveExpression(exp, isComponent) {
|
||
|
|
if (!exp.isStatic) {
|
||
|
|
const value = getLiteralExpressionValue(exp, isComponent);
|
||
|
|
if (value !== null) return (0, _vue_compiler_dom.createSimpleExpression)(value, true, exp.loc);
|
||
|
|
}
|
||
|
|
return exp;
|
||
|
|
}
|
||
|
|
function getLiteralExpressionValue(exp, excludeNumber) {
|
||
|
|
if (exp.ast) {
|
||
|
|
if (exp.ast.type === "StringLiteral") return exp.ast.value;
|
||
|
|
else if (!excludeNumber && (exp.ast.type === "NumericLiteral" || exp.ast.type === "BigIntLiteral")) return String(exp.ast.value);
|
||
|
|
else if (exp.ast.type === "TemplateLiteral") {
|
||
|
|
let result = "";
|
||
|
|
for (const [index, quasi] of exp.ast.quasis.entries()) {
|
||
|
|
result += quasi.value.cooked;
|
||
|
|
if (exp.ast.expressions[index]) {
|
||
|
|
let expressionValue = getLiteralExpressionValue({ ast: exp.ast.expressions[index] });
|
||
|
|
if (expressionValue == null) return null;
|
||
|
|
else result += expressionValue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return exp.isStatic ? exp.content : null;
|
||
|
|
}
|
||
|
|
function isInTransition(context) {
|
||
|
|
const parentNode = context.parent && context.parent.node;
|
||
|
|
return !!(parentNode && isTransitionNode(parentNode));
|
||
|
|
}
|
||
|
|
function isTransitionNode(node) {
|
||
|
|
return node.type === 1 && isTransitionTag(node.tag);
|
||
|
|
}
|
||
|
|
/** Transition or TransitionGroup: hosts whose children render specially. */
|
||
|
|
function isTransitionHostNode(node) {
|
||
|
|
return node.type === 1 && (isTransitionTag(node.tag) || isTransitionGroupTag(node.tag));
|
||
|
|
}
|
||
|
|
function isTransitionTag(tag) {
|
||
|
|
tag = tag.toLowerCase();
|
||
|
|
return tag === "transition" || tag === "vaportransition";
|
||
|
|
}
|
||
|
|
function isTransitionGroupTag(tag) {
|
||
|
|
tag = tag.toLowerCase().replace(/-/g, "");
|
||
|
|
return tag === "transitiongroup" || tag === "vaportransitiongroup";
|
||
|
|
}
|
||
|
|
function isKeepAliveTag(tag) {
|
||
|
|
tag = tag.toLowerCase().replace(/-/g, "");
|
||
|
|
return tag === "keepalive" || tag === "vaporkeepalive";
|
||
|
|
}
|
||
|
|
function isTeleportTag(tag) {
|
||
|
|
tag = tag.toLowerCase();
|
||
|
|
return tag === "teleport" || tag === "vaporteleport";
|
||
|
|
}
|
||
|
|
function isComponentTag(tag) {
|
||
|
|
return tag === "component" || tag === "Component";
|
||
|
|
}
|
||
|
|
function isBuiltInComponent(tag) {
|
||
|
|
if (isTeleportTag(tag)) return "VaporTeleport";
|
||
|
|
else if (tag === "Suspense" || tag === "suspense") return "Suspense";
|
||
|
|
else if (isKeepAliveTag(tag)) return "VaporKeepAlive";
|
||
|
|
else if (isTransitionTag(tag)) return "VaporTransition";
|
||
|
|
else if (isTransitionGroupTag(tag)) return "VaporTransitionGroup";
|
||
|
|
}
|
||
|
|
function getBlockShape(block) {
|
||
|
|
if (block.returns.length !== 1) return 2;
|
||
|
|
const root = block.dynamic.children.find((c) => c.id === block.returns[0]);
|
||
|
|
if (root && root.operation && root.operation.type === 14) return 2;
|
||
|
|
return block.node.type === 1 && block.node.children.every((child) => child.type === 2 || child.type === 5) ? 2 : 1;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transform.ts
|
||
|
|
const generatedVarRE = /^[nxr](\d+)$/;
|
||
|
|
const childContextInfoCache = /* @__PURE__ */ new WeakMap();
|
||
|
|
var TransformContext = class TransformContext {
|
||
|
|
constructor(ir, node, options = {}) {
|
||
|
|
this.ir = ir;
|
||
|
|
this.node = node;
|
||
|
|
this.selfName = null;
|
||
|
|
this.parent = null;
|
||
|
|
this.effectiveParent = null;
|
||
|
|
this.index = 0;
|
||
|
|
this.block = this.ir.block;
|
||
|
|
this.template = "";
|
||
|
|
this.templateRoot = false;
|
||
|
|
this.templateIndexMap = /* @__PURE__ */ new Map();
|
||
|
|
this.childrenTemplate = [];
|
||
|
|
this.dynamic = this.ir.block.dynamic;
|
||
|
|
this.imports = [];
|
||
|
|
this.inVOnce = false;
|
||
|
|
this.inVFor = 0;
|
||
|
|
this.comment = [];
|
||
|
|
this.component = this.ir.component;
|
||
|
|
this.directive = this.ir.directive;
|
||
|
|
this.slots = [];
|
||
|
|
this.effectIndex = this.block.effect.length;
|
||
|
|
this.operationIndex = this.block.operation.length;
|
||
|
|
this.isLastEffectiveChild = true;
|
||
|
|
this.isOnRightmostPath = true;
|
||
|
|
this.isSingleRoot = false;
|
||
|
|
this.templateCloseTags = void 0;
|
||
|
|
this.templateCloseBlocks = false;
|
||
|
|
this.globalId = 0;
|
||
|
|
this.nextIdMap = null;
|
||
|
|
this.ifIndex = 0;
|
||
|
|
this.increaseId = () => {
|
||
|
|
const id = getNextId(this.nextIdMap, this.globalId);
|
||
|
|
this.globalId = getNextId(this.nextIdMap, id + 1);
|
||
|
|
return id;
|
||
|
|
};
|
||
|
|
this.options = (0, _vue_shared.extend)({}, defaultOptions, options);
|
||
|
|
this.root = this;
|
||
|
|
if (options.filename) this.selfName = (0, _vue_compiler_dom.getSelfName)(options.filename);
|
||
|
|
this.initNextIdMap();
|
||
|
|
}
|
||
|
|
enterBlock(ir, isVFor = false) {
|
||
|
|
const { block, template, templateRoot, templateIndexMap, dynamic, childrenTemplate, slots, effectIndex, operationIndex } = this;
|
||
|
|
this.block = ir;
|
||
|
|
this.dynamic = ir.dynamic;
|
||
|
|
this.template = "";
|
||
|
|
this.templateRoot = false;
|
||
|
|
this.templateIndexMap = templateIndexMap;
|
||
|
|
this.childrenTemplate = [];
|
||
|
|
this.slots = [];
|
||
|
|
this.effectIndex = ir.effect.length;
|
||
|
|
this.operationIndex = ir.operation.length;
|
||
|
|
isVFor && this.inVFor++;
|
||
|
|
return () => {
|
||
|
|
this.registerTemplate();
|
||
|
|
this.block = block;
|
||
|
|
this.template = template;
|
||
|
|
this.templateRoot = templateRoot;
|
||
|
|
this.templateIndexMap = templateIndexMap;
|
||
|
|
this.dynamic = dynamic;
|
||
|
|
this.childrenTemplate = childrenTemplate;
|
||
|
|
this.slots = slots;
|
||
|
|
this.effectIndex = effectIndex;
|
||
|
|
this.operationIndex = operationIndex;
|
||
|
|
isVFor && this.inVFor--;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
initNextIdMap() {
|
||
|
|
const binding = this.root.options.bindingMetadata;
|
||
|
|
if (!binding) return;
|
||
|
|
const keys = Object.keys(binding);
|
||
|
|
if (keys.length === 0) return;
|
||
|
|
const numbers = /* @__PURE__ */ new Set();
|
||
|
|
for (const name of keys) {
|
||
|
|
const m = generatedVarRE.exec(name);
|
||
|
|
if (m) numbers.add(Number(m[1]));
|
||
|
|
}
|
||
|
|
if (numbers.size === 0) return;
|
||
|
|
this.globalId = getNextId(this.nextIdMap = buildNextIdMap(numbers), 0);
|
||
|
|
}
|
||
|
|
reference() {
|
||
|
|
if (this.dynamic.id !== void 0) return this.dynamic.id;
|
||
|
|
this.dynamic.flags |= 1;
|
||
|
|
return this.dynamic.id = this.increaseId();
|
||
|
|
}
|
||
|
|
nextIfIndex() {
|
||
|
|
return this.ifIndex++;
|
||
|
|
}
|
||
|
|
getTemplateNamespace() {
|
||
|
|
return this.node.type === 1 ? this.node.ns : 0;
|
||
|
|
}
|
||
|
|
canUseStaticTemplate() {
|
||
|
|
if (!this.template) return false;
|
||
|
|
if (this.inVFor) return false;
|
||
|
|
if (this.dynamic.hasDynamicChild) return false;
|
||
|
|
if (this.block.effect.length !== this.effectIndex) return false;
|
||
|
|
if (this.block.operation.length !== this.operationIndex) return false;
|
||
|
|
if (this.node.type === 2 || this.node.type === 3) return true;
|
||
|
|
return this.node.type === 1 && this.node.tagType === 0 && !(this.options.isCustomElement(this.node.tag) || this.node.tag === "template");
|
||
|
|
}
|
||
|
|
pushTemplate(content, { root = false, static: isStatic = false } = {}) {
|
||
|
|
const templateKey = JSON.stringify([
|
||
|
|
this.getTemplateNamespace(),
|
||
|
|
root,
|
||
|
|
isStatic,
|
||
|
|
content
|
||
|
|
]);
|
||
|
|
const existingIndex = this.templateIndexMap.get(templateKey);
|
||
|
|
if (existingIndex !== void 0) return existingIndex;
|
||
|
|
const ns = this.getTemplateNamespace();
|
||
|
|
const newIndex = this.ir.template.entries.length;
|
||
|
|
this.ir.template.entries.push({
|
||
|
|
content,
|
||
|
|
ns,
|
||
|
|
root,
|
||
|
|
static: isStatic
|
||
|
|
});
|
||
|
|
this.templateIndexMap.set(templateKey, newIndex);
|
||
|
|
return newIndex;
|
||
|
|
}
|
||
|
|
registerTemplate() {
|
||
|
|
if (!this.template) return -1;
|
||
|
|
const id = this.pushTemplate(this.template, {
|
||
|
|
root: this.templateRoot,
|
||
|
|
static: this.canUseStaticTemplate()
|
||
|
|
});
|
||
|
|
return this.dynamic.template = id;
|
||
|
|
}
|
||
|
|
registerEffect(expressions, operation, getIndex, preserveOrder = false) {
|
||
|
|
const operations = [operation].flat();
|
||
|
|
expressions = expressions.filter((exp) => !isConstantExpression(exp));
|
||
|
|
const once = expressions.every((e) => isConstantBinding$1(e, this.root.options.bindingMetadata));
|
||
|
|
const needsEffect = operations.some((op) => op.type === 4 && op.listeners);
|
||
|
|
if (this.inVOnce || once && !preserveOrder && !needsEffect) {
|
||
|
|
this.registerOperation(...operations);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
const index = getIndex ? getIndex() : this.block.effect.length;
|
||
|
|
this.block.effect.splice(index, 0, {
|
||
|
|
expressions,
|
||
|
|
operations,
|
||
|
|
...once && !needsEffect ? { once: true } : {}
|
||
|
|
});
|
||
|
|
if (getIndex) this.shiftEffectBoundaries(index);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
registerOperation(...node) {
|
||
|
|
this.block.operation.push(...node);
|
||
|
|
}
|
||
|
|
effectBoundary() {
|
||
|
|
return {
|
||
|
|
operationIndex: this.operationIndex,
|
||
|
|
effectIndex: this.effectIndex
|
||
|
|
};
|
||
|
|
}
|
||
|
|
create(node, index) {
|
||
|
|
let effectiveParent = this;
|
||
|
|
while (effectiveParent && effectiveParent.node.type === 1 && effectiveParent.node.tagType === 3) effectiveParent = effectiveParent.parent;
|
||
|
|
const childInfo = this.getChildContextInfo();
|
||
|
|
const isLastEffectiveChild = childInfo.isLastEffectiveChild[index];
|
||
|
|
const isOnRightmostPath = this.isOnRightmostPath && isLastEffectiveChild;
|
||
|
|
const isSingleRoot = this.isSingleRootChild(childInfo);
|
||
|
|
return Object.assign(Object.create(TransformContext.prototype), this, {
|
||
|
|
node,
|
||
|
|
parent: this,
|
||
|
|
index,
|
||
|
|
inVOnce: this.inVOnce && !isComponentNode(this.node),
|
||
|
|
template: "",
|
||
|
|
templateRoot: false,
|
||
|
|
childrenTemplate: [],
|
||
|
|
templateIndexMap: this.templateIndexMap,
|
||
|
|
dynamic: newDynamic(),
|
||
|
|
effectIndex: this.block.effect.length,
|
||
|
|
operationIndex: this.block.operation.length,
|
||
|
|
effectiveParent,
|
||
|
|
isLastEffectiveChild,
|
||
|
|
isOnRightmostPath,
|
||
|
|
isSingleRoot,
|
||
|
|
templateCloseTags: this.templateCloseTags,
|
||
|
|
templateCloseBlocks: this.templateCloseBlocks
|
||
|
|
});
|
||
|
|
}
|
||
|
|
shiftEffectBoundaries(index, dynamic = this.dynamic) {
|
||
|
|
const operation = dynamic.operation;
|
||
|
|
if (operation && isBlockOperation(operation) && operation.effectIndex !== void 0 && operation.effectIndex >= index) operation.effectIndex++;
|
||
|
|
for (const child of dynamic.children) this.shiftEffectBoundaries(index, child);
|
||
|
|
}
|
||
|
|
getChildContextInfo() {
|
||
|
|
const node = this.node;
|
||
|
|
if (node.type !== 0 && node.type !== 1) return {
|
||
|
|
node,
|
||
|
|
hasSingleRootChild: true,
|
||
|
|
isLastEffectiveChild: []
|
||
|
|
};
|
||
|
|
const cached = childContextInfoCache.get(this);
|
||
|
|
if (cached && cached.node === node) return cached;
|
||
|
|
const { children } = node;
|
||
|
|
const isLastEffectiveChild = new Array(children.length);
|
||
|
|
let hasFollowingEffectiveChild = false;
|
||
|
|
for (let i = children.length - 1; i >= 0; i--) {
|
||
|
|
isLastEffectiveChild[i] = !hasFollowingEffectiveChild;
|
||
|
|
if (!isComponentChild(children[i])) hasFollowingEffectiveChild = true;
|
||
|
|
}
|
||
|
|
const childInfo = {
|
||
|
|
node,
|
||
|
|
hasSingleRootChild: hasSingleRootChild(children),
|
||
|
|
isLastEffectiveChild
|
||
|
|
};
|
||
|
|
childContextInfoCache.set(this, childInfo);
|
||
|
|
return childInfo;
|
||
|
|
}
|
||
|
|
isSingleRootChild(childInfo) {
|
||
|
|
if (this.inVFor || !childInfo.hasSingleRootChild) return false;
|
||
|
|
if (this.node.type === 0) return true;
|
||
|
|
return this.node.type === 1 && (this.node.tagType === 3 || isTransitionNode(this.node) || isKeepAliveTag(this.node.tag)) && !!this.parent && this.isSingleRoot;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
function hasSingleRootChild(children) {
|
||
|
|
let nonCommentChildren = 0;
|
||
|
|
let hasEncounteredIf = false;
|
||
|
|
let isSingleIfBlock = true;
|
||
|
|
for (const child of children) {
|
||
|
|
if ((0, _vue_compiler_dom.isCommentOrWhitespace)(child)) continue;
|
||
|
|
nonCommentChildren++;
|
||
|
|
if (isIfChild(child)) {
|
||
|
|
if (hasEncounteredIf) isSingleIfBlock = false;
|
||
|
|
hasEncounteredIf = true;
|
||
|
|
} else if (!hasEncounteredIf || !isElseChild(child)) isSingleIfBlock = false;
|
||
|
|
}
|
||
|
|
return nonCommentChildren === 1 || isSingleIfBlock;
|
||
|
|
}
|
||
|
|
function isComponentChild(child) {
|
||
|
|
return child.type === 1 && child.tagType === 1;
|
||
|
|
}
|
||
|
|
function isIfChild(child) {
|
||
|
|
return child.type === 9 || child.type === 1 && !!(0, _vue_compiler_dom.findDir)(child, "if");
|
||
|
|
}
|
||
|
|
function isElseChild(child) {
|
||
|
|
return child.type === 1 && !!(0, _vue_compiler_dom.findDir)(child, /^else(-if)?$/, true);
|
||
|
|
}
|
||
|
|
const defaultOptions = {
|
||
|
|
filename: "",
|
||
|
|
prefixIdentifiers: true,
|
||
|
|
hoistStatic: false,
|
||
|
|
hmr: false,
|
||
|
|
cacheHandlers: false,
|
||
|
|
nodeTransforms: [],
|
||
|
|
directiveTransforms: {},
|
||
|
|
transformHoist: null,
|
||
|
|
isBuiltInComponent: _vue_shared.NOOP,
|
||
|
|
isCustomElement: _vue_shared.NOOP,
|
||
|
|
expressionPlugins: [],
|
||
|
|
scopeId: null,
|
||
|
|
slotted: true,
|
||
|
|
ssr: false,
|
||
|
|
inSSR: false,
|
||
|
|
ssrCssVars: ``,
|
||
|
|
bindingMetadata: _vue_shared.EMPTY_OBJ,
|
||
|
|
inline: false,
|
||
|
|
isTS: false,
|
||
|
|
onError: _vue_compiler_dom.defaultOnError,
|
||
|
|
onWarn: _vue_compiler_dom.defaultOnWarn
|
||
|
|
};
|
||
|
|
function transform(node, options = {}) {
|
||
|
|
const ir = {
|
||
|
|
type: 0,
|
||
|
|
node,
|
||
|
|
source: node.source,
|
||
|
|
template: new TemplateRegistry(),
|
||
|
|
component: /* @__PURE__ */ new Set(),
|
||
|
|
directive: /* @__PURE__ */ new Set(),
|
||
|
|
block: newBlock(node),
|
||
|
|
hasTemplateRef: false
|
||
|
|
};
|
||
|
|
const context = new TransformContext(ir, node, options);
|
||
|
|
transformNode(context);
|
||
|
|
ir.node.imports = context.imports;
|
||
|
|
return ir;
|
||
|
|
}
|
||
|
|
function transformNode(context) {
|
||
|
|
let { node } = context;
|
||
|
|
const { nodeTransforms } = context.options;
|
||
|
|
const exitFns = [];
|
||
|
|
for (const nodeTransform of nodeTransforms) {
|
||
|
|
const onExit = nodeTransform(node, context);
|
||
|
|
if (onExit) {
|
||
|
|
if ((0, _vue_shared.isArray)(onExit)) exitFns.push(...onExit);
|
||
|
|
else exitFns.push(onExit);
|
||
|
|
}
|
||
|
|
if (!context.node) return;
|
||
|
|
else node = context.node;
|
||
|
|
}
|
||
|
|
context.node = node;
|
||
|
|
let i = exitFns.length;
|
||
|
|
while (i--) exitFns[i]();
|
||
|
|
if (context.node.type === 0) context.registerTemplate();
|
||
|
|
}
|
||
|
|
function createStructuralDirectiveTransform(name, fn) {
|
||
|
|
const matches = (n) => (0, _vue_shared.isString)(name) ? n === name : name.includes(n);
|
||
|
|
return (node, context) => {
|
||
|
|
if (node.type === 1) {
|
||
|
|
const { props } = node;
|
||
|
|
if (node.tagType === 3 && props.some(_vue_compiler_dom.isVSlot)) return;
|
||
|
|
const exitFns = [];
|
||
|
|
for (const prop of props) if (prop.type === 7 && matches(prop.name)) {
|
||
|
|
const onExit = fn(node, prop, context);
|
||
|
|
if (onExit) exitFns.push(onExit);
|
||
|
|
}
|
||
|
|
return exitFns;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Build a "next-id" map from an occupied number set.
|
||
|
|
* For each consecutive range [start..end], map every v in the range to end + 1.
|
||
|
|
* Example: input [0, 1, 2, 4] => { 0: 3, 1: 3, 2: 3, 4: 5 }.
|
||
|
|
*/
|
||
|
|
function buildNextIdMap(nums) {
|
||
|
|
const map = /* @__PURE__ */ new Map();
|
||
|
|
const arr = Array.from(new Set(nums)).sort((a, b) => a - b);
|
||
|
|
if (arr.length === 0) return map;
|
||
|
|
for (let i = 0; i < arr.length; i++) {
|
||
|
|
let start = arr[i];
|
||
|
|
let end = start;
|
||
|
|
while (i + 1 < arr.length && arr[i + 1] === end + 1) {
|
||
|
|
i++;
|
||
|
|
end = arr[i];
|
||
|
|
}
|
||
|
|
for (let v = start; v <= end; v++) map.set(v, end + 1);
|
||
|
|
}
|
||
|
|
return map;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Return the available id for n using a map built by buildNextIdMap:
|
||
|
|
* - If n is not occupied, return n.
|
||
|
|
* - If n is occupied, return the mapped value
|
||
|
|
*/
|
||
|
|
function getNextId(map, n) {
|
||
|
|
if (map && map.has(n)) return map.get(n);
|
||
|
|
return n;
|
||
|
|
}
|
||
|
|
function isComponentNode(node) {
|
||
|
|
return node.type === 1 && node.tagType === 1;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/utils.ts
|
||
|
|
/**
|
||
|
|
* Run a helper call inside the once ambient: a helper that creates its own
|
||
|
|
* effects at a v-once site has them run once like compiled ones do.
|
||
|
|
*/
|
||
|
|
function genOnce(call, context) {
|
||
|
|
return genCall(context.helper("withOnce"), ["() => ", ...call]);
|
||
|
|
}
|
||
|
|
const IMPORT_EXP_START = "__IMPORT_EXP_START__";
|
||
|
|
const IMPORT_EXP_END = "__IMPORT_EXP_END__";
|
||
|
|
const IMPORT_EXPR_RE = new RegExp(`${IMPORT_EXP_START}(.*?)${IMPORT_EXP_END}`, "g");
|
||
|
|
const NEWLINE = Symbol(`newline`);
|
||
|
|
/** increase offset but don't push actual code */
|
||
|
|
const LF = Symbol(`line feed`);
|
||
|
|
const INDENT_START = Symbol(`indent start`);
|
||
|
|
const INDENT_END = Symbol(`indent end`);
|
||
|
|
function buildCodeFragment(...frag) {
|
||
|
|
return [
|
||
|
|
frag,
|
||
|
|
frag.push.bind(frag),
|
||
|
|
frag.unshift.bind(frag)
|
||
|
|
];
|
||
|
|
}
|
||
|
|
function genMulti([left, right, seg, placeholder], ...frags) {
|
||
|
|
if (placeholder) {
|
||
|
|
while (frags.length > 0 && !frags[frags.length - 1]) frags.pop();
|
||
|
|
frags = frags.map((frag) => frag || placeholder);
|
||
|
|
} else frags = frags.filter(Boolean);
|
||
|
|
const frag = [];
|
||
|
|
push(left);
|
||
|
|
for (let [i, fn] of frags.entries()) {
|
||
|
|
push(fn);
|
||
|
|
if (i < frags.length - 1) push(seg);
|
||
|
|
}
|
||
|
|
push(right);
|
||
|
|
return frag;
|
||
|
|
function push(fn) {
|
||
|
|
if (!(0, _vue_shared.isArray)(fn)) fn = [fn];
|
||
|
|
frag.push(...fn);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
const DELIMITERS_ARRAY = [
|
||
|
|
"[",
|
||
|
|
"]",
|
||
|
|
", "
|
||
|
|
];
|
||
|
|
const DELIMITERS_ARRAY_NEWLINE = [
|
||
|
|
[
|
||
|
|
"[",
|
||
|
|
INDENT_START,
|
||
|
|
NEWLINE
|
||
|
|
],
|
||
|
|
[
|
||
|
|
INDENT_END,
|
||
|
|
NEWLINE,
|
||
|
|
"]"
|
||
|
|
],
|
||
|
|
[",", NEWLINE]
|
||
|
|
];
|
||
|
|
const DELIMITERS_OBJECT = [
|
||
|
|
"{ ",
|
||
|
|
" }",
|
||
|
|
", "
|
||
|
|
];
|
||
|
|
const DELIMITERS_OBJECT_NEWLINE = [
|
||
|
|
[
|
||
|
|
"{",
|
||
|
|
INDENT_START,
|
||
|
|
NEWLINE
|
||
|
|
],
|
||
|
|
[
|
||
|
|
INDENT_END,
|
||
|
|
NEWLINE,
|
||
|
|
"}"
|
||
|
|
],
|
||
|
|
[",", NEWLINE]
|
||
|
|
];
|
||
|
|
function genCall(name, ...frags) {
|
||
|
|
const hasPlaceholder = (0, _vue_shared.isArray)(name);
|
||
|
|
return [hasPlaceholder ? name[0] : name, ...genMulti([
|
||
|
|
"(",
|
||
|
|
")",
|
||
|
|
", ",
|
||
|
|
hasPlaceholder ? name[1] : "null"
|
||
|
|
], ...frags)];
|
||
|
|
}
|
||
|
|
function getParserOptions(plugins) {
|
||
|
|
return { plugins: plugins ? plugins.some((plugin) => plugin === "typescript") ? plugins : [...plugins, "typescript"] : ["typescript"] };
|
||
|
|
}
|
||
|
|
function codeFragmentToString(code, context) {
|
||
|
|
const { options: { filename, sourceMap } } = context;
|
||
|
|
let map;
|
||
|
|
if (sourceMap) {
|
||
|
|
map = new source_map_js.SourceMapGenerator();
|
||
|
|
map.setSourceContent(filename, context.ir.source);
|
||
|
|
map._sources.add(filename);
|
||
|
|
}
|
||
|
|
let codegen = "";
|
||
|
|
const pos = {
|
||
|
|
line: 1,
|
||
|
|
column: 1,
|
||
|
|
offset: 0
|
||
|
|
};
|
||
|
|
let indentLevel = 0;
|
||
|
|
for (let frag of code) {
|
||
|
|
if (!frag) continue;
|
||
|
|
if (frag === NEWLINE) frag = [`\n${` `.repeat(indentLevel)}`, 0];
|
||
|
|
else if (frag === INDENT_START) {
|
||
|
|
indentLevel++;
|
||
|
|
continue;
|
||
|
|
} else if (frag === INDENT_END) {
|
||
|
|
indentLevel--;
|
||
|
|
continue;
|
||
|
|
} else if (frag === LF) {
|
||
|
|
pos.line++;
|
||
|
|
pos.column = 0;
|
||
|
|
pos.offset++;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if ((0, _vue_shared.isString)(frag)) frag = [frag];
|
||
|
|
let [code, newlineIndex = -2, loc, name] = frag;
|
||
|
|
codegen += code;
|
||
|
|
if (map) {
|
||
|
|
if (loc) addMapping(loc.start, name);
|
||
|
|
if (newlineIndex === -3) (0, _vue_compiler_dom.advancePositionWithMutation)(pos, code);
|
||
|
|
else {
|
||
|
|
pos.offset += code.length;
|
||
|
|
if (newlineIndex === -2) pos.column += code.length;
|
||
|
|
else {
|
||
|
|
if (newlineIndex === -1) newlineIndex = code.length - 1;
|
||
|
|
pos.line++;
|
||
|
|
pos.column = code.length - newlineIndex;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (loc && loc !== _vue_compiler_dom.locStub) addMapping(loc.end);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return [codegen, map];
|
||
|
|
function addMapping(loc, name = null) {
|
||
|
|
const { _names, _mappings } = map;
|
||
|
|
if (name !== null && !_names.has(name)) _names.add(name);
|
||
|
|
_mappings.add({
|
||
|
|
originalLine: loc.line,
|
||
|
|
originalColumn: loc.column - 1,
|
||
|
|
generatedLine: pos.line,
|
||
|
|
generatedColumn: pos.column - 1,
|
||
|
|
source: filename,
|
||
|
|
name
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/** Formats a numeric flags argument with its dev-only name annotation. */
|
||
|
|
function genFlags(flags, names) {
|
||
|
|
return `${flags} /* ${names.join(", ")} */`;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/dom.ts
|
||
|
|
function genInsertNode({ parent, elements, anchor }, { helper }) {
|
||
|
|
let element = elements.map((el) => `n${el}`).join(", ");
|
||
|
|
if (elements.length > 1) element = `[${element}]`;
|
||
|
|
return [NEWLINE, ...genCall(helper("insert"), element, `n${parent}`, anchor === void 0 ? void 0 : `n${anchor}`)];
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/expression.ts
|
||
|
|
function genExpression(node, context, assignment, asParams = false) {
|
||
|
|
node = context.getExpressionReplacement(node);
|
||
|
|
const { content, ast, isStatic, loc } = node;
|
||
|
|
const { options } = context;
|
||
|
|
const { inline } = options;
|
||
|
|
if (isStatic) return [[
|
||
|
|
JSON.stringify(content),
|
||
|
|
-2,
|
||
|
|
loc
|
||
|
|
]];
|
||
|
|
if (!node.content.trim() || ast === false || isConstantExpression(node)) return [[
|
||
|
|
content,
|
||
|
|
-2,
|
||
|
|
loc
|
||
|
|
], assignment && ` = ${assignment}`];
|
||
|
|
if (ast === null) return genIdentifier(content, context, loc, assignment);
|
||
|
|
const ids = [];
|
||
|
|
const parentStackMap = /* @__PURE__ */ new Map();
|
||
|
|
const parentStack = [];
|
||
|
|
(0, _vue_compiler_dom.walkIdentifiers)(ast, (id, _, __, isReference, isLocal) => {
|
||
|
|
if (isLocal) {
|
||
|
|
if (!id.typeAnnotation && !id.optional) return;
|
||
|
|
} else if (!isReference) return;
|
||
|
|
ids.push(id);
|
||
|
|
parentStackMap.set(id, parentStack.slice());
|
||
|
|
}, asParams, parentStack);
|
||
|
|
let hasMemberExpression = false;
|
||
|
|
if (ids.length) {
|
||
|
|
const [frag, push] = buildCodeFragment();
|
||
|
|
let lastEnd = 0;
|
||
|
|
ids.sort((a, b) => a.start - b.start).forEach((id) => {
|
||
|
|
const idStart = id.start - 1;
|
||
|
|
const idEnd = id.end - 1;
|
||
|
|
const source = content.slice(idStart, idEnd);
|
||
|
|
const parentStack = parentStackMap.get(id);
|
||
|
|
const parent = parentStack[parentStack.length - 1];
|
||
|
|
let start = idStart;
|
||
|
|
let end = idEnd;
|
||
|
|
if (inline && options.bindingMetadata && options.bindingMetadata[source] === "setup-let" && parent && parent.type === "UpdateExpression" && parent.argument === id) {
|
||
|
|
start = parent.start - 1;
|
||
|
|
end = parent.end - 1;
|
||
|
|
}
|
||
|
|
if (start < lastEnd) return;
|
||
|
|
const leadingText = content.slice(lastEnd, start);
|
||
|
|
if (leadingText.length) push([leadingText, -3]);
|
||
|
|
hasMemberExpression || (hasMemberExpression = parent && (parent.type === "MemberExpression" || parent.type === "OptionalMemberExpression"));
|
||
|
|
push(...genIdentifier(asParams ? id.name : source, context, {
|
||
|
|
start: (0, _vue_compiler_dom.advancePositionWithClone)(node.loc.start, source, start),
|
||
|
|
end: (0, _vue_compiler_dom.advancePositionWithClone)(node.loc.start, source, end),
|
||
|
|
source
|
||
|
|
}, hasMemberExpression ? void 0 : assignment, id, parent, parentStack, node));
|
||
|
|
lastEnd = end;
|
||
|
|
});
|
||
|
|
if (lastEnd < content.length) push([content.slice(lastEnd), -3]);
|
||
|
|
if (assignment && hasMemberExpression) push(` = ${assignment}`);
|
||
|
|
return frag;
|
||
|
|
} else return [[
|
||
|
|
content,
|
||
|
|
-3,
|
||
|
|
loc
|
||
|
|
]];
|
||
|
|
}
|
||
|
|
function genIdentifier(raw, context, loc, assignment, id, parent, parentStack, sourceNode) {
|
||
|
|
const { options, helper, identifiers } = context;
|
||
|
|
const { inline, bindingMetadata } = options;
|
||
|
|
let name = raw;
|
||
|
|
const idMap = identifiers[raw];
|
||
|
|
if (idMap && idMap.length) {
|
||
|
|
const replacement = idMap[0];
|
||
|
|
if ((0, _vue_shared.isString)(replacement)) {
|
||
|
|
if (parent && parent.type === "ObjectProperty" && parent.shorthand) return [[
|
||
|
|
`${name}: ${replacement}`,
|
||
|
|
-2,
|
||
|
|
loc
|
||
|
|
]];
|
||
|
|
else return [[
|
||
|
|
replacement,
|
||
|
|
-2,
|
||
|
|
loc
|
||
|
|
]];
|
||
|
|
} else return genExpression(replacement, context, assignment);
|
||
|
|
}
|
||
|
|
let prefix;
|
||
|
|
const type = bindingMetadata && bindingMetadata[raw];
|
||
|
|
const isDestructureAssignment = parent && (0, _vue_compiler_dom.isInDestructureAssignment)(parent, parentStack || []);
|
||
|
|
const isAssignmentLVal = parent && parent.type === "AssignmentExpression" && parent.left === id;
|
||
|
|
const isUpdateArg = parent && parent.type === "UpdateExpression" && parent.argument === id;
|
||
|
|
if ((0, _vue_compiler_dom.isStaticProperty)(parent) && parent.shorthand && !(inline && type === "setup-let" && isDestructureAssignment)) prefix = `${raw}: `;
|
||
|
|
if (inline) switch (type) {
|
||
|
|
case "setup-let":
|
||
|
|
if (isAssignmentLVal) {
|
||
|
|
const { right, operator } = parent;
|
||
|
|
const source = sourceNode;
|
||
|
|
const sourceContent = source.content;
|
||
|
|
const rightStart = right.start - 1;
|
||
|
|
const rightEnd = right.end - 1;
|
||
|
|
const rightContent = sourceContent.slice(rightStart, rightEnd);
|
||
|
|
const rightExp = (0, _vue_compiler_dom.createSimpleExpression)(rightContent, false, {
|
||
|
|
start: (0, _vue_compiler_dom.advancePositionWithClone)(source.loc.start, sourceContent, rightStart),
|
||
|
|
end: (0, _vue_compiler_dom.advancePositionWithClone)(source.loc.start, sourceContent, rightEnd),
|
||
|
|
source: rightContent
|
||
|
|
});
|
||
|
|
rightExp.ast = parseExp(context, rightContent);
|
||
|
|
return [
|
||
|
|
prefix,
|
||
|
|
`${helper("isRef")}(${raw}) ? ${raw}.value ${operator} `,
|
||
|
|
...genExpression(rightExp, context),
|
||
|
|
` : `,
|
||
|
|
[
|
||
|
|
raw,
|
||
|
|
-2,
|
||
|
|
loc,
|
||
|
|
name
|
||
|
|
]
|
||
|
|
];
|
||
|
|
} else if (isUpdateArg) {
|
||
|
|
const { prefix: isPrefix, operator } = parent;
|
||
|
|
const updatePrefix = isPrefix ? operator : ``;
|
||
|
|
const updatePostfix = isPrefix ? `` : operator;
|
||
|
|
raw = `${helper("isRef")}(${raw}) ? ${updatePrefix}${raw}.value${updatePostfix} : ${updatePrefix}${raw}${updatePostfix}`;
|
||
|
|
} else if (!isDestructureAssignment) name = raw = assignment ? `${helper("isRef")}(${raw}) ? (${raw}.value = ${assignment}) : (${raw} = ${assignment})` : unref();
|
||
|
|
break;
|
||
|
|
case "setup-ref":
|
||
|
|
name = raw = withAssignment(`${raw}.value`);
|
||
|
|
break;
|
||
|
|
case "setup-maybe-ref":
|
||
|
|
raw = isAssignmentLVal || isUpdateArg || isDestructureAssignment ? name = `${raw}.value` : assignment ? `${helper("isRef")}(${raw}) ? (${raw}.value = ${assignment}) : null` : unref();
|
||
|
|
break;
|
||
|
|
case "props":
|
||
|
|
raw = (0, _vue_shared.genPropsAccessExp)(raw);
|
||
|
|
break;
|
||
|
|
case "props-aliased":
|
||
|
|
raw = (0, _vue_shared.genPropsAccessExp)(bindingMetadata.__propsAliases[raw]);
|
||
|
|
break;
|
||
|
|
default: raw = withAssignment(raw);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
if (canPrefix(raw)) {
|
||
|
|
if (type === "props-aliased") raw = `$props['${bindingMetadata.__propsAliases[raw]}']`;
|
||
|
|
else raw = `${type === "props" ? "$props" : "_ctx"}.${raw}`;
|
||
|
|
}
|
||
|
|
raw = withAssignment(raw);
|
||
|
|
}
|
||
|
|
return [prefix, [
|
||
|
|
raw,
|
||
|
|
-2,
|
||
|
|
loc,
|
||
|
|
name
|
||
|
|
]];
|
||
|
|
function withAssignment(s) {
|
||
|
|
return assignment ? `${s} = ${assignment}` : s;
|
||
|
|
}
|
||
|
|
function unref() {
|
||
|
|
return `${helper("unref")}(${raw})`;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function canPrefix(name) {
|
||
|
|
if ((0, _vue_shared.isGloballyAllowed)(name)) return false;
|
||
|
|
if (name === "require" || name === "$props" || name === "$emit" || name === "$attrs" || name === "$slots") return false;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
function processExpressions(context, expressions, shouldDeclare) {
|
||
|
|
const expressionReplacements = /* @__PURE__ */ new Map();
|
||
|
|
const { seenVariable, variableToExpMap, expressionRecords, seenIdentifier, updatedVariable, eagerVariable } = analyzeExpressions(expressions);
|
||
|
|
const reservedNames = new Set(seenIdentifier);
|
||
|
|
const varDeclarations = processRepeatedVariables(context, seenVariable, variableToExpMap, expressionRecords, seenIdentifier, updatedVariable, eagerVariable, reservedNames, expressionReplacements);
|
||
|
|
const expDeclarations = processRepeatedExpressions(context, expressions, varDeclarations, updatedVariable, expressionRecords, reservedNames, expressionReplacements);
|
||
|
|
return {
|
||
|
|
...genDeclarations([...varDeclarations, ...expDeclarations], context, shouldDeclare),
|
||
|
|
expressionReplacements
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function analyzeExpressions(expressions) {
|
||
|
|
const seenVariable = Object.create(null);
|
||
|
|
const variableToExpMap = /* @__PURE__ */ new Map();
|
||
|
|
const expressionRecords = /* @__PURE__ */ new Map();
|
||
|
|
const seenIdentifier = /* @__PURE__ */ new Set();
|
||
|
|
const updatedVariable = /* @__PURE__ */ new Set();
|
||
|
|
const eagerVariable = /* @__PURE__ */ new Set();
|
||
|
|
const getRecord = (exp) => {
|
||
|
|
let record = expressionRecords.get(exp);
|
||
|
|
if (!record) expressionRecords.set(exp, record = { variables: [] });
|
||
|
|
return record;
|
||
|
|
};
|
||
|
|
const registerVariable = (name, exp, isIdentifier, loc, parentStack = []) => {
|
||
|
|
if (isIdentifier) seenIdentifier.add(name);
|
||
|
|
seenVariable[name] = (seenVariable[name] || 0) + 1;
|
||
|
|
variableToExpMap.set(name, (variableToExpMap.get(name) || /* @__PURE__ */ new Set()).add(exp));
|
||
|
|
getRecord(exp).variables.push({
|
||
|
|
name,
|
||
|
|
loc
|
||
|
|
});
|
||
|
|
if (parentStack.some((p) => p.type === "UpdateExpression" || p.type === "AssignmentExpression")) updatedVariable.add(name);
|
||
|
|
if (isIdentifier || !isLazilyEvaluated(parentStack)) eagerVariable.add(name);
|
||
|
|
};
|
||
|
|
for (const exp of expressions) {
|
||
|
|
if (!exp.ast) {
|
||
|
|
exp.ast === null && registerVariable(exp.content, exp, true);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const seenParents = /* @__PURE__ */ new Set();
|
||
|
|
(0, _vue_compiler_dom.walkIdentifiers)(exp.ast, (currentNode, parent, parentStack) => {
|
||
|
|
if (parent && isMemberExpression$3(parent) && !seenParents.has(parent)) {
|
||
|
|
var _parentStack$index;
|
||
|
|
seenParents.add(parent);
|
||
|
|
let hasGlobalIdentifier = false;
|
||
|
|
const memberExp = extractMemberExpression(parent, (id) => {
|
||
|
|
registerVariable(id.name, exp, true, {
|
||
|
|
start: id.start,
|
||
|
|
end: id.end
|
||
|
|
});
|
||
|
|
if ((0, _vue_shared.isGloballyAllowed)(id.name)) hasGlobalIdentifier = true;
|
||
|
|
});
|
||
|
|
if (memberExp === void 0) return;
|
||
|
|
const parentOfMemberExp = parentStack[parentStack.length - 2];
|
||
|
|
if (parentOfMemberExp && isCallExpression(parentOfMemberExp)) return;
|
||
|
|
let chainChild = parent;
|
||
|
|
let index = parentStack.length - 2;
|
||
|
|
while (((_parentStack$index = parentStack[index]) === null || _parentStack$index === void 0 ? void 0 : _parentStack$index.type) === "TSNonNullExpression") chainChild = parentStack[index--];
|
||
|
|
const chainParent = parentStack[index];
|
||
|
|
if (chainParent && chainParent.type === "OptionalMemberExpression" && !chainParent.optional && chainParent.object === chainChild) return;
|
||
|
|
if (hasGlobalIdentifier) return;
|
||
|
|
registerVariable(memberExp, exp, false, {
|
||
|
|
start: parent.start,
|
||
|
|
end: parent.end
|
||
|
|
}, parentStack);
|
||
|
|
} else if (!parentStack.some(isMemberExpression$3)) registerVariable(currentNode.name, exp, true, {
|
||
|
|
start: currentNode.start,
|
||
|
|
end: currentNode.end
|
||
|
|
}, parentStack);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
seenVariable,
|
||
|
|
seenIdentifier,
|
||
|
|
variableToExpMap,
|
||
|
|
expressionRecords,
|
||
|
|
updatedVariable,
|
||
|
|
eagerVariable
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function getProcessedExpression(exp, expressionReplacements) {
|
||
|
|
return expressionReplacements.get(exp) || exp;
|
||
|
|
}
|
||
|
|
function setExpressionReplacement(expressionReplacements, exp, content, ast) {
|
||
|
|
expressionReplacements.set(exp, (0, _vue_shared.extend)({ ast }, (0, _vue_compiler_dom.createSimpleExpression)(content, exp.isStatic, exp.loc, exp.constType)));
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Whether a node is only evaluated lazily, given its ancestor chain - i.e. it
|
||
|
|
* may be skipped entirely when a preceding condition is not met.
|
||
|
|
*/
|
||
|
|
const isLazilyEvaluated = (parentStack) => {
|
||
|
|
for (let i = parentStack.length - 1; i > 0; i--) {
|
||
|
|
const child = parentStack[i];
|
||
|
|
const parent = parentStack[i - 1];
|
||
|
|
switch (parent.type) {
|
||
|
|
case "ConditionalExpression":
|
||
|
|
if (parent.test !== child) return true;
|
||
|
|
break;
|
||
|
|
case "LogicalExpression":
|
||
|
|
if (parent.right === child) return true;
|
||
|
|
break;
|
||
|
|
case "OptionalCallExpression":
|
||
|
|
if (parent.arguments.includes(child)) return true;
|
||
|
|
break;
|
||
|
|
case "OptionalMemberExpression":
|
||
|
|
if (parent.computed && parent.property === child) return true;
|
||
|
|
break;
|
||
|
|
default: if ((0, _vue_compiler_dom.isFunctionType)(parent)) return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
};
|
||
|
|
function processRepeatedVariables(context, seenVariable, variableToExpMap, expressionRecords, seenIdentifier, updatedVariable, eagerVariable, reservedNames, expressionReplacements) {
|
||
|
|
const declarations = [];
|
||
|
|
const declaredNames = /* @__PURE__ */ new Set();
|
||
|
|
const replacementPlan = /* @__PURE__ */ new Map();
|
||
|
|
for (const [name, exps] of variableToExpMap) {
|
||
|
|
if (updatedVariable.has(name)) continue;
|
||
|
|
if (!eagerVariable.has(name)) continue;
|
||
|
|
if ((0, _vue_shared.isGloballyAllowed)(name)) continue;
|
||
|
|
if (seenVariable[name] > 1 && exps.size > 0) {
|
||
|
|
const isIdentifier = seenIdentifier.has(name);
|
||
|
|
const varName = isIdentifier ? name : getUniqueDeclarationName(genVarName(name), reservedNames);
|
||
|
|
exps.forEach((node) => {
|
||
|
|
if (node.ast && varName !== name) {
|
||
|
|
for (const variable of getExpressionVariables(expressionRecords, node)) if (variable.name === name && variable.loc) queueContentReplacement(replacementPlan, node, {
|
||
|
|
start: variable.loc.start - 1,
|
||
|
|
end: variable.loc.end - 1,
|
||
|
|
content: varName
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
if (!declaredNames.has(varName) && (!isIdentifier || shouldDeclareVariable(name, expressionRecords, exps))) {
|
||
|
|
declaredNames.add(varName);
|
||
|
|
declarations.push({
|
||
|
|
name: varName,
|
||
|
|
isIdentifier,
|
||
|
|
value: (0, _vue_shared.extend)({ ast: isIdentifier ? null : parseExp(context, name) }, (0, _vue_compiler_dom.createSimpleExpression)(name)),
|
||
|
|
rawName: name,
|
||
|
|
exps,
|
||
|
|
seenCount: seenVariable[name]
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
applyReplacementPlan(context, expressionReplacements, replacementPlan);
|
||
|
|
return declarations;
|
||
|
|
}
|
||
|
|
function shouldDeclareVariable(name, expressionRecords, exps) {
|
||
|
|
const variableUsages = [];
|
||
|
|
let allSingleVariable = true;
|
||
|
|
let hasRepeatedName = false;
|
||
|
|
let hasDifferentLength = false;
|
||
|
|
outer: for (const exp of exps) {
|
||
|
|
const variables = getExpressionVariables(expressionRecords, exp);
|
||
|
|
if (allSingleVariable && variables.length !== 1) allSingleVariable = false;
|
||
|
|
if (!hasDifferentLength && variableUsages.length > 0 && variables.length !== variableUsages[0].length) hasDifferentLength = true;
|
||
|
|
let nameCount = 0;
|
||
|
|
for (const variable of variables) if (variable.name === name && ++nameCount > 1) {
|
||
|
|
hasRepeatedName = true;
|
||
|
|
break outer;
|
||
|
|
}
|
||
|
|
variableUsages.push(variables);
|
||
|
|
}
|
||
|
|
if (allSingleVariable) return true;
|
||
|
|
if (hasRepeatedName) return true;
|
||
|
|
const first = variableUsages[0];
|
||
|
|
if (hasDifferentLength) {
|
||
|
|
for (const variables of variableUsages) {
|
||
|
|
if (variables.length === first.length) continue;
|
||
|
|
const longer = variables.length > first.length ? variables : first;
|
||
|
|
const shorter = variables.length > first.length ? first : variables;
|
||
|
|
const shorterNames = /* @__PURE__ */ new Set();
|
||
|
|
for (const variable of shorter) shorterNames.add(variable.name);
|
||
|
|
let isSubset = true;
|
||
|
|
for (const variable of longer) if (!shorterNames.has(variable.name)) {
|
||
|
|
isSubset = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (isSubset) return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
for (const variables of variableUsages) for (let i = 0; i < variables.length; i++) if (variables[i].name !== first[i].name) return true;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
function processRepeatedExpressions(context, expressions, varDeclarations, updatedVariable, expressionRecords, reservedNames, expressionReplacements) {
|
||
|
|
const declarations = [];
|
||
|
|
const seenExp = /* @__PURE__ */ new Map();
|
||
|
|
for (const exp of expressions) {
|
||
|
|
var _expressionRecords$ge;
|
||
|
|
const vars = (_expressionRecords$ge = expressionRecords.get(exp)) === null || _expressionRecords$ge === void 0 ? void 0 : _expressionRecords$ge.variables;
|
||
|
|
if (!vars) continue;
|
||
|
|
const processed = getProcessedExpression(exp, expressionReplacements);
|
||
|
|
if (canCacheExpression(processed, vars, updatedVariable)) {
|
||
|
|
const seen = seenExp.get(processed.content);
|
||
|
|
if (seen) seen.count++;
|
||
|
|
else seenExp.set(processed.content, {
|
||
|
|
count: 1,
|
||
|
|
first: exp
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
const repeatedExpressions = [...seenExp].sort(([contentA], [contentB]) => contentB.length - contentA.length);
|
||
|
|
for (const [content, { count, first }] of repeatedExpressions) if (count > 1) {
|
||
|
|
const removedDeclarations = [];
|
||
|
|
for (let i = varDeclarations.length - 1; i >= 0; i--) {
|
||
|
|
const item = varDeclarations[i];
|
||
|
|
if (!item.exps || !item.seenCount) continue;
|
||
|
|
if ([...item.exps].every((node) => getProcessedExpression(node, expressionReplacements).content === content && item.seenCount === count)) {
|
||
|
|
removedDeclarations.push({
|
||
|
|
name: item.name,
|
||
|
|
rawName: item.rawName
|
||
|
|
});
|
||
|
|
reservedNames.delete(item.name);
|
||
|
|
varDeclarations.splice(i, 1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
const value = (0, _vue_shared.extend)({}, getProcessedExpression(first, expressionReplacements));
|
||
|
|
const restorePlan = [];
|
||
|
|
for (const { name, rawName } of removedDeclarations) restorePlan.push(...findIdentifierReplacements(value, name, rawName));
|
||
|
|
if (restorePlan.length) {
|
||
|
|
value.content = applyContentReplacements(value.content, restorePlan);
|
||
|
|
if (value.ast) value.ast = parseExp(context, value.content);
|
||
|
|
}
|
||
|
|
const varName = getUniqueDeclarationName(genVarName(content), reservedNames);
|
||
|
|
declarations.push({
|
||
|
|
name: varName,
|
||
|
|
value
|
||
|
|
});
|
||
|
|
for (const exp of expressions) {
|
||
|
|
const processed = getProcessedExpression(exp, expressionReplacements);
|
||
|
|
if (processed.content === content) setExpressionReplacement(expressionReplacements, exp, varName, null);
|
||
|
|
else if (!content.includes("?.") && processed.content.includes(content)) {
|
||
|
|
const replacements = findContentReplacements(processed, content, varName);
|
||
|
|
if (replacements.length) {
|
||
|
|
const replacedContent = applyContentReplacements(processed.content, replacements);
|
||
|
|
setExpressionReplacement(expressionReplacements, exp, replacedContent, parseExp(context, replacedContent));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return declarations;
|
||
|
|
}
|
||
|
|
function canCacheExpression(processed, vars, updatedVariable) {
|
||
|
|
if (!processed.ast || processed.ast.type === "Identifier") return false;
|
||
|
|
for (const { name } of vars) if (updatedVariable.has(name) || (0, _vue_shared.isGloballyAllowed)(name)) return false;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
function getExpressionVariables(expressionRecords, exp) {
|
||
|
|
var _expressionRecords$ge2;
|
||
|
|
return ((_expressionRecords$ge2 = expressionRecords.get(exp)) === null || _expressionRecords$ge2 === void 0 ? void 0 : _expressionRecords$ge2.variables) || [];
|
||
|
|
}
|
||
|
|
function queueContentReplacement(replacementPlan, exp, replacement) {
|
||
|
|
const replacements = replacementPlan.get(exp);
|
||
|
|
if (replacements) replacements.push(replacement);
|
||
|
|
else replacementPlan.set(exp, [replacement]);
|
||
|
|
}
|
||
|
|
function applyReplacementPlan(context, expressionReplacements, replacementPlan) {
|
||
|
|
for (const [exp, replacements] of replacementPlan) {
|
||
|
|
if (!replacements.length) continue;
|
||
|
|
const content = applyContentReplacements(getProcessedExpression(exp, expressionReplacements).content, replacements);
|
||
|
|
setExpressionReplacement(expressionReplacements, exp, content, parseExp(context, content));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function findContentReplacements(exp, content, replacement) {
|
||
|
|
const nodeRanges = getNodeRanges(exp);
|
||
|
|
if (!nodeRanges.size) return [];
|
||
|
|
const replacements = [];
|
||
|
|
let searchStart = 0;
|
||
|
|
let start = exp.content.indexOf(content, searchStart);
|
||
|
|
while (start !== -1) {
|
||
|
|
const end = start + content.length;
|
||
|
|
if (nodeRanges.has(`${start}:${end}`)) {
|
||
|
|
replacements.push({
|
||
|
|
start,
|
||
|
|
end,
|
||
|
|
content: replacement
|
||
|
|
});
|
||
|
|
searchStart = end;
|
||
|
|
} else searchStart = start + 1;
|
||
|
|
start = exp.content.indexOf(content, searchStart);
|
||
|
|
}
|
||
|
|
return replacements;
|
||
|
|
}
|
||
|
|
function findIdentifierReplacements(exp, name, replacement) {
|
||
|
|
const replacements = [];
|
||
|
|
for (const { start, end } of getIdentifierRanges(exp)) if (exp.content.slice(start, end) === name) replacements.push({
|
||
|
|
start,
|
||
|
|
end,
|
||
|
|
content: replacement
|
||
|
|
});
|
||
|
|
return replacements;
|
||
|
|
}
|
||
|
|
function getNodeRanges(exp) {
|
||
|
|
const ranges = /* @__PURE__ */ new Set();
|
||
|
|
if (!exp.ast || typeof exp.ast !== "object") return ranges;
|
||
|
|
(0, estree_walker.walk)(exp.ast, { enter(node) {
|
||
|
|
if ((0, _vue_compiler_dom.isFunctionType)(node) || node.type === "TemplateElement" || node.type.startsWith("TS") && !_vue_compiler_dom.TS_NODE_TYPES.includes(node.type)) return this.skip();
|
||
|
|
if (node.start != null && node.end != null) ranges.add(`${node.start - 1}:${node.end - 1}`);
|
||
|
|
} });
|
||
|
|
return ranges;
|
||
|
|
}
|
||
|
|
function getIdentifierRanges(exp) {
|
||
|
|
if (!exp.ast || typeof exp.ast !== "object") return [];
|
||
|
|
const identifiers = [];
|
||
|
|
(0, _vue_compiler_dom.walkIdentifiers)(exp.ast, (id) => {
|
||
|
|
identifiers.push({
|
||
|
|
start: id.start - 1,
|
||
|
|
end: id.end - 1
|
||
|
|
});
|
||
|
|
}, false);
|
||
|
|
return identifiers;
|
||
|
|
}
|
||
|
|
function applyContentReplacements(content, replacements) {
|
||
|
|
replacements.sort((a, b) => b.start - a.start).forEach(({ start, end, content: replacement }) => {
|
||
|
|
content = content.slice(0, start) + replacement + content.slice(end);
|
||
|
|
});
|
||
|
|
return content;
|
||
|
|
}
|
||
|
|
function genDeclarations(declarations, context, shouldDeclare) {
|
||
|
|
const [frag, push] = buildCodeFragment();
|
||
|
|
const ids = Object.create(null);
|
||
|
|
const varNames = /* @__PURE__ */ new Set();
|
||
|
|
declarations.forEach(({ name, isIdentifier, value }) => {
|
||
|
|
if (isIdentifier) {
|
||
|
|
const varName = ids[name] = context.getUniqueLocalName(`_${name}`, varNames);
|
||
|
|
if (shouldDeclare) push(`const `);
|
||
|
|
push(`${varName} = `, ...genExpression(value, context), NEWLINE);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
declarations.forEach(({ name, isIdentifier, value }) => {
|
||
|
|
if (!isIdentifier) {
|
||
|
|
const varName = context.getUniqueLocalName(`_${name}`, varNames);
|
||
|
|
if (shouldDeclare) push(`const `);
|
||
|
|
push(`${varName} = `, ...context.withId(() => genExpression(value, context), ids), NEWLINE);
|
||
|
|
ids[name] = varName;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
return {
|
||
|
|
ids,
|
||
|
|
frag,
|
||
|
|
varNames: [...varNames]
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function parseExp(context, content) {
|
||
|
|
return (0, _babel_parser.parseExpression)(`(${content})`, getParserOptions(context.options.expressionPlugins));
|
||
|
|
}
|
||
|
|
function genVarName(exp) {
|
||
|
|
return `${exp.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/_+$/, "")}`;
|
||
|
|
}
|
||
|
|
function getUniqueDeclarationName(baseName, reservedNames) {
|
||
|
|
const normalizedBase = baseName || "exp";
|
||
|
|
let name = normalizedBase;
|
||
|
|
let i = 1;
|
||
|
|
while (reservedNames.has(name)) name = `${normalizedBase}_${i++}`;
|
||
|
|
reservedNames.add(name);
|
||
|
|
return name;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Returns the source of a member expression, or `undefined` if it contains a
|
||
|
|
* node that cannot be extracted, e.g. `foo[bar ? 'a' : 'b']`. Such expressions
|
||
|
|
* must not be cached - the extracted source would be incomplete.
|
||
|
|
*/
|
||
|
|
function extractMemberExpression(exp, onIdentifier) {
|
||
|
|
if (!exp) return;
|
||
|
|
switch (exp.type) {
|
||
|
|
case "Identifier":
|
||
|
|
onIdentifier(exp);
|
||
|
|
return exp.name;
|
||
|
|
case "StringLiteral": return exp.extra ? exp.extra.raw : exp.value;
|
||
|
|
case "NumericLiteral": return exp.value.toString();
|
||
|
|
case "BinaryExpression": {
|
||
|
|
var _exp$extra;
|
||
|
|
const left = extractMemberExpression(exp.left, onIdentifier);
|
||
|
|
const right = extractMemberExpression(exp.right, onIdentifier);
|
||
|
|
if (left === void 0 || right === void 0) return;
|
||
|
|
const expression = `${left} ${exp.operator} ${right}`;
|
||
|
|
return ((_exp$extra = exp.extra) === null || _exp$extra === void 0 ? void 0 : _exp$extra.parenthesized) ? `(${expression})` : expression;
|
||
|
|
}
|
||
|
|
case "CallExpression":
|
||
|
|
case "OptionalCallExpression": {
|
||
|
|
const callee = extractMemberExpression(exp.callee, onIdentifier);
|
||
|
|
const args = exp.arguments.map((arg) => extractMemberExpression(arg, onIdentifier));
|
||
|
|
if (callee === void 0 || args.some((arg) => arg === void 0)) return;
|
||
|
|
return `${callee}${exp.type === "OptionalCallExpression" ? "?." : ""}(${args.join(", ")})`;
|
||
|
|
}
|
||
|
|
case "MemberExpression":
|
||
|
|
case "OptionalMemberExpression": {
|
||
|
|
const object = extractMemberExpression(exp.object, onIdentifier);
|
||
|
|
const property = extractMemberExpression(exp.property, exp.computed ? onIdentifier : _vue_shared.NOOP);
|
||
|
|
if (object === void 0 || property === void 0) return;
|
||
|
|
const optional = exp.type === "OptionalMemberExpression" && exp.optional;
|
||
|
|
return `${object}${exp.computed ? `${optional ? "?." : ""}[${property}]` : `${optional ? "?." : "."}${property}`}`;
|
||
|
|
}
|
||
|
|
case "TSNonNullExpression": return extractMemberExpression(exp.expression, onIdentifier);
|
||
|
|
default: return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
const isCallExpression = (node) => {
|
||
|
|
return node.type === "CallExpression" || node.type === "OptionalCallExpression";
|
||
|
|
};
|
||
|
|
const isMemberExpression$3 = (node) => {
|
||
|
|
return node.type === "MemberExpression" || node.type === "OptionalMemberExpression" || node.type === "TSNonNullExpression";
|
||
|
|
};
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/event.ts
|
||
|
|
function genSetEvent(oper, context) {
|
||
|
|
const { helper } = context;
|
||
|
|
const { element, key, keyOverride, value, modifiers, delegate, effect } = oper;
|
||
|
|
let handler;
|
||
|
|
if (delegate) {
|
||
|
|
context.delegates.add(key.content);
|
||
|
|
if (!context.block.operation.some(isSameDelegateEvent)) return [
|
||
|
|
NEWLINE,
|
||
|
|
`n${element}.$evt${key.content} = `,
|
||
|
|
...genDirectHandler()
|
||
|
|
];
|
||
|
|
}
|
||
|
|
const name = genName();
|
||
|
|
const eventOptions = genEventOptions();
|
||
|
|
return [NEWLINE, ...genCall(helper(effect ? "onBinding" : delegate ? "delegate" : "on"), `n${element}`, name, genHandler(), eventOptions)];
|
||
|
|
function genHandler() {
|
||
|
|
return handler || (handler = genEventHandler(context, [value], modifiers));
|
||
|
|
}
|
||
|
|
function genInvoker() {
|
||
|
|
return [
|
||
|
|
`${helper("createInvoker")}(`,
|
||
|
|
...genHandler(),
|
||
|
|
`)`
|
||
|
|
];
|
||
|
|
}
|
||
|
|
function genDirectHandler() {
|
||
|
|
return modifiers.keys.length || modifiers.nonKeys.length ? genEventHandler(context, [value], modifiers, { modifierHelper: "vapor" }) : genInvoker();
|
||
|
|
}
|
||
|
|
function genName() {
|
||
|
|
const expr = genExpression(key, context);
|
||
|
|
if (keyOverride) {
|
||
|
|
const find = JSON.stringify(keyOverride[0]);
|
||
|
|
const replacement = JSON.stringify(keyOverride[1]);
|
||
|
|
const wrapped = [
|
||
|
|
"(",
|
||
|
|
...expr,
|
||
|
|
")"
|
||
|
|
];
|
||
|
|
return [
|
||
|
|
...wrapped,
|
||
|
|
` === ${find} ? ${replacement} : `,
|
||
|
|
...wrapped
|
||
|
|
];
|
||
|
|
} else return genExpression(key, context);
|
||
|
|
}
|
||
|
|
function genEventOptions() {
|
||
|
|
let { options } = modifiers;
|
||
|
|
if (!options.length) return;
|
||
|
|
return genMulti(DELIMITERS_OBJECT_NEWLINE, ...options.map((option) => [`${option}: true`]));
|
||
|
|
}
|
||
|
|
function isSameDelegateEvent(op) {
|
||
|
|
if (op.type === 6 && op !== oper && op.delegate && op.element === oper.element && op.key.content === key.content) return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function genSetDynamicEvents(oper, context) {
|
||
|
|
const { helper } = context;
|
||
|
|
return [NEWLINE, ...genCall(helper("setDynamicEvents"), `n${oper.element}`, genExpression(oper.event, context))];
|
||
|
|
}
|
||
|
|
function genEventHandler(context, values, modifiers = {
|
||
|
|
nonKeys: [],
|
||
|
|
keys: []
|
||
|
|
}, options = {}) {
|
||
|
|
const { asComponentProp = false, extraWrap = false, modifierHelper = "runtime" } = options;
|
||
|
|
const useVaporModifierHelper = modifierHelper === "vapor";
|
||
|
|
let handlerExp = [];
|
||
|
|
if (values) {
|
||
|
|
values.forEach((value, index) => {
|
||
|
|
let exp = [];
|
||
|
|
if (value && value.content.trim()) {
|
||
|
|
if ((0, _vue_compiler_dom.isMemberExpression)(value, context.options)) {
|
||
|
|
exp = genExpression(value, context);
|
||
|
|
if (!isConstantBinding(value, context) && !asComponentProp) {
|
||
|
|
const isTSNode = value.ast && _vue_compiler_dom.TS_NODE_TYPES.includes(value.ast.type);
|
||
|
|
exp = [
|
||
|
|
`e => `,
|
||
|
|
isTSNode ? "(" : "",
|
||
|
|
...exp,
|
||
|
|
isTSNode ? ")" : "",
|
||
|
|
`(e)`
|
||
|
|
];
|
||
|
|
}
|
||
|
|
} else if ((0, _vue_compiler_dom.isFnExpression)(value, context.options)) exp = genExpression(value, context);
|
||
|
|
else {
|
||
|
|
const referencesEvent = value.content.includes("$event");
|
||
|
|
const hasMultipleStatements = value.content.includes(`;`);
|
||
|
|
const expr = referencesEvent ? context.withId(() => genExpression(value, context), { $event: null }) : genExpression(value, context);
|
||
|
|
exp = [
|
||
|
|
referencesEvent ? "$event => " : "() => ",
|
||
|
|
hasMultipleStatements ? "{" : "(",
|
||
|
|
...expr,
|
||
|
|
hasMultipleStatements ? "}" : ")"
|
||
|
|
];
|
||
|
|
}
|
||
|
|
handlerExp = handlerExp.concat([index !== 0 ? ", " : "", ...exp]);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
if (values.length > 1) handlerExp = [
|
||
|
|
"[",
|
||
|
|
...handlerExp,
|
||
|
|
"]"
|
||
|
|
];
|
||
|
|
}
|
||
|
|
if (handlerExp.length === 0) handlerExp = ["() => {}"];
|
||
|
|
const { keys, nonKeys } = modifiers;
|
||
|
|
if (nonKeys.length) handlerExp = genWithModifiers(context, handlerExp, nonKeys, useVaporModifierHelper && !keys.length);
|
||
|
|
if (keys.length) handlerExp = genWithKeys(context, handlerExp, keys, useVaporModifierHelper);
|
||
|
|
if (extraWrap) handlerExp.unshift(`() => `);
|
||
|
|
return handlerExp;
|
||
|
|
}
|
||
|
|
function genWithModifiers(context, handler, nonKeys, useVaporHelper = false) {
|
||
|
|
return genCall(context.helper(useVaporHelper ? "withVaporModifiers" : "withModifiers"), handler, JSON.stringify(nonKeys));
|
||
|
|
}
|
||
|
|
function genWithKeys(context, handler, keys, useVaporHelper = false) {
|
||
|
|
return genCall(context.helper(useVaporHelper ? "withVaporKeys" : "withKeys"), handler, JSON.stringify(keys));
|
||
|
|
}
|
||
|
|
function isConstantBinding(value, context) {
|
||
|
|
if (value.ast === null) {
|
||
|
|
if (context.options.bindingMetadata[value.content] === "setup-const") return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/for.ts
|
||
|
|
function genFor(oper, context) {
|
||
|
|
const { helper } = context;
|
||
|
|
const { source, value, key, index, render, keyProp, once, id, component, onlyChild, slotRoot, wrappedRows } = oper;
|
||
|
|
const sourceExpr = [
|
||
|
|
"() => (",
|
||
|
|
...genExpression(source, context),
|
||
|
|
")"
|
||
|
|
];
|
||
|
|
const plugins = context.options.expressionPlugins;
|
||
|
|
const idToPathMap = parseValueDestructure(value, context);
|
||
|
|
const keyToPathMap = parseValueDestructure(key, context);
|
||
|
|
const indexToPathMap = parseValueDestructure(index, context);
|
||
|
|
const [depth, exitScope] = context.enterScope();
|
||
|
|
const itemVar = `_for_item${depth}`;
|
||
|
|
const idMap = buildDestructureIdMap(idToPathMap, `${itemVar}.value`, plugins);
|
||
|
|
idMap[itemVar] = null;
|
||
|
|
const args = [itemVar];
|
||
|
|
if (key) {
|
||
|
|
const keyVar = `_for_key${depth}`;
|
||
|
|
args.push(`, ${keyVar}`);
|
||
|
|
Object.assign(idMap, buildDestructureIdMap(keyToPathMap, `${keyVar}.value`, plugins));
|
||
|
|
idMap[keyVar] = null;
|
||
|
|
} else if (index) args.push(", _");
|
||
|
|
if (index) {
|
||
|
|
const indexVar = `_for_index${depth}`;
|
||
|
|
args.push(`, ${indexVar}`);
|
||
|
|
Object.assign(idMap, buildDestructureIdMap(indexToPathMap, `${indexVar}.value`, plugins));
|
||
|
|
idMap[indexVar] = null;
|
||
|
|
}
|
||
|
|
const { selectorPatterns, keyOnlyBindingPatterns, skippedEffectIndexes } = matchPatterns(render, keyProp, idMap, context);
|
||
|
|
const selectorDeclarations = [];
|
||
|
|
const selectorName = (i) => selectorPatterns.length > 1 ? `_selector${id}_${i}` : `_selector${id}`;
|
||
|
|
for (let i = 0; i < selectorPatterns.length; i++) {
|
||
|
|
const { selector } = selectorPatterns[i];
|
||
|
|
selectorDeclarations.push(`const ${selectorName(i)} = `, ...genCall(helper("createSelector"), [`() => `, ...genExpression(selector, context)]), NEWLINE);
|
||
|
|
}
|
||
|
|
const blockFn = context.withId(() => {
|
||
|
|
const frag = [];
|
||
|
|
frag.push("(", ...args, ") => {", INDENT_START);
|
||
|
|
if (selectorPatterns.length || keyOnlyBindingPatterns.length) frag.push(...genBlockContent(render, context, false, () => {
|
||
|
|
const patternFrag = [];
|
||
|
|
for (let i = 0; i < selectorPatterns.length; i++) {
|
||
|
|
const { effect } = selectorPatterns[i];
|
||
|
|
patternFrag.push(NEWLINE, `${selectorName(i)}(`, ...genExpression(keyProp, context), `, () => {`, INDENT_START);
|
||
|
|
for (const oper of effect.operations) patternFrag.push(...genOperation(oper, context));
|
||
|
|
patternFrag.push(INDENT_END, NEWLINE, `})`);
|
||
|
|
}
|
||
|
|
for (const { effect } of keyOnlyBindingPatterns) for (const oper of effect.operations) patternFrag.push(...genOperation(oper, context));
|
||
|
|
return patternFrag;
|
||
|
|
}, skippedEffectIndexes));
|
||
|
|
else frag.push(...genBlockContent(render, context));
|
||
|
|
frag.push(INDENT_END, NEWLINE, "}");
|
||
|
|
return frag;
|
||
|
|
}, idMap);
|
||
|
|
exitScope();
|
||
|
|
const flags = genForFlags(onlyChild, component, isFragmentBlock(render), !component && isSingleNodeBlock(render), once, slotRoot, wrappedRows);
|
||
|
|
const onResetCalls = [];
|
||
|
|
for (let i = 0; i < selectorPatterns.length; i++) onResetCalls.push(NEWLINE, `n${id}.onReset(${selectorName(i)}.reset)`);
|
||
|
|
return [
|
||
|
|
NEWLINE,
|
||
|
|
...selectorDeclarations,
|
||
|
|
`const n${id} = `,
|
||
|
|
...genCall([helper("createFor"), "undefined"], sourceExpr, blockFn, genCallback(keyProp), flags),
|
||
|
|
...onResetCalls
|
||
|
|
];
|
||
|
|
function genCallback(expr) {
|
||
|
|
if (!expr) return false;
|
||
|
|
return context.withId(() => [
|
||
|
|
...genAliasParams(value, key, index, context),
|
||
|
|
" => (",
|
||
|
|
...genExpression(expr, context),
|
||
|
|
")"
|
||
|
|
], genSimpleIdMap());
|
||
|
|
}
|
||
|
|
function genSimpleIdMap() {
|
||
|
|
const idMap = {};
|
||
|
|
const collect = (map) => map.forEach((_, id) => idMap[id] = null);
|
||
|
|
collect(idToPathMap);
|
||
|
|
collect(keyToPathMap);
|
||
|
|
collect(indexToPathMap);
|
||
|
|
return idMap;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function genForFlags(onlyChild, component, isFragment, isSingleNode, once, slotRoot, wrappedRows) {
|
||
|
|
let flags = 0;
|
||
|
|
const names = [];
|
||
|
|
if (onlyChild) {
|
||
|
|
flags |= 1;
|
||
|
|
names.push("FAST_REMOVE");
|
||
|
|
}
|
||
|
|
if (component) {
|
||
|
|
flags |= 2;
|
||
|
|
names.push("IS_COMPONENT");
|
||
|
|
}
|
||
|
|
if (isFragment) {
|
||
|
|
flags |= 16;
|
||
|
|
names.push("IS_FRAGMENT");
|
||
|
|
}
|
||
|
|
if (isSingleNode) {
|
||
|
|
flags |= 8;
|
||
|
|
names.push("IS_SINGLE_NODE");
|
||
|
|
}
|
||
|
|
if (once) {
|
||
|
|
flags |= 4;
|
||
|
|
names.push("ONCE");
|
||
|
|
}
|
||
|
|
if (slotRoot) {
|
||
|
|
flags |= 32;
|
||
|
|
names.push("SLOT_ROOT");
|
||
|
|
}
|
||
|
|
if (wrappedRows) {
|
||
|
|
flags |= 64;
|
||
|
|
names.push("WRAPPED_ROWS");
|
||
|
|
}
|
||
|
|
if (!flags) return;
|
||
|
|
return genFlags(flags, names);
|
||
|
|
}
|
||
|
|
function isSingleNodeBlock(block) {
|
||
|
|
const child = getSingleReturnedChild(block);
|
||
|
|
return !!child && child.template != null;
|
||
|
|
}
|
||
|
|
function isFragmentBlock(block) {
|
||
|
|
const child = getSingleReturnedChild(block);
|
||
|
|
const operation = child && child.operation;
|
||
|
|
if (!operation) return false;
|
||
|
|
return operation.type === 12 || operation.type === 15 || operation.type === 16 || operation.type === 14 && !operation.once || operation.type === 11 && !!operation.dynamic && !operation.dynamic.isStatic;
|
||
|
|
}
|
||
|
|
function getSingleReturnedChild(block) {
|
||
|
|
if (block.returns.length !== 1) return;
|
||
|
|
const id = block.returns[0];
|
||
|
|
for (const child of block.dynamic.children) if (child.id === id) return child;
|
||
|
|
}
|
||
|
|
function genAliasParams(value, key, index, context) {
|
||
|
|
return genMulti([
|
||
|
|
"(",
|
||
|
|
")",
|
||
|
|
", "
|
||
|
|
], value ? genExpression(value, context, void 0, true) : key || index ? "_" : void 0, key ? genExpression(key, context, void 0, true) : index ? "__" : void 0, index && genExpression(index, context, void 0, true));
|
||
|
|
}
|
||
|
|
function parseValueDestructure(value, context) {
|
||
|
|
const map = /* @__PURE__ */ new Map();
|
||
|
|
if (value) {
|
||
|
|
const rawValue = value.content;
|
||
|
|
if (value.ast) (0, _vue_compiler_dom.walkIdentifiers)(value.ast, (id, _, parentStack, ___, isLocal) => {
|
||
|
|
if (isLocal) {
|
||
|
|
let path = "";
|
||
|
|
let isDynamic = false;
|
||
|
|
let helper;
|
||
|
|
let helperArgs;
|
||
|
|
for (let i = 0; i < parentStack.length; i++) {
|
||
|
|
const parent = parentStack[i];
|
||
|
|
const child = parentStack[i + 1] || id;
|
||
|
|
if (parent.type === "ObjectProperty" && parent.value === child) {
|
||
|
|
if (parent.key.type === "StringLiteral") path += `[${JSON.stringify(parent.key.value)}]`;
|
||
|
|
else if (parent.computed) {
|
||
|
|
isDynamic = true;
|
||
|
|
path += `[${rawValue.slice(parent.key.start - 1, parent.key.end - 1)}]`;
|
||
|
|
} else path += `.${parent.key.name}`;
|
||
|
|
} else if (parent.type === "ArrayPattern") {
|
||
|
|
const index = parent.elements.indexOf(child);
|
||
|
|
if (child.type === "RestElement") path += `.slice(${index})`;
|
||
|
|
else path += `[${index}]`;
|
||
|
|
} else if (parent.type === "ObjectPattern" && child.type === "RestElement") {
|
||
|
|
helper = context.helper("getRestElement");
|
||
|
|
helperArgs = "[" + parent.properties.filter((p) => p.type === "ObjectProperty").map((p) => {
|
||
|
|
if (p.key.type === "StringLiteral") return JSON.stringify(p.key.value);
|
||
|
|
else if (p.computed) {
|
||
|
|
isDynamic = true;
|
||
|
|
return rawValue.slice(p.key.start - 1, p.key.end - 1);
|
||
|
|
} else return JSON.stringify(p.key.name);
|
||
|
|
}).join(", ") + "]";
|
||
|
|
}
|
||
|
|
if (child.type === "AssignmentPattern" && (parent.type === "ObjectProperty" || parent.type === "ArrayPattern" || parent.type === "ArrowFunctionExpression" && child.left === id)) {
|
||
|
|
isDynamic = true;
|
||
|
|
helper = context.helper("getDefaultValue");
|
||
|
|
helperArgs = `() => (${rawValue.slice(child.right.start - 1, child.right.end - 1)})`;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
map.set(id.name, {
|
||
|
|
path,
|
||
|
|
dynamic: isDynamic,
|
||
|
|
helper,
|
||
|
|
helperArgs
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}, true);
|
||
|
|
else if (rawValue) map.set(rawValue, null);
|
||
|
|
}
|
||
|
|
return map;
|
||
|
|
}
|
||
|
|
function buildDestructureIdMap(idToPathMap, baseAccessor, plugins) {
|
||
|
|
const idMap = {};
|
||
|
|
idToPathMap.forEach((pathInfo, id) => {
|
||
|
|
let path = baseAccessor;
|
||
|
|
if (pathInfo) {
|
||
|
|
path = `${baseAccessor}${pathInfo.path}`;
|
||
|
|
if (pathInfo.helper) {
|
||
|
|
idMap[pathInfo.helper] = null;
|
||
|
|
path = pathInfo.helperArgs ? `${pathInfo.helper}(${path}, ${pathInfo.helperArgs})` : `${pathInfo.helper}(${path})`;
|
||
|
|
}
|
||
|
|
if (pathInfo.dynamic) {
|
||
|
|
const node = idMap[id] = (0, _vue_compiler_dom.createSimpleExpression)(path);
|
||
|
|
node.ast = (0, _babel_parser.parseExpression)(`(${path})`, getParserOptions(plugins));
|
||
|
|
} else idMap[id] = path;
|
||
|
|
} else idMap[id] = path;
|
||
|
|
});
|
||
|
|
return idMap;
|
||
|
|
}
|
||
|
|
function matchPatterns(render, keyProp, idMap, context) {
|
||
|
|
const selectorPatterns = [];
|
||
|
|
const keyOnlyBindingPatterns = [];
|
||
|
|
let skippedEffectIndexes;
|
||
|
|
if (keyProp === void 0) return {
|
||
|
|
keyOnlyBindingPatterns,
|
||
|
|
selectorPatterns,
|
||
|
|
skippedEffectIndexes
|
||
|
|
};
|
||
|
|
const modelElements = new Set(render.operation.filter(isVModelOperation).map((oper) => oper.element));
|
||
|
|
const lastOrderedProp = /* @__PURE__ */ new Map();
|
||
|
|
for (let i = 0; i < render.effect.length; i++) {
|
||
|
|
const effect = render.effect[i];
|
||
|
|
if (effect.once) {
|
||
|
|
for (const operation of effect.operations) if (operation.type === 3) lastOrderedProp.set(operation.element, i);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for (let index = 0; index < render.effect.length; index++) {
|
||
|
|
const effect = render.effect[index];
|
||
|
|
if (effect.once || effect.operations.some((operation) => {
|
||
|
|
var _lastOrderedProp$get;
|
||
|
|
return isVModelListener(operation, modelElements) || operation.type === 3 && index < ((_lastOrderedProp$get = lastOrderedProp.get(operation.element)) !== null && _lastOrderedProp$get !== void 0 ? _lastOrderedProp$get : -1);
|
||
|
|
})) continue;
|
||
|
|
const selector = matchSelectorPattern(effect, keyProp.content, idMap, context);
|
||
|
|
if (selector) {
|
||
|
|
selectorPatterns.push(selector);
|
||
|
|
skipEffect(index);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const keyOnly = matchKeyOnlyBindingPattern(effect, keyProp.content);
|
||
|
|
if (keyOnly) {
|
||
|
|
keyOnlyBindingPatterns.push(keyOnly);
|
||
|
|
skipEffect(index);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
keyOnlyBindingPatterns,
|
||
|
|
selectorPatterns,
|
||
|
|
skippedEffectIndexes
|
||
|
|
};
|
||
|
|
function skipEffect(index) {
|
||
|
|
if (!skippedEffectIndexes) skippedEffectIndexes = /* @__PURE__ */ new Set();
|
||
|
|
skippedEffectIndexes.add(index);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function matchKeyOnlyBindingPattern(effect, key) {
|
||
|
|
if (effect.expressions.length === 1) {
|
||
|
|
const { ast, content } = effect.expressions[0];
|
||
|
|
if (typeof ast === "object" && ast !== null) {
|
||
|
|
if (isKeyOnlyBinding(ast, key, content)) return { effect };
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function matchSelectorPattern(effect, key, idMap, context) {
|
||
|
|
if (effect.expressions.length === 1) {
|
||
|
|
const { ast, content } = effect.expressions[0];
|
||
|
|
if (typeof ast === "object" && ast) {
|
||
|
|
const matcheds = [];
|
||
|
|
(0, estree_walker.walk)(ast, { enter(node) {
|
||
|
|
if (typeof node === "object" && node && node.type === "BinaryExpression" && node.operator === "===" && node.left.type !== "PrivateName") {
|
||
|
|
const { left, right } = node;
|
||
|
|
for (const [a, b] of [[left, right], [right, left]]) {
|
||
|
|
const aIsKey = content.slice(a.start - 1, a.end - 1) === key;
|
||
|
|
const bIsKey = isKeyOnlyBinding(b, key, content);
|
||
|
|
const bVars = analyzeVariableScopes(b, idMap);
|
||
|
|
if (aIsKey && !bIsKey && !bVars.length) matcheds.push([a, b]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} });
|
||
|
|
if (matcheds.length === 1) {
|
||
|
|
const [key, selector] = matcheds[0];
|
||
|
|
const content = effect.expressions[0].content;
|
||
|
|
let hasExtraId = false;
|
||
|
|
(0, _vue_compiler_dom.walkIdentifiers)(ast, (id) => {
|
||
|
|
if (id.start !== key.start && id.start !== selector.start) hasExtraId = true;
|
||
|
|
}, false);
|
||
|
|
if (!hasExtraId) {
|
||
|
|
const name = content.slice(selector.start - 1, selector.end - 1);
|
||
|
|
const selectorExpression = (0, _vue_compiler_dom.createSimpleExpression)(name, false, selector.loc);
|
||
|
|
selectorExpression.ast = (0, _babel_parser.parseExpression)(`(${name})`, getParserOptions(context.options.expressionPlugins));
|
||
|
|
return {
|
||
|
|
effect,
|
||
|
|
selector: selectorExpression
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function analyzeVariableScopes(ast, idMap) {
|
||
|
|
let locals = [];
|
||
|
|
const ids = [];
|
||
|
|
(0, _vue_compiler_dom.walkIdentifiers)(ast, (id) => {
|
||
|
|
ids.push(id);
|
||
|
|
}, false);
|
||
|
|
for (const id of ids) {
|
||
|
|
if ((0, _vue_shared.isGloballyAllowed)(id.name)) continue;
|
||
|
|
if (idMap[id.name]) locals.push(id.name);
|
||
|
|
}
|
||
|
|
return locals;
|
||
|
|
}
|
||
|
|
function isKeyOnlyBinding(expr, key, source) {
|
||
|
|
let only = true;
|
||
|
|
(0, estree_walker.walk)(expr, { enter(node) {
|
||
|
|
if (source.slice(node.start - 1, node.end - 1) === key) {
|
||
|
|
this.skip();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (node.type === "Identifier") only = false;
|
||
|
|
} });
|
||
|
|
return only;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/html.ts
|
||
|
|
function genSetHtml(oper, context) {
|
||
|
|
const { helper } = context;
|
||
|
|
const { value, element } = oper;
|
||
|
|
return [NEWLINE, ...genCall(helper("setHtml"), `n${element}`, genExpression(value, context))];
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/if.ts
|
||
|
|
function genIf(oper, context, isNested = false) {
|
||
|
|
const { helper } = context;
|
||
|
|
const { condition, positive, negative, once, slotRoot, index, blockShape } = oper;
|
||
|
|
const [frag, push] = buildCodeFragment();
|
||
|
|
const flags = genIfFlags(blockShape, once, slotRoot, negative ? index : void 0);
|
||
|
|
const conditionExpr = [
|
||
|
|
"() => (",
|
||
|
|
...genExpression(condition, context),
|
||
|
|
")"
|
||
|
|
];
|
||
|
|
let positiveArg = genBlock(positive, context);
|
||
|
|
let negativeArg = false;
|
||
|
|
if (negative) {
|
||
|
|
if (negative.type === 1) negativeArg = genBlock(negative, context);
|
||
|
|
else negativeArg = ["() => ", ...genIf(negative, context, true)];
|
||
|
|
}
|
||
|
|
if (!isNested) push(NEWLINE, `const n${oper.id} = `);
|
||
|
|
push(...genCall(helper("createIf"), conditionExpr, positiveArg, negativeArg, flags));
|
||
|
|
return frag;
|
||
|
|
}
|
||
|
|
function genIfFlags(blockShape, once, slotRoot, index) {
|
||
|
|
let flags = blockShape;
|
||
|
|
if (slotRoot) flags |= 128;
|
||
|
|
if (once) flags |= 16;
|
||
|
|
else if (index !== void 0) flags |= index + 1 << 8;
|
||
|
|
if (flags === 1) return false;
|
||
|
|
return genFlags(flags, genIfFlagNames(once, slotRoot, index, blockShape));
|
||
|
|
}
|
||
|
|
function genIfFlagNames(once, slotRoot, index, blockShape) {
|
||
|
|
const names = [`TRUE_${genBlockShapeName(blockShape)}`];
|
||
|
|
const falseShape = blockShape >> 2;
|
||
|
|
const hasFalseBranch = (falseShape & 3) !== 0;
|
||
|
|
if (hasFalseBranch) names.push(`FALSE_${genBlockShapeName(falseShape)}`);
|
||
|
|
if (blockShape & 32) names.push("TRUE_NO_SCOPE");
|
||
|
|
if (hasFalseBranch && blockShape & 64) names.push("FALSE_NO_SCOPE");
|
||
|
|
if (once) names.push("ONCE");
|
||
|
|
if (slotRoot) names.push("SLOT_ROOT");
|
||
|
|
if (!once && index !== void 0) names.push(`KEYED_INDEX_${index}`);
|
||
|
|
return names;
|
||
|
|
}
|
||
|
|
function genBlockShapeName(flags) {
|
||
|
|
switch (flags & 3) {
|
||
|
|
case 0: return "EMPTY";
|
||
|
|
case 1: return "SINGLE_ROOT";
|
||
|
|
case 2: return "MULTI_ROOT";
|
||
|
|
}
|
||
|
|
return "UNKNOWN";
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/prop.ts
|
||
|
|
const helpers = {
|
||
|
|
setElementText: { name: "setElementText" },
|
||
|
|
setHtml: { name: "setHtml" },
|
||
|
|
setClass: { name: "setClass" },
|
||
|
|
setClassName: { name: "setClassName" },
|
||
|
|
setStyle: { name: "setStyle" },
|
||
|
|
setValue: { name: "setValue" },
|
||
|
|
setAttr: {
|
||
|
|
name: "setAttr",
|
||
|
|
needKey: true
|
||
|
|
},
|
||
|
|
setProp: {
|
||
|
|
name: "setProp",
|
||
|
|
needKey: true
|
||
|
|
},
|
||
|
|
setDOMProp: {
|
||
|
|
name: "setDOMProp",
|
||
|
|
needKey: true
|
||
|
|
}
|
||
|
|
};
|
||
|
|
function genSetProp(oper, context) {
|
||
|
|
const { helper } = context;
|
||
|
|
const { prop: { key, values, modifier }, tag, isSVG } = oper;
|
||
|
|
if (!modifier && (0, _vue_shared.isOn)(key.content)) return genSetListener(oper, context);
|
||
|
|
const resolvedHelper = getRuntimeHelper(tag, isSVG, key.content, modifier);
|
||
|
|
if (key.content === "class" && !resolvedHelper.isSVG && resolvedHelper.name === "setClass") {
|
||
|
|
const className = genSetClassName(oper, context);
|
||
|
|
if (className) return className;
|
||
|
|
}
|
||
|
|
const propValue = genPropValue(values, context);
|
||
|
|
return [NEWLINE, ...genCall([helper(resolvedHelper.name), null], `n${oper.element}`, resolvedHelper.needKey ? genExpression(key, context) : false, propValue, resolvedHelper.isSVG && "true")];
|
||
|
|
}
|
||
|
|
const optionsModifierRE = /(Once|Passive|Capture)$/;
|
||
|
|
const optionsModifierEventRE = /^on:?(?:Once|Passive|Capture)$/;
|
||
|
|
function genSetListener(oper, context) {
|
||
|
|
const { helper } = context;
|
||
|
|
const { element, effect, prop } = oper;
|
||
|
|
const value = genPropValue(prop.values, context);
|
||
|
|
if (effect) return [NEWLINE, ...genCall(helper("setListener"), `n${element}`, JSON.stringify(prop.key.content), value)];
|
||
|
|
let name = prop.key.content;
|
||
|
|
const options = [];
|
||
|
|
let m;
|
||
|
|
while ((m = name.match(optionsModifierRE)) && !optionsModifierEventRE.test(name)) {
|
||
|
|
name = name.slice(0, name.length - m[1].length);
|
||
|
|
options.push([`${m[1].toLowerCase()}: true`]);
|
||
|
|
}
|
||
|
|
const event = name[2] === ":" ? name.slice(3) : (0, _vue_shared.hyphenate)(name.slice(2));
|
||
|
|
return [NEWLINE, ...genCall(helper("on"), `n${element}`, JSON.stringify(event), value, options.length ? genMulti(DELIMITERS_OBJECT, ...options) : void 0)];
|
||
|
|
}
|
||
|
|
const MAX_CLASS_NAME_ENTRIES = 31;
|
||
|
|
function genSetClassName(oper, context) {
|
||
|
|
const info = resolveClassName(oper.prop.values, context);
|
||
|
|
if (!info) return;
|
||
|
|
const { helper } = context;
|
||
|
|
const flags = genClassFlags(info.entries, context);
|
||
|
|
const classFragments = info.entries.map((entry) => JSON.stringify(!info.prefix && info.entries.length === 1 ? entry.className : ` ${entry.className}`));
|
||
|
|
const fragments = classFragments.length === 1 ? classFragments[0] : genMulti(DELIMITERS_ARRAY, ...classFragments);
|
||
|
|
return [NEWLINE, ...genCall([helper("setClassName"), "\"\""], `n${oper.element}`, flags, fragments, info.prefix && JSON.stringify(info.prefix), info.suffix && JSON.stringify(info.suffix))];
|
||
|
|
}
|
||
|
|
function resolveClassName(values, context) {
|
||
|
|
let prefix = "";
|
||
|
|
let suffix = "";
|
||
|
|
const entries = [];
|
||
|
|
let sawDynamic = false;
|
||
|
|
let sawSuffix = false;
|
||
|
|
for (const rawValue of values) {
|
||
|
|
const value = context.getExpressionReplacement(rawValue);
|
||
|
|
const staticValue = getLiteralExpressionValue(value, true);
|
||
|
|
if (staticValue != null) {
|
||
|
|
const normalized = (0, _vue_shared.normalizeClass)(staticValue);
|
||
|
|
if (normalized) {
|
||
|
|
if (sawSuffix) suffix = appendClass$1(suffix, normalized);
|
||
|
|
else if (sawDynamic) {
|
||
|
|
sawSuffix = true;
|
||
|
|
suffix = appendClass$1(suffix, normalized);
|
||
|
|
} else prefix = appendClass$1(prefix, normalized);
|
||
|
|
}
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const ast = value.ast;
|
||
|
|
if (!ast || sawSuffix) return;
|
||
|
|
sawDynamic = true;
|
||
|
|
if (ast.type === "ObjectExpression") {
|
||
|
|
if (!resolveObjectClassName(value, ast, entries, context)) return;
|
||
|
|
} else if (ast.type === "ConditionalExpression") {
|
||
|
|
if (!resolveConditionalClassName(value, ast, entries, context)) return;
|
||
|
|
} else return;
|
||
|
|
}
|
||
|
|
return entries.length && entries.length <= MAX_CLASS_NAME_ENTRIES ? {
|
||
|
|
prefix,
|
||
|
|
suffix,
|
||
|
|
entries
|
||
|
|
} : void 0;
|
||
|
|
}
|
||
|
|
function resolveObjectClassName(source, ast, entries, context) {
|
||
|
|
for (const prop of ast.properties) {
|
||
|
|
if (prop.type !== "ObjectProperty" || prop.computed) return false;
|
||
|
|
const rawClassName = getObjectPropertyName$1(prop);
|
||
|
|
if (rawClassName == null) return false;
|
||
|
|
const className = (0, _vue_shared.normalizeClass)(rawClassName);
|
||
|
|
if (!className) continue;
|
||
|
|
const value = getBooleanValue(prop.value);
|
||
|
|
entries.push({
|
||
|
|
className,
|
||
|
|
value,
|
||
|
|
condition: value == null ? createSubExpression(source, prop.value, context) : void 0
|
||
|
|
});
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
function resolveConditionalClassName(source, ast, entries, context) {
|
||
|
|
const consequent = getStringClassValue(ast.consequent);
|
||
|
|
const alternate = getStringClassValue(ast.alternate);
|
||
|
|
if (consequent && alternate === "") {
|
||
|
|
entries.push({
|
||
|
|
className: consequent,
|
||
|
|
condition: createSubExpression(source, ast.test, context)
|
||
|
|
});
|
||
|
|
return true;
|
||
|
|
} else if (alternate && consequent === "") {
|
||
|
|
entries.push({
|
||
|
|
className: alternate,
|
||
|
|
condition: createSubExpression(source, ast.test, context),
|
||
|
|
negate: true
|
||
|
|
});
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
function genClassFlags(entries, context) {
|
||
|
|
const values = [];
|
||
|
|
entries.forEach((entry, index) => {
|
||
|
|
if (index) values.push(" | ");
|
||
|
|
const bit = 1 << index;
|
||
|
|
if (entry.value != null) {
|
||
|
|
values.push(entry.value ? String(bit) : "0");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
values.push("((", ...genExpression(entry.condition, context), ")", entry.negate ? ` ? 0 : ${bit}` : ` ? ${bit} : 0`, ")");
|
||
|
|
});
|
||
|
|
return values;
|
||
|
|
}
|
||
|
|
function appendClass$1(base, value) {
|
||
|
|
return base ? value ? `${base} ${value}` : base : value;
|
||
|
|
}
|
||
|
|
function getObjectPropertyName$1(prop) {
|
||
|
|
const key = prop.key;
|
||
|
|
if (key.type === "Identifier") return key.name;
|
||
|
|
else if (key.type === "StringLiteral") return key.value;
|
||
|
|
else if (key.type === "NumericLiteral") return String(key.value);
|
||
|
|
}
|
||
|
|
function getStringClassValue(node) {
|
||
|
|
if (node.type === "StringLiteral") return (0, _vue_shared.normalizeClass)(node.value);
|
||
|
|
else if (node.type === "TemplateLiteral" && node.expressions.length === 0) return (0, _vue_shared.normalizeClass)(node.quasis[0].value.cooked || "");
|
||
|
|
else if (node.type === "NullLiteral" || node.type === "BooleanLiteral" && !node.value) return "";
|
||
|
|
}
|
||
|
|
function getBooleanValue(node) {
|
||
|
|
if (node.type === "BooleanLiteral") return node.value;
|
||
|
|
}
|
||
|
|
function createSubExpression(source, node, context) {
|
||
|
|
const start = node.start == null ? 0 : node.start - 1;
|
||
|
|
const end = node.end == null ? source.content.length : node.end - 1;
|
||
|
|
const content = source.content.slice(start, end);
|
||
|
|
const expression = (0, _vue_compiler_dom.createSimpleExpression)(content, false, {
|
||
|
|
start: (0, _vue_compiler_dom.advancePositionWithClone)(source.loc.start, source.content, start),
|
||
|
|
end: (0, _vue_compiler_dom.advancePositionWithClone)(source.loc.start, source.content, end),
|
||
|
|
source: content
|
||
|
|
});
|
||
|
|
expression.ast = (0, _vue_compiler_dom.isSimpleIdentifier)(content) ? null : (0, _babel_parser.parseExpression)(`(${content})`, getParserOptions(context.options.expressionPlugins));
|
||
|
|
return expression;
|
||
|
|
}
|
||
|
|
function genDynamicProps$1(oper, context) {
|
||
|
|
const { helper } = context;
|
||
|
|
const values = oper.props.map((props) => {
|
||
|
|
if (Array.isArray(props)) return genLiteralObjectProps(props, context);
|
||
|
|
if (props.kind === 1) return genLiteralObjectProps([props], context);
|
||
|
|
const value = genExpression(props.value, context);
|
||
|
|
return props.handler ? genCall(helper("toHandlers"), value, "true") : value;
|
||
|
|
});
|
||
|
|
return [NEWLINE, ...genCall(helper("setDynamicProps"), `n${oper.element}`, genMulti(DELIMITERS_ARRAY, ...values), genDynamicPropNames$1(oper, context), oper.isSVG && "true")];
|
||
|
|
}
|
||
|
|
function genDynamicPropNames$1(oper, context) {
|
||
|
|
const { bindingMetadata } = context.options;
|
||
|
|
const names = oper.props.flatMap((props) => Array.isArray(props) ? props.filter(({ key, values, modifier, handler }) => key.isStatic && modifier !== "." && !handler && key.content !== "class" && key.content !== "style" && values.some((v) => !v.isStatic && !isConstantBinding$1(v, bindingMetadata))).map((prop) => getStaticPropKeyName(prop)) : []);
|
||
|
|
if (!names.length) return false;
|
||
|
|
const json = JSON.stringify(names);
|
||
|
|
let id = context.dynamicPropNames.get(json);
|
||
|
|
if (!id) context.dynamicPropNames.set(json, id = context.kName(context.dynamicPropNames.size));
|
||
|
|
return id;
|
||
|
|
}
|
||
|
|
function genLiteralObjectProps(props, context) {
|
||
|
|
const entries = [];
|
||
|
|
const listeners = createHandlerGroups(entries);
|
||
|
|
for (const prop of props) if (isListenerProp(prop)) listeners.add(getStaticPropKeyName(prop, true), genPropKey(prop, context, true), prop.handler ? genEventHandler(context, prop.values, prop.handlerModifiers) : genPropValue(prop.values, context));
|
||
|
|
else entries.push([
|
||
|
|
...genPropKey(prop, context),
|
||
|
|
`: `,
|
||
|
|
...genPropValue(prop.values, context)
|
||
|
|
]);
|
||
|
|
listeners.fill();
|
||
|
|
return genMulti(DELIMITERS_OBJECT, ...entries);
|
||
|
|
}
|
||
|
|
function isListenerProp(prop) {
|
||
|
|
return prop.handler || !prop.modifier && !prop.model && prop.key.isStatic && (0, _vue_shared.isOn)(prop.key.content);
|
||
|
|
}
|
||
|
|
function createHandlerGroups(entries, prefix = "", delimiters = DELIMITERS_ARRAY) {
|
||
|
|
const groups = /* @__PURE__ */ new Map();
|
||
|
|
return {
|
||
|
|
add(name, keyFrag, handler) {
|
||
|
|
let group = groups.get(name);
|
||
|
|
if (!group) {
|
||
|
|
groups.set(name, group = {
|
||
|
|
keyFrag,
|
||
|
|
handlers: [],
|
||
|
|
index: entries.length
|
||
|
|
});
|
||
|
|
entries.push([]);
|
||
|
|
}
|
||
|
|
group.handlers.push(handler);
|
||
|
|
},
|
||
|
|
fill() {
|
||
|
|
for (const { keyFrag, handlers, index } of groups.values()) entries[index] = [
|
||
|
|
...keyFrag,
|
||
|
|
": ",
|
||
|
|
prefix,
|
||
|
|
...handlers.length > 1 ? genMulti(delimiters, ...handlers) : handlers[0]
|
||
|
|
];
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function getStaticPropKeyName({ key, modifier, handler, handlerModifiers }, preserveCase = false) {
|
||
|
|
return (handler ? preserveCase && /[A-Z]/.test(key.content) ? `on:${key.content}` : (0, _vue_shared.toHandlerKey)((0, _vue_shared.camelize)(key.content)) : (modifier || "") + key.content) + getHandlerModifierPostfix(handlerModifiers);
|
||
|
|
}
|
||
|
|
function getHandlerModifierPostfix(handlerModifiers) {
|
||
|
|
return handlerModifiers && handlerModifiers.options ? handlerModifiers.options.map(_vue_shared.capitalize).join("") : "";
|
||
|
|
}
|
||
|
|
function genPropKey(prop, context, preserveCase = false) {
|
||
|
|
const { key: node, modifier, runtimeCamelize, handler, handlerModifiers, model } = prop;
|
||
|
|
const { helper } = context;
|
||
|
|
const handlerModifierPostfix = getHandlerModifierPostfix(handlerModifiers);
|
||
|
|
if (node.isStatic) {
|
||
|
|
const keyName = getStaticPropKeyName(prop, preserveCase);
|
||
|
|
return [[
|
||
|
|
(0, _vue_compiler_dom.isSimpleIdentifier)(keyName) ? keyName : JSON.stringify(keyName),
|
||
|
|
-2,
|
||
|
|
node.loc
|
||
|
|
]];
|
||
|
|
}
|
||
|
|
let key = genExpression(node, context);
|
||
|
|
if (runtimeCamelize) {
|
||
|
|
key.push(" || \"\"");
|
||
|
|
key = genCall(helper("camelize"), key);
|
||
|
|
} else if (modifier) key = [
|
||
|
|
"(",
|
||
|
|
...key,
|
||
|
|
" || \"\"",
|
||
|
|
")"
|
||
|
|
];
|
||
|
|
else if (!handler && !model) key = node.ast === null ? [...key, " || \"\""] : [
|
||
|
|
"(",
|
||
|
|
...key,
|
||
|
|
") || \"\""
|
||
|
|
];
|
||
|
|
if (handler) key = genCall(helper("toHandlerKey"), key);
|
||
|
|
return [
|
||
|
|
"[",
|
||
|
|
modifier && `${JSON.stringify(modifier)} + `,
|
||
|
|
...key,
|
||
|
|
handlerModifierPostfix ? ` + ${JSON.stringify(handlerModifierPostfix)}` : void 0,
|
||
|
|
"]"
|
||
|
|
];
|
||
|
|
}
|
||
|
|
function genPropValue(values, context) {
|
||
|
|
if (values.length === 1) return genExpression(values[0], context);
|
||
|
|
return genMulti(DELIMITERS_ARRAY, ...values.map((expr) => genExpression(expr, context)));
|
||
|
|
}
|
||
|
|
function getRuntimeHelper(tag, isSVG, key, modifier) {
|
||
|
|
const tagName = tag.toUpperCase();
|
||
|
|
if (modifier) {
|
||
|
|
if (modifier === ".") return getSpecialHelper(key, tagName, isSVG) || helpers.setDOMProp;
|
||
|
|
else return isSVG ? (0, _vue_shared.extend)({ isSVG: true }, helpers.setAttr) : helpers.setAttr;
|
||
|
|
}
|
||
|
|
const helper = getSpecialHelper(key, tagName, isSVG);
|
||
|
|
if (helper) return helper;
|
||
|
|
if (/aria[A-Z]/.test(key)) return helpers.setDOMProp;
|
||
|
|
if (isSVG) return (0, _vue_shared.extend)({ isSVG: true }, helpers.setAttr);
|
||
|
|
if ((0, _vue_shared.shouldSetAsAttr)(tagName, key) || key.includes("-")) return helpers.setAttr;
|
||
|
|
return helpers.setProp;
|
||
|
|
}
|
||
|
|
function getSpecialHelper(keyName, tagName, isSVG) {
|
||
|
|
if (keyName === "value" && (0, _vue_shared.canSetValueDirectly)(tagName)) return helpers.setValue;
|
||
|
|
else if (keyName === "class") return (0, _vue_shared.extend)({ isSVG }, helpers.setClass);
|
||
|
|
else if (keyName === "style") return helpers.setStyle;
|
||
|
|
else if (keyName === "innerHTML") return helpers.setHtml;
|
||
|
|
else if (keyName === "textContent") return helpers.setElementText;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/templateRef.ts
|
||
|
|
const setTemplateRefIdent = `_setTemplateRef`;
|
||
|
|
function genSetTemplateRef(oper, context) {
|
||
|
|
const [refValue, refKey] = genRefValue(oper.value, context);
|
||
|
|
if (!oper.effect && !oper.refFor && oper.value.isStatic) return genSetStaticTemplateRef(oper, refValue, refKey, context);
|
||
|
|
context.needsTemplateRefSetter = true;
|
||
|
|
return [NEWLINE, ...genCall(setTemplateRefIdent, `n${oper.element}`, refValue, oper.refFor && "true", refKey)];
|
||
|
|
}
|
||
|
|
function genSetStaticTemplateRef(oper, refValue, refKey, context) {
|
||
|
|
return [NEWLINE, ...genCall(context.helper("setStaticTemplateRef"), `n${oper.element}`, refValue, oper.refFor && "true", refKey)];
|
||
|
|
}
|
||
|
|
function genSetTemplateRefBinding(oper, context) {
|
||
|
|
const [refValue, refKey] = genRefValue(oper.value, context);
|
||
|
|
return [NEWLINE, ...genCall([context.helper("setTemplateRefBinding"), "undefined"], `n${oper.element}`, ["() => ", ...refValue], ...oper.refFor || refKey ? [oper.refFor && "true", refKey] : [])];
|
||
|
|
}
|
||
|
|
function genRefValue(value, context) {
|
||
|
|
if (value && context.options.inline) {
|
||
|
|
const binding = context.options.bindingMetadata[value.content];
|
||
|
|
if (binding === "setup-let" || binding === "setup-ref" || binding === "setup-maybe-ref") return [[value.content], JSON.stringify(value.content)];
|
||
|
|
}
|
||
|
|
return [genExpression(value, context)];
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/text.ts
|
||
|
|
function genSetText(oper, context) {
|
||
|
|
const { helper } = context;
|
||
|
|
const { element, values, generated } = oper;
|
||
|
|
const texts = combineValues(values, context);
|
||
|
|
return [NEWLINE, ...genCall(helper("setText"), `${generated ? "x" : "n"}${element}`, texts)];
|
||
|
|
}
|
||
|
|
function combineValues(values, context) {
|
||
|
|
return values.flatMap((value, i) => {
|
||
|
|
let exp = genExpression(value, context);
|
||
|
|
if (getLiteralExpressionValue(value, true) == null) exp = genCall(context.helper("toDisplayString"), exp);
|
||
|
|
if (i > 0) exp.unshift(" + ");
|
||
|
|
return exp;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
function genGetTextChild(oper, context) {
|
||
|
|
return [NEWLINE, `const x${oper.parent} = ${context.helper("txt")}(n${oper.parent})`];
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/modifier.ts
|
||
|
|
function genDirectiveModifiers(modifiers) {
|
||
|
|
return modifiers.map((value) => `${(0, _vue_compiler_dom.isSimpleIdentifier)(value) ? value : JSON.stringify(value)}: true`).join(", ");
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/vModel.ts
|
||
|
|
const helperMap = {
|
||
|
|
text: "applyTextModel",
|
||
|
|
radio: "applyRadioModel",
|
||
|
|
checkbox: "applyCheckboxModel",
|
||
|
|
select: "applySelectModel",
|
||
|
|
dynamic: "applyDynamicModel"
|
||
|
|
};
|
||
|
|
function genVModel(oper, context) {
|
||
|
|
const { modelType, element, dir: { exp, modifiers } } = oper;
|
||
|
|
return genCall(context.helper(helperMap[modelType]), `n${element}`, [
|
||
|
|
`() => (`,
|
||
|
|
...genExpression(exp, context),
|
||
|
|
`)`
|
||
|
|
], genModelHandler(exp, context), modifiers.length ? `{ ${genDirectiveModifiers(modifiers.map((e) => e.content))} }` : void 0);
|
||
|
|
}
|
||
|
|
function genModelHandler(exp, context) {
|
||
|
|
return [
|
||
|
|
`${context.options.isTS ? `(_value: any)` : `_value`} => (`,
|
||
|
|
...genExpression(exp, context, "_value"),
|
||
|
|
")"
|
||
|
|
];
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/component.ts
|
||
|
|
function genStaticModifierPropKey(name) {
|
||
|
|
const key = (0, _vue_shared.getModifierPropName)(name);
|
||
|
|
return [(0, _vue_compiler_dom.isSimpleIdentifier)(key) ? key : JSON.stringify(key)];
|
||
|
|
}
|
||
|
|
function genCreateComponent(operation, context) {
|
||
|
|
const { helper } = context;
|
||
|
|
const singleUseAssetComponentNames = context.singleUseAssetComponentNames;
|
||
|
|
const useAssetComponentHelper = operation.asset && !operation.dynamic && context.block === context.ir.block && !!singleUseAssetComponentNames && singleUseAssetComponentNames.has(operation.tag);
|
||
|
|
const maybeSelfReference = useAssetComponentHelper && operation.tag.endsWith("__self");
|
||
|
|
const tag = genTag();
|
||
|
|
const { root, props, slots, once, slotRoot } = operation;
|
||
|
|
const isRuntimeDynamicComponent = !!(operation.dynamic && !operation.dynamic.isStatic);
|
||
|
|
const dynamicComponentFlags = isRuntimeDynamicComponent ? genDynamicComponentFlags(root, once, slotRoot, operation.ns) : false;
|
||
|
|
const nsArg = !isRuntimeDynamicComponent && (operation.useCreateElement || operation.asset || !!operation.dynamic) && operation.ns ? String(operation.ns) : false;
|
||
|
|
const slotDeclarations = [];
|
||
|
|
const rawSlots = genRawSlots(slots, context, slotDeclarations);
|
||
|
|
const [ids, handlers] = processInlineHandlers(props, context);
|
||
|
|
const rawProps = context.withId(() => genRawProps(props, context, true), ids);
|
||
|
|
const inlineHandlers = handlers.reduce((acc, { name, value }) => {
|
||
|
|
const handler = genEventHandler(context, [value]);
|
||
|
|
return [
|
||
|
|
...acc,
|
||
|
|
`const ${name} = `,
|
||
|
|
...handler,
|
||
|
|
NEWLINE
|
||
|
|
];
|
||
|
|
}, []);
|
||
|
|
return [
|
||
|
|
NEWLINE,
|
||
|
|
...inlineHandlers,
|
||
|
|
...slotDeclarations.length ? genMulti([
|
||
|
|
"let ",
|
||
|
|
NEWLINE,
|
||
|
|
", "
|
||
|
|
], ...slotDeclarations) : [],
|
||
|
|
`const n${operation.id} = `,
|
||
|
|
...genCall(isRuntimeDynamicComponent ? helper("createDynamicComponent") : operation.useCreateElement ? helper("createPlainElement") : useAssetComponentHelper ? helper("createAssetComponent") : operation.asset ? helper("createComponentWithFallback") : helper("createComponent"), tag, rawProps, rawSlots, isRuntimeDynamicComponent ? dynamicComponentFlags : root ? "true" : false, isRuntimeDynamicComponent ? operation.key && [
|
||
|
|
"() => (",
|
||
|
|
...genExpression(operation.key, context),
|
||
|
|
")"
|
||
|
|
] : once && "true", useAssetComponentHelper ? maybeSelfReference && "true" : nsArg, useAssetComponentHelper && nsArg)
|
||
|
|
];
|
||
|
|
function genTag() {
|
||
|
|
if (operation.useCreateElement) return JSON.stringify(operation.tag);
|
||
|
|
else if (operation.dynamic) {
|
||
|
|
if (operation.dynamic.isStatic) return genCall(helper("resolveDynamicComponent"), genExpression(operation.dynamic, context));
|
||
|
|
else return [
|
||
|
|
"() => (",
|
||
|
|
...genExpression(operation.dynamic, context),
|
||
|
|
")"
|
||
|
|
];
|
||
|
|
} else if (useAssetComponentHelper) {
|
||
|
|
const name = maybeSelfReference ? operation.tag.slice(0, -6) : operation.tag;
|
||
|
|
return JSON.stringify(name);
|
||
|
|
} else if (operation.asset) return (0, _vue_compiler_dom.toValidAssetId)(operation.tag, "component");
|
||
|
|
else {
|
||
|
|
const { tag } = operation;
|
||
|
|
const builtInTag = isBuiltInComponent(tag);
|
||
|
|
if (builtInTag) {
|
||
|
|
helper(builtInTag);
|
||
|
|
return `_${builtInTag}`;
|
||
|
|
}
|
||
|
|
return genExpression((0, _vue_shared.extend)((0, _vue_compiler_dom.createSimpleExpression)(tag, false), { ast: null }), context);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function genDynamicComponentFlags(root, once, slotRoot, ns) {
|
||
|
|
let flags = 0;
|
||
|
|
const names = [];
|
||
|
|
if (root) {
|
||
|
|
flags |= 1;
|
||
|
|
names.push("SINGLE_ROOT");
|
||
|
|
}
|
||
|
|
if (once) {
|
||
|
|
flags |= 2;
|
||
|
|
names.push("ONCE");
|
||
|
|
}
|
||
|
|
if (slotRoot) {
|
||
|
|
flags |= 4;
|
||
|
|
names.push("SLOT_ROOT");
|
||
|
|
}
|
||
|
|
if (ns === 1) {
|
||
|
|
flags |= 8;
|
||
|
|
names.push("NS_SVG");
|
||
|
|
} else if (ns === 2) {
|
||
|
|
flags |= 16;
|
||
|
|
names.push("NS_MATHML");
|
||
|
|
}
|
||
|
|
if (!flags) return false;
|
||
|
|
return genFlags(flags, names);
|
||
|
|
}
|
||
|
|
function getUniqueHandlerName(context, name) {
|
||
|
|
const { seenInlineHandlerNames } = context;
|
||
|
|
name = genVarName(name);
|
||
|
|
const count = seenInlineHandlerNames[name] || 0;
|
||
|
|
seenInlineHandlerNames[name] = count + 1;
|
||
|
|
return count === 0 ? name : `${name}${count}`;
|
||
|
|
}
|
||
|
|
function processInlineHandlers(props, context) {
|
||
|
|
const ids = Object.create(null);
|
||
|
|
const handlers = [];
|
||
|
|
const staticProps = props[0];
|
||
|
|
if ((0, _vue_shared.isArray)(staticProps)) for (let i = 0; i < staticProps.length; i++) {
|
||
|
|
const prop = staticProps[i];
|
||
|
|
if (!prop.handler) continue;
|
||
|
|
prop.values.forEach((value, i) => {
|
||
|
|
if (!(0, _vue_compiler_dom.isMemberExpression)(value, context.options)) {
|
||
|
|
const name = getUniqueHandlerName(context, `_on_${prop.key.content.replace(/-/g, "_")}`);
|
||
|
|
handlers.push({
|
||
|
|
name,
|
||
|
|
value
|
||
|
|
});
|
||
|
|
ids[name] = null;
|
||
|
|
prop.values[i] = (0, _vue_shared.extend)({ ast: null }, (0, _vue_compiler_dom.createSimpleExpression)(name));
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
return [ids, handlers];
|
||
|
|
}
|
||
|
|
function genRawProps(props, context, directStaticLiteralProps = false) {
|
||
|
|
const staticProps = props[0];
|
||
|
|
if ((0, _vue_shared.isArray)(staticProps)) {
|
||
|
|
if (!staticProps.length && props.length === 1) return;
|
||
|
|
return genStaticProps(staticProps, context, genDynamicProps(props.slice(1), context, directStaticLiteralProps), directStaticLiteralProps);
|
||
|
|
} else if (props.length) return genStaticProps([], context, genDynamicProps(props, context, directStaticLiteralProps), directStaticLiteralProps);
|
||
|
|
}
|
||
|
|
function genStaticProps(props, context, dynamicProps, directStaticLiteralProps = false) {
|
||
|
|
const args = [];
|
||
|
|
const handlerGroups = createHandlerGroups(args, "() => ", DELIMITERS_ARRAY_NEWLINE);
|
||
|
|
for (const prop of props) {
|
||
|
|
if (isListenerProp(prop)) {
|
||
|
|
if (!prop.key.isStatic) {
|
||
|
|
args.push(genProp(prop, context, true));
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const keyName = getStaticPropKeyName(prop);
|
||
|
|
const keyFrag = genPropKey(prop, context);
|
||
|
|
if (!prop.handler) {
|
||
|
|
handlerGroups.add(keyName, keyFrag, [
|
||
|
|
"(",
|
||
|
|
...genPropValue(prop.values, context),
|
||
|
|
")"
|
||
|
|
]);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (!!prop.handlerModifiers && (prop.handlerModifiers.keys.length > 0 || prop.handlerModifiers.nonKeys.length > 0) || prop.values.length <= 1) {
|
||
|
|
const handlerExp = genEventHandler(context, prop.values, prop.handlerModifiers, { asComponentProp: true });
|
||
|
|
handlerGroups.add(keyName, keyFrag, handlerExp);
|
||
|
|
} else for (const value of prop.values) {
|
||
|
|
const handlerExp = genEventHandler(context, [value], prop.handlerModifiers, { asComponentProp: true });
|
||
|
|
handlerGroups.add(keyName, keyFrag, handlerExp);
|
||
|
|
}
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
args.push(genProp(prop, context, true, true, directStaticLiteralProps && isDirectStaticLiteralProp(prop, context)));
|
||
|
|
if (prop.model) {
|
||
|
|
if (prop.key.isStatic) {
|
||
|
|
const keyName = `onUpdate:${(0, _vue_shared.camelize)(prop.key.content)}`;
|
||
|
|
const keyFrag = [JSON.stringify(keyName)];
|
||
|
|
handlerGroups.add(keyName, keyFrag, genModelHandler(prop.values[0], context));
|
||
|
|
} else {
|
||
|
|
const keyFrag = [
|
||
|
|
"[\"onUpdate:\" + ",
|
||
|
|
...genExpression(prop.key, context),
|
||
|
|
"]"
|
||
|
|
];
|
||
|
|
args.push([
|
||
|
|
...keyFrag,
|
||
|
|
": () => ",
|
||
|
|
...genModelHandler(prop.values[0], context)
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
const { key, modelModifiers } = prop;
|
||
|
|
if (modelModifiers && modelModifiers.length) {
|
||
|
|
const modifiersKey = key.isStatic ? genStaticModifierPropKey(key.content) : [
|
||
|
|
"[",
|
||
|
|
...genExpression(key, context),
|
||
|
|
" + \"Modifiers\"]"
|
||
|
|
];
|
||
|
|
const modifiersVal = genDirectiveModifiers(modelModifiers);
|
||
|
|
args.push([...modifiersKey, directStaticLiteralProps ? `: { ${modifiersVal} }` : `: () => ({ ${modifiersVal} })`]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
handlerGroups.fill();
|
||
|
|
if (dynamicProps) args.push([`$: `, ...dynamicProps]);
|
||
|
|
return genMulti(args.length > 1 ? DELIMITERS_OBJECT_NEWLINE : DELIMITERS_OBJECT, ...args);
|
||
|
|
}
|
||
|
|
function genDynamicProps(props, context, directStaticLiteralProps = false) {
|
||
|
|
const { helper } = context;
|
||
|
|
const frags = [];
|
||
|
|
for (const p of props) {
|
||
|
|
let expr;
|
||
|
|
if ((0, _vue_shared.isArray)(p)) {
|
||
|
|
if (p.length) frags.push(genStaticProps(p, context, void 0, directStaticLiteralProps));
|
||
|
|
continue;
|
||
|
|
} else if (p.kind === 1) {
|
||
|
|
if (p.model) {
|
||
|
|
const entries = [genProp(p, context)];
|
||
|
|
const updateKey = p.key.isStatic ? [JSON.stringify(`onUpdate:${(0, _vue_shared.camelize)(p.key.content)}`)] : [
|
||
|
|
"[\"onUpdate:\" + ",
|
||
|
|
...genExpression(p.key, context),
|
||
|
|
"]"
|
||
|
|
];
|
||
|
|
entries.push([
|
||
|
|
...updateKey,
|
||
|
|
": ",
|
||
|
|
...genModelHandler(p.values[0], context)
|
||
|
|
]);
|
||
|
|
const { modelModifiers } = p;
|
||
|
|
if (modelModifiers && modelModifiers.length) {
|
||
|
|
const modifiersKey = p.key.isStatic ? genStaticModifierPropKey(p.key.content) : [
|
||
|
|
"[",
|
||
|
|
...genExpression(p.key, context),
|
||
|
|
" + \"Modifiers\"]"
|
||
|
|
];
|
||
|
|
const modifiersVal = genDirectiveModifiers(modelModifiers);
|
||
|
|
entries.push([...modifiersKey, `: { ${modifiersVal} }`]);
|
||
|
|
}
|
||
|
|
expr = genMulti(DELIMITERS_OBJECT_NEWLINE, ...entries);
|
||
|
|
} else expr = genMulti(DELIMITERS_OBJECT, genProp(p, context, false, false));
|
||
|
|
} else {
|
||
|
|
expr = genExpression(p.value, context);
|
||
|
|
if (p.handler) expr = genCall(helper("toHandlers"), expr);
|
||
|
|
}
|
||
|
|
frags.push([
|
||
|
|
"() => (",
|
||
|
|
...expr,
|
||
|
|
")"
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
if (frags.length) return genMulti(DELIMITERS_ARRAY_NEWLINE, ...frags);
|
||
|
|
}
|
||
|
|
function genProp(prop, context, isStatic, wrapHandler = true, directStaticLiteral = false) {
|
||
|
|
let values = genPropValue(prop.values, context);
|
||
|
|
if (prop.toDisplayString) values = genCall(context.helper("toDisplayString"), values);
|
||
|
|
return [
|
||
|
|
...genPropKey(prop, context),
|
||
|
|
": ",
|
||
|
|
...prop.handler ? genEventHandler(context, prop.values, prop.handlerModifiers, {
|
||
|
|
asComponentProp: true,
|
||
|
|
extraWrap: wrapHandler
|
||
|
|
}) : isStatic ? directStaticLiteral ? values : [
|
||
|
|
"() => (",
|
||
|
|
...values,
|
||
|
|
")"
|
||
|
|
] : values
|
||
|
|
];
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Static literal values are safe to emit directly because reading them cannot
|
||
|
|
* touch reactive state. Keep handlers, v-model values, and dynamic expressions
|
||
|
|
* as getter sources to preserve lazy access and merge semantics.
|
||
|
|
*/
|
||
|
|
function isDirectStaticLiteralProp(prop, context) {
|
||
|
|
return prop.key.isStatic && prop.values.length === 1 && !prop.handler && !prop.model && isDirectConstantValue(prop.values[0], context);
|
||
|
|
}
|
||
|
|
function isDirectConstantValue(value, context) {
|
||
|
|
value = context.getExpressionReplacement(value);
|
||
|
|
if (value.isStatic) return true;
|
||
|
|
const ast = value.ast;
|
||
|
|
if (ast === null) return value.content === "true" || value.content === "false" || value.content === "null" || value.content === "undefined";
|
||
|
|
if (!ast) return false;
|
||
|
|
return isDirectConstantAst(ast);
|
||
|
|
}
|
||
|
|
function isDirectConstantAst(node) {
|
||
|
|
switch (node.type) {
|
||
|
|
case "StringLiteral":
|
||
|
|
case "NumericLiteral":
|
||
|
|
case "BooleanLiteral":
|
||
|
|
case "NullLiteral":
|
||
|
|
case "BigIntLiteral": return true;
|
||
|
|
case "Identifier": return node.name === "undefined";
|
||
|
|
case "TemplateLiteral": return node.expressions.every((expression) => isDirectTemplateConstantAst(expression));
|
||
|
|
case "ArrayExpression": return node.elements.every((element) => element === null || element.type !== "SpreadElement" && isDirectConstantAst(element));
|
||
|
|
case "ObjectExpression": return node.properties.every((prop) => prop.type === "ObjectProperty" && !prop.computed && isDirectConstantAst(prop.value));
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
function isDirectTemplateConstantAst(node) {
|
||
|
|
switch (node.type) {
|
||
|
|
case "StringLiteral":
|
||
|
|
case "NumericLiteral":
|
||
|
|
case "BooleanLiteral":
|
||
|
|
case "NullLiteral":
|
||
|
|
case "BigIntLiteral": return true;
|
||
|
|
case "Identifier": return node.name === "undefined";
|
||
|
|
case "TemplateLiteral": return node.expressions.every((expression) => isDirectTemplateConstantAst(expression));
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
function genRawSlots(slots, context, slotDeclarations) {
|
||
|
|
if (!slots.length) return;
|
||
|
|
slots = [...slots.filter((slot) => !isConditionalOrLoopSlot(slot)), ...slots.filter(isConditionalOrLoopSlot)];
|
||
|
|
const staticSlots = slots[0];
|
||
|
|
if (staticSlots.slotType === 0) {
|
||
|
|
const defaultSlot = getSingleDefaultSlot(staticSlots);
|
||
|
|
if (defaultSlot && slots.length === 1) return genSlotBlockWithProps(defaultSlot, context);
|
||
|
|
return genStaticSlots(staticSlots, context, slotDeclarations, slots.length > 1 ? slots.slice(1) : void 0);
|
||
|
|
} else return genStaticSlots({
|
||
|
|
slotType: 0,
|
||
|
|
slots: {}
|
||
|
|
}, context, slotDeclarations, slots);
|
||
|
|
}
|
||
|
|
function isConditionalOrLoopSlot(slot) {
|
||
|
|
return slot.slotType === 3 || slot.slotType === 2;
|
||
|
|
}
|
||
|
|
function getSingleDefaultSlot({ slots }) {
|
||
|
|
const names = Object.keys(slots);
|
||
|
|
return names.length === 1 && names[0] === "default" ? slots.default : void 0;
|
||
|
|
}
|
||
|
|
function genStaticSlots({ slots }, context, slotDeclarations, dynamicSlots) {
|
||
|
|
const args = Object.keys(slots).map((name) => [`${JSON.stringify(name)}: `, ...genSlotBlockWithProps(slots[name], context)]);
|
||
|
|
if (dynamicSlots) args.push([`$: `, ...genDynamicSlots(dynamicSlots, context, slotDeclarations)]);
|
||
|
|
return genMulti(DELIMITERS_OBJECT_NEWLINE, ...args);
|
||
|
|
}
|
||
|
|
function genDynamicSlots(slots, context, slotDeclarations) {
|
||
|
|
return genMulti(DELIMITERS_ARRAY_NEWLINE, ...slots.map((slot) => slot.slotType === 0 ? genStaticSlots(slot, context, slotDeclarations) : slot.slotType === 4 ? slot.slots.content : genDynamicSlot(slot, context, slotDeclarations, slot.slotType !== 2)));
|
||
|
|
}
|
||
|
|
function genDynamicSlot(slot, context, slotDeclarations, withFunction = false) {
|
||
|
|
let frag;
|
||
|
|
switch (slot.slotType) {
|
||
|
|
case 1:
|
||
|
|
frag = genBasicDynamicSlot(slot, context, slotDeclarations);
|
||
|
|
break;
|
||
|
|
case 2:
|
||
|
|
frag = genLoopSlot(slot, context);
|
||
|
|
break;
|
||
|
|
case 3: frag = genConditionalSlot(slot, context, slotDeclarations);
|
||
|
|
}
|
||
|
|
if (!withFunction) return frag;
|
||
|
|
return [
|
||
|
|
"() => (",
|
||
|
|
...frag,
|
||
|
|
")"
|
||
|
|
];
|
||
|
|
}
|
||
|
|
function genBasicDynamicSlot(slot, context, slotDeclarations) {
|
||
|
|
const { name, fn } = slot;
|
||
|
|
const slotName = context.getUniqueLocalName("s");
|
||
|
|
slotDeclarations.push(slotName);
|
||
|
|
return genMulti(DELIMITERS_OBJECT_NEWLINE, ["name: ", ...genExpression(name, context)], [
|
||
|
|
`fn: ${slotName} || (${slotName} = `,
|
||
|
|
...genSlotBlockWithProps(fn, context, false),
|
||
|
|
")"
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
function genLoopSlot(slot, context) {
|
||
|
|
const { name, fn, loop, keyProp } = slot;
|
||
|
|
const { value, key, index, source } = loop;
|
||
|
|
const plugins = context.options.expressionPlugins;
|
||
|
|
const idToPathMap = parseValueDestructure(value, context);
|
||
|
|
const keyToPathMap = parseValueDestructure(key, context);
|
||
|
|
const indexToPathMap = parseValueDestructure(index, context);
|
||
|
|
const [depth, exitScope] = context.enterScope();
|
||
|
|
const itemVar = `_for_item${depth}`;
|
||
|
|
const idMap = buildDestructureIdMap(idToPathMap, `${itemVar}.value`, plugins);
|
||
|
|
idMap[itemVar] = null;
|
||
|
|
const args = [itemVar];
|
||
|
|
if (key) {
|
||
|
|
const keyVar = `_for_key${depth}`;
|
||
|
|
args.push(keyVar);
|
||
|
|
Object.assign(idMap, buildDestructureIdMap(keyToPathMap, `${keyVar}.value`, plugins));
|
||
|
|
idMap[keyVar] = null;
|
||
|
|
} else if (index) args.push("_");
|
||
|
|
if (index) {
|
||
|
|
const indexVar = `_for_index${depth}`;
|
||
|
|
args.push(indexVar);
|
||
|
|
Object.assign(idMap, buildDestructureIdMap(indexToPathMap, `${indexVar}.value`, plugins));
|
||
|
|
idMap[indexVar] = null;
|
||
|
|
}
|
||
|
|
const renderSlot = [
|
||
|
|
...genMulti([
|
||
|
|
"(",
|
||
|
|
")",
|
||
|
|
", "
|
||
|
|
], ...args),
|
||
|
|
" => ",
|
||
|
|
...context.withId(() => genSlotBlockWithProps(fn, context, false), idMap)
|
||
|
|
];
|
||
|
|
exitScope();
|
||
|
|
const rawIdMap = {};
|
||
|
|
const collect = (map) => map.forEach((_, id) => rawIdMap[id] = null);
|
||
|
|
collect(idToPathMap);
|
||
|
|
collect(keyToPathMap);
|
||
|
|
collect(indexToPathMap);
|
||
|
|
const rawParams = context.withId(() => genAliasParams(value, key, index, context), rawIdMap);
|
||
|
|
const getName = [
|
||
|
|
...rawParams,
|
||
|
|
" => (",
|
||
|
|
...context.withId(() => genExpression(name, context), rawIdMap),
|
||
|
|
")"
|
||
|
|
];
|
||
|
|
const getKey = keyProp && [
|
||
|
|
...rawParams,
|
||
|
|
" => (",
|
||
|
|
...context.withId(() => genExpression(keyProp, context), rawIdMap),
|
||
|
|
")"
|
||
|
|
];
|
||
|
|
return [...genCall(context.helper("createForSlots"), [
|
||
|
|
"() => (",
|
||
|
|
...genExpression(source, context),
|
||
|
|
")"
|
||
|
|
], renderSlot, getName, getKey)];
|
||
|
|
}
|
||
|
|
function genConditionalSlot(slot, context, slotDeclarations) {
|
||
|
|
const { condition, positive, negative } = slot;
|
||
|
|
return [
|
||
|
|
...genExpression(condition, context),
|
||
|
|
INDENT_START,
|
||
|
|
NEWLINE,
|
||
|
|
"? ",
|
||
|
|
...genDynamicSlot(positive, context, slotDeclarations),
|
||
|
|
NEWLINE,
|
||
|
|
": ",
|
||
|
|
...negative ? genDynamicSlot(negative, context, slotDeclarations) : ["void 0"],
|
||
|
|
INDENT_END
|
||
|
|
];
|
||
|
|
}
|
||
|
|
function genSlotBlockWithProps(oper, context, emitNonStableFlag = true) {
|
||
|
|
let propsName;
|
||
|
|
let exitScope;
|
||
|
|
let depth;
|
||
|
|
const { props } = oper;
|
||
|
|
const idToPathMap = props ? parseValueDestructure(props, context) : /* @__PURE__ */ new Map();
|
||
|
|
if (props) {
|
||
|
|
if (props.ast) {
|
||
|
|
[depth, exitScope] = context.enterScope();
|
||
|
|
propsName = `_slotProps${depth}`;
|
||
|
|
} else propsName = props.content;
|
||
|
|
}
|
||
|
|
const idMap = idToPathMap.size ? buildDestructureIdMap(idToPathMap, propsName || "", context.options.expressionPlugins) : {};
|
||
|
|
if (propsName) idMap[propsName] = null;
|
||
|
|
const exitSlotBlock = context.enterSlotBlock();
|
||
|
|
const hasStableRoot = hasStableSlotRoot(oper, context);
|
||
|
|
if (!hasStableRoot) markSlotRootOperations(oper, context);
|
||
|
|
let blockFn = context.withId(() => genBlock(oper, context, propsName ? [propsName] : []), idMap);
|
||
|
|
if (emitNonStableFlag && !hasStableRoot) blockFn = genCall(context.helper("extend"), blockFn, [`{ _: ${genFlags(1, ["NON_STABLE"])} }`]);
|
||
|
|
exitSlotBlock();
|
||
|
|
exitScope && exitScope();
|
||
|
|
return blockFn;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/slotOutlet.ts
|
||
|
|
function genSlotOutlet(oper, context) {
|
||
|
|
const { helper } = context;
|
||
|
|
const { id, name, fallback, flags } = oper;
|
||
|
|
const [frag, push] = buildCodeFragment();
|
||
|
|
let fallbackArg;
|
||
|
|
if (fallback) {
|
||
|
|
if (context.inSlotBlock) markSlotRootOperations(fallback, context);
|
||
|
|
fallbackArg = genBlock(fallback, context);
|
||
|
|
}
|
||
|
|
const createSlot = helper("createSlot");
|
||
|
|
const rawPropsArg = genRawProps(oper.props, context, true);
|
||
|
|
const nameArg = name.isStatic && name.content === "default" && !rawPropsArg && !fallbackArg && !flags ? void 0 : name.isStatic ? genExpression(name, context) : [
|
||
|
|
"() => (",
|
||
|
|
...genExpression(name, context),
|
||
|
|
")"
|
||
|
|
];
|
||
|
|
push(NEWLINE, `const n${id} = `, ...genCall(createSlot, nameArg, rawPropsArg, fallbackArg, genSlotFlags(flags)));
|
||
|
|
return frag;
|
||
|
|
}
|
||
|
|
function genSlotFlags(flags) {
|
||
|
|
if (!flags) return;
|
||
|
|
const names = [];
|
||
|
|
if (flags & 1) names.push("NO_SLOTTED");
|
||
|
|
if (flags & 2) names.push("ONCE");
|
||
|
|
if (flags & 4) names.push("FORWARDED");
|
||
|
|
if (flags & 8) names.push("SHARED_FALLBACK");
|
||
|
|
return genFlags(flags, names);
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/vShow.ts
|
||
|
|
function genVShow(oper, context) {
|
||
|
|
const { element } = oper;
|
||
|
|
return genCall(context.helper("applyVShow"), `n${element}`, [
|
||
|
|
`() => (`,
|
||
|
|
...genExpression(oper.dir.exp, context),
|
||
|
|
`)`
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/directive.ts
|
||
|
|
function genBuiltinDirective(oper, context) {
|
||
|
|
let call;
|
||
|
|
switch (oper.name) {
|
||
|
|
case "show":
|
||
|
|
call = genVShow(oper, context);
|
||
|
|
break;
|
||
|
|
case "model":
|
||
|
|
call = genVModel(oper, context);
|
||
|
|
break;
|
||
|
|
default: return [];
|
||
|
|
}
|
||
|
|
return [NEWLINE, ...oper.once ? genOnce(call, context) : call];
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* user directives via `withVaporDirectives`, emitted at the end of the block
|
||
|
|
* so the element's props, children and v-model are in place first
|
||
|
|
*/
|
||
|
|
function genCustomDirectives(operations, context) {
|
||
|
|
const byElement = /* @__PURE__ */ new Map();
|
||
|
|
for (const oper of operations) if (oper.type === 13 && !oper.builtin) {
|
||
|
|
const dirs = byElement.get(oper.element);
|
||
|
|
if (dirs) dirs.push(oper);
|
||
|
|
else byElement.set(oper.element, [oper]);
|
||
|
|
}
|
||
|
|
const [frag, push] = buildCodeFragment();
|
||
|
|
for (const dirs of byElement.values()) push(...genElementDirectives(dirs, context));
|
||
|
|
return frag;
|
||
|
|
}
|
||
|
|
function genElementDirectives(opers, context) {
|
||
|
|
const { helper } = context;
|
||
|
|
const element = `n${opers[0].element}`;
|
||
|
|
const directiveItems = opers.map(genDirectiveItem);
|
||
|
|
const directives = genMulti(DELIMITERS_ARRAY, ...directiveItems);
|
||
|
|
const call = genCall(helper("withVaporDirectives"), element, directives);
|
||
|
|
return [NEWLINE, ...opers[0].once ? genOnce(call, context) : call];
|
||
|
|
function genDirectiveItem({ dir, name, asset }) {
|
||
|
|
const directiveVar = asset ? (0, _vue_compiler_dom.toValidAssetId)(name, "directive") : genExpression((0, _vue_shared.extend)((0, _vue_compiler_dom.createSimpleExpression)(name, false), { ast: null }), context);
|
||
|
|
const value = dir.exp && [
|
||
|
|
"() => (",
|
||
|
|
...genExpression(dir.exp, context),
|
||
|
|
")"
|
||
|
|
];
|
||
|
|
const argument = dir.arg && [
|
||
|
|
"() => (",
|
||
|
|
...genExpression(dir.arg, context),
|
||
|
|
")"
|
||
|
|
];
|
||
|
|
const modifiers = !!dir.modifiers.length && [
|
||
|
|
"{ ",
|
||
|
|
genDirectiveModifiers(dir.modifiers.map((m) => m.content)),
|
||
|
|
" }"
|
||
|
|
];
|
||
|
|
return genMulti(DELIMITERS_ARRAY.concat("void 0"), directiveVar, value, argument, modifiers);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/key.ts
|
||
|
|
function genKey(oper, context) {
|
||
|
|
const { id, value, block, slotRoot } = oper;
|
||
|
|
const [frag, push] = buildCodeFragment();
|
||
|
|
const blockFn = genBlock(block, context);
|
||
|
|
push(NEWLINE, `const n${id} = `, ...genCall(context.helper("createKeyedFragment"), [
|
||
|
|
`() => (`,
|
||
|
|
...genExpression(value, context),
|
||
|
|
")"
|
||
|
|
], blockFn, slotRoot ? "true" : false));
|
||
|
|
return frag;
|
||
|
|
}
|
||
|
|
function genSetBlockKey(oper, context) {
|
||
|
|
return [NEWLINE, ...genCall(context.helper("setBlockKey"), `n${oper.element}`, genExpression(oper.value, context))];
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/operation.ts
|
||
|
|
function genOperations(opers, context) {
|
||
|
|
const [frag, push] = buildCodeFragment();
|
||
|
|
for (const operation of opers) push(...genOperationWithInsertionState(operation, context));
|
||
|
|
return frag;
|
||
|
|
}
|
||
|
|
function genOperationWithInsertionState(oper, context) {
|
||
|
|
const [frag, push] = buildCodeFragment();
|
||
|
|
if (isBlockOperation(oper) && oper.parent) push(...genInsertionState(oper, context));
|
||
|
|
push(...genOperation(oper, context));
|
||
|
|
return frag;
|
||
|
|
}
|
||
|
|
function genOperation(oper, context) {
|
||
|
|
switch (oper.type) {
|
||
|
|
case 2: return genSetBlockKey(oper, context);
|
||
|
|
case 3: return genSetProp(oper, context);
|
||
|
|
case 4: return genDynamicProps$1(oper, context);
|
||
|
|
case 5: return genSetText(oper, context);
|
||
|
|
case 6: return genSetEvent(oper, context);
|
||
|
|
case 7: return genSetDynamicEvents(oper, context);
|
||
|
|
case 8: return genSetHtml(oper, context);
|
||
|
|
case 9: return genSetTemplateRef(oper, context);
|
||
|
|
case 10: return genInsertNode(oper, context);
|
||
|
|
case 14: return genIf(oper, context);
|
||
|
|
case 15: return genFor(oper, context);
|
||
|
|
case 16: return genKey(oper, context);
|
||
|
|
case 11: return genCreateComponent(oper, context);
|
||
|
|
case 12: return genSlotOutlet(oper, context);
|
||
|
|
case 13: return genBuiltinDirective(oper, context);
|
||
|
|
case 17: return genGetTextChild(oper, context);
|
||
|
|
default: throw new Error(`Unhandled operation type in genOperation: ${oper}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function genEffects(effects, context, genExtraFrag) {
|
||
|
|
const [frag, push] = buildCodeFragment();
|
||
|
|
let start = 0;
|
||
|
|
for (let i = 0; i < effects.length; i++) {
|
||
|
|
const effect = effects[i];
|
||
|
|
if (effect.once) {
|
||
|
|
push(...genReactiveEffects(effects.slice(start, i), context));
|
||
|
|
push(...genOperations(effect.operations, context));
|
||
|
|
start = i + 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
push(...genReactiveEffects(effects.slice(start), context, genExtraFrag));
|
||
|
|
return frag;
|
||
|
|
}
|
||
|
|
function genReactiveEffects(effects, context, genExtraFrag) {
|
||
|
|
const { helper } = context;
|
||
|
|
const expressions = effects.flatMap((effect) => effect.expressions);
|
||
|
|
const [frag, push, unshift] = buildCodeFragment();
|
||
|
|
const shouldDeclare = genExtraFrag === void 0;
|
||
|
|
let operationsCount = 0;
|
||
|
|
const { ids, frag: declarationFrags, varNames, expressionReplacements } = processExpressions(context, expressions, shouldDeclare);
|
||
|
|
if (shouldDeclare && !declarationFrags.length && !varNames.length) {
|
||
|
|
const effect = effects.length === 1 ? effects[0] : void 0;
|
||
|
|
const operation = effect && effect.operations.length === 1 ? effect.operations[0] : void 0;
|
||
|
|
if (operation && operation.type === 9 && operation.effect && !operation.refFor) return context.withExpressionReplacements(expressionReplacements, () => context.withId(() => genSetTemplateRefBinding(operation, context), ids));
|
||
|
|
}
|
||
|
|
return context.withExpressionReplacements(expressionReplacements, () => {
|
||
|
|
push(...declarationFrags);
|
||
|
|
for (let i = 0; i < effects.length; i++) {
|
||
|
|
const effect = effects[i];
|
||
|
|
operationsCount += effect.operations.length;
|
||
|
|
const frags = context.withId(() => genEffect(effect, context), ids);
|
||
|
|
i > 0 && push(NEWLINE);
|
||
|
|
if (frag[frag.length - 1] === ")" && frags[0] === "(") push(";");
|
||
|
|
push(...frags);
|
||
|
|
}
|
||
|
|
if (frag.filter((frag) => frag === NEWLINE).length > 1 || operationsCount > 1 || declarationFrags.length > 0) {
|
||
|
|
unshift(`{`, INDENT_START, NEWLINE);
|
||
|
|
push(INDENT_END, NEWLINE, "}");
|
||
|
|
if (!effects.length) unshift(NEWLINE);
|
||
|
|
}
|
||
|
|
if (effects.length) {
|
||
|
|
unshift(NEWLINE, `${helper("renderEffect")}(() => `);
|
||
|
|
push(`)`);
|
||
|
|
}
|
||
|
|
if (!shouldDeclare && varNames.length) unshift(NEWLINE, `let `, varNames.join(", "));
|
||
|
|
if (genExtraFrag) push(...context.withId(genExtraFrag, ids));
|
||
|
|
return frag;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
function genEffect({ operations }, context) {
|
||
|
|
const [frag, push] = buildCodeFragment();
|
||
|
|
const operationsExps = genOperations(operations, context);
|
||
|
|
if (operationsExps.filter((frag) => frag === NEWLINE).length > 1) push(...operationsExps);
|
||
|
|
else push(...operationsExps.filter((frag) => frag !== NEWLINE));
|
||
|
|
return frag;
|
||
|
|
}
|
||
|
|
function genInsertionState(operation, context) {
|
||
|
|
const { parent, anchor, appendIndex } = operation;
|
||
|
|
return [NEWLINE, ...genCall(context.helper("setInsertionState"), `n${parent}`, anchor != null ? `n${anchor}` : appendIndex ? String(appendIndex) : void 0)];
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/template.ts
|
||
|
|
function genTemplates(templates, context) {
|
||
|
|
const result = [];
|
||
|
|
templates.forEach(({ content, ns, root, static: isStatic }, i) => {
|
||
|
|
let args = JSON.stringify(content).replace(IMPORT_EXPR_RE, `" + $1 + "`);
|
||
|
|
const flags = (root ? 1 : 0) | (isStatic ? 2 : 0);
|
||
|
|
if (flags || ns) args += `, ${flags}`;
|
||
|
|
if (ns) args += `, ${ns}`;
|
||
|
|
result.push(`const ${context.tName(i)} = ${context.helper("template")}(${args})\n`);
|
||
|
|
});
|
||
|
|
return result.join("");
|
||
|
|
}
|
||
|
|
function genSelf(dynamic, context, flushBeforeDynamic) {
|
||
|
|
const [frag, push] = buildCodeFragment();
|
||
|
|
const { id, template, operation, hasDynamicChild } = dynamic;
|
||
|
|
if (id !== void 0 && template !== void 0) {
|
||
|
|
if (operation && operation.type === 10 && operation.appendIndex !== void 0) push(...genInsertionState(operation, context));
|
||
|
|
push(NEWLINE, `const n${id} = ${context.tName(template)}()`);
|
||
|
|
}
|
||
|
|
if (operation) push(...genOperationWithInsertionState(operation, context));
|
||
|
|
if (hasDynamicChild) push(...genChildren(dynamic, context, push, `n${id}`, flushBeforeDynamic));
|
||
|
|
return frag;
|
||
|
|
}
|
||
|
|
function genChildren(dynamic, context, pushBlock, from = `n${dynamic.id}`, flushBeforeDynamic) {
|
||
|
|
const [frag, push] = buildCodeFragment();
|
||
|
|
const { children } = dynamic;
|
||
|
|
let offset = 0;
|
||
|
|
/**
|
||
|
|
* `reusable` means the previous access target is a p* cursor that can be
|
||
|
|
* reassigned by the next lookup. Referenced n* variables must stay stable.
|
||
|
|
*/
|
||
|
|
let prev;
|
||
|
|
for (const [index, child] of children.entries()) {
|
||
|
|
if (child.flags & 2) offset--;
|
||
|
|
if (child.flags & 4 && child.template != null) {
|
||
|
|
if (child.anchor !== void 0) {
|
||
|
|
const elementIndex = index + offset;
|
||
|
|
const variable = `n${child.anchor}`;
|
||
|
|
pushBlock(NEWLINE, `const ${variable} = `, ...genAccessPath(context, from, elementIndex, prev));
|
||
|
|
prev = [
|
||
|
|
variable,
|
||
|
|
elementIndex,
|
||
|
|
false
|
||
|
|
];
|
||
|
|
}
|
||
|
|
flushBeforeDynamic && flushBeforeDynamic(child, push);
|
||
|
|
push(...genSelf(child, context, flushBeforeDynamic));
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const id = child.flags & 1 ? child.flags & 4 ? child.anchor : child.id : void 0;
|
||
|
|
const ownsSubtree = child.operation !== void 0;
|
||
|
|
if (id === void 0 && (!child.hasDynamicChild || ownsSubtree)) {
|
||
|
|
flushBeforeDynamic && flushBeforeDynamic(child, push);
|
||
|
|
push(...genSelf(child, context, flushBeforeDynamic));
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const elementIndex = index + offset;
|
||
|
|
const inlinePlaceholder = id === void 0 && canInlinePlaceholder(child) && child.template == null && child.operation === void 0 && !(child.flags & 6);
|
||
|
|
const accessPath = genAccessPath(context, from, elementIndex, prev, child.isText);
|
||
|
|
if (inlinePlaceholder) {
|
||
|
|
if (prev && prev[2]) {
|
||
|
|
push(...genChildren(child, context, pushBlock, [
|
||
|
|
"(",
|
||
|
|
prev[0],
|
||
|
|
" = ",
|
||
|
|
...accessPath,
|
||
|
|
")"
|
||
|
|
], flushBeforeDynamic));
|
||
|
|
prev = [
|
||
|
|
prev[0],
|
||
|
|
elementIndex,
|
||
|
|
true
|
||
|
|
];
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (!hasAdjacentFollowingAccessChild(children, index, elementIndex, offset)) {
|
||
|
|
push(...genChildren(child, context, pushBlock, accessPath, flushBeforeDynamic));
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
let variable;
|
||
|
|
if (id === void 0 && prev && prev[2]) {
|
||
|
|
variable = prev[0];
|
||
|
|
pushBlock(NEWLINE, `${variable} = `, ...accessPath);
|
||
|
|
} else {
|
||
|
|
variable = id === void 0 ? context.pName(context.block.tempId++) : `n${id}`;
|
||
|
|
pushBlock(NEWLINE, id === void 0 ? `let ${variable} = ` : `const ${variable} = `, ...accessPath);
|
||
|
|
}
|
||
|
|
if (id === child.anchor && (!child.hasDynamicChild || ownsSubtree)) {
|
||
|
|
flushBeforeDynamic && flushBeforeDynamic(child, push);
|
||
|
|
push(...genSelf(child, context, flushBeforeDynamic));
|
||
|
|
}
|
||
|
|
prev = [
|
||
|
|
variable,
|
||
|
|
elementIndex,
|
||
|
|
id === void 0
|
||
|
|
];
|
||
|
|
if (!ownsSubtree) push(...genChildren(child, context, pushBlock, variable, flushBeforeDynamic));
|
||
|
|
}
|
||
|
|
return frag;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Build one DOM lookup path while preserving the fast sibling walk:
|
||
|
|
* adjacent nodes use _next(prev), otherwise fall back to _nthChild(parent).
|
||
|
|
*/
|
||
|
|
function genAccessPath({ helper }, from, elementIndex, prev, isText) {
|
||
|
|
const textHint = isText ? "true" : void 0;
|
||
|
|
if (prev) return elementIndex - prev[1] === 1 ? genCall(helper("next"), prev[0], textHint) : genCall(helper("nthChild"), from, String(elementIndex), textHint);
|
||
|
|
if (elementIndex === 0) return genCall(helper("child"), from, textHint);
|
||
|
|
if (elementIndex === 1) {
|
||
|
|
const firstChild = genCall(helper("child"), from);
|
||
|
|
return genCall(helper("next"), firstChild, textHint);
|
||
|
|
}
|
||
|
|
return genCall(helper("nthChild"), from, String(elementIndex), textHint);
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Only inline a placeholder when materializing it would not save a parent
|
||
|
|
* lookup. If its child tree needs the parent more than once, keep p* so the
|
||
|
|
* generated code does not duplicate _child/_nthChild work.
|
||
|
|
*/
|
||
|
|
function canInlinePlaceholder(dynamic) {
|
||
|
|
return dynamic.hasDynamicChild === true && countParentAccessUsages(dynamic) === 1;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* A following access can reuse the current placeholder cursor only when it is
|
||
|
|
* the next DOM sibling. Gapped siblings need _nthChild(parent, index) instead.
|
||
|
|
* Kept in lockstep with genChildren's traversal rules.
|
||
|
|
*/
|
||
|
|
function hasAdjacentFollowingAccessChild(children, index, elementIndex, offset) {
|
||
|
|
let futureOffset = offset;
|
||
|
|
for (let i = index + 1; i < children.length; i++) {
|
||
|
|
const child = children[i];
|
||
|
|
if (child.flags & 2) futureOffset--;
|
||
|
|
if (child.flags & 4 && child.anchor === void 0) continue;
|
||
|
|
if (!!(child.flags & 1) || child.hasDynamicChild) return i + futureOffset - elementIndex === 1;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Mirrors genChildren's traversal closely enough to count how many emitted
|
||
|
|
* access paths would start from this placeholder's parent. This is the guard
|
||
|
|
* that keeps inline placeholders from duplicating parent lookups.
|
||
|
|
*/
|
||
|
|
function countParentAccessUsages(dynamic) {
|
||
|
|
let usages = 0;
|
||
|
|
let offset = 0;
|
||
|
|
let prev;
|
||
|
|
for (const [index, child] of dynamic.children.entries()) {
|
||
|
|
if (child.flags & 2) offset--;
|
||
|
|
if (child.flags & 4 && child.template != null && child.anchor === void 0) continue;
|
||
|
|
const id = child.flags & 1 ? child.flags & 4 ? child.anchor : child.id : void 0;
|
||
|
|
if (id === void 0 && !child.hasDynamicChild) continue;
|
||
|
|
const elementIndex = index + offset;
|
||
|
|
const usesParent = !prev || elementIndex - prev[0] !== 1;
|
||
|
|
if (id === void 0 && canInlinePlaceholder(child) && child.template == null && child.operation === void 0 && !(child.flags & 6)) {
|
||
|
|
if (prev && prev[1]) {
|
||
|
|
if (usesParent) usages++;
|
||
|
|
prev = [elementIndex, true];
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
if (!hasAdjacentFollowingAccessChild(dynamic.children, index, elementIndex, offset)) {
|
||
|
|
if (usesParent) usages++;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (usesParent) usages++;
|
||
|
|
prev = [elementIndex, id === void 0];
|
||
|
|
}
|
||
|
|
return usages;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generators/block.ts
|
||
|
|
function genBlock(oper, context, args = [], root) {
|
||
|
|
return [
|
||
|
|
"(",
|
||
|
|
...args,
|
||
|
|
") => {",
|
||
|
|
INDENT_START,
|
||
|
|
...genBlockContent(oper, context, root),
|
||
|
|
INDENT_END,
|
||
|
|
NEWLINE,
|
||
|
|
"}"
|
||
|
|
];
|
||
|
|
}
|
||
|
|
function genBlockContent(block, context, root, genEffectsExtraFrag, skippedEffectIndexes) {
|
||
|
|
const [frag, push] = buildCodeFragment();
|
||
|
|
const { dynamic, effect, operation, returns } = block;
|
||
|
|
const modelOperations = operation.filter(isVModelOperation);
|
||
|
|
const modelElements = new Set(modelOperations.map((oper) => oper.element));
|
||
|
|
const isModelListener = (oper) => isVModelListener(oper, modelElements);
|
||
|
|
const isDeferred = (oper) => isVModelOperation(oper) || isModelListener(oper);
|
||
|
|
const modelListenerEffects = [];
|
||
|
|
if (modelElements.size) {
|
||
|
|
for (let i = 0; i < effect.length; i++) if (!(skippedEffectIndexes && skippedEffectIndexes.has(i)) && effect[i].operations.every(isModelListener)) modelListenerEffects.push(effect[i]);
|
||
|
|
}
|
||
|
|
const resetBlock = context.enterBlock(block);
|
||
|
|
const singleUseAssetComponentNames = root ? collectSingleUseAssetComponents(block) : void 0;
|
||
|
|
const prevSingleUseAssetComponentNames = context.singleUseAssetComponentNames;
|
||
|
|
if (singleUseAssetComponentNames) context.singleUseAssetComponentNames = singleUseAssetComponentNames;
|
||
|
|
if (root) {
|
||
|
|
for (let name of context.ir.component) {
|
||
|
|
if (singleUseAssetComponentNames && singleUseAssetComponentNames.has(name)) continue;
|
||
|
|
const id = (0, _vue_compiler_dom.toValidAssetId)(name, "component");
|
||
|
|
const maybeSelfReference = name.endsWith("__self");
|
||
|
|
if (maybeSelfReference) name = name.slice(0, -6);
|
||
|
|
push(NEWLINE, `const ${id} = `, ...genCall(context.helper("resolveComponent"), JSON.stringify(name), maybeSelfReference ? "true" : void 0));
|
||
|
|
}
|
||
|
|
genResolveAssets("directive", "resolveDirective");
|
||
|
|
}
|
||
|
|
let operationIndex = 0;
|
||
|
|
let effectIndex = 0;
|
||
|
|
const flushPendingOperations = (operationEnd, effectEnd, push) => {
|
||
|
|
while (operationIndex < operationEnd) {
|
||
|
|
const oper = operation[operationIndex];
|
||
|
|
if (!isDeferred(oper)) push(...genOperationWithInsertionState(oper, context));
|
||
|
|
operationIndex++;
|
||
|
|
}
|
||
|
|
if (effectIndex < effectEnd) {
|
||
|
|
push(...genEffectRange(effectIndex, effectEnd));
|
||
|
|
effectIndex = effectEnd;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const flushBeforeDynamic = (dynamic, push) => {
|
||
|
|
const operation = dynamic.operation;
|
||
|
|
if (operation && isBlockOperation(operation) && operation.operationIndex !== void 0 && operation.effectIndex !== void 0) flushPendingOperations(operation.operationIndex, operation.effectIndex, push);
|
||
|
|
};
|
||
|
|
for (const child of dynamic.children) {
|
||
|
|
flushBeforeDynamic(child, push);
|
||
|
|
push(...genSelf(child, context, flushBeforeDynamic));
|
||
|
|
}
|
||
|
|
for (const child of dynamic.children) if (!child.hasDynamicChild) push(...genChildren(child, context, push, `n${child.id}`, flushBeforeDynamic));
|
||
|
|
if (operationIndex < operation.length) push(...genOperations(operation.slice(operationIndex).filter((oper) => !isDeferred(oper)), context));
|
||
|
|
if (effectIndex < effect.length) push(...genEffectRange(effectIndex, effect.length, genEffectsExtraFrag));
|
||
|
|
else if (genEffectsExtraFrag) push(...genEffects([], context, genEffectsExtraFrag));
|
||
|
|
if (modelOperations.length) {
|
||
|
|
push(...genOperations(modelOperations, context));
|
||
|
|
push(...genOperations(operation.filter(isModelListener), context));
|
||
|
|
if (modelListenerEffects.length) push(...genEffects(modelListenerEffects, context));
|
||
|
|
}
|
||
|
|
push(...genCustomDirectives(operation, context));
|
||
|
|
push(NEWLINE, `return `);
|
||
|
|
const returnNodes = returns.map((n) => `n${n}`);
|
||
|
|
push(...returnNodes.length > 1 ? genMulti(DELIMITERS_ARRAY, ...returnNodes) : [returnNodes[0] || "[]"]);
|
||
|
|
resetBlock();
|
||
|
|
context.singleUseAssetComponentNames = prevSingleUseAssetComponentNames;
|
||
|
|
return frag;
|
||
|
|
function genEffectRange(start, end, genExtraFrag) {
|
||
|
|
if (!skippedEffectIndexes && !modelListenerEffects.length) return genEffects(effect.slice(start, end), context, genExtraFrag);
|
||
|
|
const effects = [];
|
||
|
|
for (let i = start; i < end; i++) if (!(skippedEffectIndexes && skippedEffectIndexes.has(i)) && !modelListenerEffects.includes(effect[i])) effects.push(effect[i]);
|
||
|
|
if (effects.length || genExtraFrag) return genEffects(effects, context, genExtraFrag);
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
function genResolveAssets(kind, helper) {
|
||
|
|
for (const name of context.ir[kind]) push(NEWLINE, `const ${(0, _vue_compiler_dom.toValidAssetId)(name, kind)} = `, ...genCall(context.helper(helper), JSON.stringify(name)));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function isVModelOperation(oper) {
|
||
|
|
return oper.type === 13 && oper.builtin === true && oper.name === "model";
|
||
|
|
}
|
||
|
|
function isVModelListener(oper, modelElements) {
|
||
|
|
return (oper.type === 6 || oper.type === 7 || oper.type === 4 && oper.listeners || oper.type === 3 && !oper.prop.modifier && (0, _vue_shared.isOn)(oper.prop.key.content)) && modelElements.has(oper.element);
|
||
|
|
}
|
||
|
|
function markSlotRootOperations(block, context, sharedFallback = false) {
|
||
|
|
if (hasStableSlotRoot(block, context)) return;
|
||
|
|
sharedFallback = sharedFallback || hasMultipleDynamicSlotRoots(block);
|
||
|
|
for (let i = 0; i < block.returns.length; i++) {
|
||
|
|
const child = findReturnedDynamic$1(block, block.returns[i]);
|
||
|
|
const operation = child && child.operation;
|
||
|
|
if (!operation) continue;
|
||
|
|
if (operation.type === 14) markSlotRootIf(operation, context, sharedFallback);
|
||
|
|
else if (operation.type === 15) markSlotRootFor(operation, context);
|
||
|
|
else if (operation.type === 16) {
|
||
|
|
operation.slotRoot = true;
|
||
|
|
markSlotRootOperations(operation.block, context, sharedFallback);
|
||
|
|
} else if (operation.type === 11) markSlotRootComponent(operation);
|
||
|
|
else if (operation.type === 12) {
|
||
|
|
operation.flags |= 4;
|
||
|
|
if (sharedFallback) operation.flags |= 8;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function markSlotRootIf(operation, context, sharedFallback) {
|
||
|
|
if (!operation.once) operation.slotRoot = true;
|
||
|
|
markSlotRootOperations(operation.positive, context, sharedFallback);
|
||
|
|
const negative = operation.negative;
|
||
|
|
if (!negative) return;
|
||
|
|
if (negative.type === 14) markSlotRootIf(negative, context, sharedFallback);
|
||
|
|
else markSlotRootOperations(negative, context, sharedFallback);
|
||
|
|
}
|
||
|
|
function markSlotRootFor(operation, context) {
|
||
|
|
if (!operation.once) operation.slotRoot = true;
|
||
|
|
markSlotRootOperations(operation.render, context, true);
|
||
|
|
}
|
||
|
|
function hasMultipleDynamicSlotRoots(block) {
|
||
|
|
let count = 0;
|
||
|
|
for (let i = 0; i < block.returns.length; i++) {
|
||
|
|
const child = findReturnedDynamic$1(block, block.returns[i]);
|
||
|
|
if (child && child.operation && ++count > 1) return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
function markSlotRootComponent(operation) {
|
||
|
|
if (!operation.once && operation.dynamic && !operation.dynamic.isStatic) operation.slotRoot = true;
|
||
|
|
}
|
||
|
|
function findReturnedDynamic$1(block, id) {
|
||
|
|
for (let i = 0; i < block.dynamic.children.length; i++) {
|
||
|
|
const child = block.dynamic.children[i];
|
||
|
|
if (child.id === id) return child;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
const commentOnlyTemplateRE = /^(?:<!--[\s\S]*?-->)+$/;
|
||
|
|
function hasStableSlotRoot(block, context) {
|
||
|
|
let hasValidRoot = false;
|
||
|
|
for (let i = 0; i < block.returns.length; i++) {
|
||
|
|
const id = block.returns[i];
|
||
|
|
const child = findReturnedDynamic$1(block, id);
|
||
|
|
const operation = child && child.operation;
|
||
|
|
if (!operation) {
|
||
|
|
if (child && isStableTemplateSlotRoot(child, context)) hasValidRoot = true;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
switch (operation.type) {
|
||
|
|
case 11:
|
||
|
|
if (!operation.dynamic || operation.dynamic.isStatic) {
|
||
|
|
hasValidRoot = true;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
continue;
|
||
|
|
case 16:
|
||
|
|
if (hasStableSlotRoot(operation.block, context)) {
|
||
|
|
hasValidRoot = true;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
continue;
|
||
|
|
default: continue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return hasValidRoot;
|
||
|
|
}
|
||
|
|
function isStableTemplateSlotRoot(child, context) {
|
||
|
|
if (child.template == null) return false;
|
||
|
|
const content = context.ir.template.entries[child.template].content;
|
||
|
|
return content !== "" && !commentOnlyTemplateRE.test(content.trim());
|
||
|
|
}
|
||
|
|
function collectSingleUseAssetComponents(block) {
|
||
|
|
const usageMap = /* @__PURE__ */ new Map();
|
||
|
|
const seenOperations = /* @__PURE__ */ new Set();
|
||
|
|
visitBlock(block, true);
|
||
|
|
const names = /* @__PURE__ */ new Set();
|
||
|
|
for (const [name, usage] of usageMap) if (usage.count === 1 && usage.root) names.add(name);
|
||
|
|
return names;
|
||
|
|
function visitBlock(block, rootCandidate) {
|
||
|
|
visitDynamic(block.dynamic, rootCandidate);
|
||
|
|
for (const operation of block.operation) visitOperation(operation, rootCandidate);
|
||
|
|
for (const effect of block.effect) for (const operation of effect.operations) visitOperation(operation, false);
|
||
|
|
}
|
||
|
|
function visitDynamic(dynamic, rootCandidate) {
|
||
|
|
if (dynamic.operation) visitOperation(dynamic.operation, rootCandidate);
|
||
|
|
for (const child of dynamic.children) visitDynamic(child, rootCandidate);
|
||
|
|
}
|
||
|
|
function visitOperation(operation, rootCandidate) {
|
||
|
|
if (seenOperations.has(operation)) return;
|
||
|
|
seenOperations.add(operation);
|
||
|
|
if (operation.type === 11) {
|
||
|
|
if (operation.asset) {
|
||
|
|
const usage = usageMap.get(operation.tag) || {
|
||
|
|
count: 0,
|
||
|
|
root: false
|
||
|
|
};
|
||
|
|
usage.count++;
|
||
|
|
if (rootCandidate) usage.root = true;
|
||
|
|
usageMap.set(operation.tag, usage);
|
||
|
|
}
|
||
|
|
visitSlots(operation.slots);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
switch (operation.type) {
|
||
|
|
case 14:
|
||
|
|
visitBlock(operation.positive, false);
|
||
|
|
if (operation.negative) {
|
||
|
|
if (operation.negative.type === 14) visitOperation(operation.negative, false);
|
||
|
|
else visitBlock(operation.negative, false);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case 15:
|
||
|
|
visitBlock(operation.render, false);
|
||
|
|
break;
|
||
|
|
case 16:
|
||
|
|
visitBlock(operation.block, false);
|
||
|
|
break;
|
||
|
|
case 12: if (operation.fallback) visitBlock(operation.fallback, false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function visitSlots(slots) {
|
||
|
|
for (const slot of slots) switch (slot.slotType) {
|
||
|
|
case 0:
|
||
|
|
for (const name in slot.slots) visitBlock(slot.slots[name], false);
|
||
|
|
break;
|
||
|
|
case 1:
|
||
|
|
case 2:
|
||
|
|
visitBlock(slot.fn, false);
|
||
|
|
break;
|
||
|
|
case 3:
|
||
|
|
visitSlots([slot.positive]);
|
||
|
|
if (slot.negative) visitSlots([slot.negative]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/generate.ts
|
||
|
|
const idWithTrailingDigitsRE = /^([A-Za-z_$][\w$]*)(\d+)$/;
|
||
|
|
const helperNameAliases = {
|
||
|
|
withVaporKeys: "withKeys",
|
||
|
|
withVaporModifiers: "withModifiers"
|
||
|
|
};
|
||
|
|
var CodegenContext = class {
|
||
|
|
withExpressionReplacements(map, fn) {
|
||
|
|
if (map.size === 0) return fn();
|
||
|
|
this.expressionReplacements.unshift(map);
|
||
|
|
try {
|
||
|
|
return fn();
|
||
|
|
} finally {
|
||
|
|
(0, _vue_shared.remove)(this.expressionReplacements, map);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
getExpressionReplacement(node) {
|
||
|
|
for (const map of this.expressionReplacements) {
|
||
|
|
const replacement = map.get(node);
|
||
|
|
if (replacement) return replacement;
|
||
|
|
}
|
||
|
|
return node;
|
||
|
|
}
|
||
|
|
withId(fn, map) {
|
||
|
|
const { identifiers } = this;
|
||
|
|
const ids = Object.keys(map);
|
||
|
|
for (const id of ids) {
|
||
|
|
identifiers[id] || (identifiers[id] = []);
|
||
|
|
identifiers[id].unshift(map[id] || id);
|
||
|
|
}
|
||
|
|
const ret = fn();
|
||
|
|
ids.forEach((id) => (0, _vue_shared.remove)(identifiers[id], map[id] || id));
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
enterBlock(block) {
|
||
|
|
const parent = this.block;
|
||
|
|
this.block = block;
|
||
|
|
return () => this.block = parent;
|
||
|
|
}
|
||
|
|
enterSlotBlock() {
|
||
|
|
const parent = this.inSlotBlock;
|
||
|
|
this.inSlotBlock = true;
|
||
|
|
return () => this.inSlotBlock = parent;
|
||
|
|
}
|
||
|
|
enterScope() {
|
||
|
|
return [this.scopeLevel++, () => this.scopeLevel--];
|
||
|
|
}
|
||
|
|
getUniqueLocalName(base, scopeNames = this.generatedLocalNames) {
|
||
|
|
const name = this.findAvailableName(base, scopeNames);
|
||
|
|
scopeNames.add(name);
|
||
|
|
this.generatedLocalNames.add(name);
|
||
|
|
return name;
|
||
|
|
}
|
||
|
|
isNameAvailable(name, reservedNames) {
|
||
|
|
var _this$identifiers$nam;
|
||
|
|
if (this.bindingNames.has(name) || reservedNames.has(name)) return false;
|
||
|
|
if ((_this$identifiers$nam = this.identifiers[name]) === null || _this$identifiers$nam === void 0 ? void 0 : _this$identifiers$nam.length) return false;
|
||
|
|
for (const alias of this.helpers.values()) if (alias === name) return false;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
findAvailableName(base, reservedNames) {
|
||
|
|
if (this.isNameAvailable(base, reservedNames)) return base;
|
||
|
|
const map = this.nextIdMap.get(base);
|
||
|
|
let next = 1;
|
||
|
|
while (true) {
|
||
|
|
const id = getNextId(map, next);
|
||
|
|
const name = `${base}${id}`;
|
||
|
|
if (this.isNameAvailable(name, reservedNames)) return name;
|
||
|
|
next = id + 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
initNextIdMap() {
|
||
|
|
if (this.bindingNames.size === 0) return;
|
||
|
|
const map = /* @__PURE__ */ new Map();
|
||
|
|
for (const name of this.bindingNames) {
|
||
|
|
const m = idWithTrailingDigitsRE.exec(name);
|
||
|
|
if (!m) continue;
|
||
|
|
const prefix = m[1];
|
||
|
|
const num = Number(m[2]);
|
||
|
|
let set = map.get(prefix);
|
||
|
|
if (!set) map.set(prefix, set = /* @__PURE__ */ new Set());
|
||
|
|
set.add(num);
|
||
|
|
}
|
||
|
|
for (const [prefix, nums] of map) this.nextIdMap.set(prefix, buildNextIdMap(nums));
|
||
|
|
}
|
||
|
|
tName(i) {
|
||
|
|
let name = this.templateVars.get(i);
|
||
|
|
if (name) return name;
|
||
|
|
const map = this.nextIdMap.get("t");
|
||
|
|
let lastId = this.lastIdMap.get("t") || -1;
|
||
|
|
for (let j = this.lastTIndex + 1; j <= i; j++) this.templateVars.set(j, name = `t${lastId = getNextId(map, Math.max(j, lastId + 1))}`);
|
||
|
|
this.lastIdMap.set("t", lastId);
|
||
|
|
this.lastTIndex = i;
|
||
|
|
return name;
|
||
|
|
}
|
||
|
|
pName(i) {
|
||
|
|
return this.idName("p", i);
|
||
|
|
}
|
||
|
|
kName(i) {
|
||
|
|
return this.idName("k", i);
|
||
|
|
}
|
||
|
|
idName(prefix, i) {
|
||
|
|
const map = this.nextIdMap.get(prefix);
|
||
|
|
let lastId = this.lastIdMap.get(prefix) || -1;
|
||
|
|
this.lastIdMap.set(prefix, lastId = getNextId(map, Math.max(i, lastId + 1)));
|
||
|
|
return `${prefix}${lastId}`;
|
||
|
|
}
|
||
|
|
constructor(ir, options) {
|
||
|
|
this.ir = ir;
|
||
|
|
this.bindingNames = /* @__PURE__ */ new Set();
|
||
|
|
this.helpers = /* @__PURE__ */ new Map();
|
||
|
|
this.needsTemplateRefSetter = false;
|
||
|
|
this.inSlotBlock = false;
|
||
|
|
this.helper = (name) => {
|
||
|
|
if (this.helpers.has(name)) return this.helpers.get(name);
|
||
|
|
const base = `_${helperNameAliases[name] || name}`;
|
||
|
|
const alias = this.findAvailableName(base, this.generatedLocalNames);
|
||
|
|
this.helpers.set(name, alias);
|
||
|
|
return alias;
|
||
|
|
};
|
||
|
|
this.delegates = /* @__PURE__ */ new Set();
|
||
|
|
this.dynamicPropNames = /* @__PURE__ */ new Map();
|
||
|
|
this.identifiers = Object.create(null);
|
||
|
|
this.expressionReplacements = [];
|
||
|
|
this.seenInlineHandlerNames = Object.create(null);
|
||
|
|
this.scopeLevel = 0;
|
||
|
|
this.templateVars = /* @__PURE__ */ new Map();
|
||
|
|
this.nextIdMap = /* @__PURE__ */ new Map();
|
||
|
|
this.lastIdMap = /* @__PURE__ */ new Map();
|
||
|
|
this.generatedLocalNames = /* @__PURE__ */ new Set();
|
||
|
|
this.lastTIndex = -1;
|
||
|
|
const defaultOptions = {
|
||
|
|
mode: "module",
|
||
|
|
prefixIdentifiers: true,
|
||
|
|
sourceMap: false,
|
||
|
|
filename: `template.vue.html`,
|
||
|
|
scopeId: null,
|
||
|
|
runtimeGlobalName: `Vue`,
|
||
|
|
runtimeModuleName: `vue`,
|
||
|
|
ssrRuntimeModuleName: "vue/server-renderer",
|
||
|
|
ssr: false,
|
||
|
|
isTS: false,
|
||
|
|
inSSR: false,
|
||
|
|
inline: false,
|
||
|
|
bindingMetadata: {},
|
||
|
|
expressionPlugins: []
|
||
|
|
};
|
||
|
|
this.options = (0, _vue_shared.extend)(defaultOptions, options);
|
||
|
|
this.block = ir.block;
|
||
|
|
this.bindingNames = new Set(this.options.bindingMetadata ? Object.keys(this.options.bindingMetadata) : []);
|
||
|
|
this.initNextIdMap();
|
||
|
|
}
|
||
|
|
};
|
||
|
|
function generate(ir, options = {}) {
|
||
|
|
const [frag, push] = buildCodeFragment();
|
||
|
|
const context = new CodegenContext(ir, options);
|
||
|
|
const { inline, bindingMetadata } = options;
|
||
|
|
const functionName = "render";
|
||
|
|
const args = ["_ctx"];
|
||
|
|
if (bindingMetadata && !inline) args.push("$props", "$emit", "$attrs", "$slots");
|
||
|
|
const signature = (options.isTS ? args.map((arg) => `${arg}: any`) : args).join(", ");
|
||
|
|
if (!inline) push(NEWLINE, `export function ${functionName}(${signature}) {`);
|
||
|
|
push(INDENT_START);
|
||
|
|
const templateRefSetterHelper = ir.hasTemplateRef ? context.helper("createTemplateRefSetter") : void 0;
|
||
|
|
const body = genBlockContent(ir.block, context, true);
|
||
|
|
if (context.needsTemplateRefSetter) push(NEWLINE, `const ${setTemplateRefIdent} = ${templateRefSetterHelper}()`);
|
||
|
|
else if (templateRefSetterHelper) context.helpers.delete("createTemplateRefSetter");
|
||
|
|
push(...body);
|
||
|
|
push(INDENT_END, NEWLINE);
|
||
|
|
if (!inline) push("}");
|
||
|
|
const delegates = genDelegates(context);
|
||
|
|
const templates = genTemplates(ir.template.entries, context);
|
||
|
|
const preamble = genHelperImports(context) + genAssetImports(context) + templates + genDynamicPropNames(context) + delegates;
|
||
|
|
const newlineCount = [...preamble].filter((c) => c === "\n").length;
|
||
|
|
if (newlineCount && !inline) frag.unshift(...new Array(newlineCount).fill(LF));
|
||
|
|
let [code, map] = codeFragmentToString(frag, context);
|
||
|
|
if (!inline) code = preamble + code;
|
||
|
|
return {
|
||
|
|
code,
|
||
|
|
ast: ir,
|
||
|
|
preamble,
|
||
|
|
map: map && map.toJSON(),
|
||
|
|
helpers: new Set(Array.from(context.helpers.keys()))
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function genDynamicPropNames({ dynamicPropNames }) {
|
||
|
|
let code = "";
|
||
|
|
for (const [json, id] of dynamicPropNames) code += `const ${id} = ${json}\n`;
|
||
|
|
return code;
|
||
|
|
}
|
||
|
|
function genDelegates({ delegates, helper }) {
|
||
|
|
return delegates.size ? genCall(helper("delegateEvents"), ...Array.from(delegates).map((v) => `"${v}"`)).join("") + "\n" : "";
|
||
|
|
}
|
||
|
|
function genHelperImports({ helpers, options }) {
|
||
|
|
let imports = "";
|
||
|
|
if (helpers.size) imports += `import { ${Array.from(helpers).map(([h, alias]) => `${h} as ${alias}`).join(", ")} } from '${options.runtimeModuleName}';\n`;
|
||
|
|
return imports;
|
||
|
|
}
|
||
|
|
function genAssetImports({ ir }) {
|
||
|
|
const assetImports = ir.node.imports;
|
||
|
|
let imports = "";
|
||
|
|
for (const assetImport of assetImports) {
|
||
|
|
const name = assetImport.exp.content;
|
||
|
|
imports += `import ${name} from '${assetImport.path}';\n`;
|
||
|
|
}
|
||
|
|
return imports;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/vBind.ts
|
||
|
|
function normalizeBindShorthand(arg, context) {
|
||
|
|
if (arg.type !== 4 || !arg.isStatic) {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createCompilerError)(53, arg.loc));
|
||
|
|
return (0, _vue_compiler_dom.createSimpleExpression)("", true, arg.loc);
|
||
|
|
}
|
||
|
|
const propName = (0, _vue_shared.camelize)(arg.content);
|
||
|
|
const exp = (0, _vue_compiler_dom.createSimpleExpression)(propName, false, arg.loc);
|
||
|
|
exp.ast = null;
|
||
|
|
return exp;
|
||
|
|
}
|
||
|
|
const transformVBind = (dir, node, context) => {
|
||
|
|
const { loc, modifiers } = dir;
|
||
|
|
let { exp } = dir;
|
||
|
|
let arg = dir.arg;
|
||
|
|
const modifiersString = modifiers.map((s) => s.content);
|
||
|
|
if (!exp) exp = normalizeBindShorthand(arg, context);
|
||
|
|
if (!exp.content.trim()) {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createCompilerError)(34, loc));
|
||
|
|
exp = (0, _vue_compiler_dom.createSimpleExpression)("", true, loc);
|
||
|
|
}
|
||
|
|
arg = resolveExpression(arg);
|
||
|
|
const excludeNumber = node.tagType === 1 || node.tagType === 2 || !!context.options.isCustomElement(node.tag) || modifiersString.includes("prop") || !arg.isStatic || (0, _vue_shared.isSpecialBooleanAttr)(arg.content) || isCheckboxValueProp(node, arg.content) || !modifiersString.includes("attr") && (isFoldableBooleanAttr(arg.content) || isModelValueProp(node, arg.content));
|
||
|
|
exp = resolveExpression(exp, excludeNumber);
|
||
|
|
if (arg.isStatic && isReservedProp(arg.content)) return;
|
||
|
|
let camel = false;
|
||
|
|
if (modifiersString.includes("camel")) {
|
||
|
|
if (arg.isStatic) arg = (0, _vue_shared.extend)({}, arg, { content: (0, _vue_shared.camelize)(arg.content) });
|
||
|
|
else camel = true;
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
key: arg,
|
||
|
|
value: exp,
|
||
|
|
loc,
|
||
|
|
runtimeCamelize: camel,
|
||
|
|
modifier: modifiersString.includes("prop") ? "." : modifiersString.includes("attr") ? "^" : void 0
|
||
|
|
};
|
||
|
|
};
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/transformKey.ts
|
||
|
|
const dynamicComponentKeys = /* @__PURE__ */ new WeakMap();
|
||
|
|
const transformKey = (node, context) => {
|
||
|
|
if (node.type !== 1 || context.inVOnce || findDir$5(node, "for") || node.tagType === 3 && findDir$5(node, /^(if|else-if|else|slot)$/, true)) return;
|
||
|
|
if (isComponentTag(node.tag) && findProp$1(node, "is", true, true)) {
|
||
|
|
const prop = findProp$1(node, "key", false, true);
|
||
|
|
if (prop) dynamicComponentKeys.set(node, prop.type === 6 ? (0, _vue_compiler_dom.createSimpleExpression)(prop.value ? prop.value.content : "", true) : prop.exp || normalizeBindShorthand(prop.arg, context));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const dir = findProp$1(node, "key", true, true);
|
||
|
|
if (!dir || dir.type === 6) return;
|
||
|
|
let value;
|
||
|
|
value = dir.exp || normalizeBindShorthand(dir.arg, context);
|
||
|
|
if (isStaticExpression(value, context.options.bindingMetadata)) return;
|
||
|
|
let id = context.reference();
|
||
|
|
context.dynamic.flags |= 6;
|
||
|
|
context.node = node = wrapTemplate(node, ["key"]);
|
||
|
|
const block = newBlock(node);
|
||
|
|
const exitBlock = context.enterBlock(block);
|
||
|
|
return () => {
|
||
|
|
exitBlock();
|
||
|
|
context.dynamic.operation = {
|
||
|
|
type: 16,
|
||
|
|
id,
|
||
|
|
...context.effectBoundary(),
|
||
|
|
value,
|
||
|
|
block
|
||
|
|
};
|
||
|
|
};
|
||
|
|
};
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/vHtml.ts
|
||
|
|
function ignoreVHtmlChildren(node, context, clear) {
|
||
|
|
if (!node.children.length) return;
|
||
|
|
const dir = (0, _vue_compiler_dom.findDir)(node, "html");
|
||
|
|
if (!dir) return;
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createDOMCompilerError)(55, dir.loc));
|
||
|
|
if (clear === "node") node.children.length = 0;
|
||
|
|
else context.childrenTemplate.length = 0;
|
||
|
|
}
|
||
|
|
const transformVHtml = (dir, node, context) => {
|
||
|
|
let { exp, loc } = dir;
|
||
|
|
if (!exp) {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createDOMCompilerError)(54, loc));
|
||
|
|
exp = EMPTY_EXPRESSION;
|
||
|
|
}
|
||
|
|
ignoreVHtmlChildren(node, context, "template");
|
||
|
|
if (node.tagType === 1) return {
|
||
|
|
key: (0, _vue_compiler_dom.createSimpleExpression)("innerHTML", true, loc),
|
||
|
|
value: exp
|
||
|
|
};
|
||
|
|
context.registerEffect([exp], {
|
||
|
|
type: 8,
|
||
|
|
element: context.reference(),
|
||
|
|
value: exp
|
||
|
|
});
|
||
|
|
};
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/transformElement.ts
|
||
|
|
const isReservedProp = /*#__PURE__*/ (0, _vue_shared.makeMap)(",key,ref,ref_for,ref_key,");
|
||
|
|
/**
|
||
|
|
* `true-value` / `false-value` are only read back by `v-model` on a checkbox,
|
||
|
|
* and they are dropped from the ssr output, so a checkbox that only carries
|
||
|
|
* them in the template has nothing left to read from after hydration. A
|
||
|
|
* dynamic `type` can still make the element a checkbox at runtime.
|
||
|
|
*/
|
||
|
|
function isCheckboxValueProp(node, key) {
|
||
|
|
if (node.tag !== "input" || key !== "true-value" && key !== "false-value") return false;
|
||
|
|
const type = findProp$1(node, "type");
|
||
|
|
return type ? type.type === 7 || type.value.content === "checkbox" : (0, _vue_compiler_dom.hasDynamicKeyVBind)(node);
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Props the template string cannot carry, so they have to be applied by a
|
||
|
|
* runtime prop setter instead:
|
||
|
|
* - `innerHTML` / `textContent` are dom properties that set the element's
|
||
|
|
* content; as a content attribute they would only sit on the element and
|
||
|
|
* the content would never be written, so vdom always sets them as a dom
|
||
|
|
* property too, see `shouldSetAsProp`
|
||
|
|
* - `<textarea>` / `<select>` ignore a `value` content attribute, the value
|
||
|
|
* only takes effect as a dom property - which is where vdom sends it too,
|
||
|
|
* see `shouldSetAsProp`
|
||
|
|
* - `true-value` / `false-value`, see `isCheckboxValueProp`
|
||
|
|
*/
|
||
|
|
function isRuntimeOnlyProp(node, key) {
|
||
|
|
return key === "innerHTML" || key === "textContent" || key === "value" && (node.tag === "textarea" || node.tag === "select") || isCheckboxValueProp(node, key);
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Props `v-model` reads back off the element as raw values (`_value`,
|
||
|
|
* `_trueValue`, `_falseValue`), so a number literal bound to them has to keep
|
||
|
|
* its type - vdom bails on `<option :value="1">` in its own static
|
||
|
|
* stringification for the same reason.
|
||
|
|
*
|
||
|
|
* Deliberately wider than `isRuntimeOnlyProp`: a literal `<input value="1">`
|
||
|
|
* belongs in the template string, only the type of a *bound* number has to
|
||
|
|
* survive. So this one is consulted by `v-bind`, that one by
|
||
|
|
* `transformNativeElement`.
|
||
|
|
*/
|
||
|
|
function isModelValueProp(node, key) {
|
||
|
|
const { tag } = node;
|
||
|
|
return key === "value" && (tag === "input" || tag === "option" || tag === "textarea" || tag === "select") || isCheckboxValueProp(node, key);
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Boolean attributes are folded into the template from the value itself, which
|
||
|
|
* needs the type it was written with: `:disabled="0"` is `false`, while the
|
||
|
|
* `"0"` a stringified template attribute would carry is `true`. `hidden` is
|
||
|
|
* not a boolean attribute - it also takes `until-found` - but a number means
|
||
|
|
* the same thing there.
|
||
|
|
*/
|
||
|
|
function isFoldableBooleanAttr(key) {
|
||
|
|
return (0, _vue_shared.isBooleanAttr)(key) || key === "hidden";
|
||
|
|
}
|
||
|
|
const transformElement = (node, context) => {
|
||
|
|
let effectIndex = context.block.effect.length;
|
||
|
|
const getEffectIndex = () => effectIndex++;
|
||
|
|
if (node.type === 1 && node.children.length) ignoreVHtmlChildren(node, context, "node");
|
||
|
|
let parentSlots;
|
||
|
|
if (node.type === 1 && (node.tagType === 1 || context.options.isCustomElement(node.tag))) {
|
||
|
|
parentSlots = context.slots;
|
||
|
|
context.slots = [];
|
||
|
|
}
|
||
|
|
return function postTransformElement() {
|
||
|
|
({node} = context);
|
||
|
|
if (!(node.type === 1 && (node.tagType === 0 || node.tagType === 1))) return;
|
||
|
|
const useCreateElement = shouldUseCreateElement(node, context);
|
||
|
|
const isComponent = node.tagType === 1 || useCreateElement;
|
||
|
|
const isDynamicComponent = isComponentTag(node.tag);
|
||
|
|
const staticKey = dynamicComponentKeys.has(node) ? void 0 : resolveStaticKey(node, context, isComponent);
|
||
|
|
const propsResult = buildProps(node, context, isComponent, isDynamicComponent, getEffectIndex);
|
||
|
|
const singleRoot = context.isSingleRoot;
|
||
|
|
if (isComponent) transformComponentElement(node, propsResult, staticKey, singleRoot, context, isDynamicComponent, useCreateElement);
|
||
|
|
else transformNativeElement(node, propsResult, staticKey, singleRoot, context, getEffectIndex, context.root === context.effectiveParent || canOmitEndTag(node, context));
|
||
|
|
if (parentSlots) context.slots = parentSlots;
|
||
|
|
};
|
||
|
|
};
|
||
|
|
function canOmitEndTag(node, context) {
|
||
|
|
const { block, parent } = context;
|
||
|
|
if (!parent) return false;
|
||
|
|
if (block !== parent.block) return true;
|
||
|
|
if (context.templateCloseTags && (context.templateCloseTags.has(node.tag) || context.templateCloseTags.has("form") || context.templateCloseTags.has("li") && (node.tag === "ul" || node.tag === "ol") || (0, _vue_shared.isAlwaysCloseTag)(node.tag) || (0, _vue_shared.isFormattingTag)(node.tag)) || context.templateCloseBlocks && (0, _vue_shared.isBlockTag)(node.tag)) return false;
|
||
|
|
if ((0, _vue_shared.isAlwaysCloseTag)(node.tag) && !context.isOnRightmostPath) return false;
|
||
|
|
if ((0, _vue_shared.isFormattingTag)(node.tag) || parent.node.type === 1 && (node.tag === parent.node.tag || parent.node.ns !== 0 && node.ns !== parent.node.ns)) return context.isOnRightmostPath;
|
||
|
|
return context.isLastEffectiveChild;
|
||
|
|
}
|
||
|
|
function getChildTemplateCloseState(context) {
|
||
|
|
const { node } = context;
|
||
|
|
if (node.type !== 1 || node.tagType !== 0 || shouldUseCreateElement(node, context)) return;
|
||
|
|
const inSameTemplateAsParent = isInSameTemplateAsParent(context);
|
||
|
|
const inheritedTags = inSameTemplateAsParent ? context.templateCloseTags : void 0;
|
||
|
|
const inheritedBlocks = inSameTemplateAsParent && context.templateCloseBlocks;
|
||
|
|
if (context.root === context.effectiveParent || canOmitEndTag(node, context) || (0, _vue_shared.isVoidTag)(node.tag)) return inheritedTags || inheritedBlocks ? {
|
||
|
|
tags: inheritedTags,
|
||
|
|
blocks: inheritedBlocks
|
||
|
|
} : void 0;
|
||
|
|
const tags = new Set(inheritedTags);
|
||
|
|
tags.add(node.tag);
|
||
|
|
return {
|
||
|
|
tags,
|
||
|
|
blocks: inheritedBlocks || (0, _vue_shared.isInlineTag)(node.tag)
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function isInSameTemplateAsParent(context) {
|
||
|
|
const { parent, node, block } = context;
|
||
|
|
if (!parent || block !== parent.block) return false;
|
||
|
|
const parentNode = parent.node;
|
||
|
|
if (parentNode.type !== 1 || parentNode.tagType !== 0) return false;
|
||
|
|
return !shouldUseCreateElement(parentNode, parent) && (0, _vue_compiler_dom.isValidHTMLNesting)(parentNode.tag, node.tag);
|
||
|
|
}
|
||
|
|
function transformComponentElement(node, propsResult, staticKey, singleRoot, context, isDynamicComponent, useCreateElement) {
|
||
|
|
const dynamicComponent = isDynamicComponent ? resolveDynamicComponent(node) : void 0;
|
||
|
|
let { tag } = node;
|
||
|
|
let asset = true;
|
||
|
|
if (!dynamicComponent && !useCreateElement) {
|
||
|
|
const isProp = findProp$1(node, "is");
|
||
|
|
if (isProp && isProp.type === 6 && isVueIsValue(isProp)) tag = isProp.value.content.slice(4);
|
||
|
|
const fromSetup = resolveSetupReference(tag, context);
|
||
|
|
if (fromSetup) {
|
||
|
|
tag = fromSetup;
|
||
|
|
asset = false;
|
||
|
|
}
|
||
|
|
const builtInTag = isBuiltInComponent(tag);
|
||
|
|
if (builtInTag) {
|
||
|
|
tag = builtInTag;
|
||
|
|
asset = false;
|
||
|
|
}
|
||
|
|
const dotIndex = tag.indexOf(".");
|
||
|
|
if (dotIndex > 0) {
|
||
|
|
const ns = resolveSetupReference(tag.slice(0, dotIndex), context);
|
||
|
|
if (ns) {
|
||
|
|
tag = ns + tag.slice(dotIndex);
|
||
|
|
asset = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (asset) {
|
||
|
|
if (context.selfName && (0, _vue_shared.capitalize)((0, _vue_shared.camelize)(tag)) === context.selfName) tag += `__self`;
|
||
|
|
context.component.add(tag);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
const props = propsResult[0] ? propsResult[1] : [propsResult[1]];
|
||
|
|
if (staticKey && !useCreateElement) {
|
||
|
|
const keyProp = {
|
||
|
|
key: (0, _vue_compiler_dom.createSimpleExpression)("key", true),
|
||
|
|
values: [staticKey]
|
||
|
|
};
|
||
|
|
if ((0, _vue_shared.isArray)(props[0])) props[0].push(keyProp);
|
||
|
|
else props.unshift([keyProp]);
|
||
|
|
}
|
||
|
|
context.dynamic.flags |= 6;
|
||
|
|
const id = context.reference();
|
||
|
|
context.dynamic.operation = {
|
||
|
|
type: 11,
|
||
|
|
id,
|
||
|
|
...context.effectBoundary(),
|
||
|
|
tag,
|
||
|
|
props,
|
||
|
|
asset,
|
||
|
|
root: singleRoot,
|
||
|
|
slots: [...context.slots],
|
||
|
|
once: context.inVOnce,
|
||
|
|
dynamic: dynamicComponent,
|
||
|
|
useCreateElement,
|
||
|
|
ns: node.ns || void 0,
|
||
|
|
key: dynamicComponentKeys.get(node)
|
||
|
|
};
|
||
|
|
if (staticKey && (useCreateElement || dynamicComponent)) context.registerOperation(createSetBlockKey(id, staticKey));
|
||
|
|
context.slots = [];
|
||
|
|
}
|
||
|
|
function isVueIsValue(prop) {
|
||
|
|
return !!prop.value && prop.value.content.startsWith("vue:");
|
||
|
|
}
|
||
|
|
function resolveDynamicComponent(node) {
|
||
|
|
const isProp = findProp$1(node, "is", false, true);
|
||
|
|
if (!isProp) return;
|
||
|
|
if (isProp.type === 6) return isProp.value && (0, _vue_compiler_dom.createSimpleExpression)(isProp.value.content, true);
|
||
|
|
else return isProp.exp || (0, _vue_shared.extend)((0, _vue_compiler_dom.createSimpleExpression)(`is`, false, isProp.arg.loc), { ast: null });
|
||
|
|
}
|
||
|
|
function resolveSetupReference(name, context) {
|
||
|
|
const bindings = context.options.bindingMetadata;
|
||
|
|
if (!bindings || bindings.__isScriptSetup === false) return;
|
||
|
|
const camelName = (0, _vue_shared.camelize)(name);
|
||
|
|
const PascalName = (0, _vue_shared.capitalize)(camelName);
|
||
|
|
return bindings[name] ? name : bindings[camelName] ? camelName : bindings[PascalName] ? PascalName : void 0;
|
||
|
|
}
|
||
|
|
const dynamicKeys = [
|
||
|
|
"indeterminate",
|
||
|
|
"volume",
|
||
|
|
"playbackRate",
|
||
|
|
"defaultPlaybackRate",
|
||
|
|
"currentTime",
|
||
|
|
"valueAsNumber"
|
||
|
|
];
|
||
|
|
const NEEDS_QUOTES_RE = /[\s"'`=<>]/;
|
||
|
|
const LEADING_NEWLINE_RE = /^\r?\n/;
|
||
|
|
const UNSAFE_ATTR_NAME_RE = /[\u0000-\u0020"'<=/>]/;
|
||
|
|
function transformNativeElement(node, propsResult, staticKey, singleRoot, context, getEffectIndex, omitEndTag) {
|
||
|
|
const { tag } = node;
|
||
|
|
const { scopeId } = context.options;
|
||
|
|
const isSVG = node.ns === 1;
|
||
|
|
let template = "";
|
||
|
|
template += `<${tag}`;
|
||
|
|
if (scopeId) template += ` ${scopeId}`;
|
||
|
|
if (propsResult[0]) {
|
||
|
|
const [, dynamicArgs, expressions] = propsResult;
|
||
|
|
context.registerEffect(expressions, {
|
||
|
|
type: 4,
|
||
|
|
element: context.reference(),
|
||
|
|
props: dynamicArgs,
|
||
|
|
isSVG
|
||
|
|
}, getEffectIndex);
|
||
|
|
} else {
|
||
|
|
const appendTemplateProp = (key, value = "") => {
|
||
|
|
template += ` ${key}`;
|
||
|
|
if (value) {
|
||
|
|
const escapedValue = escapeAttrValue(value);
|
||
|
|
template += NEEDS_QUOTES_RE.test(value) ? `="${escapedValue}"` : `=${escapedValue}`;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
const needsOrderedProps = tag === "input" && propsResult[1].some(({ key, modifier }) => key.content === "valueAsNumber" && modifier !== "^");
|
||
|
|
const nativeOnProps = [];
|
||
|
|
let hasEffect = false;
|
||
|
|
for (const prop of propsResult[1]) {
|
||
|
|
const { key, values } = prop;
|
||
|
|
const canStringifyAttrName = key.isStatic && !UNSAFE_ATTR_NAME_RE.test(key.content);
|
||
|
|
let foldedValue;
|
||
|
|
if (!prop.modifier && (0, _vue_shared.isOn)(key.content)) {
|
||
|
|
if (!(0, _vue_shared.isModelListener)(key.content)) {
|
||
|
|
const operation = {
|
||
|
|
type: 3,
|
||
|
|
element: context.reference(),
|
||
|
|
prop,
|
||
|
|
tag,
|
||
|
|
isSVG
|
||
|
|
};
|
||
|
|
hasEffect = context.registerEffect(values, operation, getEffectIndex, needsOrderedProps && hasEffect);
|
||
|
|
operation.effect = hasEffect;
|
||
|
|
}
|
||
|
|
} else if (canStringifyAttrName && context.imports.some((imported) => values[0].content.includes(imported.exp.content))) template += ` ${key.content}="${IMPORT_EXP_START}${values[0].content}${IMPORT_EXP_END}"`;
|
||
|
|
else if (canStringifyAttrName && prop.modifier !== "." && values.length === 1 && (values[0].isStatic || values[0].content === "''") && !dynamicKeys.includes(key.content) && !isRuntimeOnlyProp(node, key.content)) {
|
||
|
|
const value = values[0].content === "''" ? "" : values[0].content;
|
||
|
|
appendTemplateProp(key.content, value);
|
||
|
|
} else if (canStringifyAttrName && !prop.modifier && isFoldableBooleanAttr(key.content) && (foldedValue = foldBooleanAttrValue(key.content, values)) != null) {
|
||
|
|
if (foldedValue) appendTemplateProp(key.content);
|
||
|
|
} else if (canStringifyAttrName && !prop.modifier && hasBoundValue(values) && (foldedValue = key.content === "class" ? foldClassValues(values) : key.content === "style" ? foldStyleValues(values) : void 0) != null) {
|
||
|
|
if (foldedValue) appendTemplateProp(key.content, foldedValue);
|
||
|
|
} else if (isSVG && !prop.modifier && (0, _vue_shared.isNativeOn)(key.content)) nativeOnProps.push(prop);
|
||
|
|
else hasEffect = context.registerEffect(values, {
|
||
|
|
type: 3,
|
||
|
|
element: context.reference(),
|
||
|
|
prop,
|
||
|
|
tag,
|
||
|
|
isSVG
|
||
|
|
}, getEffectIndex, needsOrderedProps && hasEffect);
|
||
|
|
}
|
||
|
|
if (nativeOnProps.length) context.registerEffect(nativeOnProps.flatMap(({ values }) => values), {
|
||
|
|
type: 4,
|
||
|
|
element: context.reference(),
|
||
|
|
props: [nativeOnProps],
|
||
|
|
isSVG
|
||
|
|
}, getEffectIndex);
|
||
|
|
}
|
||
|
|
let children = context.childrenTemplate.join("");
|
||
|
|
if (node.ns === 0 && _vue_compiler_dom.parserOptions.isIgnoreNewlineTag(tag) && LEADING_NEWLINE_RE.test(children)) children = `\n` + children;
|
||
|
|
template += `>` + children;
|
||
|
|
if (!(0, _vue_shared.isVoidTag)(tag) && !omitEndTag) template += `</${tag}>`;
|
||
|
|
context.templateRoot = singleRoot;
|
||
|
|
if (context.parent && context.parent.node.type === 1 && !(0, _vue_compiler_dom.isValidHTMLNesting)(context.parent.node.tag, tag)) {
|
||
|
|
context.reference();
|
||
|
|
context.dynamic.template = context.pushTemplate(template);
|
||
|
|
context.dynamic.flags |= 6;
|
||
|
|
} else context.template += template;
|
||
|
|
if (staticKey) context.registerOperation(createSetBlockKey(context.reference(), staticKey));
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Templates are parsed as html again at runtime, so a value written into one
|
||
|
|
* has to survive that round trip unchanged. The parser has already decoded the
|
||
|
|
* character references in a static value, and `&` would start a second round
|
||
|
|
* of decoding, turning `&lt;` into `<` instead of `<`. This is the same
|
||
|
|
* reason the vdom static stringifier escapes values before putting them into
|
||
|
|
* an html string (`escapeHtml` in `stringifyStatic`).
|
||
|
|
*
|
||
|
|
* Character references are all this fixes. `<`, `>`, `'` and whitespace need no
|
||
|
|
* escaping because `NEEDS_QUOTES_RE` already puts every value containing them
|
||
|
|
* inside double quotes, where they stand for themselves. A CR or a NUL in the
|
||
|
|
* value does still come out differently than in vdom, but that is a class of
|
||
|
|
* its own: the parser normalizes both away while preprocessing its input, and
|
||
|
|
* it does so for comment data and for text in `<pre>` and `<textarea>` just the
|
||
|
|
* same, where a NUL cannot be written back at all.
|
||
|
|
*/
|
||
|
|
function escapeAttrValue(value) {
|
||
|
|
return value.replace(/&/g, "&").replace(/"/g, """);
|
||
|
|
}
|
||
|
|
function foldBooleanAttrValue(key, values) {
|
||
|
|
if (values.length !== 1) return;
|
||
|
|
const evaluated = evaluateConstantExpression(values[0]);
|
||
|
|
if (!evaluated) return;
|
||
|
|
const value = evaluated.value;
|
||
|
|
if (key === "hidden" && typeof value === "number") return (0, _vue_shared.includeBooleanAttr)(value);
|
||
|
|
if (value === true || value === false || value == null) return (0, _vue_shared.includeBooleanAttr)(value);
|
||
|
|
}
|
||
|
|
function foldStyleValues(values) {
|
||
|
|
const evaluatedValues = [];
|
||
|
|
for (const value of values) {
|
||
|
|
const evaluated = evaluateConstantExpression(value);
|
||
|
|
if (!evaluated || !isStaticStyleValue(evaluated.value)) return;
|
||
|
|
evaluatedValues.push(evaluated.value);
|
||
|
|
}
|
||
|
|
const normalized = (0, _vue_shared.normalizeStyle)(evaluatedValues.length === 1 ? evaluatedValues[0] : evaluatedValues);
|
||
|
|
return (0, _vue_shared.stringifyStyle)(normalized);
|
||
|
|
}
|
||
|
|
function isStaticStyleValue(value) {
|
||
|
|
if (typeof value === "string") return true;
|
||
|
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
||
|
|
for (const key in value) {
|
||
|
|
const propValue = value[key];
|
||
|
|
if (!isSafeStylePropertyName(key) || !isSafeStylePropertyValue(propValue)) return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
function isSafeStylePropertyName(key) {
|
||
|
|
return !!key && !/[;:]/.test(key);
|
||
|
|
}
|
||
|
|
function isSafeStylePropertyValue(value) {
|
||
|
|
return typeof value === "number" || typeof value === "string" && !value.includes(";");
|
||
|
|
}
|
||
|
|
function hasBoundValue(values) {
|
||
|
|
return values.some((value) => !value.isStatic && value.content !== "''");
|
||
|
|
}
|
||
|
|
function foldClassValues(values) {
|
||
|
|
let templateValue = "";
|
||
|
|
let changed = false;
|
||
|
|
for (const value of values) {
|
||
|
|
const evaluated = evaluateConstantExpression(value);
|
||
|
|
if (evaluated) {
|
||
|
|
const normalized = (0, _vue_shared.normalizeClass)(evaluated.value);
|
||
|
|
if (normalized) templateValue = appendClass(templateValue, normalized);
|
||
|
|
else changed = true;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
return changed || templateValue ? templateValue : void 0;
|
||
|
|
}
|
||
|
|
function appendClass(base, value) {
|
||
|
|
return base ? value ? `${base} ${value}` : base : value;
|
||
|
|
}
|
||
|
|
function getObjectPropertyName(prop) {
|
||
|
|
const key = prop.key;
|
||
|
|
if (key.type === "Identifier") return key.name;
|
||
|
|
else if (key.type === "StringLiteral") return key.value;
|
||
|
|
else if (key.type === "NumericLiteral") return String(key.value);
|
||
|
|
}
|
||
|
|
function evaluateConstantExpression(node) {
|
||
|
|
if (node.isStatic) return { value: node.content };
|
||
|
|
const ast = node.ast;
|
||
|
|
if (ast === null) {
|
||
|
|
if (node.content === "true") return { value: true };
|
||
|
|
else if (node.content === "false") return { value: false };
|
||
|
|
else if (node.content === "null") return { value: null };
|
||
|
|
else if (node.content === "undefined") return { value: void 0 };
|
||
|
|
}
|
||
|
|
if (!ast) return;
|
||
|
|
return evaluateConstantAst(ast);
|
||
|
|
}
|
||
|
|
function evaluateConstantAst(node) {
|
||
|
|
switch (node.type) {
|
||
|
|
case "StringLiteral": return { value: node.value };
|
||
|
|
case "NumericLiteral": return { value: node.value };
|
||
|
|
case "BooleanLiteral": return { value: node.value };
|
||
|
|
case "NullLiteral": return { value: null };
|
||
|
|
case "Identifier": return node.name === "undefined" ? { value: void 0 } : void 0;
|
||
|
|
case "UnaryExpression":
|
||
|
|
if (node.operator === "void") return { value: void 0 };
|
||
|
|
else if (node.operator === "-") {
|
||
|
|
const value = evaluateConstantAst(node.argument);
|
||
|
|
return value && typeof value.value === "number" ? { value: -value.value } : void 0;
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
case "TemplateLiteral": return evaluateTemplateLiteral(node);
|
||
|
|
case "ObjectExpression": return evaluateObjectExpression(node);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function evaluateTemplateLiteral(node) {
|
||
|
|
if (node.type !== "TemplateLiteral") return;
|
||
|
|
let value = "";
|
||
|
|
for (const [index, quasi] of node.quasis.entries()) {
|
||
|
|
value += quasi.value.cooked || "";
|
||
|
|
const expression = node.expressions[index];
|
||
|
|
if (expression) {
|
||
|
|
const evaluated = evaluateConstantAst(expression);
|
||
|
|
if (!evaluated) return;
|
||
|
|
value += evaluated.value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return { value };
|
||
|
|
}
|
||
|
|
function evaluateObjectExpression(node) {
|
||
|
|
const value = {};
|
||
|
|
for (const prop of node.properties) {
|
||
|
|
if (prop.type !== "ObjectProperty" || prop.computed) return;
|
||
|
|
const key = getObjectPropertyName(prop);
|
||
|
|
if (key == null) return;
|
||
|
|
const evaluated = evaluateConstantAst(prop.value);
|
||
|
|
if (!evaluated) return;
|
||
|
|
value[key] = evaluated.value;
|
||
|
|
}
|
||
|
|
return { value };
|
||
|
|
}
|
||
|
|
function resolveStaticKey(node, context, isComponent) {
|
||
|
|
if (context.parent.node !== context.block.node) return;
|
||
|
|
const keyProp = findProp$1(node, "key", false, true);
|
||
|
|
if (!keyProp) return;
|
||
|
|
if (keyProp.type === 6) return keyProp.value ? (0, _vue_compiler_dom.createSimpleExpression)(keyProp.value.content, true, keyProp.value.loc) : EMPTY_EXPRESSION;
|
||
|
|
const value = keyProp.exp || normalizeBindShorthand(keyProp.arg, context);
|
||
|
|
if (isStaticExpression(value, context.options.bindingMetadata)) return resolveExpression(value, isComponent);
|
||
|
|
}
|
||
|
|
function createSetBlockKey(element, value) {
|
||
|
|
return {
|
||
|
|
type: 2,
|
||
|
|
element,
|
||
|
|
value
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function buildProps(node, context, isComponent, isDynamicComponent, getEffectIndex) {
|
||
|
|
const props = node.props;
|
||
|
|
if (props.length === 0) return [false, []];
|
||
|
|
const dynamicArgs = [];
|
||
|
|
const dynamicExpr = [];
|
||
|
|
let results = [];
|
||
|
|
const deferListeners = !isComponent && !!(0, _vue_compiler_dom.findDir)(node, "model") && !(0, _vue_compiler_dom.hasDynamicKeyVBind)(node) && mergesListeners(node, context);
|
||
|
|
let listenerResults = [];
|
||
|
|
function pushMergeArg(listeners = false) {
|
||
|
|
const props = listeners ? listenerResults : results;
|
||
|
|
if (props.length) {
|
||
|
|
dynamicArgs.push(dedupeProperties(props));
|
||
|
|
if (listeners) listenerResults = [];
|
||
|
|
else results = [];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function pushStaticObjectLiteralProps(props) {
|
||
|
|
if (dynamicArgs.length) {
|
||
|
|
pushMergeArg();
|
||
|
|
dynamicArgs.push(props);
|
||
|
|
} else results.push(...props.map(toDirectiveResult));
|
||
|
|
}
|
||
|
|
for (const prop of props) {
|
||
|
|
if (prop.type === 7 && !prop.arg) {
|
||
|
|
if (prop.name === "bind") {
|
||
|
|
if (prop.exp) {
|
||
|
|
const objectLiteralProps = isComponent ? resolveComponentObjectLiteralBindProps(prop.exp, context, props, prop) : resolveNativeObjectLiteralBindProps(prop.exp, context, props, prop);
|
||
|
|
if (objectLiteralProps) {
|
||
|
|
if (isComponent) pushStaticObjectLiteralProps(objectLiteralProps);
|
||
|
|
else {
|
||
|
|
dynamicExpr.push(prop.exp);
|
||
|
|
results.push(...objectLiteralProps.map(toDirectiveResult));
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
dynamicExpr.push(prop.exp);
|
||
|
|
pushMergeArg();
|
||
|
|
dynamicArgs.push({
|
||
|
|
kind: 0,
|
||
|
|
value: prop.exp
|
||
|
|
});
|
||
|
|
}
|
||
|
|
} else context.options.onError((0, _vue_compiler_dom.createCompilerError)(34, prop.loc));
|
||
|
|
continue;
|
||
|
|
} else if (prop.name === "on") {
|
||
|
|
if (prop.exp) {
|
||
|
|
const objectLiteralProps = isComponent ? resolveComponentObjectLiteralOnProps(prop.exp, context, props, prop) : void 0;
|
||
|
|
if (objectLiteralProps) pushStaticObjectLiteralProps(objectLiteralProps);
|
||
|
|
else if (isComponent || mergesListeners(node, context)) {
|
||
|
|
dynamicExpr.push(prop.exp);
|
||
|
|
pushMergeArg(deferListeners);
|
||
|
|
dynamicArgs.push({
|
||
|
|
kind: 0,
|
||
|
|
value: prop.exp,
|
||
|
|
handler: true
|
||
|
|
});
|
||
|
|
} else context.registerEffect([prop.exp], {
|
||
|
|
type: 7,
|
||
|
|
element: context.reference(),
|
||
|
|
event: prop.exp
|
||
|
|
}, getEffectIndex);
|
||
|
|
} else context.options.onError((0, _vue_compiler_dom.createCompilerError)(35, prop.loc));
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (prop.type === 6 ? prop.name === "is" && (isDynamicComponent || isVueIsValue(prop)) : isDynamicComponent && prop.name === "bind" && (0, _vue_compiler_dom.isStaticArgOf)(prop.arg, "is")) continue;
|
||
|
|
const result = transformProp(prop, node, context);
|
||
|
|
if (result) {
|
||
|
|
if (deferListeners && !result.handler && (result.modifier || !(0, _vue_shared.isOn)(result.key.content))) {
|
||
|
|
results.push(result);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
dynamicExpr.push(result.key);
|
||
|
|
if (!deferListeners || !result.handler) dynamicExpr.push(result.value);
|
||
|
|
if (deferListeners) listenerResults.push(result);
|
||
|
|
else if (isComponent && !result.key.isStatic) {
|
||
|
|
pushMergeArg();
|
||
|
|
dynamicArgs.push((0, _vue_shared.extend)(resolveDirectiveResult(result), { kind: 1 }));
|
||
|
|
} else results.push(result);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (deferListeners) {
|
||
|
|
pushMergeArg(true);
|
||
|
|
context.registerEffect(dynamicExpr, {
|
||
|
|
type: 4,
|
||
|
|
element: context.reference(),
|
||
|
|
props: dynamicArgs,
|
||
|
|
isSVG: node.ns === 1,
|
||
|
|
listeners: true
|
||
|
|
}, getEffectIndex);
|
||
|
|
return [false, dedupeProperties(results)];
|
||
|
|
}
|
||
|
|
if (dynamicArgs.length || results.some(({ key }) => !key.isStatic)) {
|
||
|
|
pushMergeArg();
|
||
|
|
return [
|
||
|
|
true,
|
||
|
|
dynamicArgs,
|
||
|
|
dynamicExpr
|
||
|
|
];
|
||
|
|
}
|
||
|
|
return [false, dedupeProperties(results)];
|
||
|
|
}
|
||
|
|
function resolveObjectLiteralProps(exp, context, keyTransform, isValidKey) {
|
||
|
|
const ast = exp.ast;
|
||
|
|
if (!ast || ast.type !== "ObjectExpression") return;
|
||
|
|
const props = [];
|
||
|
|
const knownKeys = /* @__PURE__ */ new Set();
|
||
|
|
for (const property of ast.properties) {
|
||
|
|
if (property.type !== "ObjectProperty" || property.computed) return;
|
||
|
|
let key = getObjectPropertyName(property);
|
||
|
|
if (key == null || key === "__proto__") return;
|
||
|
|
if (isValidKey && !isValidKey(key)) return;
|
||
|
|
if (keyTransform) key = keyTransform(key);
|
||
|
|
if (knownKeys.has(key)) return;
|
||
|
|
knownKeys.add(key);
|
||
|
|
props.push({
|
||
|
|
key: (0, _vue_compiler_dom.createSimpleExpression)(key, true),
|
||
|
|
values: [resolveExpression(createObjectBindSubExpression(exp, property.value, context), true)]
|
||
|
|
});
|
||
|
|
}
|
||
|
|
return props;
|
||
|
|
}
|
||
|
|
function resolveComponentObjectLiteralBindProps(exp, context, nodeProps, currentProp) {
|
||
|
|
const props = resolveObjectLiteralProps(exp, context, void 0, isSafeObjectLiteralBindKey);
|
||
|
|
if (!props || hasComponentObjectLiteralBindConflict(nodeProps, currentProp, props)) return;
|
||
|
|
return props;
|
||
|
|
}
|
||
|
|
const listenerMerge = /* @__PURE__ */ new WeakMap();
|
||
|
|
function mergesListeners(node, context) {
|
||
|
|
let merges = listenerMerge.get(node);
|
||
|
|
if (merges === void 0) listenerMerge.set(node, merges = resolveListenerMerge(node, context));
|
||
|
|
return merges;
|
||
|
|
}
|
||
|
|
function resolveListenerMerge(node, context) {
|
||
|
|
const props = node.props;
|
||
|
|
let hasVOnObject = false;
|
||
|
|
let hasStaticListener = false;
|
||
|
|
for (const p of props) {
|
||
|
|
if (p.type !== 7) continue;
|
||
|
|
const arg = p.arg && resolveExpression(p.arg);
|
||
|
|
if (p.name === "bind") {
|
||
|
|
if (!arg) {
|
||
|
|
if (p.exp) {
|
||
|
|
const bindProps = resolveNativeObjectLiteralBindProps(p.exp, context, props, p);
|
||
|
|
if (!bindProps) return true;
|
||
|
|
if (node.ns === 1 && bindProps.some(({ key }) => (0, _vue_shared.isNativeOn)(key.content))) hasStaticListener = true;
|
||
|
|
}
|
||
|
|
} else if (!arg.isStatic) return true;
|
||
|
|
else if (((0, _vue_shared.isOn)(arg.content) || node.ns === 1 && (0, _vue_shared.isNativeOn)(arg.content)) && !(0, _vue_shared.isModelListener)(arg.content) && !p.modifiers.some((m) => m.content === "prop" || m.content === "attr")) hasStaticListener = true;
|
||
|
|
} else if (p.name === "on") {
|
||
|
|
if (!arg) hasVOnObject = true;
|
||
|
|
else if (arg.isStatic && !p.modifiers.some((m) => m.content === "delegate")) hasStaticListener = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return hasVOnObject && hasStaticListener;
|
||
|
|
}
|
||
|
|
function resolveNativeObjectLiteralBindProps(exp, context, nodeProps, currentProp) {
|
||
|
|
const props = resolveObjectLiteralProps(exp, context, void 0, isSafeNativeObjectLiteralBindKey);
|
||
|
|
if (!props || hasNativeObjectLiteralBindConflict(nodeProps, currentProp, props)) return;
|
||
|
|
return props;
|
||
|
|
}
|
||
|
|
function resolveComponentObjectLiteralOnProps(exp, context, nodeProps, currentProp) {
|
||
|
|
const props = resolveObjectLiteralProps(exp, context, _vue_shared.toHandlerKey);
|
||
|
|
if (!props || hasComponentObjectLiteralBindConflict(nodeProps, currentProp, props)) return;
|
||
|
|
return props;
|
||
|
|
}
|
||
|
|
function isSafeNativeObjectLiteralBindKey(key) {
|
||
|
|
return key !== "" && !UNSAFE_ATTR_NAME_RE.test(key) && isSafeObjectLiteralBindKey(key) && !(0, _vue_shared.isOn)(key) && key.charCodeAt(0) !== 46 && key.charCodeAt(0) !== 94;
|
||
|
|
}
|
||
|
|
function isSafeObjectLiteralBindKey(key) {
|
||
|
|
return !isReservedProp(key);
|
||
|
|
}
|
||
|
|
function hasComponentObjectLiteralBindConflict(props, currentProp, objectLiteralProps) {
|
||
|
|
const keys = createComponentConflictKeySet(objectLiteralProps.map((prop) => prop.key.content));
|
||
|
|
for (const prop of props) {
|
||
|
|
if (prop === currentProp) continue;
|
||
|
|
let key;
|
||
|
|
if (prop.type === 6) key = prop.name;
|
||
|
|
else if (prop.name === "bind") {
|
||
|
|
if (!prop.arg) {
|
||
|
|
const bindKeys = getObjectLiteralKeys(prop.exp);
|
||
|
|
if (bindKeys && hasComponentKeyOverlap(keys, bindKeys)) return true;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
key = getStaticBindKey(prop);
|
||
|
|
} else if (prop.name === "on") key = getStaticHandlerKey(prop);
|
||
|
|
else if (prop.name === "model") {
|
||
|
|
if (hasComponentModelKey(keys, prop)) return true;
|
||
|
|
}
|
||
|
|
if (key && hasComponentKey(keys, key)) return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
function hasComponentModelKey(keys, prop) {
|
||
|
|
const { arg } = prop;
|
||
|
|
if (arg && (arg.type !== 4 || !arg.isStatic)) return true;
|
||
|
|
const key = arg ? arg.content : "modelValue";
|
||
|
|
return hasComponentKey(keys, key) || hasComponentKey(keys, `onUpdate:${(0, _vue_shared.camelize)(key)}`) || prop.modifiers.length > 0 && hasComponentKey(keys, (0, _vue_shared.getModifierPropName)(key));
|
||
|
|
}
|
||
|
|
function hasNativeObjectLiteralBindConflict(props, currentProp, objectLiteralProps) {
|
||
|
|
const keys = new Set(objectLiteralProps.map((prop) => prop.key.content));
|
||
|
|
for (const prop of props) {
|
||
|
|
if (prop === currentProp) continue;
|
||
|
|
let key;
|
||
|
|
if (prop.type === 6) key = prop.name;
|
||
|
|
else if (prop.name === "bind") {
|
||
|
|
if (!prop.arg) return true;
|
||
|
|
key = getStaticBindKey(prop);
|
||
|
|
if (!key) return true;
|
||
|
|
}
|
||
|
|
if (key && keys.has(key)) return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
function getStaticBindKey(prop) {
|
||
|
|
const { arg } = prop;
|
||
|
|
if (!arg || arg.type !== 4 || !arg.isStatic) return;
|
||
|
|
let key = arg.content;
|
||
|
|
if (isReservedProp(key)) return;
|
||
|
|
if (prop.modifiers.some((modifier) => modifier.content === "camel")) key = (0, _vue_shared.camelize)(key);
|
||
|
|
return key;
|
||
|
|
}
|
||
|
|
function getStaticHandlerKey(prop) {
|
||
|
|
const { arg } = prop;
|
||
|
|
if (!arg || arg.type !== 4 || !arg.isStatic) return;
|
||
|
|
let key = arg.content;
|
||
|
|
if (key.startsWith("vue:")) key = `vnode-${key.slice(4)}`;
|
||
|
|
const { nonKeyModifiers, eventOptionModifiers } = (0, _vue_compiler_dom.resolveModifiers)(`on${key}`, prop.modifiers, null, prop.loc);
|
||
|
|
if (key.toLowerCase() === "click") {
|
||
|
|
if (nonKeyModifiers.includes("middle")) key = "mouseup";
|
||
|
|
if (nonKeyModifiers.includes("right")) key = "contextmenu";
|
||
|
|
}
|
||
|
|
key = (0, _vue_shared.toHandlerKey)((0, _vue_shared.camelize)(key));
|
||
|
|
const optionPostfix = eventOptionModifiers.map(_vue_shared.capitalize).join("");
|
||
|
|
if (optionPostfix) key += optionPostfix;
|
||
|
|
return key;
|
||
|
|
}
|
||
|
|
function getObjectLiteralKeys(exp) {
|
||
|
|
const ast = exp && exp.ast;
|
||
|
|
if (!ast || ast.type !== "ObjectExpression") return;
|
||
|
|
const keys = /* @__PURE__ */ new Set();
|
||
|
|
for (const property of ast.properties) {
|
||
|
|
if (property.type !== "ObjectProperty" || property.computed) return;
|
||
|
|
const key = getObjectPropertyName(property);
|
||
|
|
if (key == null) return;
|
||
|
|
keys.add(key);
|
||
|
|
}
|
||
|
|
return keys;
|
||
|
|
}
|
||
|
|
function createComponentConflictKeySet(keys) {
|
||
|
|
const normalized = /* @__PURE__ */ new Set();
|
||
|
|
for (const key of keys) {
|
||
|
|
normalized.add(key);
|
||
|
|
normalized.add((0, _vue_shared.camelize)(key));
|
||
|
|
}
|
||
|
|
return normalized;
|
||
|
|
}
|
||
|
|
function hasComponentKey(keys, key) {
|
||
|
|
return keys.has(key) || keys.has((0, _vue_shared.camelize)(key));
|
||
|
|
}
|
||
|
|
function hasComponentKeyOverlap(left, right) {
|
||
|
|
for (const key of right) if (hasComponentKey(left, key)) return true;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
function createObjectBindSubExpression(source, node, context) {
|
||
|
|
const start = node.start == null ? 0 : node.start - 1;
|
||
|
|
const end = node.end == null ? source.content.length : node.end - 1;
|
||
|
|
const content = source.content.slice(start, end);
|
||
|
|
const expression = (0, _vue_compiler_dom.createSimpleExpression)(content, false, {
|
||
|
|
start: (0, _vue_compiler_dom.advancePositionWithClone)(source.loc.start, source.content, start),
|
||
|
|
end: (0, _vue_compiler_dom.advancePositionWithClone)(source.loc.start, source.content, end),
|
||
|
|
source: content
|
||
|
|
});
|
||
|
|
expression.ast = (0, _vue_compiler_dom.isSimpleIdentifier)(content) ? null : (0, _babel_parser.parseExpression)(`(${content})`, getParserOptions(context.options.expressionPlugins));
|
||
|
|
return expression;
|
||
|
|
}
|
||
|
|
function transformProp(prop, node, context) {
|
||
|
|
let { name } = prop;
|
||
|
|
if (prop.type === 6) {
|
||
|
|
if (isReservedProp(name)) return;
|
||
|
|
return {
|
||
|
|
key: (0, _vue_compiler_dom.createSimpleExpression)(prop.name, true, prop.nameLoc),
|
||
|
|
value: prop.value ? (0, _vue_compiler_dom.createSimpleExpression)(prop.value.content, true, prop.value.loc) : EMPTY_EXPRESSION
|
||
|
|
};
|
||
|
|
}
|
||
|
|
const directiveTransform = context.options.directiveTransforms[name];
|
||
|
|
if (directiveTransform) return directiveTransform(prop, node, context);
|
||
|
|
if (!(0, _vue_shared.isBuiltInDirective)(name)) {
|
||
|
|
if (node.tagType === 2) {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createCompilerError)(36, prop.loc));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const fromSetup = resolveSetupReference(`v-${name}`, context);
|
||
|
|
if (fromSetup) name = fromSetup;
|
||
|
|
else context.directive.add(name);
|
||
|
|
context.registerOperation({
|
||
|
|
type: 13,
|
||
|
|
element: context.reference(),
|
||
|
|
dir: prop,
|
||
|
|
name,
|
||
|
|
asset: !fromSetup,
|
||
|
|
once: context.inVOnce
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function dedupeProperties(results) {
|
||
|
|
const knownProps = /* @__PURE__ */ new Map();
|
||
|
|
const deduped = [];
|
||
|
|
for (const result of results) {
|
||
|
|
const prop = resolveDirectiveResult(result);
|
||
|
|
if (!prop.key.isStatic) {
|
||
|
|
deduped.push(prop);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const name = prop.key.content;
|
||
|
|
const existing = knownProps.get(name);
|
||
|
|
if (existing && existing.handler === prop.handler) {
|
||
|
|
if (prop.handler) deduped.push(prop);
|
||
|
|
else if (name === "style" || name === "class") mergePropValues(existing, prop);
|
||
|
|
} else {
|
||
|
|
knownProps.set(name, prop);
|
||
|
|
deduped.push(prop);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return deduped;
|
||
|
|
}
|
||
|
|
function resolveDirectiveResult(prop) {
|
||
|
|
return (0, _vue_shared.extend)({}, prop, {
|
||
|
|
value: void 0,
|
||
|
|
values: [prop.value]
|
||
|
|
});
|
||
|
|
}
|
||
|
|
function toDirectiveResult(prop) {
|
||
|
|
return (0, _vue_shared.extend)({}, prop, {
|
||
|
|
values: void 0,
|
||
|
|
value: prop.values[0]
|
||
|
|
});
|
||
|
|
}
|
||
|
|
function mergePropValues(existing, incoming) {
|
||
|
|
const newValues = incoming.values;
|
||
|
|
existing.values.push(...newValues);
|
||
|
|
}
|
||
|
|
function shouldUseCreateElement(node, context) {
|
||
|
|
return context.options.isCustomElement(node.tag) || node.tagType === 0 && node.tag === "template";
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/transformChildren.ts
|
||
|
|
const transformChildren = (node, context) => {
|
||
|
|
const isFragment = node.type === 0 || node.type === 1 && (node.tagType === 3 || node.tagType === 1);
|
||
|
|
if (!isFragment && node.type !== 1) return;
|
||
|
|
const useCreateElement = node.type === 1 && shouldUseCreateElement(node, context);
|
||
|
|
const childTemplateCloseState = !isFragment && !useCreateElement ? getChildTemplateCloseState(context) : void 0;
|
||
|
|
for (const [i, child] of node.children.entries()) {
|
||
|
|
const childContext = context.create(child, i);
|
||
|
|
const isInSameTemplate = childTemplateCloseState && child.type === 1 && child.tagType === 0 && isInSameTemplateAsParent(childContext);
|
||
|
|
childContext.templateCloseTags = isInSameTemplate ? childTemplateCloseState.tags : void 0;
|
||
|
|
childContext.templateCloseBlocks = isInSameTemplate ? childTemplateCloseState.blocks : false;
|
||
|
|
transformNode(childContext);
|
||
|
|
const childDynamic = childContext.dynamic;
|
||
|
|
const createsNode = isFragment || childContext.template !== "" || childDynamic.template != null || childDynamic.id !== void 0 || childDynamic.operation !== void 0 || childDynamic.hasDynamicChild === true;
|
||
|
|
if (isFragment) {
|
||
|
|
childContext.reference();
|
||
|
|
childContext.registerTemplate();
|
||
|
|
if (!(childDynamic.flags & 2) || childDynamic.flags & 4) context.block.returns.push(childContext.dynamic.id);
|
||
|
|
} else if (useCreateElement) {
|
||
|
|
if (createsNode) {
|
||
|
|
childContext.reference();
|
||
|
|
childContext.registerTemplate();
|
||
|
|
childDynamic.flags |= 6;
|
||
|
|
}
|
||
|
|
} else context.childrenTemplate.push(childContext.template);
|
||
|
|
if (childDynamic.hasDynamicChild || childDynamic.id !== void 0 || childDynamic.flags & 2 || childDynamic.flags & 4) context.dynamic.hasDynamicChild = true;
|
||
|
|
if (!createsNode) childDynamic.flags |= 2;
|
||
|
|
context.dynamic.children[i] = childDynamic;
|
||
|
|
}
|
||
|
|
if (!isFragment) processDynamicChildren(context, useCreateElement);
|
||
|
|
};
|
||
|
|
function processDynamicChildren(context, useCreateElement) {
|
||
|
|
const children = context.dynamic.children;
|
||
|
|
let lastTemplateIndex = -1;
|
||
|
|
for (let i = children.length - 1; i >= 0; i--) if (!(children[i].flags & 2)) {
|
||
|
|
lastTemplateIndex = i;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
let unitIndex = 0;
|
||
|
|
for (const [index, child] of children.entries()) if (child.flags & 4) {
|
||
|
|
let anchor;
|
||
|
|
if (index < lastTemplateIndex) {
|
||
|
|
context.childrenTemplate[index] = `<!>`;
|
||
|
|
child.flags = child.flags - 2 | 1;
|
||
|
|
anchor = child.anchor = context.increaseId();
|
||
|
|
}
|
||
|
|
if (child.template != null) child.operation = {
|
||
|
|
type: 10,
|
||
|
|
elements: [child.id],
|
||
|
|
parent: context.reference(),
|
||
|
|
anchor,
|
||
|
|
appendIndex: useCreateElement ? unitIndex : void 0
|
||
|
|
};
|
||
|
|
else if (child.operation && isBlockOperation(child.operation)) {
|
||
|
|
child.operation.parent = context.reference();
|
||
|
|
if (anchor !== void 0) child.operation.anchor = anchor;
|
||
|
|
else child.operation.appendIndex = unitIndex;
|
||
|
|
}
|
||
|
|
unitIndex++;
|
||
|
|
} else if (!(child.flags & 2)) unitIndex++;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/vOnce.ts
|
||
|
|
const transformVOnce = (node, context) => {
|
||
|
|
if (node.type === 1 && (0, _vue_compiler_dom.findDir)(node, "once", true)) context.inVOnce = true;
|
||
|
|
};
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/transformText.ts
|
||
|
|
const seen = /* @__PURE__ */ new WeakMap();
|
||
|
|
function markNonTemplate(node, context) {
|
||
|
|
let seenNodes = seen.get(context.root);
|
||
|
|
if (!seenNodes) {
|
||
|
|
seenNodes = /* @__PURE__ */ new WeakSet();
|
||
|
|
seen.set(context.root, seenNodes);
|
||
|
|
}
|
||
|
|
seenNodes.add(node);
|
||
|
|
}
|
||
|
|
const transformText = (node, context) => {
|
||
|
|
if (!seen.has(context.root)) seen.set(context.root, /* @__PURE__ */ new WeakSet());
|
||
|
|
if (seen.get(context.root).has(node)) {
|
||
|
|
context.dynamic.flags |= 2;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const isFragment = node.type === 0 || node.type === 1 && (node.tagType === 3 || node.tagType === 1);
|
||
|
|
if ((isFragment || node.type === 1 && node.tagType === 0) && node.children.length) {
|
||
|
|
let hasInterp = false;
|
||
|
|
let isAllTextLike = true;
|
||
|
|
for (const c of node.children) if (c.type === 5) hasInterp = true;
|
||
|
|
else if (c.type !== 2) isAllTextLike = false;
|
||
|
|
if (!isFragment && isAllTextLike && hasInterp) {
|
||
|
|
const elementContext = context;
|
||
|
|
if (shouldUseCreateElement(node, elementContext)) processCreateElementTextContainer(node.children, elementContext);
|
||
|
|
else processTextContainer(node.children, elementContext);
|
||
|
|
} else if (hasInterp) for (let i = 0; i < node.children.length; i++) {
|
||
|
|
const c = node.children[i];
|
||
|
|
const prev = node.children[i - 1];
|
||
|
|
if (c.type === 5 && prev && prev.type === 2) markNonTemplate(prev, context);
|
||
|
|
}
|
||
|
|
} else if (node.type === 5) processInterpolation(context);
|
||
|
|
else if (node.type === 2) {
|
||
|
|
var _context$parent;
|
||
|
|
const parent = (_context$parent = context.parent) === null || _context$parent === void 0 ? void 0 : _context$parent.node;
|
||
|
|
const createElementParent = parent && parent.type === 1 && shouldUseCreateElement(parent, context.parent);
|
||
|
|
const isRootText = !parent || parent.type === 0 || parent.type === 1 && (parent.tagType === 3 || parent.tagType === 1);
|
||
|
|
const isRawText = createElementParent || isRootText;
|
||
|
|
if (isRawText && node.content[0] === "<") {
|
||
|
|
materializeLiteralTextNode((0, _vue_compiler_dom.createSimpleExpression)(node.content, true, node.loc), context);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
context.template += isRawText ? node.content : (0, _vue_shared.escapeHtml)(node.content);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
function processInterpolation(context) {
|
||
|
|
const parentNode = context.parent.node;
|
||
|
|
const values = processTextLikeChildren(collectAdjacentText(context), context);
|
||
|
|
if (values.length === 0 && parentNode.type !== 0) return;
|
||
|
|
const literalValues = values.map((v) => getLiteralExpressionValue(v));
|
||
|
|
const text = literalValues.every((v) => v != null) ? literalValues.join("") : null;
|
||
|
|
const isElementChild = parentNode.type === 1 && parentNode.tagType === 0;
|
||
|
|
if (text !== null && parentNode.type !== 0 && (isElementChild || text !== "")) {
|
||
|
|
const isRawText = !isElementChild || parentNode.type === 1 && shouldUseCreateElement(parentNode, context.parent);
|
||
|
|
if (isRawText && text[0] === "<") {
|
||
|
|
materializeLiteralTextNode((0, _vue_compiler_dom.createSimpleExpression)(text, true, context.node.loc), context);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
context.template += isRawText ? text : (0, _vue_shared.escapeHtml)(text);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
context.template += " ";
|
||
|
|
const id = context.reference();
|
||
|
|
context.dynamic.isText = isElementChild;
|
||
|
|
if (values.length === 0) return;
|
||
|
|
context.registerEffect(values, {
|
||
|
|
type: 5,
|
||
|
|
element: id,
|
||
|
|
values
|
||
|
|
});
|
||
|
|
}
|
||
|
|
function collectAdjacentText(context) {
|
||
|
|
const children = context.parent.node.children;
|
||
|
|
const nodes = [];
|
||
|
|
const prev = children[context.index - 1];
|
||
|
|
let index = prev && prev.type === 2 ? context.index - 1 : context.index;
|
||
|
|
for (; index < children.length; index++) {
|
||
|
|
const child = children[index];
|
||
|
|
if (!isTextLike(child)) break;
|
||
|
|
nodes.push(child);
|
||
|
|
}
|
||
|
|
return nodes;
|
||
|
|
}
|
||
|
|
function processTextContainer(children, context) {
|
||
|
|
const values = processTextLikeChildren(children, context);
|
||
|
|
const literals = values.map((value) => getLiteralExpressionValue(value));
|
||
|
|
if (literals.every((l) => l != null)) context.childrenTemplate = literals.map((l) => (0, _vue_shared.escapeHtml)(String(l)));
|
||
|
|
else {
|
||
|
|
context.childrenTemplate = [" "];
|
||
|
|
context.registerOperation({
|
||
|
|
type: 17,
|
||
|
|
parent: context.reference()
|
||
|
|
});
|
||
|
|
context.registerEffect(values, {
|
||
|
|
type: 5,
|
||
|
|
element: context.reference(),
|
||
|
|
values,
|
||
|
|
generated: true
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function registerSyntheticTextChild(context, template, values) {
|
||
|
|
const id = context.increaseId();
|
||
|
|
context.dynamic.children[context.node.children.length] = {
|
||
|
|
id,
|
||
|
|
flags: 6,
|
||
|
|
children: [],
|
||
|
|
template: context.pushTemplate(template)
|
||
|
|
};
|
||
|
|
context.dynamic.hasDynamicChild = true;
|
||
|
|
if (values && values.length) context.registerEffect(values, {
|
||
|
|
type: 5,
|
||
|
|
element: id,
|
||
|
|
values
|
||
|
|
});
|
||
|
|
return id;
|
||
|
|
}
|
||
|
|
function processCreateElementTextContainer(children, context) {
|
||
|
|
registerSyntheticTextChild(context, "", processTextLikeChildren(children, context));
|
||
|
|
}
|
||
|
|
function materializeLiteralTextNode(value, context) {
|
||
|
|
const id = context.reference();
|
||
|
|
context.dynamic.flags |= 6;
|
||
|
|
context.dynamic.template = context.pushTemplate("");
|
||
|
|
context.registerEffect([value], {
|
||
|
|
type: 5,
|
||
|
|
element: id,
|
||
|
|
values: [value]
|
||
|
|
});
|
||
|
|
}
|
||
|
|
function processTextLikeChildren(nodes, context) {
|
||
|
|
const exps = [];
|
||
|
|
for (const node of nodes) {
|
||
|
|
let exp;
|
||
|
|
markNonTemplate(node, context);
|
||
|
|
if (node.type === 2) exp = (0, _vue_compiler_dom.createSimpleExpression)(node.content, true, node.loc);
|
||
|
|
else exp = node.content;
|
||
|
|
if (exp.content) exps.push(exp);
|
||
|
|
}
|
||
|
|
return exps;
|
||
|
|
}
|
||
|
|
function isTextLike(node) {
|
||
|
|
return node.type === 5 || node.type === 2;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/vText.ts
|
||
|
|
const isRawTextContainer = /*@__PURE__*/ (0, _vue_shared.makeMap)("iframe,noembed,noframes,noscript,script,style,xmp");
|
||
|
|
const transformVText = (dir, node, context) => {
|
||
|
|
let { exp, loc } = dir;
|
||
|
|
if (!exp) {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createDOMCompilerError)(56, loc));
|
||
|
|
exp = EMPTY_EXPRESSION;
|
||
|
|
}
|
||
|
|
if (node.children.length) {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createDOMCompilerError)(57, loc));
|
||
|
|
context.childrenTemplate.length = 0;
|
||
|
|
for (const child of node.children) markNonTemplate(child, context);
|
||
|
|
}
|
||
|
|
if ((0, _vue_shared.isVoidTag)(context.node.tag)) return;
|
||
|
|
if (node.tagType === 1) return {
|
||
|
|
key: (0, _vue_compiler_dom.createSimpleExpression)("textContent", true),
|
||
|
|
value: exp,
|
||
|
|
toDisplayString: !isConstantVTextExpression(exp, context.options.bindingMetadata)
|
||
|
|
};
|
||
|
|
const literal = getLiteralExpressionValue(exp);
|
||
|
|
const useCreateElement = shouldUseCreateElement(context.node, context);
|
||
|
|
if (literal != null) {
|
||
|
|
if (useCreateElement || isRawTextContainer(node.tag)) {
|
||
|
|
const id = registerSyntheticTextChild(context, "", [exp]);
|
||
|
|
context.registerOperation({
|
||
|
|
type: 10,
|
||
|
|
elements: [id],
|
||
|
|
parent: context.reference()
|
||
|
|
});
|
||
|
|
} else context.childrenTemplate = [(0, _vue_shared.escapeHtml)(literal)];
|
||
|
|
} else {
|
||
|
|
let id;
|
||
|
|
if (useCreateElement) {
|
||
|
|
id = registerSyntheticTextChild(context, "");
|
||
|
|
context.registerOperation({
|
||
|
|
type: 10,
|
||
|
|
elements: [id],
|
||
|
|
parent: context.reference()
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
context.childrenTemplate = [" "];
|
||
|
|
context.registerOperation({
|
||
|
|
type: 17,
|
||
|
|
parent: context.reference()
|
||
|
|
});
|
||
|
|
}
|
||
|
|
context.registerEffect([exp], {
|
||
|
|
type: 5,
|
||
|
|
element: useCreateElement ? id : context.reference(),
|
||
|
|
values: [exp],
|
||
|
|
generated: !useCreateElement
|
||
|
|
});
|
||
|
|
}
|
||
|
|
};
|
||
|
|
function isConstantVTextExpression(exp, bindings) {
|
||
|
|
if (isConstantExpression(exp)) return true;
|
||
|
|
if (exp.ast === null) {
|
||
|
|
const type = bindings[exp.content];
|
||
|
|
return type === "setup-const" || type === "literal-const";
|
||
|
|
}
|
||
|
|
if (!exp.ast) return false;
|
||
|
|
let isConstant = true;
|
||
|
|
(0, _vue_compiler_dom.walkIdentifiers)(exp.ast, (id, parent, _parentStack, isReferenced) => {
|
||
|
|
if (parent && (0, _vue_compiler_dom.isStaticPropertyKey)(id, parent)) return;
|
||
|
|
if (isReferenced && !(0, _vue_shared.isGloballyAllowed)(id.name) && id.name !== "require" || (parent === null || parent === void 0 ? void 0 : parent.type) === "CallExpression" || (parent === null || parent === void 0 ? void 0 : parent.type) === "NewExpression" || (parent === null || parent === void 0 ? void 0 : parent.type) === "MemberExpression") isConstant = false;
|
||
|
|
}, true);
|
||
|
|
return isConstant;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/vOn.ts
|
||
|
|
const delegatedEvents = /*#__PURE__*/ (0, _vue_shared.makeMap)("beforeinput,click,dblclick,contextmenu,focusin,focusout,input,keydown,keyup,mousedown,mousemove,mouseout,mouseover,mouseup,pointerdown,pointermove,pointerout,pointerover,pointerup,touchend,touchmove,touchstart");
|
||
|
|
const transformVOn = (dir, node, context) => {
|
||
|
|
let { arg, exp, loc, modifiers } = dir;
|
||
|
|
const isComponent = node.tagType === 1;
|
||
|
|
const isSlotOutlet = node.tag === "slot";
|
||
|
|
if (!exp && !modifiers.length) context.options.onError((0, _vue_compiler_dom.createCompilerError)(35, loc));
|
||
|
|
let delegateModifier;
|
||
|
|
let nonDelegateModifiers;
|
||
|
|
for (let i = 0; i < modifiers.length; i++) {
|
||
|
|
const modifier = modifiers[i];
|
||
|
|
if (modifier.content === "delegate") {
|
||
|
|
delegateModifier || (delegateModifier = modifier);
|
||
|
|
nonDelegateModifiers || (nonDelegateModifiers = modifiers.slice(0, i));
|
||
|
|
} else if (nonDelegateModifiers) nonDelegateModifiers.push(modifier);
|
||
|
|
}
|
||
|
|
if (nonDelegateModifiers) modifiers = nonDelegateModifiers;
|
||
|
|
arg = resolveExpression(arg);
|
||
|
|
if (arg.isStatic && arg.content.startsWith("vue:")) arg = (0, _vue_shared.extend)({}, arg, { content: `vnode-${arg.content.slice(4)}` });
|
||
|
|
const { keyModifiers, nonKeyModifiers, eventOptionModifiers } = (0, _vue_compiler_dom.resolveModifiers)(arg.isStatic ? `on${arg.content}` : arg, modifiers, null, loc);
|
||
|
|
let keyOverride;
|
||
|
|
const isStaticClick = arg.isStatic && arg.content.toLowerCase() === "click";
|
||
|
|
if (nonKeyModifiers.includes("right")) {
|
||
|
|
if (!isStaticClick && !arg.isStatic) keyOverride = ["click", "contextmenu"];
|
||
|
|
} else if (nonKeyModifiers.includes("middle")) {
|
||
|
|
if (!isStaticClick && !arg.isStatic) keyOverride = ["click", "mouseup"];
|
||
|
|
}
|
||
|
|
arg = normalizeStaticEventArg(arg, nonKeyModifiers);
|
||
|
|
if (keyModifiers.length && (0, _vue_compiler_dom.isStaticExp)(arg) && !(0, _vue_compiler_dom.isKeyboardEvent)(`on${arg.content.toLowerCase()}`)) keyModifiers.length = 0;
|
||
|
|
if (isComponent || isSlotOutlet || !delegateModifier && arg.isStatic && mergesListeners(node, context)) {
|
||
|
|
if (delegateModifier) warnDelegate(context, delegateModifier, ".delegate modifier is only supported on native DOM elements. The modifier will be ignored.");
|
||
|
|
return {
|
||
|
|
key: arg,
|
||
|
|
value: exp || EMPTY_EXPRESSION,
|
||
|
|
handler: true,
|
||
|
|
handlerModifiers: {
|
||
|
|
keys: keyModifiers,
|
||
|
|
nonKeys: nonKeyModifiers,
|
||
|
|
options: eventOptionModifiers
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
const isDelegatableEvent = !!delegateModifier && arg.isStatic && delegatedEvents(arg.content);
|
||
|
|
const hasStopHandler = isDelegatableEvent && !eventOptionModifiers.length && hasStopHandlerForStaticEvent(node, arg.content);
|
||
|
|
if (delegateModifier && !arg.isStatic) warnDelegate(context, delegateModifier, ".delegate modifier requires a static event name. The listener will be attached directly.");
|
||
|
|
else if (delegateModifier && !isDelegatableEvent) warnDelegate(context, delegateModifier, `.delegate modifier is not supported on the "${arg.content}" event. The listener will be attached directly.`);
|
||
|
|
const delegate = isDelegatableEvent && !eventOptionModifiers.length && !hasStopHandler;
|
||
|
|
const operation = {
|
||
|
|
type: 6,
|
||
|
|
element: context.reference(),
|
||
|
|
key: arg,
|
||
|
|
value: exp,
|
||
|
|
modifiers: {
|
||
|
|
keys: keyModifiers,
|
||
|
|
nonKeys: nonKeyModifiers,
|
||
|
|
options: eventOptionModifiers
|
||
|
|
},
|
||
|
|
keyOverride,
|
||
|
|
delegate,
|
||
|
|
effect: !arg.isStatic
|
||
|
|
};
|
||
|
|
context.registerEffect([arg], operation);
|
||
|
|
};
|
||
|
|
function normalizeStaticEventArg(arg, nonKeyModifiers) {
|
||
|
|
if (!arg.isStatic) return arg;
|
||
|
|
let normalized = arg;
|
||
|
|
const isStaticClick = arg.content.toLowerCase() === "click";
|
||
|
|
if (nonKeyModifiers.includes("right") && isStaticClick) normalized = (0, _vue_shared.extend)({}, normalized, { content: "contextmenu" });
|
||
|
|
else if (nonKeyModifiers.includes("middle") && isStaticClick) normalized = (0, _vue_shared.extend)({}, normalized, { content: "mouseup" });
|
||
|
|
return normalized;
|
||
|
|
}
|
||
|
|
function hasStopHandlerForStaticEvent(node, eventName) {
|
||
|
|
return node.props.some((prop) => {
|
||
|
|
if (prop.type !== 7 || prop.name !== "on" || !prop.arg || prop.arg.type !== 4) return false;
|
||
|
|
const arg = resolveExpression(prop.arg);
|
||
|
|
if (!arg.isStatic) return false;
|
||
|
|
const { nonKeyModifiers } = (0, _vue_compiler_dom.resolveModifiers)(`on${arg.content}`, prop.modifiers, null, prop.loc);
|
||
|
|
return nonKeyModifiers.includes("stop") && normalizeStaticEventArg(arg, nonKeyModifiers).content === eventName;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
function warnDelegate(context, modifier, message) {
|
||
|
|
const error = new SyntaxError(message);
|
||
|
|
error.loc = modifier.loc;
|
||
|
|
context.options.onWarn(error);
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/vShow.ts
|
||
|
|
const transformVShow = (dir, node, context) => {
|
||
|
|
const { exp, loc } = dir;
|
||
|
|
if (!exp) {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createDOMCompilerError)(62, loc));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (node.tagType === 2) {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createCompilerError)(36, loc));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
context.registerOperation({
|
||
|
|
type: 13,
|
||
|
|
element: context.reference(),
|
||
|
|
dir,
|
||
|
|
name: "show",
|
||
|
|
builtin: true,
|
||
|
|
once: context.inVOnce
|
||
|
|
});
|
||
|
|
};
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/transformTemplateRef.ts
|
||
|
|
const transformTemplateRef = (node, context) => {
|
||
|
|
if (node.type !== 1) return;
|
||
|
|
const dir = findProp$1(node, "ref", false, true);
|
||
|
|
if (!dir) return;
|
||
|
|
context.ir.hasTemplateRef = true;
|
||
|
|
let value;
|
||
|
|
if (dir.type === 7) value = dir.exp || normalizeBindShorthand(dir.arg, context);
|
||
|
|
else value = dir.value ? (0, _vue_compiler_dom.createSimpleExpression)(dir.value.content, true, dir.value.loc) : EMPTY_EXPRESSION;
|
||
|
|
return () => {
|
||
|
|
const id = context.reference();
|
||
|
|
const effect = !isConstantExpression(value);
|
||
|
|
context.registerEffect([value], {
|
||
|
|
type: 9,
|
||
|
|
element: id,
|
||
|
|
value,
|
||
|
|
refFor: !!context.inVFor,
|
||
|
|
effect
|
||
|
|
});
|
||
|
|
};
|
||
|
|
};
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/vModel.ts
|
||
|
|
const transformVModel = (dir, node, context) => {
|
||
|
|
const { exp, arg } = dir;
|
||
|
|
if (!exp) {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createCompilerError)(41, dir.loc));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const rawExp = exp.loc.source;
|
||
|
|
const bindingType = context.options.bindingMetadata[rawExp];
|
||
|
|
if (bindingType === "props" || bindingType === "props-aliased") {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createCompilerError)(44, exp.loc));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const expString = exp.content;
|
||
|
|
const maybeRef = context.options.inline && (bindingType === "setup-let" || bindingType === "setup-ref" || bindingType === "setup-maybe-ref");
|
||
|
|
if (!expString.trim() || !(0, _vue_compiler_dom.isMemberExpression)(exp, context.options) && !maybeRef) {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createCompilerError)(42, exp.loc));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (node.tagType === 1) return {
|
||
|
|
key: arg ? arg : (0, _vue_compiler_dom.createSimpleExpression)("modelValue", true),
|
||
|
|
value: exp,
|
||
|
|
model: true,
|
||
|
|
modelModifiers: dir.modifiers.map((m) => m.content)
|
||
|
|
};
|
||
|
|
if (dir.arg) context.options.onError((0, _vue_compiler_dom.createDOMCompilerError)(59, dir.arg.loc));
|
||
|
|
const { tag } = node;
|
||
|
|
const isCustomElement = context.options.isCustomElement(tag);
|
||
|
|
let modelType = "text";
|
||
|
|
if (tag === "input" || tag === "textarea" || tag === "select" || isCustomElement) {
|
||
|
|
if (tag === "input" || isCustomElement) {
|
||
|
|
const type = (0, _vue_compiler_dom.findProp)(node, "type");
|
||
|
|
if (type) {
|
||
|
|
if (type.type === 7) modelType = "dynamic";
|
||
|
|
else if (type.value) switch (type.value.content) {
|
||
|
|
case "radio":
|
||
|
|
modelType = "radio";
|
||
|
|
break;
|
||
|
|
case "checkbox":
|
||
|
|
modelType = "checkbox";
|
||
|
|
break;
|
||
|
|
case "file":
|
||
|
|
modelType = void 0;
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createDOMCompilerError)(60, dir.loc));
|
||
|
|
break;
|
||
|
|
default: checkDuplicatedValue();
|
||
|
|
}
|
||
|
|
} else if ((0, _vue_compiler_dom.hasDynamicKeyVBind)(node)) modelType = "dynamic";
|
||
|
|
else checkDuplicatedValue();
|
||
|
|
} else if (tag === "select") modelType = "select";
|
||
|
|
else checkDuplicatedValue();
|
||
|
|
} else context.options.onError((0, _vue_compiler_dom.createDOMCompilerError)(58, dir.loc));
|
||
|
|
if (modelType) context.registerOperation({
|
||
|
|
type: 13,
|
||
|
|
element: context.reference(),
|
||
|
|
dir,
|
||
|
|
name: "model",
|
||
|
|
modelType,
|
||
|
|
builtin: true,
|
||
|
|
once: context.inVOnce
|
||
|
|
});
|
||
|
|
function checkDuplicatedValue() {
|
||
|
|
const value = (0, _vue_compiler_dom.findDir)(node, "bind");
|
||
|
|
if (value && (0, _vue_compiler_dom.isStaticArgOf)(value.arg, "value")) context.options.onError((0, _vue_compiler_dom.createDOMCompilerError)(61, value.loc));
|
||
|
|
}
|
||
|
|
};
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/transformComment.ts
|
||
|
|
const ignoredComments = /* @__PURE__ */ new WeakMap();
|
||
|
|
function ignoreComment(node, context) {
|
||
|
|
let ignored = ignoredComments.get(context.root);
|
||
|
|
if (!ignored) ignoredComments.set(context.root, ignored = /* @__PURE__ */ new WeakSet());
|
||
|
|
ignored.add(node);
|
||
|
|
}
|
||
|
|
const transformComment = (node, context) => {
|
||
|
|
var _ignoredComments$get;
|
||
|
|
if (node.type !== 3) return;
|
||
|
|
if ((_ignoredComments$get = ignoredComments.get(context.root)) === null || _ignoredComments$get === void 0 ? void 0 : _ignoredComments$get.has(node)) context.dynamic.flags |= 2;
|
||
|
|
else if (getSiblingIf(context)) {
|
||
|
|
context.comment.push(node);
|
||
|
|
context.dynamic.flags |= 2;
|
||
|
|
} else context.template += `<!--${node.content}-->`;
|
||
|
|
};
|
||
|
|
function getSiblingIf(context, reverse) {
|
||
|
|
const parent = context.parent;
|
||
|
|
if (!parent) return;
|
||
|
|
const siblings = parent.node.children;
|
||
|
|
let sibling;
|
||
|
|
let i = siblings.indexOf(context.node);
|
||
|
|
while (reverse ? --i >= 0 : ++i < siblings.length) {
|
||
|
|
sibling = siblings[i];
|
||
|
|
if (!(0, _vue_compiler_dom.isCommentOrWhitespace)(sibling)) break;
|
||
|
|
}
|
||
|
|
if (sibling && sibling.type === 1 && sibling.props.some(({ type, name }) => type === 7 && ["else-if", reverse ? "if" : "else"].includes(name))) return sibling;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/vIf.ts
|
||
|
|
const transformVIf = createStructuralDirectiveTransform([
|
||
|
|
"if",
|
||
|
|
"else",
|
||
|
|
"else-if"
|
||
|
|
], processIf);
|
||
|
|
function processIf(node, dir, context) {
|
||
|
|
if (dir.name !== "else" && (!dir.exp || !dir.exp.content.trim())) {
|
||
|
|
const loc = dir.exp ? dir.exp.loc : node.loc;
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createCompilerError)(28, dir.loc));
|
||
|
|
dir.exp = (0, _vue_compiler_dom.createSimpleExpression)(`true`, false, loc);
|
||
|
|
}
|
||
|
|
context.dynamic.flags |= 2;
|
||
|
|
const forceMultiRoot = shouldForceMultiRoot(context);
|
||
|
|
const allowNoScope = context.block === context.root.block;
|
||
|
|
if (dir.name === "if") {
|
||
|
|
const id = context.reference();
|
||
|
|
context.dynamic.flags |= 4;
|
||
|
|
const [branch, onExit] = createIfBranch(node, context);
|
||
|
|
return () => {
|
||
|
|
onExit();
|
||
|
|
context.dynamic.operation = {
|
||
|
|
type: 14,
|
||
|
|
id,
|
||
|
|
...context.effectBoundary(),
|
||
|
|
blockShape: encodeIfBlockShape(branch, forceMultiRoot, void 0, allowNoScope),
|
||
|
|
condition: dir.exp,
|
||
|
|
positive: branch,
|
||
|
|
index: context.root.nextIfIndex(),
|
||
|
|
once: context.inVOnce || isStaticExpression(dir.exp, context.options.bindingMetadata)
|
||
|
|
};
|
||
|
|
};
|
||
|
|
} else {
|
||
|
|
const siblingIf = getSiblingIf(context, true);
|
||
|
|
const siblings = context.parent && context.parent.dynamic.children;
|
||
|
|
let lastIfNode;
|
||
|
|
if (siblings) {
|
||
|
|
let i = siblings.length;
|
||
|
|
while (i--) if (siblings[i].operation && siblings[i].operation.type === 14) {
|
||
|
|
lastIfNode = siblings[i].operation;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!siblingIf || !lastIfNode || lastIfNode.type !== 14) {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createCompilerError)(30, node.loc));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
while (lastIfNode.negative && lastIfNode.negative.type === 14) lastIfNode = lastIfNode.negative;
|
||
|
|
if (dir.name === "else-if" && lastIfNode.negative) context.options.onError((0, _vue_compiler_dom.createCompilerError)(30, node.loc));
|
||
|
|
checkSameKey(node, context);
|
||
|
|
const comments = context.comment;
|
||
|
|
if (comments.length) {
|
||
|
|
if (!isInTransition(context)) {
|
||
|
|
node = wrapTemplate(node, ["else-if", "else"]);
|
||
|
|
context.node = node = (0, _vue_shared.extend)({}, node, { children: [...comments, ...node.children] });
|
||
|
|
}
|
||
|
|
comments.length = 0;
|
||
|
|
}
|
||
|
|
const [branch, onExit] = createIfBranch(node, context);
|
||
|
|
if (dir.name === "else") lastIfNode.negative = branch;
|
||
|
|
else lastIfNode.negative = {
|
||
|
|
type: 14,
|
||
|
|
id: -1,
|
||
|
|
condition: dir.exp,
|
||
|
|
positive: branch,
|
||
|
|
index: context.root.nextIfIndex(),
|
||
|
|
blockShape: 0,
|
||
|
|
once: context.inVOnce || isStaticExpression(dir.exp, context.options.bindingMetadata)
|
||
|
|
};
|
||
|
|
return () => {
|
||
|
|
onExit();
|
||
|
|
if (lastIfNode.negative.type === 14) lastIfNode.negative.blockShape = encodeIfBlockShape(lastIfNode.negative.positive, forceMultiRoot, void 0, allowNoScope);
|
||
|
|
lastIfNode.blockShape = encodeIfBlockShape(lastIfNode.positive, forceMultiRoot, lastIfNode.negative, allowNoScope);
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function createIfBranch(node, context) {
|
||
|
|
context.node = node = wrapTemplate(node, [
|
||
|
|
"if",
|
||
|
|
"else-if",
|
||
|
|
"else"
|
||
|
|
]);
|
||
|
|
const branch = newBlock(node);
|
||
|
|
const exitBlock = context.enterBlock(branch);
|
||
|
|
context.reference();
|
||
|
|
return [branch, exitBlock];
|
||
|
|
}
|
||
|
|
function encodeIfBlockShape(positive, forceMultiRoot = false, negative, allowNoScope = true) {
|
||
|
|
if (forceMultiRoot) return 10;
|
||
|
|
const positiveNoScope = allowNoScope && canSkipIfBranchScope(positive);
|
||
|
|
const negativeNoScope = allowNoScope && negative && negative.type !== 14 && canSkipIfBranchScope(negative);
|
||
|
|
return getBlockShape(positive) | getNegativeIfBranchShape(negative) << 2 | (positiveNoScope ? 32 : 0) | (negativeNoScope ? 64 : 0);
|
||
|
|
}
|
||
|
|
function getNegativeIfBranchShape(negative) {
|
||
|
|
if (!negative) return 0;
|
||
|
|
return negative.type === 14 ? 1 : getBlockShape(negative);
|
||
|
|
}
|
||
|
|
function canSkipIfBranchScope(block) {
|
||
|
|
if (block.effect.length || block.operation.length) return false;
|
||
|
|
if (!isStaticBranch(block.node)) return false;
|
||
|
|
if (block.returns.length === 0 || block.dynamic.children.length !== block.returns.length) return false;
|
||
|
|
return block.returns.every((id) => {
|
||
|
|
const returned = findReturnedDynamic(block, id);
|
||
|
|
return !!(returned && returned.template != null && !returned.operation && !returned.hasDynamicChild && !(returned.flags & 6));
|
||
|
|
});
|
||
|
|
}
|
||
|
|
function findReturnedDynamic(block, id) {
|
||
|
|
return block.dynamic.children.find((child) => child.id === id);
|
||
|
|
}
|
||
|
|
function isStaticBranch(node) {
|
||
|
|
if (node.type !== 1 || node.tagType !== 3 || node.children.length === 0) return false;
|
||
|
|
return node.children.every((child) => isStaticTemplateNode(child));
|
||
|
|
}
|
||
|
|
function isStaticTemplateNode(node) {
|
||
|
|
if (node.type === 2 || node.type === 3) return true;
|
||
|
|
if (node.type !== 1 || node.tagType !== 0) return false;
|
||
|
|
for (const prop of node.props) if (prop.type === 7 || prop.name === "ref") return false;
|
||
|
|
return node.children.every((child) => isStaticTemplateNode(child));
|
||
|
|
}
|
||
|
|
function shouldForceMultiRoot(context) {
|
||
|
|
const parent = context.parent && context.parent.node;
|
||
|
|
return !!parent && parent.type === 1 && parent.tagType === 3 && parent.props.some((prop) => prop.type === 7 && prop.name === "for");
|
||
|
|
}
|
||
|
|
function checkSameKey(node, context) {
|
||
|
|
const key = findProp$1(node, "key");
|
||
|
|
const parent = context.parent;
|
||
|
|
if (!key || !parent) return;
|
||
|
|
const siblings = parent.node.children;
|
||
|
|
let i = siblings.indexOf(node);
|
||
|
|
while (i > 0) {
|
||
|
|
const sibling = siblings[--i];
|
||
|
|
if ((0, _vue_compiler_dom.isCommentOrWhitespace)(sibling)) continue;
|
||
|
|
if (sibling.type !== 1) return;
|
||
|
|
const dir = sibling.props.find((prop) => prop.type === 7 && (prop.name === "if" || prop.name === "else-if"));
|
||
|
|
if (!dir) return;
|
||
|
|
if (isSameKey(findProp$1(sibling, "key"), key)) context.options.onError((0, _vue_compiler_dom.createCompilerError)(29, key.loc));
|
||
|
|
if (dir.name === "if") return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function isSameKey(a, b) {
|
||
|
|
if (!a || a.type !== b.type) return false;
|
||
|
|
if (a.type === 6) {
|
||
|
|
if (a.value.content !== b.value.content) return false;
|
||
|
|
} else {
|
||
|
|
const exp = a.exp;
|
||
|
|
const branchExp = b.exp;
|
||
|
|
if (exp.type !== branchExp.type) return false;
|
||
|
|
if (exp.type !== 4 || exp.isStatic !== branchExp.isStatic || exp.content !== branchExp.content) return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/vFor.ts
|
||
|
|
const transformVFor = createStructuralDirectiveTransform("for", processFor);
|
||
|
|
function processFor(node, dir, context) {
|
||
|
|
if (!dir.exp) {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createCompilerError)(31, dir.loc));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const parseResult = dir.forParseResult;
|
||
|
|
if (!parseResult) {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createCompilerError)(32, dir.loc));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const { source, value, key, index } = parseResult;
|
||
|
|
const keyProp = findProp$1(node, "key", false, true);
|
||
|
|
const keyProperty = keyProp && (keyProp.type === 6 ? keyProp.value && propToExpression(keyProp) : keyProp.exp || normalizeBindShorthand(keyProp.arg, context));
|
||
|
|
const isComponent = node.tagType === 1 || isTemplateWithSingleComponent(node);
|
||
|
|
const wrappedRows = node.tagType === 3 && !isInTransition(context) && (node.children.length !== 1 || node.children[0].type !== 1 || !!findDir$5(node.children[0], ROW_FRAGMENT_DIR_RE));
|
||
|
|
context.node = node = wrapTemplate(node, ["for", "key"]);
|
||
|
|
context.dynamic.flags |= 6;
|
||
|
|
const id = context.reference();
|
||
|
|
const render = newBlock(node);
|
||
|
|
const exitBlock = context.enterBlock(render, true);
|
||
|
|
context.reference();
|
||
|
|
return () => {
|
||
|
|
exitBlock();
|
||
|
|
const { parent } = context;
|
||
|
|
const isOnlyChild = parent && parent.block.node !== parent.node && parent.node.children.length === 1;
|
||
|
|
context.dynamic.operation = {
|
||
|
|
type: 15,
|
||
|
|
id,
|
||
|
|
...context.effectBoundary(),
|
||
|
|
source,
|
||
|
|
value,
|
||
|
|
key,
|
||
|
|
index,
|
||
|
|
keyProp: keyProperty,
|
||
|
|
render,
|
||
|
|
once: context.inVOnce || isStaticExpression(source, context.options.bindingMetadata),
|
||
|
|
component: isComponent,
|
||
|
|
onlyChild: !!isOnlyChild,
|
||
|
|
wrappedRows
|
||
|
|
};
|
||
|
|
};
|
||
|
|
}
|
||
|
|
const ROW_FRAGMENT_DIR_RE = /^(?:if|for)$/;
|
||
|
|
function isTemplateWithSingleComponent(node) {
|
||
|
|
if (node.tag !== "template") return false;
|
||
|
|
const nonCommentChildren = node.children.filter((c) => c.type !== 3);
|
||
|
|
return nonCommentChildren.length === 1 && nonCommentChildren[0].type === 1 && nonCommentChildren[0].tagType === 1;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/transformSlotOutlet.ts
|
||
|
|
const transformSlotOutlet = (node, context) => {
|
||
|
|
if (node.type !== 1 || node.tag !== "slot") return;
|
||
|
|
const id = context.reference();
|
||
|
|
context.dynamic.flags |= 6;
|
||
|
|
const [fallback, exitBlock] = createFallback(node, context);
|
||
|
|
let slotName;
|
||
|
|
const slotProps = [];
|
||
|
|
for (const prop of node.props) if (prop.type === 6) {
|
||
|
|
if (prop.value) {
|
||
|
|
if (prop.name === "name") slotName = (0, _vue_compiler_dom.createSimpleExpression)(prop.value.content, true, prop.loc);
|
||
|
|
else slotProps.push((0, _vue_shared.extend)({}, prop, { name: (0, _vue_shared.camelize)(prop.name) }));
|
||
|
|
}
|
||
|
|
} else if (prop.name === "bind" && (0, _vue_compiler_dom.isStaticArgOf)(prop.arg, "name")) {
|
||
|
|
if (prop.exp) slotName = prop.exp;
|
||
|
|
else {
|
||
|
|
slotName = (0, _vue_compiler_dom.createSimpleExpression)((0, _vue_shared.camelize)(prop.arg.content), false, prop.arg.loc);
|
||
|
|
slotName.ast = null;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
let slotProp = prop;
|
||
|
|
if (slotProp.name === "bind" && slotProp.arg && (0, _vue_compiler_dom.isStaticExp)(slotProp.arg)) slotProp = (0, _vue_shared.extend)({}, prop, { arg: (0, _vue_shared.extend)({}, slotProp.arg, { content: (0, _vue_shared.camelize)(slotProp.arg.content) }) });
|
||
|
|
slotProps.push(slotProp);
|
||
|
|
}
|
||
|
|
slotName || (slotName = (0, _vue_compiler_dom.createSimpleExpression)("default", true));
|
||
|
|
let irProps = [];
|
||
|
|
if (slotProps.length) {
|
||
|
|
const [isDynamic, props] = buildProps((0, _vue_shared.extend)({}, node, { props: slotProps }), context, true);
|
||
|
|
irProps = isDynamic ? props : [props];
|
||
|
|
}
|
||
|
|
return () => {
|
||
|
|
exitBlock && exitBlock();
|
||
|
|
let flags = 0;
|
||
|
|
if (context.options.scopeId && !context.options.slotted) flags |= 1;
|
||
|
|
if (context.inVOnce) flags |= 2;
|
||
|
|
context.dynamic.operation = {
|
||
|
|
type: 12,
|
||
|
|
id,
|
||
|
|
...context.effectBoundary(),
|
||
|
|
name: slotName,
|
||
|
|
props: irProps,
|
||
|
|
fallback,
|
||
|
|
flags
|
||
|
|
};
|
||
|
|
};
|
||
|
|
};
|
||
|
|
function createFallback(node, context) {
|
||
|
|
if (!node.children.length) return [];
|
||
|
|
context.isSingleRoot = false;
|
||
|
|
context.node = node = (0, _vue_shared.extend)({}, node, {
|
||
|
|
type: 1,
|
||
|
|
tag: "template",
|
||
|
|
props: [],
|
||
|
|
tagType: 3,
|
||
|
|
children: node.children
|
||
|
|
});
|
||
|
|
const fallback = newBlock(node);
|
||
|
|
const exitBlock = context.enterBlock(fallback);
|
||
|
|
context.reference();
|
||
|
|
return [fallback, exitBlock];
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/vSlot.ts
|
||
|
|
const transformVSlot = (node, context) => {
|
||
|
|
if (node.type !== 1) return;
|
||
|
|
const dir = findDir$5(node, "slot", true);
|
||
|
|
const { tagType, children } = node;
|
||
|
|
const { parent } = context;
|
||
|
|
const isComponent = tagType === 1;
|
||
|
|
const isSlotTemplate = (0, _vue_compiler_dom.isTemplateNode)(node) && parent && parent.node.type === 1 && parent.node.tagType === 1;
|
||
|
|
if (isComponent && children.length) return transformComponentSlot(node, dir, context);
|
||
|
|
else if (isSlotTemplate && dir) return transformTemplateSlot(node, dir, context);
|
||
|
|
else if (!isComponent && dir) context.options.onError((0, _vue_compiler_dom.createCompilerError)(40, dir.loc));
|
||
|
|
};
|
||
|
|
function transformComponentSlot(node, dir, context) {
|
||
|
|
const { children } = node;
|
||
|
|
const arg = dir && dir.arg;
|
||
|
|
const hasTemplateSlots = children.some(isSlotTemplateChild);
|
||
|
|
const isTransitionHost = isTransitionHostNode(node);
|
||
|
|
const emptyTextNodes = [];
|
||
|
|
const nonSlotTemplateChildren = children.filter((n) => {
|
||
|
|
if (isSlotTemplateChild(n)) return false;
|
||
|
|
if (n.type === 3 && (hasTemplateSlots || isTransitionHost)) {
|
||
|
|
ignoreComment(n, context);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (isNonWhitespaceContent(n)) return true;
|
||
|
|
else {
|
||
|
|
emptyTextNodes.push(n);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
if (!nonSlotTemplateChildren.length) emptyTextNodes.forEach((n) => {
|
||
|
|
markNonTemplate(n, context);
|
||
|
|
});
|
||
|
|
const [block, onExit] = createSlotBlock(node, dir, context);
|
||
|
|
const { slots } = context;
|
||
|
|
return () => {
|
||
|
|
onExit();
|
||
|
|
const hasOtherSlots = !!slots.length;
|
||
|
|
if (dir && hasOtherSlots) {
|
||
|
|
context.options.onError((0, _vue_compiler_dom.createCompilerError)(37, dir.loc));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (nonSlotTemplateChildren.length) {
|
||
|
|
if (hasStaticSlot(slots, "default")) context.options.onError((0, _vue_compiler_dom.createCompilerError)(39, nonSlotTemplateChildren[0].loc));
|
||
|
|
else {
|
||
|
|
registerSlot(slots, arg, block);
|
||
|
|
context.slots = slots;
|
||
|
|
}
|
||
|
|
} else if (hasOtherSlots) context.slots = slots;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function transformTemplateSlot(node, dir, context) {
|
||
|
|
context.dynamic.flags |= 2;
|
||
|
|
const resolvedArg = dir.arg && resolveExpression(dir.arg);
|
||
|
|
let arg = resolvedArg;
|
||
|
|
if (!arg) arg = (0, _vue_compiler_dom.createSimpleExpression)("default", true);
|
||
|
|
const vFor = findDir$5(node, "for");
|
||
|
|
const vIf = findDir$5(node, "if");
|
||
|
|
const vElse = findDir$5(node, /^else(-if)?$/, true);
|
||
|
|
const { slots } = context;
|
||
|
|
const [block, onExit] = createSlotBlock(node, dir, context);
|
||
|
|
if (!vFor && !vIf && !vElse) {
|
||
|
|
const slotName = resolvedArg ? resolvedArg.isStatic && resolvedArg.content : "default";
|
||
|
|
if (slotName && hasStaticSlot(slots, slotName)) context.options.onError((0, _vue_compiler_dom.createCompilerError)(38, dir.loc));
|
||
|
|
else registerSlot(slots, arg, block);
|
||
|
|
} else if (vIf) registerDynamicSlot(slots, {
|
||
|
|
slotType: 3,
|
||
|
|
condition: vIf.exp,
|
||
|
|
positive: {
|
||
|
|
slotType: 1,
|
||
|
|
name: arg,
|
||
|
|
fn: block
|
||
|
|
}
|
||
|
|
});
|
||
|
|
else if (vElse) {
|
||
|
|
const vIfSlot = slots[slots.length - 1];
|
||
|
|
if (vIfSlot && vIfSlot.slotType === 3) {
|
||
|
|
let ifNode = vIfSlot;
|
||
|
|
while (ifNode.negative && ifNode.negative.slotType === 3) ifNode = ifNode.negative;
|
||
|
|
const negative = vElse.exp ? {
|
||
|
|
slotType: 3,
|
||
|
|
condition: vElse.exp,
|
||
|
|
positive: {
|
||
|
|
slotType: 1,
|
||
|
|
name: arg,
|
||
|
|
fn: block
|
||
|
|
}
|
||
|
|
} : {
|
||
|
|
slotType: 1,
|
||
|
|
name: arg,
|
||
|
|
fn: block
|
||
|
|
};
|
||
|
|
ifNode.negative = negative;
|
||
|
|
} else context.options.onError((0, _vue_compiler_dom.createCompilerError)(30, vElse.loc));
|
||
|
|
} else if (vFor) {
|
||
|
|
if (vFor.forParseResult) {
|
||
|
|
const keyProp = findProp$1(node, "key");
|
||
|
|
registerDynamicSlot(slots, {
|
||
|
|
slotType: 2,
|
||
|
|
name: arg,
|
||
|
|
fn: block,
|
||
|
|
loop: vFor.forParseResult,
|
||
|
|
keyProp: keyProp && propToExpression(keyProp)
|
||
|
|
});
|
||
|
|
} else context.options.onError((0, _vue_compiler_dom.createCompilerError)(32, vFor.loc));
|
||
|
|
}
|
||
|
|
return onExit;
|
||
|
|
}
|
||
|
|
function ensureStaticSlots(slots) {
|
||
|
|
let lastSlots = slots[slots.length - 1];
|
||
|
|
if (!slots.length || lastSlots.slotType !== 0) slots.push(lastSlots = {
|
||
|
|
slotType: 0,
|
||
|
|
slots: {}
|
||
|
|
});
|
||
|
|
return lastSlots.slots;
|
||
|
|
}
|
||
|
|
function registerSlot(slots, name, block) {
|
||
|
|
if (!name || name.isStatic) {
|
||
|
|
const staticSlots = ensureStaticSlots(slots);
|
||
|
|
staticSlots[name ? name.content : "default"] = block;
|
||
|
|
} else slots.push({
|
||
|
|
slotType: 1,
|
||
|
|
name,
|
||
|
|
fn: block
|
||
|
|
});
|
||
|
|
}
|
||
|
|
function registerDynamicSlot(allSlots, dynamic) {
|
||
|
|
allSlots.push(dynamic);
|
||
|
|
}
|
||
|
|
function hasStaticSlot(slots, name) {
|
||
|
|
return slots.some((slot) => {
|
||
|
|
if (slot.slotType === 0) return !!slot.slots[name];
|
||
|
|
});
|
||
|
|
}
|
||
|
|
function createSlotBlock(slotNode, dir, context) {
|
||
|
|
const block = newBlock(slotNode);
|
||
|
|
block.props = dir && dir.exp;
|
||
|
|
return [block, context.enterBlock(block)];
|
||
|
|
}
|
||
|
|
function isNonWhitespaceContent(node) {
|
||
|
|
if (node.type !== 2) return true;
|
||
|
|
return !!node.content.trim();
|
||
|
|
}
|
||
|
|
function isSlotTemplateChild(node) {
|
||
|
|
return node.type === 1 && (0, _vue_compiler_dom.isTemplateNode)(node) && !!findDir$5(node, "slot", true);
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/transforms/transformTransition.ts
|
||
|
|
const transformTransition = (node, context) => {
|
||
|
|
if (node.type === 1 && node.tagType === 1) {
|
||
|
|
if (isTransitionTag(node.tag)) return (0, _vue_compiler_dom.postTransformTransition)(node, context.options.onError, hasMultipleChildren);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
function hasMultipleChildren(node) {
|
||
|
|
const children = node.children = node.children.filter((c) => c.type !== 3 && !(c.type === 2 && !c.content.trim()));
|
||
|
|
const first = children[0];
|
||
|
|
if (children.length === 1 && first.type === 1) {
|
||
|
|
if (findDir$5(first, "for")) return true;
|
||
|
|
if ((0, _vue_compiler_dom.isTemplateNode)(first)) return hasMultipleChildren(first);
|
||
|
|
}
|
||
|
|
const hasElse = (node) => findDir$5(node, "else-if") || findDir$5(node, "else", true);
|
||
|
|
if (children.length > 0 && children.every((c, index) => c.type === 1 && (!(0, _vue_compiler_dom.isTemplateNode)(c) || !hasMultipleChildren(c)) && !findDir$5(c, "for") && (index === 0 ? findDir$5(c, "if") : hasElse(c)))) return false;
|
||
|
|
return children.length !== 1;
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/compile.ts
|
||
|
|
function compile(source, options = {}) {
|
||
|
|
const resolvedOptions = (0, _vue_shared.extend)({}, options);
|
||
|
|
const ast = (0, _vue_shared.isString)(source) ? (0, _vue_compiler_dom.parse)(source, resolvedOptions) : source;
|
||
|
|
const [nodeTransforms, directiveTransforms] = getBaseTransformPreset();
|
||
|
|
if (options.isTS) {
|
||
|
|
const { expressionPlugins } = options;
|
||
|
|
if (!expressionPlugins || !expressionPlugins.includes("typescript")) resolvedOptions.expressionPlugins = [...expressionPlugins || [], "typescript"];
|
||
|
|
}
|
||
|
|
return generate(transform(ast, (0, _vue_shared.extend)({}, resolvedOptions, {
|
||
|
|
nodeTransforms: [
|
||
|
|
...nodeTransforms,
|
||
|
|
...[transformTransition],
|
||
|
|
...options.nodeTransforms || []
|
||
|
|
],
|
||
|
|
directiveTransforms: (0, _vue_shared.extend)({}, directiveTransforms, options.directiveTransforms || {})
|
||
|
|
})), resolvedOptions);
|
||
|
|
}
|
||
|
|
function getBaseTransformPreset() {
|
||
|
|
return [[
|
||
|
|
transformVOnce,
|
||
|
|
transformVIf,
|
||
|
|
transformVFor,
|
||
|
|
transformKey,
|
||
|
|
transformSlotOutlet,
|
||
|
|
transformTemplateRef,
|
||
|
|
transformElement,
|
||
|
|
transformText,
|
||
|
|
transformVSlot,
|
||
|
|
transformComment,
|
||
|
|
transformChildren
|
||
|
|
], {
|
||
|
|
bind: transformVBind,
|
||
|
|
on: transformVOn,
|
||
|
|
html: transformVHtml,
|
||
|
|
text: transformVText,
|
||
|
|
show: transformVShow,
|
||
|
|
model: transformVModel
|
||
|
|
}];
|
||
|
|
}
|
||
|
|
//#endregion
|
||
|
|
//#region packages/compiler-vapor/src/errors.ts
|
||
|
|
function createVaporCompilerError(code, loc) {
|
||
|
|
return (0, _vue_compiler_dom.createCompilerError)(code, loc, VaporErrorMessages);
|
||
|
|
}
|
||
|
|
const VaporErrorCodes = {
|
||
|
|
"X_V_PLACEHOLDER": 100,
|
||
|
|
"100": "X_V_PLACEHOLDER",
|
||
|
|
"__EXTEND_POINT__": 101,
|
||
|
|
"101": "__EXTEND_POINT__"
|
||
|
|
};
|
||
|
|
const VaporErrorMessages = {
|
||
|
|
[100]: `[placeholder]`,
|
||
|
|
[101]: ``
|
||
|
|
};
|
||
|
|
//#endregion
|
||
|
|
exports.CodegenContext = CodegenContext;
|
||
|
|
exports.DynamicFlag = DynamicFlag;
|
||
|
|
exports.IRDynamicPropsKind = IRDynamicPropsKind;
|
||
|
|
exports.IRNodeTypes = IRNodeTypes;
|
||
|
|
exports.IRSlotType = IRSlotType;
|
||
|
|
exports.TemplateRegistry = TemplateRegistry;
|
||
|
|
exports.VaporErrorCodes = VaporErrorCodes;
|
||
|
|
exports.VaporErrorMessages = VaporErrorMessages;
|
||
|
|
exports.buildCodeFragment = buildCodeFragment;
|
||
|
|
exports.codeFragmentToString = codeFragmentToString;
|
||
|
|
exports.compile = compile;
|
||
|
|
exports.createStructuralDirectiveTransform = createStructuralDirectiveTransform;
|
||
|
|
exports.createVaporCompilerError = createVaporCompilerError;
|
||
|
|
exports.genCall = genCall;
|
||
|
|
exports.genMulti = genMulti;
|
||
|
|
exports.generate = generate;
|
||
|
|
exports.isBlockOperation = isBlockOperation;
|
||
|
|
exports.parse = _vue_compiler_dom.parse;
|
||
|
|
exports.transform = transform;
|
||
|
|
exports.transformChildren = transformChildren;
|
||
|
|
exports.transformComment = transformComment;
|
||
|
|
exports.transformElement = transformElement;
|
||
|
|
exports.transformKey = transformKey;
|
||
|
|
exports.transformSlotOutlet = transformSlotOutlet;
|
||
|
|
exports.transformTemplateRef = transformTemplateRef;
|
||
|
|
exports.transformText = transformText;
|
||
|
|
exports.transformVBind = transformVBind;
|
||
|
|
exports.transformVFor = transformVFor;
|
||
|
|
exports.transformVHtml = transformVHtml;
|
||
|
|
exports.transformVIf = transformVIf;
|
||
|
|
exports.transformVModel = transformVModel;
|
||
|
|
exports.transformVOn = transformVOn;
|
||
|
|
exports.transformVOnce = transformVOnce;
|
||
|
|
exports.transformVShow = transformVShow;
|
||
|
|
exports.transformVSlot = transformVSlot;
|
||
|
|
exports.transformVText = transformVText;
|
||
|
|
exports.wrapTemplate = wrapTemplate;
|