@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.
Files changed (68) hide show
  1. package/dist/analyze/intrinsics.cjs +18 -0
  2. package/dist/analyze/intrinsics.d.ts.map +1 -1
  3. package/dist/analyze/intrinsics.js +18 -0
  4. package/dist/analyze/intrinsics.mjs +18 -0
  5. package/dist/analyze/reactive-bindings.cjs +18 -0
  6. package/dist/analyze/reactive-bindings.mjs +18 -0
  7. package/dist/analyze/static-graph.cjs +22 -4
  8. package/dist/analyze/static-graph.d.ts.map +1 -1
  9. package/dist/analyze/static-graph.js +6 -4
  10. package/dist/analyze/static-graph.mjs +22 -4
  11. package/dist/{babel-GI375YZ2.mjs → babel-RJHJQVEM.mjs} +4 -4
  12. package/dist/{chunk-QZ4CJPYP.mjs → chunk-56QSOVVL.mjs} +1 -1
  13. package/dist/{chunk-XJ5H2MXY.mjs → chunk-OD53TMER.mjs} +19 -1
  14. package/dist/{chunk-DWNWN5RH.mjs → chunk-R7PPFBCL.mjs} +1 -1
  15. package/dist/{chunk-VOUI6XPV.mjs → chunk-TJIH7TLX.mjs} +1 -1
  16. package/dist/{chunk-VC6X44FS.mjs → chunk-U7HCFLZ2.mjs} +153 -48
  17. package/dist/codegen/backends/imperative.cjs +24 -6
  18. package/dist/codegen/backends/imperative.d.ts.map +1 -1
  19. package/dist/codegen/backends/imperative.js +19 -4
  20. package/dist/codegen/backends/imperative.mjs +24 -6
  21. package/dist/frontend/babel/build-ir-lit.cjs +120 -43
  22. package/dist/frontend/babel/build-ir-lit.mjs +120 -43
  23. package/dist/frontend/babel/build-ir.cjs +120 -43
  24. package/dist/frontend/babel/build-ir.mjs +120 -43
  25. package/dist/frontend/babel/index.cjs +121 -44
  26. package/dist/frontend/babel/index.mjs +121 -44
  27. package/dist/frontend/babel/lower-template.cjs +120 -43
  28. package/dist/frontend/babel/lower-template.mjs +120 -43
  29. package/dist/frontend/babel/plugin.cjs +120 -43
  30. package/dist/frontend/babel/plugin.mjs +120 -43
  31. package/dist/index.cjs +41 -38
  32. package/dist/index.mjs +41 -38
  33. package/dist/integrations.cjs +176 -52
  34. package/dist/integrations.mjs +8 -8
  35. package/dist/lower/compile-template.cjs +41 -38
  36. package/dist/lower/compile-template.mjs +41 -38
  37. package/dist/lower/jsx.cjs +509 -6
  38. package/dist/lower/jsx.d.ts.map +1 -1
  39. package/dist/lower/jsx.js +114 -6
  40. package/dist/lower/jsx.mjs +509 -6
  41. package/dist/lower/template.cjs +40 -37
  42. package/dist/lower/template.d.ts.map +1 -1
  43. package/dist/lower/template.js +22 -30
  44. package/dist/lower/template.mjs +40 -37
  45. package/dist/resolve/builtins.cjs +1 -1
  46. package/dist/resolve/builtins.mjs +1 -1
  47. package/dist/resolve/component-globals.cjs +14 -0
  48. package/dist/resolve/component-globals.mjs +14 -0
  49. package/dist/resolve/write-globals.cjs +14 -0
  50. package/dist/resolve/write-globals.mjs +14 -0
  51. package/dist/{server-fns-BBZRZUPP.mjs → server-fns-ZFRDIQ2X.mjs} +4 -4
  52. package/dist/{server-functions-VEGLIFCE.mjs → server-functions-CTDXX67X.mjs} +3 -3
  53. package/dist/transform/index.cjs +170 -47
  54. package/dist/transform/index.mjs +170 -47
  55. package/dist/transform/intrinsics.cjs +18 -0
  56. package/dist/transform/intrinsics.mjs +18 -0
  57. package/dist/transform/source-locations.cjs +64 -3
  58. package/dist/transform/source-locations.d.cts +7 -2
  59. package/dist/transform/source-locations.d.ts +7 -2
  60. package/dist/transform/source-locations.d.ts.map +1 -1
  61. package/dist/transform/source-locations.js +68 -3
  62. package/dist/transform/source-locations.mjs +64 -3
  63. package/dist/transform/templates.cjs +169 -46
  64. package/dist/transform/templates.js +2 -2
  65. package/dist/transform/templates.mjs +169 -46
  66. package/dist/{transform-UWZ7ZGJ2.mjs → transform-QWWQDCXE.mjs} +7 -7
  67. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  68. 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 (const child of children) {
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
- if (component) {
204
- const load = readLoad(node.openingElement.attributes);
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) {