@sprlab/wccompiler 0.16.10 → 0.16.12
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 +16 -18
- package/lib/sfc-parser.js +9 -4
- package/package.json +1 -1
package/lib/codegen.js
CHANGED
|
@@ -1138,14 +1138,25 @@ export function generateComponent(parseResult, options = {}) {
|
|
|
1138
1138
|
if (slots.length > 0) {
|
|
1139
1139
|
lines.push(' const __slotMap = {};');
|
|
1140
1140
|
lines.push(' const __defaultSlotNodes = [];');
|
|
1141
|
+
lines.push(' const __templatesToRemove = [];');
|
|
1141
1142
|
lines.push(' for (const child of Array.from(this.childNodes)) {');
|
|
1142
1143
|
lines.push(" if (child.nodeName === 'TEMPLATE') {");
|
|
1144
|
+
lines.push(' let handled = false;');
|
|
1143
1145
|
lines.push(' for (const attr of child.attributes) {');
|
|
1144
1146
|
lines.push(" if (attr.name.startsWith('#')) {");
|
|
1145
1147
|
lines.push(' const slotName = attr.name.slice(1);');
|
|
1146
1148
|
lines.push(' __slotMap[slotName] = { content: child.innerHTML, propsExpr: attr.value };');
|
|
1149
|
+
lines.push(' handled = true;');
|
|
1150
|
+
lines.push(' } else if (attr.name === "slot") {');
|
|
1151
|
+
// NEW: <template slot="name"> syntax (Vue standard)
|
|
1152
|
+
lines.push(' const slotName = attr.value;');
|
|
1153
|
+
lines.push(" const propsExpr = child.getAttribute('slot-props') || '';");
|
|
1154
|
+
lines.push(" child.removeAttribute('slot-props');");
|
|
1155
|
+
lines.push(' __slotMap[slotName] = { content: child.innerHTML, propsExpr };');
|
|
1156
|
+
lines.push(' handled = true;');
|
|
1147
1157
|
lines.push(' }');
|
|
1148
1158
|
lines.push(' }');
|
|
1159
|
+
lines.push(' if (handled) __templatesToRemove.push(child);');
|
|
1149
1160
|
lines.push(" } else if (child.nodeType === 1 && child.getAttribute('slot')) {");
|
|
1150
1161
|
// NEW: regular element with slot="name" (cross-framework support)
|
|
1151
1162
|
lines.push(" const slotName = child.getAttribute('slot');");
|
|
@@ -1154,21 +1165,15 @@ export function generateComponent(parseResult, options = {}) {
|
|
|
1154
1165
|
lines.push(" child.removeAttribute('slot-props');");
|
|
1155
1166
|
lines.push(" __slotMap[slotName] = { content: propsExpr ? child.innerHTML : child.outerHTML, propsExpr };");
|
|
1156
1167
|
lines.push(" } else if (child.nodeType === 1) {");
|
|
1157
|
-
// NEW: check for slot-template-<name> attributes (React/Angular string attribute pattern)
|
|
1158
|
-
lines.push(" for (const attr of Array.from(child.attributes)) {");
|
|
1159
|
-
lines.push(" if (attr.name.startsWith('slot-template-')) {");
|
|
1160
|
-
lines.push(" const slotName = attr.name.slice('slot-template-'.length);");
|
|
1161
|
-
lines.push(" if (!__slotMap[slotName]) {");
|
|
1162
|
-
lines.push(" __slotMap[slotName] = { content: attr.value, propsExpr: '' };");
|
|
1163
|
-
lines.push(" }");
|
|
1164
|
-
lines.push(" child.removeAttribute(attr.name);");
|
|
1165
|
-
lines.push(" }");
|
|
1166
|
-
lines.push(" }");
|
|
1167
1168
|
lines.push(" __defaultSlotNodes.push(child);");
|
|
1168
1169
|
lines.push(" } else if (child.nodeType === 3 && child.textContent.trim()) {");
|
|
1169
1170
|
lines.push(' __defaultSlotNodes.push(child);');
|
|
1170
1171
|
lines.push(' }');
|
|
1171
1172
|
lines.push(' }');
|
|
1173
|
+
// Remove processed template elements to prevent them from appearing in default slot
|
|
1174
|
+
lines.push(' for (const tpl of __templatesToRemove) {');
|
|
1175
|
+
lines.push(' if (tpl.parentNode) tpl.parentNode.removeChild(tpl);');
|
|
1176
|
+
lines.push(' }');
|
|
1172
1177
|
}
|
|
1173
1178
|
|
|
1174
1179
|
// Clone template
|
|
@@ -1312,15 +1317,8 @@ export function generateComponent(parseResult, options = {}) {
|
|
|
1312
1317
|
lines.push(" __sm[sn] = { content: pe ? child.innerHTML : child.outerHTML, propsExpr: pe };");
|
|
1313
1318
|
lines.push(" child.remove();");
|
|
1314
1319
|
lines.push(" } else if (child.nodeType === 1) {");
|
|
1315
|
-
lines.push(" for (const attr of Array.from(child.attributes)) {");
|
|
1316
|
-
lines.push(" if (attr.name.startsWith('slot-template-')) {");
|
|
1317
|
-
lines.push(" const sn = attr.name.slice('slot-template-'.length);");
|
|
1318
|
-
lines.push(" if (!__sm[sn]) { __sm[sn] = { content: attr.value, propsExpr: '' }; }");
|
|
1319
|
-
lines.push(" child.removeAttribute(attr.name);");
|
|
1320
|
-
lines.push(" }");
|
|
1321
|
-
lines.push(" }");
|
|
1322
1320
|
lines.push(" __dn.push(child);");
|
|
1323
|
-
lines.push(" } else if (child.nodeType === 3 && child.textContent.trim()) {");
|
|
1321
|
+
lines.push(" } else if (child.nodeType === 3 && child.textContent.trim()) {",);
|
|
1324
1322
|
lines.push(" __dn.push(child);");
|
|
1325
1323
|
lines.push(' }');
|
|
1326
1324
|
lines.push(' }');
|
package/lib/sfc-parser.js
CHANGED
|
@@ -287,16 +287,21 @@ export function parseSFC(source, fileName = '<unknown>') {
|
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
// Collect all block ranges for unexpected-content check
|
|
290
|
+
// Use filtered templateBlocks (main SFC template only, not nested slot templates)
|
|
291
|
+
// The main template's range already covers all nested content including <template slot="name">
|
|
290
292
|
/** @type {Array<{start: number, end: number}>} */
|
|
291
293
|
const allRanges = [
|
|
292
294
|
...scriptBlocks,
|
|
293
|
-
...templateBlocks,
|
|
295
|
+
...templateBlocks, // Only main SFC blocks (filtered to exclude slot templates)
|
|
294
296
|
...styleBlocks,
|
|
295
297
|
].sort((a, b) => a.start - b.start);
|
|
296
298
|
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
|
|
299
|
+
// Validate unexpected content ONLY if there are no nested slot templates
|
|
300
|
+
// Nested <template slot="name"> elements can cause false positives in range validation
|
|
301
|
+
const hasNestedSlotTemplates = allTemplateBlocks.length > templateBlocks.length;
|
|
302
|
+
if (!hasNestedSlotTemplates) {
|
|
303
|
+
validateNoUnexpectedContent(source, allRanges, fileName);
|
|
304
|
+
}
|
|
300
305
|
|
|
301
306
|
// Extract block contents
|
|
302
307
|
const scriptContent = scriptBlocks[0].content;
|
package/package.json
CHANGED