@proteus-vue/compiler 0.3.0-beta.2 → 0.3.0-beta.3

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.js CHANGED
@@ -14694,6 +14694,17 @@ var EVENT_MAP = {
14694
14694
  scroll: "scroll"
14695
14695
  // scroll-view 内置滚动事件(v0.4 虚拟列表)
14696
14696
  };
14697
+ var GESTURE_MP_EVENTS = {
14698
+ tap: "tap",
14699
+ longpress: "longpress"
14700
+ };
14701
+ var MP_GESTURE_ALTERNATIVES = {
14702
+ pan: "`@touchstart/@touchmove/@touchend`\uFF08\u81EA\u884C\u5224\u5B9A\u4F4D\u79FB\uFF09\u6216\u539F\u751F `<pan-gesture-handler>` \u7EC4\u4EF6",
14703
+ pinch: "`<scale-gesture-handler>` \u7EC4\u4EF6\uFF08worklet:ongesture\uFF09",
14704
+ rotate: "\u539F\u751F\u624B\u52BF\u5904\u7406\u5668\u7EC4\u4EF6\uFF08MP \u65E0 rotate \u4E8B\u4EF6\u5C5E\u6027\uFF09",
14705
+ press: "`<force-press-gesture-handler>` \u7EC4\u4EF6\uFF08\u9700 3D Touch \u8BBE\u5907\uFF09",
14706
+ swipe: "`@touchstart/@touchend` \u81EA\u884C\u5224\u5B9A\u65B9\u5411"
14707
+ };
14697
14708
  var SEMANTIC_CLASS = {
14698
14709
  h1: "proteus-h1",
14699
14710
  h2: "proteus-h2",
@@ -14900,6 +14911,38 @@ var TEMPLATE_RULES = [
14900
14911
  verify: "tests/compiler-ir-m3.test.ts\u300C\u672A\u77E5 p-* \u4E3B\u7F16\u8BD1\u8B66\u544A\u300D",
14901
14912
  source: "src/compiler/template.ts \u2192 serializeElement\uFF08\u672A\u77E5 p-* \u68C0\u6D4B\uFF09"
14902
14913
  }),
