@fluixi/compiler 1.0.0-alpha.90 → 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-DP7TXPOQ.mjs → babel-GI375YZ2.mjs} +4 -4
  10. package/dist/{chunk-RZ3JE33I.mjs → chunk-DWNWN5RH.mjs} +1 -1
  11. package/dist/{chunk-RCOCGLLD.mjs → chunk-QZ4CJPYP.mjs} +1 -1
  12. package/dist/{chunk-USZWARUE.mjs → chunk-VC6X44FS.mjs} +2 -2
  13. package/dist/{chunk-XTMCL6V7.mjs → chunk-VOUI6XPV.mjs} +1 -1
  14. package/dist/{chunk-VR2UFMLQ.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-DHOJLQKS.mjs → server-fns-BBZRZUPP.mjs} +4 -4
  50. package/dist/{server-functions-KSH5BDVT.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-2RU4ODF3.mjs → transform-UWZ7ZGJ2.mjs} +31 -6
  66. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  67. package/package.json +3 -3
@@ -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);
@@ -136,7 +137,9 @@ var INTRINSICS = {
136
137
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
137
138
  // dependency analysis must not guess at.
138
139
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
139
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
140
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
141
+ // An environment variable, public or server-only; the browser build refuses a secret.
142
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
140
143
  };
141
144
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
142
145
 
@@ -178,7 +181,8 @@ function componentGlobals(rules, options = {}) {
178
181
  builtins = true,
179
182
  intrinsics = true,
180
183
  generator = "@fluixi/compiler",
181
- specifier = (module2) => module2
184
+ specifier = (module2) => module2,
185
+ candidates = []
182
186
  } = options;
183
187
  const all = [...rules];
