@dongmingzhixiu/vuexir-compiler 0.3.16 → 0.3.18

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.
@@ -434,11 +434,35 @@ function kotlinCondExpr(expr) {
434
434
  return `vrnField(${f[1]}, "${f[2]}").isNotEmpty()`;
435
435
  let s = expr.replace(/!==/g, '!=').replace(/===/g, '==');
436
436
  s = s.replace(/'(\\[^]|[^'\\])*'/g, (m) => '"' + m.slice(1, -1).replace(/"/g, '\\"') + '"');
437
+ // R113:对象字段条件 → vrnField 取值判空
438
+ const negField = s.match(/^!([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)$/);
439
+ if (negField)
440
+ return `vrnField(${negField[1]}, "${negField[2]}").isEmpty()`;
441
+ const posField = s.match(/^([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)$/);
442
+ if (posField)
443
+ return `vrnField(${posField[1]}, "${posField[2]}").isNotEmpty()`;
444
+ const cmpField = s.match(/^([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)\s*(==|!=)\s*(.+)$/);
445
+ if (cmpField)
446
+ return `vrnField(${cmpField[1]}, "${cmpField[2]}") ${cmpField[3]} ${cmpField[4]}`;
447
+ const andExpr = s.match(/^([A-Za-z_$][\w$.]*)\s*&&\s*([A-Za-z_$][\w$.]*)$/);
448
+ if (andExpr) {
449
+ const truthy = (v) => v.includes('.') ? `vrnField(${v.split('.')[0]}, "${v.split('.').slice(1).join('.')}").isNotEmpty()` : `${v}.toString().isNotEmpty()`;
450
+ return `${truthy(andExpr[1])} && ${truthy(andExpr[2])}`;
451
+ }
452
+ // R111:Kotlin 不接受 String/Int 当条件 → 统一判真
453
+ const neg = s.match(/^!([A-Za-z_$][\w$]*)(?:\.length)?$/);
454
+ if (neg)
455
+ return `vrnTruthy(${neg[1]}.toString()).not()`;
456
+ if (/^[A-Za-z_$][\w$]*\.length$/.test(s))
457
+ return `${s} > 0`;
458
+ if (/^[A-Za-z_$][\w$]*$/.test(s) && !['true', 'false'].includes(s))
459
+ return `vrnTruthy(${s}.toString())`;
437
460
  return s;
438
461
  }
439
462
  /** Swift 风格字符串表达式 → Kotlin(三元 c ? a : b → if (c) a else b;引号归一双引号) */
440
463
  function kotlinStringExpr(expr) {
441
- let s = expr.replace(/'(\\[^]|[^'\\])*'/g, (m) => '"' + m.slice(1, -1).replace(/"/g, '\\"') + '"');
464
+ let s0 = expr.replace(/vrnTruthy\(String\(([A-Za-z_$][\w$]*)\)\)/g, (_m, id) => `vrnTruthy(${id}.toString())`);
465
+ let s = s0.replace(/'(\\[^]|[^'\\])*'/g, (m) => '"' + m.slice(1, -1).replace(/"/g, '\\"') + '"');
442
466
  const ternary = s.match(/^([^?]+)\?([^:]+):(.+)$/);
