@sprlab/wccompiler 0.5.3 → 0.5.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 +5 -4
- package/lib/sfc-parser.js +52 -9
- package/lib/tree-walker.js +4 -4
- package/package.json +1 -1
package/lib/codegen.js
CHANGED
|
@@ -473,7 +473,7 @@ function generateItemSetup(lines, forBlock, itemVar, indexVar, propNames, signal
|
|
|
473
473
|
lines.push(`${indent} const __sp = { ${propsEntries} };`);
|
|
474
474
|
lines.push(`${indent} let __h = __slotEl.innerHTML;`);
|
|
475
475
|
lines.push(`${indent} for (const [k, v] of Object.entries(__sp)) {`);
|
|
476
|
-
lines.push(`${indent} __h = __h.replace(new RegExp('\\\\{\\\\{\\\\s*' + k + '\\\\s*\\\\}\\\\}', 'g'), v ?? '');`);
|
|
476
|
+
lines.push(`${indent} __h = __h.replace(new RegExp('\\\\{\\\\{\\\\s*' + k + '(\\\\(\\\\))?\\\\s*\\\\}\\\\}', 'g'), v ?? '');`);
|
|
477
477
|
lines.push(`${indent} }`);
|
|
478
478
|
lines.push(`${indent} __slotEl.innerHTML = __h;`);
|
|
479
479
|
lines.push(`${indent} }`);
|
|
@@ -761,13 +761,14 @@ export function generateComponent(parseResult, options = {}) {
|
|
|
761
761
|
lines.push(` this.${b.varName}.textContent = this._c_${b.name}() ?? '';`);
|
|
762
762
|
lines.push(' }));');
|
|
763
763
|
} else {
|
|
764
|
-
// method type — check if it's a props.x access
|
|
764
|
+
// method/expression type — check if it's a props.x access or a complex expression
|
|
765
765
|
let ref;
|
|
766
766
|
if (propsObjectName && b.name.startsWith(propsObjectName + '.')) {
|
|
767
767
|
const propName = b.name.slice(propsObjectName.length + 1);
|
|
768
768
|
ref = `this._s_${propName}()`;
|
|
769
769
|
} else {
|
|
770
|
-
|
|
770
|
+
// Use transformExpr for complex expressions (e.g. items().length, ternary)
|
|
771
|
+
ref = transformExpr(b.name, signalNames, computedNames, propsObjectName, propNames, emitsObjectName, constantNames, methodNames);
|
|
771
772
|
}
|
|
772
773
|
lines.push(' this.__disposers.push(__effect(() => {');
|
|
773
774
|
lines.push(` this.${b.varName}.textContent = ${ref} ?? '';`);
|
|
@@ -787,7 +788,7 @@ export function generateComponent(parseResult, options = {}) {
|
|
|
787
788
|
lines.push(` const __props = { ${propsObj} };`);
|
|
788
789
|
lines.push(` let __html = this.__slotTpl_${s.name};`);
|
|
789
790
|
lines.push(" for (const [k, v] of Object.entries(__props)) {");
|
|
790
|
-
lines.push(` __html = __html.replace(new RegExp('\\\\{\\\\{\\\\s*' + k + '\\\\s*\\\\}\\\\}', 'g'), v ?? '');`);
|
|
791
|
+
lines.push(` __html = __html.replace(new RegExp('\\\\{\\\\{\\\\s*' + k + '(\\\\(\\\\))?\\\\s*\\\\}\\\\}', 'g'), v ?? '');`);
|
|
791
792
|
lines.push(' }');
|
|
792
793
|
lines.push(` this.${s.varName}.innerHTML = __html;`);
|
|
793
794
|
lines.push(' });');
|
package/lib/sfc-parser.js
CHANGED
|
@@ -57,16 +57,59 @@ function findBlocks(source, blockName) {
|
|
|
57
57
|
let m;
|
|
58
58
|
|
|
59
59
|
while ((m = openRe.exec(source)) !== null) {
|
|
60
|
+
const attrs = m[1] || '';
|
|
61
|
+
|
|
62
|
+
// For template blocks: skip <template #name> (slot content, not SFC block)
|
|
63
|
+
if (blockName === 'template' && /#/.test(attrs)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
60
67
|
const openEnd = m.index + m[0].length;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
|
|
69
|
+
// Use depth counting to find the matching close tag (handles nested <template #name>)
|
|
70
|
+
if (blockName === 'template') {
|
|
71
|
+
let depth = 1;
|
|
72
|
+
let searchPos = openEnd;
|
|
73
|
+
let closeIdx = -1;
|
|
74
|
+
const openTagRe = /<template[\s>]/g;
|
|
75
|
+
const closeTagStr = '</template>';
|
|
76
|
+
|
|
77
|
+
while (depth > 0 && searchPos < source.length) {
|
|
78
|
+
const nextClose = source.indexOf(closeTagStr, searchPos);
|
|
79
|
+
if (nextClose === -1) break;
|
|
80
|
+
|
|
81
|
+
// Check for any opening <template> between searchPos and nextClose
|
|
82
|
+
openTagRe.lastIndex = searchPos;
|
|
83
|
+
let openMatch;
|
|
84
|
+
while ((openMatch = openTagRe.exec(source)) !== null && openMatch.index < nextClose) {
|
|
85
|
+
depth++;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
depth--; // for the </template> we found
|
|
89
|
+
if (depth === 0) {
|
|
90
|
+
closeIdx = nextClose;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
searchPos = nextClose + closeTagStr.length;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (closeIdx === -1) continue;
|
|
97
|
+
matches.push({
|
|
98
|
+
content: source.slice(openEnd, closeIdx),
|
|
99
|
+
attrs,
|
|
100
|
+
start: m.index,
|
|
101
|
+
end: closeIdx + closeTag.length,
|
|
102
|
+
});
|
|
103
|
+
} else {
|
|
104
|
+
const closeIdx = source.indexOf(closeTag, openEnd);
|
|
105
|
+
if (closeIdx === -1) continue;
|
|
106
|
+
matches.push({
|
|
107
|
+
content: source.slice(openEnd, closeIdx),
|
|
108
|
+
attrs,
|
|
109
|
+
start: m.index,
|
|
110
|
+
end: closeIdx + closeTag.length,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
70
113
|
}
|
|
71
114
|
|
|
72
115
|
return matches;
|
package/lib/tree-walker.js
CHANGED
|
@@ -240,10 +240,10 @@ export function walkTree(rootEl, signalNames, computedNames, propNames = new Set
|
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
// --- Text node with interpolations ---
|
|
243
|
-
if (node.nodeType === 3 && /\{\{[
|
|
243
|
+
if (node.nodeType === 3 && /\{\{(?:[^}]|\}(?!\}))+\}\}/.test(node.textContent)) {
|
|
244
244
|
const text = node.textContent;
|
|
245
245
|
const trimmed = text.trim();
|
|
246
|
-
const soleMatch = trimmed.match(/^\{\{([
|
|
246
|
+
const soleMatch = trimmed.match(/^\{\{((?:[^}]|\}(?!\}))+)\}\}$/);
|
|
247
247
|
const parent = node.parentNode;
|
|
248
248
|
|
|
249
249
|
// Strip trailing () from expression to get the base name for type lookup
|
|
@@ -268,7 +268,7 @@ export function walkTree(rootEl, signalNames, computedNames, propNames = new Set
|
|
|
268
268
|
// Case 2: Mixed text and interpolations — split into spans
|
|
269
269
|
const doc = node.ownerDocument;
|
|
270
270
|
const fragment = doc.createDocumentFragment();
|
|
271
|
-
const parts = text.split(/(\{\{[
|
|
271
|
+
const parts = text.split(/(\{\{(?:[^}]|\}(?!\}))+\}\})/);
|
|
272
272
|
const parentPath = pathParts.slice(0, -1);
|
|
273
273
|
|
|
274
274
|
// Find the index of this text node among its siblings
|
|
@@ -280,7 +280,7 @@ export function walkTree(rootEl, signalNames, computedNames, propNames = new Set
|
|
|
280
280
|
|
|
281
281
|
let offset = 0;
|
|
282
282
|
for (const part of parts) {
|
|
283
|
-
const bm = part.match(/^\{\{([
|
|
283
|
+
const bm = part.match(/^\{\{((?:[^}]|\}(?!\}))+)\}\}$/);
|
|
284
284
|
if (bm) {
|
|
285
285
|
fragment.appendChild(doc.createElement('span'));
|
|
286
286
|
const varName = `__b${bindIdx++}`;
|
package/package.json
CHANGED