@sprlab/wccompiler 0.16.3 → 0.16.5
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/lib/codegen.js +50 -7
- package/package.json +1 -1
package/lib/codegen.js
CHANGED
|
@@ -58,19 +58,43 @@ function slotPropRef(source, signalNames, computedNames, propNames) {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
|
-
* Wrap an expression in parentheses if it contains
|
|
62
|
-
*
|
|
61
|
+
* Wrap an expression in parentheses if it contains operators that could have
|
|
62
|
+
* precedence issues when combined with ?? (nullish coalescing).
|
|
63
|
+
*
|
|
64
|
+
* This prevents bugs like: this._count() || 'No items' ?? ''
|
|
65
|
+
* which JavaScript interprets as: this._count() || ('No items' ?? '')
|
|
66
|
+
*
|
|
67
|
+
* Operators that need wrapping:
|
|
68
|
+
* - Ternary: ? :
|
|
69
|
+
* - Logical OR: ||
|
|
70
|
+
* - Logical AND: &&
|
|
71
|
+
* - Nullish coalescing: ?? (nested)
|
|
63
72
|
*
|
|
64
73
|
* @param {string} expr - Expression to potentially wrap
|
|
65
|
-
* @returns {string} - Wrapped expression if it contains
|
|
74
|
+
* @returns {string} - Wrapped expression if it contains risky operators, otherwise unchanged
|
|
66
75
|
*/
|
|
67
76
|
function wrapTernaryExpr(expr) {
|
|
68
77
|
const trimmed = expr.trim();
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
|
|
78
|
+
|
|
79
|
+
// Check for operators that have lower precedence than ?? or can cause ambiguity
|
|
80
|
+
// Ternary operator (? :)
|
|
81
|
+
const hasTernary = trimmed.includes('?') && trimmed.includes(':');
|
|
82
|
+
|
|
83
|
+
// Logical OR (||)
|
|
84
|
+
const hasLogicalOr = trimmed.includes('||');
|
|
85
|
+
|
|
86
|
+
// Logical AND (&&)
|
|
87
|
+
const hasLogicalAnd = trimmed.includes('&&');
|
|
88
|
+
|
|
89
|
+
// Nested nullish coalescing (??)
|
|
90
|
+
// If expression contains ??, wrap it to avoid conflict with the trailing ?? ''
|
|
91
|
+
const hasNullish = trimmed.includes('??');
|
|
92
|
+
|
|
93
|
+
// Wrap if any risky operator is found
|
|
94
|
+
if (hasTernary || hasLogicalOr || hasLogicalAnd || hasNullish) {
|
|
72
95
|
return `(${trimmed})`;
|
|
73
96
|
}
|
|
97
|
+
|
|
74
98
|
return trimmed;
|
|
75
99
|
}
|
|
76
100
|
|
|
@@ -1572,8 +1596,9 @@ export function generateComponent(parseResult, options = {}) {
|
|
|
1572
1596
|
lines.push(' }));');
|
|
1573
1597
|
} else {
|
|
1574
1598
|
// String expression: set className
|
|
1599
|
+
// Wrap ternary/logical expressions to prevent precedence issues
|
|
1575
1600
|
lines.push(' this.__disposers.push(__effect(() => {');
|
|
1576
|
-
lines.push(` this.${ab.varName}.className = ${expr};`);
|
|
1601
|
+
lines.push(` this.${ab.varName}.className = ${wrapTernaryExpr(expr)};`);
|
|
1577
1602
|
lines.push(' }));');
|
|
1578
1603
|
}
|
|
1579
1604
|
} else if (ab.kind === 'style') {
|
|
@@ -1930,6 +1955,24 @@ export function generateComponent(parseResult, options = {}) {
|
|
|
1930
1955
|
lines.push('');
|
|
1931
1956
|
}
|
|
1932
1957
|
|
|
1958
|
+
// Wrapper methods for defineModel signals (dual getter/setter)
|
|
1959
|
+
// These act as the interface between template code and internal signals
|
|
1960
|
+
// - As getter (no args): returns signal value
|
|
1961
|
+
// - As setter (with arg): calls _modelSet_* to update and dispatch events
|
|
1962
|
+
if (modelDefs.length > 0) {
|
|
1963
|
+
lines.push(' // --- Model wrapper methods ---');
|
|
1964
|
+
for (const md of modelDefs) {
|
|
1965
|
+
lines.push(` _${md.name}(val) {`);
|
|
1966
|
+
lines.push(` if (arguments.length === 0) {`);
|
|
1967
|
+
lines.push(` return this._m_${md.name}();`);
|
|
1968
|
+
lines.push(` } else {`);
|
|
1969
|
+
lines.push(` this._modelSet_${md.name}(val);`);
|
|
1970
|
+
lines.push(` }`);
|
|
1971
|
+
lines.push(` }`);
|
|
1972
|
+
lines.push('');
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1933
1976
|
// __scopedSlots instance getter and registerSlotRenderer (if scoped slots exist)
|
|
1934
1977
|
if (scopedSlotNames.length > 0) {
|
|
1935
1978
|
lines.push(' get __scopedSlots() { return this.constructor.__scopedSlots || []; }');
|
package/package.json
CHANGED