443
467
  if (ternary) {
444
468
  return `if (${ternary[1].trim()}) ${ternary[2].trim()} else ${ternary[3].trim()}`;
@@ -1034,10 +1058,10 @@ function emitNodeInner(node, ctx, depth, loop, useParamModifier = false, parentS
1034
1058
  pre += cpad + 'Spacer(\n' + cpad + ' modifier = Modifier.width(' + dp(cp.marginLeft) + '),\n' + cpad + ')\n';
1035
1059
  }
1036
1060
  if (kind === 'Row' && cp.marginRight !== undefined) {
1037
- post = post + cpad + 'Spacer(\n' + cpad + ' modifier = Modifier.width(' + dp(cp.marginRight) + '),\n' + cpad + ')\n';
1061
+ post = post + '\n' + cpad + 'Spacer(\n' + cpad + ' modifier = Modifier.width(' + dp(cp.marginRight) + '),\n' + cpad + ')\n';
1038
1062
  }
1039
1063
  if (kind === 'Column' && cp.marginBottom !== undefined) {
1040
- post = post + cpad + 'Spacer(\n' + cpad + ' modifier = Modifier.height(' + dp(cp.marginBottom) + '),\n' + cpad + ')\n';
1064
+ post = post + '\n' + cpad + 'Spacer(\n' + cpad + ' modifier = Modifier.height(' + dp(cp.marginBottom) + '),\n' + cpad + ')\n';
1041
1065
  }
1042
1066
  const stretch = kind === 'Column' && cp.width === undefined && cp.flex === undefined && cp.position !== 'absolute' && !cp.marginLeftAuto;
1043
1067
  return pre + emitNode(c, ctx, d, undefined, false, stretch) + post;
@@ -1188,7 +1212,7 @@ function emitNodeInner(node, ctx, depth, loop, useParamModifier = false, parentS
1188
1212
  case 'button': {
1189
1213
  const chain = modChain([...stretchModifiers(parentStretch, node), ...sizeModifiers(p), ...absModifiers(p), ...clipModifiers(p), ...visualModifiers(p), ...borderModifiers(p), ...paddingModifiers(p), ...alphaArr, ...transformModifiers(p)], pad + ' ');
1190
1214
  // R108:动态按钮文案(props.bind)优先;Kotlin 里用字符串模板插值
1191
- const label = p.bind !== undefined ? '"${' + String(p.bind) + '}"' : (p.label ?? '');
1215
+ const label = p.bind !== undefined ? String(p.bind) : (p.label ?? '');
1192
1216
  const click = kotlinClickAction(p, ctx, loop);
1193
1217
  const labelStyle = [];
1194
1218
  if (p.fontSize !== undefined)
@@ -527,9 +527,26 @@ function swiftCondExpr(expr) {
527
527
  // R110:数值状态直接当条件(Swift 不接受 Int 当 Bool)
528
528
  if (/^[A-Za-z_$][\w$]*$/.test(s))
529
529
  return `vrnTruthy(String(${s}))`;
530
+ // R113:对象字段条件(form.avatarData)→ 走 vrnField 取 JSON 字段
531
+ const negField = s.match(/^!([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)$/);
532
+ if (negField)
533
+ return `vrnField(${negField[1]}, "${negField[2]}").isEmpty`;
534
+ const posField = s.match(/^([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)$/);
535
+ if (posField)
536
+ return `!vrnField(${posField[1]}, "${posField[2]}").isEmpty`;
537
+ // R113:对象字段比较(form.calendar == "gregorian")→ vrnField 取值后比较
538
+ const cmpField = s.match(/^([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)\s*(==|!=)\s*(.+)$/);
539
+ if (cmpField)
540
+ return `vrnField(${cmpField[1]}, "${cmpField[2]}") ${cmpField[3]} ${cmpField[4]}`;
530
541
  // R110:裸标识符条件(状态可能是字符串/对象/布尔)→ 统一走判真
531
542
  if (/^[A-Za-z_$][\w$]*$/.test(s) && !['true', 'false'].includes(s))
532
543
  return `vrnTruthy(String(${s}))`;
544
+ // R112:循环项字段的 && 组合(item && item.cd)→ 判真
545
+ const andExpr = s.match(/^([A-Za-z_$][\w$.]*)\s*&&\s*([A-Za-z_$][\w$.]*)$/);
546
+ if (andExpr) {
547
+ const truthy = (v) => (v.includes('.') ? `!vrnField(${v.split('.')[0]}, "${v.split('.').slice(1).join('.')}").isEmpty` : `vrnTruthy(String(${v}))`);
548
+ return `${truthy(andExpr[1])} && ${truthy(andExpr[2])}`;
549
+ }
533
550
  return s;
534
551
  }
535
552
  function emitNodeInner(node, ctx) {
@@ -1413,12 +1413,20 @@ function matchFieldPath(name) {
1413
1413
  }
1414
1414
  function parseTernaryExpr(exp) {
1415
1415
  const t = exp.trim();
1416
+ // R113:三元里出现对象字段访问(form.avatarData)时,静态翻译做不到 →
1417
+ // 直接返回 null,交给表达式下沉在 JS 运行时求值(结果一致且两端都能用)
1418
+ if (/[A-Za-z_$][\w$]*\.[A-Za-z_$][\w$]*/.test(t))
1419
+ return null;
1416
1420
  const m = t.match(/^(.+?)\s*\?\s*'([^']+)'\s*:\s*'([^']+)'$/);
1417
1421
  if (!m)
1418
1422
  return null;
1419
- const cond = swiftExpr(m[1]);
1423
+ let cond = swiftExpr(m[1]);
1420
1424
  if (cond === null)
1421
1425
  return null;
1426
+ // R112:三元条件里的字符串/数字状态要判真(Swift/Kotlin 不接受非 Bool 条件)
1427
+ if (/^[A-Za-z_$][\w$]*$/.test(cond) && !['true', 'false'].includes(cond)) {
1428
+ cond = `vrnTruthy(String(${cond}))`;
1429
+ }
1422
1430
  return `${cond} ? "${m[2]}" : "${m[3]}"`;
1423
1431
  }
1424
1432
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dongmingzhixiu/vuexir-compiler",
3
- "version": "0.3.16",
3
+ "version": "0.3.18",
4
4
  "description": "Vue SFC → IR → 原生源码(SwiftUI / Compose)编译器核心:纯函数、零 IO",
5
5
  "type": "module",
6
6
  "license": "MIT",