@wevu/compiler 0.0.6 → 0.1.0

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
@@ -346,6 +346,7 @@ declare function getClassStyleWxsSource(options?: ClassStyleWxsSourceOptions): s
346
346
  interface ClassStyleHelperNames {
347
347
  normalizeClassName: string;
348
348
  normalizeStyleName: string;
349
+ unrefName?: string;
349
350
  }
350
351
  declare function buildClassStyleComputedCode(bindings: ClassStyleBinding[], helpers: ClassStyleHelperNames): string | null;
351
352
  //#endregion
package/dist/index.mjs CHANGED
@@ -628,10 +628,16 @@ function getClassStyleWxsSource(options = {}) {
628
628
  "}"
629
629
  ] : [
630
630
  "function isArray(value) {",
631
- " if (typeof Array !== 'undefined' && Array.isArray) {",
632
- " return Array.isArray(value)",
631
+ " if (!value) {",
632
+ " return false",
633
+ " }",
634
+ " if (typeof Array !== 'undefined' && Array.isArray && Array.isArray(value)) {",
635
+ " return true",
633
636
  " }",
634
- " return value && typeof value.length === 'number' && typeof value.splice === 'function'",
637
+ " if (toString && toString.call(value) === '[object Array]') {",
638
+ " return true",
639
+ " }",
640
+ " return typeof value.length === 'number' && typeof value.join === 'function'",
635
641
  "}"
636
642
  ];
637
643
  const hyphenateUpperCaseLine = isSjs ? " res += str.charAt(i).toLowerCase()" : " res += String.fromCharCode(code + 32)";
