@fluixi/compiler 1.0.0-alpha.92 → 1.0.0-alpha.94

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 (102) hide show
  1. package/dist/analyze/intrinsics.cjs +31 -1
  2. package/dist/analyze/intrinsics.d.cts +14 -0
  3. package/dist/analyze/intrinsics.d.ts +14 -0
  4. package/dist/analyze/intrinsics.d.ts.map +1 -1
  5. package/dist/analyze/intrinsics.js +35 -0
  6. package/dist/analyze/intrinsics.mjs +31 -1
  7. package/dist/analyze/reactive-bindings.cjs +18 -0
  8. package/dist/analyze/reactive-bindings.mjs +18 -0
  9. package/dist/analyze/static-graph.cjs +22 -4
  10. package/dist/analyze/static-graph.d.ts.map +1 -1
  11. package/dist/analyze/static-graph.js +6 -4
  12. package/dist/analyze/static-graph.mjs +22 -4
  13. package/dist/{babel-GI375YZ2.mjs → babel-RJFQVFJW.mjs} +4 -4
  14. package/dist/{chunk-QZ4CJPYP.mjs → chunk-DP2QDWWH.mjs} +1 -1
  15. package/dist/{chunk-DWNWN5RH.mjs → chunk-E2RWTIYE.mjs} +21 -15
  16. package/dist/{chunk-XJ5H2MXY.mjs → chunk-HCCBEJEZ.mjs} +31 -1
  17. package/dist/{chunk-VOUI6XPV.mjs → chunk-HIZU7WI2.mjs} +1 -1
  18. package/dist/{chunk-VC6X44FS.mjs → chunk-ZR2QHTEX.mjs} +505 -68
  19. package/dist/codegen/backends/imperative.cjs +24 -6
  20. package/dist/codegen/backends/imperative.d.ts.map +1 -1
  21. package/dist/codegen/backends/imperative.js +20 -4
  22. package/dist/codegen/backends/imperative.mjs +24 -6
  23. package/dist/frontend/babel/build-ir-lit.cjs +470 -63
  24. package/dist/frontend/babel/build-ir-lit.mjs +470 -63
  25. package/dist/frontend/babel/build-ir.cjs +470 -63
  26. package/dist/frontend/babel/build-ir.mjs +470 -63
  27. package/dist/frontend/babel/index.cjs +471 -64
  28. package/dist/frontend/babel/index.mjs +471 -64
  29. package/dist/frontend/babel/lower-template.cjs +470 -63
  30. package/dist/frontend/babel/lower-template.mjs +470 -63
  31. package/dist/frontend/babel/plugin.cjs +470 -63
  32. package/dist/frontend/babel/plugin.mjs +470 -63
  33. package/dist/index.cjs +360 -58
  34. package/dist/index.mjs +372 -58
  35. package/dist/integrations.cjs +1347 -98
  36. package/dist/integrations.d.ts.map +1 -1
  37. package/dist/integrations.js +44 -2
  38. package/dist/integrations.mjs +205 -19
  39. package/dist/lower/compile-template.cjs +354 -57
  40. package/dist/lower/compile-template.d.cts +13 -0
  41. package/dist/lower/compile-template.d.ts +13 -0
  42. package/dist/lower/compile-template.d.ts.map +1 -1
  43. package/dist/lower/compile-template.js +3 -0
  44. package/dist/lower/compile-template.mjs +366 -57
  45. package/dist/lower/entities.cjs +288 -0
  46. package/dist/lower/entities.d.cts +1 -0
  47. package/dist/lower/entities.d.ts +2 -0
  48. package/dist/lower/entities.d.ts.map +1 -0
  49. package/dist/lower/entities.js +54 -0
  50. package/dist/lower/entities.mjs +267 -0
  51. package/dist/lower/jsx.cjs +567 -7
  52. package/dist/lower/jsx.d.cts +8 -0
  53. package/dist/lower/jsx.d.ts +8 -0
  54. package/dist/lower/jsx.d.ts.map +1 -1
  55. package/dist/lower/jsx.js +205 -7
  56. package/dist/lower/jsx.mjs +567 -7
  57. package/dist/lower/template.cjs +332 -56
  58. package/dist/lower/template.d.ts.map +1 -1
  59. package/dist/lower/template.js +57 -49
  60. package/dist/lower/template.mjs +332 -56
  61. package/dist/resolve/builtins.cjs +1 -1
  62. package/dist/resolve/builtins.mjs +1 -1
  63. package/dist/resolve/component-globals.cjs +20 -1
  64. package/dist/resolve/component-globals.js +2 -2
  65. package/dist/resolve/component-globals.mjs +20 -1
  66. package/dist/resolve/write-globals.cjs +20 -1
  67. package/dist/resolve/write-globals.mjs +20 -1
  68. package/dist/{server-fns-BBZRZUPP.mjs → server-fns-JLSTKWPS.mjs} +4 -4
  69. package/dist/{server-functions-VEGLIFCE.mjs → server-functions-BGY3RD4R.mjs} +3 -3
  70. package/dist/transform/index.cjs +1123 -77
  71. package/dist/transform/index.mjs +1141 -91
  72. package/dist/transform/intrinsics.cjs +18 -0
  73. package/dist/transform/intrinsics.mjs +18 -0
  74. package/dist/transform/props.mjs +19 -14
  75. package/dist/transform/server-fns.mjs +19 -14
  76. package/dist/transform/source-locations.cjs +64 -3
  77. package/dist/transform/source-locations.d.cts +7 -2
  78. package/dist/transform/source-locations.d.ts +7 -2
  79. package/dist/transform/source-locations.d.ts.map +1 -1
  80. package/dist/transform/source-locations.js +68 -3
  81. package/dist/transform/source-locations.mjs +64 -3
  82. package/dist/transform/styles.cjs +588 -0
  83. package/dist/transform/styles.d.cts +211 -0
  84. package/dist/transform/styles.d.ts +212 -0
  85. package/dist/transform/styles.d.ts.map +1 -0
  86. package/dist/transform/styles.js +714 -0
  87. package/dist/transform/styles.mjs +653 -0
  88. package/dist/transform/templates.cjs +1122 -76
  89. package/dist/transform/templates.d.cts +13 -0
  90. package/dist/transform/templates.d.ts +13 -0
  91. package/dist/transform/templates.d.ts.map +1 -1
  92. package/dist/transform/templates.js +51 -14
  93. package/dist/transform/templates.mjs +1140 -90
  94. package/dist/{transform-UWZ7ZGJ2.mjs → transform-GBP6Y4UI.mjs} +603 -19
  95. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  96. package/dist/vite-styles.cjs +180 -0
  97. package/dist/vite-styles.d.cts +59 -0
  98. package/dist/vite-styles.d.ts +60 -0
  99. package/dist/vite-styles.d.ts.map +1 -0
  100. package/dist/vite-styles.js +198 -0
  101. package/dist/vite-styles.mjs +159 -0
  102. package/package.json +10 -3