14914
+ // ============ 手势指令(G-32 B4 ④) ============
14915
+ {
14916
+ id: "directive/v-gesture",
14917
+ phase: "template",
14918
+ status: "implemented",
14919
+ title: "v-gesture:<kind> \u2192 MP \u539F\u751F\u4E8B\u4EF6\uFF08\u6709\u5BF9\u7B49\u8005\u76F4\u6620\u5C04\uFF0C\u65E0\u5BF9\u7B49\u8005\u660E\u793A\u66FF\u4EE3\uFF09",
14920
+ titleEn: "v-gesture:<kind> maps to native MP events (direct map when equivalent, explicit alternative otherwise)",
14921
+ description: "v-gesture:tap|longpress \u2192 bindtap/bindlongpress\uFF08MP \u539F\u751F\u4E8B\u4EF6\u5BF9\u7B49\uFF09\uFF1Bpan/pinch/rotate/press \u65E0\u4E8B\u4EF6\u5BF9\u7B49\uFF08\u5B98\u65B9\u4E3A worklet \u624B\u52BF\u5904\u7406\u5668\u7EC4\u4EF6\uFF09\u2192 \u5265\u79BB\u5E76\u7ED9\u51FA\u5177\u4F53\u66FF\u4EE3\u6307\u5F15\u8D77",
14922
+ descriptionEn: "v-gesture:tap|longpress become bindtap/bindlongpress (native MP event equivalents); pan/pinch/rotate/press have no event equivalent (the official form is worklet gesture-handler components) so they are stripped with a concrete alternative hint",
14923
+ why: "\u4FEE\u300C\u9759\u9ED8\u5931\u6548\u300D\u7F3A\u9677\uFF1A\u6B64\u524D v-gesture:* \u4E00\u5F8B\u843D\u5165 directive/custom \u88AB\u5265\u79BB\u4E14\u8B66\u544A\u300C\u65E0\u5BF9\u7B49\u673A\u5236\u300D\uFF0C\u4F46 gesture.tap \u7684 mpEquiv \u660E\u5199 bindtap\uFF08\u539F\u751F\u771F\u5B9E\u5B58\u5728\uFF09\u2014\u2014\u4E24\u8005\u77DB\u76FE\uFF0C\u5199 v-gesture:tap \u7684\u5F00\u53D1\u8005\u5728\u5C0F\u7A0B\u5E8F\u4E0A handler \u6C38\u4E0D\u89E6\u53D1",
14924
+ whyEn: "fixes silent failure: v-gesture:* used to fall into directive/custom, get stripped, and warn that nothing is equivalent \u2014 yet gesture.tap declares bindtap as its mpEquiv, so handlers written with v-gesture:tap never fired on MP",
14925
+ when: "\u6A21\u677F\u5143\u7D20\u4E0A\u6709 v-gesture:<kind> \u65F6",
14926
+ example: { before: '<view v-gesture:tap="onTap">x</view>', after: '<view bindtap="onTap">x</view>' },
14927
+ verify: "tests/p-gesture-batch.test.ts\uFF08\u53CC\u8DEF\u5F84 + \u7834\u574F\u6027\uFF09",
14928
+ source: "packages/compiler/src/template.ts \u2192 serializeElement\uFF08case gesture\uFF09+ tags.ts GESTURE_MP_EVENTS/MP_GESTURE_ALTERNATIVES"
14929
+ },
14930
+ // ============ 属性降级(EA-5 / G-31.2,批次 4 M6) ============
14931
+ {
14932
+ id: "prop/no-degradation",
14933
+ phase: "template",
14934
+ status: "implemented",
14935
+ title: "\u76EE\u6807\u7AEF unsupported \u5C5E\u6027 fail-closed \u8BCA\u65AD\uFF08PROP_NO_DEGRADATION\uFF09",
14936
+ titleEn: "target-end unsupported props fail closed (PROP_NO_DEGRADATION)",
14937
+ description: "\u7EC4\u4EF6\u5C5E\u6027\u5728\u76EE\u6807\u7AEF\u964D\u7EA7\u4E09\u6001\u4E3A unsupported\uFF08\u672C\u7AEF\u65E0\u6CD5\u5B9E\u73B0\uFF09\u65F6\uFF0C\u4F7F\u7528\u5373\u4EA7\u751F\u7F16\u8BD1\u671F\u8BCA\u65AD\uFF08PROP_NO_DEGRADATION\uFF09\uFF1Bfallback\uFF08\u6709\u610F\u964D\u7EA7\u3001\u884C\u4E3A\u5DF2\u58F0\u660E\uFF09\u4E0D\u62A5",
14938
+ descriptionEn: "when a component prop is declared unsupported on the target end, using it raises a compile-time diagnostic (PROP_NO_DEGRADATION); fallback (intentional, behavior declared) is not reported",
14939
+ why: "G-31.2 \u94C1\u5F8B\uFF1A\u5C5E\u6027\u5728\u5404\u7AEF\u5FC5\u987B\u58F0\u660E supported/fallback/unsupported\uFF1Bunsupported \u7684\u9759\u9ED8\u5931\u8D25\u662F\u300C\u5F02\u7AEF\u300D\uFF08\u5F00\u53D1\u8005\u5230\u771F\u673A\u624D\u53D1\u73B0\uFF09\uFF0C\u6545\u7F16\u8BD1\u671F fail-closed",
14940
+ whyEn: "G-31.2: every prop must declare supported/fallback/unsupported per end; silently failing unsupported props are the anti-pattern to eliminate, so the compiler fails closed",
14941
+ when: "p-* \u7EC4\u4EF6\u7684\u9759\u6001\u5C5E\u6027\u5728\u964D\u7EA7\u8868\u4E2D\u8BE5\u7AEF\u4E3A unsupported \u65F6",
14942
+ example: { before: '<p-media foo="x" />', after: "\u7F16\u8BD1\u8BCA\u65AD PROP_NO_DEGRADATION\uFF08mp \u7AEF unsupported\uFF09" },
14943
+ verify: "tests/degradation-batch4.test.ts\uFF08\u7F16\u8BD1\u671F\u8BCA\u65AD\uFF09+ scripts/audit-degradation.mjs\uFF08\u5168\u8868\u95E8\u7981\uFF09",
14944
+ source: "packages/compiler/src/template.ts \u2192 serializeElement\uFF08prop/no-degradation \u5206\u652F\uFF09+ component-ir/degradation.ts"
14945
+ },
14903
14946
  // ============ 语义基础类 ============
