@fluixi/compiler 1.0.0-alpha.92 → 1.0.0-alpha.93
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/dist/analyze/intrinsics.cjs +18 -0
- package/dist/analyze/intrinsics.d.ts.map +1 -1
- package/dist/analyze/intrinsics.js +18 -0
- package/dist/analyze/intrinsics.mjs +18 -0
- package/dist/analyze/reactive-bindings.cjs +18 -0
- package/dist/analyze/reactive-bindings.mjs +18 -0
- package/dist/analyze/static-graph.cjs +22 -4
- package/dist/analyze/static-graph.d.ts.map +1 -1
- package/dist/analyze/static-graph.js +6 -4
- package/dist/analyze/static-graph.mjs +22 -4
- package/dist/{babel-GI375YZ2.mjs → babel-RJHJQVEM.mjs} +4 -4
- package/dist/{chunk-QZ4CJPYP.mjs → chunk-56QSOVVL.mjs} +1 -1
- package/dist/{chunk-XJ5H2MXY.mjs → chunk-OD53TMER.mjs} +19 -1
- package/dist/{chunk-DWNWN5RH.mjs → chunk-R7PPFBCL.mjs} +1 -1
- package/dist/{chunk-VOUI6XPV.mjs → chunk-TJIH7TLX.mjs} +1 -1
- package/dist/{chunk-VC6X44FS.mjs → chunk-U7HCFLZ2.mjs} +153 -48
- package/dist/codegen/backends/imperative.cjs +24 -6
- package/dist/codegen/backends/imperative.d.ts.map +1 -1
- package/dist/codegen/backends/imperative.js +19 -4
- package/dist/codegen/backends/imperative.mjs +24 -6
- package/dist/frontend/babel/build-ir-lit.cjs +120 -43
- package/dist/frontend/babel/build-ir-lit.mjs +120 -43
- package/dist/frontend/babel/build-ir.cjs +120 -43
- package/dist/frontend/babel/build-ir.mjs +120 -43
- package/dist/frontend/babel/index.cjs +121 -44
- package/dist/frontend/babel/index.mjs +121 -44
- package/dist/frontend/babel/lower-template.cjs +120 -43
- package/dist/frontend/babel/lower-template.mjs +120 -43
- package/dist/frontend/babel/plugin.cjs +120 -43
- package/dist/frontend/babel/plugin.mjs +120 -43
- package/dist/index.cjs +41 -38
- package/dist/index.mjs +41 -38
- package/dist/integrations.cjs +176 -52
- package/dist/integrations.mjs +8 -8
- package/dist/lower/compile-template.cjs +41 -38
- package/dist/lower/compile-template.mjs +41 -38
- package/dist/lower/jsx.cjs +509 -6
- package/dist/lower/jsx.d.ts.map +1 -1
- package/dist/lower/jsx.js +114 -6
- package/dist/lower/jsx.mjs +509 -6
- package/dist/lower/template.cjs +40 -37
- package/dist/lower/template.d.ts.map +1 -1
- package/dist/lower/template.js +22 -30
- package/dist/lower/template.mjs +40 -37
- package/dist/resolve/builtins.cjs +1 -1
- package/dist/resolve/builtins.mjs +1 -1
- package/dist/resolve/component-globals.cjs +14 -0
- package/dist/resolve/component-globals.mjs +14 -0
- package/dist/resolve/write-globals.cjs +14 -0
- package/dist/resolve/write-globals.mjs +14 -0
- package/dist/{server-fns-BBZRZUPP.mjs → server-fns-ZFRDIQ2X.mjs} +4 -4
- package/dist/{server-functions-VEGLIFCE.mjs → server-functions-CTDXX67X.mjs} +3 -3
- package/dist/transform/index.cjs +170 -47
- package/dist/transform/index.mjs +170 -47
- package/dist/transform/intrinsics.cjs +18 -0
- package/dist/transform/intrinsics.mjs +18 -0
- package/dist/transform/source-locations.cjs +64 -3
- package/dist/transform/source-locations.d.cts +7 -2
- package/dist/transform/source-locations.d.ts +7 -2
- package/dist/transform/source-locations.d.ts.map +1 -1
- package/dist/transform/source-locations.js +68 -3
- package/dist/transform/source-locations.mjs +64 -3
- package/dist/transform/templates.cjs +169 -46
- package/dist/transform/templates.js +2 -2
- package/dist/transform/templates.mjs +169 -46
- package/dist/{transform-UWZ7ZGJ2.mjs → transform-QWWQDCXE.mjs} +7 -7
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +9 -3
package/dist/lower/jsx.js
CHANGED
|
@@ -4,6 +4,7 @@ import { shapeOf } from '../analyze/expr-shape.js';
|
|
|
4
4
|
import { analyzeStatic } from '../optimize/analyze-static.js';
|
|
5
5
|
import { cleanTemplateText } from './text.js';
|
|
6
6
|
import { paren } from '../analyze/paren.js';
|
|
7
|
+
import { imperativeBackend, inlineTemplates } from '../codegen/backends/imperative.js';
|
|
7
8
|
export const SVG_TAGS = new Set([
|
|
8
9
|
'svg', 'path', 'circle', 'rect', 'line', 'polygon', 'polyline',
|
|
9
10
|
'ellipse', 'g', 'defs', 'clipPath', 'text',
|
|
@@ -14,6 +15,29 @@ const DELEGATED = new Set([
|
|
|
14
15
|
'keydown', 'keyup', 'keypress', 'mousedown', 'mouseup',
|
|
15
16
|
]);
|
|
16
17
|
const isReactive = (node) => isReactiveShape(shapeOf(node));
|
|
18
|
+
/** The tag that carries directives and renders only its content. Never a custom element: no dash. */
|
|
19
|
+
const CONTAINER = 'container';
|
|
20
|
+
/** An intrinsic element's `if`, `else`, `each` or `key` attribute, as written. */
|
|
21
|
+
function directive(node, name) {
|
|
22
|
+
if (node.type !== 'JSXElement')
|
|
23
|
+
return undefined;
|
|
24
|
+
const opening = node.openingElement;
|
|
25
|
+
if (opening.name.type !== 'JSXIdentifier' || opening.name.name[0] !== opening.name.name[0].toLowerCase())
|
|
26
|
+
return undefined;
|
|
27
|
+
return opening.attributes.find((a) => a.type === 'JSXAttribute' && a.name.type === 'JSXIdentifier' && a.name.name === name);
|
|
28
|
+
}
|
|
29
|
+
/** The expression a directive holds: `if={cond}`. */
|
|
30
|
+
function directiveExpr(attr) {
|
|
31
|
+
const v = attr.value;
|
|
32
|
+
return v?.type === 'JSXExpressionContainer' && v.expression?.type !== 'JSXEmptyExpression' ? v.expression : undefined;
|
|
33
|
+
}
|
|
34
|
+
/** A nested subtree as code, for `Show`'s fallback and `For`'s render function. */
|
|
35
|
+
function emitIR(ir, ctx) {
|
|
36
|
+
const { code, imports, templates } = imperativeBackend.emit(ir, {});
|
|
37
|
+
for (const s of imports)
|
|
38
|
+
ctx.used.add(s);
|
|
39
|
+
return inlineTemplates(code, templates);
|
|
40
|
+
}
|
|
17
41
|
/** Only when the host asked for source locations, the flag that records usage sites too. */
|
|
18
42
|
const posOf = (node, ctx) => {
|
|
19
43
|
if (!ctx.sourceFile)
|
|
@@ -146,7 +170,19 @@ function buildProps(attrs, ctx) {
|
|
|
146
170
|
}
|
|
147
171
|
function buildChildren(children, ctx) {
|
|
148
172
|
const out = [];
|
|
149
|
-
for (
|
|
173
|
+
for (let i = 0; i < children.length; i++) {
|
|
174
|
+
const child = children[i];
|
|
175
|
+
if (directive(child, 'if')) {
|
|
176
|
+
// The next element, past whitespace, is the fallback when it says `else`.
|
|
177
|
+
let next = i + 1;
|
|
178
|
+
while (next < children.length && children[next].type === 'JSXText' && !cleanTemplateText(children[next].value))
|
|
179
|
+
next++;
|
|
180
|
+
const fallback = directive(children[next], 'else') ? children[next] : null;
|
|
181
|
+
out.push(buildIf(child, fallback, ctx));
|
|
182
|
+
if (fallback)
|
|
183
|
+
i = next;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
150
186
|
if (child.type === 'JSXText') {
|
|
151
187
|
// Drop whitespace-only text spanning a newline so a lone child stays lone ,
|
|
152
188
|
// an array insert will not reactively bind a memo/component inside it.
|
|
@@ -190,21 +226,93 @@ function readLoad(attrs) {
|
|
|
190
226
|
}
|
|
191
227
|
return undefined;
|
|
192
228
|
}
|
|
229
|
+
/** `<el if={cond}>` and an optional `<el else>` after it → `<Show when fallback>`. */
|
|
230
|
+
function buildIf(node, fallback, ctx) {
|
|
231
|
+
const cond = directiveExpr(directive(node, 'if'));
|
|
232
|
+
const props = [
|
|
233
|
+
cond
|
|
234
|
+
? { name: 'when', kind: 'attr', expr: ctx.code(cond), reactive: isReactive(cond), at: posOf(cond, ctx) }
|
|
235
|
+
: { name: 'when', kind: 'attr', literal: true },
|
|
236
|
+
];
|
|
237
|
+
if (fallback) {
|
|
238
|
+
props.push({ name: 'fallback', kind: 'attr', expr: emitIR(buildElement(fallback, ctx, ['else']), ctx), jsxElement: true });
|
|
239
|
+
}
|
|
240
|
+
return { kind: 'component', name: 'Show', props, children: [buildElement(node, ctx, ['if'])] };
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* `<el each={items} key?>{(item) => …}</el>` → `<el><For each by>{…}</For></el>`: the
|
|
244
|
+
* content repeats, the element does not. Null when there is no `each`.
|
|
245
|
+
*/
|
|
246
|
+
function buildEach(node, ctx) {
|
|
247
|
+
const attr = directive(node, 'each');
|
|
248
|
+
if (!attr)
|
|
249
|
+
return null;
|
|
250
|
+
const list = directiveExpr(attr);
|
|
251
|
+
const props = [
|
|
252
|
+
list
|
|
253
|
+
? { name: 'each', kind: 'attr', expr: ctx.code(list), reactive: isReactive(list), at: posOf(list, ctx) }
|
|
254
|
+
: { name: 'each', kind: 'attr', expr: '[]' },
|
|
255
|
+
];
|
|
256
|
+
const key = directive(node, 'key');
|
|
257
|
+
if (key) {
|
|
258
|
+
const keyExpr = directiveExpr(key);
|
|
259
|
+
const by = isString(key.value)
|
|
260
|
+
? `(item) => item[${JSON.stringify(literalOf(key.value))}]`
|
|
261
|
+
: keyExpr
|
|
262
|
+
? ctx.code(keyExpr)
|
|
263
|
+
: undefined;
|
|
264
|
+
if (by)
|
|
265
|
+
props.push({ name: 'by', kind: 'attr', expr: by });
|
|
266
|
+
}
|
|
267
|
+
const content = node.children.filter((c) => !(c.type === 'JSXText' && !cleanTemplateText(c.value)));
|
|
268
|
+
const only = content.length === 1 && content[0].type === 'JSXExpressionContainer' ? content[0].expression : null;
|
|
269
|
+
let render;
|
|
270
|
+
if (only && (only.type === 'ArrowFunctionExpression' || only.type === 'FunctionExpression')) {
|
|
271
|
+
const fn = ctx.code(only);
|
|
272
|
+
// A body that reads signals, `{(it) => it.label + count()}`, is handed back as an
|
|
273
|
+
// accessor so the runtime binds it; a body that builds elements needs nothing.
|
|
274
|
+
const live = only.type === 'ArrowFunctionExpression' && only.body.type !== 'BlockStatement' && isReactive(only.body);
|
|
275
|
+
render = live ? `(...args) => () => (${fn})(...args)` : fn;
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
const built = buildChildren(node.children, ctx);
|
|
279
|
+
const ir = built.length === 1 ? built[0] : { kind: 'fragment', children: built };
|
|
280
|
+
render = `() => ${paren(emitIR(ir, ctx), 'arrowBody')}`;
|
|
281
|
+
}
|
|
282
|
+
return { kind: 'component', name: 'For', props, children: [{ kind: 'expr', code: render, reactive: false }] };
|
|
283
|
+
}
|
|
284
|
+
/** An element, with the directives already handled by the caller left out. */
|
|
285
|
+
function buildElement(node, ctx, handled) {
|
|
286
|
+
const skip = new Set(handled);
|
|
287
|
+
// `key` is only a directive beside `each`; anywhere else it is an ordinary attribute.
|
|
288
|
+
const directives = new Set(['if', 'else', 'each', ...(directive(node, 'each') ? ['key'] : [])]);
|
|
289
|
+
const attributes = node.openingElement.attributes.filter((a) => !(a.type === 'JSXAttribute' && a.name.type === 'JSXIdentifier' && (skip.has(a.name.name) || directives.has(a.name.name))));
|
|
290
|
+
const { tag } = tagInfo(node.openingElement.name, ctx);
|
|
291
|
+
const each = buildEach(node, ctx);
|
|
292
|
+
const children = each ? [each] : buildChildren(node.children, ctx);
|
|
293
|
+
if (tag === CONTAINER)
|
|
294
|
+
return children.length === 1 ? children[0] : { kind: 'fragment', children };
|
|
295
|
+
const at = ctx.sourceFile && node.loc?.start
|
|
296
|
+
? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column }
|
|
297
|
+
: undefined;
|
|
298
|
+
return { kind: 'element', tag, svg: SVG_TAGS.has(tag), props: buildProps(attributes, ctx), children, static: false, ...(at ? { at } : {}) };
|
|
299
|
+
}
|
|
193
300
|
function buildNode(node, ctx) {
|
|
194
301
|
if (node.type === 'JSXFragment') {
|
|
195
302
|
return { kind: 'fragment', children: buildChildren(node.children, ctx) };
|
|
196
303
|
}
|
|
304
|
+
if (directive(node, 'if'))
|
|
305
|
+
return buildIf(node, null, ctx);
|
|
197
306
|
const { tag, component } = tagInfo(node.openingElement.name, ctx);
|
|
307
|
+
if (!component)
|
|
308
|
+
return buildElement(node, ctx, []);
|
|
198
309
|
const props = buildProps(node.openingElement.attributes, ctx);
|
|
199
310
|
const children = buildChildren(node.children, ctx);
|
|
200
311
|
const at = ctx.sourceFile && node.loc?.start
|
|
201
312
|
? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column }
|
|
202
313
|
: undefined;
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
return { kind: 'component', name: tag, props, children, ...(load ? { load } : {}), ...(at ? { at } : {}) };
|
|
206
|
-
}
|
|
207
|
-
return { kind: 'element', tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...(at ? { at } : {}) };
|
|
314
|
+
const load = readLoad(node.openingElement.attributes);
|
|
315
|
+
return { kind: 'component', name: tag, props, children, ...(load ? { load } : {}), ...(at ? { at } : {}) };
|
|
208
316
|
}
|
|
209
317
|
/** Build IR from a JSXElement or JSXFragment. */
|
|
210
318
|
export function buildJsxIR(node, ctx) {
|