tyfigo 0.1.0-next.ffecb89.0 → 0.1.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 (2) hide show
  1. package/README.md +182 -3
  2. package/package.json +14 -2
package/README.md CHANGED
@@ -2,24 +2,203 @@
2
2
 
3
3
  # tyfigo
4
4
 
5
- **Import YAML, TOML, JSON5, INI and .env files into TypeScript with full type inference.**
5
+ **Typed, validated application config for TypeScript.**
6
6
 
7
7
  [![GitHub](https://img.shields.io/github/license/imranbarbhuiya/tyfigo)](https://github.com/imranbarbhuiya/tyfigo/blob/main/LICENSE)
8
8
  [![npm](https://img.shields.io/npm/v/tyfigo?color=crimson&logo=npm&style=flat-square)](https://www.npmjs.com/package/tyfigo)
9
9
 
10
10
  </div>
11
11
 
12
- > [!WARNING]
13
- > tyfigo is in early development and not usable yet.
12
+ `import config from './app.config.yaml'` gives you the config for the current environment: the base file merged with
13
+ `app.<env>.config.yaml` and your local overrides, `${PLACEHOLDERS}` filled in from `.env` files and the real environment, and
14
+ the result deep-frozen. The type comes from the file through a TypeScript 7.1 content mapper that runs inside `tsc` and the
15
+ editor, so there is no codegen step, and a wrong key or value in any layer is reported at its line in the config file. Add a
16
+ Standard Schema (Zod, Valibot, ArkType, …) or an Effect Schema when you need ranges, URLs, enums or required variables.
14
17
 
15
18
  Read the documentation at [tyfigo.vercel.app](https://tyfigo.vercel.app).
16
19
 
17
20
  ## Install
18
21
 
22
+ tyfigo needs TypeScript 7.1, the first release with content mappers, and Node 24 or later (or Bun).
23
+
19
24
  ```bash
20
25
  npm i tyfigo
26
+ npm i -D typescript@7.1.0-beta
27
+ ```
28
+
29
+ ## Register the content mapper
30
+
31
+ ```jsonc
32
+ // tsconfig.json
33
+ {
34
+ "compilerOptions": {
35
+ "module": "nodenext",
36
+ "strict": true,
37
+ "noEmit": true,
38
+ "allowImportingTsExtensions": true,
39
+ "skipLibCheck": true,
40
+ "types": ["node"],
41
+ },
42
+ "contentMappers": [
43
+ {
44
+ "package": "tyfigo",
45
+ "extensions": [
46
+ ".config.yaml",
47
+ ".config.yml",
48
+ ".config.toml",
49
+ ".config.jsonc",
50
+ ".config.json5",
51
+ ".config.ini",
52
+ ".config.properties",
53
+ ".config.xml",
54
+ ],
55
+ },
56
+ ],
57
+ "include": ["src", "config"],
58
+ }
59
+ ```
60
+
61
+ `tsc` runs content mappers only with `--runExternalCode`:
62
+
63
+ ```json
64
+ {
65
+ "scripts": {
66
+ "typecheck": "tsc --noEmit --runExternalCode"
67
+ }
68
+ }
69
+ ```
70
+
71
+ Including `config` makes tsc check environment and local files even when no code imports them directly. TypeScript 7 defaults `types` to `[]`, so list `node` (or `bun`) yourself. `skipLibCheck` keeps tsc from checking the bundler types that the plugin declarations reference, which you only have installed for the bundler you use.
72
+
73
+ ## Example
74
+
75
+ ```yaml
76
+ # config/app.config.yaml
77
+ server:
78
+ host: localhost
79
+ port: ${PORT:-3000}
80
+ database:
81
+ url: ${DATABASE_URL}
82
+ pool:
83
+ max: 5
84
+ features: [search]
85
+ ```
86
+
87
+ ```yaml
88
+ # config/app.production.config.yaml
89
+ server:
90
+ port: 8080
91
+ hostname: 0.0.0.0
92
+ database:
93
+ pool:
94
+ max: twenty
95
+ features: [search, 42]
96
+ ```
97
+
98
+ ```ts
99
+ // src/main.ts
100
+ import config from '../config/app.config.yaml';
101
+
102
+ const port: string = config.server.port;
103
+ ```
104
+
105
+ The type of `config` comes from the base file, widened so other environments can change values:
106
+
107
+ ```ts
108
+ // const config: {
109
+ // readonly server: { readonly host: string; readonly port: number };
110
+ // readonly database: { readonly url: string; readonly pool: { readonly max: number } };
111
+ // readonly features: readonly string[];
112
+ // }
113
+ ```
114
+
115
+ and `tsc --noEmit --runExternalCode` reports each mistake at its line in the YAML or the code:
116
+
117
+ ```txt
118
+ config/app.production.config.yaml(3,5): error TS2353: Object literal may only specify known properties, and 'hostname' does not exist in type '{ readonly host?: string | undefined; readonly port?: number | undefined; }'.
119
+ config/app.production.config.yaml(6,9): error TS2322: Type 'string' is not assignable to type 'number'.
120
+ config/app.production.config.yaml(7,20): error TS2322: Type 'number' is not assignable to type 'string'.
121
+ src/main.ts(3,7): error TS2322: Type 'number' is not assignable to type 'string'.
21
122
  ```
22
123
 
124
+ `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
+ with `Environment variable 'DATABASE_URL' is not set (missing-variable)`.
126
+
127
+ Layers are read in this order, each one winning over the last: `app.config.yaml`, `app.<env>.config.yaml`,
128
+ `app.local.config.yaml`, `app.<env>.local.config.yaml`. The environment is `NODE_ENV` unless you pass `environment`.
129
+ Placeholders (`${VAR}`, `${VAR:-default}`, `${VAR:?message}`) read `.env`, `.env.local`, `.env.<env>` and `.env.<env>.local`,
130
+ with real environment variables on top. tyfigo never writes `process.env`.
131
+
132
+ ## Schemas
133
+
134
+ `loadConfig` validates a config import and `loadEnv` validates environment variables, with any Standard Schema or an Effect
135
+ Schema. Errors list every issue with the `file:line:column` the value came from.
136
+
137
+ ```ts
138
+ import { loadConfig, loadEnv } from 'tyfigo';
139
+ import { z } from 'zod';
140
+
141
+ import config from '../config/app.config.yaml';
142
+
143
+ const Config = z.object({
144
+ server: z.object({ host: z.string(), port: z.number().int().positive() }),
145
+ database: z.object({ url: z.url({ protocol: /^postgres$/ }) }),
146
+ });
147
+
148
+ const settings = loadConfig(config, Config);
149
+ const env = loadEnv(z.object({ NODE_ENV: z.enum(['development', 'production', 'test']).default('development') }));
150
+ ```
151
+
152
+ `loadConfigAsync` and `loadEnvAsync` take async schemas.
153
+
154
+ ## Effect
155
+
156
+ `tyfigo/effect` has the same loaders returning Effects that fail with a typed `ConfigError`, plus `ConfigService`, layers and a
157
+ `ConfigProvider` that reads a config file. See [Effect](https://tyfigo.vercel.app/docs/effect).
158
+
159
+ ## Runtimes and bundlers
160
+
161
+ | Target | Setup | Example |
162
+ | ---------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
163
+ | Node 24+ | `node --import tyfigo/register src/main.ts` | [node](https://github.com/imranbarbhuiya/tyfigo/tree/main/examples/node) |
164
+ | Bun | `preload = ["tyfigo/bun"]` in `bunfig.toml`; `plugins: [tyfigo()]` from `tyfigo/bun` in `Bun.build` | [bun](https://github.com/imranbarbhuiya/tyfigo/tree/main/examples/bun) |
165
+ | nub | `"preload": ["tyfigo/register"]` in `nub.jsonc` | [nub](https://github.com/imranbarbhuiya/tyfigo/tree/main/examples/nub) |
166
+ | Vite and Vitest | `plugins: [tyfigo()]` from `tyfigo/vite` | [vite](https://github.com/imranbarbhuiya/tyfigo/tree/main/examples/vite) |
167
+ | Next.js (webpack, Turbopack) | `export default withTyfigo({})` from `tyfigo/next` | [next](https://github.com/imranbarbhuiya/tyfigo/tree/main/examples/next) |
168
+ | esbuild and tsup | `plugins: [tyfigo()]` (tsup: `esbuildPlugins`) from `tyfigo/esbuild` | [esbuild](https://github.com/imranbarbhuiya/tyfigo/tree/main/examples/esbuild) |
169
+ | Rollup | `plugins: [tyfigo({ target: 'server' })]` from `tyfigo/rollup` (defaults to browser) | |
170
+ | Rolldown and tsdown | `plugins: [tyfigo()]` from `tyfigo/rolldown` | |
171
+ | webpack | `plugins: [tyfigo()]` from `tyfigo/webpack` | [webpack](https://github.com/imranbarbhuiya/tyfigo/tree/main/examples/webpack) |
172
+ | Rspack and Rsbuild | `plugins: [tyfigo()]` from `tyfigo/rspack` or `tyfigo/rsbuild` | [rspack](https://github.com/imranbarbhuiya/tyfigo/tree/main/examples/rspack) |
173
+ | 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
+
175
+ 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 fix the environment when they build: they inline the base, environment and local files, ignore
177
+ `NODE_ENV` at run time for picking layers, and read `.env` files and environment variables when they start. See
178
+ [Browser builds](https://tyfigo.vercel.app/docs/browser-builds).
179
+
180
+ ## Formats
181
+
182
+ tyfigo reads seven formats under eight suffixes, since YAML takes both `.config.yaml` and `.config.yml`.
183
+
184
+ | Suffix | Format |
185
+ | ----------------------------- | ------------- |
186
+ | `.config.yaml`, `.config.yml` | YAML |
187
+ | `.config.toml` | TOML |
188
+ | `.config.jsonc` | JSONC |
189
+ | `.config.json5` | JSON5 |
190
+ | `.config.ini` | INI |
191
+ | `.config.properties` | `.properties` |
192
+ | `.config.xml` | XML |
193
+
194
+ ## tyfigo and Motherload
195
+
196
+ [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 only claims `*.config.*` files and is for the settings your app reads at start-up: widened
198
+ types, layered environment files checked against the base, placeholders and schema validation. They can share a project,
199
+ since TypeScript gives each extension one owner and the longest suffix wins, so tyfigo can own `.config.yaml` while
200
+ Motherload owns `.yaml`. See [tyfigo and Motherload](https://tyfigo.vercel.app/docs#tyfigo-and-motherload).
201
+
23
202
  ## Buy me some doughnuts
24
203
 
25
204
  If you want to support me by donating, you can do so by using any of the following methods. Thank you very much in advance!
package/package.json CHANGED
@@ -1,16 +1,28 @@
1
1
  {
2
2
  "name": "tyfigo",
3
- "version": "0.1.0-next.ffecb89.0",
4
- "description": "Import YAML, TOML, JSON5, INI and .env files into TypeScript with full type inference",
3
+ "version": "0.1.0",
4
+ "description": "Typed, validated application config for TypeScript: import layered YAML, TOML, JSONC, JSON5, INI, .properties and XML config files, typed by a TypeScript 7.1 content mapper",
5
5
  "keywords": [
6
6
  "config",
7
+ "configuration",
7
8
  "content-mapper",
8
9
  "dotenv",
9
10
  "effect",
11
+ "env",
12
+ "esbuild",
10
13
  "ini",
11
14
  "json5",
15
+ "jsonc",
16
+ "nextjs",
17
+ "properties",
18
+ "rollup",
19
+ "rspack",
20
+ "standard-schema",
12
21
  "toml",
13
22
  "typescript",
23
+ "vite",
24
+ "webpack",
25
+ "xml",
14
26
  "yaml"
15
27
  ],
16
28
  "homepage": "https://tyfigo.vercel.app",