@sprlab/wccompiler 0.5.4 → 0.5.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.
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} }`);
@@ -788,7 +788,7 @@ export function generateComponent(parseResult, options = {}) {
788
788
  lines.push(` const __props = { ${propsObj} };`);
789
789
  lines.push(` let __html = this.__slotTpl_${s.name};`);
790
790
  lines.push(" for (const [k, v] of Object.entries(__props)) {");
791
- 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 ?? '');`);
792
792
  lines.push(' }');
793
793
  lines.push(` this.${s.varName}.innerHTML = __html;`);
794
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
- const closeIdx = source.indexOf(closeTag, openEnd);
62
- if (closeIdx === -1) continue; // unclosed tag skip
63
-
64
- matches.push({
65
- content: source.slice(openEnd, closeIdx),
66
- attrs: m[1] || '',
67
- start: m.index,
68
- end: closeIdx + closeTag.length,
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;
@@ -74,6 +74,14 @@ export function walkTree(rootEl, signalNames, computedNames, propNames = new Set
74
74
  if (node.nodeType === 1) {
75
75
  const el = /** @type {Element} */ (node);
76
76
 
77
+ // Skip <template #name> elements — they are slot content passed to child components
78
+ // Their interpolations are resolved by the provider, not the consumer
79
+ if (el.tagName === 'TEMPLATE') {
80
+ for (const attr of Array.from(el.attributes)) {
81
+ if (attr.name.startsWith('#')) return;
82
+ }
83
+ }
84
+
77
85
  // Detect <slot> elements — replace with <span data-slot="..."> placeholder
78
86
  if (el.tagName === 'SLOT') {
79
87
  const slotName = el.getAttribute('name') || '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sprlab/wccompiler",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "Zero-runtime compiler that transforms .wcc single-file components into native web components with signals-based reactivity",
5
5
  "type": "module",
6
6
  "bin": {