184
188
  if (builtins) {
@@ -190,7 +194,8 @@ function componentGlobals(rules, options = {}) {
190
194
  const shadowedByDom = [];
191
195
  const unavailable = [];
192
196
  const resolved = /* @__PURE__ */ new Map();
193
- for (const name of [...resolver.names()].sort()) {
197
+ const names = /* @__PURE__ */ new Set([...resolver.names(), ...[...candidates].filter((n) => /^[A-Za-z_$][\w$]*$/.test(n))]);
198
+ for (const name of [...names].sort()) {
194
199
  const target = resolver.resolve(name);
195
200
  if (!target) continue;
196
201
  const pkg = packageOf(target.module);
@@ -201,7 +206,11 @@ function componentGlobals(rules, options = {}) {
201
206
  resolved.set(name, target);
202
207
  }
203
208
  }
204
- const intrinsicModules = intrinsics ? [...new Set(Object.values(INTRINSICS).map((i) => i.module))] : [];
209
+ const usableIntrinsics = intrinsics ? Object.entries(INTRINSICS).filter(([, i]) => {
210
+ const pkg = packageOf(i.module);
211
+ return !available || !pkg || available.has(pkg);
212
+ }) : [];
213
+ const intrinsicModules = [...new Set(usableIntrinsics.map(([, i]) => i.module))];
205
214
  const modules = [
206
215
  .../* @__PURE__ */ new Set([...declared.map((name) => resolved.get(name).module), ...intrinsicModules])
207
216
  ].sort();
@@ -221,15 +230,18 @@ function componentGlobals(rules, options = {}) {
221
230
  return `// import { ${n} } from '${module2 ? specifier(module2) : ""}';
222
231
  `;
223
232
  }).join("") : "";
224
- const intrinsicLines = intrinsics ? Object.entries(INTRINSICS).map(
233
+ const intrinsicLines = usableIntrinsics.map(
225
234
  ([name, intrinsic]) => ` const ${name}: typeof ${namespaceAlias(intrinsic.module)}.${intrinsic.export};`
226
- ) : [];
235
+ );
227
236
  const patternRules = rules.filter((rule) => "match" in rule).length;
228
- const patternNote = patternRules > 0 ? `//
237
+ const patternNote = patternRules === 0 ? "" : options.candidates ? `//
238
+ // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"}: declared for the files the module path
239
+ // points at. A name with no such file still resolves at build time; declare it by hand.
240
+ ` : `//
229
241
  // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"} cannot be declared:
230
242
  // a pattern matches unboundedly many names, so there is no list to emit. Those
231
243
  // tags still resolve at build time; declare them by hand if the editor needs them.
232
- ` : "";
244
+ `;
233
245
  const source = `// GENERATED by ${generator}, do not edit.
234
246
  //
235
247
  // The components \`resolve\` supplies without an import. This describes what the
@@ -286,6 +298,30 @@ function projectDependencies(root) {
286
298
  return void 0;
287
299
  }
288
300
  }
301
+ function patternCandidates(rules, root) {
302
+ const out = [];
303
+ for (const rule of rules) {
304
+ if (!("match" in rule) || !rule.module.startsWith("/")) continue;
305
+ const dir = (0, import_node_path.dirname)(rule.module);
306
+ const file = (0, import_node_path.basename)(rule.module);
307
+ const group = file.match(/\$\d+/);
308
+ if (dir.includes("$") || !group || file.indexOf("$", group.index + 1) !== -1) continue;
309
+ const before = file.slice(0, group.index);
310
+ const after = file.slice(group.index + group[0].length);
311
+ let entries;
312
+ try {
313
+ entries = (0, import_node_fs.readdirSync)((0, import_node_path.resolve)(root, dir.slice(1)));
314
+ } catch {
315
+ continue;
316
+ }
317
+ for (const entry of entries) {
318
+ if (entry.length > before.length + after.length && entry.startsWith(before) && entry.endsWith(after)) {
319
+ out.push(entry.slice(before.length, entry.length - after.length));
320
+ }
321
+ }
322
+ }
323
+ return out;
324
+ }
289
325
  function writeComponentGlobals(options, root) {
290
326
  if (options.globals === false) return { status: "skipped", reason: "disabled" };
291
327
  const rules = options.resolve ?? [];
@@ -301,6 +337,7 @@ function writeComponentGlobals(options, root) {
301
337
  }
302
338
  const { source, declared } = componentGlobals(rules, {
303
339
  available: projectDependencies(root),
340
+ candidates: patternCandidates(rules, root),
304
341
  specifier: (module2) => forTypeScript(module2, (0, import_node_path.dirname)(target), root)
305
342
  });
306
343
  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;
@@ -111,7 +111,9 @@ var INTRINSICS = {
111
111
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
112
112
  // dependency analysis must not guess at.
113
113
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
114
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
114
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
115
+ // An environment variable, public or server-only; the browser build refuses a secret.
116
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
115
117
  };
116
118
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
117
119
 
@@ -153,7 +155,8 @@ function componentGlobals(rules, options = {}) {
153
155
  builtins = true,
154
156
  intrinsics = true,
155
157
  generator = "@fluixi/compiler",
156
- specifier = (module) => module
158
+ specifier = (module) => module,
159
+ candidates = []
157
160
  } = options;
158
161
  const all = [...rules];
159
162
  if (builtins) {
@@ -165,7 +168,8 @@ function componentGlobals(rules, options = {}) {
165
168
  const shadowedByDom = [];
166
169
  const unavailable = [];
167
170
  const resolved = /* @__PURE__ */ new Map();
168
- for (const name of [...resolver.names()].sort()) {
171
+ const names = /* @__PURE__ */ new Set([...resolver.names(), ...[...candidates].filter((n) => /^[A-Za-z_$][\w$]*$/.test(n))]);
172
+ for (const name of [...names].sort()) {
169
173
  const target = resolver.resolve(name);
170
174
  if (!target) continue;
171
175
  const pkg = packageOf(target.module);
@@ -176,7 +180,11 @@ function componentGlobals(rules, options = {}) {
176
180
  resolved.set(name, target);
177
181
  }
178
182
  }
179
- const intrinsicModules = intrinsics ? [...new Set(Object.values(INTRINSICS).map((i) => i.module))] : [];
183
+ const usableIntrinsics = intrinsics ? Object.entries(INTRINSICS).filter(([, i]) => {
184
+ const pkg = packageOf(i.module);
185
+ return !available || !pkg || available.has(pkg);
186
+ }) : [];
187
+ const intrinsicModules = [...new Set(usableIntrinsics.map(([, i]) => i.module))];
180
188
  const modules = [
181
189
  .../* @__PURE__ */ new Set([...declared.map((name) => resolved.get(name).module), ...intrinsicModules])
182
190
  ].sort();
@@ -196,15 +204,18 @@ function componentGlobals(rules, options = {}) {
196
204
  return `// import { ${n} } from '${module ? specifier(module) : ""}';
197
205
  `;
198
206
  }).join("") : "";
199
- const intrinsicLines = intrinsics ? Object.entries(INTRINSICS).map(
207
+ const intrinsicLines = usableIntrinsics.map(
200
208
  ([name, intrinsic]) => ` const ${name}: typeof ${namespaceAlias(intrinsic.module)}.${intrinsic.export};`
201
- ) : [];
209
+ );
202
210
  const patternRules = rules.filter((rule) => "match" in rule).length;
203
- const patternNote = patternRules > 0 ? `//
211
+ const patternNote = patternRules === 0 ? "" : options.candidates ? `//
212
+ // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"}: declared for the files the module path
213
+ // points at. A name with no such file still resolves at build time; declare it by hand.
214
+ ` : `//
204
215
  // ${patternRules} pattern rule${patternRules === 1 ? "" : "s"} cannot be declared:
205
216
  // a pattern matches unboundedly many names, so there is no list to emit. Those
206
217
  // tags still resolve at build time; declare them by hand if the editor needs them.
207
- ` : "";
218
+ `;
208
219
  const source = `// GENERATED by ${generator}, do not edit.
209
220
  //
210
221
  // The components \`resolve\` supplies without an import. This describes what the
@@ -261,6 +272,30 @@ function projectDependencies(root) {
261
272
  return void 0;
262
273
  }
263
274
  }
275
+ function patternCandidates(rules, root) {
276
+ const out = [];
277
+ for (const rule of rules) {
278
+ if (!("match" in rule) || !rule.module.startsWith("/")) continue;
279
+ const dir = dirname(rule.module);
280
+ const file = basename(rule.module);
281
+ const group = file.match(/\$\d+/);
282
+ if (dir.includes("$") || !group || file.indexOf("$", group.index + 1) !== -1) continue;
283
+ const before = file.slice(0, group.index);
284
+ const after = file.slice(group.index + group[0].length);
285
+ let entries;
286
+ try {
287
+ entries = readdirSync(resolvePath(root, dir.slice(1)));
288
+ } catch {
289
+ continue;
290
+ }
291
+ for (const entry of entries) {
292
+ if (entry.length > before.length + after.length && entry.startsWith(before) && entry.endsWith(after)) {
293
+ out.push(entry.slice(before.length, entry.length - after.length));
294
+ }
295
+ }
296
+ }
297
+ return out;
298
+ }
264
299
  function writeComponentGlobals(options, root) {
265
300
  if (options.globals === false) return { status: "skipped", reason: "disabled" };
266
301
  const rules = options.resolve ?? [];
@@ -276,6 +311,7 @@ function writeComponentGlobals(options, root) {
276
311
  }
277
312
  const { source, declared } = componentGlobals(rules, {
278
313
  available: projectDependencies(root),
314
+ candidates: patternCandidates(rules, root),
279
315
  specifier: (module) => forTypeScript(module, dirname(target), root)
280
316
  });
281
317
  if (existing === source) {
@@ -302,5 +338,6 @@ function warnIfUnreachable(root, target) {
302
338
  }
303
339
  export {
304
340
  DEFAULT_GLOBALS_PATH,
341
+ patternCandidates,
305
342
  writeComponentGlobals
306
343
  };
@@ -1,11 +1,11 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.90 | (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
  MagicString
4
- } from "./chunk-RZ3JE33I.mjs";
4
+ } from "./chunk-DWNWN5RH.mjs";
5
5
  import {
6
6
  serverFnId
7
- } from "./chunk-RCOCGLLD.mjs";
8
- import "./chunk-XTMCL6V7.mjs";
7
+ } from "./chunk-QZ4CJPYP.mjs";
8
+ import "./chunk-VOUI6XPV.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.90 | (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
  serverFnId
4
- } from "./chunk-RCOCGLLD.mjs";
5
- import "./chunk-XTMCL6V7.mjs";
4
+ } from "./chunk-QZ4CJPYP.mjs";
5
+ import "./chunk-VOUI6XPV.mjs";
6
6
 
