@proteus-vue/compiler 0.3.0-beta.12 → 0.3.0-beta.15

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
@@ -14677,7 +14677,87 @@ var TAG_MAP = {
14677
14677
  video: "video",
14678
14678
  canvas: "canvas",
14679
14679
  "scroll-view": "scroll-view",
14680
- slot: "slot"
14680
+ slot: "slot",
14681
+ // ★★2026-09-20(外部实战报告第二十三/二十四节):**补全常见 HTML 标签 → WXML 等价映射**。
14682
+ // 此前这些标签落到「未知标签逃生舱」**原样输出** → 微信 wxml 编译器直接拒绝(或渲染异常):
14683
+ // 外部工程实测因 <details>/<summary>/<pre>/<table>/<select>/<option>/<label>/<br> 等
14684
+ // 导致**模拟器整屏黑屏**(构建期零报错、产物看似齐全)。
14685
+ // 语义映射原则:块级 → view;行内/文本类 → text;表格/列表/折叠等无对等物 → view/text
14686
+ // (样式与交互由 CSS + 显式状态承担,见报告第二十四节的正当适配)。
14687
+ // 块级容器
14688
+ section: "view",
14689
+ article: "view",
14690
+ aside: "view",
14691
+ nav: "view",
14692
+ main: "view",
14693
+ header: "view",
14694
+ footer: "view",
14695
+ figure: "view",
14696
+ figcaption: "text",
14697
+ details: "view",
14698
+ summary: "text",
14699
+ dialog: "view",
14700
+ form: "form",
14701
+ fieldset: "view",
14702
+ legend: "text",
14703
+ // 列表
14704
+ ul: "view",
14705
+ ol: "view",
14706
+ li: "view",
14707
+ dl: "view",
14708
+ dt: "text",
14709
+ dd: "text",
14710
+ // 表格(微信无表格组件 → view 结构 + CSS)
14711
+ table: "view",
14712
+ thead: "view",
14713
+ tbody: "view",
14714
+ tfoot: "view",
14715
+ tr: "view",
14716
+ th: "text",
14717
+ td: "text",
14718
+ caption: "text",
14719
+ // 行内 / 语义文本
14720
+ strong: "text",
14721
+ b: "text",
14722
+ em: "text",
14723
+ i: "text",
14724
+ u: "text",
14725
+ s: "text",
14726
+ small: "text",
14727
+ mark: "text",
14728
+ sub: "text",
14729
+ sup: "text",
14730
+ code: "text",
14731
+ pre: "text",
14732
+ kbd: "text",
14733
+ samp: "text",
14734
+ var: "text",
14735
+ abbr: "text",
14736
+ cite: "text",
14737
+ q: "text",
14738
+ blockquote: "view",
14739
+ time: "text",
14740
+ address: "text",
14741
+ // 表单控件(无对等物者映射为 view/text,交互由 picker/state 承担)
14742
+ select: "view",
14743
+ option: "view",
14744
+ optgroup: "view",
14745
+ // ★注:`label` / `audio` **不映射**——它们是微信 wxml 原生组件(表单组件/媒体组件),
14746
+ // 映射会把可用能力降级(p-label 的 `for` 关联、p-media 的 audio 分支都会失效;
14747
+ // 实测被 tests/component-b6 与 tests/p-batch3-contract 抓住)。
14748
+ datalist: "view",
14749
+ output: "text",
14750
+ meter: "view",
14751
+ progress: "progress",
14752
+ // 其它常见
14753
+ hr: "view",
14754
+ br: "view",
14755
+ picture: "image",
14756
+ source: "view",
14757
+ track: "view",
14758
+ iframe: "web-view"
14759
+ // ★注:`template` **不映射**——它在 WXML 里是定义块(is=/data=),语义与 Vue 的片段容器不同,
14760
+ // 属「须改写法」而非「可映射」(见第二十四节:`<template v-if>` 应改为 `<view v-if>`)。
14681
14761
  };
14682
14762
  var EVENT_MAP = {
14683
14763
  click: "tap",
@@ -17043,6 +17123,99 @@ function scanWxmlPlatformIssues(wxml) {
17043
17123
  seenKeys.add(key);
17044
17124
  }
17045
17125
  }
