@sola-air-ui/compiler 1.0.5 → 1.0.7
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/package.json +1 -1
- package/src/index.js +38 -3
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -172,6 +172,10 @@ function extractExpressions(text) {
|
|
|
172
172
|
const inner = text.slice(i + 1, closeIdx).trim();
|
|
173
173
|
if (inner.startsWith('#') || inner.startsWith('/') || inner.startsWith(':')) {
|
|
174
174
|
result += text.slice(i, closeIdx + 1); i = closeIdx + 1;
|
|
175
|
+
} else if (inner.startsWith('@html')) {
|
|
176
|
+
const htmlExpr = inner.slice('@html'.length).trim();
|
|
177
|
+
result += `<sola-html expr="${htmlExpr.replace(/"/g, '"')}"></sola-html>`;
|
|
178
|
+
i = closeIdx + 1;
|
|
175
179
|
} else {
|
|
176
180
|
result += `<sola-expr expr="${inner.replace(/"/g, '"')}"></sola-expr>`;
|
|
177
181
|
i = closeIdx + 1;
|
|
@@ -245,7 +249,7 @@ export function compile(source, options = {}) {
|
|
|
245
249
|
templateNodes.pop();
|
|
246
250
|
}
|
|
247
251
|
}
|
|
248
|
-
}, { recognizeSelfClosing: true, lowerCaseTags: false });
|
|
252
|
+
}, { recognizeSelfClosing: true, lowerCaseTags: false, lowerCaseAttributeNames: false });
|
|
249
253
|
|
|
250
254
|
parser.write(rawTemplate.trim() || '<div></div>');
|
|
251
255
|
parser.end();
|
|
@@ -440,7 +444,25 @@ export function compile(source, options = {}) {
|
|
|
440
444
|
const id = `e${uid++}`;
|
|
441
445
|
domCode += ` const ${id} = document.createTextNode('');\n`;
|
|
442
446
|
domCode += ` ${parentVar}.appendChild(${id});\n`;
|
|
443
|
-
|
|
447
|
+
// Parenthesize expr before `?? ''`: JS forbids mixing ?? with || or && at the
|
|
448
|
+
// same level without explicit grouping (e.g. `col.label || col ?? ''` is a
|
|
449
|
+
// SyntaxError), and any {a || b}-style fallback expression — an extremely
|
|
450
|
+
// common pattern — would otherwise produce invalid generated code.
|
|
451
|
+
domCode += ` createEffect(() => { ${id}.textContent = String((${expr}) ?? ''); });\n`;
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// {@html expr} — renders expr as raw HTML via innerHTML, unlike {expr} which always
|
|
456
|
+
// goes through textContent. Wrapped in its own element so setting innerHTML can't
|
|
457
|
+
// clobber unrelated sibling nodes. Callers are responsible for trusting/sanitizing
|
|
458
|
+
// whatever markup they pass — same contract as innerHTML anywhere else.
|
|
459
|
+
if (node.name === 'sola-html') {
|
|
460
|
+
const expr = (node.attribs.expr || '').replace(/"/g, '"');
|
|
461
|
+
const id = `h${uid++}`;
|
|
462
|
+
domCode += ` const ${id} = document.createElement('div');\n`;
|
|
463
|
+
domCode += ` ${id}.style.display = 'contents';\n`;
|
|
464
|
+
domCode += ` ${parentVar}.appendChild(${id});\n`;
|
|
465
|
+
domCode += ` createEffect(() => { ${id}.innerHTML = String((${expr}) ?? ''); });\n`;
|
|
444
466
|
return;
|
|
445
467
|
}
|
|
446
468
|
|
|
@@ -454,10 +476,23 @@ export function compile(source, options = {}) {
|
|
|
454
476
|
// Dynamically-bound props (rows={items}) arrive here as __soladyn_N__ placeholders —
|
|
455
477
|
// resolve them back to the real expression from dynAttrs and pass it as a raw
|
|
456
478
|
// (unquoted) property so the child receives live data, not the placeholder text.
|
|
479
|
+
//
|
|
480
|
+
// `onXxx`-named props (e.g. onChange={handler}) are a special case: preprocessTemplate
|
|
481
|
+
// strips their {expr} down to raw identifier text before this code ever sees them
|
|
482
|
+
// (the same exception that makes real onclick/on:click DOM handlers work), so they
|
|
483
|
+
// never arrive as a __soladyn_N__ placeholder at all. Since preprocessTemplate can't
|
|
484
|
+
// yet tell a component apart from a native element, that exception can't distinguish
|
|
485
|
+
// "this is a DOM event on <button>" from "this is a callback prop on <Toggle>" — so
|
|
486
|
+
// treat any on-prefixed key here as a raw expression too, same as a real dynAttr.
|
|
457
487
|
const propEntries = [];
|
|
458
488
|
for (const [key, val] of Object.entries(node.attribs || {})) {
|
|
459
489
|
const dynMatch = /^__soladyn_(\d+)__$/.exec(val);
|
|
460
|
-
const
|
|
490
|
+
const isEventLikeProp = /^on:?[\w]+$/.test(key);
|
|
491
|
+
const propValue = dynMatch
|
|
492
|
+
? `(${dynAttrs[parseInt(dynMatch[1], 10)]})`
|
|
493
|
+
: isEventLikeProp
|
|
494
|
+
? `(${val})`
|
|
495
|
+
: JSON.stringify(val);
|
|
461
496
|
propEntries.push(`${JSON.stringify(key)}: ${propValue}`);
|
|
462
497
|
}
|
|
463
498
|
|