7
7
  // src/frontend/babel/server-functions.ts
8
8
  import { transformSync } from "@babel/core";
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.90 | (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;
@@ -498,7 +498,9 @@ var INTRINSICS = {
498
498
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
499
499
  // dependency analysis must not guess at.
500
500
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
501
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
501
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
502
+ // An environment variable, public or server-only; the browser build refuses a secret.
503
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
502
504
  };
503
505
  var RUNTIME_PRIMITIVES = {
504
506
  signal: "signal-handle",
@@ -2358,10 +2360,34 @@ function collectIntrinsicEdits(program) {
2358
2360
  });
2359
2361
  return { edits, diagnostics, imports };
2360
2362
  }
2363
+ function avoidBindingClashes(program, result, bound) {
2364
+ const importedAsIs = /* @__PURE__ */ new Set();
2365
+ for (const stmt of program.body ?? []) {
2366
+ if (stmt.type !== "ImportDeclaration") continue;
2367
+ const module2 = stmt.source.value;
2368
+ for (const spec of stmt.specifiers ?? []) {
2369
+ if (spec.type !== "ImportSpecifier") continue;
2370
+ const imported = spec.imported.name ?? spec.imported.value;
2371
+ if (imported === spec.local.name && result.imports.get(module2)?.has(imported)) {
2372
+ importedAsIs.add(imported);
2373
+ }
2374
+ }
2375
+ }
2376
+ const aliases = /* @__PURE__ */ new Map();
2377
+ for (const names of result.imports.values()) {
2378
+ for (const name of names) if (bound.has(name) && !importedAsIs.has(name)) aliases.set(name, `__fx_${name}`);
2379
+ }
2380
+ if (!aliases.size) return;
2381
+ for (const edit of result.edits) {
2382
+ const alias = aliases.get(edit.code);
2383
+ if (alias) edit.code = alias;
2384
+ }
2385
+ result.aliases = aliases;
2386
+ }
2361
2387
  function intrinsicImports(result, bound) {
2362
2388
  const lines = [];
2363
2389
  for (const [module2, names] of [...result.imports].sort(([a], [b]) => a.localeCompare(b))) {
2364
- const wanted = [...names].filter((name) => !bound.has(name)).sort();
2390
+ 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);
2365
2391
  if (wanted.length) lines.push(`import { ${wanted.join(", ")} } from ${JSON.stringify(module2)};`);
2366
2392
  }
