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

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 (67) hide show
  1. package/dist/analyze/intrinsics.cjs +3 -1
  2. package/dist/analyze/intrinsics.d.ts.map +1 -1
  3. package/dist/analyze/intrinsics.js +2 -0
  4. package/dist/analyze/intrinsics.mjs +3 -1
  5. package/dist/analyze/reactive-bindings.cjs +3 -1
  6. package/dist/analyze/reactive-bindings.mjs +3 -1
  7. package/dist/analyze/static-graph.cjs +4 -2
  8. package/dist/analyze/static-graph.mjs +4 -2
  9. package/dist/{babel-VBLQRHQ2.mjs → babel-GI375YZ2.mjs} +4 -4
  10. package/dist/{chunk-TWDJUXWZ.mjs → chunk-DWNWN5RH.mjs} +1 -1
  11. package/dist/{chunk-D53J7ICY.mjs → chunk-QZ4CJPYP.mjs} +1 -1
  12. package/dist/{chunk-3JWMCK4A.mjs → chunk-VC6X44FS.mjs} +2 -2
  13. package/dist/{chunk-QX6Y3OAR.mjs → chunk-VOUI6XPV.mjs} +1 -1
  14. package/dist/{chunk-S4J4OCWK.mjs → chunk-XJ5H2MXY.mjs} +4 -2
  15. package/dist/codegen/backends/imperative.cjs +3 -1
  16. package/dist/codegen/backends/imperative.mjs +3 -1
  17. package/dist/frontend/babel/build-ir-lit.cjs +3 -1
  18. package/dist/frontend/babel/build-ir-lit.mjs +3 -1
  19. package/dist/frontend/babel/build-ir.cjs +3 -1
  20. package/dist/frontend/babel/build-ir.mjs +3 -1
  21. package/dist/frontend/babel/index.cjs +4 -2
  22. package/dist/frontend/babel/index.mjs +4 -2
  23. package/dist/frontend/babel/lower-template.cjs +3 -1
  24. package/dist/frontend/babel/lower-template.mjs +3 -1
  25. package/dist/frontend/babel/plugin.cjs +3 -1
  26. package/dist/frontend/babel/plugin.mjs +3 -1
  27. package/dist/index.cjs +46 -9
  28. package/dist/index.mjs +48 -11
  29. package/dist/integrations.cjs +71 -10
  30. package/dist/integrations.mjs +53 -19
  31. package/dist/lower/compile-template.cjs +4 -2
  32. package/dist/lower/compile-template.mjs +4 -2
  33. package/dist/lower/template.cjs +3 -1
  34. package/dist/lower/template.mjs +3 -1
  35. package/dist/resolve/builtins.cjs +1 -1
  36. package/dist/resolve/builtins.mjs +1 -1
  37. package/dist/resolve/component-globals.cjs +19 -8
  38. package/dist/resolve/component-globals.d.cts +8 -0
  39. package/dist/resolve/component-globals.d.ts +8 -0
  40. package/dist/resolve/component-globals.d.ts.map +1 -1
  41. package/dist/resolve/component-globals.js +21 -12
  42. package/dist/resolve/component-globals.mjs +19 -8
  43. package/dist/resolve/write-globals.cjs +45 -8
  44. package/dist/resolve/write-globals.d.cts +6 -0
  45. package/dist/resolve/write-globals.d.ts +6 -0
  46. package/dist/resolve/write-globals.d.ts.map +1 -1
  47. package/dist/resolve/write-globals.js +35 -2
  48. package/dist/resolve/write-globals.mjs +47 -10
  49. package/dist/{server-fns-J56G3PFP.mjs → server-fns-BBZRZUPP.mjs} +4 -4
  50. package/dist/{server-functions-7PUFLRGF.mjs → server-functions-VEGLIFCE.mjs} +3 -3
  51. package/dist/transform/index.cjs +30 -3
  52. package/dist/transform/index.mjs +30 -3
  53. package/dist/transform/intrinsics.cjs +29 -2
  54. package/dist/transform/intrinsics.d.cts +12 -0
  55. package/dist/transform/intrinsics.d.ts +12 -0
  56. package/dist/transform/intrinsics.d.ts.map +1 -1
  57. package/dist/transform/intrinsics.js +43 -1
  58. package/dist/transform/intrinsics.mjs +29 -2
  59. package/dist/transform/source-locations.cjs +3 -1
  60. package/dist/transform/source-locations.mjs +3 -1
  61. package/dist/transform/templates.cjs +29 -2
  62. package/dist/transform/templates.d.ts.map +1 -1
  63. package/dist/transform/templates.js +3 -1
  64. package/dist/transform/templates.mjs +29 -2
  65. package/dist/{transform-D536WXGM.mjs → transform-UWZ7ZGJ2.mjs} +31 -6
  66. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  67. package/package.json +3 -3
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.91 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.92 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
@@ -165,7 +165,9 @@ var init_intrinsics = __esm({
165
165
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
166
166
  // dependency analysis must not guess at.
167
167
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
168
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
168
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
169
+ // An environment variable, public or server-only; the browser build refuses a secret.
170
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
169
171
  };
170
172
  RUNTIME_PRIMITIVES = {
171
173
  signal: "signal-handle",
@@ -3171,10 +3173,34 @@ function collectIntrinsicEdits(program) {
3171
3173
  });
3172
3174
  return { edits, diagnostics, imports };
3173
3175
  }
