c12 3.0.4 → 3.2.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.
- package/README.md +31 -39
- package/dist/index.d.mts +14 -4
- package/dist/index.mjs +2 -2
- package/dist/shared/{c12.CEGFwQZa.mjs → c12.DDjD4HmS.mjs} +23 -12
- package/dist/update.mjs +1 -1
- package/package.json +15 -15
package/README.md
CHANGED
|
@@ -27,42 +27,24 @@ c12 (pronounced as /siːtwelv/, like c-twelve) is a smart configuration loader.
|
|
|
27
27
|
## 🦴 Used by
|
|
28
28
|
|
|
29
29
|
- [Nuxt](https://nuxt.com/)
|
|
30
|
-
- [Nitro](https://nitro.
|
|
30
|
+
- [Nitro](https://nitro.build/)
|
|
31
31
|
- [Unbuild](https://unbuild.unjs.io)
|
|
32
32
|
- [Automd](https://automd.unjs.io)
|
|
33
33
|
- [Changelogen](https://changelogen.unjs.io)
|
|
34
34
|
- [RemixKit](https://github.com/jrestall/remix-kit)
|
|
35
35
|
- [Hey API](https://github.com/hey-api/openapi-ts)
|
|
36
36
|
- [kysely-ctl](https://github.com/kysely-org/kysely-ctl)
|
|
37
|
+
- [Prisma](https://github.com/prisma/prisma)
|
|
37
38
|
|
|
38
39
|
## Usage
|
|
39
40
|
|
|
40
41
|
Install package:
|
|
41
42
|
|
|
42
|
-
<!-- automd:pm-install -->
|
|
43
|
-
|
|
44
43
|
```sh
|
|
45
44
|
# ✨ Auto-detect
|
|
46
45
|
npx nypm install c12
|
|
47
|
-
|
|
48
|
-
# npm
|
|
49
|
-
npm install c12
|
|
50
|
-
|
|
51
|
-
# yarn
|
|
52
|
-
yarn add c12
|
|
53
|
-
|
|
54
|
-
# pnpm
|
|
55
|
-
pnpm install c12
|
|
56
|
-
|
|
57
|
-
# bun
|
|
58
|
-
bun install c12
|
|
59
|
-
|
|
60
|
-
# deno
|
|
61
|
-
deno install c12
|
|
62
46
|
```
|
|
63
47
|
|
|
64
|
-
<!-- /automd -->
|
|
65
|
-
|
|
66
48
|
Import:
|
|
67
49
|
|
|
68
50
|
```js
|
|
@@ -171,10 +153,17 @@ Environment name used for [environment specific configuration](#environment-spec
|
|
|
171
153
|
|
|
172
154
|
The default is `process.env.NODE_ENV`. You can set `envName` to `false` or an empty string to disable the feature.
|
|
173
155
|
|
|
156
|
+
### `context`
|
|
157
|
+
|
|
158
|
+
Context object passed to dynamic config functions.
|
|
159
|
+
|
|
174
160
|
### `resolve`
|
|
175
161
|
|
|
176
162
|
You can define a custom function that resolves the config.
|
|
177
163
|
|
|
164
|
+
### `configFileRequired`
|
|
165
|
+
|
|
166
|
+
If this option is set to `true`, loader fails if the main config file does not exists.
|
|
178
167
|
|
|
179
168
|
## Extending configuration
|
|
180
169
|
|
|
@@ -386,30 +375,11 @@ Update or create a new configuration files.
|
|
|
386
375
|
|
|
387
376
|
Add `magicast` peer dependency:
|
|
388
377
|
|
|
389
|
-
<!-- automd:pm-install name="magicast" dev -->
|
|
390
|
-
|
|
391
378
|
```sh
|
|
392
379
|
# ✨ Auto-detect
|
|
393
380
|
npx nypm install -D magicast
|
|
394
|
-
|
|
395
|
-
# npm
|
|
396
|
-
npm install -D magicast
|
|
397
|
-
|
|
398
|
-
# yarn
|
|
399
|
-
yarn add -D magicast
|
|
400
|
-
|
|
401
|
-
# pnpm
|
|
402
|
-
pnpm install -D magicast
|
|
403
|
-
|
|
404
|
-
# bun
|
|
405
|
-
bun install -D magicast
|
|
406
|
-
|
|
407
|
-
# deno
|
|
408
|
-
deno install --dev magicast
|
|
409
381
|
```
|
|
410
382
|
|
|
411
|
-
<!-- /automd -->
|
|
412
|
-
|
|
413
383
|
Import util from `c12/update`
|
|
414
384
|
|
|
415
385
|
```js
|
|
@@ -430,6 +400,28 @@ const { configFile, created } = await updateConfig({
|
|
|
430
400
|
console.log(`Config file ${created ? "created" : "updated"} in ${configFile}`);
|
|
431
401
|
```
|
|
432
402
|
|
|
403
|
+
## Configuration functions
|
|
404
|
+
|
|
405
|
+
You can use a function to define your configuration dynamically based on context.
|
|
406
|
+
|
|
407
|
+
```ts
|
|
408
|
+
// config.ts
|
|
409
|
+
export default (ctx) => {
|
|
410
|
+
return {
|
|
411
|
+
apiUrl: ctx?.dev ? "http://localhost:3000" : "https://api.example.com",
|
|
412
|
+
};
|
|
413
|
+
};
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
```ts
|
|
417
|
+
// Usage
|
|
418
|
+
import { loadConfig } from "c12";
|
|
419
|
+
|
|
420
|
+
const config = await loadConfig({
|
|
421
|
+
context: { dev: true },
|
|
422
|
+
});
|
|
423
|
+
```
|
|
424
|
+
|
|
433
425
|
## Contribution
|
|
434
426
|
|
|
435
427
|
<details>
|
package/dist/index.d.mts
CHANGED
|
@@ -9,10 +9,11 @@ interface DotenvOptions {
|
|
|
9
9
|
*/
|
|
10
10
|
cwd: string;
|
|
11
11
|
/**
|
|
12
|
-
* What file to look in for environment variables (either absolute or relative
|
|
12
|
+
* What file or files to look in for environment variables (either absolute or relative
|
|
13
13
|
* to the current working directory). For example, `.env`.
|
|
14
|
+
* With the array type, the order enforce the env loading priority (last one overrides).
|
|
14
15
|
*/
|
|
15
|
-
fileName?: string;
|
|
16
|
+
fileName?: string | string[];
|
|
16
17
|
/**
|
|
17
18
|
* Whether to interpolate variables within .env.
|
|
18
19
|
*
|
|
@@ -92,9 +93,15 @@ interface ResolvedConfig<T extends UserInputConfig = UserInputConfig, MT extends
|
|
|
92
93
|
config: T;
|
|
93
94
|
layers?: ConfigLayer<T, MT>[];
|
|
94
95
|
cwd?: string;
|
|
96
|
+
_configFile?: string;
|
|
97
|
+
}
|
|
98
|
+
type ConfigSource = "overrides" | "main" | "rc" | "packageJson" | "defaultConfig";
|
|
99
|
+
interface ConfigFunctionContext {
|
|
100
|
+
[key: string]: any;
|
|
95
101
|
}
|
|
96
102
|
interface ResolvableConfigContext<T extends UserInputConfig = UserInputConfig> {
|
|
97
|
-
configs: Record<
|
|
103
|
+
configs: Record<ConfigSource, T | null | undefined>;
|
|
104
|
+
rawConfigs: Record<ConfigSource, ResolvableConfig<T> | null | undefined>;
|
|
98
105
|
}
|
|
99
106
|
type MaybePromise<T> = T | Promise<T>;
|
|
100
107
|
type ResolvableConfig<T extends UserInputConfig = UserInputConfig> = MaybePromise<T | null | undefined> | ((ctx: ResolvableConfigContext<T>) => MaybePromise<T | null | undefined>);
|
|
@@ -111,6 +118,8 @@ interface LoadConfigOptions<T extends UserInputConfig = UserInputConfig, MT exte
|
|
|
111
118
|
defaultConfig?: ResolvableConfig<T>;
|
|
112
119
|
overrides?: ResolvableConfig<T>;
|
|
113
120
|
omit$Keys?: boolean;
|
|
121
|
+
/** Context passed to config functions */
|
|
122
|
+
context?: ConfigFunctionContext;
|
|
114
123
|
resolve?: (id: string, options: LoadConfigOptions<T, MT>) => null | undefined | ResolvedConfig<T, MT> | Promise<ResolvedConfig<T, MT> | undefined | null>;
|
|
115
124
|
jiti?: Jiti;
|
|
116
125
|
jitiOptions?: JitiOptions;
|
|
@@ -119,6 +128,7 @@ interface LoadConfigOptions<T extends UserInputConfig = UserInputConfig, MT exte
|
|
|
119
128
|
extend?: false | {
|
|
120
129
|
extendKey?: string | string[];
|
|
121
130
|
};
|
|
131
|
+
configFileRequired?: boolean;
|
|
122
132
|
}
|
|
123
133
|
type DefineConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> = (input: InputConfig<T, MT>) => InputConfig<T, MT>;
|
|
124
134
|
declare function createDefineConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta>(): DefineConfig<T, MT>;
|
|
@@ -152,4 +162,4 @@ interface WatchConfigOptions<T extends UserInputConfig = UserInputConfig, MT ext
|
|
|
152
162
|
declare function watchConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta>(options: WatchConfigOptions<T, MT>): Promise<ConfigWatcher<T, MT>>;
|
|
153
163
|
|
|
154
164
|
export { SUPPORTED_EXTENSIONS, createDefineConfig, loadConfig, loadDotenv, setupDotenv, watchConfig };
|
|
155
|
-
export type { C12InputConfig, ConfigLayer, ConfigLayerMeta, ConfigWatcher, DefineConfig, DotenvOptions, Env, InputConfig, LoadConfigOptions, ResolvableConfig, ResolvableConfigContext, ResolvedConfig, SourceOptions, UserInputConfig, WatchConfigOptions };
|
|
165
|
+
export type { C12InputConfig, ConfigFunctionContext, ConfigLayer, ConfigLayerMeta, ConfigSource, ConfigWatcher, DefineConfig, DotenvOptions, Env, InputConfig, LoadConfigOptions, ResolvableConfig, ResolvableConfigContext, ResolvedConfig, SourceOptions, UserInputConfig, WatchConfigOptions };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { l as loadConfig, S as SUPPORTED_EXTENSIONS } from './shared/c12.
|
|
2
|
-
export { a as loadDotenv, s as setupDotenv } from './shared/c12.
|
|
1
|
+
import { l as loadConfig, S as SUPPORTED_EXTENSIONS } from './shared/c12.DDjD4HmS.mjs';
|
|
2
|
+
export { a as loadDotenv, s as setupDotenv } from './shared/c12.DDjD4HmS.mjs';
|
|
3
3
|
import { debounce } from 'perfect-debounce';
|
|
4
4
|
import { resolve } from 'pathe';
|
|
5
5
|
import 'node:fs';
|
|
@@ -31,10 +31,15 @@ async function setupDotenv(options) {
|
|
|
31
31
|
}
|
|
32
32
|
async function loadDotenv(options) {
|
|
33
33
|
const environment = /* @__PURE__ */ Object.create(null);
|
|
34
|
-
const
|
|
34
|
+
const _fileName = options.fileName || ".env";
|
|
35
|
+
const dotenvFiles = typeof _fileName === "string" ? [_fileName] : _fileName;
|
|
35
36
|
const dotenvVars = getDotEnvVars(options.env || {});
|
|
36
37
|
Object.assign(environment, options.env);
|
|
37
|
-
|
|
38
|
+
for (const file of dotenvFiles) {
|
|
39
|
+
const dotenvFile = resolve(options.cwd, file);
|
|
40
|
+
if (!statSync(dotenvFile, { throwIfNoEntry: false })?.isFile()) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
38
43
|
const parsed = dotenv.parse(await promises.readFile(dotenvFile, "utf8"));
|
|
39
44
|
for (const key in parsed) {
|
|
40
45
|
if (key in environment && !dotenvVars.has(key)) {
|
|
@@ -144,9 +149,10 @@ async function loadConfig(options) {
|
|
|
144
149
|
config: {},
|
|
145
150
|
cwd: options.cwd,
|
|
146
151
|
configFile: resolve(options.cwd, options.configFile),
|
|
147
|
-
layers: []
|
|
152
|
+
layers: [],
|
|
153
|
+
_configFile: void 0
|
|
148
154
|
};
|
|
149
|
-
const
|
|
155
|
+
const rawConfigs = {
|
|
150
156
|
overrides: options.overrides,
|
|
151
157
|
main: void 0,
|
|
152
158
|
rc: void 0,
|
|
@@ -161,8 +167,9 @@ async function loadConfig(options) {
|
|
|
161
167
|
}
|
|
162
168
|
const _mainConfig = await resolveConfig(".", options);
|
|
163
169
|
if (_mainConfig.configFile) {
|
|
164
|
-
|
|
170
|
+
rawConfigs.main = _mainConfig.config;
|
|
165
171
|
r.configFile = _mainConfig.configFile;
|
|
172
|
+
r._configFile = _mainConfig._configFile;
|
|
166
173
|
}
|
|
167
174
|
if (_mainConfig.meta) {
|
|
168
175
|
r.meta = _mainConfig.meta;
|
|
@@ -178,7 +185,7 @@ async function loadConfig(options) {
|
|
|
178
185
|
}
|
|
179
186
|
rcSources.push(rc9.readUser({ name: options.rcFile, dir: options.cwd }));
|
|
180
187
|
}
|
|
181
|
-
|
|
188
|
+
rawConfigs.rc = _merger({}, ...rcSources);
|
|
182
189
|
}
|
|
183
190
|
if (options.packageJson) {
|
|
184
191
|
const keys = (Array.isArray(options.packageJson) ? options.packageJson : [
|
|
@@ -187,12 +194,12 @@ async function loadConfig(options) {
|
|
|
187
194
|
const pkgJsonFile = await readPackageJSON(options.cwd).catch(() => {
|
|
188
195
|
});
|
|
189
196
|
const values = keys.map((key) => pkgJsonFile?.[key]);
|
|
190
|
-
|
|
197
|
+
rawConfigs.packageJson = _merger({}, ...values);
|
|
191
198
|
}
|
|
192
199
|
const configs = {};
|
|
193
|
-
for (const key in
|
|
194
|
-
const value =
|
|
195
|
-
configs[key] = await (typeof value === "function" ? value({ configs }) : value);
|
|
200
|
+
for (const key in rawConfigs) {
|
|
201
|
+
const value = rawConfigs[key];
|
|
202
|
+
configs[key] = await (typeof value === "function" ? value({ configs, rawConfigs }) : value);
|
|
196
203
|
}
|
|
197
204
|
r.config = _merger(
|
|
198
205
|
configs.overrides,
|
|
@@ -231,6 +238,9 @@ async function loadConfig(options) {
|
|
|
231
238
|
}
|
|
232
239
|
}
|
|
233
240
|
}
|
|
241
|
+
if (options.configFileRequired && !r._configFile) {
|
|
242
|
+
throw new Error(`Required config (${r.configFile}) cannot be resolved.`);
|
|
243
|
+
}
|
|
234
244
|
return r;
|
|
235
245
|
}
|
|
236
246
|
async function extendConfig(config, options) {
|
|
@@ -356,6 +366,7 @@ async function resolveConfig(source, options, sourceOptions = {}) {
|
|
|
356
366
|
if (!existsSync(res.configFile)) {
|
|
357
367
|
return res;
|
|
358
368
|
}
|
|
369
|
+
res._configFile = res.configFile;
|
|
359
370
|
const configFileExt = extname(res.configFile) || "";
|
|
360
371
|
if (configFileExt in ASYNC_LOADERS) {
|
|
361
372
|
const asyncLoader = await ASYNC_LOADERS[configFileExt]();
|
|
@@ -366,8 +377,8 @@ async function resolveConfig(source, options, sourceOptions = {}) {
|
|
|
366
377
|
default: true
|
|
367
378
|
});
|
|
368
379
|
}
|
|
369
|
-
if (res.config
|
|
370
|
-
res.config = await res.config();
|
|
380
|
+
if (typeof res.config === "function") {
|
|
381
|
+
res.config = await res.config(options.context);
|
|
371
382
|
}
|
|
372
383
|
if (options.envName) {
|
|
373
384
|
const envConfig = {
|
package/dist/update.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolveModulePath } from 'exsolve';
|
|
2
|
-
import { S as SUPPORTED_EXTENSIONS } from './shared/c12.
|
|
2
|
+
import { S as SUPPORTED_EXTENSIONS } from './shared/c12.DDjD4HmS.mjs';
|
|
3
3
|
import { join, normalize } from 'pathe';
|
|
4
4
|
import { mkdir, writeFile, readFile } from 'node:fs/promises';
|
|
5
5
|
import { dirname, extname } from 'node:path';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "c12",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Smart Config Loader",
|
|
5
5
|
"repository": "unjs/c12",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,29 +34,29 @@
|
|
|
34
34
|
"chokidar": "^4.0.3",
|
|
35
35
|
"confbox": "^0.2.2",
|
|
36
36
|
"defu": "^6.1.4",
|
|
37
|
-
"dotenv": "^
|
|
38
|
-
"exsolve": "^1.0.
|
|
37
|
+
"dotenv": "^17.2.1",
|
|
38
|
+
"exsolve": "^1.0.7",
|
|
39
39
|
"giget": "^2.0.0",
|
|
40
|
-
"jiti": "^2.
|
|
40
|
+
"jiti": "^2.5.1",
|
|
41
41
|
"ohash": "^2.0.11",
|
|
42
42
|
"pathe": "^2.0.3",
|
|
43
43
|
"perfect-debounce": "^1.0.0",
|
|
44
|
-
"pkg-types": "^2.
|
|
44
|
+
"pkg-types": "^2.2.0",
|
|
45
45
|
"rc9": "^2.1.2"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@types/node": "^
|
|
49
|
-
"@vitest/coverage-v8": "^3.
|
|
48
|
+
"@types/node": "^24.1.0",
|
|
49
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
50
50
|
"automd": "^0.4.0",
|
|
51
|
-
"changelogen": "^0.6.
|
|
52
|
-
"eslint": "^9.
|
|
53
|
-
"eslint-config-unjs": "^0.
|
|
54
|
-
"expect-type": "^1.2.
|
|
51
|
+
"changelogen": "^0.6.2",
|
|
52
|
+
"eslint": "^9.32.0",
|
|
53
|
+
"eslint-config-unjs": "^0.5.0",
|
|
54
|
+
"expect-type": "^1.2.2",
|
|
55
55
|
"magicast": "^0.3.5",
|
|
56
|
-
"prettier": "^3.
|
|
56
|
+
"prettier": "^3.6.2",
|
|
57
57
|
"typescript": "^5.8.3",
|
|
58
|
-
"unbuild": "^3.
|
|
59
|
-
"vitest": "^3.
|
|
58
|
+
"unbuild": "^3.6.0",
|
|
59
|
+
"vitest": "^3.2.4"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"magicast": "^0.3.5"
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"optional": true
|
|
67
67
|
}
|
|
68
68
|
},
|
|
69
|
-
"packageManager": "pnpm@10.
|
|
69
|
+
"packageManager": "pnpm@10.13.1"
|
|
70
70
|
}
|