@wevu/compiler 6.16.24 → 6.16.26

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,52 @@ 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 isCallTarget(node, parent) {
5747
+ return (t.isCallExpression(parent) || t.isOptionalCallExpression(parent) || t.isNewExpression(parent)) && parent.callee === node;
5748
+ }
5749
+ function rewriteTopLevelRefLikeAccess(ast, context) {
5750
+ traverse(ast, {
5751
+ AssignmentExpression(path) {
5752
+ const left = path.node.left;
5753
+ if (t.isIdentifier(left) && isScriptSetupRefLikeBinding(context, left.name)) path.node.left = buildCtxValueAccess(t.memberExpression(t.identifier("ctx"), t.identifier(left.name)));
5754
+ else if (t.isIdentifier(left) && isScriptSetupBinding(context, left.name)) path.node.left = t.memberExpression(t.identifier("ctx"), t.identifier(left.name));
5755
+ else if (isRefLikeCtxMember(left, context)) path.node.left = buildCtxValueAccess(left);
5756
+ },
5757
+ UpdateExpression(path) {
5758
+ const arg = path.node.argument;
5759
+ if (t.isIdentifier(arg) && isScriptSetupRefLikeBinding(context, arg.name)) path.node.argument = buildCtxValueAccess(t.memberExpression(t.identifier("ctx"), t.identifier(arg.name)));
5760
+ else if (t.isIdentifier(arg) && isScriptSetupBinding(context, arg.name)) path.node.argument = t.memberExpression(t.identifier("ctx"), t.identifier(arg.name));
5761
+ else if (isRefLikeCtxMember(arg, context)) path.node.argument = buildCtxValueAccess(arg);
5762
+ }
5763
+ });
5764
+ traverse(ast, { MemberExpression(path) {
5765
+ if (!isRefLikeCtxMember(path.node, context)) return;
5766
+ if (isValueMemberObject(path.node, path.parentPath?.node)) return;
5767
+ if (isCallTarget(path.node, path.parentPath?.node)) return;
5768
+ path.replaceWith(buildCtxValueAccess(path.node));
5769
+ path.skip();
5770
+ } });
5771
+ }
5696
5772
  function registerInlineExpression(exp, context) {
5697
5773
  const parsed = parseBabelExpressionFile(exp);
5698
5774
  if (!parsed) return null;
@@ -5708,6 +5784,7 @@ function registerInlineExpression(exp, context) {
5708
5784
  usedLocals.push(name);
5709
5785
  };
5710
5786
  rewriteExpressionAst(ast, locals, { markLocal });
5787
+ rewriteTopLevelRefLikeAccess(ast, context);
5711
5788
  const forAliases = collectForAliasMapping$1(context);
5712
5789
  const updatedStmt = ast.program.body[0];
5713
5790
  const updatedExpressionNode = updatedStmt && "expression" in updatedStmt ? updatedStmt.expression : null;
@@ -6523,6 +6600,7 @@ function collectElementAttributes(node, context, options) {
6523
6600
  else layoutHostKey = rawKey;
6524
6601
  continue;
6525
6602
  }
6603
+ 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
6604
  if (prop.name === "ref") {
6527
6605
  if (prop.value?.type === NodeTypes.TEXT) {
6528
6606
  const name = prop.value.content.trim();
@@ -6561,6 +6639,11 @@ function collectElementAttributes(node, context, options) {
6561
6639
  context.warnings.push("暂不支持动态 layout-host,已忽略该绑定。");
6562
6640
  continue;
6563
6641
  }
6642
+ 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:"))) {
6643
+ if (prop.arg.content.endsWith("-class") || prop.arg.content.endsWith(":class") || prop.arg.content.endsWith("-style") || prop.arg.content.endsWith(":style")) continue;
6644
+ context.warnings.push(`暂不支持动态 ${prop.arg.content},已忽略该绑定。`);
6645
+ continue;
6646
+ }
6564
6647
  if (prop.name === "bind" && prop.arg?.type === NodeTypes.SIMPLE_EXPRESSION && prop.arg.content === "class") {
6565
6648
  dynamicClassExp = getBindDirectiveExpression(prop) || void 0;
6566
6649
  continue;
@@ -6584,7 +6667,7 @@ function collectElementAttributes(node, context, options) {
6584
6667
  }
6585
6668
  if (mappedTagClass) staticClass = prependStaticClass(staticClass, mappedTagClass);
6586
6669
  if (templateRef) {
6587
- const className = `__wv-ref-${context.templateRefIndexSeed++}`;
6670
+ const className = `${WEVU_TEMPLATE_REF_CLASS_PREFIX}${context.templateRefIndexSeed++}`;
6588
6671
  staticClass = staticClass ? `${staticClass} ${className}` : className;
6589
6672
  context.templateRefs.push({
6590
6673
  selector: `.${className}`,
@@ -6779,7 +6862,8 @@ function buildSlotDeclaration(name, propsExp, children, context, options) {
6779
6862
  children,
6780
6863
  implicitDefault: options?.implicitDefault,
6781
6864
  conditionKind: options?.conditionKind,
6782
- condition: options?.condition
6865
+ condition: options?.condition,
6866
+ wrapper: options?.wrapper
6783
6867
  };
6784
6868
  }
6785
6869
  function createScopedSlotComponent(context, slotKey, props, children, transformNode, options) {
@@ -6828,7 +6912,8 @@ function createScopedSlotComponent(context, slotKey, props, children, transformN
6828
6912
  slotKey
6829
6913
  };
6830
6914
  }
6831
- function injectAttributeIntoOpeningTag(source, attr) {
6915
+ function injectAttributesIntoOpeningTag(source, attrs) {
6916
+ if (!attrs.length) return source;
6832
6917
  if (!source.startsWith("<") || source.startsWith("</") || source.startsWith("<!--")) return null;
6833
6918
  let tagNameEnd = 1;
6834
6919
  while (tagNameEnd < source.length) {
@@ -6837,7 +6922,7 @@ function injectAttributeIntoOpeningTag(source, attr) {
6837
6922
  tagNameEnd += 1;
6838
6923
  }
6839
6924
  if (tagNameEnd <= 1) return null;
6840
- return `${source.slice(0, tagNameEnd)} ${attr}${source.slice(tagNameEnd)}`;
6925
+ return `${source.slice(0, tagNameEnd)} ${attrs.join(" ")}${source.slice(tagNameEnd)}`;
6841
6926
  }
6842
6927
  function createSlotAttributeNode(sourceNode, attr) {
6843
6928
  const match = /^slot="([\s\S]*)"$/.exec(attr);
@@ -6854,22 +6939,119 @@ function createSlotAttributeNode(sourceNode, attr) {
6854
6939
  loc: sourceNode.loc
6855
6940
  };
6856
6941
  }
6857
- function injectSlotAttributeIntoElementNode(child, slotAttr, transformNode, context) {
6942
+ function injectSlotAttributeIntoElementNode(child, slotAttr, extraAttrs, transformNode, context) {
6858
6943
  if (child.type !== NodeTypes.ELEMENT || child.tag === "template") return null;
6859
6944
  const sourceNode = child;
6860
6945
  const slotAttribute = createSlotAttributeNode(sourceNode, slotAttr);
6861
6946
  if (!slotAttribute) return null;
6862
- return transformNode({
6947
+ return injectAttributesIntoOpeningTag(transformNode({
6863
6948
  ...sourceNode,
6864
6949
  props: [slotAttribute, ...sourceNode.props]
6865
- }, context);
6950
+ }, context), extraAttrs);
6866
6951
  }
6867
6952
  function isRenderableFallbackChild(child) {
6868
6953
  if (child.type === NodeTypes.COMMENT) return false;
6869
6954
  if (child.type === NodeTypes.TEXT) return child.content.trim().length > 0;
6870
6955
  return true;
6871
6956
  }
6872
- function renderSlotFallback(decl, context, transformNode) {
6957
+ function canInjectSlotAttributeIntoFallbackChild(child) {
6958
+ if (child.type !== NodeTypes.ELEMENT) return true;
6959
+ return child.tag !== "slot";
6960
+ }
6961
+ function matchesSlotFallbackWrapperMatcher(matcher, value) {
6962
+ if (!matcher) return true;
6963
+ if (!value) return false;
6964
+ if (Array.isArray(matcher)) return matcher.some((item) => matchesSlotFallbackWrapperMatcher(item, value));
6965
+ return typeof matcher === "string" ? matcher === value : matcher.test(value);
6966
+ }
6967
+ function normalizeSlotFallbackWrapperTag(tag, context) {
6968
+ const normalized = tag?.trim() || "view";
6969
+ if (normalized === "block") {
6970
+ context.warnings.push("slot fallback wrapper 不支持配置为 block,已回退为 view。");
6971
+ return "view";
6972
+ }
6973
+ return normalized;
6974
+ }
6975
+ function mergeSlotFallbackWrapperAttrs(base, override) {
6976
+ if (!base) return override;
6977
+ if (!override) return base;
6978
+ return {
6979
+ ...base,
6980
+ ...override
6981
+ };
6982
+ }
6983
+ function resolveSlotFallbackWrapper(context, info) {
6984
+ const resolved = {
6985
+ tag: normalizeSlotFallbackWrapperTag(context.slotFallbackWrapper.tag, context),
6986
+ attrs: context.slotFallbackWrapper.attrs,
6987
+ singleRootNoWrapper: context.slotFallbackWrapper.singleRootNoWrapper ?? context.slotSingleRootNoWrapper
6988
+ };
6989
+ for (const rule of context.slotFallbackWrapper.rules) if (matchesSlotFallbackWrapperMatcher(rule.component, info.component) && matchesSlotFallbackWrapperMatcher(rule.componentName, info.componentName) && matchesSlotFallbackWrapperMatcher(rule.slot, info.slot)) {
6990
+ if (rule.tag) resolved.tag = normalizeSlotFallbackWrapperTag(rule.tag, context);
6991
+ if (rule.attrs) resolved.attrs = mergeSlotFallbackWrapperAttrs(resolved.attrs, rule.attrs);
6992
+ if (rule.singleRootNoWrapper !== void 0) resolved.singleRootNoWrapper = rule.singleRootNoWrapper;
6993
+ }
6994
+ if (info.local?.tag) resolved.tag = normalizeSlotFallbackWrapperTag(info.local.tag, context);
6995
+ if (info.local?.staticClass !== void 0) resolved.staticClass = info.local.staticClass;
6996
+ if (info.local?.dynamicClassExp !== void 0) resolved.dynamicClassExp = info.local.dynamicClassExp;
6997
+ if (info.local?.staticStyle !== void 0) resolved.staticStyle = info.local.staticStyle;
6998
+ if (info.local?.dynamicStyleExp !== void 0) resolved.dynamicStyleExp = info.local.dynamicStyleExp;
6999
+ if (info.local?.singleRootNoWrapper !== void 0) resolved.singleRootNoWrapper = info.local.singleRootNoWrapper;
7000
+ return resolved;
7001
+ }
7002
+ function createStaticAttributeNode(name, value) {
7003
+ return {
7004
+ type: NodeTypes.ATTRIBUTE,
7005
+ name,
7006
+ nameLoc: void 0,
7007
+ value: {
7008
+ type: NodeTypes.TEXT,
7009
+ content: value,
7010
+ loc: void 0
7011
+ },
7012
+ loc: void 0
7013
+ };
7014
+ }
7015
+ function renderSlotFallbackWrapperAttrs(wrapper, context) {
7016
+ const attrs = [];
7017
+ for (const [name, value] of Object.entries(wrapper.attrs ?? {})) {
7018
+ if (name === "class" && (wrapper.staticClass !== void 0 || wrapper.dynamicClassExp !== void 0)) continue;
7019
+ if (name === "style" && (wrapper.staticStyle !== void 0 || wrapper.dynamicStyleExp !== void 0)) continue;
7020
+ const attr = transformAttribute(createStaticAttributeNode(name, value), context);
7021
+ if (attr) attrs.push(attr);
7022
+ }
7023
+ const classAttr = renderClassAttribute(wrapper.staticClass, wrapper.dynamicClassExp, context);
7024
+ if (classAttr) attrs.push(classAttr);
7025
+ const styleAttr = renderStyleAttribute(wrapper.staticStyle, wrapper.dynamicStyleExp, void 0, context);
7026
+ if (styleAttr) attrs.push(styleAttr);
7027
+ return attrs;
7028
+ }
7029
+ function renderPlainSlotOutlet(node, context, transformNode) {
7030
+ const slotNameInfo = resolveSlotNameFromSlotElement(node);
7031
+ const hasScopeBindings = node.props.some((prop) => {
7032
+ if (prop.type === NodeTypes.DIRECTIVE && prop.name === "bind") return prop.arg?.type !== NodeTypes.SIMPLE_EXPRESSION || prop.arg.content !== "name";
7033
+ return false;
7034
+ });
7035
+ if (hasScopeBindings) context.warnings.push("已禁用作用域插槽参数,插槽绑定将被忽略。");
7036
+ const fallbackContent = node.children.map((child) => transformNode(child, context)).join("");
7037
+ const slotAttrs = [];
7038
+ const nameAttr = renderSlotNameAttribute(slotNameInfo, context, "name");
7039
+ if (nameAttr) slotAttrs.push(nameAttr);
7040
+ const slotAttrString = slotAttrs.length ? ` ${slotAttrs.join(" ")}` : "";
7041
+ if (!hasScopeBindings && fallbackContent) {
7042
+ const slotPresentExp = createSlotPresenceExpression(slotNameInfo);
7043
+ if (slotPresentExp) {
7044
+ const slotTag = `<slot${slotAttrString} />`;
7045
+ return `${context.platform.wrapIf(slotPresentExp, slotTag, (exp) => renderMustache(exp, context))}${context.platform.wrapElse(fallbackContent)}`;
7046
+ }
7047
+ }
7048
+ return fallbackContent ? `<slot${slotAttrString}>${fallbackContent}</slot>` : `<slot${slotAttrString} />`;
7049
+ }
7050
+ function transformFallbackChild(child, context, transformNode) {
7051
+ if (child.type === NodeTypes.ELEMENT && child.tag === "slot") return renderPlainSlotOutlet(child, context, transformNode);
7052
+ return transformNode(child, context);
7053
+ }
7054
+ function renderSlotFallback(decl, context, transformNode, options) {
6873
7055
  const slotAttr = renderSlotNameAttribute(decl.name, context, "slot");
6874
7056
  const wrapCondition = (content) => {
6875
7057
  if (decl.conditionKind === "else") return context.platform.wrapElse(content);
@@ -6884,17 +7066,31 @@ function renderSlotFallback(decl, context, transformNode) {
6884
7066
  }
6885
7067
  const renderableChildren = decl.children.filter(isRenderableFallbackChild);
6886
7068
  if (!renderableChildren.length) return "";
6887
- if (!context.slotSingleRootNoWrapper) {
6888
- const rawContent = decl.children.map((child) => transformNode(child, context)).join("");
7069
+ const staticSlotName = resolveSlotStaticName(decl.name);
7070
+ const wrapper = resolveSlotFallbackWrapper(context, {
7071
+ component: options?.component,
7072
+ componentName: options?.componentName,
7073
+ slot: staticSlotName,
7074
+ local: {
7075
+ ...options?.wrapper,
7076
+ ...decl.wrapper
7077
+ }
7078
+ });
7079
+ const wrapperAttrs = renderSlotFallbackWrapperAttrs(wrapper, context);
7080
+ const wrapperAttrString = wrapperAttrs.length ? ` ${wrapperAttrs.join(" ")}` : "";
7081
+ if (!wrapper.singleRootNoWrapper) {
7082
+ const rawContent = decl.children.map((child) => transformFallbackChild(child, context, transformNode)).join("");
6889
7083
  if (!rawContent) return "";
6890
- return wrapCondition(`<view ${slotAttr}>${rawContent}</view>`);
7084
+ return wrapCondition(`<${wrapper.tag} ${slotAttr}${wrapperAttrString}>${rawContent}</${wrapper.tag}>`);
6891
7085
  }
6892
7086
  if (renderableChildren.length === 1) {
6893
7087
  const child = renderableChildren[0];
6894
- const projected = child.type === NodeTypes.ELEMENT && isStructuralDirective(child).type ? injectSlotAttributeIntoElementNode(child, slotAttr, transformNode, context) : injectAttributeIntoOpeningTag(transformNode(child, context), slotAttr);
7088
+ let projected = null;
7089
+ if (canInjectSlotAttributeIntoFallbackChild(child)) projected = child.type === NodeTypes.ELEMENT && isStructuralDirective(child).type ? injectSlotAttributeIntoElementNode(child, slotAttr, wrapperAttrs, transformNode, context) : injectAttributesIntoOpeningTag(transformNode(child, context), [slotAttr, ...wrapperAttrs]);
6895
7090
  if (projected) return wrapCondition(projected);
6896
7091
  }
6897
- return wrapCondition(`<view ${slotAttr}>${renderableChildren.map((child) => transformNode(child, context)).join("")}</view>`);
7092
+ const content = renderableChildren.map((child) => transformFallbackChild(child, context, transformNode)).join("");
7093
+ return wrapCondition(`<${wrapper.tag} ${slotAttr}${wrapperAttrString}>${content}</${wrapper.tag}>`);
6898
7094
  }
6899
7095
  function transformSlotElement(node, context, transformNode) {
6900
7096
  if (isScopedSlotsDisabled(context)) return transformSlotElementPlain(node, context, transformNode);
@@ -6913,6 +7109,7 @@ function transformSlotElement(node, context, transformNode) {
6913
7109
  else if (!slotPropsExp) slotTag = `<slot${slotAttrString}>${fallbackContent}</slot>`;
6914
7110
  }
6915
7111
  if (!slotPropsExp && (context.scopedSlotsRequireProps || slotNameInfo.type !== "default" && context.scopedSlotsCompiler !== "augmented")) return slotTag;
7112
+ const hasScopeBindings = Boolean(slotPropsExp);
6916
7113
  const genericKey = `scoped-slots-${resolveSlotKey(context, slotNameInfo)}`;
6917
7114
  context.componentGenerics[genericKey] = true;
6918
7115
  slotPropsExp = slotPropsExp ?? "[]";
@@ -6923,30 +7120,12 @@ function transformSlotElement(node, context, transformNode) {
6923
7120
  ];
6924
7121
  if (context.slotMultipleInstance) scopedAttrs.push(`${WEVU_SLOT_SCOPE_ATTR}="${renderMustache(WEVU_SLOT_SCOPE_KEY, context)}"`);
6925
7122
  const scopedTag = `<${genericKey}${scopedAttrs.length ? ` ${scopedAttrs.join(" ")}` : ""} />`;
6926
- const projectedContent = `${slotTag}${scopedTag}`;
7123
+ const projectedContent = hasScopeBindings ? scopedTag : `${scopedTag}${context.platform.wrapElse(slotTag)}`;
6927
7124
  if (fallbackContent && slotPresentExp) return `${context.platform.wrapIf(slotPresentExp, projectedContent, (exp) => renderMustache(exp, context))}${context.platform.wrapElse(fallbackContent)}`;
6928
7125
  return projectedContent;
6929
7126
  }
6930
7127
  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} />`;
7128
+ return renderPlainSlotOutlet(node, context, transformNode);
6950
7129
  }
6951
7130
  //#endregion
6952
7131
  //#region src/plugins/vue/compiler/template/elements/tag-component.ts
@@ -7022,11 +7201,82 @@ function pushSlotNamesAttr(attrs, slotNames, context) {
7022
7201
  function shouldExposePlainSlotPresence(node) {
7023
7202
  return node.tag === "component";
7024
7203
  }
7025
- function renderPlainSlotContentInSourceOrder(renderItems, plainSlotDeclarations, implicitDefaultDeclaration, context, transformNode) {
7204
+ function normalizeBooleanAttributeValue(value) {
7205
+ if (value === void 0 || value === "") return true;
7206
+ if (value === "true") return true;
7207
+ if (value === "false") return false;
7208
+ }
7209
+ function isSlotFallbackWrapperName(name, baseName, slotName) {
7210
+ return name === baseName || slotName !== void 0 && (name === `${baseName}-${slotName}` || name === `${baseName}:${slotName}`);
7211
+ }
7212
+ function isSlotFallbackWrapperAttr(name, baseName, slotName, attrName) {
7213
+ if (!attrName) return isSlotFallbackWrapperName(name, baseName, slotName);
7214
+ return name === `${baseName}-${attrName}` || slotName !== void 0 && (name === `${baseName}-${slotName}-${attrName}` || name === `${baseName}:${slotName}:${attrName}`);
7215
+ }
7216
+ function resolveLocalSlotFallbackWrapperConfig(node, context, slotName) {
7217
+ const wrapper = {};
7218
+ let hasConfig = false;
7219
+ for (const prop of node.props) if (prop.type === NodeTypes.ATTRIBUTE) {
7220
+ if (isSlotFallbackWrapperAttr(prop.name, "slot-wrapper", slotName)) {
7221
+ const tag = prop.value?.type === NodeTypes.TEXT ? prop.value.content.trim() : "";
7222
+ if (tag) {
7223
+ wrapper.tag = tag;
7224
+ hasConfig = true;
7225
+ } else context.warnings.push("slot-wrapper 需要提供非空标签名,已忽略该配置。");
7226
+ } else if (isSlotFallbackWrapperAttr(prop.name, "slot-single-root-no-wrapper", slotName)) {
7227
+ const value = normalizeBooleanAttributeValue(prop.value?.type === NodeTypes.TEXT ? prop.value.content.trim() : void 0);
7228
+ if (value === void 0) context.warnings.push("slot-single-root-no-wrapper 仅支持 true / false 静态值,已忽略该配置。");
7229
+ else {
7230
+ wrapper.singleRootNoWrapper = value;
7231
+ hasConfig = true;
7232
+ }
7233
+ } else if (isSlotFallbackWrapperAttr(prop.name, "slot-wrapper", slotName, "class")) {
7234
+ const value = prop.value?.type === NodeTypes.TEXT ? prop.value.content.trim() : "";
7235
+ if (value) {
7236
+ wrapper.staticClass = value;
7237
+ hasConfig = true;
7238
+ }
7239
+ } else if (isSlotFallbackWrapperAttr(prop.name, "slot-wrapper", slotName, "style")) {
7240
+ const value = prop.value?.type === NodeTypes.TEXT ? prop.value.content.trim() : "";
7241
+ if (value) {
7242
+ wrapper.staticStyle = value;
7243
+ hasConfig = true;
7244
+ }
7245
+ }
7246
+ } else if (prop.type === NodeTypes.DIRECTIVE && prop.name === "bind" && prop.arg?.type === NodeTypes.SIMPLE_EXPRESSION) {
7247
+ if (isSlotFallbackWrapperAttr(prop.arg.content, "slot-wrapper", slotName, "class")) {
7248
+ const exp = getBindDirectiveExpression(prop);
7249
+ if (exp) {
7250
+ wrapper.dynamicClassExp = exp;
7251
+ hasConfig = true;
7252
+ }
7253
+ } else if (isSlotFallbackWrapperAttr(prop.arg.content, "slot-wrapper", slotName, "style")) {
7254
+ const exp = getBindDirectiveExpression(prop);
7255
+ if (exp) {
7256
+ wrapper.dynamicStyleExp = exp;
7257
+ hasConfig = true;
7258
+ }
7259
+ }
7260
+ }
7261
+ return hasConfig ? wrapper : void 0;
7262
+ }
7263
+ function mergeLocalSlotFallbackWrapperConfig(base, override) {
7264
+ if (!base) return override;
7265
+ if (!override) return base;
7266
+ return {
7267
+ ...base,
7268
+ ...override
7269
+ };
7270
+ }
7271
+ function renderPlainSlotContentInSourceOrder(renderItems, plainSlotDeclarations, implicitDefaultDeclaration, ownerComponent, ownerComponentName, ownerWrapper, context, transformNode) {
7026
7272
  const plainSlots = new Set(plainSlotDeclarations);
7027
7273
  const shouldRenderImplicitDefault = implicitDefaultDeclaration ? plainSlots.has(implicitDefaultDeclaration) : false;
7028
7274
  return renderItems.map((item) => {
7029
- if (item.type === "declaration") return plainSlots.has(item.declaration) ? renderSlotFallback(item.declaration, context, transformNode) : "";
7275
+ if (item.type === "declaration") return plainSlots.has(item.declaration) ? renderSlotFallback(item.declaration, context, transformNode, {
7276
+ component: ownerComponent,
7277
+ componentName: ownerComponentName,
7278
+ wrapper: ownerWrapper
7279
+ }) : "";
7030
7280
  return shouldRenderImplicitDefault ? transformNode(item.child, context) : "";
7031
7281
  }).join("");
7032
7282
  }
@@ -7042,6 +7292,7 @@ function transformComponentWithSlots(node, context, transformNode, options) {
7042
7292
  const extraAttrs = options?.extraAttrs ?? [];
7043
7293
  const slotDeclarations = [];
7044
7294
  const slotDirective = findSlotDirective(node);
7295
+ const ownerWrapper = resolveLocalSlotFallbackWrapperConfig(node, context);
7045
7296
  const nonTemplateChildren = [];
7046
7297
  const renderItems = [];
7047
7298
  for (const child of node.children) {
@@ -7050,7 +7301,10 @@ function transformComponentWithSlots(node, context, transformNode, options) {
7050
7301
  if (templateSlot) {
7051
7302
  const slotName = resolveSlotNameFromDirective(templateSlot);
7052
7303
  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);
7304
+ const declaration = buildSlotDeclaration(slotName, templateSlot.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? templateSlot.exp.content : void 0, child.children, context, {
7305
+ ...templateSlotCondition,
7306
+ wrapper: mergeLocalSlotFallbackWrapperConfig(resolveLocalSlotFallbackWrapperConfig(node, context, slotName.type === "static" ? slotName.value : void 0), resolveLocalSlotFallbackWrapperConfig(child, context))
7307
+ });
7054
7308
  slotDeclarations.push(declaration);
7055
7309
  renderItems.push({
7056
7310
  type: "declaration",
@@ -7070,7 +7324,7 @@ function transformComponentWithSlots(node, context, transformNode, options) {
7070
7324
  if (slotDirective) {
7071
7325
  if (slotDeclarations.length) context.warnings.push("组件上的 v-slot 与 <template v-slot> 不能同时使用;仅使用组件上的 v-slot。");
7072
7326
  slotDeclarations.length = 0;
7073
- slotDeclarations.push(buildSlotDeclaration(resolveSlotNameFromDirective(slotDirective), slotDirective.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? slotDirective.exp.content : void 0, node.children, context));
7327
+ slotDeclarations.push(buildSlotDeclaration(resolveSlotNameFromDirective(slotDirective), slotDirective.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? slotDirective.exp.content : void 0, node.children, context, { wrapper: ownerWrapper }));
7074
7328
  } 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
7329
  else {
7076
7330
  implicitDefaultDeclaration = buildSlotDeclaration({ type: "default" }, void 0, defaultSlotChildren, context, { implicitDefault: true });
@@ -7100,6 +7354,7 @@ function transformComponentWithSlots(node, context, transformNode, options) {
7100
7354
  else plainSlotDeclarations.push(decl);
7101
7355
  const slotNames = [];
7102
7356
  const slotGenericAttrs = [];
7357
+ const ownerComponentName = context.componentNameMap?.[node.tag];
7103
7358
  for (const decl of scopedSlotDeclarations) {
7104
7359
  const slotKey = resolveSlotKey(context, decl.name);
7105
7360
  const { componentName } = createScopedSlotComponent(context, slotKey, decl.props, decl.children, transformNode, { hostComponentName: node.tag });
@@ -7132,13 +7387,18 @@ function transformComponentWithSlots(node, context, transformNode, options) {
7132
7387
  }
7133
7388
  const attrString = mergedAttrs.length ? ` ${mergedAttrs.join(" ")}` : "";
7134
7389
  const { tag } = node;
7135
- const plainSlotContent = slotDirective ? plainSlotDeclarations.map((decl) => renderSlotFallback(decl, context, transformNode)).join("") : renderPlainSlotContentInSourceOrder(renderItems, plainSlotDeclarations, implicitDefaultDeclaration, context, transformNode);
7390
+ const plainSlotContent = slotDirective ? plainSlotDeclarations.map((decl) => renderSlotFallback(decl, context, transformNode, {
7391
+ component: node.tag,
7392
+ componentName: ownerComponentName,
7393
+ wrapper: ownerWrapper
7394
+ })).join("") : renderPlainSlotContentInSourceOrder(renderItems, plainSlotDeclarations, implicitDefaultDeclaration, node.tag, ownerComponentName, ownerWrapper, context, transformNode);
7136
7395
  return plainSlotContent ? `<${tag}${attrString}>${plainSlotContent}</${tag}>` : `<${tag}${attrString} />`;
7137
7396
  }
7138
7397
  function transformComponentWithSlotsFallback(node, context, transformNode, options) {
7139
7398
  const extraAttrs = options?.extraAttrs ?? [];
7140
7399
  const slotDeclarations = [];
7141
7400
  const slotDirective = findSlotDirective(node);
7401
+ const ownerWrapper = resolveLocalSlotFallbackWrapperConfig(node, context);
7142
7402
  const nonTemplateChildren = [];
7143
7403
  const renderItems = [];
7144
7404
  for (const child of node.children) {
@@ -7147,7 +7407,10 @@ function transformComponentWithSlotsFallback(node, context, transformNode, optio
7147
7407
  if (templateSlot) {
7148
7408
  const slotName = resolveSlotNameFromDirective(templateSlot);
7149
7409
  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);
7410
+ const declaration = buildSlotDeclaration(slotName, templateSlot.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? templateSlot.exp.content : void 0, child.children, context, {
7411
+ ...templateSlotCondition,
7412
+ wrapper: mergeLocalSlotFallbackWrapperConfig(resolveLocalSlotFallbackWrapperConfig(node, context, slotName.type === "static" ? slotName.value : void 0), resolveLocalSlotFallbackWrapperConfig(child, context))
7413
+ });
7151
7414
  slotDeclarations.push(declaration);
7152
7415
  renderItems.push({
7153
7416
  type: "declaration",
@@ -7167,7 +7430,7 @@ function transformComponentWithSlotsFallback(node, context, transformNode, optio
7167
7430
  if (slotDirective) {
7168
7431
  if (slotDeclarations.length) context.warnings.push("组件上的 v-slot 与 <template v-slot> 不能同时使用;仅使用组件上的 v-slot。");
7169
7432
  slotDeclarations.length = 0;
7170
- slotDeclarations.push(buildSlotDeclaration(resolveSlotNameFromDirective(slotDirective), slotDirective.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? slotDirective.exp.content : void 0, node.children, context));
7433
+ slotDeclarations.push(buildSlotDeclaration(resolveSlotNameFromDirective(slotDirective), slotDirective.exp?.type === NodeTypes.SIMPLE_EXPRESSION ? slotDirective.exp.content : void 0, node.children, context, { wrapper: ownerWrapper }));
7171
7434
  } 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
7435
  else {
7173
7436
  implicitDefaultDeclaration = buildSlotDeclaration({ type: "default" }, void 0, defaultSlotChildren, context);
@@ -7188,7 +7451,11 @@ function transformComponentWithSlotsFallback(node, context, transformNode, optio
7188
7451
  return children ? `<${tag}${attrString}>${children}</${tag}>` : `<${tag}${attrString} />`;
7189
7452
  }
7190
7453
  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);
7454
+ const renderedSlots = slotDirective ? slotDeclarations.map((decl) => renderSlotFallback(decl, context, transformNode, {
7455
+ component: node.tag,
7456
+ componentName: context.componentNameMap?.[node.tag],
7457
+ wrapper: ownerWrapper
7458
+ })).join("") : renderPlainSlotContentInSourceOrder(renderItems, slotDeclarations, implicitDefaultDeclaration, node.tag, context.componentNameMap?.[node.tag], ownerWrapper, context, transformNode);
7192
7459
  const { attrs } = collectElementAttributes(node, context, {
7193
7460
  skipSlotDirective: true,
7194
7461
  forInfo: options?.forInfo,
@@ -7260,7 +7527,7 @@ function resolveConditionExpression$1(rawExpValue, context, hint) {
7260
7527
  return (context.rewriteScopedSlot || shouldFallbackToRuntimeBinding(rawExpValue) ? registerRuntimeBindingExpression(rawExpValue, context, { hint }) : null) ?? normalizeWxmlExpressionWithContext(rawExpValue, context);
7261
7528
  }
7262
7529
  function resolveListExpression(rawExpValue, context, hint) {
7263
- return (shouldFallbackToRuntimeBinding(rawExpValue) ? registerRuntimeBindingExpression(rawExpValue, context, { hint }) : null) ?? normalizeWxmlExpressionWithContext(rawExpValue, context);
7530
+ return (context.rewriteScopedSlot || shouldFallbackToRuntimeBinding(rawExpValue) ? registerRuntimeBindingExpression(rawExpValue, context, { hint }) : null) ?? normalizeWxmlExpressionWithContext(rawExpValue, context);
7264
7531
  }
7265
7532
  function transformIfElement(node, context, transformNode) {
7266
7533
  const renderTemplateMustache = (exp) => renderMustache(exp, context);
@@ -7327,12 +7594,17 @@ function transformForElement(node, context, transformNode) {
7327
7594
  };
7328
7595
  const extraAttrs = listExp ? context.platform.forAttrs(listExp, renderTemplateMustache, forInfo.item, forInfo.index) : [];
7329
7596
  if (elementWithoutFor.tag === "slot") {
7597
+ const keyDirective = elementWithoutFor.props.find((prop) => {
7598
+ return prop.type === NodeTypes.DIRECTIVE && prop.name === "bind" && prop.arg?.type === NodeTypes.SIMPLE_EXPRESSION && prop.arg.content === "key";
7599
+ });
7330
7600
  const content = transformSlotElement({
7331
7601
  ...elementWithoutFor,
7332
7602
  props: elementWithoutFor.props.filter((prop) => {
7333
- return !(prop.type === NodeTypes.DIRECTIVE && prop.name === "bind" && prop.arg?.type === NodeTypes.SIMPLE_EXPRESSION && prop.arg.content === "key");
7603
+ return prop !== keyDirective;
7334
7604
  })
7335
7605
  }, context, transformNode);
7606
+ const keyAttr = keyDirective ? transformBindDirective(keyDirective, context, forInfo) : null;
7607
+ if (keyAttr) extraAttrs.push(keyAttr);
7336
7608
  const attrString = extraAttrs.length ? ` ${extraAttrs.join(" ")}` : "";
7337
7609
  return attrString ? `<block${attrString}>${content}</block>` : content;
7338
7610
  }
@@ -7494,6 +7766,18 @@ const HTML_VOID_TAGS = new Set([
7494
7766
  "track",
7495
7767
  "wbr"
7496
7768
  ]);
7769
+ function resolveSlotFallbackWrapperConfig(config) {
7770
+ if (typeof config === "string") return {
7771
+ tag: config || "view",
7772
+ rules: []
7773
+ };
7774
+ return {
7775
+ tag: config?.tag || "view",
7776
+ attrs: config?.attrs,
7777
+ singleRootNoWrapper: config?.singleRootNoWrapper,
7778
+ rules: config?.rules ?? []
7779
+ };
7780
+ }
7497
7781
  /**
7498
7782
  * 将 Vue 模板编译为 WXML。
7499
7783
  */
@@ -7504,6 +7788,7 @@ function compileVueTemplateToWxml(template, filename, options) {
7504
7788
  const wxsExtension = options?.wxsExtension;
7505
7789
  const scopedSlotsRequireProps = options?.scopedSlotsRequireProps ?? options?.scopedSlotsCompiler !== "augmented";
7506
7790
  const slotSingleRootNoWrapper = options?.slotSingleRootNoWrapper ?? false;
7791
+ const slotFallbackWrapper = resolveSlotFallbackWrapperConfig(options?.slotFallbackWrapper);
7507
7792
  const htmlTagToWxmlMap = resolveHtmlTagToWxmlMap(options?.htmlTagToWxml);
7508
7793
  try {
7509
7794
  const ast = parse$1(template, {
@@ -7519,14 +7804,17 @@ function compileVueTemplateToWxml(template, filename, options) {
7519
7804
  platform: options?.platform ?? getMiniProgramTemplatePlatform(),
7520
7805
  propsAliases: options?.propsAliases,
7521
7806
  propsDerivedKeys: options?.propsDerivedKeys,
7807
+ scriptSetupBindings: options?.scriptSetupBindings,
7522
7808
  htmlTagToWxmlMap,
7523
7809
  htmlTagToWxmlTagClass: options?.htmlTagToWxmlTagClass ?? true,
7524
7810
  scopedSlotsCompiler: options?.scopedSlotsCompiler ?? "auto",
7525
7811
  scopedSlotsRequireProps,
7526
7812
  slotSingleRootNoWrapper,
7813
+ slotFallbackWrapper,
7527
7814
  slotMultipleInstance: options?.slotMultipleInstance ?? true,
7528
7815
  scopedSlotComponents: [],
7529
7816
  componentGenerics: {},
7817
+ componentNameMap: options?.componentNameMap,
7530
7818
  scopeStack: [],
7531
7819
  slotPropStack: [],
7532
7820
  rewriteScopedSlot: false,
@@ -7593,6 +7881,49 @@ function isVueSfcSource(source) {
7593
7881
  function pascalToKebab(name) {
7594
7882
  return name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").toLowerCase();
7595
7883
  }
7884
+ function extractStringPropertyFromObject(node, keyName) {
7885
+ for (const property of node.properties) {
7886
+ if (!t.isObjectProperty(property)) continue;
7887
+ const key = property.key;
7888
+ if (!(t.isIdentifier(key) ? key.name === keyName : t.isStringLiteral(key) ? key.value === keyName : false) || !t.isStringLiteral(property.value)) continue;
7889
+ return property.value.value;
7890
+ }
7891
+ }
7892
+ function extractStaticDefineOptionsName(scriptSetupContent) {
7893
+ let ast;
7894
+ try {
7895
+ ast = parse$3(scriptSetupContent, BABEL_TS_MODULE_PARSER_OPTIONS);
7896
+ } catch {
7897
+ return;
7898
+ }
7899
+ let componentName;
7900
+ traverse(ast, { CallExpression(path) {
7901
+ if (componentName) return;
7902
+ const callee = path.node.callee;
7903
+ if (!t.isIdentifier(callee, { name: "defineOptions" })) return;
7904
+ const arg = path.node.arguments[0];
7905
+ if (!t.isObjectExpression(arg)) return;
7906
+ componentName = extractStringPropertyFromObject(arg, "name");
7907
+ } });
7908
+ return componentName;
7909
+ }
7910
+ async function resolveVueSfcComponentName(resolvedId, warn) {
7911
+ if (!resolvedId?.endsWith(".vue")) return;
7912
+ try {
7913
+ const { descriptor, errors } = parse(await readFile$1(resolvedId, "utf8"), { filename: resolvedId });
7914
+ if (errors.length > 0 || !descriptor.scriptSetup?.content) return;
7915
+ return extractStaticDefineOptionsName(descriptor.scriptSetup.content);
7916
+ } catch (error) {
7917
+ const message = error instanceof Error ? error.message : String(error);
7918
+ warn?.(`[Vue 编译] 解析 ${resolvedId} 的 defineOptions.name 失败:${message}`);
7919
+ return;
7920
+ }
7921
+ }
7922
+ function registerComponentName(result, tag, componentName) {
7923
+ if (!componentName) return;
7924
+ result.componentNameMap[tag] = componentName;
7925
+ result.componentNameMap[pascalToKebab(tag)] = componentName;
7926
+ }
7596
7927
  function collectTemplateComponentNames(template, filename, warn) {
7597
7928
  const warnHandler = resolveWarnHandler(warn);
7598
7929
  const tags = collectVueTemplateTags(template, {
@@ -7651,6 +7982,10 @@ async function collectScriptSetupUsingComponents(options) {
7651
7982
  from: removeExtensionDeep(importSource),
7652
7983
  resolvedId: importSource
7653
7984
  };
7985
+ if (!resolved?.resolvedId && isVueSfcSource(importSource) && importSource.startsWith(".")) resolved = {
7986
+ ...resolved ?? {},
7987
+ resolvedId: path.resolve(path.dirname(filename), importSource)
7988
+ };
7654
7989
  if (resolved?.from) {
7655
7990
  result.autoUsingComponentsMap[localName] = resolved.from;
7656
7991
  result.autoComponentMeta[localName] = resolved.from;
@@ -7659,6 +7994,7 @@ async function collectScriptSetupUsingComponents(options) {
7659
7994
  result.wevuComponentTags.add(localName);
7660
7995
  result.wevuComponentTags.add(pascalToKebab(localName));
7661
7996
  }
7997
+ registerComponentName(result, localName, await resolveVueSfcComponentName(resolved?.resolvedId, autoUsingComponents?.warn ?? compileOptions?.warn));
7662
7998
  }
7663
7999
  } catch (error) {
7664
8000
  const message = error instanceof Error ? error.message : String(error);
@@ -7687,13 +8023,17 @@ async function collectAutoImportWevuComponents(options) {
7687
8023
  result.wevuComponentTags.add(tag);
7688
8024
  if (resolved.name) result.wevuComponentTags.add(resolved.name);
7689
8025
  }
8026
+ const componentName = await resolveVueSfcComponentName(resolved.resolvedId, autoImportTags.warn ?? warn);
8027
+ registerComponentName(result, tag, componentName);
8028
+ if (resolved.name) registerComponentName(result, resolved.name, componentName);
7690
8029
  }
7691
8030
  }
7692
8031
  async function collectComponentSourceInfo(options) {
7693
8032
  const result = {
7694
8033
  autoUsingComponentsMap: {},
7695
8034
  autoComponentMeta: {},
7696
- wevuComponentTags: /* @__PURE__ */ new Set()
8035
+ wevuComponentTags: /* @__PURE__ */ new Set(),
8036
+ componentNameMap: {}
7697
8037
  };
7698
8038
  await collectScriptSetupUsingComponents({
7699
8039
  descriptor: options.descriptor,
@@ -8577,18 +8917,22 @@ async function compileVueFile(source, filename, options) {
8577
8917
  ...options?.template,
8578
8918
  propsAliases,
8579
8919
  propsDerivedKeys,
8920
+ scriptSetupBindings: scriptCompiled?.bindings,
8580
8921
  scopedSlotsRequireProps: true
8581
8922
  } : {
8582
8923
  ...options?.template,
8583
8924
  propsAliases,
8584
- propsDerivedKeys
8925
+ propsDerivedKeys,
8926
+ scriptSetupBindings: scriptCompiled?.bindings
8585
8927
  };
8586
8928
  const templateOptions = componentSourceInfo.wevuComponentTags.size ? {
8587
8929
  ...baseTemplateOptions,
8588
- wevuComponentTags: componentSourceInfo.wevuComponentTags
8930
+ wevuComponentTags: componentSourceInfo.wevuComponentTags,
8931
+ componentNameMap: componentSourceInfo.componentNameMap
8589
8932
  } : {
8590
8933
  ...baseTemplateOptions,
8591
- wevuComponentTags: []
8934
+ wevuComponentTags: [],
8935
+ componentNameMap: componentSourceInfo.componentNameMap
8592
8936
  };
8593
8937
  const templateCompiled = compileTemplatePhase(parsed.descriptor, filename, templateOptions, result);
8594
8938
  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.26",
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.26",
56
56
  "rolldown-require": "2.0.17"
57
57
  },
58
58
  "publishConfig": {