3176
+ function avoidBindingClashes(program, result, bound) {
3177
+ const importedAsIs = /* @__PURE__ */ new Set();
3178
+ for (const stmt of program.body ?? []) {
3179
+ if (stmt.type !== "ImportDeclaration") continue;
3180
+ const module2 = stmt.source.value;
3181
+ for (const spec of stmt.specifiers ?? []) {
3182
+ if (spec.type !== "ImportSpecifier") continue;
3183
+ const imported = spec.imported.name ?? spec.imported.value;
3184
+ if (imported === spec.local.name && result.imports.get(module2)?.has(imported)) {
3185
+ importedAsIs.add(imported);
3186
+ }
3187
+ }
3188
+ }
3189
+ const aliases = /* @__PURE__ */ new Map();
3190
+ for (const names of result.imports.values()) {
3191
+ for (const name of names) if (bound.has(name) && !importedAsIs.has(name)) aliases.set(name, `__fx_${name}`);
3192
+ }
3193
+ if (!aliases.size) return;
3194
+ for (const edit of result.edits) {
3195
+ const alias = aliases.get(edit.code);
3196
+ if (alias) edit.code = alias;
3197
+ }
3198
+ result.aliases = aliases;
3199
+ }
3174
3200
  function intrinsicImports(result, bound) {
3175
3201
  const lines = [];
3176
3202
  for (const [module2, names] of [...result.imports].sort(([a], [b]) => a.localeCompare(b))) {
3177
- const wanted = [...names].filter((name) => !bound.has(name)).sort();
3203
+ const wanted = [...names].filter((name) => result.aliases?.has(name) || !bound.has(name)).sort().map((name) => result.aliases?.has(name) ? `${name} as ${result.aliases.get(name)}` : name);
3178
3204
  if (wanted.length) lines.push(`import { ${wanted.join(", ")} } from ${JSON.stringify(module2)};`);
3179
3205
  }
3180
3206
  return lines.length ? `${lines.join("\n")}
@@ -3367,6 +3393,7 @@ function transformTemplates(code, id, options = {}) {
3367
3393
  });
3368
3394
  const props = options.propsDestructure === false ? { edits: [], diagnostics: [], used: /* @__PURE__ */ new Set() } : collectPropsEdits(ast.program, code, { runtimeModule: options.runtimeModule });
3369
3395
  const intrinsics = options.intrinsics === false ? { edits: [], diagnostics: [], imports: /* @__PURE__ */ new Map() } : collectIntrinsicEdits(ast.program);
3396
+ if (intrinsics.edits.length) avoidBindingClashes(ast.program, intrinsics, moduleBindings(ast.program));
3370
3397
  const sources = options.sourceLocations === true ? collectSourceEdits(ast.program, sourceName) : { edits: [], marked: 0 };
3371
3398
  const silent = found.length === 0 && props.edits.length === 0 && sources.edits.length === 0 && intrinsics.edits.length === 0 && intrinsics.diagnostics.length === 0 && props.diagnostics.length === 0;
3372
3399
  if (silent) return null;
@@ -3839,7 +3866,8 @@ function componentGlobals(rules, options = {}) {
3839
3866
  builtins = true,
3840
3867
  intrinsics = true,
3841
3868
  generator = "@fluixi/compiler",
3842
- specifier = (module2) => module2
3869
+ specifier = (module2) => module2,
3870
+ candidates = []
3843
3871
  } = options;
3844
3872
  const all = [...rules];
3845
3873
  if (builtins) {
@@ -3851,7 +3879,8 @@ function componentGlobals(rules, options = {}) {
3851
3879
  const shadowedByDom = [];
3852
3880
  const unavailable = [];
3853
3881
  const resolved = /* @__PURE__ */ new Map();
3854
- for (const name of [...resolver.names()].sort()) {
3882
+ const names = /* @__PURE__ */ new Set([...resolver.names(), ...[...candidates].filter((n) => /^[A-Za-z_$][\w$]*$/.test(n))]);
3883
+ for (const name of [...names].sort()) {
3855
3884
  const target = resolver.resolve(name);
3856
3885
  if (!target) continue;
3857
3886
  const pkg = packageOf(target.module);
@@ -3862,7 +3891,11 @@ function componentGlobals(rules, options = {}) {
3862
3891
  resolved.set(name, target);
3863
3892
  }
3864
3893
  }
3865
- const intrinsicModules = intrinsics ? [...new Set(Object.values(INTRINSICS).map((i) => i.module))] : [];
3894
+ const usableIntrinsics = intrinsics ? Object.entries(INTRINSICS).filter(([, i]) => {
3895
+ const pkg = packageOf(i.module);
3896
+ return !available || !pkg || available.has(pkg);
3897
+ }) : [];
3898
+ const intrinsicModules = [...new Set(usableIntrinsics.map(([, i]) => i.module))];
3866
3899
  const modules = [
3867
3900
  .../* @__PURE__ */ new Set([...declared2.map((name) => resolved.get(name).module), ...intrinsicModules])
3868
3901
  ].sort();
@@ -3882,15 +3915,18 @@ function componentGlobals(rules, options = {}) {
3882
3915
  return `// import { ${n} } from '${module2 ? specifier(module2) : ""}';
3883
3916
  `;
3884
3917
  }).join("") : "";
3885
- const intrinsicLines = intrinsics ? Object.entries(INTRINSICS).map(
3918
+ const intrinsicLines = usableIntrinsics.map(
3886
3919
  ([name, intrinsic]) => ` const ${name}: typeof ${namespaceAlias(intrinsic.module)}.${intrinsic.export};`
3887
- ) : [];
3920
+ );
3888
3921
  const patternRules = rules.filter((rule) => "match" in rule).length;
3889
- const patternNote = patternRules > 0 ? `//
3922
+ const patternNote = patternRules === 0 ? "" : options.candidates ? `//
3923
+ // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"}: declared for the files the module path
3924
+ // points at. A name with no such file still resolves at build time; declare it by hand.
3925
+ ` : `//
3890
3926
  // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"} cannot be declared:
3891
3927
  // a pattern matches unboundedly many names, so there is no list to emit. Those
3892
3928
  // tags still resolve at build time; declare them by hand if the editor needs them.
3893
- ` : "";
3929
+ `;
3894
3930
  const source = `// GENERATED by ${generator}, do not edit.
3895
3931
  //
3896
3932
  // The components \`resolve\` supplies without an import. This describes what the
@@ -3947,6 +3983,30 @@ function projectDependencies(root) {
3947
3983
  return void 0;
3948
3984
  }
3949
3985
  }
