tyfigo 0.2.0-next.a30eb96.0 → 0.2.1
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.
- package/README.md +28 -4
- package/dist/bun.d.mts +8 -1
- package/dist/bun.mjs +7 -7
- package/dist/bun.mjs.map +1 -1
- package/dist/effect.mjs +2 -2
- package/dist/{env-Bd-1Atoz.mjs → env--pSRlq_k.mjs} +2 -2
- package/dist/{env-Bd-1Atoz.mjs.map → env--pSRlq_k.mjs.map} +1 -1
- package/dist/env-Dv5OHfEf.mjs +51 -0
- package/dist/env-Dv5OHfEf.mjs.map +1 -0
- package/dist/{formats-D_dKXoPf.mjs → formats-Bf8-iQw-.mjs} +43 -15
- package/dist/{formats-D_dKXoPf.mjs.map → formats-Bf8-iQw-.mjs.map} +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{load-C-kweoyY.d.mts → load-D1KO5LdK.d.mts} +6 -4
- package/dist/{load-DxIjRpX6.mjs → load-yFCdP4to.mjs} +49 -23
- package/dist/load-yFCdP4to.mjs.map +1 -0
- package/dist/mapper.mjs +28 -11
- package/dist/mapper.mjs.map +1 -1
- package/dist/plugins/esbuild.d.mts +2 -2
- package/dist/plugins/esbuild.mjs +1 -1
- package/dist/plugins/jest.d.mts +1 -1
- package/dist/plugins/jest.mjs +4 -4
- package/dist/plugins/loader.d.mts +1 -1
- package/dist/plugins/loader.mjs +3 -2
- package/dist/plugins/loader.mjs.map +1 -1
- package/dist/plugins/next.d.mts +1 -1
- package/dist/plugins/next.mjs +9 -4
- package/dist/plugins/next.mjs.map +1 -1
- package/dist/plugins/rolldown.d.mts +2 -2
- package/dist/plugins/rolldown.mjs +1 -1
- package/dist/plugins/rollup.d.mts +2 -2
- package/dist/plugins/rollup.mjs +1 -1
- package/dist/plugins/rsbuild.d.mts +2 -2
- package/dist/plugins/rsbuild.mjs +1 -1
- package/dist/plugins/rspack.d.mts +2 -2
- package/dist/plugins/rspack.mjs +1 -1
- package/dist/plugins/vite.d.mts +2 -2
- package/dist/plugins/vite.mjs +1 -1
- package/dist/plugins/webpack.d.mts +2 -2
- package/dist/plugins/webpack.mjs +1 -1
- package/dist/problems-DS_eJB6e.mjs +86 -0
- package/dist/problems-DS_eJB6e.mjs.map +1 -0
- package/dist/register.mjs +5 -5
- package/dist/register.mjs.map +1 -1
- package/dist/{resolve-D3geHCGs.mjs → resolve-DQfTdYJN.mjs} +32 -12
- package/dist/resolve-DQfTdYJN.mjs.map +1 -0
- package/dist/runtime/index.d.mts +13 -4
- package/dist/runtime/index.mjs +2 -2
- package/dist/{runtime-DeRUtPZ9.mjs → runtime-B3GmIYop.mjs} +13 -9
- package/dist/runtime-B3GmIYop.mjs.map +1 -0
- package/dist/{shared-CZ44uwQq.d.mts → shared-B6Y3_kdn.d.mts} +6 -5
- package/dist/{shared-BnK77Zcp.mjs → shared-DOMPQnVO.mjs} +4 -6
- package/dist/shared-DOMPQnVO.mjs.map +1 -0
- package/dist/{sync-B-HAK-_E.mjs → sync-mWkXcCOW.mjs} +2 -2
- package/dist/{sync-B-HAK-_E.mjs.map → sync-mWkXcCOW.mjs.map} +1 -1
- package/dist/unplugin-BYfqHkIE.d.mts +2 -0
- package/dist/{unplugin-BQGm_bhA.mjs → unplugin-BoZ7PwTA.mjs} +36 -13
- package/dist/unplugin-BoZ7PwTA.mjs.map +1 -0
- package/package.json +2 -2
- package/dist/env-R3_XPW_u.mjs +0 -78
- package/dist/env-R3_XPW_u.mjs.map +0 -1
- package/dist/load-DxIjRpX6.mjs.map +0 -1
- package/dist/problems-BNAqmOzL.mjs +0 -23
- package/dist/problems-BNAqmOzL.mjs.map +0 -1
- package/dist/resolve-D3geHCGs.mjs.map +0 -1
- package/dist/runtime-DeRUtPZ9.mjs.map +0 -1
- package/dist/shared-BnK77Zcp.mjs.map +0 -1
- package/dist/unplugin-AC_HM_T2.d.mts +0 -2
- package/dist/unplugin-BQGm_bhA.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -121,6 +121,11 @@ config/app.production.config.yaml(7,20): error TS2322: Type 'number' is not assi
|
|
|
121
121
|
src/main.ts(3,7): error TS2322: Type 'number' is not assignable to type 'string'.
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
+
Without a schema, the types are strict and widened: an environment file can't add a key (so there are no optional sections),
|
|
125
|
+
`logLevel: info` is `string` rather than `'info' | 'debug'`, a placeholder without a default is `string`, and a `loadConfig`
|
|
126
|
+
mismatch is reported at the call rather than on the YAML line. A schema handles each of these; see
|
|
127
|
+
[What tsc checks without a schema](https://tyfigo.vercel.app/docs/type-checking#what-tsc-checks-without-a-schema).
|
|
128
|
+
|
|
124
129
|
`database.url` has no default, so set `DATABASE_URL` (in `.env` or the environment) before you run the example. Without it, the import fails
|
|
125
130
|
with `Environment variable 'DATABASE_URL' is not set (missing-variable)`.
|
|
126
131
|
|
|
@@ -173,9 +178,12 @@ const env = loadEnv(z.object({ NODE_ENV: z.enum(['development', 'production', 't
|
|
|
173
178
|
| Jest | `'tyfigo/jest'` as the `transform` for config files, with their extensions in `moduleFileExtensions` | [jest](https://github.com/imranbarbhuiya/tyfigo/tree/main/examples/jest) |
|
|
174
179
|
|
|
175
180
|
Browser builds get the base and environment files inlined, and a `${VAR}` placeholder or an import of `loadEnv` in a client bundle
|
|
176
|
-
fails the build. Server bundles
|
|
177
|
-
`NODE_ENV`
|
|
178
|
-
[
|
|
181
|
+
fails the build. Server bundles are built once and deployed anywhere: they inline the base, local and every environment's
|
|
182
|
+
files, pick the layers by `NODE_ENV` when they start (unless the plugin's `environment` option fixes it), and read `.env` files
|
|
183
|
+
and environment variables then. See [Server bundles](https://tyfigo.vercel.app/docs/browser-builds#server-bundles).
|
|
184
|
+
|
|
185
|
+
`next build` can't pass `--runExternalCode` to its type check, so `withTyfigo` turns Next's check off and runs
|
|
186
|
+
`tsc --noEmit --runExternalCode` itself after the compile. See [Next.js](https://tyfigo.vercel.app/docs/bundlers/next).
|
|
179
187
|
|
|
180
188
|
## Formats
|
|
181
189
|
|
|
@@ -191,10 +199,26 @@ tyfigo reads seven formats under eight suffixes, since YAML takes both `.config.
|
|
|
191
199
|
| `.config.properties` | `.properties` |
|
|
192
200
|
| `.config.xml` | XML |
|
|
193
201
|
|
|
202
|
+
Plain `.json` isn't supported: it's a built-in TypeScript extension, so no content mapper can claim `.json`, `.config.json` or
|
|
203
|
+
`.config/<name>.json` (tsc reports `TS18066`). Rename the file to `.config.jsonc`; every JSON file is valid JSONC.
|
|
204
|
+
|
|
205
|
+
### A `.config` directory
|
|
206
|
+
|
|
207
|
+
Config files can also live in a `.config` folder with plain extensions: `.config/app.yaml` is a base file and
|
|
208
|
+
`.config/app.production.yaml`, `.config/app.local.yaml` and `.config/app.production.local.yaml` are its layers. Every runtime and
|
|
209
|
+
bundler loads them by path with no setup, and `.yaml` files elsewhere are left alone. `.env` files are read from the folder
|
|
210
|
+
that contains `.config`.
|
|
211
|
+
|
|
212
|
+
Type-checking them is opt-in: add the plain extensions you use to tyfigo's `extensions` (`".yaml"` next to the `.config.*`
|
|
213
|
+
suffixes) and include `".config/*"`. tyfigo then owns that extension, so it can't be combined with another mapper (such as
|
|
214
|
+
Motherload) for it, and every other `.yaml` file is typed as plain data, with no layers or placeholders. See
|
|
215
|
+
[A `.config` directory](https://tyfigo.vercel.app/docs/config-files#a-config-directory) and the
|
|
216
|
+
[config-dir example](https://github.com/imranbarbhuiya/tyfigo/tree/main/examples/config-dir).
|
|
217
|
+
|
|
194
218
|
## tyfigo and Motherload
|
|
195
219
|
|
|
196
220
|
[Motherload](https://motherload.dev) also imports data files through TypeScript 7.1 content mappers, but it is a general data
|
|
197
|
-
loader: import any `.yaml`, `.toml`, `.csv`, `.md` or other data file and get its contents, typed as `as const` would type them. tyfigo
|
|
221
|
+
loader: import any `.yaml`, `.toml`, `.csv`, `.md` or other data file and get its contents, typed as `as const` would type them. tyfigo claims `*.config.*` files (and, opt-in, a `.config` folder) and is for the settings your app reads at start-up: widened
|
|
198
222
|
types, layered environment files checked against the base, placeholders and schema validation. They can share a project,
|
|
199
223
|
since TypeScript gives each extension one owner and the longest suffix wins, so tyfigo can own `.config.yaml` while
|
|
200
224
|
Motherload owns `.yaml`. See [tyfigo and Motherload](https://tyfigo.vercel.app/docs#tyfigo-and-motherload).
|
package/dist/bun.d.mts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { BunPlugin } from "bun";
|
|
2
|
+
export interface TyfigoBunOptions {
|
|
3
|
+
/**
|
|
4
|
+
* The environment name. Defaults to `NODE_ENV`, read when the config loads, or when a server `Bun.build` bundle starts.
|
|
5
|
+
* Setting it fixes the environment of a server bundle.
|
|
6
|
+
*/
|
|
7
|
+
readonly environment?: string | undefined;
|
|
8
|
+
}
|
|
2
9
|
/**
|
|
3
10
|
* The tyfigo Bun plugin. Importing `tyfigo/bun` (a `bunfig.toml` `preload`) registers it for the runtime and `bun test`; pass
|
|
4
11
|
* `tyfigo()` in `plugins` to use it with `Bun.build`, where a `browser` target inlines the config and a server target inlines the config files and reads `.env` files when it runs.
|
|
5
12
|
*/
|
|
6
|
-
export declare const tyfigo: () => BunPlugin;
|
|
13
|
+
export declare const tyfigo: (options?: TyfigoBunOptions) => BunPlugin;
|
|
7
14
|
//# sourceMappingURL=bun.d.mts.map
|
package/dist/bun.mjs
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import { n as formatProblems } from "./problems-
|
|
2
|
-
import {
|
|
3
|
-
import { t as load } from "./load-
|
|
1
|
+
import { n as formatProblems } from "./problems-DS_eJB6e.mjs";
|
|
2
|
+
import { n as configPathPattern } from "./formats-Bf8-iQw-.mjs";
|
|
3
|
+
import { t as load } from "./load-yFCdP4to.mjs";
|
|
4
4
|
import { extname } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { plugin } from "bun";
|
|
7
7
|
// src/bun.ts
|
|
8
8
|
const runtime = fileURLToPath(new URL(`runtime/index${extname(import.meta.url)}`, import.meta.url));
|
|
9
|
-
const filter = new RegExp(`[^/\\\\](?:${configSuffixes.map((suffix) => suffix.replaceAll(".", "\\.")).join("|")})$`);
|
|
10
9
|
/**
|
|
11
10
|
* The tyfigo Bun plugin. Importing `tyfigo/bun` (a `bunfig.toml` `preload`) registers it for the runtime and `bun test`; pass
|
|
12
11
|
* `tyfigo()` in `plugins` to use it with `Bun.build`, where a `browser` target inlines the config and a server target inlines the config files and reads `.env` files when it runs.
|
|
13
12
|
*/
|
|
14
|
-
const tyfigo = () => ({
|
|
13
|
+
const tyfigo = (options = {}) => ({
|
|
15
14
|
name: "tyfigo",
|
|
16
15
|
setup(build) {
|
|
17
16
|
const config = build.config;
|
|
18
17
|
const target = config?.target === "browser" ? "browser" : "server";
|
|
19
|
-
build.onLoad({ filter }, ({ path }) => {
|
|
18
|
+
build.onLoad({ filter: configPathPattern }, ({ path }) => {
|
|
20
19
|
const result = load(path, {
|
|
21
20
|
target,
|
|
22
21
|
runtime,
|
|
23
|
-
bundle: config !== void 0
|
|
22
|
+
bundle: config !== void 0,
|
|
23
|
+
environment: options.environment
|
|
24
24
|
});
|
|
25
25
|
if (result.problems.length > 0) throw new Error(`Invalid config ${path}\n${formatProblems(result.problems)}`);
|
|
26
26
|
return {
|
package/dist/bun.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bun.mjs","names":[],"sources":["../src/bun.ts"],"sourcesContent":["import { extname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { plugin } from 'bun';\n\nimport {
|
|
1
|
+
{"version":3,"file":"bun.mjs","names":[],"sources":["../src/bun.ts"],"sourcesContent":["import { extname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { plugin } from 'bun';\n\nimport { configPathPattern, formatProblems } from './core/index.ts';\nimport { load } from './runtime/index.ts';\n\nimport type { BunPlugin } from 'bun';\n\n// The runtime next to this module, so it resolves from config files outside the dependency tree: `.ts` in this repo, `.mjs` once built.\nconst runtime = fileURLToPath(new URL(`runtime/index${extname(import.meta.url)}`, import.meta.url));\n\nexport interface TyfigoBunOptions {\n\t/**\n\t * The environment name. Defaults to `NODE_ENV`, read when the config loads, or when a server `Bun.build` bundle starts.\n\t * Setting it fixes the environment of a server bundle.\n\t */\n\treadonly environment?: string | undefined;\n}\n\n/**\n * The tyfigo Bun plugin. Importing `tyfigo/bun` (a `bunfig.toml` `preload`) registers it for the runtime and `bun test`; pass\n * `tyfigo()` in `plugins` to use it with `Bun.build`, where a `browser` target inlines the config and a server target inlines the config files and reads `.env` files when it runs.\n */\nexport const tyfigo = (options: TyfigoBunOptions = {}): BunPlugin => ({\n\tname: 'tyfigo',\n\tsetup(build) {\n\t\tconst config = build.config as typeof build.config | undefined;\n\t\tconst target = config?.target === 'browser' ? 'browser' : 'server';\n\t\tbuild.onLoad({ filter: configPathPattern }, ({ path }) => {\n\t\t\tconst result = load(path, {\n\t\t\t\ttarget,\n\t\t\t\truntime,\n\t\t\t\tbundle: config !== undefined,\n\t\t\t\tenvironment: options.environment,\n\t\t\t});\n\t\t\tif (result.problems.length > 0) {\n\t\t\t\tthrow new Error(`Invalid config ${path}\\n${formatProblems(result.problems)}`);\n\t\t\t}\n\t\t\treturn { contents: result.code, loader: 'js' };\n\t\t});\n\t},\n});\n\nvoid plugin(tyfigo());\n"],"mappings":";;;;;;;AAWA,MAAM,UAAU,cAAc,IAAI,IAAI,gBAAgB,QAAQ,YAAY,GAAG,KAAK,YAAY,GAAG,CAAC;;;;;AAclG,MAAa,UAAU,UAA4B,CAAC,OAAkB;CACrE,MAAM;CACN,MAAM,OAAO;EACZ,MAAM,SAAS,MAAM;EACrB,MAAM,SAAS,QAAQ,WAAW,YAAY,YAAY;EAC1D,MAAM,OAAO,EAAE,QAAQ,kBAAkB,IAAI,EAAE,WAAW;GACzD,MAAM,SAAS,KAAK,MAAM;IACzB;IACA;IACA,QAAQ,WAAW,KAAA;IACnB,aAAa,QAAQ;GACtB,CAAC;GACD,IAAI,OAAO,SAAS,SAAS,GAC5B,MAAM,IAAI,MAAM,kBAAkB,KAAK,IAAI,eAAe,OAAO,QAAQ,GAAG;GAE7E,OAAO;IAAE,UAAU,OAAO;IAAM,QAAQ;GAAK;EAC9C,CAAC;CACF;AACD;AAEK,OAAO,OAAO,CAAC"}
|
package/dist/effect.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as ConfigValidationError } from "./schema-DcD4N9N-.mjs";
|
|
2
|
-
import { t as decodeEnv } from "./env
|
|
2
|
+
import { t as decodeEnv } from "./env--pSRlq_k.mjs";
|
|
3
3
|
import { a as layerConfig, i as ConfigService, n as layerConfigProvider, o as loadConfig, r as ConfigError, t as configProvider } from "./effect.browser-CO87TEE_.mjs";
|
|
4
|
-
import { t as resolveConfig } from "./resolve-
|
|
4
|
+
import { t as resolveConfig } from "./resolve-DQfTdYJN.mjs";
|
|
5
5
|
import { ConfigProvider, Effect, Layer } from "effect";
|
|
6
6
|
// src/effect/env.ts
|
|
7
7
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as processEnv, r as readEnv } from "./env-
|
|
1
|
+
import { n as processEnv, r as readEnv } from "./env-Dv5OHfEf.mjs";
|
|
2
2
|
import { r as validate } from "./schema-DcD4N9N-.mjs";
|
|
3
3
|
import { Effect } from "effect";
|
|
4
4
|
import { join } from "node:path";
|
|
@@ -24,4 +24,4 @@ const decodeEnv = Effect.fn("decodeEnv")(function* (schema, options) {
|
|
|
24
24
|
});
|
|
25
25
|
export { decodeEnv as t };
|
|
26
26
|
|
|
27
|
-
//# sourceMappingURL=env
|
|
27
|
+
//# sourceMappingURL=env--pSRlq_k.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env
|
|
1
|
+
{"version":3,"file":"env--pSRlq_k.mjs","names":[],"sources":["../src/env.ts"],"sourcesContent":["import { join } from 'node:path';\nimport process from 'node:process';\n\nimport { Effect } from 'effect';\n\nimport { processEnv, readEnv } from './core/env.ts';\nimport { validate } from './schema.ts';\n\nimport type { ConfigSchema, LoadEnvOptions } from './schema.ts';\n\nexport const decodeEnv = Effect.fn('decodeEnv')(function* <S extends ConfigSchema>(\n\tschema: S,\n\toptions: LoadEnvOptions & { readonly async: boolean; readonly native?: boolean | undefined },\n) {\n\tconst env = options.env ?? processEnv();\n\tconst environment = options.environment ?? (env.NODE_ENV || undefined);\n\tconst result = yield* readEnv(join(options.cwd ?? process.cwd(), '.env'), { environment, env });\n\treturn yield* validate(schema, result.variables, {\n\t\tsubject: 'environment variables',\n\t\tasync: options.async,\n\t\tnative: options.native,\n\t\tissues: result.problems.map((problem) => ({\n\t\t\tpath: [],\n\t\t\tmessage: problem.message,\n\t\t\tlocation: `${problem.file}:${problem.line}:${problem.column}`,\n\t\t})),\n\t});\n});\n"],"mappings":";;;;;;AAUA,MAAa,YAAY,OAAO,GAAG,WAAW,CAAC,CAAC,WAC/C,QACA,SACC;CACD,MAAM,MAAM,QAAQ,OAAO,WAAW;CACtC,MAAM,cAAc,QAAQ,gBAAgB,IAAI,YAAY,KAAA;CAC5D,MAAM,SAAS,OAAO,QAAQ,KAAK,QAAQ,OAAO,QAAQ,IAAI,GAAG,MAAM,GAAG;EAAE;EAAa;CAAI,CAAC;CAC9F,OAAO,OAAO,SAAS,QAAQ,OAAO,WAAW;EAChD,SAAS;EACT,OAAO,QAAQ;EACf,QAAQ,QAAQ;EAChB,QAAQ,OAAO,SAAS,KAAK,aAAa;GACzC,MAAM,CAAC;GACP,SAAS,QAAQ;GACjB,UAAU,GAAG,QAAQ,KAAK,GAAG,QAAQ,KAAK,GAAG,QAAQ;EACtD,EAAE;CACH,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { a as envDirectories, o as findFile, t as fileProblem } from "./problems-DS_eJB6e.mjs";
|
|
2
|
+
import { Effect, Result } from "effect";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { readFileSync } from "node:fs";
|
|
6
|
+
import { parseEnv } from "node:util";
|
|
7
|
+
// src/core/env.ts
|
|
8
|
+
/**
|
|
9
|
+
* A copy of the real environment. This is the only place tyfigo reads `process.env`.
|
|
10
|
+
*/
|
|
11
|
+
const processEnv = () => ({ ...process.env });
|
|
12
|
+
const envFileNames = (environment) => environment ? [
|
|
13
|
+
".env",
|
|
14
|
+
".env.local",
|
|
15
|
+
`.env.${environment}`,
|
|
16
|
+
`.env.${environment}.local`
|
|
17
|
+
] : [".env", ".env.local"];
|
|
18
|
+
/**
|
|
19
|
+
* Reads `.env`, `.env.local`, `.env.<environment>` and `.env.<environment>.local` (each later one wins) and puts `env` on top.
|
|
20
|
+
* Each file is searched next to `baseFile` first (above its `.config` directory when it is in one), then in the nearest directory
|
|
21
|
+
* with a `package.json`. Never writes `process.env`.
|
|
22
|
+
*/
|
|
23
|
+
const readEnv = Effect.fn("readEnv")(function* (baseFile, options = {}) {
|
|
24
|
+
const directories = yield* envDirectories(resolve(baseFile));
|
|
25
|
+
const variables = {};
|
|
26
|
+
const files = [];
|
|
27
|
+
const problems = [];
|
|
28
|
+
for (const name of envFileNames(options.environment)) {
|
|
29
|
+
const file = yield* findFile(directories, name);
|
|
30
|
+
if (!file) continue;
|
|
31
|
+
const parsed = yield* Effect.result(Effect.try({
|
|
32
|
+
try: () => parseEnv(readFileSync(file, "utf8")),
|
|
33
|
+
catch: (error) => fileProblem(file, "read-error", `Cannot read ${file}: ${error.message}`)
|
|
34
|
+
}));
|
|
35
|
+
if (Result.isFailure(parsed)) {
|
|
36
|
+
problems.push(parsed.failure);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
files.push(file);
|
|
40
|
+
Object.assign(variables, parsed.success);
|
|
41
|
+
}
|
|
42
|
+
for (const [key, value] of Object.entries(options.env ?? processEnv())) if (value !== void 0) variables[key] = value;
|
|
43
|
+
return {
|
|
44
|
+
variables,
|
|
45
|
+
files,
|
|
46
|
+
problems
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
export { processEnv as n, readEnv as r, envFileNames as t };
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=env-Dv5OHfEf.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-Dv5OHfEf.mjs","names":[],"sources":["../src/core/env.ts"],"sourcesContent":["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 { envDirectories, findFile } 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 (above its `.config` directory when it is in one), then in the nearest directory\n * 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* envDirectories(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"],"mappings":";;;;;;;;;;AA6BA,MAAa,oBAAkC,EAAE,GAAG,QAAQ,IAAI;AAEhE,MAAa,gBAAgB,gBAC5B,cAAc;CAAC;CAAQ;CAAc,QAAQ;CAAe,QAAQ,YAAY;AAAO,IAAI,CAAC,QAAQ,YAAY;;;;;;AAOjH,MAAa,UAAU,OAAO,GAAG,SAAS,CAAC,CAAC,WAC3C,UACA,UAAkG,CAAC,GAClG;CACD,MAAM,cAAc,OAAO,eAAe,QAAQ,QAAQ,CAAC;CAC3D,MAAM,YAAgD,CAAC;CACvD,MAAM,QAAkB,CAAC;CACzB,MAAM,WAAsB,CAAC;CAC7B,KAAK,MAAM,QAAQ,aAAa,QAAQ,WAAW,GAAG;EACrD,MAAM,OAAO,OAAO,SAAS,aAAa,IAAI;EAC9C,IAAI,CAAC,MAAM;EACX,MAAM,SAAS,OAAO,OAAO,OAC5B,OAAO,IAAI;GACV,WAAW,SAAS,aAAa,MAAM,MAAM,CAAC;GAC9C,QAAQ,UAAU,YAAY,MAAM,cAAc,eAAe,KAAK,IAAK,MAAgB,SAAS;EACrG,CAAC,CACF;EACA,IAAI,OAAO,UAAU,MAAM,GAAG;GAC7B,SAAS,KAAK,OAAO,OAAO;GAC5B;EACD;EAEA,MAAM,KAAK,IAAI;EACf,OAAO,OAAO,WAAW,OAAO,OAAO;CACxC;CAEA,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,OAAO,WAAW,CAAC,GACpE,IAAI,UAAU,KAAA,GAAW,UAAU,OAAO;CAE3C,OAAO;EAAE;EAAW;EAAO;CAAS;AACrC,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { r as problemAt } from "./problems-
|
|
1
|
+
import { i as configDirectory, l as isInConfigDirectory, r as problemAt } from "./problems-DS_eJB6e.mjs";
|
|
2
2
|
import { n as formatPath, r as pathKey, t as SourceIndex } from "./positions-BCTEFZTX.mjs";
|
|
3
|
+
import { basename, extname } from "node:path";
|
|
3
4
|
import { getStaticJSONValue, parseJSON, tokenize } from "jsonc-eslint-parser";
|
|
4
5
|
import { getNodeValue, parseTree, printParseErrorCode } from "jsonc-parser";
|
|
5
6
|
import { getStaticTOMLValue, parseTOML } from "toml-eslint-parser";
|
|
@@ -874,27 +875,54 @@ const yaml = {
|
|
|
874
875
|
parseScalar
|
|
875
876
|
};
|
|
876
877
|
// src/core/formats/index.ts
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
".
|
|
882
|
-
".
|
|
883
|
-
".
|
|
884
|
-
".
|
|
885
|
-
".
|
|
886
|
-
|
|
878
|
+
/**
|
|
879
|
+
* The formats by file extension.
|
|
880
|
+
*/
|
|
881
|
+
const formatExtensions = {
|
|
882
|
+
".yaml": yaml,
|
|
883
|
+
".yml": yaml,
|
|
884
|
+
".toml": toml,
|
|
885
|
+
".jsonc": jsonc,
|
|
886
|
+
".json5": json5,
|
|
887
|
+
".ini": ini,
|
|
888
|
+
".properties": properties,
|
|
889
|
+
".xml": xml
|
|
890
|
+
};
|
|
891
|
+
const formats = Object.fromEntries(Object.entries(formatExtensions).map(([extension, format]) => [`.config${extension}`, format]));
|
|
887
892
|
const configSuffixes = Object.keys(formats);
|
|
888
893
|
/**
|
|
889
|
-
*
|
|
894
|
+
* The format of a file extension such as `.yaml`, or `undefined` when tyfigo does not read it.
|
|
890
895
|
*/
|
|
891
|
-
const
|
|
896
|
+
const formatOfExtension = (extension) => Object.hasOwn(formatExtensions, extension) ? formatExtensions[extension] : void 0;
|
|
897
|
+
/**
|
|
898
|
+
* Splits a config file path into its stem and suffix, or returns `undefined` when tyfigo does not claim it. A config file's name
|
|
899
|
+
* ends in a suffix such as `.config.yaml`, or it has a format extension such as `.yaml` and sits in a `.config` directory.
|
|
900
|
+
*/
|
|
901
|
+
const parseConfigPath = (path) => {
|
|
902
|
+
const fileName = basename(path);
|
|
892
903
|
for (const [suffix, format] of Object.entries(formats)) if (fileName.endsWith(suffix) && fileName.length > suffix.length) return {
|
|
893
904
|
stem: fileName.slice(0, -suffix.length),
|
|
894
905
|
suffix,
|
|
895
906
|
format
|
|
896
907
|
};
|
|
908
|
+
const suffix = extname(fileName);
|
|
909
|
+
const format = formatOfExtension(suffix);
|
|
910
|
+
if (!format || !isInConfigDirectory(path) || fileName.startsWith(".")) return void 0;
|
|
911
|
+
return {
|
|
912
|
+
stem: fileName.slice(0, -suffix.length),
|
|
913
|
+
suffix,
|
|
914
|
+
format
|
|
915
|
+
};
|
|
897
916
|
};
|
|
898
|
-
|
|
917
|
+
const escape = (text) => text.replaceAll(".", String.raw`\.`);
|
|
918
|
+
/**
|
|
919
|
+
* Matches the paths {@link parseConfigPath} claims, with either path separator, for loader and bundler filters.
|
|
920
|
+
*/
|
|
921
|
+
const configPathPattern = new RegExp(String.raw`(?:[^/\\](?:${configSuffixes.map(escape).join("|")})|(?:^|[/\\])${escape(configDirectory)}[/\\][^/\\.][^/\\]*(?:${Object.keys(formatExtensions).map(escape).join("|")}))$`, "u");
|
|
922
|
+
/**
|
|
923
|
+
* A short description of the files tyfigo claims, for error messages.
|
|
924
|
+
*/
|
|
925
|
+
const configFileDescription = `a name ending in ${configSuffixes.join(", ")}, or a ${Object.keys(formatExtensions).join(", ")} file in a ${configDirectory} directory`;
|
|
926
|
+
export { formatOfExtension as a, isPlainObject as c, formatExtensions as i, kindOf as l, configPathPattern as n, parseConfigPath as o, configSuffixes as r, hasPlaceholder as s, configFileDescription as t, resolvePlaceholders as u };
|
|
899
927
|
|
|
900
|
-
//# sourceMappingURL=formats-
|
|
928
|
+
//# sourceMappingURL=formats-Bf8-iQw-.mjs.map
|