@fluixi/compiler 1.0.0-alpha.91 → 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 (81) hide show
  1. package/dist/analyze/intrinsics.cjs +21 -1
  2. package/dist/analyze/intrinsics.d.ts.map +1 -1
  3. package/dist/analyze/intrinsics.js +20 -0
  4. package/dist/analyze/intrinsics.mjs +21 -1
  5. package/dist/analyze/reactive-bindings.cjs +21 -1
  6. package/dist/analyze/reactive-bindings.mjs +21 -1
  7. package/dist/analyze/static-graph.cjs +25 -5
  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 +25 -5
  11. package/dist/{babel-VBLQRHQ2.mjs → babel-RJHJQVEM.mjs} +4 -4
  12. package/dist/{chunk-D53J7ICY.mjs → chunk-56QSOVVL.mjs} +1 -1
  13. package/dist/{chunk-S4J4OCWK.mjs → chunk-OD53TMER.mjs} +22 -2
  14. package/dist/{chunk-TWDJUXWZ.mjs → chunk-R7PPFBCL.mjs} +1 -1
  15. package/dist/{chunk-QX6Y3OAR.mjs → chunk-TJIH7TLX.mjs} +1 -1
  16. package/dist/{chunk-3JWMCK4A.mjs → chunk-U7HCFLZ2.mjs} +153 -48
  17. package/dist/codegen/backends/imperative.cjs +27 -7
  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 +27 -7
  21. package/dist/frontend/babel/build-ir-lit.cjs +123 -44
  22. package/dist/frontend/babel/build-ir-lit.mjs +123 -44
  23. package/dist/frontend/babel/build-ir.cjs +123 -44
  24. package/dist/frontend/babel/build-ir.mjs +123 -44
  25. package/dist/frontend/babel/index.cjs +124 -45
  26. package/dist/frontend/babel/index.mjs +124 -45
  27. package/dist/frontend/babel/lower-template.cjs +123 -44
  28. package/dist/frontend/babel/lower-template.mjs +123 -44
  29. package/dist/frontend/babel/plugin.cjs +123 -44
  30. package/dist/frontend/babel/plugin.mjs +123 -44
  31. package/dist/index.cjs +86 -46
  32. package/dist/index.mjs +88 -48
  33. package/dist/integrations.cjs +246 -61
  34. package/dist/integrations.mjs +53 -19
  35. package/dist/lower/compile-template.cjs +44 -39
  36. package/dist/lower/compile-template.mjs +44 -39
  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 +43 -38
  42. package/dist/lower/template.d.ts.map +1 -1
  43. package/dist/lower/template.js +22 -30
  44. package/dist/lower/template.mjs +43 -38
  45. package/dist/resolve/builtins.cjs +1 -1
  46. package/dist/resolve/builtins.mjs +1 -1
  47. package/dist/resolve/component-globals.cjs +33 -8
  48. package/dist/resolve/component-globals.d.cts +8 -0
  49. package/dist/resolve/component-globals.d.ts +8 -0
  50. package/dist/resolve/component-globals.d.ts.map +1 -1
  51. package/dist/resolve/component-globals.js +21 -12
  52. package/dist/resolve/component-globals.mjs +33 -8
  53. package/dist/resolve/write-globals.cjs +59 -8
  54. package/dist/resolve/write-globals.d.cts +6 -0
  55. package/dist/resolve/write-globals.d.ts +6 -0
  56. package/dist/resolve/write-globals.d.ts.map +1 -1
  57. package/dist/resolve/write-globals.js +35 -2
  58. package/dist/resolve/write-globals.mjs +61 -10
  59. package/dist/{server-fns-J56G3PFP.mjs → server-fns-ZFRDIQ2X.mjs} +4 -4
  60. package/dist/{server-functions-7PUFLRGF.mjs → server-functions-CTDXX67X.mjs} +3 -3
  61. package/dist/transform/index.cjs +199 -49
  62. package/dist/transform/index.mjs +199 -49
  63. package/dist/transform/intrinsics.cjs +47 -2
  64. package/dist/transform/intrinsics.d.cts +12 -0
  65. package/dist/transform/intrinsics.d.ts +12 -0
  66. package/dist/transform/intrinsics.d.ts.map +1 -1
  67. package/dist/transform/intrinsics.js +43 -1
  68. package/dist/transform/intrinsics.mjs +47 -2
  69. package/dist/transform/source-locations.cjs +67 -4
  70. package/dist/transform/source-locations.d.cts +7 -2
  71. package/dist/transform/source-locations.d.ts +7 -2
  72. package/dist/transform/source-locations.d.ts.map +1 -1
  73. package/dist/transform/source-locations.js +68 -3
  74. package/dist/transform/source-locations.mjs +67 -4
  75. package/dist/transform/templates.cjs +198 -48
  76. package/dist/transform/templates.d.ts.map +1 -1
  77. package/dist/transform/templates.js +5 -3
  78. package/dist/transform/templates.mjs +198 -48
  79. package/dist/{transform-D536WXGM.mjs → transform-QWWQDCXE.mjs} +33 -8
  80. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  81. package/package.json +9 -3