3986
+ function patternCandidates(rules, root) {
3987
+ const out = [];
3988
+ for (const rule of rules) {
3989
+ if (!("match" in rule) || !rule.module.startsWith("/")) continue;
3990
+ const dir = (0, import_node_path.dirname)(rule.module);
3991
+ const file = (0, import_node_path.basename)(rule.module);
3992
+ const group = file.match(/\$\d+/);
3993
+ if (dir.includes("$") || !group || file.indexOf("$", group.index + 1) !== -1) continue;
3994
+ const before = file.slice(0, group.index);
3995
+ const after = file.slice(group.index + group[0].length);
3996
+ let entries;
3997
+ try {
3998
+ entries = (0, import_node_fs.readdirSync)((0, import_node_path.resolve)(root, dir.slice(1)));
3999
+ } catch {
4000
+ continue;
4001
+ }
4002
+ for (const entry of entries) {
4003
+ if (entry.length > before.length + after.length && entry.startsWith(before) && entry.endsWith(after)) {
4004
+ out.push(entry.slice(before.length, entry.length - after.length));
4005
+ }
4006
+ }
4007
+ }
4008
+ return out;
4009
+ }
3950
4010
  function writeComponentGlobals(options, root) {
3951
4011
  if (options.globals === false) return { status: "skipped", reason: "disabled" };
3952
4012
  const rules = options.resolve ?? [];
@@ -3962,6 +4022,7 @@ function writeComponentGlobals(options, root) {
3962
4022
  }
3963
4023
  const { source, declared: declared2 } = componentGlobals(rules, {
3964
4024
  available: projectDependencies(root),
4025
+ candidates: patternCandidates(rules, root),
3965
4026
  specifier: (module2) => forTypeScript(module2, (0, import_node_path.dirname)(target), root)
3966
4027
  });
3967
4028
  if (existing === source) {
@@ -1,16 +1,16 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.91 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.92 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  import {
3
3
  INTRINSICS,
4
4
  builtinComponentMap,
5
5
  createComponentResolver
6
- } from "./chunk-S4J4OCWK.mjs";
6
+ } from "./chunk-XJ5H2MXY.mjs";
7
7
  import {
8
8
  __require
9
- } from "./chunk-QX6Y3OAR.mjs";
9
+ } from "./chunk-VOUI6XPV.mjs";
10
10
 
