tyfigo 0.1.0-next.ddcaab3.0 → 0.1.0-next.f085cb0.0

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 (66) hide show
  1. package/dist/effect.d.mts +2 -3
  2. package/dist/effect.mjs +2 -2
  3. package/dist/index.d.mts +2 -3
  4. package/dist/index.mjs +1 -1
  5. package/dist/{index-CM4xg0II.d.mts → resolve-BeFHJeZb.d.mts} +50 -8
  6. package/dist/{resolve-B7e2uGDa.mjs → resolve-CDWA58rz.mjs} +100 -82
  7. package/dist/resolve-CDWA58rz.mjs.map +1 -0
  8. package/dist/runtime/index.d.mts +44 -3
  9. package/dist/runtime/index.mjs +99 -4
  10. package/dist/runtime/index.mjs.map +1 -0
  11. package/dist/{schema-C_damFGy.mjs → schema-C31aywfc.mjs} +2 -3
  12. package/dist/{schema-C_damFGy.mjs.map → schema-C31aywfc.mjs.map} +1 -1
  13. package/dist/{schema-CkQRd2Uf.d.mts → schema-CNquZBC8.d.mts} +2 -3
  14. package/package.json +2 -108
  15. package/dist/bun.d.mts +0 -7
  16. package/dist/bun.mjs +0 -35
  17. package/dist/bun.mjs.map +0 -1
  18. package/dist/load-BqGJgpfo.mjs +0 -124
  19. package/dist/load-BqGJgpfo.mjs.map +0 -1
  20. package/dist/load-CKIE0mVT.d.mts +0 -53
  21. package/dist/plugins/esbuild.d.mts +0 -5
  22. package/dist/plugins/esbuild.mjs +0 -6
  23. package/dist/plugins/esbuild.mjs.map +0 -1
  24. package/dist/plugins/jest.d.mts +0 -10
  25. package/dist/plugins/jest.mjs +0 -29
  26. package/dist/plugins/jest.mjs.map +0 -1
  27. package/dist/plugins/loader.d.mts +0 -15
  28. package/dist/plugins/loader.mjs +0 -21
  29. package/dist/plugins/loader.mjs.map +0 -1
  30. package/dist/plugins/next.d.mts +0 -21
  31. package/dist/plugins/next.mjs +0 -121
  32. package/dist/plugins/next.mjs.map +0 -1
  33. package/dist/plugins/rolldown.d.mts +0 -5
  34. package/dist/plugins/rolldown.mjs +0 -6
  35. package/dist/plugins/rolldown.mjs.map +0 -1
  36. package/dist/plugins/rollup.d.mts +0 -5
  37. package/dist/plugins/rollup.mjs +0 -6
  38. package/dist/plugins/rollup.mjs.map +0 -1
  39. package/dist/plugins/rsbuild.d.mts +0 -5
  40. package/dist/plugins/rsbuild.mjs +0 -6
  41. package/dist/plugins/rsbuild.mjs.map +0 -1
  42. package/dist/plugins/rspack.d.mts +0 -5
  43. package/dist/plugins/rspack.mjs +0 -6
  44. package/dist/plugins/rspack.mjs.map +0 -1
  45. package/dist/plugins/vite.d.mts +0 -5
  46. package/dist/plugins/vite.mjs +0 -6
  47. package/dist/plugins/vite.mjs.map +0 -1
  48. package/dist/plugins/webpack.d.mts +0 -5
  49. package/dist/plugins/webpack.mjs +0 -6
  50. package/dist/plugins/webpack.mjs.map +0 -1
  51. package/dist/register.d.mts +0 -1
  52. package/dist/register.mjs +0 -25
  53. package/dist/register.mjs.map +0 -1
  54. package/dist/resolve-B7e2uGDa.mjs.map +0 -1
  55. package/dist/resolve-BUtCDolX.d.mts +0 -65
  56. package/dist/resolve-hzoKURuJ.mjs +0 -72
  57. package/dist/resolve-hzoKURuJ.mjs.map +0 -1
  58. package/dist/runtime-la_KkjCS.mjs +0 -1
  59. package/dist/shared-BuRtKsWB.mjs +0 -16
  60. package/dist/shared-BuRtKsWB.mjs.map +0 -1
  61. package/dist/shared-CLa0Be_8.d.mts +0 -22
  62. package/dist/sync-DUNHC9W6.mjs +0 -14
  63. package/dist/sync-DUNHC9W6.mjs.map +0 -1
  64. package/dist/unplugin-DXVarwkX.mjs +0 -69
  65. package/dist/unplugin-DXVarwkX.mjs.map +0 -1
  66. package/dist/unplugin-ce5g3K3a.d.mts +0 -2
package/dist/effect.d.mts CHANGED
@@ -1,6 +1,5 @@
1
- import { a as LocatedSpan, c as Path, i as ResolvedLayer, l as Span, n as ResolveOptions, o as Problem, r as ResolvedConfig, s as ProblemCode } from "./index-CM4xg0II.mjs";
2
- import { i as ConfigSource } from "./resolve-BUtCDolX.mjs";
3
- import { a as LooseInput, i as LoadEnvOptions, n as ConfigSchema, o as SchemaInput, r as ConfigValidationError, s as SchemaOutput, t as ConfigIssue } from "./schema-CkQRd2Uf.mjs";
1
+ import { d as ResolvedLayer, f as LocatedSpan, g as Span, h as Path, l as ResolveOptions, m as ProblemCode, p as Problem, r as ConfigSource, u as ResolvedConfig } from "./resolve-BeFHJeZb.mjs";
2
+ import { a as LooseInput, i as LoadEnvOptions, n as ConfigSchema, o as SchemaInput, r as ConfigValidationError, s as SchemaOutput, t as ConfigIssue } from "./schema-CNquZBC8.mjs";
4
3
  import { ConfigProvider, Context, Effect, Layer, Schema } from "effect";
5
4
  import { StandardSchemaV1 } from "@standard-schema/spec";
6
5
  /**
package/dist/effect.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { t as resolveConfig } from "./resolve-B7e2uGDa.mjs";
2
- import { n as decodeConfig, r as decodeEnv, t as ConfigValidationError } from "./schema-C_damFGy.mjs";
1
+ import { o as resolveConfig } from "./resolve-CDWA58rz.mjs";
2
+ import { n as decodeConfig, r as decodeEnv, t as ConfigValidationError } from "./schema-C31aywfc.mjs";
3
3
  import { ConfigProvider, Context, Effect, Layer } from "effect";
4
4
  // src/effect/load.ts
5
5
  /**
package/dist/index.d.mts CHANGED
@@ -1,6 +1,5 @@
1
- import { a as LocatedSpan, c as Path, i as ResolvedLayer, l as Span, n as ResolveOptions, o as Problem, r as ResolvedConfig, s as ProblemCode } from "./index-CM4xg0II.mjs";
2
- import { i as ConfigSource } from "./resolve-BUtCDolX.mjs";
3
- import { a as LooseInput, i as LoadEnvOptions, n as ConfigSchema, o as SchemaInput, r as ConfigValidationError, s as SchemaOutput, t as ConfigIssue } from "./schema-CkQRd2Uf.mjs";
1
+ import { d as ResolvedLayer, f as LocatedSpan, g as Span, h as Path, l as ResolveOptions, m as ProblemCode, p as Problem, r as ConfigSource, u as ResolvedConfig } from "./resolve-BeFHJeZb.mjs";
2
+ import { a as LooseInput, i as LoadEnvOptions, n as ConfigSchema, o as SchemaInput, r as ConfigValidationError, s as SchemaOutput, t as ConfigIssue } from "./schema-CNquZBC8.mjs";
4
3
  /**
5
4
  * Validates a config import (or any value) with a Standard Schema or an Effect Schema and returns the schema's output.
6
5
  *
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as decodeConfig, r as decodeEnv, t as ConfigValidationError } from "./schema-C_damFGy.mjs";
1
+ import { n as decodeConfig, r as decodeEnv, t as ConfigValidationError } from "./schema-C31aywfc.mjs";
2
2
  import { Effect } from "effect";
3
3
  // src/index.ts
4
4
  /**
@@ -53,10 +53,6 @@ interface Format {
53
53
  readonly parseScalar: (text: string) => unknown;
54
54
  }
55
55
  type LayerKind = 'base' | 'environment' | 'local' | 'environment-local';
56
- interface LayerFile {
57
- readonly file: string;
58
- readonly kind: LayerKind;
59
- }
60
56
  /**
61
57
  * A {@link Span} together with the file it is in.
62
58
  */