14904
14947
  {
14905
14948
  id: "semantic/base-class",
@@ -15774,7 +15817,7 @@ var TAG_RULE_BY_TAG = Object.fromEntries(
15774
15817
  );
15775
15818
 
15776
15819
  // src/template.ts
15777
- import { TAG_SEMANTIC_MAP } from "@proteus-vue/component-ir";
15820
+ import { TAG_SEMANTIC_MAP, MP_UNSUPPORTED_PROPS, PROP_NO_DEGRADATION, FRAMEWORK_INTERNAL_TAGS } from "@proteus-vue/component-ir";
15778
15821
 
15779
15822
  // src/transforms/script.ts
15780
15823
  var SCRIPT_RULES = [
@@ -18395,12 +18438,28 @@ ${inner}
18395
18438
  ctx.warnings.push(svgMsg);
18396
18439
  ctx.trace?.add("template/svg-no-peer", { line: node.loc.start.line, before: `<${node.tag}>`, after: "\uFF08MP \u65E0\u5BF9\u7B49\uFF1ASVG \u6807\u7B7E\u4E0D\u6E32\u67D3\uFF09" });
18397
18440
  }
18398
- if (node.tag.startsWith("p-") && !TAG_SEMANTIC_MAP[node.tag] && !ctx.tagMap[node.tag] && !ctx.disabled.has("tag/unknown-p-star")) {
18441
+ if (node.tag.startsWith("p-") && !TAG_SEMANTIC_MAP[node.tag] && !FRAMEWORK_INTERNAL_TAGS.has(node.tag) && !ctx.tagMap[node.tag] && !ctx.disabled.has("tag/unknown-p-star")) {
18399
18442
  ctx.warnings.push(
18400
18443
  `<${node.tag}> \u4EE5 p- \u524D\u7F00\u547D\u540D\u4F46\u4E0D\u5728\u7EC4\u4EF6\u5E93\u8BED\u4E49\u767B\u8BB0\u8868\uFF08TAG_SEMANTIC_MAP\uFF09\u2014\u2014\u62FC\u5199\u9519\u8BEF\u6216\u672A\u5165\u5E93\u7EC4\u4EF6\uFF1F\u4EA7\u7269\u5C06\u6309\u672A\u6CE8\u518C\u81EA\u5B9A\u4E49\u7EC4\u4EF6\u8F93\u51FA\uFF08MP \u7AEF\u4E0D\u6E32\u67D3\u3001\u65E0\u8BED\u4E49\u94FE\u63A5\uFF09\uFF1B\u8BF7\u68C0\u67E5\u7EC4\u4EF6\u540D\u6216\u79FB\u9664 p- \u524D\u7F00`
18401
18444
  );
18402
18445
  ctx.trace?.add("tag/unknown-p-star", { line: node.loc.start.line, before: `<${node.tag}>`, after: "\uFF08\u672A\u767B\u8BB0 p-*\uFF1A\u6309\u672A\u6CE8\u518C\u81EA\u5B9A\u4E49\u7EC4\u4EF6\u8F93\u51FA\u2014\u2014MP \u4E0D\u6E32\u67D3\uFF09" });
18403
18446
  }
18447
+ if (node.tag.startsWith("p-") && !ctx.disabled.has("prop/no-degradation")) {
18448
+ const unsupported = ctx.degradationTable ? new Set(
18449
+ Object.entries(ctx.degradationTable[node.tag] ?? {}).filter(([, e]) => e.mp === "unsupported").map(([k]) => camelToKebab(k))
18450
+ ) : MP_UNSUPPORTED_PROPS[node.tag];
18451
+ if (unsupported?.size) {
18452
+ for (const p of node.props) {
18453
+ if (p.type !== NodeTypes2.ATTRIBUTE) continue;
18454
+ const name = p.name;
18455
+ if (!unsupported.has(camelToKebab(name))) continue;
18456
+ const msg = `[${PROP_NO_DEGRADATION}] <${node.tag}> \u7684\u5C5E\u6027 "${name}" \u5728 mp \u7AEF unsupported\uFF08\u672C\u7AEF\u65E0\u6CD5\u5B9E\u73B0\uFF09\u2014\u2014\u7EE7\u7EED\u4F7F\u7528\u4F1A\u9759\u9ED8\u5931\u8D25\uFF08\u8FDD\u53CD G-31.2\uFF09\uFF1B\u8BF7\u6539\u7528 @conditional \u663E\u5F0F\u5206\u652F\u6216\u79FB\u9664\u8BE5\u5C5E\u6027`;
18457
+ if (ctx.failFast) failFastThrow(ctx.filename, msg);
18458
+ ctx.warnings.push(msg);
18459
+ ctx.trace?.add("prop/no-degradation", { line: node.loc.start.line, before: `<${node.tag} ${name}>`, after: "\uFF08mp unsupported\u2014\u2014fail-closed \u8BCA\u65AD\uFF09" });
18460
+ }
18461
+ }
18462
+ }
18404
18463
  if (!ctx.disabled.has("tag/unknown-kebab") && !(tagRuleId && ctx.disabled.has(tagRuleId))) {
18405
18464
  ctx.trace?.add(
18406
18465
  hasVHtml ? "tag/rich-text" : node.tag === "router-link" ? "tag/router-link" : TAG_RULE_BY_TAG[node.tag] ?? "tag/unknown-kebab",
@@ -18619,6 +18678,39 @@ ${inner}
18619
18678
  );
18620
18679
  break;
18621
18680
  }
18681
+ case "gesture": {
18682
+ if (ctx.disabled.has("directive/v-gesture")) {
18683
+ ctx.warnings.push(`\u89C4\u5219 directive/v-gesture \u5DF2\u88AB\u7981\u7528\uFF08rules.disabled\uFF09\uFF0Cv-gesture \u5DF2\u5FFD\u7565`);
18684
+ break;
18685
+ }
18686
+ const kind = dir.arg ? exprContent(dir.arg).trim() : "";
18687
+ const gestureEvent = GESTURE_MP_EVENTS[kind];
18688
+ if (!gestureEvent) {
18689
+ const alt = MP_GESTURE_ALTERNATIVES[kind] ?? "\uFF08\u8BE5\u624B\u52BF MP \u65E0\u7B49\u4EF7\uFF1B\u8BF7\u7528\u539F\u751F *-gesture-handler \u7EC4\u4EF6\uFF09";
18690
+ ctx.warnings.push(
18691
+ `v-gesture:${kind || "(\u7F3A\u624B\u52BF\u540D)"} \u5728\u5C0F\u7A0B\u5E8F\u7AEF\u65E0\u4E8B\u4EF6\u5BF9\u7B49\uFF08\u5B98\u65B9\u7528 worklet \u624B\u52BF\u5904\u7406\u5668\u7EC4\u4EF6 ${kind}-gesture-handler\uFF09\u2014\u2014\u5DF2\u5265\u79BB\u3002\u66FF\u4EE3\uFF1A\u6539\u7528 ${alt}`
18692
+ );
18693
+ ctx.trace?.add("directive/v-gesture", { line: node.loc.start.line, before: `v-gesture:${kind}`, after: `\uFF08MP \u65E0\u4E8B\u4EF6\u5BF9\u7B49\uFF0C\u5DF2\u5265\u79BB\u5E76\u7ED9\u51FA\u66FF\u4EE3\uFF09` });
18694
+ break;
18695
+ }
18696
+ const flow = dir.exp;
18697
+ const gExp = flow && "content" in flow ? exprContent(flow) : void 0;
18698
+ const gHandler = cleanHandler(gExp ?? "", ctx.warnings, ctx.failFast, ctx.filename);
18699
+ const gMods = dir.modifiers.map(
18700
+ (m) => typeof m === "string" ? m : m.content ?? ""
18701
+ );
18702
+ const gCatch = gMods.includes("catch") || gMods.includes("stop");
18703
+ const gSelf = gMods.includes("self");
18704
+ const gOnce = gMods.includes("once");
18705
+ if (gSelf || gOnce) {
18706
+ ctx.warnings.push(
18707
+ `v-gesture:${kind} \u7684\u4FEE\u9970\u7B26 .${[gSelf ? "self" : "", gOnce ? "once" : ""].filter(Boolean).join(".")} \u5728\u5C0F\u7A0B\u5E8F\u65E0\u5BF9\u7B49\uFF08\u5DF2\u5FFD\u7565\u8BE5\u4FEE\u9970\u7B26\uFF0C\u4E8B\u4EF6\u7167\u5E38\u7ED1\u5B9A\uFF09\u2014\u2014\u8BF7\u6539\u7528\u4E8B\u4EF6\u5C5E\u6027 @tap \u7B49\uFF08vue-compat Batch A\uFF09`
18708
+ );
18709
+ }
18710
+ attrs.push(`${gCatch ? "catch" : "bind"}${gestureEvent}="${gHandler}"`);
18711
+ ctx.trace?.add("directive/v-gesture", { line: node.loc.start.line, before: `v-gesture:${kind}`, after: `${gCatch ? "catch" : "bind"}${gestureEvent}="${gHandler}"\uFF08MP \u539F\u751F\u4E8B\u4EF6\u5BF9\u7B49\uFF09` });
18712
+ break;
18713
+ }
18622
18714
  case "bind": {
18623
18715
  const arg = exprContent(dir.arg);
18624
18716
  const exp = exprContent(dir.exp);
@@ -18950,7 +19042,9 @@ function transformTemplateToWxml(source, opts = { px2rpx: true, rpxRatio: 2, ann
18950
19042
  semanticGrids: [],
18951
19043
  isPage: opts.isComponent !== true,
18952
19044
  // ★G-22 柔性布局:p-fluid 编译期 clamp 生成参数
18953
- fluidLayout: opts.fluidLayout
19045
+ fluidLayout: opts.fluidLayout,
19046
+ // ★批次 4(M6):降级表覆盖(缺省 = component-ir DEGRADATION_TABLE)
19047
+ degradationTable: opts.degradationTable
18954
19048
  };
18955
19049
  const root = domParse(source, { onError: () => void 0 });
18956
19050
  pruneStaticConditionals(root.children, ctx);
package/dist/tags.d.ts CHANGED
@@ -1,3 +1,16 @@
1
1
  export declare const TAG_MAP: Record<string, string>;
2
2
  export declare const EVENT_MAP: Record<string, string>;
3
+ /**
4
+ * ★v-gesture:<kind> → MP 原生事件名(2026-09-18)。
5
+ *
6
+ * 只登记**有真实原生事件对等**的手势。未登记者在编译器走「剥离 + 明示替代」路径
7
+ * (pan/pinch/rotate/press —— MP 无简单事件对等:官方用 worklet 手势处理器**组件**
8
+ * `<pan-gesture-handler>` 等(属性为 `worklet:ongesture` + 协商),非事件属性)。
9
+ *
10
+ * 依据:EVENT_MAP 的 `click: 'tap'` / `longpress: 'longpress'` 即原生真实事件;
11
+ * 官方 view 通用事件表含 tap/longpress(另有 touchstart/move/end/cancel)。
12
+ */
13
+ export declare const GESTURE_MP_EVENTS: Record<string, string>;
14
+ /** 无事件对等手势的**具体**替代指引(反黑盒:不笼统说「无对等机制」) */
15
+ export declare const MP_GESTURE_ALTERNATIVES: Record<string, string>;
3
16
  export declare const SEMANTIC_CLASS: Record<string, string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proteus-vue/compiler",
3
- "version": "0.3.0-beta.2",
3
+ "version": "0.3.0-beta.3",
4
4
  "description": "Proteus 编译引擎 —— 标准 Vue SFC → 小程序四件套(纯函数、零运行时依赖、规则注册表 + AI 说明书)",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -40,9 +40,9 @@
40
40
  "@babel/plugin-transform-numeric-separator": "^8.0.1",
41
41
  "@babel/plugin-transform-object-rest-spread": "^7.29.0",
42
42
  "@babel/plugin-transform-optional-chaining": "^7.29.0",
43
- "@proteus-vue/component-ir": "0.1.1-beta.0",
44
- "@proteus-vue/contracts": "0.1.0",
45
- "@proteus-vue/types": "0.2.0-beta.1"
43
+ "@proteus-vue/component-ir": "0.2.0-beta.1",
44
+ "@proteus-vue/contracts": "0.1.1-beta.0",
45
+ "@proteus-vue/types": "0.2.0-beta.2"
46
46
  },
47
47
  "scripts": {
48
48
  "build": "tsc -p tsconfig.build.json --emitDeclarationOnly && esbuild src/index.ts src/style-safety/index.ts --bundle --format=esm --platform=node --outdir=dist --external:@vue/compiler-sfc --external:@vue/compiler-dom --external:@proteus-vue/contracts --external:@proteus-vue/component-ir --external:@babel/core --external:@babel/plugin-transform-nullish-coalescing-operator --external:@babel/plugin-transform-optional-chaining --external:@babel/plugin-transform-logical-assignment-operators --external:@babel/plugin-transform-object-rest-spread"