@@ -644,10 +650,13 @@ function getClassStyleWxsSource(options = {}) {
644
650
  ...isArrayFunctionLines,
645
651
  "",
646
652
  "function getObjectKeys(obj) {",
647
- " if (!objectCtor || !objectCtor.keys) {",
648
- " return null",
653
+ " if (objectCtor && objectCtor.keys) {",
654
+ " return objectCtor.keys(obj)",
655
+ " }",
656
+ " if (objectCtor && objectCtor.getOwnPropertyNames) {",
657
+ " return objectCtor.getOwnPropertyNames(obj)",
649
658
  " }",
650
- " return objectCtor.keys(obj)",
659
+ " return null",
651
660
  "}",
652
661
  "",
653
662
  "function isWordCharCode(code) {",
@@ -1524,6 +1533,36 @@ function mergeJsExpressionParts(parts) {
1524
1533
  if (parts.length === 1) return parts[0];
1525
1534
  return t.arrayExpression(parts);
1526
1535
  }
1536
+ function unwrapTsExpression(node) {
1537
+ if (t.isTSAsExpression(node) || t.isTSNonNullExpression(node) || t.isTSTypeAssertion(node)) return unwrapTsExpression(node.expression);
1538
+ return node;
1539
+ }
1540
+ function shouldPreferJsClassStyleRuntime(exp) {
1541
+ const ast = parseBabelExpression(exp);
1542
+ if (!ast) return true;
1543
+ const visit = (node) => {
1544
+ const current = unwrapTsExpression(node);
1545
+ if (t.isIdentifier(current) || t.isMemberExpression(current) || t.isOptionalMemberExpression(current) || t.isCallExpression(current) || t.isOptionalCallExpression(current) || t.isThisExpression(current) || t.isSuper(current) || t.isAwaitExpression(current) || t.isYieldExpression(current) || t.isNewExpression(current)) return true;
1546
+ if (t.isStringLiteral(current) || t.isNumericLiteral(current) || t.isBooleanLiteral(current) || t.isNullLiteral(current) || t.isBigIntLiteral(current) || t.isRegExpLiteral(current)) return false;
1547
+ if (t.isTemplateLiteral(current)) return current.expressions.some((exp) => visit(exp));
1548
+ if (t.isArrayExpression(current)) {
1549
+ for (const element of current.elements) {
1550
+ if (!element || t.isSpreadElement(element)) return true;
1551
+ if (visit(element)) return true;
1552
+ }
1553
+ return false;
1554
+ }
1555
+ if (t.isObjectExpression(current)) {
1556
+ for (const property of current.properties) if (t.isSpreadElement(property) || !t.isObjectProperty(property)) return true;
1557
+ return false;
1558
+ }
1559
+ if (t.isConditionalExpression(current)) return visit(current.test) || visit(current.consequent) || visit(current.alternate);
1560
+ if (t.isLogicalExpression(current) || t.isBinaryExpression(current)) return visit(current.left) || visit(current.right);
1561
+ if (t.isUnaryExpression(current)) return visit(current.argument);
1562
+ return true;
1563
+ };
1564
+ return visit(ast);
1565
+ }
1527
1566
  function createClassStyleBinding(context, type, exp, expAst) {
1528
1567
  const index = context.classStyleBindings.length;
1529
1568
  return {
@@ -1539,7 +1578,7 @@ function renderClassAttribute(staticClass, dynamicClassExp, context) {
1539
1578
  if (!dynamicClassExp) return staticValue ? `class="${staticValue}"` : void 0;
1540
1579
  const parts = [];
1541
1580
  if (staticValue) parts.push(toWxmlStringLiteral(staticValue));
1542
- if (context.classStyleRuntime === "wxs") {
1581
+ if (context.classStyleRuntime === "wxs" && !shouldPreferJsClassStyleRuntime(dynamicClassExp)) {
1543
1582
  const normalizedParts = normalizeClassBindingExpression(dynamicClassExp, context);
1544
1583
  for (const part of normalizedParts) parts.push(`(${part})`);
1545
1584
  const mergedExp = parts.length > 1 ? `[${parts.join(",")}]` : parts[0];
@@ -1561,7 +1600,7 @@ function renderStyleAttribute(staticStyle, dynamicStyleExp, vShowExp, context) {
1561
1600
  if (!Boolean(dynamicStyleExp || vShowExp)) return staticValue ? `style="${staticValue}"` : void 0;
1562
1601
  const parts = [];
1563
1602
  if (staticValue) parts.push(toWxmlStringLiteral(staticValue));
1564
- if (context.classStyleRuntime === "wxs") {
1603
+ if (context.classStyleRuntime === "wxs" && (!dynamicStyleExp || !shouldPreferJsClassStyleRuntime(dynamicStyleExp))) {
1565
1604
  if (dynamicStyleExp) {
1566
1605
  const normalizedParts = normalizeStyleBindingExpression(dynamicStyleExp, context);
1567
1606
  for (const part of normalizedParts) parts.push(`(${part})`);
@@ -1711,6 +1750,17 @@ function buildInlineScopeAttrs(scopeBindings) {
1711
1750
  return `data-wv-s${index}="{{${binding.replace(/"/g, """)}}}"`;
1712
1751
  });
1713
1752
  }
1753
+ function resolveEventPrefix(modifiers) {
1754
+ const hasCatch = modifiers.some((modifier) => modifier.content === "catch");
1755
+ const hasStop = modifiers.some((modifier) => modifier.content === "stop");
1756
+ const hasCapture = modifiers.some((modifier) => modifier.content === "capture");
1757
+ const hasMut = modifiers.some((modifier) => modifier.content === "mut");
1758
+ if ((hasCatch || hasStop) && hasCapture) return "capture-catch";
1759
+ if (hasCatch || hasStop) return "catch";
1760
+ if (hasMut) return "mut-bind";
1761
+ if (hasCapture) return "capture-bind";
1762
+ return "bind";
1763
+ }
1714
1764
  function transformOnDirective(node, context) {
1715
1765
  const { exp, arg } = node;
1716
1766
  if (!arg) return null;
@@ -1720,7 +1770,8 @@ function transformOnDirective(node, context) {
1720
1770
  const isInlineExpression = rawExpValue && !isSimpleHandler(rawExpValue);
1721
1771
  const inlineExpression = isInlineExpression ? registerInlineExpression(rawExpValue, context) : null;
1722
1772
  const mappedEvent = context.platform.mapEventName(argValue);
1723
- const bindAttr = context.platform.eventBindingAttr(mappedEvent);
1773
+ const eventPrefix = resolveEventPrefix(node.modifiers);
1774
+ const bindAttr = context.platform.eventBindingAttr(`${eventPrefix}:${mappedEvent}`);
1724
1775
  if (context.rewriteScopedSlot) {
1725
1776
  if (inlineExpression) {
1726
1777
  const scopeAttrs = buildInlineScopeAttrs(inlineExpression.scopeBindings);
@@ -2286,7 +2337,7 @@ function transformForElement(node, context, transformNode) {
2286
2337
  const forInfo = parseForExpression(forDirective.exp.type === NodeTypes.SIMPLE_EXPRESSION ? forDirective.exp.content : "");
2287
2338
  if (context.classStyleRuntime === "js" && !forInfo.index) forInfo.index = `__wv_index_${context.forIndexSeed++}`;
2288
2339
  const listExp = forInfo.listExp ? normalizeWxmlExpressionWithContext(forInfo.listExp, context) : void 0;
2289
- const listExpAst = context.classStyleRuntime === "js" && forInfo.listExp ? normalizeJsExpressionWithContext(forInfo.listExp, context, { hint: "v-for 列表" }) : void 0;
2340
+ const listExpAst = forInfo.listExp ? normalizeJsExpressionWithContext(forInfo.listExp, context, { hint: "v-for 列表" }) : void 0;
2290
2341
  const scopedForInfo = listExp ? {
2291
2342
  ...forInfo,
2292
2343
  listExp,
@@ -2462,6 +2513,27 @@ function toOnEventName(eventName) {
2462
2513
  if (!eventName) return "on";
2463
2514
  return `on${(eventName[0] ?? "").toUpperCase()}${eventName.slice(1)}`;
2464
2515
  }
2516
+ function parseEventBinding$3(eventName) {
2517
+ const prefixed = /^(bind|catch|capture-bind|capture-catch|mut-bind):(.+)$/.exec(eventName);
2518
+ if (prefixed) return {
2519
+ prefix: prefixed[1],
2520
+ name: prefixed[2]
2521
+ };
2522
+ return {
2523
+ prefix: "bind",
2524
+ name: eventName
2525
+ };
2526
+ }
2527
+ function toAlipayDirectiveEvent(prefix, eventName) {
2528
+ if (!eventName) return "on";
2529
+ const pascalEvent = `${(eventName[0] ?? "").toUpperCase()}${eventName.slice(1)}`;
2530
+ switch (prefix) {
2531
+ case "catch": return `catch${pascalEvent}`;
2532
+ case "capture-bind": return `capture${pascalEvent}`;
2533
+ case "capture-catch": return `captureCatch${pascalEvent}`;
2534
+ default: return toOnEventName(eventName);
2535
+ }
2536
+ }
2465
2537
  /**
2466
2538
  * 支付宝小程序平台适配器。
2467
2539
  */
@@ -2480,8 +2552,9 @@ const alipayPlatform = {
2480
2552
  keyAttr: (value) => `a:key="${value}"`,
2481
2553
  mapEventName: (eventName) => eventMap$3[eventName] || eventName,
2482
2554
  eventBindingAttr: (eventName) => {
2483
- if (eventName.includes(":")) return `on:${eventName}`;
2484
- return toOnEventName(eventName);
2555
+ const { prefix, name } = parseEventBinding$3(eventName);
2556
+ if (name.includes(":")) return `on:${name}`;
2557
+ return toAlipayDirectiveEvent(prefix, name);
2485
2558
  }
2486
2559
  };
2487
2560
 
@@ -2509,6 +2582,17 @@ const eventMap$2 = {
2509
2582
  longtap: "longtap",
2510
2583
  longpress: "longpress"
2511
2584
  };
2585
+ function parseEventBinding$2(eventName) {
2586
+ const prefixed = /^(bind|catch|capture-bind|capture-catch|mut-bind):(.+)$/.exec(eventName);
2587
+ if (prefixed) return {
2588
+ prefix: prefixed[1],
2589
+ name: prefixed[2]
2590
+ };
2591
+ return {
2592
+ prefix: "bind",
2593
+ name: eventName
2594
+ };
2595
+ }
2512
2596
  /**
2513
2597
  * 百度智能小程序平台适配器。
2514
2598
  */
@@ -2527,7 +2611,14 @@ const swanPlatform = {
2527
2611
  keyAttr: (value) => `s-key="${value}"`,
2528
2612
  mapEventName: (eventName) => eventMap$2[eventName] || eventName,
2529
2613
  eventBindingAttr: (eventName) => {
2530
- return eventName.includes(":") ? `bind:${eventName}` : `bind${eventName}`;
2614
+ const { prefix, name } = parseEventBinding$2(eventName);
2615
+ switch (prefix) {
2616
+ case "catch": return name.includes(":") ? `catch:${name}` : `catch${name}`;
2617
+ case "capture-bind": return `capture-bind:${name}`;
2618
+ case "capture-catch": return `capture-catch:${name}`;
2619
+ case "mut-bind": return `mut-bind:${name}`;
2620
+ default: return name.includes(":") ? `bind:${name}` : `bind${name}`;
2621
+ }
2531
2622
  }
2532
2623
  };
2533
2624
 
@@ -2555,6 +2646,17 @@ const eventMap$1 = {
2555
2646
  longtap: "longtap",
2556
2647
  longpress: "longpress"
2557
2648
  };
2649
+ function parseEventBinding$1(eventName) {
2650
+ const prefixed = /^(bind|catch|capture-bind|capture-catch|mut-bind):(.+)$/.exec(eventName);
2651
+ if (prefixed) return {
2652
+ prefix: prefixed[1],
2653
+ name: prefixed[2]
2654
+ };
2655
+ return {
2656
+ prefix: "bind",
2657
+ name: eventName
2658
+ };
2659
+ }
2558
2660
  /**
2559
2661
  * 抖音小程序平台适配器。
2560
2662
  */
@@ -2573,7 +2675,14 @@ const ttPlatform = {
2573
2675
  keyAttr: (value) => `tt:key="${value}"`,
2574
2676
  mapEventName: (eventName) => eventMap$1[eventName] || eventName,
2575
2677
  eventBindingAttr: (eventName) => {
2576
- return eventName.includes(":") ? `bind:${eventName}` : `bind${eventName}`;
2678
+ const { prefix, name } = parseEventBinding$1(eventName);
2679
+ switch (prefix) {
2680
+ case "catch": return name.includes(":") ? `catch:${name}` : `catch${name}`;
2681
+ case "capture-bind": return `capture-bind:${name}`;
2682
+ case "capture-catch": return `capture-catch:${name}`;
2683
+ case "mut-bind": return `mut-bind:${name}`;
2684
+ default: return name.includes(":") ? `bind:${name}` : `bind${name}`;
2685
+ }
2577
2686
  }
2578
2687
  };
2579
2688
 
@@ -2601,6 +2710,17 @@ const eventMap = {
2601
2710
  longtap: "longtap",
2602
2711
  longpress: "longpress"
2603
2712
  };
2713
+ function parseEventBinding(eventName) {
2714
+ const prefixed = /^(bind|catch|capture-bind|capture-catch|mut-bind):(.+)$/.exec(eventName);
2715
+ if (prefixed) return {
2716
+ prefix: prefixed[1],
2717
+ name: prefixed[2]
2718
+ };
2719
+ return {
2720
+ prefix: "bind",
2721
+ name: eventName
2722
+ };
2723
+ }
2604
2724
  /**
2605
2725
  * 微信小程序平台适配器。
2606
2726
  */
@@ -2619,7 +2739,14 @@ const wechatPlatform = {
2619
2739
  keyAttr: (value) => `wx:key="${value}"`,
2620
2740
  mapEventName: (eventName) => eventMap[eventName] || eventName,
2621
2741
  eventBindingAttr: (eventName) => {
2622
- return eventName.includes(":") ? `bind:${eventName}` : `bind${eventName}`;
2742
+ const { prefix, name } = parseEventBinding(eventName);
2743
+ switch (prefix) {
2744
+ case "catch": return name.includes(":") ? `catch:${name}` : `catch${name}`;
2745
+ case "capture-bind": return `capture-bind:${name}`;
2746
+ case "capture-catch": return `capture-catch:${name}`;
2747
+ case "mut-bind": return `mut-bind:${name}`;
2748
+ default: return name.includes(":") ? `bind:${name}` : `bind${name}`;
2749
+ }
2623
2750
  }
2624
2751
  };
2625
2752
 
@@ -2648,7 +2775,7 @@ function getMiniProgramTemplatePlatform(platform) {
2648
2775
  */
2649
2776
  function compileVueTemplateToWxml(template, filename, options) {
2650
2777
  const warnings = [];
2651
- const runtimeMode = options?.classStyleRuntime ?? "auto";
2778
+ const runtimeMode = options?.classStyleRuntime ?? "js";
2652
2779
  const resolvedRuntime = runtimeMode === "auto" ? options?.wxsExtension ? "wxs" : "js" : runtimeMode === "wxs" && !options?.wxsExtension ? "js" : runtimeMode;
2653
2780
  const wxsExtension = options?.wxsExtension;
2654
2781
  const scopedSlotsRequireProps = options?.scopedSlotsRequireProps ?? options?.scopedSlotsCompiler !== "augmented";
@@ -2763,13 +2890,20 @@ function buildForExpression(binding, forStack, level, helpers) {
2763
2890
  const info = forStack[level];
2764
2891
  const listId = t.identifier(`__wv_list_${level}`);
2765
2892
  const listExp = info.listExpAst ? t.cloneNode(info.listExpAst, true) : t.arrayExpression([]);
2766
- const listDecl = t.variableDeclaration("const", [t.variableDeclarator(listId, listExp)]);
2893
+ const unrefHelper = helpers.unref ? t.cloneNode(helpers.unref) : t.identifier("unref");
2894
+ const listUnrefExp = t.callExpression(unrefHelper, [listExp]);
2895
+ const listDecl = t.variableDeclaration("let", [t.variableDeclarator(listId, t.arrayExpression([]))]);
2896
+ const listSafeAssign = t.tryStatement(t.blockStatement([t.expressionStatement(t.assignmentExpression("=", listId, listUnrefExp))]), t.catchClause(t.identifier(`__wv_err_${level}`), t.blockStatement([t.expressionStatement(t.assignmentExpression("=", listId, t.arrayExpression([])))])), null);
2767
2897
  const arrayCheck = t.callExpression(t.memberExpression(t.identifier("Array"), t.identifier("isArray")), [listId]);
2768
2898
  const arrayMap = buildArrayMapExpression(binding, forStack, level, listId, helpers);
2769
2899
  const objectCheck = t.logicalExpression("&&", t.binaryExpression("!=", listId, t.nullLiteral()), t.binaryExpression("===", t.unaryExpression("typeof", listId), t.stringLiteral("object")));
2770
2900
  const objectBlock = buildObjectMapExpression(binding, forStack, level, listId, helpers);
2771
2901
  const fallbackReturn = t.returnStatement(t.arrayExpression([]));
2772
- const body = t.blockStatement([listDecl, t.ifStatement(arrayCheck, t.blockStatement([t.returnStatement(arrayMap)]), t.ifStatement(objectCheck, objectBlock, t.blockStatement([fallbackReturn])))]);
2902
+ const body = t.blockStatement([
2903
+ listDecl,
2904
+ listSafeAssign,
2905
+ t.ifStatement(arrayCheck, t.blockStatement([t.returnStatement(arrayMap)]), t.ifStatement(objectCheck, objectBlock, t.blockStatement([fallbackReturn])))
2906
+ ]);
2773
2907
  return t.callExpression(t.arrowFunctionExpression([], body), []);
2774
2908
  }
2775
2909
  function buildComputedFunctionBody(binding, helpers) {
@@ -2796,7 +2930,8 @@ function buildClassStyleComputedCode(bindings, helpers) {
2796
2930
  if (!bindings.length) return null;
2797
2931
  const obj = buildClassStyleComputedObject(bindings, {
2798
2932
  normalizeClass: t.identifier(helpers.normalizeClassName),
2799
- normalizeStyle: t.identifier(helpers.normalizeStyleName)
2933
+ normalizeStyle: t.identifier(helpers.normalizeStyleName),
2934
+ unref: t.identifier(helpers.unrefName ?? "unref")
2800
2935
  });
2801
2936
  if (!obj) return null;
2802
2937
  const { code } = generate(obj, { compact: true });
@@ -4694,7 +4829,8 @@ function injectClassStyleComputed(optionsObject, bindings, warn) {
4694
4829
  const warnHandler = resolveWarnHandler(warn);
4695
4830
  const entries = buildClassStyleComputedEntries(bindings, {
4696
4831
  normalizeClass: t.identifier("__wevuNormalizeClass"),
4697
- normalizeStyle: t.identifier("__wevuNormalizeStyle")
4832
+ normalizeStyle: t.identifier("__wevuNormalizeStyle"),
4833
+ unref: t.identifier("__wevuUnref")
4698
4834
  });
4699
4835
  if (!entries.length) return false;
4700
4836
  const computedProp = getObjectPropertyByKey(optionsObject, "computed");
@@ -4716,6 +4852,7 @@ function injectClassStyleComputed(optionsObject, bindings, warn) {
4716
4852
  function ensureClassStyleRuntimeImports(program) {
4717
4853
  ensureRuntimeImport(program, "normalizeClass", "__wevuNormalizeClass");
4718
4854
  ensureRuntimeImport(program, "normalizeStyle", "__wevuNormalizeStyle");
4855
+ ensureRuntimeImport(program, "unref", "__wevuUnref");
4719
4856
  }
4720
4857
 
4721
4858
  //#endregion
@@ -4952,7 +5089,7 @@ function rewriteDefaultExport(ast, state, options, enabledPageFeatures, serializ
4952
5089
  parsedWevuDefaults,
4953
5090
  options
4954
5091
  }) || transformed;
4955
- const classStyleBindings = options?.classStyleRuntime === "js" ? options?.classStyleBindings ?? [] : [];
5092
+ const classStyleBindings = options?.classStyleBindings ?? [];
4956
5093
  if (classStyleBindings.length) if (componentExpr && t.isObjectExpression(componentExpr)) {
4957
5094
  ensureClassStyleRuntimeImports(ast.program);
4958
5095
  transformed = injectClassStyleComputed(componentExpr, classStyleBindings, warn) || transformed;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@wevu/compiler",
3
3
  "type": "module",
4
- "version": "0.0.6",
4
+ "version": "0.1.0",
5
5
  "description": "wevu 编译器基础包,面向小程序模板的编译与转换",
6
6
  "author": "ice breaker <1324318532@qq.com>",
7
7
  "license": "MIT",
@@ -45,14 +45,14 @@
45
45
  "@babel/parser": "^7.29.0",
46
46
  "@babel/traverse": "^7.29.0",
47
47
  "@babel/types": "^7.29.0",
48
- "@vue/compiler-core": "^3.5.27",
48
+ "@vue/compiler-core": "^3.5.28",
49
49
  "comment-json": "^4.5.1",
50
50
  "fs-extra": "^11.3.3",
51
51
  "lru-cache": "^11.2.5",
52
52
  "magic-string": "^0.30.21",
53
53
  "merge": "^2.1.1",
54
54
  "pathe": "^2.0.3",
55
- "vue": "^3.5.27",
55
+ "vue": "^3.5.28",
56
56
  "@weapp-core/shared": "3.0.1",
57
57
  "rolldown-require": "2.0.6"
58
58
  },