leanweb 3.0.6 → 3.0.8
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.
- package/commands/build.js +31 -27
- package/package.json +3 -3
- package/templates/lib/lw-element.js +32 -12
- package/templates/lib/lw-expr-parser.js +25 -4
package/commands/build.js
CHANGED
|
@@ -45,34 +45,38 @@ const buildModule = (projectPath) => {
|
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
const buildHTML = () => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
try {
|
|
49
|
+
project.components.forEach(cmp => {
|
|
50
|
+
const cmpName = utils.getComponentName(cmp);
|
|
51
|
+
const htmlFilename = `${utils.dirs.build}/components/${cmp}/${cmpName}.html`;
|
|
52
|
+
const htmlFileExists = fs.existsSync(htmlFilename);
|
|
53
|
+
if (htmlFileExists) {
|
|
54
|
+
const cssFilename = `${utils.dirs.build}/components/${cmp}/${cmpName}.css`;
|
|
55
|
+
const cssFileExists = fs.existsSync(cssFilename);
|
|
56
|
+
let cssString = `@import "global-styles.css";\n`;
|
|
57
|
+
if (cssFileExists) {
|
|
58
|
+
cssString += fs.readFileSync(cssFilename, 'utf8');
|
|
59
|
+
}
|
|
60
|
+
cssString += '\n[lw-false],[lw-for]{display:none !important;}\n';
|
|
61
|
+
const htmlString = fs.readFileSync(htmlFilename, 'utf8');
|
|
62
|
+
const minifiedHtml = minify(htmlString, {
|
|
63
|
+
caseSensitive: true,
|
|
64
|
+
collapseWhitespace: true,
|
|
65
|
+
minifyCSS: true,
|
|
66
|
+
minifyJS: true,
|
|
67
|
+
removeComments: true,
|
|
68
|
+
});
|
|
69
|
+
const ast = parser.parse(minifiedHtml);
|
|
70
|
+
ast.css = cssString;
|
|
71
|
+
ast.componentFullName = project.name + '-' + cmp.replace(/\//g, '-');
|
|
72
|
+
ast.runtimeVersion = project.version;
|
|
73
|
+
ast.builderVersion = leanwebPackageJSON.version;
|
|
74
|
+
utils.writeIfChanged(`${utils.dirs.build}/components/${cmp}/ast.js`, `export default ${JSON.stringify(ast, null, 0)};`);
|
|
58
75
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
collapseWhitespace: true,
|
|
64
|
-
minifyCSS: true,
|
|
65
|
-
minifyJS: true,
|
|
66
|
-
removeComments: true,
|
|
67
|
-
});
|
|
68
|
-
const ast = parser.parse(minifiedHtml);
|
|
69
|
-
ast.css = cssString;
|
|
70
|
-
ast.componentFullName = project.name + '-' + cmp.replace(/\//g, '-');
|
|
71
|
-
ast.runtimeVersion = project.version;
|
|
72
|
-
ast.builderVersion = leanwebPackageJSON.version;
|
|
73
|
-
utils.writeIfChanged(`${utils.dirs.build}/components/${cmp}/ast.js`, `export default ${JSON.stringify(ast, null, 0)};`);
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
+
});
|
|
77
|
+
} catch (e) {
|
|
78
|
+
console.error('Error in buildHTML:', e);
|
|
79
|
+
}
|
|
76
80
|
};
|
|
77
81
|
|
|
78
82
|
copySrc();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leanweb",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.8",
|
|
4
4
|
"description": "Builds framework agnostic web components.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"leanweb": "leanweb.js",
|
|
@@ -20,12 +20,12 @@
|
|
|
20
20
|
"author": "Qian Chen",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@babel/parser": "^7.28.
|
|
23
|
+
"@babel/parser": "^7.28.4",
|
|
24
24
|
"esbuild": "^0.25.9",
|
|
25
25
|
"fs-extra": "^11.3.1",
|
|
26
26
|
"globby": "^14.1.0",
|
|
27
27
|
"html-minifier": "^4.0.0",
|
|
28
|
-
"isomorphic-git": "^1.33.
|
|
28
|
+
"isomorphic-git": "^1.33.1",
|
|
29
29
|
"live-server": "^1.2.2",
|
|
30
30
|
"node-watch": "^0.7.4",
|
|
31
31
|
"parse5": "^8.0.0",
|
|
@@ -111,10 +111,14 @@ export default class LWElement extends HTMLElement {
|
|
|
111
111
|
|
|
112
112
|
this._bindMethods();
|
|
113
113
|
setTimeout(() => {
|
|
114
|
-
this.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
const result = this.domReady?.call(this);
|
|
115
|
+
if (result && typeof result.then === 'function') {
|
|
116
|
+
// domReady is async
|
|
117
|
+
result.then(() => this.update());
|
|
118
|
+
} else {
|
|
119
|
+
// domReady is sync
|
|
120
|
+
this.update();
|
|
121
|
+
}
|
|
118
122
|
});
|
|
119
123
|
|
|
120
124
|
if (this.urlHashChanged && typeof this.urlHashChanged === 'function') {
|
|
@@ -286,7 +290,9 @@ export default class LWElement extends HTMLElement {
|
|
|
286
290
|
} else if (modelNode.type === 'checkbox') {
|
|
287
291
|
if (Array.isArray(object[propertyExpr])) {
|
|
288
292
|
if (modelNode.checked) {
|
|
289
|
-
object[propertyExpr].
|
|
293
|
+
if (!object[propertyExpr].includes(modelNode.value)) {
|
|
294
|
+
object[propertyExpr].push(modelNode.value);
|
|
295
|
+
}
|
|
290
296
|
} else {
|
|
291
297
|
const index = object[propertyExpr].indexOf(modelNode.value);
|
|
292
298
|
if (index > -1) {
|
|
@@ -335,9 +341,14 @@ export default class LWElement extends HTMLElement {
|
|
|
335
341
|
} else if (modelNode.type === 'radio') {
|
|
336
342
|
modelNode.checked = parsed[0] === modelNode.value;
|
|
337
343
|
} else if (modelNode.type === 'select-multiple') {
|
|
344
|
+
// First, clear all selections
|
|
338
345
|
for (let i = 0; i < modelNode.options.length; ++i) {
|
|
339
|
-
|
|
340
|
-
|
|
346
|
+
modelNode.options[i].selected = false;
|
|
347
|
+
}
|
|
348
|
+
// Then, set selected options
|
|
349
|
+
if (parsed[0]) {
|
|
350
|
+
for (let i = 0; i < modelNode.options.length; ++i) {
|
|
351
|
+
const option = modelNode.options[i];
|
|
341
352
|
option.selected = parsed[0].includes(option.value);
|
|
342
353
|
}
|
|
343
354
|
}
|
|
@@ -419,11 +430,20 @@ export default class LWElement extends HTMLElement {
|
|
|
419
430
|
const parsed = parser.evaluate(interpolation.ast, context, interpolation.loc);
|
|
420
431
|
|
|
421
432
|
if (interpolation.lwValue === 'class') {
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
433
|
+
const dynamicClass = parsed[0];
|
|
434
|
+
const initClass = bindNode.getAttribute('lw-init-class') || '';
|
|
435
|
+
// Ensure initial classes are present
|
|
436
|
+
if (initClass) {
|
|
437
|
+
initClass.split(' ').forEach(cls => {
|
|
438
|
+
if (cls) bindNode.classList.add(cls);
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
// Add or remove the dynamic class
|
|
442
|
+
if (dynamicClass) {
|
|
443
|
+
bindNode.classList.add(dynamicClass);
|
|
444
|
+
} else if (dynamicClass !== undefined) {
|
|
445
|
+
// Only remove if not undefined (so we don't remove all classes accidentally)
|
|
446
|
+
bindNode.classList.remove(dynamicClass);
|
|
427
447
|
}
|
|
428
448
|
} else {
|
|
429
449
|
if (parsed[0] !== false && parsed[0] !== undefined && parsed[0] !== null) {
|
|
@@ -96,14 +96,35 @@ const nodeHandlers = {
|
|
|
96
96
|
'ExpressionStatement': (node, context) => evalNode(node.expression, context),
|
|
97
97
|
'BinaryExpression': (node, context) => binaryOperations[node.operator](evalNode(node.left, context), evalNode(node.right, context)),
|
|
98
98
|
'AssignmentExpression': (node, context) => {
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
// Support complex left-hand sides (e.g., obj.prop = 1, obj[expr] = 1)
|
|
100
|
+
let obj, prop;
|
|
101
|
+
if (node.left.type === 'MemberExpression' || node.left.type === 'OptionalMemberExpression') {
|
|
102
|
+
obj = evalNode(node.left.object, context);
|
|
103
|
+
prop = node.left.computed ? evalNode(node.left.property, context) : node.left.property.name;
|
|
104
|
+
} else if (node.left.type === 'Identifier') {
|
|
105
|
+
// Simple variable assignment
|
|
106
|
+
obj = immediateContext(node.left, context);
|
|
107
|
+
prop = node.left.name;
|
|
108
|
+
} else {
|
|
109
|
+
throw new Error('Unsupported assignment left-hand side');
|
|
110
|
+
}
|
|
111
|
+
assignmentOperations[node.operator](obj, prop, evalNode(node.right, context));
|
|
101
112
|
},
|
|
102
113
|
'LogicalExpression': (node, context) => logicalOperators[node.operator](evalNode(node.left, context), evalNode(node.right, context)),
|
|
103
114
|
'UnaryExpression': (node, context) => unaryOperators[node.operator](evalNode(node.argument, context)),
|
|
104
115
|
'UpdateExpression': (node, context) => {
|
|
105
|
-
|
|
106
|
-
|
|
116
|
+
// Support complex left-hand sides (e.g., ++obj.prop, ++obj[expr])
|
|
117
|
+
let obj, prop;
|
|
118
|
+
if (node.argument.type === 'MemberExpression' || node.argument.type === 'OptionalMemberExpression') {
|
|
119
|
+
obj = evalNode(node.argument.object, context);
|
|
120
|
+
prop = node.argument.computed ? evalNode(node.argument.property, context) : node.argument.property.name;
|
|
121
|
+
} else if (node.argument.type === 'Identifier') {
|
|
122
|
+
obj = immediateContext(node.argument, context);
|
|
123
|
+
prop = node.argument.name;
|
|
124
|
+
} else {
|
|
125
|
+
throw new Error('Unsupported update left-hand side');
|
|
126
|
+
}
|
|
127
|
+
return updateOperators(node.operator, node.prefix)(obj, prop);
|
|
107
128
|
},
|
|
108
129
|
'ConditionalExpression': (node, context) => {
|
|
109
130
|
const test = evalNode(node.test, context);
|