@aiot-toolkit/aiotpack 2.1.0-prender.5 → 2.1.0-prender.6
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.
|
@@ -44,11 +44,16 @@ class UxAfterCompile {
|
|
|
44
44
|
level: _sharedUtils.Loglevel.SUCCESS,
|
|
45
45
|
message: ['javascript compile success']
|
|
46
46
|
}]);
|
|
47
|
-
}).catch(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
}).catch(err => {
|
|
48
|
+
const errors = err?.errors;
|
|
49
|
+
const warnings = err?.warnings;
|
|
50
|
+
if (!errors?.length && !warnings?.length) {
|
|
51
|
+
onLog?.([{
|
|
52
|
+
level: _sharedUtils.Loglevel.THROW,
|
|
53
|
+
message: [`javascript compile failed: ${err?.message ?? err}`]
|
|
54
|
+
}]);
|
|
55
|
+
throw err instanceof Error ? err : new Error(String(err));
|
|
56
|
+
}
|
|
52
57
|
const errorLength = errors?.length || 0;
|
|
53
58
|
const messages = [`webpack error:\r\n`];
|
|
54
59
|
if (errors?.length) {
|
|
@@ -12,16 +12,6 @@ declare function uxToTemplateJson(templateNode: any, styleObjectId?: number, sty
|
|
|
12
12
|
* `screen and ` is preserved; `not` / `only` are preserved as-is.
|
|
13
13
|
*/
|
|
14
14
|
declare function normalizeMediaQuery(condition: string): string;
|
|
15
|
-
/**
|
|
16
|
-
* Parse compiled $app_style$ array. Each rule is either:
|
|
17
|
-
* [selectors, props] — base rule
|
|
18
|
-
* [{condition: "<media-query>"}, selectors, props] — conditional rule (@media or @import with query)
|
|
19
|
-
*
|
|
20
|
-
* Returns a flat map: selectors → props for base rules, plus
|
|
21
|
-
* `"@media <normalizedConditionText>"` keys whose values are the per-condition
|
|
22
|
-
* `{selector: props}` map. The condition text is normalized to Level 3 so
|
|
23
|
-
* runtime only needs a Level-3 matcher.
|
|
24
|
-
*/
|
|
25
15
|
declare function parseStyleArray(code: string): Record<string, any>;
|
|
26
16
|
/** Convert CSS text to css.json format */
|
|
27
17
|
export { uxToTemplateJson, parseStyleArray, normalizeMediaQuery };
|
|
@@ -100,10 +100,74 @@ function normalizeMediaQuery(condition) {
|
|
|
100
100
|
* `{selector: props}` map. The condition text is normalized to Level 3 so
|
|
101
101
|
* runtime only needs a Level-3 matcher.
|
|
102
102
|
*/
|
|
103
|
+
const NAMED_COLORS = new Set(['transparent', 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 'beige', 'bisque', 'black', 'blanchedalmond', 'blue', 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkgrey', 'darkkhaki', 'darkmagenta', 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray', 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink', 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick', 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'gray', 'green', 'greenyellow', 'grey', 'honeydew', 'hotpink', 'indianred', 'indigo', 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan', 'lightgoldenrodyellow', 'lightgray', 'lightgreen', 'lightgrey', 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue', 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow', 'lime', 'limegreen', 'linen', 'magenta', 'maroon', 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream', 'mistyrose', 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive', 'olivedrab', 'orange', 'orangered', 'orchid', 'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'purple', 'rebeccapurple', 'red', 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue', 'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue', 'tan', 'teal', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'white', 'whitesmoke', 'yellow', 'yellowgreen']);
|
|
104
|
+
const COLOR_PROP_RE = /(?:^|[a-z])[Cc]olor$/;
|
|
105
|
+
const NON_NAMED_COLOR_VALUE_RE = /^(?:#[0-9a-fA-F]{3,8}|rgba?\(|hsla?\(|currentColor)/;
|
|
103
106
|
function parseStyleArray(code) {
|
|
104
107
|
const styleSheet = {};
|
|
108
|
+
const expandShortHex = value => {
|
|
109
|
+
const short = /^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])?$/.exec(value);
|
|
110
|
+
if (!short) return value;
|
|
111
|
+
const r = short[1] + short[1];
|
|
112
|
+
const g = short[2] + short[2];
|
|
113
|
+
const b = short[3] + short[3];
|
|
114
|
+
const a = short[4] ? short[4] + short[4] : '';
|
|
115
|
+
return ('#' + r + g + b + a).toLowerCase();
|
|
116
|
+
};
|
|
117
|
+
const normalizeTransform = obj => {
|
|
118
|
+
if (!obj || typeof obj !== 'object') return typeof obj === 'string' ? obj : JSON.stringify(obj);
|
|
119
|
+
const out = {};
|
|
120
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
121
|
+
out[k] = typeof v === 'number' && /^translate[XYZ]?$/.test(k) ? `${v}px` : v;
|
|
122
|
+
}
|
|
123
|
+
return JSON.stringify(out);
|
|
124
|
+
};
|
|
125
|
+
const expandKeyframeSteps = value => {
|
|
126
|
+
let arr = [];
|
|
127
|
+
if (typeof value === 'string') {
|
|
128
|
+
try {
|
|
129
|
+
arr = JSON.parse(value);
|
|
130
|
+
} catch {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
} else if (Array.isArray(value)) {
|
|
134
|
+
arr = value;
|
|
135
|
+
} else {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
return arr.map(step => {
|
|
139
|
+
const out = {};
|
|
140
|
+
const entries = Object.entries(step ?? {});
|
|
141
|
+
for (const [k, v] of entries) {
|
|
142
|
+
if (k === 'time') continue;
|
|
143
|
+
out[k] = k === 'transform' && v && typeof v === 'object' ? normalizeTransform(v) : v;
|
|
144
|
+
}
|
|
145
|
+
if ('time' in (step ?? {})) out.time = step.time;
|
|
146
|
+
return out;
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
const normalizeStyleProps = props => {
|
|
150
|
+
if (!props || typeof props !== 'object') return props;
|
|
151
|
+
const out = {};
|
|
152
|
+
for (const [k, v] of Object.entries(props)) {
|
|
153
|
+
if ((k === 'animationIterationCount' || k === 'iterationCount') && v === 'infinite') {
|
|
154
|
+
out[k] = -1;
|
|
155
|
+
} else if (typeof v === 'string' && COLOR_PROP_RE.test(k)) {
|
|
156
|
+
if (NAMED_COLORS.has(v.toLowerCase())) {
|
|
157
|
+
out[k] = v;
|
|
158
|
+
} else if (NON_NAMED_COLOR_VALUE_RE.test(v)) {
|
|
159
|
+
out[k] = expandShortHex(v);
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
out[k] = v;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
};
|
|
105
167
|
const ingest = parsed => {
|
|
106
168
|
if (!Array.isArray(parsed)) return;
|
|
169
|
+
let currentMediaCondition = null;
|
|
170
|
+
let currentMediaEntry = null;
|
|
107
171
|
for (const rule of parsed) {
|
|
108
172
|
if (!Array.isArray(rule) || rule.length < 2) continue;
|
|
109
173
|
let selectors, props, conditionText;
|
|
@@ -115,16 +179,47 @@ function parseStyleArray(code) {
|
|
|
115
179
|
selectors = rule[0];
|
|
116
180
|
props = rule[1];
|
|
117
181
|
}
|
|
118
|
-
if (!Array.isArray(selectors)) continue;
|
|
119
|
-
let target
|
|
182
|
+
if (!Array.isArray(selectors) || selectors.length === 0) continue;
|
|
183
|
+
let target;
|
|
120
184
|
if (conditionText) {
|
|
121
|
-
const
|
|
122
|
-
|
|
185
|
+
const normalized = normalizeMediaQuery(conditionText);
|
|
186
|
+
if (currentMediaCondition !== normalized) {
|
|
187
|
+
const list = styleSheet['@MEDIA'] = styleSheet['@MEDIA'] || [];
|
|
188
|
+
currentMediaEntry = {
|
|
189
|
+
condition: normalized
|
|
190
|
+
};
|
|
191
|
+
list.push(currentMediaEntry);
|
|
192
|
+
currentMediaCondition = normalized;
|
|
193
|
+
}
|
|
194
|
+
target = currentMediaEntry;
|
|
195
|
+
} else {
|
|
196
|
+
target = styleSheet;
|
|
197
|
+
currentMediaCondition = null;
|
|
198
|
+
currentMediaEntry = null;
|
|
123
199
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
200
|
+
const normalizedProps = normalizeStyleProps(props);
|
|
201
|
+
const firstSel = selectors[0];
|
|
202
|
+
if (Array.isArray(firstSel) && firstSel.length >= 2 && firstSel[0] === 3) {
|
|
203
|
+
const bucket = target['@KEYFRAMES'] = target['@KEYFRAMES'] || {};
|
|
204
|
+
bucket[firstSel[1]] = expandKeyframeSteps(props?.keyframes ?? '[]');
|
|
205
|
+
} else if (Array.isArray(firstSel) && firstSel.length >= 2 && firstSel[0] === 4) {
|
|
206
|
+
const bucket = target['@FONT-FACE'] = target['@FONT-FACE'] || {};
|
|
207
|
+
bucket[firstSel[1]] = props?.fontface ?? normalizedProps;
|
|
208
|
+
} else {
|
|
209
|
+
const pieces = [];
|
|
210
|
+
for (let i = 0; i < selectors.length; i++) {
|
|
211
|
+
const sel = selectors[i];
|
|
212
|
+
if (!Array.isArray(sel) || sel.length < 2) continue;
|
|
213
|
+
if (sel[0] === 5) {
|
|
214
|
+
pieces.push(String(sel[1]));
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (pieces.length && pieces[pieces.length - 1] !== '>' && pieces[pieces.length - 1] !== '~' && pieces[pieces.length - 1] !== '+') {
|
|
218
|
+
pieces.push(' ');
|
|
219
|
+
}
|
|
220
|
+
if (sel[0] === 0) pieces.push(`.${sel[1]}`);else if (sel[0] === 1) pieces.push(`#${sel[1]}`);else pieces.push(String(sel[1]));
|
|
127
221
|
}
|
|
222
|
+
if (pieces.length) target[pieces.join('')] = normalizedProps;
|
|
128
223
|
}
|
|
129
224
|
}
|
|
130
225
|
};
|
|
@@ -147,6 +147,11 @@ class ViteCompiler {
|
|
|
147
147
|
}
|
|
148
148
|
async compile(param) {
|
|
149
149
|
await this.clean(param);
|
|
150
|
+
const nodeMajor = parseInt((process.versions.node ?? '0').split('.')[0], 10);
|
|
151
|
+
const nodeMinor = parseInt((process.versions.node ?? '0').split('.')[1] ?? '0', 10);
|
|
152
|
+
if (nodeMajor < 20 || nodeMajor === 20 && nodeMinor < 19) {
|
|
153
|
+
throw new Error(`vite ^8 requires Node ^20.19.0 || >=22.12.0; current Node is v${process.versions.node}. ` + `Upgrade Node (recommend 22 LTS) and re-run the build.`);
|
|
154
|
+
}
|
|
150
155
|
const {
|
|
151
156
|
projectPath,
|
|
152
157
|
sourceRoot,
|
|
@@ -167,10 +172,13 @@ class ViteCompiler {
|
|
|
167
172
|
message: [`Failed to load quickapp.config.js: ${e.message}`]
|
|
168
173
|
}]);
|
|
169
174
|
}
|
|
175
|
+
const entryFailures = [];
|
|
176
|
+
let entryAttempted = 0;
|
|
170
177
|
for (const [entryName, entryValue] of Object.entries(entries)) {
|
|
171
178
|
const entryPath = entryValue.split('?')[0];
|
|
172
179
|
const resolvedEntry = _path.default.resolve(originalProjectPath, entryPath);
|
|
173
180
|
if (!_fsExtra.default.existsSync(resolvedEntry)) continue;
|
|
181
|
+
entryAttempted++;
|
|
174
182
|
const outputFile = _path.default.join(buildPath, `${entryName}.js`);
|
|
175
183
|
_fsExtra.default.ensureDirSync(_path.default.dirname(outputFile));
|
|
176
184
|
const allEntryPaths = Object.values(entries).map(v => _path.default.resolve(originalProjectPath, v.split('?')[0]));
|
|
@@ -205,10 +213,17 @@ class ViteCompiler {
|
|
|
205
213
|
commonjsOptions: {
|
|
206
214
|
transformMixedEsModules: true
|
|
207
215
|
},
|
|
208
|
-
minify: param.mode === 'production' ? 'terser' : false,
|
|
216
|
+
minify: param.mode === 'production' ? userVite.build?.minify ?? 'terser' : false,
|
|
209
217
|
terserOptions: {
|
|
210
218
|
format: {
|
|
211
|
-
comments: false
|
|
219
|
+
comments: false,
|
|
220
|
+
...(userVite.build?.terserOptions?.format ?? {})
|
|
221
|
+
},
|
|
222
|
+
compress: {
|
|
223
|
+
...(userVite.build?.terserOptions?.compress ?? {})
|
|
224
|
+
},
|
|
225
|
+
mangle: {
|
|
226
|
+
...(userVite.build?.terserOptions?.mangle ?? {})
|
|
212
227
|
}
|
|
213
228
|
}
|
|
214
229
|
},
|
|
@@ -244,9 +259,11 @@ class ViteCompiler {
|
|
|
244
259
|
async load(id) {
|
|
245
260
|
if (!id.endsWith('.ux')) return null;
|
|
246
261
|
const content = _fsExtra.default.readFileSync(id, 'utf-8');
|
|
247
|
-
const
|
|
262
|
+
const idPosix = id.replace(/\\/g, '/');
|
|
263
|
+
const resolvedEntryPosix = resolvedEntry.replace(/\\/g, '/');
|
|
264
|
+
const isApp = idPosix.endsWith('/app.ux') && _path.default.basename(_path.default.dirname(id)) === 'src';
|
|
248
265
|
// Generate template.json and css.json
|
|
249
|
-
if (
|
|
266
|
+
if (idPosix === resolvedEntryPosix) {
|
|
250
267
|
const parse5 = require("aiot-parse5");
|
|
251
268
|
const doc = parse5.parseFragment(content, {
|
|
252
269
|
scriptingEnabled: false
|
|
@@ -407,9 +424,19 @@ class ViteCompiler {
|
|
|
407
424
|
}
|
|
408
425
|
}
|
|
409
426
|
} catch (err) {
|
|
410
|
-
|
|
427
|
+
const msg = err.message;
|
|
428
|
+
console.warn(`vite: failed to build ${entryName}:`, msg);
|
|
429
|
+
entryFailures.push({
|
|
430
|
+
entry: entryName,
|
|
431
|
+
error: msg
|
|
432
|
+
});
|
|
411
433
|
}
|
|
412
434
|
}
|
|
435
|
+
if (entryAttempted > 0 && entryFailures.length === entryAttempted) {
|
|
436
|
+
const sample = entryFailures.slice(0, 3).map(f => ` ${f.entry}: ${f.error}`).join('\n');
|
|
437
|
+
const more = entryFailures.length > 3 ? `\n ...and ${entryFailures.length - 3} more` : '';
|
|
438
|
+
throw new Error(`vite build failed for all ${entryAttempted} entry page(s); no JS was emitted.\n` + `First failures:\n${sample}${more}`);
|
|
439
|
+
}
|
|
413
440
|
// Second pass: compile ALL .ux files that weren't entry pages
|
|
414
441
|
// Each .ux file gets its own template.json + css.json + js
|
|
415
442
|
const allUxFiles = [];
|
|
@@ -425,7 +452,7 @@ class ViteCompiler {
|
|
|
425
452
|
const compiledEntries = new Set(Object.values(entries).map(v => _path.default.resolve(originalProjectPath, v.split('?')[0])));
|
|
426
453
|
for (const uxFile of allUxFiles) {
|
|
427
454
|
if (compiledEntries.has(uxFile)) continue; // already compiled as entry
|
|
428
|
-
if (uxFile.endsWith('/app.ux')) continue; // app.ux handled separately
|
|
455
|
+
if (uxFile.replace(/\\/g, '/').endsWith('/app.ux')) continue; // app.ux handled separately
|
|
429
456
|
const relPath = _path.default.relative(srcPath, uxFile).replace(/\.ux$/, '');
|
|
430
457
|
const outputJs = _path.default.join(buildPath, `${relPath}.js`);
|
|
431
458
|
const outputTpl = _path.default.join(buildPath, `${relPath}.template.json`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiot-toolkit/aiotpack",
|
|
3
|
-
"version": "2.1.0-prender.
|
|
3
|
+
"version": "2.1.0-prender.6",
|
|
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.
|
|
23
|
-
"@aiot-toolkit/parser": "2.1.0-prender.
|
|
24
|
-
"@aiot-toolkit/shared-utils": "2.1.0-prender.
|
|
22
|
+
"@aiot-toolkit/generator": "2.1.0-prender.6",
|
|
23
|
+
"@aiot-toolkit/parser": "2.1.0-prender.6",
|
|
24
|
+
"@aiot-toolkit/shared-utils": "2.1.0-prender.6",
|
|
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.
|
|
31
|
+
"file-lane": "2.1.0-prender.6",
|
|
32
32
|
"file-loader": "^6.2.0",
|
|
33
33
|
"fs-extra": "^11.2.0",
|
|
34
34
|
"jsrsasign": "^11.1.0",
|