@aiot-toolkit/aiotpack 2.1.0-prender.14 → 2.1.0-prender.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.
@@ -1,4 +1,11 @@
1
1
  declare function uxToTemplateJson(templateNode: any, styleObjectId?: number, styleSheet?: any, importMap?: Record<string, string>, pageDir?: string, componentsMap?: Record<string, string>): any;
2
+ /**
3
+ * `for="x in expr"` / `for="(k, v) in expr"` declare loop variable names that the
4
+ * children reference verbatim (no `this.` prefix). If `repeat` loses `value`, runtime
5
+ * falls back to naming the item `$item` and every `x.*` reference in the subtree
6
+ * resolves to undefined — the rows render empty with no error.
7
+ */
8
+ declare function assertRepeatVariablePreserved(root: any, pageDir?: string): void;
2
9
  /**
3
10
  * Normalize a media query condition text from CSS Level 4 syntax to Level 3.
4
11
  *
@@ -14,6 +21,6 @@ declare function uxToTemplateJson(templateNode: any, styleObjectId?: number, sty
14
21
  declare function normalizeMediaQuery(condition: string): string;
15
22
  declare function parseStyleArray(code: string): Record<string, any>;
16
23
  /** Convert CSS text to css.json format */
17
- export { uxToTemplateJson, parseStyleArray, normalizeMediaQuery };
24
+ export { uxToTemplateJson, parseStyleArray, normalizeMediaQuery, assertRepeatVariablePreserved };
18
25
  /** Compute styleObjectId hash from a string (same algorithm as blueos-pack) */
19
26
  export declare function getStyleObjectId(name: string): number;
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.assertRepeatVariablePreserved = assertRepeatVariablePreserved;
6
7
  exports.getStyleObjectId = getStyleObjectId;
7
8
  exports.normalizeMediaQuery = normalizeMediaQuery;
8
9
  exports.parseStyleArray = parseStyleArray;