2367
2393
  return lines.length ? `${lines.join("\n")}
@@ -2561,6 +2587,7 @@ function transformTemplates(code, id, options = {}) {
2561
2587
  });
2562
2588
  const props = options.propsDestructure === false ? { edits: [], diagnostics: [], used: /* @__PURE__ */ new Set() } : collectPropsEdits(ast.program, code, { runtimeModule: options.runtimeModule });
2563
2589
  const intrinsics = options.intrinsics === false ? { edits: [], diagnostics: [], imports: /* @__PURE__ */ new Map() } : collectIntrinsicEdits(ast.program);
2590
+ if (intrinsics.edits.length) avoidBindingClashes(ast.program, intrinsics, moduleBindings(ast.program));
2564
2591
  const sources = options.sourceLocations === true ? collectSourceEdits(ast.program, sourceName) : { edits: [], marked: 0 };
2565
2592
  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;
2566
2593
  if (silent) return null;
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.90 | (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/transform/templates.ts
4
4
  import { parse as parse2 } from "@babel/parser";
@@ -1530,7 +1530,9 @@ var INTRINSICS = {
1530
1530
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
1531
1531
  // dependency analysis must not guess at.
1532
1532
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
1533
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
1533
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
1534
+ // An environment variable, public or server-only; the browser build refuses a secret.
1535
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
1534
1536
  };
1535
1537
  var RUNTIME_PRIMITIVES = {
1536
1538
  signal: "signal-handle",
@@ -3391,10 +3393,34 @@ function collectIntrinsicEdits(program) {
3391
3393
  });
3392
3394
  return { edits, diagnostics, imports };
3393
3395
  }
3396
+ function avoidBindingClashes(program, result, bound) {
3397
+ const importedAsIs = /* @__PURE__ */ new Set();
3398
+ for (const stmt of program.body ?? []) {
3399
+ if (stmt.type !== "ImportDeclaration") continue;
3400
+ const module = stmt.source.value;
3401
+ for (const spec of stmt.specifiers ?? []) {
3402
+ if (spec.type !== "ImportSpecifier") continue;
3403
+ const imported = spec.imported.name ?? spec.imported.value;
3404
+ if (imported === spec.local.name && result.imports.get(module)?.has(imported)) {
3405
+ importedAsIs.add(imported);
3406
+ }
3407
+ }
3408
+ }
3409
+ const aliases = /* @__PURE__ */ new Map();
3410
+ for (const names of result.imports.values()) {
3411
+ for (const name of names) if (bound.has(name) && !importedAsIs.has(name)) aliases.set(name, `__fx_${name}`);
3412
+ }
3413
+ if (!aliases.size) return;
3414
+ for (const edit of result.edits) {
3415
+ const alias = aliases.get(edit.code);
3416
+ if (alias) edit.code = alias;
3417
+ }
3418
+ result.aliases = aliases;
3419
+ }
3394
3420
  function intrinsicImports(result, bound) {
3395
3421
  const lines = [];
3396
3422
  for (const [module, names] of [...result.imports].sort(([a], [b]) => a.localeCompare(b))) {
3397
- const wanted = [...names].filter((name) => !bound.has(name)).sort();
3423
+ 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);
3398
3424
  if (wanted.length) lines.push(`import { ${wanted.join(", ")} } from ${JSON.stringify(module)};`);
3399
3425
  }
3400
3426
  return lines.length ? `${lines.join("\n")}