11
11
  // src/resolve/write-globals.ts
12
- import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
13
- import { dirname, relative, sep, resolve as resolvePath } from "node:path";
12
+ import { mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
13
+ import { basename, dirname, relative, sep, resolve as resolvePath } from "node:path";
14
14
 
15
15
  // src/resolve/component-globals.ts
16
16
  var DOM_GLOBALS = /* @__PURE__ */ new Set([
@@ -50,7 +50,8 @@ function componentGlobals(rules, options = {}) {
50
50
  builtins = true,
51
51
  intrinsics = true,
52
52
  generator = "@fluixi/compiler",
53
- specifier = (module) => module
53
+ specifier = (module) => module,
54
+ candidates = []
54
55
  } = options;
55
56
  const all = [...rules];
56
57
  if (builtins) {
@@ -62,7 +63,8 @@ function componentGlobals(rules, options = {}) {
62
63
  const shadowedByDom = [];
63
64
  const unavailable = [];
64
65
  const resolved = /* @__PURE__ */ new Map();
65
- for (const name of [...resolver.names()].sort()) {
66
+ const names = /* @__PURE__ */ new Set([...resolver.names(), ...[...candidates].filter((n) => /^[A-Za-z_$][\w$]*$/.test(n))]);
67
+ for (const name of [...names].sort()) {
66
68
  const target = resolver.resolve(name);
67
69
  if (!target) continue;
68
70
  const pkg = packageOf(target.module);
@@ -73,7 +75,11 @@ function componentGlobals(rules, options = {}) {
73
75
  resolved.set(name, target);
74
76
  }
75
77
  }
76
- const intrinsicModules = intrinsics ? [...new Set(Object.values(INTRINSICS).map((i) => i.module))] : [];
78
+ const usableIntrinsics = intrinsics ? Object.entries(INTRINSICS).filter(([, i]) => {
79
+ const pkg = packageOf(i.module);
80
+ return !available || !pkg || available.has(pkg);
81
+ }) : [];
82
+ const intrinsicModules = [...new Set(usableIntrinsics.map(([, i]) => i.module))];
77
83
  const modules = [
78
84
  .../* @__PURE__ */ new Set([...declared.map((name) => resolved.get(name).module), ...intrinsicModules])
79
85
  ].sort();
@@ -93,15 +99,18 @@ function componentGlobals(rules, options = {}) {
93
99
  return `// import { ${n} } from '${module ? specifier(module) : ""}';
94
100
  `;
95
101
  }).join("") : "";
96
- const intrinsicLines = intrinsics ? Object.entries(INTRINSICS).map(
102
+ const intrinsicLines = usableIntrinsics.map(
97
103
  ([name, intrinsic]) => ` const ${name}: typeof ${namespaceAlias(intrinsic.module)}.${intrinsic.export};`
98
- ) : [];
104
+ );
99
105
  const patternRules = rules.filter((rule) => "match" in rule).length;
100
- const patternNote = patternRules > 0 ? `//
106
+ const patternNote = patternRules === 0 ? "" : options.candidates ? `//
107
+ // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"}: declared for the files the module path
108
+ // points at. A name with no such file still resolves at build time; declare it by hand.
109
+ ` : `//
101
110
  // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"} cannot be declared:
102
111
  // a pattern matches unboundedly many names, so there is no list to emit. Those
103
112
  // tags still resolve at build time; declare them by hand if the editor needs them.
104
- ` : "";
113
+ `;
105
114
  const source = `// GENERATED by ${generator}, do not edit.
106
115
  //
107
116
  // The components \`resolve\` supplies without an import. This describes what the
@@ -158,6 +167,30 @@ function projectDependencies(root) {
158
167
  return void 0;
159
168
  }
160
169
  }
170
+ function patternCandidates(rules, root) {
171
+ const out = [];
172
+ for (const rule of rules) {
173
+ if (!("match" in rule) || !rule.module.startsWith("/")) continue;
174
+ const dir = dirname(rule.module);
175
+ const file = basename(rule.module);
176
+ const group = file.match(/\$\d+/);
177
+ if (dir.includes("$") || !group || file.indexOf("$", group.index + 1) !== -1) continue;
178
+ const before = file.slice(0, group.index);
179
+ const after = file.slice(group.index + group[0].length);
180
+ let entries;
181
+ try {
182
+ entries = readdirSync(resolvePath(root, dir.slice(1)));
183
+ } catch {
184
+ continue;
185
+ }
186
+ for (const entry of entries) {
187
+ if (entry.length > before.length + after.length && entry.startsWith(before) && entry.endsWith(after)) {
188
+ out.push(entry.slice(before.length, entry.length - after.length));
189
+ }
190
+ }
191
+ }
192
+ return out;
193
+ }
161
194
  function writeComponentGlobals(options, root) {
162
195
  if (options.globals === false) return { status: "skipped", reason: "disabled" };
163
196
  const rules = options.resolve ?? [];
@@ -173,6 +206,7 @@ function writeComponentGlobals(options, root) {
173
206
  }
174
207
  const { source, declared } = componentGlobals(rules, {
175
208
  available: projectDependencies(root),
209
+ candidates: patternCandidates(rules, root),
176
210
  specifier: (module) => forTypeScript(module, dirname(target), root)
177
211
  });
178
212
  if (existing === source) {
@@ -199,12 +233,12 @@ function warnIfUnreachable(root, target) {
199
233
  }
200
234
 
201
235
  // src/integrations.ts
202
- import { readdirSync, readFileSync as readFileSync2 } from "node:fs";
236
+ import { readdirSync as readdirSync2, readFileSync as readFileSync2 } from "node:fs";
203
237
  import { join as _join } from "node:path";
204
238
  async function createBabelPlugin(options = {}) {
205
239
  let pluginModule = null;
206
240
  try {
207
- pluginModule = await import("./babel-VBLQRHQ2.mjs");
241
+ pluginModule = await import("./babel-GI375YZ2.mjs");
208
242
  } catch (e) {
209
243
  console.warn("Could not load the babel front-end:", e);
210
244
  }
@@ -375,7 +409,7 @@ function transformOptions(options, id) {
375
409
  }
376
410
  async function rewriteProps(code, id, options) {
377
411
  if (options.propsDestructure === false) return code;
378
- const { transformProps } = await import("./transform-D536WXGM.mjs");
412
+ const { transformProps } = await import("./transform-UWZ7ZGJ2.mjs");
379
413
  const result = transformProps(code, id);
380
414
  reportDiagnostics({ propsDiagnostics: result.diagnostics }, id);
381
415
  return result.rewritten > 0 ? result.code : code;
@@ -398,7 +432,7 @@ function reportDiagnostics(result, id) {
398
432
  }
399
433
  async function compileModule(code, id, options) {
400
434
  if (!options.babel) {
401
- const { transformTemplates } = await import("./transform-D536WXGM.mjs");
435
+ const { transformTemplates } = await import("./transform-UWZ7ZGJ2.mjs");
402
436
  const result2 = transformTemplates(code, id, transformOptions(options, id));
403
437
  reportDiagnostics(result2, id);
404
438
  return result2;
@@ -473,7 +507,7 @@ function hasServerDirective(source) {
473
507
  function findServerFnModules(dir, out = []) {
474
508
  let entries;
475
509
  try {
476
- entries = readdirSync(dir, { withFileTypes: true });
510
+ entries = readdirSync2(dir, { withFileTypes: true });
477
511
  } catch {
478
512
  return out;
479
513
  }
@@ -517,10 +551,10 @@ export { isServerFnRequest, handleServerFn } from '@fluixi/start/server-fn';
517
551
  if (!code.includes("use server")) return null;
518
552
  const args = { ssr: !!opts?.ssr, filename: id, root };
519
553
  if (options.babel) {
520
- const { transformServerFunctions } = await import("./server-functions-7PUFLRGF.mjs");
554
+ const { transformServerFunctions } = await import("./server-functions-VEGLIFCE.mjs");
521
555
  return transformServerFunctions(code, args);
522
556
  }
523
- const { transformServerFns } = await import("./server-fns-J56G3PFP.mjs");
557
+ const { transformServerFns } = await import("./server-fns-BBZRZUPP.mjs");
524
558
  return transformServerFns(code, args);
525
559
  }
526
560
  };
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.91 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.92 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -477,7 +477,9 @@ var INTRINSICS = {
477
477
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
478
478
  // dependency analysis must not guess at.
479
479
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
480
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
480
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
481
+ // An environment variable, public or server-only; the browser build refuses a secret.
482
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
481
483
  };
482
484
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
483
485
 
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.91 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.92 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/optimize/analyze-static.ts
4
4
  function propReason(prop) {
@@ -451,7 +451,9 @@ var INTRINSICS = {
451
451
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
452
452
  // dependency analysis must not guess at.
453
453
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
454
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
454
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
455
+ // An environment variable, public or server-only; the browser build refuses a secret.
456
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
455
457
  };
456
458
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
457
459
 
@@ -292,7 +292,9 @@ var INTRINSICS = {
292
292
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
293
293
  // dependency analysis must not guess at.
294
294
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
295
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
295
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
296
+ // An environment variable, public or server-only; the browser build refuses a secret.
297
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
296
298
  };
297
299
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
298
300
 
@@ -270,7 +270,9 @@ var INTRINSICS = {
270
270
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
271
271
  // dependency analysis must not guess at.
272
272
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
273
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
273
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
274
+ // An environment variable, public or server-only; the browser build refuses a secret.
275
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
274
276
  };
275
277
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
276
278
 
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.91 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.92 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.91 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.92 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/resolve/builtins.ts
4
4
  var DOM_CONTROL_FLOW = [
@@ -133,7 +133,9 @@ var INTRINSICS = {
133
133
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
134
134
  // dependency analysis must not guess at.
135
135
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
136
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
136
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
137
+ // An environment variable, public or server-only; the browser build refuses a secret.
138
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
137
139
  };
138
140
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
139
141
 
@@ -175,7 +177,8 @@ function componentGlobals(rules, options = {}) {
175
177
  builtins = true,
176
178
  intrinsics = true,
177
179
  generator = "@fluixi/compiler",
178
- specifier = (module2) => module2
180
+ specifier = (module2) => module2,
181
+ candidates = []
179
182
  } = options;
180
183
  const all = [...rules];
181
184
  if (builtins) {
@@ -187,7 +190,8 @@ function componentGlobals(rules, options = {}) {
187
190
  const shadowedByDom = [];
188
191
  const unavailable = [];
189
192
  const resolved = /* @__PURE__ */ new Map();
190
- for (const name of [...resolver.names()].sort()) {
193
+ const names = /* @__PURE__ */ new Set([...resolver.names(), ...[...candidates].filter((n) => /^[A-Za-z_$][\w$]*$/.test(n))]);
194
+ for (const name of [...names].sort()) {
191
195
  const target = resolver.resolve(name);
192
196
  if (!target) continue;
193
197
  const pkg = packageOf(target.module);
@@ -198,7 +202,11 @@ function componentGlobals(rules, options = {}) {
198
202
  resolved.set(name, target);
199
203
  }
200
204
  }
201
- const intrinsicModules = intrinsics ? [...new Set(Object.values(INTRINSICS).map((i) => i.module))] : [];
205
+ const usableIntrinsics = intrinsics ? Object.entries(INTRINSICS).filter(([, i]) => {
206
+ const pkg = packageOf(i.module);
207
+ return !available || !pkg || available.has(pkg);
208
+ }) : [];
209
+ const intrinsicModules = [...new Set(usableIntrinsics.map(([, i]) => i.module))];
202
210
  const modules = [
203
211
  .../* @__PURE__ */ new Set([...declared.map((name) => resolved.get(name).module), ...intrinsicModules])
204
212
  ].sort();
@@ -218,15 +226,18 @@ function componentGlobals(rules, options = {}) {
218
226
  return `// import { ${n} } from '${module2 ? specifier(module2) : ""}';
219
227
  `;
220
228
  }).join("") : "";
221
- const intrinsicLines = intrinsics ? Object.entries(INTRINSICS).map(
229
+ const intrinsicLines = usableIntrinsics.map(
222
230
  ([name, intrinsic]) => ` const ${name}: typeof ${namespaceAlias(intrinsic.module)}.${intrinsic.export};`
223
- ) : [];
231
+ );
224
232
  const patternRules = rules.filter((rule) => "match" in rule).length;
225
- const patternNote = patternRules > 0 ? `//
233
+ const patternNote = patternRules === 0 ? "" : options.candidates ? `//
234
+ // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"}: declared for the files the module path
235
+ // points at. A name with no such file still resolves at build time; declare it by hand.
236
+ ` : `//
226
237
  // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"} cannot be declared:
227
238
  // a pattern matches unboundedly many names, so there is no list to emit. Those
228
239
  // tags still resolve at build time; declare them by hand if the editor needs them.
229
- ` : "";
240
+ `;
230
241
  const source = `// GENERATED by ${generator}, do not edit.
231
242
  //
232
243
  // The components \`resolve\` supplies without an import. This describes what the
@@ -46,6 +46,14 @@ export interface ComponentGlobalsOptions {
46
46
  * "Cannot find name '$signal'" for code that builds correctly.
47
47
  */
48
48
  intrinsics?: boolean;
49
+ /**
50
+ * Names to try against the pattern rules.
51
+ *
52
+ * A pattern has no name list of its own, but the files it points at do: the caller lists
53
+ * them (the generator stays off the filesystem) and each name the resolver answers is
54
+ * declared like any other.
55
+ */
56
+ candidates?: Iterable<string>;
49
57
  /** Attribution written into the header. */
50
58
  generator?: string;
51
59
  /**
@@ -46,6 +46,14 @@ export interface ComponentGlobalsOptions {
46
46
  * "Cannot find name '$signal'" for code that builds correctly.
47
47
  */
48
48
  intrinsics?: boolean;
49
+ /**
50
+ * Names to try against the pattern rules.
51
+ *
52
+ * A pattern has no name list of its own, but the files it points at do: the caller lists
53
+ * them (the generator stays off the filesystem) and each name the resolver answers is
54
+ * declared like any other.
55
+ */
56
+ candidates?: Iterable<string>;
49
57
  /** Attribution written into the header. */
50
58
  generator?: string;
51
59
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"component-globals.d.ts","sourceRoot":"","sources":["../../src/resolve/component-globals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAEL,KAAK,qBAAqB,EAE3B,MAAM,yBAAyB,CAAC;AAmCjC,MAAM,WAAW,uBAAuB;IACtC;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;CACxC;AAED,MAAM,WAAW,sBAAsB;IACrC,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,qEAAqE;IACrE,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB;;;;;;OAMG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAgBD,0FAA0F;AAC1F,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,qBAAqB,EAAE,EACvC,OAAO,GAAE,uBAA4B,GACpC,sBAAsB,CA2GxB"}
1
+ {"version":3,"file":"component-globals.d.ts","sourceRoot":"","sources":["../../src/resolve/component-globals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAEL,KAAK,qBAAqB,EAE3B,MAAM,yBAAyB,CAAC;AAmCjC,MAAM,WAAW,uBAAuB;IACtC;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;CACxC;AAED,MAAM,WAAW,sBAAsB;IACrC,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,qEAAqE;IACrE,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB;;;;;;OAMG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAgBD,0FAA0F;AAC1F,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,qBAAqB,EAAE,EACvC,OAAO,GAAE,uBAA4B,GACpC,sBAAsB,CAoHxB"}
@@ -65,7 +65,7 @@ function namespaceAlias(module) {
65
65
  }
66
66
  /** Build the ambient `.d.ts` for the components a project's `resolve` config supplies. */
67
67
  export function componentGlobals(rules, options = {}) {
68
- const { available: availableList, builtins = true, intrinsics = true, generator = '@fluixi/compiler', specifier = (module) => module, } = options;
68
+ const { available: availableList, builtins = true, intrinsics = true, generator = '@fluixi/compiler', specifier = (module) => module, candidates = [], } = options;
69
69
  const all = [...rules];
70
70
  if (builtins) {
71
71
  // Appended, so an explicit rule for the same name still wins, the resolver is
@@ -78,9 +78,9 @@ export function componentGlobals(rules, options = {}) {
78
78
  const shadowedByDom = [];
79
79
  const unavailable = [];
80
80
  const resolved = new Map();
81
- for (const name of [...resolver.names()].sort()) {
81
+ const names = new Set([...resolver.names(), ...[...candidates].filter((n) => /^[A-Za-z_$][\w$]*$/.test(n))]);
82
+ for (const name of [...names].sort()) {
82
83
  const target = resolver.resolve(name);
83
- /* c8 ignore next */
84
84
  if (!target)
85
85
  continue;
86
86
  const pkg = packageOf(target.module);
@@ -97,7 +97,15 @@ export function componentGlobals(rules, options = {}) {
97
97
  // '$signal'" for code that compiles. tsc doesn't load language-service plugins, so an
98
98
  // ambient declaration is the only thing that answers for both the editor and the
99
99
  // command line.
100
- const intrinsicModules = intrinsics ? [...new Set(Object.values(INTRINSICS).map((i) => i.module))] : [];
100
+ // Only the intrinsics whose package the project has: `$env` comes from `@fluixi/start`, and
101
+ // an app without it would otherwise get a declaration that fails to resolve.
102
+ const usableIntrinsics = intrinsics
103
+ ? Object.entries(INTRINSICS).filter(([, i]) => {
104
+ const pkg = packageOf(i.module);
105
+ return !available || !pkg || available.has(pkg);
106
+ })
107
+ : [];
108
+ const intrinsicModules = [...new Set(usableIntrinsics.map(([, i]) => i.module))];
101
109
  const modules = [
102
110
  ...new Set([...declared.map((name) => resolved.get(name).module), ...intrinsicModules]),
103
111
  ].sort();
@@ -130,15 +138,16 @@ export function componentGlobals(rules, options = {}) {
130
138
  // `typeof ns.signal` rather than an alias: the intrinsic is a global that stands for
131
139
  // the runtime call, so it takes the runtime's signature without claiming to be that
132
140
  // symbol: go-to-definition on `$signal` should land on what it compiles to.
133
- const intrinsicLines = intrinsics
134
- ? Object.entries(INTRINSICS).map(([name, intrinsic]) => ` const ${name}: typeof ${namespaceAlias(intrinsic.module)}.${intrinsic.export};`)
135
- : [];
141
+ const intrinsicLines = usableIntrinsics.map(([name, intrinsic]) => ` const ${name}: typeof ${namespaceAlias(intrinsic.module)}.${intrinsic.export};`);
136
142
  const patternRules = rules.filter((rule) => 'match' in rule).length;
137
- const patternNote = patternRules > 0
138
- ? `//\n// ${patternRules} pattern rule${patternRules === 1 ? '' : 's'} cannot be declared:\n` +
139
- `// a pattern matches unboundedly many names, so there is no list to emit. Those\n` +
140
- `// tags still resolve at build time; declare them by hand if the editor needs them.\n`
141
- : '';
143
+ const patternNote = patternRules === 0
144
+ ? ''
145
+ : options.candidates
146
+ ? `//\n// ${patternRules} pattern rule${patternRules === 1 ? '' : 's'}: declared for the files the module path\n` +
147
+ `// points at. A name with no such file still resolves at build time; declare it by hand.\n`
148
+ : `//\n// ${patternRules} pattern rule${patternRules === 1 ? '' : 's'} cannot be declared:\n` +
149
+ `// a pattern matches unboundedly many names, so there is no list to emit. Those\n` +
150
+ `// tags still resolve at build time; declare them by hand if the editor needs them.\n`;
142
151
  const source = `// GENERATED by ${generator}, do not edit.\n` +
143
152
  `//\n` +
144
153
  `// The components \`resolve\` supplies without an import. This describes what the\n` +
@@ -107,7 +107,9 @@ var INTRINSICS = {
107
107
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
108
108
  // dependency analysis must not guess at.
109
109
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
110
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
110
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
111
+ // An environment variable, public or server-only; the browser build refuses a secret.
112
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
111
113
  };
112
114
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
113
115
 
@@ -149,7 +151,8 @@ function componentGlobals(rules, options = {}) {
149
151
  builtins = true,
150
152
  intrinsics = true,
151
153
  generator = "@fluixi/compiler",
152
- specifier = (module) => module
154
+ specifier = (module) => module,
155
+ candidates = []
153
156
  } = options;
154
157
  const all = [...rules];
155
158
  if (builtins) {
@@ -161,7 +164,8 @@ function componentGlobals(rules, options = {}) {
161
164
  const shadowedByDom = [];
162
165
  const unavailable = [];
163
166
  const resolved = /* @__PURE__ */ new Map();
164
- for (const name of [...resolver.names()].sort()) {
167
+ const names = /* @__PURE__ */ new Set([...resolver.names(), ...[...candidates].filter((n) => /^[A-Za-z_$][\w$]*$/.test(n))]);
168
+ for (const name of [...names].sort()) {
165
169
  const target = resolver.resolve(name);
166
170
  if (!target) continue;
167
171
  const pkg = packageOf(target.module);
@@ -172,7 +176,11 @@ function componentGlobals(rules, options = {}) {
172
176
  resolved.set(name, target);
173
177
  }
174
178
  }
175
- const intrinsicModules = intrinsics ? [...new Set(Object.values(INTRINSICS).map((i) => i.module))] : [];
179
+ const usableIntrinsics = intrinsics ? Object.entries(INTRINSICS).filter(([, i]) => {
180
+ const pkg = packageOf(i.module);
181
+ return !available || !pkg || available.has(pkg);
182
+ }) : [];
183
+ const intrinsicModules = [...new Set(usableIntrinsics.map(([, i]) => i.module))];
176
184
  const modules = [
177
185
  .../* @__PURE__ */ new Set([...declared.map((name) => resolved.get(name).module), ...intrinsicModules])
178
186
  ].sort();
@@ -192,15 +200,18 @@ function componentGlobals(rules, options = {}) {
192
200
  return `// import { ${n} } from '${module ? specifier(module) : ""}';
193
201
  `;
194
202
  }).join("") : "";
195
- const intrinsicLines = intrinsics ? Object.entries(INTRINSICS).map(
203
+ const intrinsicLines = usableIntrinsics.map(
196
204
  ([name, intrinsic]) => ` const ${name}: typeof ${namespaceAlias(intrinsic.module)}.${intrinsic.export};`
197
- ) : [];
205
+ );
198
206
  const patternRules = rules.filter((rule) => "match" in rule).length;
199
- const patternNote = patternRules > 0 ? `//
207
+ const patternNote = patternRules === 0 ? "" : options.candidates ? `//
208
+ // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"}: declared for the files the module path
209
+ // points at. A name with no such file still resolves at build time; declare it by hand.
210
+ ` : `//
200
211
  // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"} cannot be declared:
201
212
  // a pattern matches unboundedly many names, so there is no list to emit. Those
202
213
  // tags still resolve at build time; declare them by hand if the editor needs them.
203
- ` : "";
214
+ `;
204
215
  const source = `// GENERATED by ${generator}, do not edit.
205
216
  //
206
217
  // The components \`resolve\` supplies without an import. This describes what the