@@ -106,8 +102,54 @@ interface ResolvedConfig {
106
102
  readonly positions: ReadonlyMap<string, LocatedSpan>;
107
103
  readonly problems: readonly Problem[];
108
104
  }
109
- interface LayerSource extends LayerFile {
110
- readonly text: string;
105
+ /**
106
+ * The key of the non-enumerable {@link ConfigSource} on a config object exported by a generated server module.
107
+ */
108
+ declare const configSource: unique symbol;
109
+ interface SourcePosition {
110
+ readonly file: string;
111
+ readonly line: number;
112
+ readonly column: number;
113
+ }
114
+ interface ConfigSource {
115
+ /**
116
+ * The base config file, as an absolute path.
117
+ */
118
+ readonly file: string;
119
+ readonly environment: string | undefined;
120
+ /**
121
+ * The layer files that were merged, in the order they apply.
122
+ */
123
+ readonly layers: readonly string[];
124
+ /**
125
+ * The `.env` files that were read, in the order they apply.
126
+ */
127
+ readonly envFiles: readonly string[];
128
+ /**
129
+ * Where the value at `path` was set. A path the config does not have resolves to its nearest ancestor that it does have.
130
+ */
131
+ readonly position: (path: Path) => SourcePosition | undefined;
111
132
  }
112
- export { LocatedSpan as a, Path as c, ResolvedLayer as i, Span as l, ResolveOptions as n, Problem as o, ResolvedConfig as r, ProblemCode as s, LayerSource as t };
113
- //# sourceMappingURL=index-CM4xg0II.d.mts.map
133
+ declare const ConfigModuleError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
134
+ readonly _tag: "ConfigModuleError";
135
+ } & Readonly<A>;
136
+ declare class ConfigModuleError extends ConfigModuleError_base<{
137
+ readonly message: string;
138
+ readonly file: string;
139
+ readonly problems: readonly Problem[];
140
+ }> {}
141
+ interface ConfigModuleOptions {
142
+ /**
143
+ * The environment name that picks `app.<environment>.config.yaml` and `.env.<environment>`. Defaults to `NODE_ENV`.
144
+ */
145
+ readonly environment?: string | undefined;
146
+ }
147
+ declare const deepFreeze: <T>(value: T) => T;
148
+ declare const getConfigSource: (value: unknown) => ConfigSource | undefined;
149
+ /**
150
+ * Resolves a config file with its layers, `.env` files and placeholders, and returns the deep-frozen value. This is what a
151
+ * generated server module calls when it is evaluated. Throws a {@link ConfigModuleError} listing every problem.
152
+ */
153
+ declare const resolveConfigModule: (file: string, options?: ConfigModuleOptions) => unknown;
154
+ export { configSource as a, resolveConfigModule as c, ResolvedLayer as d, LocatedSpan as f, Span as g, Path as h, SourcePosition as i, ResolveOptions as l, ProblemCode as m, ConfigModuleOptions as n, deepFreeze as o, Problem as p, ConfigSource as r, getConfigSource as s, ConfigModuleError as t, ResolvedConfig as u };
155
+ //# sourceMappingURL=resolve-BeFHJeZb.d.mts.map
@@ -1,5 +1,5 @@
1
- import { a as parseConfigFileName, c as pathKey, d as problemAt, i as configSuffixes, l as fileProblem, n as isPlainObject, o as SourceIndex, r as resolvePlaceholders, s as formatPath } from "./placeholders-MqW2KO9Z.mjs";
2
- import { Effect, Result } from "effect";
1
+ import { a as parseConfigFileName, c as pathKey, d as problemAt, i as configSuffixes, l as fileProblem, n as isPlainObject, o as SourceIndex, r as resolvePlaceholders, s as formatPath, u as formatProblems } from "./placeholders-MqW2KO9Z.mjs";
2
+ import { Data, Effect, Result } from "effect";
3
3
  import { basename, dirname, join, resolve } from "node:path";
4
4
  import process from "node:process";
5
5
  import { readFileSync, statSync } from "node:fs";
@@ -172,18 +172,48 @@ const readText = (file) => Effect.try({
172
172
  try: () => readFileSync(file, "utf8"),
173
173
  catch: (error) => fileProblem(file, "read-error", `Cannot read ${file}: ${error.message}`)
174
174
  });
