@aiot-toolkit/aiotpack 2.1.0-prender.11 → 2.1.0-prender.13

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.
@@ -22,6 +22,16 @@ declare class UxAfterCompile {
22
22
  * @param params
23
23
  */
24
24
  static compressResource: FollowWork<IJavascriptCompileOption>;
25
+ /**
26
+ * Relocate manifest.icon into build root so debug and release rpks share the
27
+ * same asset layout. Rewrites `manifest.icon` + every string reference to the
28
+ * old icon path inside template.json / css.json / *.js. Files are text-scanned
29
+ * and quoted-substring matched only (no cross-string boundary rewriting).
30
+ *
31
+ * No-op when manifest.icon is already at root, the physical file is missing,
32
+ * or the destination basename already exists at root.
33
+ */
34
+ static relocateManifestIcon: FollowWork<IJavascriptCompileOption>;
25
35
  /**
26
36
  * 如果是更新触发,则对比临时项目build文件夹 和 项目build文件夹,生成diff.json
27
37
  * @param context
@@ -99,8 +99,12 @@ class UxAfterCompile {
99
99
  context,
100
100
  compilerOption
101
101
  } = params;
102
- if (compilerOption && compilerOption.enableJsc === true) {
103
- return new _Jsc.default(context.projectPath, _path.default.join(context.projectPath, context.output, compilerOption.outputPath)).jsc();
102
+ if (compilerOption) {
103
+ const buildPath = _path.default.join(context.projectPath, context.output, compilerOption.outputPath);
104
+ _Jsc.default.wrapAllJsWithIife(buildPath);
105
+ if (compilerOption.enableJsc === true) {
106
+ return new _Jsc.default(context.projectPath, buildPath).jsc();
107
+ }
104
108
  }
105
109
  };
106
110
  static toRpk = async params => {
@@ -334,6 +338,78 @@ class UxAfterCompile {
334
338
  }
335
339
  };
336
340
 
341
+ /**
342
+ * Relocate manifest.icon into build root so debug and release rpks share the
343
+ * same asset layout. Rewrites `manifest.icon` + every string reference to the
344
+ * old icon path inside template.json / css.json / *.js. Files are text-scanned
345
+ * and quoted-substring matched only (no cross-string boundary rewriting).
346
+ *
347
+ * No-op when manifest.icon is already at root, the physical file is missing,
348
+ * or the destination basename already exists at root.
349
+ */
350
+ static relocateManifestIcon = async params => {
351
+ const {
352
+ compilerOption,
353
+ onLog
354
+ } = params;
355
+ if (!compilerOption) return;
356
+ const {
357
+ projectPath,
358
+ outputPath
359
+ } = compilerOption;
360
+ const buildDir = _path.default.join(projectPath, outputPath);
361
+ const manifestPath = _path.default.join(buildDir, 'manifest.json');
362
+ if (!_fsExtra.default.existsSync(manifestPath)) return;
363
+ const manifest = _fsExtra.default.readJSONSync(manifestPath);
364
+ const oldIcon = manifest.icon;
365
+ if (!oldIcon || typeof oldIcon !== 'string') return;
366
+ const basename = _path.default.basename(oldIcon);
367
+ const newIcon = '/' + basename;
368
+ if (oldIcon === newIcon) return;
369
+ const oldFile = _path.default.join(buildDir, oldIcon.replace(/^\//, ''));
370
+ const newFile = _path.default.join(buildDir, basename);
371
+ if (!_fsExtra.default.existsSync(oldFile)) return;
372
+ if (_fsExtra.default.existsSync(newFile)) {
373
+ onLog?.([{
374
+ level: _sharedUtils.Loglevel.WARN,
375
+ message: [`relocateManifestIcon: skipped — build root already contains ${basename}`]
376
+ }]);
377
+ return;
378
+ }
379
+ _fsExtra.default.moveSync(oldFile, newFile);
380
+ manifest.icon = newIcon;
381
+ _fsExtra.default.writeJSONSync(manifestPath, manifest, {
382
+ spaces: 2
383
+ });
384
+ const variants = [oldIcon, oldIcon.replace(/^\//, '')];
385
+ const replacements = [];
386
+ for (const v of variants) {
387
+ const target = v === oldIcon ? newIcon : basename;
388
+ replacements.push([JSON.stringify(v), JSON.stringify(target)]);
389
+ replacements.push([`'${v}'`, `'${target}'`]);
390
+ }
391
+ const rewriteFile = fp => {
392
+ let text;
393
+ try {
394
+ text = _fsExtra.default.readFileSync(fp, 'utf-8');
395
+ } catch {
396
+ return;
397
+ }
398
+ let changed = false;
399
+ for (const [from, to] of replacements) {
400
+ if (text.includes(from)) {
401
+ text = text.split(from).join(to);
402
+ changed = true;
403
+ }
404
+ }
405
+ if (changed) _fsExtra.default.writeFileSync(fp, text, 'utf-8');
406
+ };
407
+ for (const fp of _sharedUtils.FileUtil.readAlldirSync(buildDir)) {
408
+ if (fp === manifestPath) continue;
409
+ if (/\.(template\.json|css\.json|js|jsx?)$/.test(fp)) rewriteFile(fp);
410
+ }
411
+ };
412
+
337
413
  /**
338
414
  * 如果是更新触发,则对比临时项目build文件夹 和 项目build文件夹,生成diff.json
339
415
  * @param context
@@ -1,4 +1,4 @@
1
- declare function uxToTemplateJson(templateNode: any, styleObjectId?: number, styleSheet?: any, importMap?: Record<string, string>, pageDir?: string): any;
1
+ declare function uxToTemplateJson(templateNode: any, styleObjectId?: number, styleSheet?: any, importMap?: Record<string, string>, pageDir?: string, componentsMap?: Record<string, string>): any;
2
2
  /**
3
3
  * Normalize a media query condition text from CSS Level 4 syntax to Level 3.
4
4
  *
@@ -35,6 +35,81 @@ function hasApplicableMediaRule(styleSheet, tagName, classTokens) {
35
35
  }
36
36
  return false;
37
37
  }
38
+ // Parse a simple/compound selector like ".a", ".a.b", "text", "text.a", ".a #id"
39
+ // (id treated as a class token for build-time approximation).
40
+ function parseCompoundSelector(part) {
41
+ const out = {
42
+ classes: []
43
+ };
44
+ const re = /(\.[\w-]+)|(#[\w-]+)|(\*)|([a-zA-Z][\w-]*)/g;
45
+ let m;
46
+ let matched = false;
47
+ while ((m = re.exec(part)) !== null) {
48
+ matched = true;
49
+ if (m[1]) out.classes.push(m[1].slice(1));else if (m[2]) out.classes.push(m[2].slice(1));else if (m[4]) out.tag = m[4];
50
+ }
51
+ return matched ? out : null;
52
+ }
53
+ function matchesCompound(comp, tag, classes) {
54
+ if (comp.tag && comp.tag !== tag) return false;
55
+ for (const c of comp.classes) if (!classes.has(c)) return false;
56
+ return true;
57
+ }
58
+
59
+ // Match a CSS selector against an element + its ancestor chain (root...parent).
60
+ // Supports descendant, child (>), and compound (.a.b) selectors. Sibling
61
+ // combinators (+, ~) require sibling context and are treated as non-match here.
62
+ function selectorMatchesElement(selector, tag, classes, ancestors) {
63
+ const parts = [];
64
+ const combinators = [];
65
+ let cur = '';
66
+ for (let i = 0; i < selector.length; i++) {
67
+ const ch = selector[i];
68
+ if (ch === '>' || ch === '+' || ch === '~') {
69
+ if (cur.trim()) parts.push(cur.trim());
70
+ combinators.push(ch);
71
+ cur = '';
72
+ } else if (ch === ' ' || ch === '\t') {
73
+ if (cur.trim()) {
74
+ parts.push(cur.trim());
75
+ combinators.push(' ');
76
+ cur = '';
77
+ }
78
+ } else {
79
+ cur += ch;
80
+ }
81
+ }
82
+ if (cur.trim()) parts.push(cur.trim());
83
+ if (parts.length === 0) return false;
84
+ const rightMost = parseCompoundSelector(parts[parts.length - 1]);
85
+ if (!rightMost) return false;
86
+ if (!matchesCompound(rightMost, tag, classes)) return false;
87
+ let idx = ancestors.length - 1;
88
+ for (let i = parts.length - 2; i >= 0; i--) {
89
+ const combinator = combinators[i];
90
+ const simple = parseCompoundSelector(parts[i]);
91
+ if (!simple) return false;
92
+ if (combinator === ' ') {
93
+ let found = false;
94
+ while (idx >= 0) {
95
+ if (matchesCompound(simple, ancestors[idx].tag, ancestors[idx].classes)) {
96
+ idx--;
97
+ found = true;
98
+ break;
99
+ }
100
+ idx--;
101
+ }
102
+ if (!found) return false;
103
+ } else if (combinator === '>') {
104
+ if (idx < 0) return false;
105
+ if (!matchesCompound(simple, ancestors[idx].tag, ancestors[idx].classes)) return false;
106
+ idx--;
107
+ } else {
108
+ return false;
109
+ }
110
+ }
111
+ return true;
112
+ }
38
113
 
39
114
  // vivo blueos-pack's aggressive camelCase applied to transition-property values.
40
115
  // Every letter that follows a non-letter character (separator or digit) is upper-cased,
@@ -156,11 +231,17 @@ function normalizeCssTransform(input) {
156
231
  }
157
232
  return matched ? JSON.stringify(out) : null;
158
233
  }
159
- function uxToTemplateJson(templateNode, styleObjectId, styleSheet, importMap, pageDir) {
234
+ function uxToTemplateJson(templateNode, styleObjectId, styleSheet, importMap, pageDir, componentsMap) {
160
235
  const children = templateNode.content?.childNodes || templateNode.childNodes || [];
161
236
  const rootEl = children.find(n => n.tagName && n.nodeName !== '#text');
162
237
  if (!rootEl) return {};
163
238
  const result = elementToJson(rootEl, styleSheet, importMap, undefined, pageDir);
239
+ const componentsForRoot = componentsMap && Object.keys(componentsMap).length ? componentsMap : importMap;
240
+ if (componentsForRoot && Object.keys(componentsForRoot).length) {
241
+ result.components = {
242
+ ...componentsForRoot
243
+ };
244
+ }
164
245
  // Insert styleObjectId before children (vivo format)
165
246
  if (styleObjectId !== undefined) {
166
247
  const ordered = {};
@@ -178,6 +259,16 @@ function uxToTemplateJson(templateNode, styleObjectId, styleSheet, importMap, pa
178
259
  /** Add this. prefix to variable references in an expression */
179
260
  // blueos-pack's pathTestRE: matches simple paths like a.b.c, a['key'], a[0], a[$idx]
180
261
  const pathTestRE = /^[A-Za-z_$][\w$]*(?:\.[\w$]+|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/;
262
+ function tryEvalStaticShowLiteral(expr) {
263
+ if (/^'[^']*'$/.test(expr) || /^"[^"]*"$/.test(expr)) {
264
+ const inner = expr.slice(1, -1);
265
+ return inner.length > 0;
266
+ }
267
+ if (expr === 'undefined' || expr === 'null' || expr === 'NaN') return false;
268
+ if (expr === 'Infinity') return true;
269
+ return undefined;
270
+ }
271
+
181
272
  /**
182
273
  * Normalize a media query condition text from CSS Level 4 syntax to Level 3.
183
274
  *
@@ -469,6 +560,7 @@ function emitTextValueAttr(rawText) {
469
560
  };
470
561
  }
471
562
  function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
563
+ let ancestors = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : [];
472
564
  const tagName = el.tagName === 'img' ? 'image' : el.tagName;
473
565
  const node = {
474
566
  type: tagName
@@ -493,9 +585,7 @@ function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
493
585
  name = name.slice(1);
494
586
  if (!value.includes('{{')) value = `{{${value}}}`;
495
587
  }
496
- if (name === 'is' && tagName === 'component') {
497
- continue; // is attribute handled at runtime
498
- } else if (name === 'class') {
588
+ if (name === 'class') {
499
589
  className = value.replace(/\s+/g, ' ').trim();
500
590
  } else if (name.startsWith('@') || name.startsWith('on') && name.length > 2) {
501
591
  const rawEvtName = name.startsWith('@') ? name.slice(1) : name.replace(/^on/, '');
@@ -538,13 +628,20 @@ function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
538
628
  } else if (name === 'show') {
539
629
  const showVal = value.replace(/\{\{|\}\}/g, '').trim();
540
630
  if (showVal === 'true') attrObj['show'] = true;else if (showVal === 'false') attrObj['show'] = false;else {
541
- // Try to evaluate as literal
542
631
  try {
543
632
  const v = JSON.parse(showVal);
544
633
  attrObj["show"] = v;
545
634
  } catch {
546
- attrObj['$show'] = showVal;
547
- hasBind = true;
635
+ const staticVal = tryEvalStaticShowLiteral(showVal);
636
+ if (staticVal !== undefined) {
637
+ attrObj['show'] = staticVal;
638
+ } else if (pathTestRE.test(showVal)) {
639
+ attrObj['$show'] = showVal;
640
+ hasBind = true;
641
+ } else {
642
+ attrObj['$show'] = `function () { return ${addThisPrefix(showVal)}; }`;
643
+ hasBind = true;
644
+ }
548
645
  }
549
646
  }
550
647
  } else if (name === 'for') {
@@ -764,15 +861,15 @@ function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
764
861
  // @media rules are applied at runtime by SDK, not inlined here.
765
862
  // Class rules apply in stylesheet declaration order (later declarations override earlier),
766
863
  // NOT in class-attribute order.
767
- if (styleSheet) {
768
- const staticClassTokens = [];
769
- if (className) {
770
- const parts = className.split(/(\{\{[\s\S]*?\}\})/).filter(Boolean);
771
- for (const p of parts) {
772
- if (/^\{\{[\s\S]*?\}\}$/.test(p)) continue;
773
- for (const tok of p.trim().split(/\s+/)) if (tok) staticClassTokens.push(tok);
774
- }
864
+ const staticClassTokens = [];
865
+ if (className) {
866
+ const parts = className.split(/(\{\{[\s\S]*?\}\})/).filter(Boolean);
867
+ for (const p of parts) {
868
+ if (/^\{\{[\s\S]*?\}\}$/.test(p)) continue;
869
+ for (const tok of p.trim().split(/\s+/)) if (tok) staticClassTokens.push(tok);
775
870
  }
871
+ }
872
+ if (styleSheet) {
776
873
  const hasMedia = hasApplicableMediaRule(styleSheet, el.tagName, staticClassTokens);
777
874
  // Skip class-rule merge when the node has any dynamic binding OR any @media
778
875
  // rule that applies to it — runtime must resolve class chain against the
@@ -794,11 +891,19 @@ function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
794
891
  if (Object.keys(inlined).length) node.style = inlined;
795
892
  } else {
796
893
  const merged = {};
797
- if (styleSheet[el.tagName]) Object.assign(merged, styleSheet[el.tagName]);
798
- if (staticClassTokens.length) {
799
- const classSet = new Set(staticClassTokens);
800
- for (const key of Object.keys(styleSheet)) {
801
- if (key.length > 1 && key.startsWith('.') && classSet.has(key.slice(1))) {
894
+ const classSet = new Set(staticClassTokens);
895
+ for (const key of Object.keys(styleSheet)) {
896
+ if (key.startsWith('@')) continue;
897
+ if (key === el.tagName) {
898
+ Object.assign(merged, styleSheet[key]);
899
+ continue;
900
+ }
901
+ if (key.length > 1 && key.startsWith('.') && !/[\s>+~.]/.test(key.slice(1))) {
902
+ if (classSet.has(key.slice(1))) Object.assign(merged, styleSheet[key]);
903
+ continue;
904
+ }
905
+ if (/[\s>+~]/.test(key) || /\.[\w-]+\./.test(key)) {
906
+ if (selectorMatchesElement(key, el.tagName, classSet, ancestors)) {
802
907
  Object.assign(merged, styleSheet[key]);
803
908
  }
804
909
  }
@@ -823,7 +928,10 @@ function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
823
928
  const isMixedContent = hasElementChildren && hasTextChildren && (tagName === 'text' || tagName === 'span' || tagName === 'a' || tagName === 'marquee');
824
929
  for (const child of el.childNodes || []) {
825
930
  if (child.tagName) {
826
- childNodes.push(elementToJson(child, styleSheet, importMap, scopeVars, pageDir));
931
+ childNodes.push(elementToJson(child, styleSheet, importMap, scopeVars, pageDir, [...ancestors, {
932
+ tag: el.tagName,
933
+ classes: new Set(staticClassTokens)
934
+ }]));
827
935
  } else if (isMixedContent && child.value?.trim()) {
828
936
  const emitted = emitTextValueAttr(child.value);
829
937
  const spanNode = {
@@ -11,7 +11,9 @@ declare class ViteCompiler implements ICompiler {
11
11
  clean(param: ICompileParam & IJavascriptCompileOption): Promise<void>;
12
12
  }
13
13
  declare function stripDeadDefProp(code: string): string;
14
+ declare function mergeStyleSheets(app: any, page: any): any;
14
15
  export declare const __test: {
15
16
  stripDeadDefProp: typeof stripDeadDefProp;
17
+ mergeStyleSheets: typeof mergeStyleSheets;
16
18
  };
17
19
  export default ViteCompiler;
@@ -90,12 +90,43 @@ function rewriteSystemImports(code) {
90
90
  replacement: parts.join(' ')
91
91
  });
92
92
  }
93
+ // Rewrite CJS require() calls for system modules: require('@system.xxx') → $app_require$("@app-module/system.xxx")
94
+ collectRequireEdits(ast, edits);
93
95
  if (edits.length === 0) return code;
94
96
  edits.sort((a, b) => b.start - a.start);
95
97
  let out = code;
96
98
  for (const e of edits) out = out.slice(0, e.start) + e.replacement + out.slice(e.end);
97
99
  return out;
98
100
  }
101
+ function collectRequireEdits(node, edits) {
102
+ if (!node || typeof node !== 'object') return;
103
+ if (node.type === 'CallExpression' && node.callee?.type === 'Identifier' && node.callee.name === 'require' && node.arguments?.length === 1 && node.arguments[0].type === 'Literal' && typeof node.arguments[0].value === 'string') {
104
+ const src = node.arguments[0].value;
105
+ let moduleName = null;
106
+ if (NS_PREFIX.test(src)) {
107
+ moduleName = src.replace(NS_PREFIX, '$1.');
108
+ } else if (src.startsWith(APP_MODULE_PREFIX)) {
109
+ moduleName = src.slice(APP_MODULE_PREFIX.length);
110
+ }
111
+ if (moduleName !== null) {
112
+ edits.push({
113
+ start: node.start,
114
+ end: node.end,
115
+ replacement: `$app_require$("${APP_MODULE_PREFIX}${moduleName}")`
116
+ });
117
+ return;
118
+ }
119
+ }
120
+ for (const key of Object.keys(node)) {
121
+ if (key === 'start' || key === 'end' || key === 'type') continue;
122
+ const val = node[key];
123
+ if (Array.isArray(val)) {
124
+ for (const child of val) collectRequireEdits(child, edits);
125
+ } else if (val && typeof val === 'object' && val.type) {
126
+ collectRequireEdits(val, edits);
127
+ }
128
+ }
129
+ }
99
130
  function loadUserViteConfig(projectPath, mode) {
100
131
  const configPath = _path.default.join(projectPath, 'quickapp.config.js');
101
132
  if (!_fsExtra.default.existsSync(configPath)) return {};
@@ -246,6 +277,7 @@ class ViteCompiler {
246
277
  }
247
278
  const entryFailures = [];
248
279
  let entryAttempted = 0;
280
+ let appStyleSheet = {};
249
281
  for (const [entryName, entryValue] of Object.entries(entries)) {
250
282
  const entryPath = entryValue.split('?')[0];
251
283
  const resolvedEntry = _path.default.resolve(originalProjectPath, entryPath);
@@ -396,6 +428,7 @@ class ViteCompiler {
396
428
  });
397
429
  let templateNode = null;
398
430
  const importMap = {}; // name -> path
431
+ const componentsMap = {}; // originalName -> path
399
432
  for (const node of doc.childNodes) {
400
433
  if (node.nodeName === 'template') templateNode = node;else if (node.nodeName === 'import') {
401
434
  const nameAttr = node.attrs?.find(a => a.name === 'name');
@@ -404,6 +437,7 @@ class ViteCompiler {
404
437
  const compAbsPath = _path.default.resolve(_path.default.dirname(resolvedEntry), srcAttr.value).replace(/\.ux$/, '');
405
438
  const compPath = _path.default.relative(srcPath, compAbsPath).replace(/\\/g, '/');
406
439
  importMap[nameAttr.value.toLowerCase()] = compPath;
440
+ componentsMap[nameAttr.value] = compPath;
407
441
  }
408
442
  }
409
443
  }
@@ -427,6 +461,9 @@ class ViteCompiler {
427
461
  if (styleLiteral) {
428
462
  styleSheet = (0, _TemplateCompiler.parseStyleArray)(styleLiteral);
429
463
  }
464
+ if (isApp) {
465
+ appStyleSheet = styleSheet;
466
+ }
430
467
  // Write css.json
431
468
  const cssPath = _path.default.join(buildPath, `${isApp ? 'app' : pageName}.css.json`);
432
469
  _fsExtra.default.ensureDirSync(_path.default.dirname(cssPath));
@@ -439,7 +476,8 @@ class ViteCompiler {
439
476
  if (templateNode && !isApp) {
440
477
  const tplPath = _path.default.join(buildPath, `${pageName}.template.json`);
441
478
  _fsExtra.default.ensureDirSync(_path.default.dirname(tplPath));
442
- _fsExtra.default.writeJSONSync(tplPath, (0, _TemplateCompiler.uxToTemplateJson)(templateNode, sid, styleSheet, importMap, _path.default.dirname(pageName)), param.mode === 'production' ? undefined : {
479
+ const mergedSheet = mergeStyleSheets(appStyleSheet, styleSheet);
480
+ _fsExtra.default.writeJSONSync(tplPath, (0, _TemplateCompiler.uxToTemplateJson)(templateNode, sid, mergedSheet, importMap, _path.default.dirname(pageName), componentsMap), param.mode === 'production' ? undefined : {
443
481
  spaces: 2
444
482
  });
445
483
  // Worklist BFS over nested <import> chain so transitively imported
@@ -469,6 +507,7 @@ class ViteCompiler {
469
507
  });
470
508
  let compTpl = null;
471
509
  const compImportMap = {};
510
+ const compComponentsMap = {};
472
511
  for (const node of compDoc.childNodes) {
473
512
  if (node.nodeName === 'template') compTpl = node;else if (node.nodeName === 'import') {
474
513
  const n = node.attrs?.find(a => a.name === 'name');
@@ -477,6 +516,7 @@ class ViteCompiler {
477
516
  const nestedAbsPath = _path.default.resolve(_path.default.dirname(compUxPath), s.value).replace(/\.ux$/, '');
478
517
  const nestedPath = _path.default.relative(srcPath, nestedAbsPath).replace(/\\/g, '/');
479
518
  compImportMap[n.value.toLowerCase()] = nestedPath;
519
+ compComponentsMap[n.value] = nestedPath;
480
520
  if (!visited.has(nestedPath)) {
481
521
  worklist.push({
482
522
  compName: n.value.toLowerCase(),
@@ -504,7 +544,7 @@ class ViteCompiler {
504
544
  compStyleSheet = (0, _TemplateCompiler.parseStyleArray)(csm);
505
545
  }
506
546
  const compSid = (0, _TemplateCompiler.getStyleObjectId)(compPath);
507
- _fsExtra.default.writeJSONSync(compTplPath, (0, _TemplateCompiler.uxToTemplateJson)(compTpl, compSid, compStyleSheet, compImportMap, _path.default.dirname(compPath)), param.mode === 'production' ? undefined : {
547
+ _fsExtra.default.writeJSONSync(compTplPath, (0, _TemplateCompiler.uxToTemplateJson)(compTpl, compSid, mergeStyleSheets(appStyleSheet, compStyleSheet), compImportMap, _path.default.dirname(compPath), compComponentsMap), param.mode === 'production' ? undefined : {
508
548
  spaces: 2
509
549
  });
510
550
  const compCssPath = _path.default.join(buildPath, `${compPath}.css.json`);
@@ -594,13 +634,16 @@ class ViteCompiler {
594
634
  });
595
635
  let templateNode = null;
596
636
  const importMap = {};
637
+ const componentsMap = {};
597
638
  for (const node of doc.childNodes) {
598
639
  if (node.nodeName === 'template') templateNode = node;else if (node.nodeName === 'import') {
599
640
  const nameAttr = node.attrs?.find(a => a.name === 'name');
600
641
  const srcAttr = node.attrs?.find(a => a.name === 'src');
601
642
  if (nameAttr && srcAttr) {
602
643
  const compPath = _path.default.resolve(_path.default.dirname(uxFile), srcAttr.value).replace(/\.ux$/, '');
603
- importMap[nameAttr.value.toLowerCase()] = _path.default.relative(srcPath, compPath).replace(/\\/g, '/');
644
+ const rel = _path.default.relative(srcPath, compPath).replace(/\\/g, '/');
645
+ importMap[nameAttr.value.toLowerCase()] = rel;
646
+ componentsMap[nameAttr.value] = rel;
604
647
  }
605
648
  }
606
649
  }
@@ -630,7 +673,7 @@ class ViteCompiler {
630
673
  // Generate template.json
631
674
  if (templateNode) {
632
675
  _fsExtra.default.ensureDirSync(_path.default.dirname(outputTpl));
633
- _fsExtra.default.writeJSONSync(outputTpl, (0, _TemplateCompiler.uxToTemplateJson)(templateNode, sid, styleSheet, Object.keys(importMap).length ? importMap : undefined, _path.default.dirname(relPath)), param.mode === 'production' ? undefined : {
676
+ _fsExtra.default.writeJSONSync(outputTpl, (0, _TemplateCompiler.uxToTemplateJson)(templateNode, sid, mergeStyleSheets(appStyleSheet, styleSheet), Object.keys(importMap).length ? importMap : undefined, _path.default.dirname(relPath), Object.keys(componentsMap).length ? componentsMap : undefined), param.mode === 'production' ? undefined : {
634
677
  spaces: 2
635
678
  });
636
679
  }
@@ -708,6 +751,29 @@ function wrapOutput(code, entryName, isApp) {
708
751
  });
709
752
  // Remove Object.defineProperty for Symbol.toStringTag
710
753
  code = code.replace(/\s*Object\.defineProperty\(\w+,\s*Symbol\.toStringTag[^;]*;\s*/g, '');
754
+ // Rewrite __require("@system.*") → $app_require$("@app-module/system.*") in rolldown output.
755
+ // Rolldown emits __require when CJS require() survives bundling (aliased require, dynamic
756
+ // concat, or patterns the pre-transform couldn't catch). Also catch _require() which appears
757
+ // when the original code does `var _require = require; _require('@system.xxx')`.
758
+ const sysRequirePattern = /\b_?_?require\(\s*"(@(?:system|service|android|hap)\.[^"]+)"\s*\)/g;
759
+ code = code.replace(sysRequirePattern, (_, mod) => {
760
+ const moduleName = mod.replace(/^@(system|service|android|hap)\./, '$1.');
761
+ return `$app_require$("@app-module/${moduleName}")`;
762
+ });
763
+ // Same for @app-module/ prefix
764
+ code = code.replace(/\b_?_?require\(\s*"(@app-module\/[^"]+)"\s*\)/g, (_, mod) => {
765
+ const moduleName = mod.slice('@app-module/'.length);
766
+ return `$app_require$("@app-module/${moduleName}")`;
767
+ });
768
+ // Also handle single-quoted variants
769
+ code = code.replace(/\b_?_?require\(\s*'(@(?:system|service|android|hap)\.[^']+)'\s*\)/g, (_, mod) => {
770
+ const moduleName = mod.replace(/^@(system|service|android|hap)\./, '$1.');
771
+ return `$app_require$("@app-module/${moduleName}")`;
772
+ });
773
+ // Remove the __require polyfill definition if it's no longer referenced anywhere
774
+ if (!/\b__require\b/.test(code)) {
775
+ code = code.replace(/var __require\s*=\s*\/\*[^*]*\*\/\s*\(\(x\)\s*=>[\s\S]*?}\);\n?/g, '');
776
+ }
711
777
  // Extract the default export variable