@@ -3594,6 +3620,7 @@ function transformTemplates(code, id, options = {}) {
3594
3620
  });
3595
3621
  const props = options.propsDestructure === false ? { edits: [], diagnostics: [], used: /* @__PURE__ */ new Set() } : collectPropsEdits(ast.program, code, { runtimeModule: options.runtimeModule });
3596
3622
  const intrinsics = options.intrinsics === false ? { edits: [], diagnostics: [], imports: /* @__PURE__ */ new Map() } : collectIntrinsicEdits(ast.program);
3623
+ if (intrinsics.edits.length) avoidBindingClashes(ast.program, intrinsics, moduleBindings(ast.program));
3597
3624
  const sources = options.sourceLocations === true ? collectSourceEdits(ast.program, sourceName) : { edits: [], marked: 0 };
3598
3625
  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;
3599
3626
  if (silent) return null;
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/transform/intrinsics.ts
21
21
  var intrinsics_exports = {};
22
22
  __export(intrinsics_exports, {
23
+ avoidBindingClashes: () => avoidBindingClashes,
23
24
  collectIntrinsicEdits: () => collectIntrinsicEdits,
24
25
  intrinsicImports: () => intrinsicImports
25
26
  });
@@ -42,7 +43,9 @@ var INTRINSICS = {
42
43
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
43
44
  // dependency analysis must not guess at.
44
45
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
45
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
46
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
47
+ // An environment variable, public or server-only; the browser build refuses a secret.
48
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
46
49
  };