@@ -98,6 +98,7 @@ var INTRINSICS = {
98
98
  $effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
99
99
  $store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
100
100
  $resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
101
+ $cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
101
102
  // No short runtime form for these yet, so the intrinsic stands for the `create*`
102
103
  // name. Still worth having: no import to write, and when a shorter form is
103
104
  // designed, the change is this line rather than a compiler pass.
@@ -107,7 +108,22 @@ var INTRINSICS = {
107
108
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
108
109
  // dependency analysis must not guess at.
109
110
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
110
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
111
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
112
+ // Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
113
+ // no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
114
+ $batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
115
+ $cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
116
+ $root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
117
+ $context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
118
+ $renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
119
+ $computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
120
+ // Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
121
+ // handle as far as reads go: the same accessor with `set` on it.
122
+ $storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
123
+ $asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
124
+ $persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
125
+ // An environment variable, public or server-only; the browser build refuses a secret.
126
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
111
127
  };
112
128
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
113
129
 
@@ -149,7 +165,8 @@ function componentGlobals(rules, options = {}) {
149
165
  builtins = true,
150
166
  intrinsics = true,
151
167
  generator = "@fluixi/compiler",
152
- specifier = (module) => module
168
+ specifier = (module) => module,
169
+ candidates = []
153
170
  } = options;
154
171
  const all = [...rules];
155
172
  if (builtins) {
@@ -161,7 +178,8 @@ function componentGlobals(rules, options = {}) {
161
178
  const shadowedByDom = [];
162
179
  const unavailable = [];
163
180
  const resolved = /* @__PURE__ */ new Map();
164
- for (const name of [...resolver.names()].sort()) {
181
+ const names = /* @__PURE__ */ new Set([...resolver.names(), ...[...candidates].filter((n) => /^[A-Za-z_$][\w$]*$/.test(n))]);
182
+ for (const name of [...names].sort()) {
165
183
  const target = resolver.resolve(name);
166
184
  if (!target) continue;
167
185
  const pkg = packageOf(target.module);
@@ -172,7 +190,11 @@ function componentGlobals(rules, options = {}) {
172
190
  resolved.set(name, target);
173
191
  }
174
192
  }
175
- const intrinsicModules = intrinsics ? [...new Set(Object.values(INTRINSICS).map((i) => i.module))] : [];
193
+ const usableIntrinsics = intrinsics ? Object.entries(INTRINSICS).filter(([, i]) => {
194
+ const pkg = packageOf(i.module);
195
+ return !available || !pkg || available.has(pkg);
196
+ }) : [];
197
+ const intrinsicModules = [...new Set(usableIntrinsics.map(([, i]) => i.module))];
176
198
  const modules = [
177
199
  .../* @__PURE__ */ new Set([...declared.map((name) => resolved.get(name).module), ...intrinsicModules])
178
200
  ].sort();
@@ -192,15 +214,18 @@ function componentGlobals(rules, options = {}) {
192
214
  return `// import { ${n} } from '${module ? specifier(module) : ""}';
193
215
  `;
194
216
  }).join("") : "";
195
- const intrinsicLines = intrinsics ? Object.entries(INTRINSICS).map(
217
+ const intrinsicLines = usableIntrinsics.map(
196
218
  ([name, intrinsic]) => ` const ${name}: typeof ${namespaceAlias(intrinsic.module)}.${intrinsic.export};`
197
- ) : [];
219
+ );
198
220
  const patternRules = rules.filter((rule) => "match" in rule).length;
199
- const patternNote = patternRules > 0 ? `//
221
+ const patternNote = patternRules === 0 ? "" : options.candidates ? `//
222
+ // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"}: declared for the files the module path
223
+ // points at. A name with no such file still resolves at build time; declare it by hand.
224
+ ` : `//
200
225
  // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"} cannot be declared:
201
226
  // a pattern matches unboundedly many names, so there is no list to emit. Those
202
227
  // tags still resolve at build time; declare them by hand if the editor needs them.
203
- ` : "";
228
+ `;
204
229
  const source = `// GENERATED by ${generator}, do not edit.
205
230
  //
206
231
  // The components \`resolve\` supplies without an import. This describes what the
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var write_globals_exports = {};
22
22
  __export(write_globals_exports, {
23
23
  DEFAULT_GLOBALS_PATH: () => DEFAULT_GLOBALS_PATH,
24
+ patternCandidates: () => patternCandidates,
24
25
  writeComponentGlobals: () => writeComponentGlobals
25
26
  });
26
27
  module.exports = __toCommonJS(write_globals_exports);
@@ -127,6 +128,7 @@ var INTRINSICS = {
127
128
  $effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
128
129
  $store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
129
130
  $resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
131
+ $cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
130
132
  // No short runtime form for these yet, so the intrinsic stands for the `create*`
131
133
  // name. Still worth having: no import to write, and when a shorter form is
132
134
  // designed, the change is this line rather than a compiler pass.
@@ -136,7 +138,22 @@ var INTRINSICS = {
136
138
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
137
139
  // dependency analysis must not guess at.
138
140
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
139
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
141
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
142
+ // Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
143
+ // no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
144
+ $batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
145
+ $cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
146
+ $root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
147
+ $context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
148
+ $renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
149
+ $computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
150
+ // Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
151
+ // handle as far as reads go: the same accessor with `set` on it.
152
+ $storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
153
+ $asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
154
+ $persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
155
+ // An environment variable, public or server-only; the browser build refuses a secret.
156
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
140
157
  };
141
158
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
142
159
 
@@ -178,7 +195,8 @@ function componentGlobals(rules, options = {}) {
178
195
  builtins = true,
179
196
  intrinsics = true,
180
197
  generator = "@fluixi/compiler",
181
- specifier = (module2) => module2
198
+ specifier = (module2) => module2,
199
+ candidates = []
182
200
  } = options;
183
201
  const all = [...rules];
184
202
  if (builtins) {
@@ -190,7 +208,8 @@ function componentGlobals(rules, options = {}) {
190
208
  const shadowedByDom = [];
191
209
  const unavailable = [];
192
210
  const resolved = /* @__PURE__ */ new Map();
193
- for (const name of [...resolver.names()].sort()) {
211
+ const names = /* @__PURE__ */ new Set([...resolver.names(), ...[...candidates].filter((n) => /^[A-Za-z_$][\w$]*$/.test(n))]);
212
+ for (const name of [...names].sort()) {
194
213
  const target = resolver.resolve(name);
195
214
  if (!target) continue;
196
215
  const pkg = packageOf(target.module);
@@ -201,7 +220,11 @@ function componentGlobals(rules, options = {}) {
201
220
  resolved.set(name, target);
202
221
  }
203
222
  }
204
- const intrinsicModules = intrinsics ? [...new Set(Object.values(INTRINSICS).map((i) => i.module))] : [];
223
+ const usableIntrinsics = intrinsics ? Object.entries(INTRINSICS).filter(([, i]) => {
224
+ const pkg = packageOf(i.module);
225
+ return !available || !pkg || available.has(pkg);
226
+ }) : [];
227
+ const intrinsicModules = [...new Set(usableIntrinsics.map(([, i]) => i.module))];
205
228
  const modules = [
206
229
  .../* @__PURE__ */ new Set([...declared.map((name) => resolved.get(name).module), ...intrinsicModules])
207
230
  ].sort();
@@ -221,15 +244,18 @@ function componentGlobals(rules, options = {}) {
221
244
  return `// import { ${n} } from '${module2 ? specifier(module2) : ""}';
222
245
  `;
223
246
  }).join("") : "";
224
- const intrinsicLines = intrinsics ? Object.entries(INTRINSICS).map(
247
+ const intrinsicLines = usableIntrinsics.map(
225
248
  ([name, intrinsic]) => ` const ${name}: typeof ${namespaceAlias(intrinsic.module)}.${intrinsic.export};`
226
- ) : [];
249
+ );
227
250
  const patternRules = rules.filter((rule) => "match" in rule).length;
228
- const patternNote = patternRules > 0 ? `//
251
+ const patternNote = patternRules === 0 ? "" : options.candidates ? `//
252
+ // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"}: declared for the files the module path
253
+ // points at. A name with no such file still resolves at build time; declare it by hand.
254
+ ` : `//
229
255
  // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"} cannot be declared:
230
256
  // a pattern matches unboundedly many names, so there is no list to emit. Those
231
257
  // tags still resolve at build time; declare them by hand if the editor needs them.
232
- ` : "";
258
+ `;
233
259
  const source = `// GENERATED by ${generator}, do not edit.
234
260
  //
235
261
  // The components \`resolve\` supplies without an import. This describes what the
@@ -286,6 +312,30 @@ function projectDependencies(root) {
286
312
  return void 0;
287
313
  }
288
314
  }
315
+ function patternCandidates(rules, root) {
316
+ const out = [];
317
+ for (const rule of rules) {
318
+ if (!("match" in rule) || !rule.module.startsWith("/")) continue;
319
+ const dir = (0, import_node_path.dirname)(rule.module);
320
+ const file = (0, import_node_path.basename)(rule.module);
321
+ const group = file.match(/\$\d+/);
322
+ if (dir.includes("$") || !group || file.indexOf("$", group.index + 1) !== -1) continue;
323
+ const before = file.slice(0, group.index);
324
+ const after = file.slice(group.index + group[0].length);
325
+ let entries;
326
+ try {
327
+ entries = (0, import_node_fs.readdirSync)((0, import_node_path.resolve)(root, dir.slice(1)));
328
+ } catch {
329
+ continue;
330
+ }
331
+ for (const entry of entries) {
332
+ if (entry.length > before.length + after.length && entry.startsWith(before) && entry.endsWith(after)) {
333
+ out.push(entry.slice(before.length, entry.length - after.length));
334
+ }
335
+ }
336
+ }
337
+ return out;
338
+ }
289
339
  function writeComponentGlobals(options, root) {
290
340
  if (options.globals === false) return { status: "skipped", reason: "disabled" };
291
341
  const rules = options.resolve ?? [];
@@ -301,6 +351,7 @@ function writeComponentGlobals(options, root) {
301
351
  }
302
352
  const { source, declared } = componentGlobals(rules, {
303
353
  available: projectDependencies(root),
354
+ candidates: patternCandidates(rules, root),
304
355
  specifier: (module2) => forTypeScript(module2, (0, import_node_path.dirname)(target), root)
305
356
  });
306
357
  if (existing === source) {
@@ -26,5 +26,11 @@ export type WriteGlobalsOutcome = ({
26
26
  */
27
27
  warning?: string;
28
28
  };
29
+ /**
30
+ * Names from the files a pattern rule points at: `/src/components/$1.tsx` lists
31
+ * `src/components` and offers each `X` for `X.tsx`. Only a project path with the group in
32
+ * the file name; the resolver still decides whether a name matches.
33
+ */
34
+ export declare function patternCandidates(rules: readonly ComponentResolverRule[], root: string): string[];
29
35
  /** Generate and write the declarations for `root`, returning what was done. */
30
36
  export declare function writeComponentGlobals(options: WriteGlobalsOptions, root: string): WriteGlobalsOutcome;
@@ -26,6 +26,12 @@ export type WriteGlobalsOutcome = ({
26
26
  */
27
27
  warning?: string;
28
28
  };
29
+ /**
30
+ * Names from the files a pattern rule points at: `/src/components/$1.tsx` lists
31
+ * `src/components` and offers each `X` for `X.tsx`. Only a project path with the group in
32
+ * the file name; the resolver still decides whether a name matches.
33
+ */
34
+ export declare function patternCandidates(rules: readonly ComponentResolverRule[], root: string): string[];
29
35
  /** Generate and write the declarations for `root`, returning what was done. */
30
36
  export declare function writeComponentGlobals(options: WriteGlobalsOptions, root: string): WriteGlobalsOutcome;
31
37
  //# sourceMappingURL=write-globals.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"write-globals.d.ts","sourceRoot":"","sources":["../../src/resolve/write-globals.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAKrE,eAAO,MAAM,oBAAoB,gBAAgB,CAAC;AAElD,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC3C,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC1B;AAED,MAAM,MAAM,mBAAmB,GAAG,CAC9B;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,UAAU,GAAG,cAAc,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAC5E,GAAG;IACF;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AA2EF,+EAA+E;AAC/E,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,mBAAmB,EAC5B,IAAI,EAAE,MAAM,GACX,mBAAmB,CAwCrB"}
1
+ {"version":3,"file":"write-globals.d.ts","sourceRoot":"","sources":["../../src/resolve/write-globals.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAKrE,eAAO,MAAM,oBAAoB,gBAAgB,CAAC;AAElD,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC3C,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC1B;AAED,MAAM,MAAM,mBAAmB,GAAG,CAC9B;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,UAAU,GAAG,cAAc,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAC5E,GAAG;IACF;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AA2EF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,qBAAqB,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAuBjG;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,mBAAmB,EAC5B,IAAI,EAAE,MAAM,GACX,mBAAmB,CAyCrB"}
@@ -12,8 +12,8 @@
12
12
  * - **Only declare what the project can resolve.** Dependencies come from its manifest,
13
13
  * so a component from an uninstalled package is skipped rather than degraded to `any`.
14
14
  */
15
- import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
16
- import { dirname, relative, sep, resolve as resolvePath } from 'node:path';
15
+ import { mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
16
+ import { basename, dirname, relative, sep, resolve as resolvePath } from 'node:path';
17
17
  import { componentGlobals } from './component-globals.js';
18
18
  /** The marker every generated file carries, used to tell ours from a hand-written one. */
19
19
  const GENERATED_MARKER = 'GENERATED by @fluixi/compiler';
@@ -88,6 +88,38 @@ function projectDependencies(root) {
88
88
  return undefined;
89
89
  }
90
90
  }
91
+ /**
92
+ * Names from the files a pattern rule points at: `/src/components/$1.tsx` lists
93
+ * `src/components` and offers each `X` for `X.tsx`. Only a project path with the group in
94
+ * the file name; the resolver still decides whether a name matches.
95
+ */
96
+ export function patternCandidates(rules, root) {
97
+ const out = [];
98
+ for (const rule of rules) {
99
+ if (!('match' in rule) || !rule.module.startsWith('/'))
100
+ continue;
101
+ const dir = dirname(rule.module);
102
+ const file = basename(rule.module);
103
+ const group = file.match(/\$\d+/);
104
+ if (dir.includes('$') || !group || file.indexOf('$', group.index + 1) !== -1)
105
+ continue;
106
+ const before = file.slice(0, group.index);
107
+ const after = file.slice(group.index + group[0].length);
108
+ let entries;
109
+ try {
110
+ entries = readdirSync(resolvePath(root, dir.slice(1)));
111
+ }
112
+ catch {
113
+ continue;
114
+ }
115
+ for (const entry of entries) {
116
+ if (entry.length > before.length + after.length && entry.startsWith(before) && entry.endsWith(after)) {
117
+ out.push(entry.slice(before.length, entry.length - after.length));
118
+ }
119
+ }
120
+ }
121
+ return out;
122
+ }
91
123
  /** Generate and write the declarations for `root`, returning what was done. */
92
124
  export function writeComponentGlobals(options, root) {
93
125
  if (options.globals === false)
@@ -106,6 +138,7 @@ export function writeComponentGlobals(options, root) {
106
138
  }
107
139
  const { source, declared } = componentGlobals(rules, {
108
140
  available: projectDependencies(root),
141
+ candidates: patternCandidates(rules, root),
109
142
  specifier: (module) => forTypeScript(module, dirname(target), root),
110
143
  });
111
144
  if (existing === source) {
@@ -1,6 +1,6 @@
1
1
  // src/resolve/write-globals.ts
2
- import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
- import { dirname, relative, sep, resolve as resolvePath } from "node:path";
2
+ import { mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { basename, dirname, relative, sep, resolve as resolvePath } from "node:path";
4
4
 
5
5
  // src/resolve/component-resolver.ts
6
6
  var isMapRule = (rule) => "components" in rule;
@@ -102,6 +102,7 @@ var INTRINSICS = {
102
102
  $effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
103
103
  $store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
104
104
  $resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
105
+ $cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
105
106
  // No short runtime form for these yet, so the intrinsic stands for the `create*`
106
107
  // name. Still worth having: no import to write, and when a shorter form is
107
108
  // designed, the change is this line rather than a compiler pass.
@@ -111,7 +112,22 @@ var INTRINSICS = {
111
112
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
112
113
  // dependency analysis must not guess at.
113
114
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
114
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
115
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
116
+ // Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
117
+ // no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
118
+ $batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
119
+ $cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
120
+ $root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
121
+ $context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
122
+ $renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
123
+ $computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
124
+ // Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
125
+ // handle as far as reads go: the same accessor with `set` on it.
126
+ $storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
127
+ $asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
128
+ $persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
129
+ // An environment variable, public or server-only; the browser build refuses a secret.
130
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
115
131
  };
116
132
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
117
133
 
@@ -153,7 +169,8 @@ function componentGlobals(rules, options = {}) {
153
169
  builtins = true,
154
170
  intrinsics = true,
155
171
  generator = "@fluixi/compiler",
156
- specifier = (module) => module
172
+ specifier = (module) => module,
173
+ candidates = []
157
174
  } = options;
158
175
  const all = [...rules];
159
176
  if (builtins) {
@@ -165,7 +182,8 @@ function componentGlobals(rules, options = {}) {
165
182
  const shadowedByDom = [];
166
183
  const unavailable = [];
167
184
  const resolved = /* @__PURE__ */ new Map();
168
- for (const name of [...resolver.names()].sort()) {
185
+ const names = /* @__PURE__ */ new Set([...resolver.names(), ...[...candidates].filter((n) => /^[A-Za-z_$][\w$]*$/.test(n))]);
186
+ for (const name of [...names].sort()) {
169
187
  const target = resolver.resolve(name);
170
188
  if (!target) continue;
171
189
  const pkg = packageOf(target.module);
@@ -176,7 +194,11 @@ function componentGlobals(rules, options = {}) {
176
194
  resolved.set(name, target);
177
195
  }
178
196
  }
179
- const intrinsicModules = intrinsics ? [...new Set(Object.values(INTRINSICS).map((i) => i.module))] : [];
197
+ const usableIntrinsics = intrinsics ? Object.entries(INTRINSICS).filter(([, i]) => {
198
+ const pkg = packageOf(i.module);
199
+ return !available || !pkg || available.has(pkg);
200
+ }) : [];
201
+ const intrinsicModules = [...new Set(usableIntrinsics.map(([, i]) => i.module))];
180
202
  const modules = [
181
203
  .../* @__PURE__ */ new Set([...declared.map((name) => resolved.get(name).module), ...intrinsicModules])
182
204
  ].sort();
@@ -196,15 +218,18 @@ function componentGlobals(rules, options = {}) {
196
218
  return `// import { ${n} } from '${module ? specifier(module) : ""}';
197
219
  `;
198
220
  }).join("") : "";
199
- const intrinsicLines = intrinsics ? Object.entries(INTRINSICS).map(
221
+ const intrinsicLines = usableIntrinsics.map(
200
222
  ([name, intrinsic]) => ` const ${name}: typeof ${namespaceAlias(intrinsic.module)}.${intrinsic.export};`
201
- ) : [];
223
+ );
202
224
  const patternRules = rules.filter((rule) => "match" in rule).length;
203
- const patternNote = patternRules > 0 ? `//
225
+ const patternNote = patternRules === 0 ? "" : options.candidates ? `//
226
+ // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"}: declared for the files the module path
227
+ // points at. A name with no such file still resolves at build time; declare it by hand.
228
+ ` : `//
204
229
  // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"} cannot be declared:
205
230
  // a pattern matches unboundedly many names, so there is no list to emit. Those
206
231
  // tags still resolve at build time; declare them by hand if the editor needs them.
207
- ` : "";
232
+ `;
208
233
  const source = `// GENERATED by ${generator}, do not edit.
209
234
  //
210
235
  // The components \`resolve\` supplies without an import. This describes what the
@@ -261,6 +286,30 @@ function projectDependencies(root) {
261
286
  return void 0;
262
287
  }
263
288
  }
289
+ function patternCandidates(rules, root) {
290
+ const out = [];
291
+ for (const rule of rules) {
292
+ if (!("match" in rule) || !rule.module.startsWith("/")) continue;
293
+ const dir = dirname(rule.module);
294
+ const file = basename(rule.module);
295
+ const group = file.match(/\$\d+/);
296
+ if (dir.includes("$") || !group || file.indexOf("$", group.index + 1) !== -1) continue;
297
+ const before = file.slice(0, group.index);
298
+ const after = file.slice(group.index + group[0].length);
299
+ let entries;
300
+ try {
301
+ entries = readdirSync(resolvePath(root, dir.slice(1)));
302
+ } catch {
303
+ continue;
304
+ }
305
+ for (const entry of entries) {
306
+ if (entry.length > before.length + after.length && entry.startsWith(before) && entry.endsWith(after)) {
307
+ out.push(entry.slice(before.length, entry.length - after.length));
308
+ }
309
+ }
310
+ }
311
+ return out;
312
+ }
264
313
  function writeComponentGlobals(options, root) {
265
314
  if (options.globals === false) return { status: "skipped", reason: "disabled" };
266
315
  const rules = options.resolve ?? [];
@@ -276,6 +325,7 @@ function writeComponentGlobals(options, root) {
276
325
  }
277
326
  const { source, declared } = componentGlobals(rules, {
278
327
  available: projectDependencies(root),
328
+ candidates: patternCandidates(rules, root),
279
329
  specifier: (module) => forTypeScript(module, dirname(target), root)
280
330
  });
281
331
  if (existing === source) {
@@ -302,5 +352,6 @@ function warnIfUnreachable(root, target) {
302
352
  }
303
353
  export {
304
354
  DEFAULT_GLOBALS_PATH,
355
+ patternCandidates,
305
356
  writeComponentGlobals
306
357
  };
@@ -1,11 +1,11 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.91 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.93 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  import {
3
3
  MagicString
4
- } from "./chunk-TWDJUXWZ.mjs";
4
+ } from "./chunk-R7PPFBCL.mjs";
5
5
  import {
6
6
  serverFnId
7
- } from "./chunk-D53J7ICY.mjs";
8
- import "./chunk-QX6Y3OAR.mjs";
7
+ } from "./chunk-56QSOVVL.mjs";
8
+ import "./chunk-TJIH7TLX.mjs";
9
9
 
10
10
  // src/transform/server-fns.ts
11
11
  import { parse } from "@babel/parser";
@@ -1,8 +1,8 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.91 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.93 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  import {
3
3
  serverFnId
4
- } from "./chunk-D53J7ICY.mjs";
5
- import "./chunk-QX6Y3OAR.mjs";
4
+ } from "./chunk-56QSOVVL.mjs";
5
+ import "./chunk-TJIH7TLX.mjs";
6
6
 
7
7
  // src/frontend/babel/server-functions.ts
8
8
  import { transformSync } from "@babel/core";