712
778
  let exportVar = '_default';
713
779
  const m1 = code.match(/export\s*\{\s*(\w+)\s+as\s+default\s*\}/);
@@ -738,7 +804,33 @@ $app_define$("${defineId}", [], function($app_require$, $app_exports$, $app_modu
738
804
  $app_bootstrap$("${bootstrapId}");
739
805
  `;
740
806
  }
807
+ function mergeStyleSheets(app, page) {
808
+ if (!app || !Object.keys(app).length) return page;
809
+ if (!page || !Object.keys(page).length) return app;
810
+ const merged = {
811
+ ...app
812
+ };
813
+ for (const [k, v] of Object.entries(page)) {
814
+ if (k === '@KEYFRAMES' || k === '@FONT-FACE') {
815
+ merged[k] = {
816
+ ...(merged[k] || {}),
817
+ ...v
818
+ };
819
+ } else if (k === '@MEDIA') {
820
+ merged[k] = [...(merged[k] || []), ...v];
821
+ } else if (typeof v === 'object' && v !== null && typeof merged[k] === 'object' && merged[k] !== null) {
822
+ merged[k] = {
823
+ ...merged[k],
824
+ ...v
825
+ };
826
+ } else {
827
+ merged[k] = v;
828
+ }
829
+ }
830
+ return merged;
831
+ }
741
832
  const __test = exports.__test = {
742
- stripDeadDefProp
833
+ stripDeadDefProp,
834
+ mergeStyleSheets
743
835
  };
744
836
  var _default = exports.default = ViteCompiler;
@@ -6,5 +6,8 @@ declare class Jsc {
6
6
  private logBeforeInvoke;
7
7
  private logAfterInvoke;
8
8
  private static listFiles;
9
+ private assertJscVersion;
10
+ static wrapAllJsWithIife(buildPath: string): void;
11
+ private static compareSemver;
9
12
  }
10
13
  export default Jsc;
@@ -9,6 +9,9 @@ var path = _interopRequireWildcard(require("path"));
9
9
  var _sharedUtils = require("@aiot-toolkit/shared-utils");
10
10
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
11
11
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
12
+ const REQUIRED_JSC_VERSION = '1.0.9';
13
+ const IIFE_WRAP_PREFIX = 'export default (function (__ctx) {\n' + ' let { requireModule, unRequireModule, $app_define$, $app_bootstrap$, $app_require$,\n' + ' console = global.console } = __ctx;\n' + ' let { setTimeout, clearTimeout, setInterval, clearInterval } = __ctx;\n\n';
14
+ const IIFE_WRAP_SUFFIX = '\n});\n';
12
15
  class Jsc {
13
16
  constructor(projectPath, buildPath) {
14
17
  this.projectPath = projectPath;
@@ -23,8 +26,10 @@ class Jsc {
23
26
  const beforeJsCount = Jsc.listFiles(buildPath, '.js').length;
24
27
  return _sharedUtils.CommonUtil.requireNodeModule(projectPath, `@aiot-toolkit/jsc`).then(async module => {
25
28
  this.logBeforeInvoke();
29
+ this.assertJscVersion();
30
+ Jsc.wrapAllJsWithIife(buildPath);
26
31
  const start = Date.now();
27
- const msg = await module.default(buildPath);
32
+ const msg = await module.default(buildPath, []);
28
33
  const elapsed = Date.now() - start;
29
34
  if (msg) {
30
35
  _sharedUtils.ColorConsole.success({
@@ -119,5 +124,42 @@ class Jsc {
119
124
  walk(dir);
120
125
  return out;
121
126
  }
127
+ assertJscVersion() {
128
+ const {
129
+ projectPath
130
+ } = this;
131
+ const jscName = '@aiot-toolkit/jsc';
132
+ try {
133
+ const pkgJsonPath = require.resolve(`${jscName}/package.json`, {
134
+ paths: [projectPath]
135
+ });
136
+ const pkg = require(pkgJsonPath);
137
+ const version = pkg.version || '0.0.0';
138
+ if (Jsc.compareSemver(version, REQUIRED_JSC_VERSION) < 0) {
139
+ _sharedUtils.ColorConsole.throw(`[jsc] ${jscName}@${version} is too old — need >= ${REQUIRED_JSC_VERSION}. ` + `Run: npm i ${jscName}@^${REQUIRED_JSC_VERSION}`);
140
+ throw new Error(`[jsc] ${jscName} must be >= ${REQUIRED_JSC_VERSION}, got ${version}`);
141
+ }
142
+ } catch (e) {
143
+ if (e?.message?.includes(`must be >= ${REQUIRED_JSC_VERSION}`)) throw e;
144
+ }
145
+ }
146
+ static wrapAllJsWithIife(buildPath) {
147
+ for (const {
148
+ rel
149
+ } of Jsc.listFiles(buildPath, '.js')) {
150
+ const abs = path.join(buildPath, rel);
151
+ const body = fs.readFileSync(abs, 'utf-8');
152
+ if (body.startsWith('export default (function (__ctx)')) continue;
153
+ fs.writeFileSync(abs, IIFE_WRAP_PREFIX + body + IIFE_WRAP_SUFFIX, 'utf-8');
154
+ }
155
+ }
156
+ static compareSemver(a, b) {
157
+ const parse = v => v.replace(/^[\^~=v]/, '').split(/[.-]/).slice(0, 3).map(p => parseInt(p, 10) || 0);
158
+ const [a1, a2, a3] = parse(a);
159
+ const [b1, b2, b3] = parse(b);
160
+ if (a1 !== b1) return a1 - b1;
161
+ if (a2 !== b2) return a2 - b2;
162
+ return a3 - b3;
163
+ }
122
164
  }
123
165
  var _default = exports.default = Jsc;
@@ -153,8 +153,17 @@ class ZipUtil {
153
153
  // basename from manifest.icon (e.g. `/resources/base/media/icon_small.png`
154
154
  // → `icon_small.vug` at rpk root) so runtime + IDE previews can look it up
155
155
  // by the manifest-declared name.
156
- if (config.icon) {
157
- const iconPath = _path.default.join(buildDir, config.icon.replace(/^\//, ''));
156
+ const runtimeIconPath = (() => {
157
+ const buildManifest = _path.default.join(buildDir, 'manifest.json');
158
+ if (_fsExtra.default.existsSync(buildManifest)) {
159
+ try {
160
+ return _fsExtra.default.readJSONSync(buildManifest).icon;
161
+ } catch {/* fall through */}
162
+ }
163
+ return config.icon;
164
+ })();
165
+ if (runtimeIconPath) {
166
+ const iconPath = _path.default.join(buildDir, runtimeIconPath.replace(/^\//, ''));
158
167
  if (_fsExtra.default.existsSync(iconPath)) {
159
168
  const iconBuf = _fsExtra.default.readFileSync(iconPath);
160
169
  outerPackage.addResource({
@@ -86,6 +86,9 @@ class UxConfig {
86
86
  }, {
87
87
  worker: _UxAfterCompile.default.copyResource,
88
88
  workerDescribe: 'Copy resource files'
89
+ }, {
90
+ worker: _UxAfterCompile.default.relocateManifestIcon,
91
+ workerDescribe: 'Move manifest.icon to build root + rewrite refs'
89
92
  }, {
90
93
  worker: _UxAfterCompile.default.compressResource,
91
94
  workerDescribe: 'Compress resource files'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiot-toolkit/aiotpack",
3
- "version": "2.1.0-prender.11",
3
+ "version": "2.1.0-prender.13",
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.11",
23
- "@aiot-toolkit/parser": "2.1.0-prender.11",
24
- "@aiot-toolkit/shared-utils": "2.1.0-prender.11",
22
+ "@aiot-toolkit/generator": "2.1.0-prender.13",
23
+ "@aiot-toolkit/parser": "2.1.0-prender.13",
24
+ "@aiot-toolkit/shared-utils": "2.1.0-prender.13",
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.11",
31
+ "file-lane": "2.1.0-prender.13",
32
32
  "file-loader": "^6.2.0",
33
33
  "fs-extra": "^11.2.0",
34
34
  "jsrsasign": "^11.1.0",