@sola-air-ui/compiler 1.0.0 → 1.0.1
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 +58 -5
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -25,6 +25,11 @@ function scopeStyles(css, scopeHash) {
|
|
|
25
25
|
.map(part => {
|
|
26
26
|
const trimmed = part.trim();
|
|
27
27
|
if (!trimmed) return part;
|
|
28
|
+
// Insert scope hash before pseudo-class/element (e.g. button:hover → button.hash:hover)
|
|
29
|
+
const pseudoIdx = trimmed.search(/::?[\w-]/);
|
|
30
|
+
if (pseudoIdx > 0) {
|
|
31
|
+
return `${trimmed.slice(0, pseudoIdx)}.${scopeHash}${trimmed.slice(pseudoIdx)}`;
|
|
32
|
+
}
|
|
28
33
|
return `${trimmed}.${scopeHash}`;
|
|
29
34
|
})
|
|
30
35
|
.join(', ');
|
|
@@ -69,6 +74,35 @@ export function compile(source, options = {}) {
|
|
|
69
74
|
const scopedCss = hasStyles ? scopeStyles(styleContent, scopeHash) : '';
|
|
70
75
|
|
|
71
76
|
let rawTemplate = rawTemplateSource;
|
|
77
|
+
|
|
78
|
+
// Pre-process attribute-bound expressions BEFORE extractExpressions.
|
|
79
|
+
// extractExpressions replaces {expr} with <sola-expr> HTML tags, which breaks
|
|
80
|
+
// htmlparser2 when those tags land inside attribute values.
|
|
81
|
+
const dynAttrs = []; // expressions for __soladyn_N__ markers
|
|
82
|
+
|
|
83
|
+
// Event handlers: on:event={expr} → on:event="expr"
|
|
84
|
+
rawTemplate = rawTemplate.replace(/\bon:([\w]+)=\{([^}]+)\}/g, 'on:$1="$2"');
|
|
85
|
+
// Bind: bind:prop={expr} → bind:prop="expr"
|
|
86
|
+
rawTemplate = rawTemplate.replace(/\bbind:([\w]+)=\{([^}]+)\}/g, 'bind:$1="$2"');
|
|
87
|
+
// Quoted string interpolation: attr="text {expr} text" → attr="__soladyn_N__"
|
|
88
|
+
// Run iteratively to handle multiple {expr} per value.
|
|
89
|
+
let _prev;
|
|
90
|
+
do {
|
|
91
|
+
_prev = rawTemplate;
|
|
92
|
+
rawTemplate = rawTemplate.replace(/([\w:-]+)="([^"]*\{[^{}]+\}[^"]*)"/g, (_, attr, val) => {
|
|
93
|
+
const jsExpr = '`' + val.replace(/\{([^{}]+)\}/g, (__, e) => `\${${e.trim()}}`) + '`';
|
|
94
|
+
const i = dynAttrs.length;
|
|
95
|
+
dynAttrs.push(jsExpr);
|
|
96
|
+
return `${attr}="__soladyn_${i}__"`;
|
|
97
|
+
});
|
|
98
|
+
} while (rawTemplate !== _prev);
|
|
99
|
+
// Unquoted attr expressions: attr={expr} → attr="__soladyn_N__"
|
|
100
|
+
rawTemplate = rawTemplate.replace(/([\w:-]+)=\{([^{}]+)\}/g, (_, attr, expr) => {
|
|
101
|
+
const i = dynAttrs.length;
|
|
102
|
+
dynAttrs.push(expr.trim());
|
|
103
|
+
return `${attr}="__soladyn_${i}__"`;
|
|
104
|
+
});
|
|
105
|
+
|
|
72
106
|
rawTemplate = extractExpressions(rawTemplate);
|
|
73
107
|
|
|
74
108
|
// Pre-process logic blocks: structured if-then-else
|
|
@@ -148,7 +182,7 @@ export function compile(source, options = {}) {
|
|
|
148
182
|
exportedProps.push({ name, default: defaultVal });
|
|
149
183
|
edits.push({
|
|
150
184
|
start: node.start,
|
|
151
|
-
end: node.
|
|
185
|
+
end: node.end,
|
|
152
186
|
replacement: ''
|
|
153
187
|
});
|
|
154
188
|
});
|
|
@@ -173,10 +207,13 @@ export function compile(source, options = {}) {
|
|
|
173
207
|
const varName = decl.id.name;
|
|
174
208
|
const expr = decl.init.arguments[0];
|
|
175
209
|
const exprSrc = expr ? scriptContent.slice(expr.start, expr.end) : 'undefined';
|
|
210
|
+
const isFn = expr && (expr.type === 'ArrowFunctionExpression' || expr.type === 'FunctionExpression');
|
|
176
211
|
edits.push({
|
|
177
212
|
start: node.start,
|
|
178
213
|
end: node.end,
|
|
179
|
-
replacement:
|
|
214
|
+
replacement: isFn
|
|
215
|
+
? `const ${varName} = createDerived(${exprSrc});`
|
|
216
|
+
: `const ${varName} = createDerived(() => ${exprSrc});`
|
|
180
217
|
});
|
|
181
218
|
} else if (callee.type === 'Identifier' && callee.name === '$effect') {
|
|
182
219
|
const body = decl.init.arguments[0];
|
|
@@ -367,15 +404,31 @@ export function compile(source, options = {}) {
|
|
|
367
404
|
domCode += ` ${id}.classList.add('${scopeHash}');\n`;
|
|
368
405
|
}
|
|
369
406
|
|
|
407
|
+
const BOOLEAN_ATTRS = new Set(['disabled', 'checked', 'selected', 'readonly', 'required', 'multiple', 'open']);
|
|
370
408
|
for (const [key, val] of Object.entries(node.attribs || {})) {
|
|
409
|
+
// Dynamic attribute pre-processed from {expr} in attribute values
|
|
410
|
+
const dynMatch = /^__soladyn_(\d+)__$/.exec(val);
|
|
411
|
+
if (dynMatch) {
|
|
412
|
+
const expr = dynAttrs[parseInt(dynMatch[1])];
|
|
413
|
+
if (BOOLEAN_ATTRS.has(key)) {
|
|
414
|
+
domCode += ` createEffect(() => { const _v = !!(${expr}); if (_v) ${id}.setAttribute('${key}', ''); else ${id}.removeAttribute('${key}'); });\n`;
|
|
415
|
+
} else if (key === 'class' || key === 'className') {
|
|
416
|
+
const suffix = hasStyles ? ` + ' ${scopeHash}'` : '';
|
|
417
|
+
domCode += ` createEffect(() => { ${id}.className = (${expr})${suffix}; });\n`;
|
|
418
|
+
} else {
|
|
419
|
+
domCode += ` createEffect(() => { ${id}.setAttribute('${key}', String(${expr})); });\n`;
|
|
420
|
+
}
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
371
423
|
if (key.startsWith('on:')) {
|
|
372
424
|
const eventName = key.slice(3);
|
|
373
425
|
if (!/^[a-zA-Z][a-zA-Z0-9]*$/.test(eventName)) continue;
|
|
374
|
-
|
|
426
|
+
// val is the handler expression (pre-processed from {expr}), pass directly
|
|
427
|
+
domCode += ` ${id}.addEventListener('${eventName}', ${val});\n`;
|
|
375
428
|
} else if (key.startsWith('on')) {
|
|
376
429
|
const eventName = key.slice(2).toLowerCase();
|
|
377
430
|
if (!/^[a-zA-Z][a-zA-Z0-9]*$/.test(eventName)) continue;
|
|
378
|
-
domCode += ` ${id}.addEventListener('${eventName}',
|
|
431
|
+
domCode += ` ${id}.addEventListener('${eventName}', ${val});\n`;
|
|
379
432
|
} else if (key.startsWith('bind:')) {
|
|
380
433
|
const prop = key.slice(5);
|
|
381
434
|
if (prop === 'value') {
|
|
@@ -402,7 +455,7 @@ export function compile(source, options = {}) {
|
|
|
402
455
|
|
|
403
456
|
// Assemble final output module
|
|
404
457
|
let output = '';
|
|
405
|
-
output += `// Compiled by @sola-air-ui/compiler v1.0.
|
|
458
|
+
output += `// Compiled by @sola-air-ui/compiler v1.0.1\n`;
|
|
406
459
|
output += `import { createSignal, createDerived, createEffect, createIntent, createData, onMount, onDestroy, pushContext, popContext, __flush_mounts, __flush_destroys } from '@sola-air-ui/core';\n`;
|
|
407
460
|
|
|
408
461
|
for (const imp of componentImports) {
|