@dongmingzhixiu/vuexir-compiler 0.4.1 → 0.4.2

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.
@@ -810,7 +810,7 @@ function emitNodeInner(node, ctx) {
810
810
  let line = isRef
811
811
  ? pad(`Text(${props.ref})`)
812
812
  : props.bindExpr !== undefined
813
- ? pad(`Text(${props.bindExpr})`)
813
+ ? pad(`Text(${String(props.bindExpr).includes('.') ? '""' : props.bindExpr})`)
814
814
  : props.fieldOf !== undefined
815
815
  ? pad(`Text(vrnField(${props.fieldOf.obj}, "${props.fieldOf.field}"${props.fieldOf.fallback !== undefined ? `, "${swiftStringEscape(props.fieldOf.fallback)}"` : ''}))`)
816
816
  : props.dynField !== undefined
@@ -41,6 +41,8 @@ function addJsExprState(expr) {
41
41
  jsExprStates.push({ name, init: '', computed: js });
42
42
  return name;
43
43
  }
44
+ /** R125 当前生效的 v-for 作用域栈(绕开 loopScope 透传不一致的问题) */
45
+ let activeLoops = [];
44
46
  /** R115 是否允许未注册组件降级(由 vueToIr 选项设置) */
45
47
  let allowUnknownComponentsFlag = false;
46
48
  /** R104 脚本里声明过的名字(const/let/function)——未登记为 state 时走运行时求值 */
@@ -979,6 +981,7 @@ export function vueToIr(source, opts = {}) {
979
981
  jsExprSeq = 0;
980
982
  jsExprStates = [];
981
983
  allowUnknownComponentsFlag = opts.allowUnknownComponents === true;
984
+ activeLoops = [];
982
985
  const warnings = [];
983
986
  const { descriptor, errors } = parse(source, { filename: 'Screen.vue' });
984
987
  if (errors.length > 0) {
@@ -1417,12 +1420,18 @@ function walk(node, classProps, comboRules, scopedRules, pseudoRules, warnings,
1417
1420
  if (tri)
1418
1421
  return [{ type: 'text', props: { bindExpr: tri } }];
1419
1422
  // M2:v-for 循环变量(item/index)优先于状态表
1420
- const loopVar = loopScope.find((l) => l.itemKey === name || l.indexKey === name);
1423
+ const loopVar = loopScope.find((l) => l.itemKey === name || l.indexKey === name) ??
1424
+ [...activeLoops].reverse().find((l) => l.itemKey === name.split('.')[0] || l.indexKey === name.split('.')[0]);
1421
1425
  if (loopVar) {
1422
- // M4b 动态列表项属性访问 {{ item.field }} → dynField(Swift 侧 [String: Any] 字段取值)
1426
+ // M4b 动态列表项属性访问 {{ item.field }} / item.a.b → dynField(点路径拍平键)
1423
1427
  const dot = name.split('.');
1424
- if (dot.length === 2 && dot[0] === loopVar.itemKey && /^\w+$/.test(dot[1])) {
1425
- return [{ type: 'text', props: { dynField: { var: dot[0], field: dot[1] } } }];
1428
+ if (dot.length >= 2 && dot[0] === loopVar.itemKey && dot.slice(1).every((seg) => /^\w+$/.test(seg))) {
1429
+ return [{ type: 'text', props: { dynField: { var: dot[0], field: dot.slice(1).join('.') } } }];
1430
+ }
1431
+ // R126:循环体内出现复杂表达式(三元等)→ 原生端无法静态求值,置空避免非法代码
1432
+ if (!/^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*)*$/.test(name)) {
1433
+ warnings.push(`v-for 项内复杂表达式「${name.slice(0, 30)}」暂不支持 → 已置空(R126)`);
1434
+ return [{ type: 'text', props: { text: ' ' } }];
1426
1435
  }
1427
1436
  return [{ type: 'text', bind: { key: name } }];
1428
1437
  }
@@ -1707,10 +1716,12 @@ function walkElement(node, classProps, comboRules, scopedRules, pseudoRules, war
1707
1716
  ...node,
1708
1717
  props: node.props.filter((p) => !(p.type === NodeTypes.DIRECTIVE && p.name === 'for')),
1709
1718
  };
1719
+ activeLoops.push({ itemKey: vfSunk.itemKey, indexKey: vfSunk.indexKey });
1710
1720
  const itemSunk = walkElement(innerNodeSunk, classProps, comboRules, scopedRules, pseudoRules, warnings, state, compTable, propRefs, [
1711
1721
  ...loopScope,
1712
1722
  { itemKey: vfSunk.itemKey, indexKey: vfSunk.indexKey },
1713
1723
  ], ancestorClasses);
1724
+ activeLoops.pop();
1714
1725
  return { type: 'for', vfor: vfSunk, children: [itemSunk] };
1715
1726
  }
1716
1727
  }
@@ -1746,10 +1757,12 @@ function walkElement(node, classProps, comboRules, scopedRules, pseudoRules, war
1746
1757
  throw new VueCompileError(`v-for 动态数据源「${vf.listState}」未在 <script setup> 中声明为 ref 数组(M4b)`);
1747
1758
  }
1748
1759
  const innerNode = { ...node, props: node.props.filter((p) => !(p.type === NodeTypes.DIRECTIVE && p.name === 'for')) };
1760
+ activeLoops.push({ itemKey: vf.itemKey, indexKey: vf.indexKey });
1749
1761
  const item = walkElement(innerNode, classProps, comboRules, scopedRules, pseudoRules, warnings, state, compTable, propRefs, [
1750
1762
  ...loopScope,
1751
1763
  { itemKey: vf.itemKey, indexKey: vf.indexKey },
1752
1764
  ], ancestorClasses);
1765
+ activeLoops.pop();
1753
1766
  return { type: 'for', vfor: vf, children: [item] };
1754
1767
  }
1755
1768
  // R76 Vue 内置容器组件(Transition/KeepAlive/Teleport/Suspense/Fragment)→ 透明展开:
@@ -2000,7 +2013,8 @@ function walkElement(node, classProps, comboRules, scopedRules, pseudoRules, war
2000
2013
  // 动态列表项属性 {{ item.field }}:基名(dot[0])命中循环变量才成立
2001
2014
  const dot = name.split('.');
2002
2015
  const base = dot[0];
2003
- const loopVar = loopScope.find((l) => l.itemKey === base || l.indexKey === base);
2016
+ const loopVar = loopScope.find((l) => l.itemKey === base || l.indexKey === base) ??
2017
+ [...activeLoops].reverse().find((l) => l.itemKey === base || l.indexKey === base);
2004
2018
  const dyn = loopVar && dot.length >= 2 && dot[0] === loopVar.itemKey && dot.slice(1).every((seg) => /^\w+$/.test(seg));
2005
2019
  if (!text && !parts.some((p) => 'bind' in p || 'dynField' in p || 'fieldOf' in p)) {
2006
2020
  // M2 模板内三元(D1 小范围):cond ? 'a' : 'b' → Swift 三元字符串表达式(Text(expr))
@@ -2069,7 +2083,7 @@ function walkElement(node, classProps, comboRules, scopedRules, pseudoRules, war
2069
2083
  }
2070
2084
  // 混合段:静态文本之后的插值
2071
2085
  if (dyn)
2072
- parts.push({ dynField: { var: dot[0], field: dot[1] } });
2086
+ parts.push({ dynField: { var: dot[0], field: dot.slice(1).join('.') } });
2073
2087
  else if (/^\w+$/.test(name) && (loopVar || (state && state.states.some((s) => s.name === name))))
2074
2088
  parts.push({ bind: name });
2075
2089
  else if (propRefs)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dongmingzhixiu/vuexir-compiler",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "Vue SFC → IR → 原生源码(SwiftUI / Compose)编译器核心:纯函数、零 IO",
5
5
  "type": "module",
6
6
  "license": "MIT",