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

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.
@@ -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,
@@ -469,6 +544,7 @@ function emitTextValueAttr(rawText) {
469
544
  };
470
545
  }
471
546
  function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
547
+ let ancestors = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : [];
472
548
  const tagName = el.tagName === 'img' ? 'image' : el.tagName;
473
549
  const node = {
474
550
  type: tagName
@@ -493,9 +569,7 @@ function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
493
569
  name = name.slice(1);
494
570
  if (!value.includes('{{')) value = `{{${value}}}`;
495
571
  }
496
- if (name === 'is' && tagName === 'component') {
497
- continue; // is attribute handled at runtime
498
- } else if (name === 'class') {
572
+ if (name === 'class') {
499
573
  className = value.replace(/\s+/g, ' ').trim();
500
574
  } else if (name.startsWith('@') || name.startsWith('on') && name.length > 2) {
501
575
  const rawEvtName = name.startsWith('@') ? name.slice(1) : name.replace(/^on/, '');
@@ -764,15 +838,15 @@ function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
764
838
  // @media rules are applied at runtime by SDK, not inlined here.
765
839
  // Class rules apply in stylesheet declaration order (later declarations override earlier),
766
840
  // 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
- }
841
+ const staticClassTokens = [];
842
+ if (className) {
843
+ const parts = className.split(/(\{\{[\s\S]*?\}\})/).filter(Boolean);
844
+ for (const p of parts) {
845
+ if (/^\{\{[\s\S]*?\}\}$/.test(p)) continue;
846
+ for (const tok of p.trim().split(/\s+/)) if (tok) staticClassTokens.push(tok);
775
847
  }
848
+ }
849
+ if (styleSheet) {
776
850
  const hasMedia = hasApplicableMediaRule(styleSheet, el.tagName, staticClassTokens);
777
851
  // Skip class-rule merge when the node has any dynamic binding OR any @media
778
852
  // rule that applies to it — runtime must resolve class chain against the
@@ -794,11 +868,19 @@ function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
794
868
  if (Object.keys(inlined).length) node.style = inlined;
795
869
  } else {
796
870
  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))) {
871
+ const classSet = new Set(staticClassTokens);
872
+ for (const key of Object.keys(styleSheet)) {
873
+ if (key.startsWith('@')) continue;
874
+ if (key === el.tagName) {
875
+ Object.assign(merged, styleSheet[key]);
876
+ continue;
877
+ }
878
+ if (key.length > 1 && key.startsWith('.') && !/[\s>+~.]/.test(key.slice(1))) {
879
+ if (classSet.has(key.slice(1))) Object.assign(merged, styleSheet[key]);
880
+ continue;
881
+ }
882
+ if (/[\s>+~]/.test(key) || /\.[\w-]+\./.test(key)) {
883
+ if (selectorMatchesElement(key, el.tagName, classSet, ancestors)) {
802
884
  Object.assign(merged, styleSheet[key]);
803
885
  }
804
886
  }
@@ -823,7 +905,10 @@ function elementToJson(el, styleSheet, importMap, scopeVars, pageDir) {
823
905
  const isMixedContent = hasElementChildren && hasTextChildren && (tagName === 'text' || tagName === 'span' || tagName === 'a' || tagName === 'marquee');
824
906
  for (const child of el.childNodes || []) {
825
907
  if (child.tagName) {
826
- childNodes.push(elementToJson(child, styleSheet, importMap, scopeVars, pageDir));
908
+ childNodes.push(elementToJson(child, styleSheet, importMap, scopeVars, pageDir, [...ancestors, {
909
+ tag: el.tagName,
910
+ classes: new Set(staticClassTokens)
911
+ }]));
827
912
  } else if (isMixedContent && child.value?.trim()) {
828
913
  const emitted = emitTextValueAttr(child.value);
829
914
  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;
@@ -246,6 +246,7 @@ class ViteCompiler {
246
246
  }
247
247
  const entryFailures = [];
248
248
  let entryAttempted = 0;
249
+ let appStyleSheet = {};
249
250
  for (const [entryName, entryValue] of Object.entries(entries)) {
250
251
  const entryPath = entryValue.split('?')[0];
251
252
  const resolvedEntry = _path.default.resolve(originalProjectPath, entryPath);
@@ -427,6 +428,9 @@ class ViteCompiler {
427
428
  if (styleLiteral) {
428
429
  styleSheet = (0, _TemplateCompiler.parseStyleArray)(styleLiteral);
429
430
  }
431
+ if (isApp) {
432
+ appStyleSheet = styleSheet;
433
+ }
430
434
  // Write css.json
431
435
  const cssPath = _path.default.join(buildPath, `${isApp ? 'app' : pageName}.css.json`);
432
436
  _fsExtra.default.ensureDirSync(_path.default.dirname(cssPath));
@@ -439,7 +443,8 @@ class ViteCompiler {
439
443
  if (templateNode && !isApp) {
440
444
  const tplPath = _path.default.join(buildPath, `${pageName}.template.json`);
441
445
  _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 : {
446
+ const mergedSheet = mergeStyleSheets(appStyleSheet, styleSheet);
447
+ _fsExtra.default.writeJSONSync(tplPath, (0, _TemplateCompiler.uxToTemplateJson)(templateNode, sid, mergedSheet, importMap, _path.default.dirname(pageName)), param.mode === 'production' ? undefined : {
443
448
  spaces: 2
444
449
  });
445
450
  // Worklist BFS over nested <import> chain so transitively imported
@@ -504,7 +509,7 @@ class ViteCompiler {
504
509
  compStyleSheet = (0, _TemplateCompiler.parseStyleArray)(csm);
505
510
  }
506
511
  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 : {
512
+ _fsExtra.default.writeJSONSync(compTplPath, (0, _TemplateCompiler.uxToTemplateJson)(compTpl, compSid, mergeStyleSheets(appStyleSheet, compStyleSheet), compImportMap, _path.default.dirname(compPath)), param.mode === 'production' ? undefined : {
508
513
  spaces: 2
509
514
  });
510
515
  const compCssPath = _path.default.join(buildPath, `${compPath}.css.json`);
@@ -630,7 +635,7 @@ class ViteCompiler {
630
635
  // Generate template.json
631
636
  if (templateNode) {
632
637
  _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 : {
638
+ _fsExtra.default.writeJSONSync(outputTpl, (0, _TemplateCompiler.uxToTemplateJson)(templateNode, sid, mergeStyleSheets(appStyleSheet, styleSheet), Object.keys(importMap).length ? importMap : undefined, _path.default.dirname(relPath)), param.mode === 'production' ? undefined : {
634
639
  spaces: 2
635
640
  });
636
641
  }
@@ -738,7 +743,33 @@ $app_define$("${defineId}", [], function($app_require$, $app_exports$, $app_modu
738
743
  $app_bootstrap$("${bootstrapId}");
739
744
  `;
740
745
  }
746
+ function mergeStyleSheets(app, page) {
747
+ if (!app || !Object.keys(app).length) return page;
748
+ if (!page || !Object.keys(page).length) return app;
749
+ const merged = {
750
+ ...app
751
+ };
752
+ for (const [k, v] of Object.entries(page)) {
753
+ if (k === '@KEYFRAMES' || k === '@FONT-FACE') {
754
+ merged[k] = {
755
+ ...(merged[k] || {}),
756
+ ...v
757
+ };
758
+ } else if (k === '@MEDIA') {
759
+ merged[k] = [...(merged[k] || []), ...v];
760
+ } else if (typeof v === 'object' && v !== null && typeof merged[k] === 'object' && merged[k] !== null) {
761
+ merged[k] = {
762
+ ...merged[k],
763
+ ...v
764
+ };
765
+ } else {
766
+ merged[k] = v;
767
+ }
768
+ }
769
+ return merged;
770
+ }
741
771
  const __test = exports.__test = {
742
- stripDeadDefProp
772
+ stripDeadDefProp,
773
+ mergeStyleSheets
743
774
  };
744
775
  var _default = exports.default = ViteCompiler;
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.12",
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.12",
23
+ "@aiot-toolkit/parser": "2.1.0-prender.12",
24
+ "@aiot-toolkit/shared-utils": "2.1.0-prender.12",
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.12",
32
32
  "file-loader": "^6.2.0",
33
33
  "fs-extra": "^11.2.0",
34
34
  "jsrsasign": "^11.1.0",