@wevu/compiler 6.16.24 → 6.16.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -281,11 +281,13 @@ interface TemplateCompileOptions {
281
281
  */
282
282
  propsAliases?: Record<string, string>;
283
283
  propsDerivedKeys?: string[];
284
+ scriptSetupBindings?: Record<string, unknown>;
284
285
  htmlTagToWxml?: boolean | Record<string, string>;
285
286
  htmlTagToWxmlTagClass?: boolean;
286
287
  scopedSlotsCompiler?: ScopedSlotsCompilerMode;
287
288
  scopedSlotsRequireProps?: boolean;
288
289
  slotSingleRootNoWrapper?: boolean;
290
+ slotFallbackWrapper?: SlotFallbackWrapperConfig;
289
291
  slotMultipleInstance?: boolean;
290
292
  classStyleRuntime?: ClassStyleRuntime | 'auto';
291
293
  objectLiteralBindMode?: ObjectLiteralBindMode;
@@ -295,11 +297,36 @@ interface TemplateCompileOptions {
295
297
  classStyleWxsSrc?: string;
296
298
  functionPropNames?: Iterable<FunctionPropNameMatcher>;
297
299
  wevuComponentTags?: Iterable<string>;
300
+ componentNameMap?: Record<string, string>;
298
301
  }
299
302
  /**
300
303
  * 作用域插槽编译模式。
301
304
  */
302
305
  type ScopedSlotsCompilerMode = 'auto' | 'augmented' | 'off';
306
+ /**
307
+ * 命名插槽 fallback 容器策略匹配器。
308
+ */
309
+ type SlotFallbackWrapperMatcher = string | RegExp | Array<string | RegExp>;
310
+ /**
311
+ * 命名插槽 fallback 容器规则。
312
+ */
313
+ interface SlotFallbackWrapperRule {
314
+ component?: SlotFallbackWrapperMatcher;
315
+ componentName?: SlotFallbackWrapperMatcher;
316
+ slot?: SlotFallbackWrapperMatcher;
317
+ tag?: string;
318
+ attrs?: Record<string, string>;
319
+ singleRootNoWrapper?: boolean;
320
+ }
321
+ /**
322
+ * 命名插槽 fallback 容器配置。
323
+ */
324
+ type SlotFallbackWrapperConfig = string | {
325
+ tag?: string;
326
+ attrs?: Record<string, string>;
327
+ singleRootNoWrapper?: boolean;
328
+ rules?: SlotFallbackWrapperRule[];
329
+ };
303
330
  /**
304
331
  * class/style 运行时模式。
305
332
  */
package/dist/index.mjs CHANGED
@@ -13,7 +13,7 @@ import os from "node:os";
13
13
  import process from "node:process";
14
14
  import { collectFeatureFlagsFromCode, collectJsxImportedComponentsAndDefaultExportFromBabelAst, collectJsxTemplateTagsFromBabelExpression, getRenderPropertyFromComponentOptions, parseJsLikeWithEngine, resolveRenderExpressionFromComponentOptions, toStaticObjectKey, unwrapTypeScriptExpression } from "@weapp-vite/ast";
15
15
  import { LRUCache } from "lru-cache";
16
- import { WEVU_CLASS_STYLE_RUNTIME_FILE, WEVU_CLASS_STYLE_RUNTIME_MODULE, WEVU_EXPRESSION_ERROR_IDENTIFIER, WEVU_FUNCTION_PROP_PATHS_KEY, WEVU_INLINE_HANDLER, WEVU_INLINE_MAP_KEY, WEVU_IS_PAGE_KEY, WEVU_LAYOUT_HOSTS_KEY, WEVU_LAYOUT_HOST_ID_PREFIX, WEVU_LAYOUT_HOST_REF_PREFIX, WEVU_MODEL_HANDLER, WEVU_OWNER_HANDLER, WEVU_PROPS_ALIASES_KEY, WEVU_PROPS_DERIVED_KEYS_KEY, WEVU_PROPS_KEY, WEVU_SLOT_NAMES_ATTR, WEVU_SLOT_NAMES_PROP, WEVU_SLOT_OWNER_ID_ATTR, WEVU_SLOT_OWNER_ID_KEY, WEVU_SLOT_OWNER_ID_PROP, WEVU_SLOT_OWNER_KEY, WEVU_SLOT_OWNER_PROXY_KEY, WEVU_SLOT_PROPS_ATTR, WEVU_SLOT_PROPS_DATA_KEY, WEVU_SLOT_PROPS_KEY, WEVU_SLOT_SCOPE_ATTR, WEVU_SLOT_SCOPE_KEY, WEVU_TEMPLATE_REFS_KEY } from "@weapp-core/constants";
16
+ import { WEVU_CLASS_STYLE_RUNTIME_FILE, WEVU_CLASS_STYLE_RUNTIME_MODULE, WEVU_EXPRESSION_ERROR_IDENTIFIER, WEVU_FUNCTION_PROP_PATHS_KEY, WEVU_INLINE_HANDLER, WEVU_INLINE_MAP_KEY, WEVU_IS_PAGE_KEY, WEVU_LAYOUT_HOSTS_KEY, WEVU_LAYOUT_HOST_ID_PREFIX, WEVU_LAYOUT_HOST_REF_PREFIX, WEVU_MODEL_HANDLER, WEVU_OWNER_HANDLER, WEVU_PROPS_ALIASES_KEY, WEVU_PROPS_DERIVED_KEYS_KEY, WEVU_PROPS_KEY, WEVU_SLOT_NAMES_ATTR, WEVU_SLOT_NAMES_PROP, WEVU_SLOT_OWNER_ID_ATTR, WEVU_SLOT_OWNER_ID_KEY, WEVU_SLOT_OWNER_ID_PROP, WEVU_SLOT_OWNER_KEY, WEVU_SLOT_OWNER_PROXY_KEY, WEVU_SLOT_PROPS_ATTR, WEVU_SLOT_PROPS_DATA_KEY, WEVU_SLOT_PROPS_KEY, WEVU_SLOT_SCOPE_ATTR, WEVU_SLOT_SCOPE_KEY, WEVU_TEMPLATE_REFS_KEY, WEVU_TEMPLATE_REF_CLASS_PREFIX } from "@weapp-core/constants";
17
17
  import { compileScript, parse } from "vue/compiler-sfc";
18
18
  import { fileURLToPath } from "node:url";
19
19
  import { parse as parse$1 } from "@vue/compiler-dom";
@@ -2241,11 +2241,31 @@ function buildConsoleErrorGuard(message, errorId) {
2241
2241
  function buildRuntimeExpressionErrorGuard(binding, errorId) {
2242
2242
  return buildConsoleErrorGuard(`[wevu] 模板运行时表达式执行失败: ${binding.name} = ${binding.exp}`, errorId);
2243
2243
  }
2244
+ function isScopedSlotOwnerBinding(exp) {
2245
+ if (!exp) return false;
2246
+ const seen = /* @__PURE__ */ new WeakSet();
2247
+ const visit = (node) => {
2248
+ if (!node || typeof node !== "object") return false;
2249
+ if (seen.has(node)) return false;
2250
+ seen.add(node);
2251
+ if (node.type === "MemberExpression") {
2252
+ const member = node;
2253
+ const property = member.property;
2254
+ if (!member.computed && member.object?.type === "ThisExpression" && property?.type === "Identifier" && (property.name === WEVU_SLOT_OWNER_PROXY_KEY || property.name === WEVU_SLOT_OWNER_KEY)) return true;
2255
+ }
2256
+ for (const value of Object.values(node)) if (Array.isArray(value)) {
2257
+ if (value.some((item) => visit(item))) return true;
2258
+ } else if (visit(value)) return true;
2259
+ return false;
2260
+ };
2261
+ return visit(exp);
2262
+ }
2244
2263
  function shouldReportRuntimeExpressionError(binding) {
2245
- return binding.type === "bind";
2264
+ return binding.type === "bind" && !isScopedSlotOwnerBinding(binding.expAst);
2246
2265
  }
2247
2266
  function shouldReportForSourceError(info) {
2248
- return !(info.listExp?.trim() ?? "").startsWith(`${WEVU_SLOT_PROPS_DATA_KEY}.`);
2267
+ const listExp = info.listExp?.trim() ?? "";
2268
+ return !listExp.startsWith(`${WEVU_SLOT_PROPS_DATA_KEY}.`) && !listExp.startsWith(`${WEVU_SLOT_OWNER_KEY}.`) && !isScopedSlotOwnerBinding(info.listExpAst);
2249
2269
  }
2250
2270
  function createDataPropsFallbackExpression(fallback) {
2251
2271
  const propsObject = t.memberExpression(t.thisExpression(), t.identifier(WEVU_PROPS_KEY));
@@ -2283,7 +2303,7 @@ function buildNormalizedExpression(binding, helpers) {
2283
2303
  const errorId = t.identifier(WEVU_EXPRESSION_ERROR_IDENTIFIER);
2284
2304
  if (binding.type === "bind") {
2285
2305
  const exp = binding.expAst ? t.cloneNode(binding.expAst, true) : t.identifier("undefined");
2286
- return t.callExpression(t.arrowFunctionExpression([], t.blockStatement([t.tryStatement(t.blockStatement([t.returnStatement(exp)]), t.catchClause(t.cloneNode(errorId), t.blockStatement([buildRuntimeExpressionErrorGuard(binding, errorId), t.returnStatement(t.identifier("undefined"))])), null)])), []);
2306
+ return t.callExpression(t.arrowFunctionExpression([], t.blockStatement([t.tryStatement(t.blockStatement([t.returnStatement(exp)]), t.catchClause(t.cloneNode(errorId), t.blockStatement([...shouldReportRuntimeExpressionError(binding) ? [buildRuntimeExpressionErrorGuard(binding, errorId)] : [], t.returnStatement(t.identifier("undefined"))])), null)])), []);
2287
2307
  }
2288
2308
  const normalizeHelper = binding.type === "class" ? helpers.normalizeClass : helpers.normalizeStyle;
2289
2309
  const errorFallback = binding.errorFallback ?? "";
@@ -5394,7 +5414,7 @@ function collectForAliasMapping$2(context) {
5394
5414
  }
5395
5415
  return mapping;
5396
5416
  }
5397
- function replaceIdentifierWithExpression(path, replacement) {
5417
+ function replaceIdentifierWithExpression$1(path, replacement) {
5398
5418
  const parent = path.parentPath;
5399
5419
  if (parent.isObjectProperty() && parent.node.shorthand && parent.node.key === path.node) {
5400
5420
  parent.node.shorthand = false;
@@ -5425,16 +5445,16 @@ function rewriteScopedSlotExpression(exp, context) {
5425
5445
  if (hasOwn(forAliases, name)) {
5426
5446
  const aliasExp = parseBabelExpression(forAliases[name]);
5427
5447
  if (aliasExp) {
5428
- replaceIdentifierWithExpression(path, t.cloneNode(aliasExp, true));
5448
+ replaceIdentifierWithExpression$1(path, t.cloneNode(aliasExp, true));
5429
5449
  return;
5430
5450
  }
5431
5451
  }
5432
5452
  if (locals.has(name)) return;
5433
5453
  if (hasOwn(slotProps, name)) {
5434
- replaceIdentifierWithExpression(path, createMemberAccess(WEVU_SLOT_PROPS_DATA_KEY, slotProps[name]));
5454
+ replaceIdentifierWithExpression$1(path, createMemberAccess(WEVU_SLOT_PROPS_DATA_KEY, slotProps[name]));
5435
5455
  return;
5436
5456
  }
5437
- replaceIdentifierWithExpression(path, createMemberAccess(WEVU_SLOT_OWNER_KEY, name));
5457
+ replaceIdentifierWithExpression$1(path, createMemberAccess(WEVU_SLOT_OWNER_KEY, name));
5438
5458
  } });
5439
5459
  const stmt = ast.program.body[0];
5440
5460
  const updatedExpression = stmt && "expression" in stmt ? stmt.expression : null;
@@ -5453,7 +5473,7 @@ function rewriteForAliasExpression(exp, context) {
5453
5473
  if (path.scope.hasBinding(name)) return;
5454
5474
  if (hasOwn(forAliases, name)) {
5455
5475
  const aliasExp = parseBabelExpression(forAliases[name]);
5456
- if (aliasExp) replaceIdentifierWithExpression(path, t.cloneNode(aliasExp, true));
5476
+ if (aliasExp) replaceIdentifierWithExpression$1(path, t.cloneNode(aliasExp, true));
5457
5477
  }
5458
5478
  } });
5459
5479
  const stmt = ast.program.body[0];
@@ -5613,10 +5633,20 @@ const INLINE_GLOBALS = new Set([
5613
5633
  ]);
5614
5634
  const IDENTIFIER_RE$2 = /^[A-Z_$][\w$]*$/i;
5615
5635
  const SIMPLE_PATH_RE = /^[A-Z_$][\w$]*(?:\.[A-Z_$][\w$]*)*$/i;
5636
+ const SCRIPT_SETUP_REF_BINDINGS = new Set(["setup-ref", "setup-maybe-ref"]);
5616
5637
  function createMemberAccess$1(target, prop) {
5617
5638
  if (IDENTIFIER_RE$2.test(prop)) return t.memberExpression(t.identifier(target), t.identifier(prop));
5618
5639
  return t.memberExpression(t.identifier(target), t.stringLiteral(prop), true);
5619
5640
  }
5641
+ function replaceIdentifierWithExpression(path, replacement) {
5642
+ const parent = path.parentPath;
5643
+ if (parent.isObjectProperty() && parent.node.shorthand && parent.node.key === path.node) {
5644
+ parent.node.shorthand = false;
5645
+ parent.node.value = replacement;
5646
+ return;
5647
+ }
5648
+ path.replaceWith(replacement);
5649
+ }
5620
5650
  function resolveSlotPropBinding(slotProps, name) {
5621
5651
  if (!hasOwn(slotProps, name)) return null;
5622
5652
  const prop = slotProps[name];
@@ -5633,11 +5663,11 @@ function rewriteExpressionAst(ast, locals, options) {
5633
5663
  if (path.scope.getBinding(name)) return;
5634
5664
  if (locals.has(name)) {
5635
5665
  options?.markLocal?.(name);
5636
- path.replaceWith(createMemberAccess$1("scope", name));
5666
+ replaceIdentifierWithExpression(path, createMemberAccess$1("scope", name));
5637
5667
  return;
5638
5668
  }
5639
5669
  if (INLINE_GLOBALS.has(name)) return;
5640
- path.replaceWith(createMemberAccess$1("ctx", name));
5670
+ replaceIdentifierWithExpression(path, createMemberAccess$1("ctx", name));
5641
5671
  },
5642
5672
  ThisExpression(path) {
5643
5673
  path.replaceWith(t.identifier("ctx"));
@@ -5693,6 +5723,48 @@ function collectForAliasMapping$1(context) {
5693
5723
  }
5694
5724
  return mapping;
5695
5725
  }
5726
+ function getScriptSetupBindingType(context, name) {
5727
+ const binding = context.scriptSetupBindings?.[name];
5728
+ return typeof binding === "string" ? binding : void 0;
5729
+ }
5730
+ function isScriptSetupBinding(context, name) {
5731
+ return Boolean(getScriptSetupBindingType(context, name));
5732
+ }
5733
+ function isScriptSetupRefLikeBinding(context, name) {
5734
+ const bindingType = getScriptSetupBindingType(context, name);
5735
+ return bindingType ? SCRIPT_SETUP_REF_BINDINGS.has(bindingType) : false;
5736
+ }
5737
+ function isRefLikeCtxMember(node, context) {
5738
+ return t.isMemberExpression(node) && t.isIdentifier(node.object, { name: "ctx" }) && t.isIdentifier(node.property) && !node.computed && isScriptSetupRefLikeBinding(context, node.property.name);
5739
+ }
5740
+ function buildCtxValueAccess(member) {
5741
+ return t.memberExpression(t.cloneNode(member), t.identifier("value"));
5742
+ }
5743
+ function isValueMemberObject(node, parent) {
5744
+ return t.isMemberExpression(parent) && parent.object === node && t.isIdentifier(parent.property, { name: "value" }) && !parent.computed;
5745
+ }
5746
+ function rewriteTopLevelRefLikeAccess(ast, context) {
5747
+ traverse(ast, {
5748
+ AssignmentExpression(path) {
5749
+ const left = path.node.left;
5750
+ if (t.isIdentifier(left) && isScriptSetupRefLikeBinding(context, left.name)) path.node.left = buildCtxValueAccess(t.memberExpression(t.identifier("ctx"), t.identifier(left.name)));
5751
+ else if (t.isIdentifier(left) && isScriptSetupBinding(context, left.name)) path.node.left = t.memberExpression(t.identifier("ctx"), t.identifier(left.name));
5752
+ else if (isRefLikeCtxMember(left, context)) path.node.left = buildCtxValueAccess(left);
5753
+ },
5754
+ UpdateExpression(path) {
5755
+ const arg = path.node.argument;
5756
+ if (t.isIdentifier(arg) && isScriptSetupRefLikeBinding(context, arg.name)) path.node.argument = buildCtxValueAccess(t.memberExpression(t.identifier("ctx"), t.identifier(arg.name)));
5757
+ else if (t.isIdentifier(arg) && isScriptSetupBinding(context, arg.name)) path.node.argument = t.memberExpression(t.identifier("ctx"), t.identifier(arg.name));
5758
+ else if (isRefLikeCtxMember(arg, context)) path.node.argument = buildCtxValueAccess(arg);
5759
+ }
5760
+ });
5761
+ traverse(ast, { MemberExpression(path) {
5762
+ if (!isRefLikeCtxMember(path.node, context)) return;
5763
+ if (isValueMemberObject(path.node, path.parentPath?.node)) return;
5764
+ path.replaceWith(buildCtxValueAccess(path.node));
5765
+ path.skip();
5766
+ } });
5767
+ }
5696
5768
  function registerInlineExpression(exp, context) {
5697
5769
  const parsed = parseBabelExpressionFile(exp);
5698
5770
  if (!parsed) return null;
@@ -5708,6 +5780,7 @@ function registerInlineExpression(exp, context) {
5708
5780
  usedLocals.push(name);
5709
5781
  };
5710
5782
  rewriteExpressionAst(ast, locals, { markLocal });
5783
+ rewriteTopLevelRefLikeAccess(ast, context);
5711
5784
  const forAliases = collectForAliasMapping$1(context);
5712
5785
  const updatedStmt = ast.program.body[0];
5713
5786
  const updatedExpressionNode = updatedStmt && "expression" in updatedStmt ? updatedStmt.expression : null;
@@ -6523,6 +6596,7 @@ function collectElementAttributes(node, context, options) {
6523
6596
  else layoutHostKey = rawKey;
6524
6597
  continue;
6525
6598
  }
6599
+ if (prop.name === "slot-wrapper" || prop.name.startsWith("slot-wrapper-") || prop.name.startsWith("slot-wrapper:") || prop.name === "slot-single-root-no-wrapper" || prop.name.startsWith("slot-single-root-no-wrapper-") || prop.name.startsWith("slot-single-root-no-wrapper:")) continue;
6526
6600
  if (prop.name === "ref") {
6527
6601
  if (prop.value?.type === NodeTypes.TEXT) {
6528
6602
  const name = prop.value.content.trim();
@@ -6561,6 +6635,11 @@ function collectElementAttributes(node, context, options) {
6561
6635
  context.warnings.push("暂不支持动态 layout-host,已忽略该绑定。");
6562
6636
  continue;
6563
6637
  }
6638
+ if (prop.name === "bind" && prop.arg?.type === NodeTypes.SIMPLE_EXPRESSION && (prop.arg.content === "slot-wrapper" || prop.arg.content.startsWith("slot-wrapper-") || prop.arg.content.startsWith("slot-wrapper:") || prop.arg.content === "slot-single-root-no-wrapper" || prop.arg.content.startsWith("slot-single-root-no-wrapper-") || prop.arg.content.startsWith("slot-single-root-no-wrapper:"))) {
6639
+ if (prop.arg.content.endsWith("-class") || prop.arg.content.endsWith(":class") || prop.arg.content.endsWith("-style") || prop.arg.content.endsWith(":style")) continue;
6640
+ context.warnings.push(`暂不支持动态 ${prop.arg.content},已忽略该绑定。`);
6641
+ continue;
6642
+ }
6564
6643
  if (prop.name === "bind" && prop.arg?.type === NodeTypes.SIMPLE_EXPRESSION && prop.arg.content === "class") {
6565
6644
  dynamicClassExp = getBindDirectiveExpression(prop) || void 0;
6566
6645
  continue;
@@ -6584,7 +6663,7 @@ function collectElementAttributes(node, context, options) {
6584
6663
  }
6585
6664
  if (mappedTagClass) staticClass = prependStaticClass(staticClass, mappedTagClass);
6586
6665
  if (templateRef) {
6587
- const className = `__wv-ref-${context.templateRefIndexSeed++}`;
6666
+ const className = `${WEVU_TEMPLATE_REF_CLASS_PREFIX}${context.templateRefIndexSeed++}`;
6588
6667
  staticClass = staticClass ? `${staticClass} ${className}` : className;
6589
6668
  context.templateRefs.push({
6590
6669
  selector: `.${className}`,
@@ -6779,7 +6858,8 @@ function buildSlotDeclaration(name, propsExp, children, context, options) {
6779
6858
  children,
6780
6859
  implicitDefault: options?.implicitDefault,
6781
6860
  conditionKind: options?.conditionKind,
6782
- condition: options?.condition
6861
+ condition: options?.condition,
6862
+ wrapper: options?.wrapper
6783
6863
  };
6784
6864
  }
6785
6865
  function createScopedSlotComponent(context, slotKey, props, children, transformNode, options) {
@@ -6828,7 +6908,8 @@ function createScopedSlotComponent(context, slotKey, props, children, transformN
6828
6908
  slotKey
6829
6909
  };
6830
6910
  }
6831
- function injectAttributeIntoOpeningTag(source, attr) {
6911
+ function injectAttributesIntoOpeningTag(source, attrs) {
6912
+ if (!attrs.length) return source;
6832
6913
  if (!source.startsWith("<") || source.startsWith("</") || source.startsWith("<!--")) return null;
6833
6914
  let tagNameEnd = 1;
6834
6915
  while (tagNameEnd < source.length) {
@@ -6837,7 +6918,7 @@ function injectAttributeIntoOpeningTag(source, attr) {
6837
6918
  tagNameEnd += 1;
6838
6919
  }
6839
6920
  if (tagNameEnd <= 1) return null;
6840
- return `${source.slice(0, tagNameEnd)} ${attr}${source.slice(tagNameEnd)}`;
6921
+ return `${source.slice(0, tagNameEnd)} ${attrs.join(" ")}${source.slice(tagNameEnd)}`;
6841
6922
  }
6842
6923
  function createSlotAttributeNode(sourceNode, attr) {
6843
6924
  const match = /^slot="([\s\S]*)"$/.exec(attr);
@@ -6854,22 +6935,119 @@ function createSlotAttributeNode(sourceNode, attr) {
6854
6935
  loc: sourceNode.loc
6855
6936
  };
6856
6937
  }
6857
- function injectSlotAttributeIntoElementNode(child, slotAttr, transformNode, context) {
6938
+ function injectSlotAttributeIntoElementNode(child, slotAttr, extraAttrs, transformNode, context) {
6858
6939
  if (child.type !== NodeTypes.ELEMENT || child.tag === "template") return null;
6859
6940
  const sourceNode = child;
6860
6941
  const slotAttribute = createSlotAttributeNode(sourceNode, slotAttr);
6861
6942
  if (!slotAttribute) return null;
6862
- return transformNode({
6943
+ return injectAttributesIntoOpeningTag(transformNode({
6863
6944
  ...sourceNode,
6864
6945
  props: [slotAttribute, ...sourceNode.props]
6865
- }, context);
6946
+ }, context), extraAttrs);
6866
6947
  }
6867
6948
  function isRenderableFallbackChild(child) {
6868
6949
  if (child.type === NodeTypes.COMMENT) return false;
6869
6950
  if (child.type === NodeTypes.TEXT) return child.content.trim().length > 0;
6870
6951
  return true;
6871
6952
  }
6872
- function renderSlotFallback(decl, context, transformNode) {
6953
+ function canInjectSlotAttributeIntoFallbackChild(child) {
6954
+ if (child.type !== NodeTypes.ELEMENT) return true;
6955
+ return child.tag !== "slot";
6956
+ }
6957
+ function matchesSlotFallbackWrapperMatcher(matcher, value) {
6958
+ if (!matcher) return true;
6959
+ if (!value) return false;
6960
+ if (Array.isArray(matcher)) return matcher.some((item) => matchesSlotFallbackWrapperMatcher(item, value));
6961
+ return typeof matcher === "string" ? matcher === value : matcher.test(value);
6962
+ }
6963
+ function normalizeSlotFallbackWrapperTag(tag, context) {
6964
+ const normalized = tag?.trim() || "view";
6965
+ if (normalized === "block") {
6966
+ context.warnings.push("slot fallback wrapper 不支持配置为 block,已回退为 view。");
6967
+ return "view";
6968
+ }
6969
+ return normalized;
6970
+ }
6971
+ function mergeSlotFallbackWrapperAttrs(base, override) {
6972
+ if (!base) return override;
6973
+ if (!override) return base;
6974
+ return {
6975
+ ...base,
6976
+ ...override
6977
+ };
6978
+ }
6979
+ function resolveSlotFallbackWrapper(context, info) {
6980
+ const resolved = {
6981
+ tag: normalizeSlotFallbackWrapperTag(context.slotFallbackWrapper.tag, context),
6982
+ attrs: context.slotFallbackWrapper.attrs,
6983
+ singleRootNoWrapper: context.slotFallbackWrapper.singleRootNoWrapper ?? context.slotSingleRootNoWrapper
6984
+ };
6985
+ for (const rule of context.slotFallbackWrapper.rules) if (matchesSlotFallbackWrapperMatcher(rule.component, info.component) && matchesSlotFallbackWrapperMatcher(rule.componentName, info.componentName) && matchesSlotFallbackWrapperMatcher(rule.slot, info.slot)) {
6986
+ if (rule.tag) resolved.tag = normalizeSlotFallbackWrapperTag(rule.tag, context);
6987
+ if (rule.attrs) resolved.attrs = mergeSlotFallbackWrapperAttrs(resolved.attrs, rule.attrs);
6988
+ if (rule.singleRootNoWrapper !== void 0) resolved.singleRootNoWrapper = rule.singleRootNoWrapper;
6989
+ }
6990
+ if (info.local?.tag) resolved.tag = normalizeSlotFallbackWrapperTag(info.local.tag, context);
6991
+ if (info.local?.staticClass !== void 0) resolved.staticClass = info.local.staticClass;
6992
+ if (info.local?.dynamicClassExp !== void 0) resolved.dynamicClassExp = info.local.dynamicClassExp;
6993
+ if (info.local?.staticStyle !== void 0) resolved.staticStyle = info.local.staticStyle;
6994
+ if (info.local?.dynamicStyleExp !== void 0) resolved.dynamicStyleExp = info.local.dynamicStyleExp;
6995
+ if (info.local?.singleRootNoWrapper !== void 0) resolved.singleRootNoWrapper = info.local.singleRootNoWrapper;
6996
+ return resolved;
6997
+ }
6998
+ function createStaticAttributeNode(name, value) {
6999
+ return {
7000
+ type: NodeTypes.ATTRIBUTE,
7001
+ name,
7002
+ nameLoc: void 0,
7003
+ value: {
7004
+ type: NodeTypes.TEXT,
7005
+ content: value,
7006
+ loc: void 0
7007
+ },
7008
+ loc: void 0
7009
+ };
7010
+ }
7011
+ function renderSlotFallbackWrapperAttrs(wrapper, context) {
7012
+ const attrs = [];
7013
+ for (const [name, value] of Object.entries(wrapper.attrs ?? {})) {
7014
+ if (name === "class" && (wrapper.staticClass !== void 0 || wrapper.dynamicClassExp !== void 0)) continue;
7015
+ if (name === "style" && (wrapper.staticStyle !== void 0 || wrapper.dynamicStyleExp !== void 0)) continue;
7016
+ const attr = transformAttribute(createStaticAttributeNode(name, value), context);
7017
+ if (attr) attrs.push(attr);
7018
+ }
7019
+ const classAttr = renderClassAttribute(wrapper.staticClass, wrapper.dynamicClassExp, context);
7020
+ if (classAttr) attrs.push(classAttr);
7021
+ const styleAttr = renderStyleAttribute(wrapper.staticStyle, wrapper.dynamicStyleExp, void 0, context);
7022
+ if (styleAttr) attrs.push(styleAttr);
7023
+ return attrs;
7024
+ }
7025
+ function renderPlainSlotOutlet(node, context, transformNode) {
7026
+ const slotNameInfo = resolveSlotNameFromSlotElement(node);
7027
+ const hasScopeBindings = node.props.some((prop) => {
7028
+ if (prop.type === NodeTypes.DIRECTIVE && prop.name === "bind") return prop.arg?.type !== NodeTypes.SIMPLE_EXPRESSION || prop.arg.content !== "name";
7029
+ return false;
7030
+ });
7031
+ if (hasScopeBindings) context.warnings.push("已禁用作用域插槽参数,插槽绑定将被忽略。");
7032
+ const fallbackContent = node.children.map((child) => transformNode(child, context)).join("");
7033
+ const slotAttrs = [];
7034
+ const nameAttr = renderSlotNameAttribute(slotNameInfo, context, "name");
7035
+ if (nameAttr) slotAttrs.push(nameAttr);
7036
+ const slotAttrString = slotAttrs.length ? ` ${slotAttrs.join(" ")}` : "";
7037
+ if (!hasScopeBindings && fallbackContent) {
7038
+ const slotPresentExp = createSlotPresenceExpression(slotNameInfo);
7039
+ if (slotPresentExp) {
7040
+ const slotTag = `<slot${slotAttrString} />`;
7041
+ return `${context.platform.wrapIf(slotPresentExp, slotTag, (exp) => renderMustache(exp, context))}${context.platform.wrapElse(fallbackContent)}`;
7042
+ }
7043
+ }
7044
+ return fallbackContent ? `<slot${slotAttrString}>${fallbackContent}</slot>` : `<slot${slotAttrString} />`;
7045
+ }
7046
+ function transformFallbackChild(child, context, transformNode) {
7047
+ if (child.type === NodeTypes.ELEMENT && child.tag === "slot") return renderPlainSlotOutlet(child, context, transformNode);
7048
+ return transformNode(child, context);
7049
+ }
7050
+ function renderSlotFallback(decl, context, transformNode, options) {
6873
7051
  const slotAttr = renderSlotNameAttribute(decl.name, context, "slot");
6874
7052
  const wrapCondition = (content) => {
6875
7053
  if (decl.conditionKind === "else") return context.platform.wrapElse(content);
@@ -6884,17 +7062,31 @@ function renderSlotFallback(decl, context, transformNode) {
6884
7062
  }
6885
7063
  const renderableChildren = decl.children.filter(isRenderableFallbackChild);
6886
7064
  if (!renderableChildren.length) return "";
6887
- if (!context.slotSingleRootNoWrapper) {
6888
- const rawContent = decl.children.map((child) => transformNode(child, context)).join("");
7065
+ const staticSlotName = resolveSlotStaticName(decl.name);
7066
+ const wrapper = resolveSlotFallbackWrapper(context, {
7067
+ component: options?.component,
7068
+ componentName: options?.componentName,
7069
+ slot: staticSlotName,
7070
+ local: {
7071
+ ...options?.wrapper,
7072
+ ...decl.wrapper
7073
+ }
7074
+ });
7075
+ const wrapperAttrs = renderSlotFallbackWrapperAttrs(wrapper, context);
7076
+ const wrapperAttrString = wrapperAttrs.length ? ` ${wrapperAttrs.join(" ")}` : "";
7077
+ if (!wrapper.singleRootNoWrapper) {
7078
+ const rawContent = decl.children.map((child) => transformFallbackChild(child, context, transformNode)).join("");
6889
7079
  if (!rawContent) return "";
6890
- return wrapCondition(`<view ${slotAttr}>${rawContent}</view>`);
7080
+ return wrapCondition(`<${wrapper.tag} ${slotAttr}${wrapperAttrString}>${rawContent}</${wrapper.tag}>`);
6891
7081
  }
6892
7082
  if (renderableChildren.length === 1) {
6893
7083
  const child = renderableChildren[0];
6894
- const projected = child.type === NodeTypes.ELEMENT && isStructuralDirective(child).type ? injectSlotAttributeIntoElementNode(child, slotAttr, transformNode, context) : injectAttributeIntoOpeningTag(transformNode(child, context), slotAttr);
7084
+ let projected = null;
7085
+ if (canInjectSlotAttributeIntoFallbackChild(child)) projected = child.type === NodeTypes.ELEMENT && isStructuralDirective(child).type ? injectSlotAttributeIntoElementNode(child, slotAttr, wrapperAttrs, transformNode, context) : injectAttributesIntoOpeningTag(transformNode(child, context), [slotAttr, ...wrapperAttrs]);
6895
7086
  if (projected) return wrapCondition(projected);
6896
7087
  }
6897
- return wrapCondition(`<view ${slotAttr}>${renderableChildren.map((child) => transformNode(child, context)).join("")}</view>`);
7088
+ const content = renderableChildren.map((child) => transformFallbackChild(child, context, transformNode)).join("");
7089
+ return wrapCondition(`<${wrapper.tag} ${slotAttr}${wrapperAttrString}>${content}</${wrapper.tag}>`);
6898
7090
  }
6899
7091
  function transformSlotElement(node, context, transformNode) {
6900
7092
  if (isScopedSlotsDisabled(context)) return transformSlotElementPlain(node, context, transformNode);
@@ -6913,6 +7105,7 @@ function transformSlotElement(node, context, transformNode) {
6913
7105
  else if (!slotPropsExp) slotTag = `<slot${slotAttrString}>${fallbackContent}</slot>`;
6914
7106
  }
6915
7107
  if (!slotPropsExp && (context.scopedSlotsRequireProps || slotNameInfo.type !== "default" && context.scopedSlotsCompiler !== "augmented")) return slotTag;
7108
+ const hasScopeBindings = Boolean(slotPropsExp);
6916
7109
  const genericKey = `scoped-slots-${resolveSlotKey(context, slotNameInfo)}`;
6917
7110
  context.componentGenerics[genericKey] = true;
6918
7111
  slotPropsExp = slotPropsExp ?? "[]";
@@ -6923,30 +7116,12 @@ function transformSlotElement(node, context, transformNode) {
6923
7116
  ];
6924
7117
  if (context.slotMultipleInstance) scopedAttrs.push(`${WEVU_SLOT_SCOPE_ATTR}="${renderMustache(WEVU_SLOT_SCOPE_KEY, context)}"`);
6925
7118
  const scopedTag = `<${genericKey}${scopedAttrs.length ? ` ${scopedAttrs.join(" ")}` : ""} />`;
6926
- const projectedContent = `${slotTag}${scopedTag}`;
7119
+ const projectedContent = hasScopeBindings ? scopedTag : `${scopedTag}${context.platform.wrapElse(slotTag)}`;
6927
7120
  if (fallbackContent && slotPresentExp) return `${context.platform.wrapIf(slotPresentExp, projectedContent, (exp) => renderMustache(exp, context))}${context.platform.wrapElse(fallbackContent)}`;
6928
7121
  return projectedContent;
6929
7122
  }
6930
7123
  function transformSlotElementPlain(node, context, transformNode) {
6931
- const slotNameInfo = resolveSlotNameFromSlotElement(node);
6932
- const hasScopeBindings = node.props.some((prop) => {
6933
- if (prop.type === NodeTypes.DIRECTIVE && prop.name === "bind") return prop.arg?.type !== NodeTypes.SIMPLE_EXPRESSION || prop.arg.content !== "name";
6934
- return false;
6935
- });
6936
- if (hasScopeBindings) context.warnings.push("已禁用作用域插槽参数,插槽绑定将被忽略。");
6937
- const fallbackContent = node.children.map((child) => transformNode(child, context)).join("");
6938
- const slotAttrs = [];
6939
- const nameAttr = renderSlotNameAttribute(slotNameInfo, context, "name");
6940
- if (nameAttr) slotAttrs.push(nameAttr);
6941
- const slotAttrString = slotAttrs.length ? ` ${slotAttrs.join(" ")}` : "";
6942
- if (!hasScopeBindings && fallbackContent) {
6943
- const slotPresentExp = createSlotPresenceExpression(slotNameInfo);
6944
- if (slotPresentExp) {
6945
- const slotTag = `<slot${slotAttrString} />`;
6946
- return `${context.platform.wrapIf(slotPresentExp, slotTag, (exp) => renderMustache(exp, context))}${context.platform.wrapElse(fallbackContent)}`;
6947
- }
6948
- }
6949
- return fallbackContent ? `<slot${slotAttrString}>${fallbackContent}</slot>` : `<slot${slotAttrString} />`;
7124
+ return renderPlainSlotOutlet(node, context, transformNode);
6950
7125
  }
6951
7126
  //#endregion
6952
7127
  //#region src/plugins/vue/compiler/template/elements/tag-component.ts
@@ -7022,11 +7197,82 @@ function pushSlotNamesAttr(attrs, slotNames, context) {
7022
7197
  function shouldExposePlainSlotPresence(node) {
7023
7198
  return node.tag === "component";
7024
7199
  }
7025
- function renderPlainSlotContentInSourceOrder(renderItems, plainSlotDeclarations, implicitDefaultDeclaration, context, transformNode) {
7200
+ function normalizeBooleanAttributeValue(value) {
7201
+ if (value === void 0 || value === "") return true;
7202
+ if (value === "true") return true;
7203
+ if (value === "false") return false;
7204
+ }
7205
+ function isSlotFallbackWrapperName(name, baseName, slotName) {
7206
+ return name === baseName || slotName !== void 0 && (name === `${baseName}-${slotName}` || name === `${baseName}:${slotName}`);
7207
+ }
7208
+ function isSlotFallbackWrapperAttr(name, baseName, slotName, attrName) {
7209
+ if (!attrName) return isSlotFallbackWrapperName(name, baseName, slotName);
7210
+ return name === `${baseName}-${attrName}` || slotName !== void 0 && (name === `${baseName}-${slotName}-${attrName}` || name === `${baseName}:${slotName}:${attrName}`);
7211
+ }
7212
+ function resolveLocalSlotFallbackWrapperConfig(node, context, slotName) {
7213
+ const wrapper = {};
7214
+ let hasConfig = false;
7215
+ for (const prop of node.props) if (prop.type === NodeTypes.ATTRIBUTE) {
7216
+ if (isSlotFallbackWrapperAttr(prop.name, "slot-wrapper", slotName)) {
7217
+ const tag = prop.value?.type === NodeTypes.TEXT ? prop.value.content.trim() : "";
7218
+ if (tag) {
7219
+ wrapper.tag = tag;
7220
+ hasConfig = true;
7221
+ } else context.warnings.push("slot-wrapper 需要提供非空标签名,已忽略该配置。");
7222
+ } else if (isSlotFallbackWrapperAttr(prop.name, "slot-single-root-no-wrapper", slotName)) {
7223
+ const value = normalizeBooleanAttributeValue(prop.value?.type === NodeTypes.TEXT ? prop.value.content.trim() : void 0);
7224
+ if (value === void 0) context.warnings.push("slot-single-root-no-wrapper 仅支持 true / false 静态值,已忽略该配置。");
7225
+ else {
7226
+ wrapper.singleRootNoWrapper = value;
7227
+ hasConfig = true;
7228
+ }
7229
+ } else if (isSlotFallbackWrapperAttr(prop.name, "slot-wrapper", slotName, "class")) {
7230
+ const value = prop.value?.type === NodeTypes.TEXT ? prop.value.content.trim() : "";
7231
+ if (value) {
7232
+ wrapper.staticClass = value;
7233
+ hasConfig = true;
7234
+ }
7235
+ } else if (isSlotFallbackWrapperAttr(prop.name, "slot-wrapper", slotName, "style")) {
7236
+ const value = prop.value?.type === NodeTypes.TEXT ? prop.value.content.trim() : "";
7237
+ if (value) {
7238
+ wrapper.staticStyle = value;
7239
+ hasConfig = true;
7240
+ }
7241
+ }
7242
+ } else if (prop.type === NodeTypes.DIRECTIVE && prop.name === "bind" && prop.arg?.type === NodeTypes.SIMPLE_EXPRESSION) {
7243
+ if (isSlotFallbackWrapperAttr(prop.arg.content, "slot-wrapper", slotName, "class")) {
7244
+ const exp = getBindDirectiveExpression(prop);
7245
+ if (exp) {
7246
+ wrapper.dynamicClassExp = exp;
7247
+ hasConfig = true;
7248
+ }
7249
+ } else if (isSlotFallbackWrapperAttr(prop.arg.content, "slot-wrapper", slotName, "style")) {
7250
+ const exp = getBindDirectiveExpression(prop);
7251
+ if (exp) {
7252
+ wrapper.dynamicStyleExp = exp;
7253
+ hasConfig = true;
7254
+ }
7255
+ }
7256
+ }
7257
+ return hasConfig ? wrapper : void 0;
7258
+ }
7259
+ function mergeLocalSlotFallbackWrapperConfig(base, override) {
7260
+ if (!base) return override;
7261
+ if (!override) return base;
7262
+ return {
7263
+ ...base,
7264
+ ...override
7265
+ };
7266
+ }
7267
+ function renderPlainSlotContentInSourceOrder(renderItems, plainSlotDeclarations, implicitDefaultDeclaration, ownerComponent, ownerComponentName, ownerWrapper, context, transformNode) {
7026
7268
  const plainSlots = new Set(plainSlotDeclarations);
7027
7269
  const shouldRenderImplicitDefault = implicitDefaultDeclaration ? plainSlots.has(implicitDefaultDeclaration) : false;
7028
7270
  return renderItems.map((item) => {
7029
- if (item.type === "declaration") return plainSlots.has(item.declaration) ? renderSlotFallback(item.declaration, context, transformNode) : "";
7271
+ if (item.type === "declaration") return plainSlots.has(item.declaration) ? renderSlotFallback(item.declaration, context, transformNode, {
7272
+ component: ownerComponent,
7273
+ componentName: ownerComponentName,
7274
+ wrapper: ownerWrapper
7275
+ }) : "";
7030
7276
  return shouldRenderImplicitDefault ? transformNode(item.child, context) : "";
7031
7277
  }).join("");
7032
7278
  }
@@ -7042,6 +7288,7 @@ function transformComponentWithSlots(node, context, transformNode, options) {
7042
7288
  const extraAttrs = options?.extraAttrs ?? [];
7043
7289
  const slotDeclarations = [];
7044
7290
  const slotDirective = findSlotDirective(node);
7291
+ const ownerWrapper = resolveLocalSlotFallbackWrapperConfig(node, context);
7045
7292
  const nonTemplateChildren = [];
7046
7293
  const renderItems = [];
7047
7294
  for (const child of node.children) {
@@ -7050,7 +7297,10 @@ function transformComponentWithSlots(node, context, transformNode, options) {
7050
7297
  if (templateSlot) {
7051
7298
  const slotName = resolveSlotNameFromDirective(templateSlot);
7052
7299
  const templateSlotCondition = resolveTemplateSlotCondition(child, context);
7053
- const declaration = buildSlotDeclaration(slotName, templateSlot.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? templateSlot.exp.content : void 0, child.children, context, templateSlotCondition);
7300
+ const declaration = buildSlotDeclaration(slotName, templateSlot.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? templateSlot.exp.content : void 0, child.children, context, {
7301
+ ...templateSlotCondition,
7302
+ wrapper: mergeLocalSlotFallbackWrapperConfig(resolveLocalSlotFallbackWrapperConfig(node, context, slotName.type === "static" ? slotName.value : void 0), resolveLocalSlotFallbackWrapperConfig(child, context))
7303
+ });
7054
7304
  slotDeclarations.push(declaration);
7055
7305
  renderItems.push({
7056
7306
  type: "declaration",
@@ -7070,7 +7320,7 @@ function transformComponentWithSlots(node, context, transformNode, options) {
7070
7320
  if (slotDirective) {
7071
7321
  if (slotDeclarations.length) context.warnings.push("组件上的 v-slot 与 <template v-slot> 不能同时使用;仅使用组件上的 v-slot。");
7072
7322
  slotDeclarations.length = 0;
7073
- slotDeclarations.push(buildSlotDeclaration(resolveSlotNameFromDirective(slotDirective), slotDirective.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? slotDirective.exp.content : void 0, node.children, context));
7323
+ slotDeclarations.push(buildSlotDeclaration(resolveSlotNameFromDirective(slotDirective), slotDirective.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? slotDirective.exp.content : void 0, node.children, context, { wrapper: ownerWrapper }));
7074
7324
  } else if (slotDeclarations.length && defaultSlotChildren.length) if (slotDeclarations.some((decl) => decl.name.type === "default" || decl.name.type === "static" && decl.name.value === "default")) context.warnings.push("存在显式的 v-slot:default,默认插槽内容将被忽略。");
7075
7325
  else {
7076
7326
  implicitDefaultDeclaration = buildSlotDeclaration({ type: "default" }, void 0, defaultSlotChildren, context, { implicitDefault: true });
@@ -7100,6 +7350,7 @@ function transformComponentWithSlots(node, context, transformNode, options) {
7100
7350
  else plainSlotDeclarations.push(decl);
7101
7351
  const slotNames = [];
7102
7352
  const slotGenericAttrs = [];
7353
+ const ownerComponentName = context.componentNameMap?.[node.tag];
7103
7354
  for (const decl of scopedSlotDeclarations) {
7104
7355
  const slotKey = resolveSlotKey(context, decl.name);
7105
7356
  const { componentName } = createScopedSlotComponent(context, slotKey, decl.props, decl.children, transformNode, { hostComponentName: node.tag });
@@ -7132,13 +7383,18 @@ function transformComponentWithSlots(node, context, transformNode, options) {
7132
7383
  }
7133
7384
  const attrString = mergedAttrs.length ? ` ${mergedAttrs.join(" ")}` : "";
7134
7385
  const { tag } = node;
7135
- const plainSlotContent = slotDirective ? plainSlotDeclarations.map((decl) => renderSlotFallback(decl, context, transformNode)).join("") : renderPlainSlotContentInSourceOrder(renderItems, plainSlotDeclarations, implicitDefaultDeclaration, context, transformNode);
7386
+ const plainSlotContent = slotDirective ? plainSlotDeclarations.map((decl) => renderSlotFallback(decl, context, transformNode, {
7387
+ component: node.tag,
7388
+ componentName: ownerComponentName,
7389
+ wrapper: ownerWrapper
7390
+ })).join("") : renderPlainSlotContentInSourceOrder(renderItems, plainSlotDeclarations, implicitDefaultDeclaration, node.tag, ownerComponentName, ownerWrapper, context, transformNode);
7136
7391
  return plainSlotContent ? `<${tag}${attrString}>${plainSlotContent}</${tag}>` : `<${tag}${attrString} />`;
7137
7392
  }
7138
7393
  function transformComponentWithSlotsFallback(node, context, transformNode, options) {
7139
7394
  const extraAttrs = options?.extraAttrs ?? [];
7140
7395
  const slotDeclarations = [];
7141
7396
  const slotDirective = findSlotDirective(node);
7397
+ const ownerWrapper = resolveLocalSlotFallbackWrapperConfig(node, context);
7142
7398
  const nonTemplateChildren = [];
7143
7399
  const renderItems = [];
7144
7400
  for (const child of node.children) {
@@ -7147,7 +7403,10 @@ function transformComponentWithSlotsFallback(node, context, transformNode, optio
7147
7403
  if (templateSlot) {
7148
7404
  const slotName = resolveSlotNameFromDirective(templateSlot);
7149
7405
  const templateSlotCondition = resolveTemplateSlotCondition(child, context);
7150
- const declaration = buildSlotDeclaration(slotName, templateSlot.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? templateSlot.exp.content : void 0, child.children, context, templateSlotCondition);
7406
+ const declaration = buildSlotDeclaration(slotName, templateSlot.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? templateSlot.exp.content : void 0, child.children, context, {
7407
+ ...templateSlotCondition,
7408
+ wrapper: mergeLocalSlotFallbackWrapperConfig(resolveLocalSlotFallbackWrapperConfig(node, context, slotName.type === "static" ? slotName.value : void 0), resolveLocalSlotFallbackWrapperConfig(child, context))
7409
+ });
7151
7410
  slotDeclarations.push(declaration);
7152
7411
  renderItems.push({
7153
7412
  type: "declaration",
@@ -7167,7 +7426,7 @@ function transformComponentWithSlotsFallback(node, context, transformNode, optio
7167
7426
  if (slotDirective) {
7168
7427
  if (slotDeclarations.length) context.warnings.push("组件上的 v-slot 与 <template v-slot> 不能同时使用;仅使用组件上的 v-slot。");
7169
7428
  slotDeclarations.length = 0;
7170
- slotDeclarations.push(buildSlotDeclaration(resolveSlotNameFromDirective(slotDirective), slotDirective.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? slotDirective.exp.content : void 0, node.children, context));
7429
+ slotDeclarations.push(buildSlotDeclaration(resolveSlotNameFromDirective(slotDirective), slotDirective.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? slotDirective.exp.content : void 0, node.children, context, { wrapper: ownerWrapper }));
7171
7430
  } else if (slotDeclarations.length && defaultSlotChildren.length) if (slotDeclarations.some((decl) => decl.name.type === "default" || decl.name.type === "static" && decl.name.value === "default")) context.warnings.push("存在显式的 v-slot:default,默认插槽内容将被忽略。");
7172
7431
  else {
7173
7432
  implicitDefaultDeclaration = buildSlotDeclaration({ type: "default" }, void 0, defaultSlotChildren, context);
@@ -7188,7 +7447,11 @@ function transformComponentWithSlotsFallback(node, context, transformNode, optio
7188
7447
  return children ? `<${tag}${attrString}>${children}</${tag}>` : `<${tag}${attrString} />`;
7189
7448
  }
7190
7449
  if (slotDeclarations.some((decl) => Object.keys(decl.props).length)) context.warnings.push("已禁用作用域插槽参数,插槽绑定将被忽略。");
7191
- const renderedSlots = slotDirective ? slotDeclarations.map((decl) => renderSlotFallback(decl, context, transformNode)).join("") : renderPlainSlotContentInSourceOrder(renderItems, slotDeclarations, implicitDefaultDeclaration, context, transformNode);
7450
+ const renderedSlots = slotDirective ? slotDeclarations.map((decl) => renderSlotFallback(decl, context, transformNode, {
7451
+ component: node.tag,
7452
+ componentName: context.componentNameMap?.[node.tag],
7453
+ wrapper: ownerWrapper
7454
+ })).join("") : renderPlainSlotContentInSourceOrder(renderItems, slotDeclarations, implicitDefaultDeclaration, node.tag, context.componentNameMap?.[node.tag], ownerWrapper, context, transformNode);
7192
7455
  const { attrs } = collectElementAttributes(node, context, {
7193
7456
  skipSlotDirective: true,
7194
7457
  forInfo: options?.forInfo,
@@ -7260,7 +7523,7 @@ function resolveConditionExpression$1(rawExpValue, context, hint) {
7260
7523
  return (context.rewriteScopedSlot || shouldFallbackToRuntimeBinding(rawExpValue) ? registerRuntimeBindingExpression(rawExpValue, context, { hint }) : null) ?? normalizeWxmlExpressionWithContext(rawExpValue, context);
7261
7524
  }
7262
7525
  function resolveListExpression(rawExpValue, context, hint) {
7263
- return (shouldFallbackToRuntimeBinding(rawExpValue) ? registerRuntimeBindingExpression(rawExpValue, context, { hint }) : null) ?? normalizeWxmlExpressionWithContext(rawExpValue, context);
7526
+ return (context.rewriteScopedSlot || shouldFallbackToRuntimeBinding(rawExpValue) ? registerRuntimeBindingExpression(rawExpValue, context, { hint }) : null) ?? normalizeWxmlExpressionWithContext(rawExpValue, context);
7264
7527
  }
7265
7528
  function transformIfElement(node, context, transformNode) {
7266
7529
  const renderTemplateMustache = (exp) => renderMustache(exp, context);
@@ -7327,12 +7590,17 @@ function transformForElement(node, context, transformNode) {
7327
7590
  };
7328
7591
  const extraAttrs = listExp ? context.platform.forAttrs(listExp, renderTemplateMustache, forInfo.item, forInfo.index) : [];
7329
7592
  if (elementWithoutFor.tag === "slot") {
7593
+ const keyDirective = elementWithoutFor.props.find((prop) => {
7594
+ return prop.type === NodeTypes.DIRECTIVE && prop.name === "bind" && prop.arg?.type === NodeTypes.SIMPLE_EXPRESSION && prop.arg.content === "key";
7595
+ });
7330
7596
  const content = transformSlotElement({
7331
7597
  ...elementWithoutFor,
7332
7598
  props: elementWithoutFor.props.filter((prop) => {
7333
- return !(prop.type === NodeTypes.DIRECTIVE && prop.name === "bind" && prop.arg?.type === NodeTypes.SIMPLE_EXPRESSION && prop.arg.content === "key");
7599
+ return prop !== keyDirective;
7334
7600
  })
7335
7601
  }, context, transformNode);
7602
+ const keyAttr = keyDirective ? transformBindDirective(keyDirective, context, forInfo) : null;
7603
+ if (keyAttr) extraAttrs.push(keyAttr);
7336
7604
  const attrString = extraAttrs.length ? ` ${extraAttrs.join(" ")}` : "";
7337
7605
  return attrString ? `<block${attrString}>${content}</block>` : content;
7338
7606
  }
@@ -7494,6 +7762,18 @@ const HTML_VOID_TAGS = new Set([
7494
7762
  "track",
7495
7763
  "wbr"
7496
7764
  ]);
7765
+ function resolveSlotFallbackWrapperConfig(config) {
7766
+ if (typeof config === "string") return {
7767
+ tag: config || "view",
7768
+ rules: []
7769
+ };
7770
+ return {
7771
+ tag: config?.tag || "view",
7772
+ attrs: config?.attrs,
7773
+ singleRootNoWrapper: config?.singleRootNoWrapper,
7774
+ rules: config?.rules ?? []
7775
+ };
7776
+ }
7497
7777
  /**
7498
7778
  * 将 Vue 模板编译为 WXML。
7499
7779
  */
@@ -7504,6 +7784,7 @@ function compileVueTemplateToWxml(template, filename, options) {
7504
7784
  const wxsExtension = options?.wxsExtension;
7505
7785
  const scopedSlotsRequireProps = options?.scopedSlotsRequireProps ?? options?.scopedSlotsCompiler !== "augmented";
7506
7786
  const slotSingleRootNoWrapper = options?.slotSingleRootNoWrapper ?? false;
7787
+ const slotFallbackWrapper = resolveSlotFallbackWrapperConfig(options?.slotFallbackWrapper);
7507
7788
  const htmlTagToWxmlMap = resolveHtmlTagToWxmlMap(options?.htmlTagToWxml);
7508
7789
  try {
7509
7790
  const ast = parse$1(template, {
@@ -7519,14 +7800,17 @@ function compileVueTemplateToWxml(template, filename, options) {
7519
7800
  platform: options?.platform ?? getMiniProgramTemplatePlatform(),
7520
7801
  propsAliases: options?.propsAliases,
7521
7802
  propsDerivedKeys: options?.propsDerivedKeys,
7803
+ scriptSetupBindings: options?.scriptSetupBindings,
7522
7804
  htmlTagToWxmlMap,
7523
7805
  htmlTagToWxmlTagClass: options?.htmlTagToWxmlTagClass ?? true,
7524
7806
  scopedSlotsCompiler: options?.scopedSlotsCompiler ?? "auto",
7525
7807
  scopedSlotsRequireProps,
7526
7808
  slotSingleRootNoWrapper,
7809
+ slotFallbackWrapper,
7527
7810
  slotMultipleInstance: options?.slotMultipleInstance ?? true,
7528
7811
  scopedSlotComponents: [],
7529
7812
  componentGenerics: {},
7813
+ componentNameMap: options?.componentNameMap,
7530
7814
  scopeStack: [],
7531
7815
  slotPropStack: [],
7532
7816
  rewriteScopedSlot: false,
@@ -7593,6 +7877,49 @@ function isVueSfcSource(source) {
7593
7877
  function pascalToKebab(name) {
7594
7878
  return name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").toLowerCase();
7595
7879
  }
7880
+ function extractStringPropertyFromObject(node, keyName) {
7881
+ for (const property of node.properties) {
7882
+ if (!t.isObjectProperty(property)) continue;
7883
+ const key = property.key;
7884
+ if (!(t.isIdentifier(key) ? key.name === keyName : t.isStringLiteral(key) ? key.value === keyName : false) || !t.isStringLiteral(property.value)) continue;
7885
+ return property.value.value;
7886
+ }
7887
+ }
7888
+ function extractStaticDefineOptionsName(scriptSetupContent) {
7889
+ let ast;
7890
+ try {
7891
+ ast = parse$3(scriptSetupContent, BABEL_TS_MODULE_PARSER_OPTIONS);
7892
+ } catch {
7893
+ return;
7894
+ }
7895
+ let componentName;
7896
+ traverse(ast, { CallExpression(path) {
7897
+ if (componentName) return;
7898
+ const callee = path.node.callee;
7899
+ if (!t.isIdentifier(callee, { name: "defineOptions" })) return;
7900
+ const arg = path.node.arguments[0];
7901
+ if (!t.isObjectExpression(arg)) return;
7902
+ componentName = extractStringPropertyFromObject(arg, "name");
7903
+ } });
7904
+ return componentName;
7905
+ }
7906
+ async function resolveVueSfcComponentName(resolvedId, warn) {
7907
+ if (!resolvedId?.endsWith(".vue")) return;
7908
+ try {
7909
+ const { descriptor, errors } = parse(await readFile$1(resolvedId, "utf8"), { filename: resolvedId });
7910
+ if (errors.length > 0 || !descriptor.scriptSetup?.content) return;
7911
+ return extractStaticDefineOptionsName(descriptor.scriptSetup.content);
7912
+ } catch (error) {
7913
+ const message = error instanceof Error ? error.message : String(error);
7914
+ warn?.(`[Vue 编译] 解析 ${resolvedId} 的 defineOptions.name 失败:${message}`);
7915
+ return;
7916
+ }
7917
+ }
7918
+ function registerComponentName(result, tag, componentName) {
7919
+ if (!componentName) return;
7920
+ result.componentNameMap[tag] = componentName;
7921
+ result.componentNameMap[pascalToKebab(tag)] = componentName;
7922
+ }
7596
7923
  function collectTemplateComponentNames(template, filename, warn) {
7597
7924
  const warnHandler = resolveWarnHandler(warn);
7598
7925
  const tags = collectVueTemplateTags(template, {
@@ -7651,6 +7978,10 @@ async function collectScriptSetupUsingComponents(options) {
7651
7978
  from: removeExtensionDeep(importSource),
7652
7979
  resolvedId: importSource
7653
7980
  };
7981
+ if (!resolved?.resolvedId && isVueSfcSource(importSource) && importSource.startsWith(".")) resolved = {
7982
+ ...resolved ?? {},
7983
+ resolvedId: path.resolve(path.dirname(filename), importSource)
7984
+ };
7654
7985
  if (resolved?.from) {
7655
7986
  result.autoUsingComponentsMap[localName] = resolved.from;
7656
7987
  result.autoComponentMeta[localName] = resolved.from;
@@ -7659,6 +7990,7 @@ async function collectScriptSetupUsingComponents(options) {
7659
7990
  result.wevuComponentTags.add(localName);
7660
7991
  result.wevuComponentTags.add(pascalToKebab(localName));
7661
7992
  }
7993
+ registerComponentName(result, localName, await resolveVueSfcComponentName(resolved?.resolvedId, autoUsingComponents?.warn ?? compileOptions?.warn));
7662
7994
  }
7663
7995
  } catch (error) {
7664
7996
  const message = error instanceof Error ? error.message : String(error);
@@ -7687,13 +8019,17 @@ async function collectAutoImportWevuComponents(options) {
7687
8019
  result.wevuComponentTags.add(tag);
7688
8020
  if (resolved.name) result.wevuComponentTags.add(resolved.name);
7689
8021
  }
8022
+ const componentName = await resolveVueSfcComponentName(resolved.resolvedId, autoImportTags.warn ?? warn);
8023
+ registerComponentName(result, tag, componentName);
8024
+ if (resolved.name) registerComponentName(result, resolved.name, componentName);
7690
8025
  }
7691
8026
  }
7692
8027
  async function collectComponentSourceInfo(options) {
7693
8028
  const result = {
7694
8029
  autoUsingComponentsMap: {},
7695
8030
  autoComponentMeta: {},
7696
- wevuComponentTags: /* @__PURE__ */ new Set()
8031
+ wevuComponentTags: /* @__PURE__ */ new Set(),
8032
+ componentNameMap: {}
7697
8033
  };
7698
8034
  await collectScriptSetupUsingComponents({
7699
8035
  descriptor: options.descriptor,
@@ -8577,18 +8913,22 @@ async function compileVueFile(source, filename, options) {
8577
8913
  ...options?.template,
8578
8914
  propsAliases,
8579
8915
  propsDerivedKeys,
8916
+ scriptSetupBindings: scriptCompiled?.bindings,
8580
8917
  scopedSlotsRequireProps: true
8581
8918
  } : {
8582
8919
  ...options?.template,
8583
8920
  propsAliases,
8584
- propsDerivedKeys
8921
+ propsDerivedKeys,
8922
+ scriptSetupBindings: scriptCompiled?.bindings
8585
8923
  };
8586
8924
  const templateOptions = componentSourceInfo.wevuComponentTags.size ? {
8587
8925
  ...baseTemplateOptions,
8588
- wevuComponentTags: componentSourceInfo.wevuComponentTags
8926
+ wevuComponentTags: componentSourceInfo.wevuComponentTags,
8927
+ componentNameMap: componentSourceInfo.componentNameMap
8589
8928
  } : {
8590
8929
  ...baseTemplateOptions,
8591
- wevuComponentTags: []
8930
+ wevuComponentTags: [],
8931
+ componentNameMap: componentSourceInfo.componentNameMap
8592
8932
  };
8593
8933
  const templateCompiled = compileTemplatePhase(parsed.descriptor, filename, templateOptions, result);
8594
8934
  const scriptPhase = await compileScriptPhase(parsed.descriptor, parsed.descriptorForCompile, filename, options, autoUsingComponents, templateCompiled, parsed.isAppFile, componentSourceInfo, scriptCompiled);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@wevu/compiler",
3
3
  "type": "module",
4
- "version": "6.16.24",
4
+ "version": "6.16.25",
5
5
  "description": "wevu 编译器基础包,面向小程序模板的编译与转换",
6
6
  "author": "ice breaker <1324318532@qq.com>",
7
7
  "license": "MIT",
@@ -50,9 +50,9 @@
50
50
  "merge": "^2.1.1",
51
51
  "pathe": "^2.0.3",
52
52
  "vue": "^3.5.34",
53
- "@weapp-core/constants": "0.1.9",
53
+ "@weapp-core/constants": "0.1.10",
54
54
  "@weapp-core/shared": "3.0.4",
55
- "@weapp-vite/ast": "6.16.24",
55
+ "@weapp-vite/ast": "6.16.25",
56
56
  "rolldown-require": "2.0.17"
57
57
  },
58
58
  "publishConfig": {