17126
+ for (const m of wxml.matchAll(/\{\{([\s\S]*?)\}\}/g)) {
17127
+ const expr = m[1] ?? "";
17128
+ if (expr.includes(String.fromCharCode(96)) || expr.includes("${")) {
17129
+ issues.push({
17130
+ code: "TemplateLiteralInExpression",
17131
+ message: `\u7ED1\u5B9A\u8868\u8FBE\u5F0F\u542B\u6A21\u677F\u5B57\u9762\u91CF\uFF08\u53CD\u5F15\u53F7 / \u7F8E\u5143\u5927\u62EC\u53F7\uFF09\uFF1A{{ ${expr.trim().slice(0, 60)} }}\u2014\u2014WXML \u8868\u8FBE\u5F0F\u4E0D\u652F\u6301\uFF0C\u5FAE\u4FE1\u62A5 "unexpected character inside expression"\u3002\u8BF7\u628A\u5B57\u7B26\u4E32\u62FC\u63A5\u79FB\u5230 script \u9884\u8BA1\u7B97\uFF08computed \u6216 data \u5B57\u6BB5\uFF09`,
17132
+ at: m.index ?? 0
17133
+ });
17134
+ }
17135
+ }
17136
+ for (const m of wxml.matchAll(/<template\b([^>]*?)>([\s\S]*?)<\/template>/g)) {
17137
+ const attrs = m[1] ?? "";
17138
+ const body = m[2] ?? "";
17139
+ const hasChildren = /<[a-zA-Z]/.test(body.trim());
17140
+ if (hasChildren && /wx:(if|elif|else|for)\b/.test(attrs)) {
17141
+ issues.push({
17142
+ code: "TemplateChildNodes",
17143
+ message: `<template${attrs.trim() ? " " + attrs.trim().slice(0, 40) : ""}> \u542B\u5B50\u5143\u7D20\u2014\u2014WXML \u7684 <template> \u662F\u5B9A\u4E49\u5757\uFF08is=/data=\uFF09\uFF0C\u4E0D\u662F Vue \u7684\u7247\u6BB5\u5BB9\u5668\uFF08\u5FAE\u4FE1\u62A5 "child nodes are not allowed"/"missing module name"\uFF09\u3002\u8BF7\u6539\u7528 <view wx:if>`,
17144
+ at: m.index ?? 0
17145
+ });
17146
+ }
17147
+ }
17148
+ const KNOWN_HTML_TAGS = /* @__PURE__ */ new Set([
17149
+ "section",
17150
+ "article",
17151
+ "aside",
17152
+ "nav",
17153
+ "main",
17154
+ "header",
17155
+ "footer",
17156
+ "figure",
17157
+ "figcaption",
17158
+ "details",
17159
+ "summary",
17160
+ "dialog",
17161
+ "fieldset",
17162
+ "legend",
17163
+ "ul",
17164
+ "ol",
17165
+ "li",
17166
+ "dl",
17167
+ "dt",
17168
+ "dd",
17169
+ "table",
17170
+ "thead",
17171
+ "tbody",
17172
+ "tfoot",
17173
+ "tr",
17174
+ "th",
17175
+ "td",
17176
+ "caption",
17177
+ "strong",
17178
+ "b",
17179
+ "em",
17180
+ "i",
17181
+ "u",
17182
+ "s",
17183
+ "small",
17184
+ "mark",
17185
+ "sub",
17186
+ "sup",
17187
+ "code",
17188
+ "pre",
17189
+ "kbd",
17190
+ "samp",
17191
+ "var",
17192
+ "abbr",
17193
+ "cite",
17194
+ "q",
17195
+ "blockquote",
17196
+ "time",
17197
+ "address",
17198
+ "select",
17199
+ "option",
17200
+ "optgroup",
17201
+ "datalist",
17202
+ "output",
17203
+ "meter",
17204
+ "hr",
17205
+ "br",
17206
+ "picture",
17207
+ "source",
17208
+ "track",
17209
+ "iframe"
17210
+ ]);
17211
+ for (const tag of scanOpenTags(wxml)) {
17212
+ if (!KNOWN_HTML_TAGS.has(tag.name)) continue;
17213
+ issues.push({
17214
+ code: "UnknownHtmlTag",
17215
+ message: `\u6807\u7B7E <${tag.name}> \u662F HTML \u6807\u7B7E\u3001\u5FAE\u4FE1 wxml \u65E0\u6B64\u539F\u751F\u6807\u7B7E\u2014\u2014\u672A\u88AB\u6620\u5C04\uFF08TAG_MAP \u9057\u6F0F\uFF09\u800C\u539F\u6837\u8FDB\u4EA7\u7269\uFF0C\u5FAE\u4FE1\u7F16\u8BD1\u4F1A\u5931\u8D25\u6216\u6E32\u67D3\u5F02\u5E38\u3002\u8BF7\u6539\u7528 WXML \u7B49\u4EF7\u7ED3\u6784\uFF08\u5757\u7EA7 \u2192 <view>\u3001\u6587\u672C\u7C7B \u2192 <text>\uFF09`,
17216
+ at: tag.at
17217
+ });
17218
+ }
17046
17219
  return issues;