47
50
  var RUNTIME_PRIMITIVES = {
48
51
  signal: "signal-handle",
@@ -205,10 +208,34 @@ function collectIntrinsicEdits(program) {
205
208
  });
206
209
  return { edits, diagnostics, imports };
207
210
  }
211
+ function avoidBindingClashes(program, result, bound) {
212
+ const importedAsIs = /* @__PURE__ */ new Set();
213
+ for (const stmt of program.body ?? []) {
214
+ if (stmt.type !== "ImportDeclaration") continue;
215
+ const module2 = stmt.source.value;
216
+ for (const spec of stmt.specifiers ?? []) {
217
+ if (spec.type !== "ImportSpecifier") continue;
218
+ const imported = spec.imported.name ?? spec.imported.value;
219
+ if (imported === spec.local.name && result.imports.get(module2)?.has(imported)) {
220
+ importedAsIs.add(imported);
221
+ }
222
+ }
223
+ }
224
+ const aliases = /* @__PURE__ */ new Map();
225
+ for (const names of result.imports.values()) {
226
+ for (const name of names) if (bound.has(name) && !importedAsIs.has(name)) aliases.set(name, `__fx_${name}`);
227
+ }
228
+ if (!aliases.size) return;
229
+ for (const edit of result.edits) {
230
+ const alias = aliases.get(edit.code);
231
+ if (alias) edit.code = alias;
232
+ }
233
+ result.aliases = aliases;
234
+ }
208
235
  function intrinsicImports(result, bound) {
209
236
  const lines = [];
210
237
  for (const [module2, names] of [...result.imports].sort(([a], [b]) => a.localeCompare(b))) {
211
- const wanted = [...names].filter((name) => !bound.has(name)).sort();
238
+ 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);
212
239
  if (wanted.length) lines.push(`import { ${wanted.join(", ")} } from ${JSON.stringify(module2)};`);
213
240
  }