@@ -10,7 +10,9 @@ import { parseTemplate, } from '@fluixi/template-parser';
10
10
  import { parseLoadDirective } from '../resolve/load-directive.js';
11
11
  import { imperativeBackend, inlineTemplates } from '../codegen/backends/imperative.js';
12
12
  import { cleanTemplateText } from './text.js';
13
+ import { decodeEntities } from './entities.js';
13
14
  import { paren } from '../analyze/paren.js';
15
+ import { markHole } from '../transform/source-locations.js';
14
16
  const DELEGATED = new Set([
15
17
  'click', 'dblclick', 'input', 'change', 'submit', 'focus', 'blur',
16
18
  'keydown', 'keyup', 'keypress', 'mousedown', 'mouseup',
@@ -19,6 +21,8 @@ const DELEGATED = new Set([
19
21
  function escapeTemplate(s) {
20
22
  return s.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
21
23
  }
24
+ /** The tag that carries directives and renders only its content. Never a custom element: no dash. */
25
+ const CONTAINER = 'container';
22
26
  function capitalize(s) {
23
27
  return s.charAt(0).toUpperCase() + s.slice(1);
24
28
  }
@@ -88,10 +92,6 @@ class Lowerer {
88
92
  i = elseIdx;
89
93
  continue;
90
94
  }
91
- if (child.attributes.some((a) => a.kind === 'EachDirective')) {
92
- out.push(this.lowerEach(child));
93
- continue;
94
- }
95
95
  }
96
96
  const node = this.lowerNode(child);
97
97
  if (node)
@@ -107,7 +107,8 @@ class Lowerer {
107
107
  case 'Text': {
108
108
  if (node.raw)
109
109
  return { kind: 'text', value: node.value };
110
- const cleaned = cleanTemplateText(node.value);
110
+ // Decoded after cleaning, so an entity written as a space is kept as written.
111
+ const cleaned = decodeEntities(cleanTemplateText(node.value));
111
112
  return cleaned ? { kind: 'text', value: cleaned } : null;
112
113
  }
113
114
  case 'Comment':
@@ -137,13 +138,19 @@ class Lowerer {
137
138
  node.props.unshift({ name: 'component', kind: 'attr', expr: `() => ${paren(this.hole(isAttr.value.hole).code, 'arrowBody')}` });
138
139
  return node;
139
140
  }
141
+ // `each` repeats the element's content, never the element: `<ul each>` is one list.
142
+ const each = this.lowerEach(el);
143
+ const children = each ? [each] : this.lowerChildren(el.children);
144
+ // A `<container>` is only what it holds. It carries the directives and is never rendered.
145
+ if (el.tag === CONTAINER)
146
+ return children.length === 1 ? children[0] : { kind: 'fragment', children };
140
147
  const at = this.tagAt(el);
141
148
  return {
142
149
  kind: 'element',
143
150
  tag: el.tag,
144
151
  svg: el.namespace === 'svg',
145
- props: this.lowerAttributes(el.attributes),
146
- children: this.lowerChildren(el.children),
152
+ props: this.lowerAttributes(el.attributes, true),
153
+ children,
147
154
  static: false,
148
155
  ...(at ? { at } : {}),
149
156
  };
@@ -233,11 +240,15 @@ class Lowerer {
233
240
  const at = this.tagAt(el);
234
241
  return { kind: 'component', name: 'Show', props, children: [child], ...(at ? { at } : {}), ...(cond.at ? { bindAt: cond.at } : {}) };
235
242
  }
236
- /** `<el each=${items} key?>${item => …}</el>` → `<For each>{item => <el>…</el>}</For>`. */
243
+ /**
244
+ * `<el each=${items} key?>${item => …}</el>` → `<el><For each>{item => …}</For></el>`: the
245
+ * content is repeated per item. Content that is not a `${item => …}` arrow is repeated as
246
+ * it is. Null when the element has no `each`.
247
+ */
237
248
  lowerEach(el) {
238
249
  const eachDir = el.attributes.find((a) => a.kind === 'EachDirective');
239
250
  if (!eachDir || eachDir.kind !== 'EachDirective')
240
- return this.lowerNode(el);
251
+ return null;
241
252
  const each = this.hole(eachDir.hole);
242
253
  const props = [{ name: 'each', kind: 'attr', expr: each.code, reactive: each.reactive, ...(each.at ? { at: each.at } : {}) }];
243
254
  if (eachDir.key) {
@@ -248,17 +259,18 @@ class Lowerer {
248
259
  : this.hole(eachDir.key.hole).code;
249
260
  props.push({ name: 'by', kind: 'attr', expr: by });
250
261
  }
251
- // The element minus its each/key, repeated per item.
252
262
  const arrow = this.itemArrow(el);
253
263
  let childrenCode;
254
264
  if (arrow) {
255
- const bodyIR = { kind: 'expr', code: arrow.body, reactive: arrow.bodyReactive };
256
- const repeated = this.rebuildWithChildren(el, [bodyIR]);
257
- childrenCode = `(${arrow.params.join(', ')}) => ${paren(this.emit(repeated), 'arrowBody')}`;
265
+ // A body that reads signals, `${(it) => it.label + count()}`, stays live: it is handed
266
+ // back as an accessor for the runtime to bind, as it was inside the repeated element.
267
+ const body = arrow.bodyReactive ? `() => ${paren(arrow.body, 'arrowBody')}` : paren(arrow.body, 'arrowBody');
268
+ childrenCode = `(${arrow.params.join(', ')}) => ${body}`;
258
269
  }
259
270
  else {
260
- const repeated = this.stripAndLower(el, (a) => a.kind === 'EachDirective');
261
- childrenCode = `() => ${paren(this.emit(repeated), 'arrowBody')}`;
271
+ const content = this.lowerChildren(el.children);
272
+ const ir = content.length === 1 ? content[0] : { kind: 'fragment', children: content };
273
+ childrenCode = `() => ${paren(this.emit(ir), 'arrowBody')}`;
262
274
  }
263
275
  const children = [{ kind: 'expr', code: childrenCode, reactive: false }];
264
276
  const at = this.tagAt(el);
@@ -276,31 +288,25 @@ class Lowerer {
276
288
  const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
277
289
  return clone.kind === 'Element' ? this.lowerElement(clone) : this.lowerComponent(clone);
278
290
  }
279
- /** Same element (minus each/key) but with explicit IR children. */
280
- rebuildWithChildren(el, children) {
281
- const props = this.lowerAttributes(el.attributes.filter((a) => a.kind !== 'EachDirective'));
282
- if (el.kind === 'Element') {
283
- const at = this.tagAt(el);
284
- return {
285
- kind: 'element',
286
- tag: el.tag,
287
- svg: el.namespace === 'svg',
288
- props,
289
- children,
290
- static: false,
291
- ...(at ? { at } : {}),
292
- };
293
- }
294
- return { kind: 'component', name: el.tag, props, children };
295
- }
296
291
  // --- attributes ---------------------------------------------------------
297
- lowerAttributes(attrs) {
292
+ /**
293
+ * `element`: a DOM element, where each class:/style: value that moves is its own accessor.
294
+ * A component gets the object as before, rebuilt whole when any value moves.
295
+ */
296
+ lowerAttributes(attrs, element = false) {
297
+ let anyReactive = false;
298
+ const entry = (name, h) => {
299
+ anyReactive ||= h.reactive;
300
+ if (!element || !h.reactive)
301
+ return `${JSON.stringify(name)}: ${h.code}`;
302
+ const accessor = `() => ${paren(h.code, 'arrowBody')}`;
303
+ // Marked like any other binding hole when positions are on.
304
+ return `${JSON.stringify(name)}: ${h.at ? markHole(accessor, h.at.line, h.at.column) : accessor}`;
305
+ };
298
306
  const props = [];
299
307
  const classEntries = [];
300
- let classReactive = false;
301
308
  let classAt;
302
309
  const styleEntries = [];
303
- let styleReactive = false;
304
310
  let styleAt;
305
311
  const usePairs = [];
306
312
  for (const a of attrs) {
@@ -339,15 +345,13 @@ class Lowerer {
339
345
  break;
340
346
  case 'ClassDirective': {
341
347
  const h = this.hole(a.hole);
342
- classEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
343
- classReactive = classReactive || h.reactive;
348
+ classEntries.push(entry(a.name, h));
344
349
  classAt ??= h.at;
345
350
  break;
346
351
  }
347
352
  case 'StyleDirective': {
348
353
  const h = this.hole(a.hole);
349
- styleEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
350
- styleReactive = styleReactive || h.reactive;
354
+ styleEntries.push(entry(a.name, h));
351
355
  styleAt ??= h.at;
352
356
  break;
353
357
  }
@@ -376,18 +380,22 @@ class Lowerer {
376
380
  name: 'classList',
377
381
  kind: 'attr',
378
382
  expr: `{ ${classEntries.join(', ')} }`,
379
- reactive: classReactive,
383
+ reactive: !element && anyReactive,
380
384
  ...(classAt ? { at: classAt } : {}),
381
385
  });
382
386
  }
387
+ // Each entry that moves is its own accessor, so the runtime updates that key alone.
383
388
  if (styleEntries.length > 0) {
384
- props.push({
385
- name: 'style',
386
- kind: 'attr',
387
- expr: `{ ${styleEntries.join(', ')} }`,
388
- reactive: styleReactive,
389
- ...(styleAt ? { at: styleAt } : {}),
390
- });
389
+ const entries = `{ ${styleEntries.join(', ')} }`;
390
+ // `style=${…}` as well: it goes first, the keys after it, applied in order.
391
+ const base = props.findIndex((p) => p.name === 'style');
392
+ if (base === -1)
393
+ props.push({ name: 'style', kind: 'attr', expr: entries, reactive: !element && anyReactive, ...(styleAt ? { at: styleAt } : {}) });
394
+ else {
395
+ const prop = props[base];
396
+ const value = prop.expr === undefined ? JSON.stringify(prop.literal) : prop.reactive ? `() => ${paren(prop.expr, 'arrowBody')}` : prop.expr;
397
+ props[base] = { name: 'style', kind: 'attr', expr: `[${value}, ${entries}]`, reactive: false, ...(prop.at ? { at: prop.at } : {}) };
398
+ }
391
399
  }
392
400
  // All use: directives normalize to one `use` prop = an array of [dir, accessor?] pairs.
393
401
  if (usePairs.length > 0) {
@@ -492,7 +500,7 @@ class Lowerer {
492
500
  return base;
493
501
  }
494
502
  if (v.kind === 'static') {
495
- base.literal = v.value;
503
+ base.literal = decodeEntities(v.value);
496
504
  return base;
497
505
  }
498
506
  if (v.kind === 'hole') {
@@ -509,7 +517,7 @@ class Lowerer {
509
517
  const body = v.parts
510
518
  .map((p) => {
511
519
  if ('text' in p)
512
- return escapeTemplate(p.text);
520
+ return escapeTemplate(decodeEntities(p.text));
513
521
  const h = this.hole(p.hole);
514
522
  reactive = reactive || h.reactive;
515
523
  at ??= h.at;