17047
17220
  }
17048
17221
  function splitStyleDecls(styleVal) {
@@ -21968,7 +22141,16 @@ function transformScriptToPage(source, _opts = { px2rpx: true, rpxRatio: 2 }, ex
21968
22141
  }
21969
22142
  for (const ni of reactiveInits) dataExtra[ni.name] = null;
21970
22143
  const storeBindings = extra.storeBindings ?? [];
21971
- const storeVar = runtimeInits.find((i) => i.name === "store" && /^use\w*Store\(/.test(i.call))?.name;
22144
+ const storeCandidates = runtimeInits.filter((i) => /^use\w*Store\(/.test(i.call));
22145
+ const strict = storeCandidates.find((i) => i.name === "store");
22146
+ const storeVar = strict?.name ?? (storeCandidates.length === 1 ? storeCandidates[0].name : void 0);
22147
+ if (storeBindings.length && !storeVar) {
22148
+ warnings.push(
22149
+ `\u6A21\u677F\u5F15\u7528\u4E86 store \u5B57\u6BB5\uFF08${storeBindings.join(" / ")}\uFF09\uFF0C\u4F46\u672A\u80FD\u8BC6\u522B\u51FA store \u53D8\u91CF\u2014\u2014MP \u7AEF\u7ED1\u5B9A\u4E0D\u4F1A\u751F\u6548\uFF08\u6784\u5EFA\u901A\u8FC7\u4F46\u771F\u673A\u53D6\u4E0D\u5230\u503C\uFF09\u3002
22150
+ \u8BC6\u522B\u8981\u6C42\uFF1A\u2460 \u53D8\u91CF\u58F0\u660E\u4E3A \`const store = useXxxStore()\`\uFF08\u53D8\u91CF\u540D\u987B\u4E3A store\uFF09\uFF0C\u6216 \u2461 \u672C\u6587\u4EF6**\u53EA\u6709\u4E00\u4E2A** \`useXxxStore()\` \u8C03\u7528\u3002
22151
+ \u5F53\u524D\u672A\u6EE1\u8DB3${storeCandidates.length > 1 ? `\uFF08\u68C0\u6D4B\u5230\u591A\u4E2A useXxxStore()\uFF1A${storeCandidates.map((i) => i.name).join(" / ")}\u2014\u2014\u8BF7\u628A\u7528\u4E8E\u6A21\u677F\u7ED1\u5B9A\u7684\u90A3\u4E2A\u547D\u540D\u4E3A store\uFF09` : "\uFF08\u672A\u68C0\u6D4B\u5230\u4EFB\u4F55 useXxxStore() \u5F62\u6001\u7684\u8C03\u7528\uFF09"}\u3002`
22152
+ );
22153
+ }
21972
22154
  const storeBindingInit = storeVar && storeBindings.length ? storeBindingLine(storeBindings, storeVar) : "";
21973
22155
  if (storeBindingInit) {
21974
22156
  trace?.add("script/store-binding", {
@@ -34,7 +34,7 @@ export declare function validateWxml(wxml: string): {
34
34
  export declare function assertValidResult(result: CompileResult, filename: string): void;
35
35
  /** 单条 wxml 平台违规(code = 官方 ParseErrorKind 蓝本) */
36
36
  export interface WxmlPlatformIssue {
37
- code: 'DataBindingNotAllowed' | 'DuplicatedAttribute' | 'AvoidUppercaseLetters' | 'UnsupportedSyntax' | 'InvalidAttribute' | 'DuplicatedStylePropertyNames';
37
+ code: 'DataBindingNotAllowed' | 'DuplicatedAttribute' | 'AvoidUppercaseLetters' | 'UnsupportedSyntax' | 'InvalidAttribute' | 'DuplicatedStylePropertyNames' | 'TemplateLiteralInExpression' | 'TemplateChildNodes' | 'UnknownHtmlTag';
38
38
  message: string;
39
39
  /** wxml 字符偏移(定位用) */
40
40
  at: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proteus-vue/compiler",
3
- "version": "0.3.0-beta.12",
3
+ "version": "0.3.0-beta.15",
4
4
  "description": "Proteus 编译引擎 —— 标准 Vue SFC → 小程序四件套(纯函数、零运行时依赖、规则注册表 + AI 说明书)",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",