175
- const mergeLayers = Effect.fn("mergeLayers")(function* (format, files, read, variables) {
176
- const problems = [];
175
+ /**
176
+ * Reads a config file with its environment and local layers and `.env` files, resolves placeholders and merges the layers.
177
+ * Never fails: everything that went wrong is in `problems`.
178
+ */
179
+ const resolveConfig = Effect.fn("resolveConfig")(function* (path, options = {}) {
180
+ const file = resolve(path);
181
+ const env = options.env ?? processEnv();
182
+ const environment = options.environment ?? (env.NODE_ENV || void 0);
183
+ const name = parseConfigFileName(basename(file));
184
+ const empty = {
185
+ file,
186
+ format: name?.format,
187
+ environment,
188
+ value: void 0,
189
+ layers: [],
190
+ envFiles: [],
191
+ positions: /* @__PURE__ */ new Map()
192
+ };
193
+ if (!name) return {
194
+ ...empty,
195
+ problems: [fileProblem(file, "unsupported-file", `${basename(file)} is not a config file; expected a name ending in ${configSuffixes.join(", ")}`)]
196
+ };
197
+ if (!(yield* isFile(file))) return {
198
+ ...empty,
199
+ problems: [fileProblem(file, "file-not-found", `Cannot find ${file}`)]
200
+ };
201
+ const envResult = yield* readEnv(file, {
202
+ environment,
203
+ env
204
+ });
205
+ const problems = [...envResult.problems];
177
206
  const layers = [];
178
207
  let merged;
179
- for (const layer of files) {
180
- const content = yield* Effect.result(read(layer));
181
- if (Result.isFailure(content)) {
182
- problems.push(content.failure);
208
+ for (const layer of yield* discoverLayers(file, environment)) {
209
+ if (options.layers && !options.layers.includes(layer.kind)) continue;
210
+ const read = yield* Effect.result(readText(layer.file));
211
+ if (Result.isFailure(read)) {
212
+ problems.push(read.failure);
183
213
  continue;
184
214
  }
185
- const text = content.success;
186
- const parsed = format.parse(text, layer.file);
215
+ const text = read.success;
216
+ const parsed = name.format.parse(text, layer.file);
187
217
  problems.push(...parsed.problems);
188
218
  const source = new SourceIndex(text);
189
219
  const resolved = parsed.value === void 0 ? {
@@ -194,13 +224,12 @@ const mergeLayers = Effect.fn("mergeLayers")(function* (format, files, read, var
194
224
  positions: parsed.positions,
195
225
  source,
196
226
  file: layer.file,
197
- format,
198
- variables
227
+ format: name.format,
228
+ variables: envResult.variables
199
229
  });
200
230
  problems.push(...resolved.problems);
201
231
  layers.push({
202
- file: layer.file,
203
- kind: layer.kind,
232
+ ...layer,
204
233
  text,
205
234
  value: resolved.value,
206
235
  positions: parsed.positions
@@ -223,86 +252,75 @@ const mergeLayers = Effect.fn("mergeLayers")(function* (format, files, read, var
223
252
  merged = result;
224
253
  }
225
254
  return {
255
+ ...empty,
256
+ envFiles: envResult.files,
226
257
  layers,
227
258
  value: merged?.value,
228
259
  positions: merged?.positions ?? /* @__PURE__ */ new Map(),
229
260
  problems
230
261
  };
231
262
  });
232
- const unsupportedFile = (file) => fileProblem(file, "unsupported-file", `${basename(file)} is not a config file; expected a name ending in ${configSuffixes.join(", ")}`);
263
+ // src/core/sync.ts
233
264
  /**
234
- * Reads a config file with its environment and local layers and `.env` files, resolves placeholders and merges the layers.
235
- * Never fails: everything that went wrong is in `problems`.
265
+ * {@link resolveConfig} for synchronous callers such as Node `registerHooks` load hooks.
236
266
  */
237
- const resolveConfig = Effect.fn("resolveConfig")(function* (path, options = {}) {
238
- const file = resolve(path);
239
- const env = options.env ?? processEnv();
240
- const environment = options.environment ?? (env.NODE_ENV || void 0);
241
- const name = parseConfigFileName(basename(file));
242
- const empty = {
243
- file,
244
- format: name?.format,
245
- environment,
246
- value: void 0,
247
- layers: [],
248
- envFiles: [],
249
- positions: /* @__PURE__ */ new Map()
250
- };
251
- if (!name) return {
252
- ...empty,
253
- problems: [unsupportedFile(file)]
254
- };
255
- if (!(yield* isFile(file))) return {
256
- ...empty,
257
- problems: [fileProblem(file, "file-not-found", `Cannot find ${file}`)]
267
+ const resolveConfigSync = (path, options) => Effect.runSync(resolveConfig(path, options));
268
+ // src/runtime/resolve.ts
269
+ /**
270
+ * The key of the non-enumerable {@link ConfigSource} on a config object exported by a generated server module.
271
+ */
272
+ const configSource = Symbol.for("tyfigo.source");
273
+ var ConfigModuleError = class extends Data.TaggedError("ConfigModuleError") {};
274
+ const deepFreeze = (value) => {
275
+ if (typeof value === "object" && value !== null && !Object.isFrozen(value)) {
276
+ Object.freeze(value);
277
+ for (const item of Object.values(value)) deepFreeze(item);
278
+ }
279
+ return value;
280
+ };
281
+ const getConfigSource = (value) => typeof value === "object" && value !== null ? value[configSource] : void 0;
282
+ const sourceOf = (result) => {
283
+ const texts = new Map(result.layers.map((layer) => [layer.file, layer.text]));
284
+ const indexes = /* @__PURE__ */ new Map();
285
+ const indexOf = (file) => {
286
+ const text = texts.get(file);
287
+ if (text === void 0) return void 0;
288
+ const index = indexes.get(file) ?? new SourceIndex(text);
289
+ indexes.set(file, index);
290
+ return index;
258
291
  };
259
- const envResult = yield* readEnv(file, {
260
- environment,
261
- env
262
- });
263
- const files = (yield* discoverLayers(file, environment)).filter((layer) => !options.layers || options.layers.includes(layer.kind));
264
- const merged = yield* mergeLayers(name.format, files, (layer) => readText(layer.file), envResult.variables);
265
292
  return {
266
- ...empty,
267
- ...merged,
268
- envFiles: envResult.files,
269
- problems: [...envResult.problems, ...merged.problems]
293
+ file: result.file,
294
+ environment: result.environment,
295
+ layers: result.layers.map((layer) => layer.file),
296
+ envFiles: result.envFiles,
297
+ position: (path) => {
298
+ for (let depth = path.length; depth >= 0; depth--) {
299
+ const span = result.positions.get(pathKey(path.slice(0, depth)));
300
+ if (!span) continue;
301
+ const index = indexOf(span.file);
302
+ return index ? {
303
+ file: span.file,
304
+ ...index.lineColumn(span.valueStart)
305
+ } : void 0;
306
+ }
307
+ }
270
308
  };
271
- });
309
+ };
272
310
  /**
273
- * {@link resolveConfig} for layer files whose text was read earlier, such as the layers a bundler inlined at build time. `file`
274
- * names the base file and picks the format; it is used as given and never read. Never fails: everything that went wrong is in
275
- * `problems`.
311
+ * Resolves a config file with its layers, `.env` files and placeholders, and returns the deep-frozen value. This is what a
312
+ * generated server module calls when it is evaluated. Throws a {@link ConfigModuleError} listing every problem.
276
313
  */
277
- const resolveConfigSources = Effect.fn("resolveConfigSources")(function* (file, sources, options) {
278
- const env = options.env ?? processEnv();
279
- const environment = options.environment ?? (env.NODE_ENV || void 0);
280
- const name = parseConfigFileName(basename(file));
281
- const empty = {
282
- file,
283
- format: name?.format,
284
- environment,
285
- value: void 0,
286
- layers: [],
287
- envFiles: [],
288
- positions: /* @__PURE__ */ new Map()
289
- };
290
- if (!name) return {
291
- ...empty,
292
- problems: [unsupportedFile(file)]
293
- };
294
- const envResult = yield* readEnv(options.envFrom, {
295
- environment,
296
- env
314
+ const resolveConfigModule = (file, options = {}) => {
315
+ const result = resolveConfigSync(file, { environment: options.environment });
316
+ if (result.problems.length > 0) throw new ConfigModuleError({
317
+ message: `Invalid config ${result.file}\n${formatProblems(result.problems)}`,
318
+ file: result.file,
319
+ problems: result.problems
297
320
  });
298
- const merged = yield* mergeLayers(name.format, sources, (layer) => Effect.succeed(layer.text), envResult.variables);
299
- return {
300
- ...empty,
301
- ...merged,
302
- envFiles: envResult.files,
303
- problems: [...envResult.problems, ...merged.problems]
304
- };
305
- });
306
- export { readEnv as a, searchDirectories as c, processEnv as i, resolveConfigSources as n, findProjectRoot as o, envFileNames as r, isFile as s, resolveConfig as t };
321
+ if (typeof result.value === "object" && result.value !== null) Object.defineProperty(result.value, configSource, { value: sourceOf(result) });
322
+ return deepFreeze(result.value);
323
+ };
324
+ export { resolveConfigModule as a, processEnv as c, searchDirectories as d, getConfigSource as i, readEnv as l, configSource as n, resolveConfig as o, deepFreeze as r, envFileNames as s, ConfigModuleError as t, isFile as u };
307
325
 
308
- //# sourceMappingURL=resolve-B7e2uGDa.mjs.map
326
+ //# sourceMappingURL=resolve-CDWA58rz.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-CDWA58rz.mjs","names":[],"sources":["../src/core/files.ts","../src/core/env.ts","../src/core/layers.ts","../src/core/merge.ts","../src/core/resolve.ts","../src/core/sync.ts","../src/runtime/resolve.ts"],"sourcesContent":["import { statSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nimport { Effect } from 'effect';\n\nexport const isFile = (path: string): Effect.Effect<boolean> =>\n\tEffect.sync(() => statSync(path, { throwIfNoEntry: false })?.isFile() ?? false);\n\n/**\n * The nearest directory at or above `directory` that has a `package.json`.\n */\nexport const findProjectRoot = Effect.fn('findProjectRoot')(function* (directory: string) {\n\tfor (let current = directory; ; current = dirname(current)) {\n\t\tif (yield* isFile(join(current, 'package.json'))) return current;\n\t\tif (dirname(current) === current) return undefined;\n\t}\n});\n\n/**\n * The first existing `name` in `directories`.\n */\nexport const findFile = Effect.fn('findFile')(function* (directories: readonly string[], name: string) {\n\tfor (const directory of directories) {\n\t\tconst path = join(directory, name);\n\t\tif (yield* isFile(path)) return path;\n\t}\n\treturn undefined;\n});\n\n/**\n * The base file's directory followed by the project root when it is a different directory.\n */\nexport const searchDirectories = Effect.fn('searchDirectories')(function* (baseFile: string) {\n\tconst directory = dirname(baseFile);\n\tconst root = yield* findProjectRoot(directory);\n\treturn root === undefined || root === directory ? [directory] : [directory, root];\n});\n","import { readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport process from 'node:process';\nimport { parseEnv } from 'node:util';\n\nimport { Effect, Result } from 'effect';\n\nimport { findFile, searchDirectories } from './files.ts';\nimport { fileProblem } from './problems.ts';\n\nimport type { Problem } from './problems.ts';\n\nexport type EnvVariables = Readonly<Record<string, string | undefined>>;\n\nexport interface EnvResult {\n\t/**\n\t * The `.env` values with the real environment on top.\n\t */\n\treadonly variables: EnvVariables;\n\t/**\n\t * The `.env` files that were read, in the order they apply.\n\t */\n\treadonly files: readonly string[];\n\treadonly problems: readonly Problem[];\n}\n\n/**\n * A copy of the real environment. This is the only place tyfigo reads `process.env`.\n */\nexport const processEnv = (): EnvVariables => ({ ...process.env });\n\nexport const envFileNames = (environment?: string): readonly string[] =>\n\tenvironment ? ['.env', '.env.local', `.env.${environment}`, `.env.${environment}.local`] : ['.env', '.env.local'];\n\n/**\n * Reads `.env`, `.env.local`, `.env.<environment>` and `.env.<environment>.local` (each later one wins) and puts `env` on top.\n * Each file is searched next to `baseFile` first, then in the nearest directory with a `package.json`. Never writes `process.env`.\n */\nexport const readEnv = Effect.fn('readEnv')(function* (\n\tbaseFile: string,\n\toptions: { readonly environment?: string | undefined; readonly env?: EnvVariables | undefined } = {},\n) {\n\tconst directories = yield* searchDirectories(resolve(baseFile));\n\tconst variables: Record<string, string | undefined> = {};\n\tconst files: string[] = [];\n\tconst problems: Problem[] = [];\n\tfor (const name of envFileNames(options.environment)) {\n\t\tconst file = yield* findFile(directories, name);\n\t\tif (!file) continue;\n\t\tconst parsed = yield* Effect.result(\n\t\t\tEffect.try({\n\t\t\t\ttry: () => parseEnv(readFileSync(file, 'utf8')),\n\t\t\t\tcatch: (error) => fileProblem(file, 'read-error', `Cannot read ${file}: ${(error as Error).message}`),\n\t\t\t}),\n\t\t);\n\t\tif (Result.isFailure(parsed)) {\n\t\t\tproblems.push(parsed.failure);\n\t\t\tcontinue;\n\t\t}\n\n\t\tfiles.push(file);\n\t\tObject.assign(variables, parsed.success);\n\t}\n\n\tfor (const [key, value] of Object.entries(options.env ?? processEnv())) {\n\t\tif (value !== undefined) variables[key] = value;\n\t}\n\treturn { variables, files, problems } satisfies EnvResult;\n});\n","import { basename, dirname, join, resolve } from 'node:path';\n\nimport { Effect } from 'effect';\n\nimport { findFile, isFile, searchDirectories } from './files.ts';\nimport { parseConfigFileName } from './formats/index.ts';\n\nexport type LayerKind = 'base' | 'environment' | 'local' | 'environment-local';\n\nexport interface LayerFile {\n\treadonly file: string;\n\treadonly kind: LayerKind;\n}\n\n/**\n * The layer files of a base config file, in the order they apply: `app.config.yaml`, `app.<environment>.config.yaml`,\n * `app.local.config.yaml` and `app.<environment>.local.config.yaml`. Only files that exist are listed. Environment files sit next\n * to the base file, and local files are searched next to it first, then in the nearest directory with a `package.json`.\n */\nexport const discoverLayers = Effect.fn('discoverLayers')(function* (baseFile: string, environment?: string) {\n\tconst file = resolve(baseFile);\n\tconst name = parseConfigFileName(basename(file));\n\tif (!name) return [];\n\n\tconst directories = yield* searchDirectories(file);\n\tconst layers: LayerFile[] = [];\n\tif (yield* isFile(file)) layers.push({ file, kind: 'base' });\n\tif (environment) {\n\t\tconst environmentFile = join(dirname(file), `${name.stem}.${environment}${name.suffix}`);\n\t\tif (yield* isFile(environmentFile)) layers.push({ file: environmentFile, kind: 'environment' });\n\t}\n\n\tconst local = yield* findFile(directories, `${name.stem}.local${name.suffix}`);\n\tif (local) layers.push({ file: local, kind: 'local' });\n\tif (environment) {\n\t\tconst environmentLocal = yield* findFile(directories, `${name.stem}.${environment}.local${name.suffix}`);\n\t\tif (environmentLocal) layers.push({ file: environmentLocal, kind: 'environment-local' });\n\t}\n\n\treturn layers;\n});\n","import { basename } from 'node:path';\n\nimport { isPlainObject } from './placeholders.ts';\nimport { formatPath, pathKey } from './positions.ts';\nimport { problemAt } from './problems.ts';\n\nimport type { Path, PositionMap, SourceIndex, Span } from './positions.ts';\nimport type { Problem } from './problems.ts';\n\n/**\n * A {@link Span} together with the file it is in.\n */\nexport interface LocatedSpan extends Span {\n\treadonly file: string;\n}\n\nexport interface MergeLayer {\n\treadonly file: string;\n\treadonly value: unknown;\n\treadonly positions: PositionMap;\n\treadonly source: SourceIndex;\n}\n\nexport interface MergeResult {\n\treadonly value: unknown;\n\treadonly positions: ReadonlyMap<string, LocatedSpan>;\n\treadonly problems: readonly Problem[];\n}\n\nconst kindOf = (value: unknown) => (value === null ? 'null' : Array.isArray(value) ? 'array' : typeof value);\n\nconst isWithin = (id: string, prefix: string) =>\n\tid === prefix || id.startsWith(prefix === '[]' ? '[' : `${prefix.slice(0, -1)},`);\n\nexport const locate = (file: string, positions: PositionMap): Map<string, LocatedSpan> =>\n\tnew Map([...positions].map(([id, span]) => [id, { ...span, file }]));\n\n/**\n * Applies `layer` over `base`. Objects merge, arrays and primitives replace. A key that `base` lacks, or a value of a different\n * type (`null`, boolean, number, string, array or object), is a problem and that part of the layer is skipped.\n */\nexport const mergeLayer = (\n\tbase: { readonly value: unknown; readonly positions: ReadonlyMap<string, LocatedSpan> },\n\tlayer: MergeLayer,\n): MergeResult => {\n\tconst positions = new Map(base.positions);\n\tconst problems: Problem[] = [];\n\n\tconst report = (path: Path, onKey: boolean, code: 'unknown-key' | 'type-mismatch', message: string) => {\n\t\tconst span = layer.positions.get(pathKey(path));\n\t\tconst start = span ? (onKey ? span.keyStart : span.valueStart) : 0;\n\t\tconst length = span ? (onKey ? span.keyLength : span.valueLength) : 0;\n\t\tproblems.push(problemAt(layer.source, layer.file, start, length, code, message));\n\t};\n\n\tconst origin = (path: Path) => {\n\t\tconst file = positions.get(pathKey(path))?.file;\n\t\treturn file ? basename(file) : 'the base file';\n\t};\n\n\tconst replace = (path: Path) => {\n\t\tconst prefix = pathKey(path);\n\t\tfor (const id of positions.keys()) if (isWithin(id, prefix)) positions.delete(id);\n\t\tfor (const [id, span] of layer.positions) {\n\t\t\tif (isWithin(id, prefix)) positions.set(id, { ...span, file: layer.file });\n\t\t}\n\t};\n\n\tconst merge = (current: unknown, next: unknown, path: Path): unknown => {\n\t\tif (isPlainObject(current) && isPlainObject(next)) {\n\t\t\tconst result = { ...current };\n\t\t\tfor (const [key, value] of Object.entries(next)) {\n\t\t\t\tconst childPath = [...path, key];\n\t\t\t\tif (Object.hasOwn(current, key)) result[key] = merge(current[key], value, childPath);\n\t\t\t\telse {\n\t\t\t\t\treport(\n\t\t\t\t\t\tchildPath,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t'unknown-key',\n\t\t\t\t\t\t`'${formatPath(childPath)}' is not in ${origin(path)}; environment and local files can only override existing keys`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tconst expected = kindOf(current);\n\t\tconst actual = kindOf(next);\n\t\tif (expected !== actual) {\n\t\t\treport(\n\t\t\t\tpath,\n\t\t\t\tfalse,\n\t\t\t\t'type-mismatch',\n\t\t\t\t`Expected ${expected} at '${formatPath(path) || '(root)'}' as in ${origin(path)}, got ${actual}`,\n\t\t\t);\n\t\t\treturn current;\n\t\t}\n\n\t\treplace(path);\n\t\treturn next;\n\t};\n\n\treturn { value: merge(base.value, layer.value, []), positions, problems };\n};\n","import { readFileSync } from 'node:fs';\nimport { basename, resolve } from 'node:path';\n\nimport { Effect, Result } from 'effect';\n\nimport { processEnv, readEnv } from './env.ts';\nimport { isFile } from './files.ts';\nimport { configSuffixes, parseConfigFileName } from './formats/index.ts';\nimport { discoverLayers } from './layers.ts';\nimport { locate, mergeLayer } from './merge.ts';\nimport { resolvePlaceholders } from './placeholders.ts';\nimport { SourceIndex } from './positions.ts';\nimport { fileProblem } from './problems.ts';\n\nimport type { EnvVariables } from './env.ts';\nimport type { Format } from './formats/index.ts';\nimport type { LayerKind } from './layers.ts';\nimport type { LocatedSpan } from './merge.ts';\nimport type { PositionMap } from './positions.ts';\nimport type { Problem } from './problems.ts';\n\nexport interface ResolveOptions {\n\t/**\n\t * The real environment variables, which win over every `.env` file. Defaults to a copy of the current ones.\n\t */\n\treadonly env?: EnvVariables | undefined;\n\t/**\n\t * The environment name that picks `app.<environment>.config.yaml` and `.env.<environment>`. Defaults to `env.NODE_ENV`.\n\t */\n\treadonly environment?: string | undefined;\n\t/**\n\t * The layer kinds to read. Defaults to all of them.\n\t */\n\treadonly layers?: readonly LayerKind[] | undefined;\n}\n\nexport interface ResolvedLayer {\n\treadonly file: string;\n\treadonly kind: LayerKind;\n\treadonly text: string;\n\t/**\n\t * The parsed value with placeholders resolved, or `undefined` when the file could not be parsed.\n\t */\n\treadonly value: unknown;\n\treadonly positions: PositionMap;\n}\n\nexport interface ResolvedConfig {\n\t/**\n\t * The base file, resolved to an absolute path.\n\t */\n\treadonly file: string;\n\treadonly format: Format | undefined;\n\treadonly environment: string | undefined;\n\t/**\n\t * The merged value, or `undefined` when the base file is missing or could not be parsed.\n\t */\n\treadonly value: unknown;\n\treadonly layers: readonly ResolvedLayer[];\n\treadonly envFiles: readonly string[];\n\t/**\n\t * Where each key path of `value` came from, keyed by `pathKey`.\n\t */\n\treadonly positions: ReadonlyMap<string, LocatedSpan>;\n\treadonly problems: readonly Problem[];\n}\n\nconst readText = (file: string) =>\n\tEffect.try({\n\t\ttry: () => readFileSync(file, 'utf8'),\n\t\tcatch: (error) => fileProblem(file, 'read-error', `Cannot read ${file}: ${(error as Error).message}`),\n\t});\n\n/**\n * Reads a config file with its environment and local layers and `.env` files, resolves placeholders and merges the layers.\n * Never fails: everything that went wrong is in `problems`.\n */\nexport const resolveConfig = Effect.fn('resolveConfig')(function* (path: string, options: ResolveOptions = {}) {\n\tconst file = resolve(path);\n\tconst env = options.env ?? processEnv();\n\tconst environment = options.environment ?? (env.NODE_ENV || undefined);\n\tconst name = parseConfigFileName(basename(file));\n\tconst empty = {\n\t\tfile,\n\t\tformat: name?.format,\n\t\tenvironment,\n\t\tvalue: undefined,\n\t\tlayers: [],\n\t\tenvFiles: [],\n\t\tpositions: new Map(),\n\t};\n\tif (!name) {\n\t\treturn {\n\t\t\t...empty,\n\t\t\tproblems: [\n\t\t\t\tfileProblem(\n\t\t\t\t\tfile,\n\t\t\t\t\t'unsupported-file',\n\t\t\t\t\t`${basename(file)} is not a config file; expected a name ending in ${configSuffixes.join(', ')}`,\n\t\t\t\t),\n\t\t\t],\n\t\t} satisfies ResolvedConfig;\n\t}\n\tif (!(yield* isFile(file))) {\n\t\treturn {\n\t\t\t...empty,\n\t\t\tproblems: [fileProblem(file, 'file-not-found', `Cannot find ${file}`)],\n\t\t} satisfies ResolvedConfig;\n\t}\n\n\tconst envResult = yield* readEnv(file, { environment, env });\n\tconst problems: Problem[] = [...envResult.problems];\n\tconst layers: ResolvedLayer[] = [];\n\tlet merged: { value: unknown; positions: ReadonlyMap<string, LocatedSpan> } | undefined;\n\n\tfor (const layer of yield* discoverLayers(file, environment)) {\n\t\tif (options.layers && !options.layers.includes(layer.kind)) continue;\n\t\tconst read = yield* Effect.result(readText(layer.file));\n\t\tif (Result.isFailure(read)) {\n\t\t\tproblems.push(read.failure);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst text = read.success;\n\t\tconst parsed = name.format.parse(text, layer.file);\n\t\tproblems.push(...parsed.problems);\n\t\tconst source = new SourceIndex(text);\n\t\tconst resolved =\n\t\t\tparsed.value === undefined\n\t\t\t\t? { value: undefined, problems: [] }\n\t\t\t\t: resolvePlaceholders({\n\t\t\t\t\t\tvalue: parsed.value,\n\t\t\t\t\t\tpositions: parsed.positions,\n\t\t\t\t\t\tsource,\n\t\t\t\t\t\tfile: layer.file,\n\t\t\t\t\t\tformat: name.format,\n\t\t\t\t\t\tvariables: envResult.variables,\n\t\t\t\t\t});\n\t\tproblems.push(...resolved.problems);\n\t\tlayers.push({ ...layer, text, value: resolved.value, positions: parsed.positions });\n\t\tif (resolved.value === undefined) continue;\n\n\t\tif (!merged) {\n\t\t\tmerged =\n\t\t\t\tlayer.kind === 'base'\n\t\t\t\t\t? { value: resolved.value, positions: locate(layer.file, parsed.positions) }\n\t\t\t\t\t: undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tconst result = mergeLayer(merged, {\n\t\t\tfile: layer.file,\n\t\t\tvalue: resolved.value,\n\t\t\tpositions: parsed.positions,\n\t\t\tsource,\n\t\t});\n\t\tproblems.push(...result.problems);\n\t\tmerged = result;\n\t}\n\n\treturn {\n\t\t...empty,\n\t\tenvFiles: envResult.files,\n\t\tlayers,\n\t\tvalue: merged?.value,\n\t\tpositions: merged?.positions ?? new Map(),\n\t\tproblems,\n\t} satisfies ResolvedConfig;\n});\n","import { Effect } from 'effect';\n\nimport { resolveConfig } from './resolve.ts';\n\nimport type { ResolveOptions, ResolvedConfig } from './resolve.ts';\n\n/**\n * {@link resolveConfig} for synchronous callers such as Node `registerHooks` load hooks.\n */\nexport const resolveConfigSync = (path: string, options?: ResolveOptions): ResolvedConfig =>\n\tEffect.runSync(resolveConfig(path, options));\n","import { Data } from 'effect';\n\nimport { formatProblems, pathKey, resolveConfigSync, SourceIndex } from '../core/index.ts';\n\nimport type { Path, Problem, ResolvedConfig } from '../core/index.ts';\n\n/**\n * The key of the non-enumerable {@link ConfigSource} on a config object exported by a generated server module.\n */\nexport const configSource = Symbol.for('tyfigo.source');\n\nexport interface SourcePosition {\n\treadonly file: string;\n\treadonly line: number;\n\treadonly column: number;\n}\n\nexport interface ConfigSource {\n\t/**\n\t * The base config file, as an absolute path.\n\t */\n\treadonly file: string;\n\treadonly environment: string | undefined;\n\t/**\n\t * The layer files that were merged, in the order they apply.\n\t */\n\treadonly layers: readonly string[];\n\t/**\n\t * The `.env` files that were read, in the order they apply.\n\t */\n\treadonly envFiles: readonly string[];\n\t/**\n\t * Where the value at `path` was set. A path the config does not have resolves to its nearest ancestor that it does have.\n\t */\n\treadonly position: (path: Path) => SourcePosition | undefined;\n}\n\nexport class ConfigModuleError extends Data.TaggedError('ConfigModuleError')<{\n\treadonly message: string;\n\treadonly file: string;\n\treadonly problems: readonly Problem[];\n}> {}\n\nexport interface ConfigModuleOptions {\n\t/**\n\t * The environment name that picks `app.<environment>.config.yaml` and `.env.<environment>`. Defaults to `NODE_ENV`.\n\t */\n\treadonly environment?: string | undefined;\n}\n\nexport const deepFreeze = <T>(value: T): T => {\n\tif (typeof value === 'object' && value !== null && !Object.isFrozen(value)) {\n\t\tObject.freeze(value);\n\t\tfor (const item of Object.values(value)) deepFreeze(item);\n\t}\n\treturn value;\n};\n\nexport const getConfigSource = (value: unknown): ConfigSource | undefined =>\n\ttypeof value === 'object' && value !== null\n\t\t? (value as { readonly [configSource]?: ConfigSource })[configSource]\n\t\t: undefined;\n\nconst sourceOf = (result: ResolvedConfig): ConfigSource => {\n\tconst texts = new Map(result.layers.map((layer) => [layer.file, layer.text]));\n\tconst indexes = new Map<string, SourceIndex>();\n\tconst indexOf = (file: string) => {\n\t\tconst text = texts.get(file);\n\t\tif (text === undefined) return undefined;\n\t\tconst index = indexes.get(file) ?? new SourceIndex(text);\n\t\tindexes.set(file, index);\n\t\treturn index;\n\t};\n\n\treturn {\n\t\tfile: result.file,\n\t\tenvironment: result.environment,\n\t\tlayers: result.layers.map((layer) => layer.file),\n\t\tenvFiles: result.envFiles,\n\t\tposition: (path) => {\n\t\t\tfor (let depth = path.length; depth >= 0; depth--) {\n\t\t\t\tconst span = result.positions.get(pathKey(path.slice(0, depth)));\n\t\t\t\tif (!span) continue;\n\t\t\t\tconst index = indexOf(span.file);\n\t\t\t\treturn index ? { file: span.file, ...index.lineColumn(span.valueStart) } : undefined;\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t};\n};\n\n/**\n * Resolves a config file with its layers, `.env` files and placeholders, and returns the deep-frozen value. This is what a\n * generated server module calls when it is evaluated. Throws a {@link ConfigModuleError} listing every problem.\n */\nexport const resolveConfigModule = (file: string, options: ConfigModuleOptions = {}): unknown => {\n\tconst result = resolveConfigSync(file, { environment: options.environment });\n\tif (result.problems.length > 0) {\n\t\tthrow new ConfigModuleError({\n\t\t\tmessage: `Invalid config ${result.file}\\n${formatProblems(result.problems)}`,\n\t\t\tfile: result.file,\n\t\t\tproblems: result.problems,\n\t\t});\n\t}\n\n\tif (typeof result.value === 'object' && result.value !== null) {\n\t\tObject.defineProperty(result.value, configSource, { value: sourceOf(result) });\n\t}\n\treturn deepFreeze(result.value);\n};\n"],"mappings":"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"}
@@ -1,3 +1,44 @@
1
- import { a as SourcePosition, c as getConfigSource, i as ConfigSource, l as resolveBundledConfigModule, n as ConfigModuleError, o as configSource, r as ConfigModuleOptions, s as deepFreeze, t as BundledConfig, u as resolveConfigModule } from "../resolve-BUtCDolX.mjs";
2
- import { a as loadModule, i as load, n as LoadResult, o as valueLiteral, r as LoadTarget, t as LoadOptions } from "../load-CKIE0mVT.mjs";
3
- export { BundledConfig, ConfigModuleError, ConfigModuleOptions, ConfigSource, LoadOptions, LoadResult, LoadTarget, SourcePosition, configSource, deepFreeze, getConfigSource, load, loadModule, resolveBundledConfigModule, resolveConfigModule, valueLiteral };
1
+ import { a as configSource, c as resolveConfigModule, i as SourcePosition, n as ConfigModuleOptions, o as deepFreeze, p as Problem, r as ConfigSource, s as getConfigSource, t as ConfigModuleError } from "../resolve-BeFHJeZb.mjs";
2
+ import { Effect } from "effect";
3
+ export type LoadTarget = 'server' | 'browser';
4
+ export interface LoadOptions {
5
+ /**
6
+ * `server` resolves the config when the module runs. `browser` inlines the base and environment files at build time and
7
+ * reports every placeholder as a problem.
8
+ */
9
+ readonly target: LoadTarget;
10
+ /**
11
+ * The environment name, such as the bundler's mode. Defaults to `NODE_ENV`, read when the server module runs and when
12
+ * `load` runs for the browser.
13
+ */
14
+ readonly environment?: string | undefined;
15
+ /**
16
+ * The specifier the server module imports the runtime from. Defaults to `tyfigo/runtime`.
17
+ */
18
+ readonly runtime?: string | undefined;
19
+ }
20
+ export interface LoadResult {
21
+ /**
22
+ * The JavaScript module, with the config as its default export.
23
+ */
24
+ readonly code: string;
25
+ /**
26
+ * Every file whose creation, change or removal changes the module, whether or not it exists now.
27
+ */
28
+ readonly watchFiles: readonly string[];
29
+ readonly problems: readonly Problem[];
30
+ }
31
+ /**
32
+ * Generates the JavaScript module for a config file import. Loaders fail the import or build when `problems` is not empty.
33
+ */
34
+ export declare const loadModule: (path: string, options: LoadOptions) => Effect.Effect<{
35
+ code: string;
36
+ watchFiles: string[];
37
+ problems: Problem[];
38
+ }, never, never>;
39
+ /**
40
+ * {@link loadModule} for synchronous callers such as Node `registerHooks` load hooks.
41
+ */
42
+ export declare const load: (path: string, options: LoadOptions) => LoadResult;
43
+ export { ConfigModuleError, ConfigModuleOptions, ConfigSource, SourcePosition, configSource, deepFreeze, getConfigSource, resolveConfigModule };
44
+ //# sourceMappingURL=index.d.mts.map
@@ -1,4 +1,99 @@
1
- import { a as resolveBundledConfigModule, i as getConfigSource, n as configSource, o as resolveConfigModule, r as deepFreeze, t as ConfigModuleError } from "../resolve-hzoKURuJ.mjs";
2
- import { n as loadModule, r as valueLiteral, t as load } from "../load-BqGJgpfo.mjs";
3
- import "../runtime-la_KkjCS.mjs";
4
- export { ConfigModuleError, configSource, deepFreeze, getConfigSource, load, loadModule, resolveBundledConfigModule, resolveConfigModule, valueLiteral };
1
+ import { a as resolveConfigModule, c as processEnv, d as searchDirectories, i as getConfigSource, n as configSource, o as resolveConfig, r as deepFreeze, s as envFileNames, t as ConfigModuleError, u as isFile } from "../resolve-CDWA58rz.mjs";
2
+ import { a as parseConfigFileName, c as pathKey, d as problemAt, i as configSuffixes, l as fileProblem, n as isPlainObject, o as SourceIndex, s as formatPath, t as hasPlaceholder, u as formatProblems } from "../placeholders-MqW2KO9Z.mjs";
3
+ import { Effect } from "effect";
4
+ import { basename, dirname, join, resolve } from "node:path";
5
+ // src/runtime/load.ts
6
+ const browserLayers = ["base", "environment"];
7
+ const watchFilesOf = Effect.fn("watchFilesOf")(function* (file, environment, target) {
8
+ const name = parseConfigFileName(basename(file));
9
+ if (!name) return [file];
10
+ const files = [file];
11
+ if (environment) files.push(join(dirname(file), `${name.stem}.${environment}${name.suffix}`));
12
+ if (target === "browser") return files;
13
+ const directories = yield* searchDirectories(file);
14
+ const locals = environment ? [`${name.stem}.local${name.suffix}`, `${name.stem}.${environment}.local${name.suffix}`] : [`${name.stem}.local${name.suffix}`];
15
+ for (const fileName of [...locals, ...envFileNames(environment)]) for (const directory of directories) files.push(join(directory, fileName));
16
+ return files;
17
+ });
18
+ const literal = (value, indent) => {
19
+ if (value === void 0) return "undefined";
20
+ if (typeof value === "number") return Object.is(value, -0) ? "-0" : String(value);
21
+ if (typeof value === "bigint") return `${value}n`;
22
+ if (value instanceof Date) return `new Date(${literal(value.getTime(), indent)})`;
23
+ const inner = `${indent}\t`;
24
+ if (Array.isArray(value)) {
25
+ if (value.length === 0) return "Object.freeze([])";
26
+ return `Object.freeze([\n${value.map((item) => `${inner}${literal(item, inner)},\n`).join("")}${indent}])`;
27
+ }
28
+ if (isPlainObject(value)) {
29
+ const entries = Object.entries(value);
30
+ if (entries.length === 0) return "Object.freeze({})";
31
+ return `Object.freeze({\n${entries.map(([key, item]) => {
32
+ const name = key === "__proto__" ? `[${JSON.stringify(key)}]` : JSON.stringify(key);
33
+ return `${inner}${name}: ${literal(item, inner)},\n`;
34
+ }).join("")}${indent}})`;
35
+ }
36
+ return JSON.stringify(value);
37
+ };
38
+ const hasUnescapedPlaceholder = (text) => hasPlaceholder(text.replaceAll("$${", ""));
39
+ const placeholderProblems = (file, text, value, positions) => {
40
+ const source = new SourceIndex(text);
41
+ const problems = [];
42
+ const visit = (item, path) => {
43
+ if (typeof item === "string") {
44
+ if (!hasUnescapedPlaceholder(item)) return;
45
+ const span = positions.get(pathKey(path));
46
+ problems.push(problemAt(source, file, span?.valueStart ?? 0, span?.valueLength ?? 0, "browser-placeholder", `'${formatPath(path) || "(root)"}' uses an environment placeholder, which browser builds cannot read`));
47
+ } else if (Array.isArray(item)) for (const [index, child] of item.entries()) visit(child, [...path, index]);
48
+ else if (isPlainObject(item)) for (const [key, child] of Object.entries(item)) visit(child, [...path, key]);
49
+ };
50
+ visit(value, []);
51
+ return problems;
52
+ };
53
+ const failingCode = (file, problems) => `throw new Error(${JSON.stringify(`Invalid config ${file}\n${formatProblems(problems)}`)});\n\nexport default undefined;\n`;
54
+ const serverModule = Effect.fn("serverModule")(function* (file, options) {
55
+ const problems = [];
56
+ if (!parseConfigFileName(basename(file))) problems.push(fileProblem(file, "unsupported-file", `${basename(file)} is not a config file; expected a name ending in ${configSuffixes.join(", ")}`));
57
+ else if (!(yield* isFile(file))) problems.push(fileProblem(file, "file-not-found", `Cannot find ${file}`));
58
+ const settings = options.environment === void 0 ? "" : `, { environment: ${JSON.stringify(options.environment)} }`;
59
+ const code = `import { resolveConfigModule } from ${JSON.stringify(options.runtime ?? "tyfigo/runtime")};\n\nexport default resolveConfigModule(${JSON.stringify(file)}${settings});\n`;
60
+ const environment = options.environment ?? (processEnv().NODE_ENV || void 0);
61
+ return {
62
+ code,
63
+ watchFiles: yield* watchFilesOf(file, environment, "server"),
64
+ problems
65
+ };
66
+ });
67
+ const browserModule = Effect.fn("browserModule")(function* (file, options) {
68
+ const environment = options.environment ?? (processEnv().NODE_ENV || void 0);
69
+ const result = yield* resolveConfig(file, {
70
+ environment,
71
+ env: {},
72
+ layers: browserLayers
73
+ });
74
+ const files = /* @__PURE__ */ new Set([result.file, ...result.layers.map((layer) => layer.file)]);
75
+ const problems = result.problems.filter((problem) => files.has(problem.file) && problem.code !== "missing-variable" && problem.code !== "invalid-placeholder");
76
+ for (const layer of result.layers) {
77
+ const parsed = result.format?.parse(layer.text, layer.file);
78
+ if (parsed?.value !== void 0) problems.push(...placeholderProblems(layer.file, layer.text, parsed.value, layer.positions));
79
+ }
80
+ return {
81
+ code: problems.length > 0 ? failingCode(result.file, problems) : `export default ${literal(result.value, "")};\n`,
82
+ watchFiles: yield* watchFilesOf(result.file, environment, "browser"),
83
+ problems
84
+ };
85
+ });
86
+ /**
87
+ * Generates the JavaScript module for a config file import. Loaders fail the import or build when `problems` is not empty.
88
+ */
89
+ const loadModule = Effect.fn("loadModule")(function* (path, options) {
90
+ const file = resolve(path);
91
+ return options.target === "browser" ? yield* browserModule(file, options) : yield* serverModule(file, options);
92
+ });
93
+ /**
94
+ * {@link loadModule} for synchronous callers such as Node `registerHooks` load hooks.
95
+ */
96
+ const load = (path, options) => Effect.runSync(loadModule(path, options));
97
+ export { ConfigModuleError, configSource, deepFreeze, getConfigSource, load, loadModule, resolveConfigModule };
98
+
99
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/runtime/load.ts"],"sourcesContent":["import { basename, dirname, join, resolve } from 'node:path';\n\nimport { Effect } from 'effect';\n\nimport { isFile, searchDirectories } from '../core/files.ts';\nimport {\n\tconfigSuffixes,\n\tenvFileNames,\n\tfileProblem,\n\tformatPath,\n\tformatProblems,\n\thasPlaceholder,\n\tisPlainObject,\n\tparseConfigFileName,\n\tpathKey,\n\tproblemAt,\n\tprocessEnv,\n\tresolveConfig,\n\tSourceIndex,\n} from '../core/index.ts';\n\nimport type { Path, PositionMap, Problem } from '../core/index.ts';\n\nexport type LoadTarget = 'server' | 'browser';\n\nexport interface LoadOptions {\n\t/**\n\t * `server` resolves the config when the module runs. `browser` inlines the base and environment files at build time and\n\t * reports every placeholder as a problem.\n\t */\n\treadonly target: LoadTarget;\n\t/**\n\t * The environment name, such as the bundler's mode. Defaults to `NODE_ENV`, read when the server module runs and when\n\t * `load` runs for the browser.\n\t */\n\treadonly environment?: string | undefined;\n\t/**\n\t * The specifier the server module imports the runtime from. Defaults to `tyfigo/runtime`.\n\t */\n\treadonly runtime?: string | undefined;\n}\n\nexport interface LoadResult {\n\t/**\n\t * The JavaScript module, with the config as its default export.\n\t */\n\treadonly code: string;\n\t/**\n\t * Every file whose creation, change or removal changes the module, whether or not it exists now.\n\t */\n\treadonly watchFiles: readonly string[];\n\treadonly problems: readonly Problem[];\n}\n\nconst browserLayers = ['base', 'environment'] as const;\n\nconst watchFilesOf = Effect.fn('watchFilesOf')(function* (\n\tfile: string,\n\tenvironment: string | undefined,\n\ttarget: LoadTarget,\n) {\n\tconst name = parseConfigFileName(basename(file));\n\tif (!name) return [file];\n\n\tconst files = [file];\n\tif (environment) files.push(join(dirname(file), `${name.stem}.${environment}${name.suffix}`));\n\tif (target === 'browser') return files;\n\n\tconst directories = yield* searchDirectories(file);\n\tconst locals = environment\n\t\t? [`${name.stem}.local${name.suffix}`, `${name.stem}.${environment}.local${name.suffix}`]\n\t\t: [`${name.stem}.local${name.suffix}`];\n\tfor (const fileName of [...locals, ...envFileNames(environment)]) {\n\t\tfor (const directory of directories) files.push(join(directory, fileName));\n\t}\n\treturn files;\n});\n\nconst literal = (value: unknown, indent: string): string => {\n\tif (value === undefined) return 'undefined';\n\tif (typeof value === 'number') return Object.is(value, -0) ? '-0' : String(value);\n\tif (typeof value === 'bigint') return `${value}n`;\n\tif (value instanceof Date) return `new Date(${literal(value.getTime(), indent)})`;\n\tconst inner = `${indent}\\t`;\n\tif (Array.isArray(value)) {\n\t\tif (value.length === 0) return 'Object.freeze([])';\n\t\tconst items = value.map((item) => `${inner}${literal(item, inner)},\\n`);\n\t\treturn `Object.freeze([\\n${items.join('')}${indent}])`;\n\t}\n\tif (isPlainObject(value)) {\n\t\tconst entries = Object.entries(value);\n\t\tif (entries.length === 0) return 'Object.freeze({})';\n\t\tconst properties = entries.map(([key, item]) => {\n\t\t\tconst name = key === '__proto__' ? `[${JSON.stringify(key)}]` : JSON.stringify(key);\n\t\t\treturn `${inner}${name}: ${literal(item, inner)},\\n`;\n\t\t});\n\t\treturn `Object.freeze({\\n${properties.join('')}${indent}})`;\n\t}\n\treturn JSON.stringify(value);\n};\n\nconst hasUnescapedPlaceholder = (text: string) => hasPlaceholder(text.replaceAll('$${', ''));\n\nconst placeholderProblems = (file: string, text: string, value: unknown, positions: PositionMap) => {\n\tconst source = new SourceIndex(text);\n\tconst problems: Problem[] = [];\n\tconst visit = (item: unknown, path: Path) => {\n\t\tif (typeof item === 'string') {\n\t\t\tif (!hasUnescapedPlaceholder(item)) return;\n\t\t\tconst span = positions.get(pathKey(path));\n\t\t\tproblems.push(\n\t\t\t\tproblemAt(\n\t\t\t\t\tsource,\n\t\t\t\t\tfile,\n\t\t\t\t\tspan?.valueStart ?? 0,\n\t\t\t\t\tspan?.valueLength ?? 0,\n\t\t\t\t\t'browser-placeholder',\n\t\t\t\t\t`'${formatPath(path) || '(root)'}' uses an environment placeholder, which browser builds cannot read`,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (Array.isArray(item)) for (const [index, child] of item.entries()) visit(child, [...path, index]);\n\t\telse if (isPlainObject(item)) for (const [key, child] of Object.entries(item)) visit(child, [...path, key]);\n\t};\n\tvisit(value, []);\n\treturn problems;\n};\n\nconst failingCode = (file: string, problems: readonly Problem[]) =>\n\t`throw new Error(${JSON.stringify(`Invalid config ${file}\\n${formatProblems(problems)}`)});\\n\\nexport default undefined;\\n`;\n\nconst serverModule = Effect.fn('serverModule')(function* (file: string, options: LoadOptions) {\n\tconst problems: Problem[] = [];\n\tif (!parseConfigFileName(basename(file))) {\n\t\tproblems.push(\n\t\t\tfileProblem(\n\t\t\t\tfile,\n\t\t\t\t'unsupported-file',\n\t\t\t\t`${basename(file)} is not a config file; expected a name ending in ${configSuffixes.join(', ')}`,\n\t\t\t),\n\t\t);\n\t} else if (!(yield* isFile(file))) problems.push(fileProblem(file, 'file-not-found', `Cannot find ${file}`));\n\n\tconst settings =\n\t\toptions.environment === undefined ? '' : `, { environment: ${JSON.stringify(options.environment)} }`;\n\tconst code = `import { resolveConfigModule } from ${JSON.stringify(options.runtime ?? 'tyfigo/runtime')};\\n\\nexport default resolveConfigModule(${JSON.stringify(file)}${settings});\\n`;\n\tconst environment = options.environment ?? (processEnv().NODE_ENV || undefined);\n\treturn { code, watchFiles: yield* watchFilesOf(file, environment, 'server'), problems } satisfies LoadResult;\n});\n\nconst browserModule = Effect.fn('browserModule')(function* (file: string, options: LoadOptions) {\n\tconst environment = options.environment ?? (processEnv().NODE_ENV || undefined);\n\tconst result = yield* resolveConfig(file, { environment, env: {}, layers: browserLayers });\n\tconst files = new Set([result.file, ...result.layers.map((layer) => layer.file)]);\n\tconst problems = result.problems.filter(\n\t\t(problem) =>\n\t\t\tfiles.has(problem.file) && problem.code !== 'missing-variable' && problem.code !== 'invalid-placeholder',\n\t);\n\tfor (const layer of result.layers) {\n\t\tconst parsed = result.format?.parse(layer.text, layer.file);\n\t\tif (parsed?.value !== undefined) {\n\t\t\tproblems.push(...placeholderProblems(layer.file, layer.text, parsed.value, layer.positions));\n\t\t}\n\t}\n\n\tconst code =\n\t\tproblems.length > 0 ? failingCode(result.file, problems) : `export default ${literal(result.value, '')};\\n`;\n\treturn {\n\t\tcode,\n\t\twatchFiles: yield* watchFilesOf(result.file, environment, 'browser'),\n\t\tproblems,\n\t} satisfies LoadResult;\n});\n\n/**\n * Generates the JavaScript module for a config file import. Loaders fail the import or build when `problems` is not empty.\n */\nexport const loadModule = Effect.fn('loadModule')(function* (path: string, options: LoadOptions) {\n\tconst file = resolve(path);\n\treturn options.target === 'browser' ? yield* browserModule(file, options) : yield* serverModule(file, options);\n});\n\n/**\n * {@link loadModule} for synchronous callers such as Node `registerHooks` load hooks.\n */\nexport const load = (path: string, options: LoadOptions): LoadResult => Effect.runSync(loadModule(path, options));\n"],"mappings":"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"}
@@ -1,6 +1,5 @@
1
- import { a as readEnv, i as processEnv } from "./resolve-B7e2uGDa.mjs";
1
+ import { c as processEnv, i as getConfigSource, l as readEnv } from "./resolve-CDWA58rz.mjs";
2
2
  import { s as formatPath } from "./placeholders-MqW2KO9Z.mjs";
3
- import { i as getConfigSource } from "./resolve-hzoKURuJ.mjs";
4
3
  import { Data, Effect, Schema, SchemaIssue } from "effect";
5
4
  import { join } from "node:path";
6
5
  import process from "node:process";
@@ -87,4 +86,4 @@ const decodeEnv = Effect.fn("decodeEnv")(function* (schema, options) {
87
86
  });
88
87
  export { decodeConfig as n, decodeEnv as r, ConfigValidationError as t };
89
88
 
90
- //# sourceMappingURL=schema-C_damFGy.mjs.map
89
+ //# sourceMappingURL=schema-C31aywfc.mjs.map