214
241
  return lines.length ? `${lines.join("\n")}
@@ -14,8 +14,20 @@ export interface IntrinsicsResult {
14
14
  diagnostics: IntrinsicDiagnostic[];
15
15
  /** Runtime exports the rewritten code needs, by module. */
16
16
  imports: Map<string, Set<string>>;
17
+ /** Runtime exports imported under another name, because the module binds theirs. */
18
+ aliases?: Map<string, string>;
17
19
  }
18
20
  /** Find the `$` calls in a module and say what they compile to. */
19
21
  export declare function collectIntrinsicEdits(program: unknown): IntrinsicsResult;
22
+ /**
23
+ * Point a rewritten call past a local binding of the same name.
24
+ *
25
+ * `$env('X')` becomes `env('X')`, and the import of `env` used to be skipped when the module
26
+ * already bound `env`, on the assumption that it was the same import. A config module with its
27
+ * own `const env = {…}` is common, and there the call reached the app's object instead. Such a
28
+ * name is now imported under a private alias. A module that imports that very export from that
29
+ * very module keeps the old behaviour: the binding is the runtime already.
30
+ */
31
+ export declare function avoidBindingClashes(program: unknown, result: IntrinsicsResult, bound: Set<string>): void;
20
32
  /** The import statements a result needs, minus anything the module already binds. */
21
33
  export declare function intrinsicImports(result: IntrinsicsResult, bound: Set<string>): string;
@@ -14,9 +14,21 @@ export interface IntrinsicsResult {
14
14
  diagnostics: IntrinsicDiagnostic[];
15
15
  /** Runtime exports the rewritten code needs, by module. */
16
16
  imports: Map<string, Set<string>>;
17
+ /** Runtime exports imported under another name, because the module binds theirs. */
18
+ aliases?: Map<string, string>;
17
19
  }
18
20
  /** Find the `$` calls in a module and say what they compile to. */
19
21
  export declare function collectIntrinsicEdits(program: unknown): IntrinsicsResult;
22
+ /**
23
+ * Point a rewritten call past a local binding of the same name.
24
+ *
25
+ * `$env('X')` becomes `env('X')`, and the import of `env` used to be skipped when the module
26
+ * already bound `env`, on the assumption that it was the same import. A config module with its
27
+ * own `const env = {…}` is common, and there the call reached the app's object instead. Such a
28
+ * name is now imported under a private alias. A module that imports that very export from that
29
+ * very module keeps the old behaviour: the binding is the runtime already.
30
+ */
31
+ export declare function avoidBindingClashes(program: unknown, result: IntrinsicsResult, bound: Set<string>): void;
20
32
  /** The import statements a result needs, minus anything the module already binds. */
21
33
  export declare function intrinsicImports(result: IntrinsicsResult, bound: Set<string>): string;
22
34
  //# sourceMappingURL=intrinsics.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"intrinsics.d.ts","sourceRoot":"","sources":["../../src/transform/intrinsics.ts"],"names":[],"mappings":"AAwBA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,2DAA2D;IAC3D,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;CACnC;AAaD,mEAAmE;AACnE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CAuCxE;AAED,qFAAqF;AACrF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAOrF"}
1
+ {"version":3,"file":"intrinsics.d.ts","sourceRoot":"","sources":["../../src/transform/intrinsics.ts"],"names":[],"mappings":"AAwBA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,2DAA2D;IAC3D,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAClC,oFAAoF;IACpF,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAaD,mEAAmE;AACnE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CAuCxE;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAwBxG;AAED,qFAAqF;AACrF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAUrF"}
@@ -66,11 +66,53 @@ export function collectIntrinsicEdits(program) {
66
66
  });
67
67
  return { edits, diagnostics, imports };
68
68
  }
69
+ /**
70
+ * Point a rewritten call past a local binding of the same name.
71
+ *
72
+ * `$env('X')` becomes `env('X')`, and the import of `env` used to be skipped when the module
73
+ * already bound `env`, on the assumption that it was the same import. A config module with its
74
+ * own `const env = {…}` is common, and there the call reached the app's object instead. Such a
75
+ * name is now imported under a private alias. A module that imports that very export from that
76
+ * very module keeps the old behaviour: the binding is the runtime already.
77
+ */
78
+ export function avoidBindingClashes(program, result, bound) {
79
+ const importedAsIs = new Set();
80
+ for (const stmt of program.body ?? []) {
81
+ if (stmt.type !== 'ImportDeclaration')
82
+ continue;
83
+ const module = stmt.source.value;
84
+ for (const spec of stmt.specifiers ?? []) {
85
+ if (spec.type !== 'ImportSpecifier')
86
+ continue;
87
+ const imported = (spec.imported.name ?? spec.imported.value);
88
+ if (imported === spec.local.name && result.imports.get(module)?.has(imported)) {
89
+ importedAsIs.add(imported);
90
+ }
91
+ }
92
+ }
93
+ const aliases = new Map();
94
+ for (const names of result.imports.values()) {
95
+ for (const name of names)
96
+ if (bound.has(name) && !importedAsIs.has(name))
97
+ aliases.set(name, `__fx_${name}`);
98
+ }
99
+ if (!aliases.size)
100
+ return;
101
+ for (const edit of result.edits) {
102
+ const alias = aliases.get(edit.code);
103
+ if (alias)
104
+ edit.code = alias;
105
+ }
106
+ result.aliases = aliases;
107
+ }
69
108
  /** The import statements a result needs, minus anything the module already binds. */
70
109
  export function intrinsicImports(result, bound) {
71
110
  const lines = [];
72
111
  for (const [module, names] of [...result.imports].sort(([a], [b]) => a.localeCompare(b))) {
73
- const wanted = [...names].filter((name) => !bound.has(name)).sort();
112
+ const wanted = [...names]
113
+ .filter((name) => result.aliases?.has(name) || !bound.has(name))
114
+ .sort()
115
+ .map((name) => (result.aliases?.has(name) ? `${name} as ${result.aliases.get(name)}` : name));
74
116
  if (wanted.length)
75
117
  lines.push(`import { ${wanted.join(', ')} } from ${JSON.stringify(module)};`);
76
118
  }