@@ -238,6 +239,7 @@ function uxToTemplateJson(templateNode, styleObjectId, styleSheet, importMap, pa
238
239
  const result = elementToJson(rootEl, styleSheet, importMap, undefined, pageDir);
239
240
  assertNoRelativeAssetPaths(result, pageDir);
240
241
  assertNoDelimitersInEvents(result, pageDir);
242
+ assertRepeatVariablePreserved(result, pageDir);
241
243
  const componentsForRoot = componentsMap && Object.keys(componentsMap).length ? componentsMap : importMap;
242
244
  if (componentsForRoot && Object.keys(componentsForRoot).length) {
243
245
  result.components = {
@@ -262,6 +264,16 @@ function uxToTemplateJson(templateNode, styleObjectId, styleSheet, importMap, pa
262
264
  // blueos-pack's pathTestRE: matches simple paths like a.b.c, a['key'], a[0], a[$idx]
263
265
  const pathTestRE = /^[A-Za-z_$][\w$]*(?:\.[\w$]+|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/;
264
266
 
267
+ // `for="x in expr"` declares a loop variable, so the variable names must survive in
268
+ // `repeat.{key,value}`. The whole binding therefore stays inside `repeat.$exp`, which
269
+ // holds a dotted path verbatim and anything else as a function string. `$repeat` is
270
+ // reserved for the variable-less `for="{{expr}}"` form, where runtime names the item
271
+ // `$item` itself.
272
+ const dottedPathRE = /^[a-zA-Z_$][\w$.]*$/;
273
+ function forRepeatExp(expr) {
274
+ return dottedPathRE.test(expr) ? expr : `function () { return ${addThisPrefix(expr)}; }`;
275
+ }
276
+
265
277
  // Attributes whose value is a resource path and therefore must be rewritten from
266
278
  // `./x` / `../x` (relative to the owning .ux file) to an rpk-root absolute path.
267
279
  // Runtime resolves <image src> against the rpk root, so a relative path emitted
@@ -430,6 +442,30 @@ function assertNoDelimitersInEvents(root, pageDir) {
430
442
  throw new Error(`[template] ${offenders.length} event handler(s) still contain template delimiters` + `${pageDir ? ` in ${pageDir}` : ''}. Runtime cannot compile or resolve these, so the ` + `events are silently dead:\n` + offenders.map(o => ` ${o}`).join('\n'));
431
443
  }
432
444
  }
445
+
446
+ /**
447
+ * `for="x in expr"` / `for="(k, v) in expr"` declare loop variable names that the
448
+ * children reference verbatim (no `this.` prefix). If `repeat` loses `value`, runtime
449
+ * falls back to naming the item `$item` and every `x.*` reference in the subtree
450
+ * resolves to undefined — the rows render empty with no error.
451
+ */
452
+ function assertRepeatVariablePreserved(root, pageDir) {
453
+ const offenders = [];
454
+ const walk = node => {
455
+ if (!node || typeof node !== 'object') return;
456
+ const repeat = node.repeat;
457
+ if (repeat && !Array.isArray(repeat) && typeof repeat === 'object') {
458
+ if (typeof repeat.value !== 'string' || !repeat.value) {
459
+ offenders.push(`<${node.type ?? '?'} repeat.$exp="${repeat['$exp']}">`);
460
+ }
461
+ }
462
+ if (Array.isArray(node.children)) node.children.forEach(walk);
463
+ };
464
+ walk(root);
465
+ if (offenders.length) {
466
+ throw new Error(`[template] ${offenders.length} repeat binding(s) lost the declared loop variable` + `${pageDir ? ` in ${pageDir}` : ''}:\n` + offenders.map(o => ` ${o}`).join('\n'));
467
+ }
468
+ }
433
469
  function tryEvalStaticShowLiteral(expr) {
434
470
  if (/^'[^']*'$/.test(expr) || /^"[^"]*"$/.test(expr)) {
435
471
  const inner = expr.slice(1, -1);
@@ -829,28 +865,18 @@ function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
829
865
  if (inMatch) {
830
866
  // for="(key, value) in expr" syntax
831
867
  const expr = inMatch[3].trim();
832
- if (/^[a-zA-Z_$][\w$.]*$/.test(expr)) {
833
- node['repeat'] = {
834
- '$exp': expr,
835
- key: inMatch[1],
836
- value: inMatch[2]
837
- };
838
- } else {
839
- node['$repeat'] = `function () { return ${addThisPrefix(expr)}; }`;
840
- node['repeat'] = [];
841
- }
868
+ node['repeat'] = {
869
+ '$exp': forRepeatExp(expr),
870
+ key: inMatch[1],
871
+ value: inMatch[2]
872
+ };
842
873
  } else if (simpleInMatch) {
843
874
  // for="value in expr" syntax
844
875
  const expr = simpleInMatch[2].trim();
845
- if (/^[a-zA-Z_$][\w$.]*$/.test(expr)) {
846
- node['repeat'] = {
847
- '$exp': expr,
848
- value: simpleInMatch[1]
849
- };
850
- } else {
851
- node['$repeat'] = `function () { return ${addThisPrefix(expr)}; }`;
852
- node['repeat'] = [];
853
- }
876
+ node['repeat'] = {
877
+ '$exp': forRepeatExp(expr),
878
+ value: simpleInMatch[1]
879
+ };
854
880
  } else if (pathTestRE.test(forVal)) {
855
881
  node['$repeat'] = forVal;
856
882
  node['repeat'] = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiot-toolkit/aiotpack",
3
- "version": "2.1.0-prender.14",
3
+ "version": "2.1.0-prender.15",
4
4
  "description": "The process tool for packaging aiot projects.",
5
5
  "keywords": [
6
6
  "aiotpack"
@@ -19,16 +19,16 @@
19
19
  "test": "node ./__tests__/aiotpack.test.js"
20
20
  },
21
21
  "dependencies": {
22
- "@aiot-toolkit/generator": "2.1.0-prender.14",
23
- "@aiot-toolkit/parser": "2.1.0-prender.14",
24
- "@aiot-toolkit/shared-utils": "2.1.0-prender.14",
22
+ "@aiot-toolkit/generator": "2.1.0-prender.15",
23
+ "@aiot-toolkit/parser": "2.1.0-prender.15",
24
+ "@aiot-toolkit/shared-utils": "2.1.0-prender.15",
25
25
  "@hap-toolkit/aaptjs": "^2.0.0",
26
26
  "@rspack/core": "^1.3.9",
27
27
  "acorn": "^8.16.0",
28
28
  "aiot-parse5": "^1.0.2",
29
29
  "astring": "^1.9.0",
30
30
  "babel-loader": "^9.1.3",
31
- "file-lane": "2.1.0-prender.14",
31
+ "file-lane": "2.1.0-prender.15",
32
32
  "file-loader": "^6.2.0",
33
33
  "fs-extra": "^11.2.0",
34
34
  "jsrsasign": "^11.1.0",