c12 2.0.3 → 3.0.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 CHANGED
@@ -65,22 +65,14 @@ deno install c12
65
65
 
66
66
  Import:
67
67
 
68
- <!-- automd:jsimport cjs imports="loadConfig,watchConfig" -->
69
-
70
- **ESM** (Node.js, Bun, Deno)
71
-
72
68
  ```js
69
+ // ESM import
73
70
  import { loadConfig, watchConfig } from "c12";
74
- ```
75
-
76
- **CommonJS** (Legacy Node.js)
77
71
 
78
- ```js
79
- const { loadConfig, watchConfig } = require("c12");
72
+ // or using dynamic import
73
+ const { loadConfig, watchConfig } = await import("c12");
80
74
  ```
81
75
 
82
- <!-- /automd -->
83
-
84
76
  Load configuration:
85
77
 
86
78
  ```js
package/dist/index.d.mts CHANGED
@@ -120,7 +120,7 @@ interface LoadConfigOptions<T extends UserInputConfig = UserInputConfig, MT exte
120
120
  type DefineConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> = (input: InputConfig<T, MT>) => InputConfig<T, MT>;
121
121
  declare function createDefineConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta>(): DefineConfig<T, MT>;
122
122
 
123
- declare const SUPPORTED_EXTENSIONS: readonly [".js", ".ts", ".mjs", ".cjs", ".mts", ".cts", ".json", ".jsonc", ".json5", ".yaml", ".yml", ".toml"];
123
+ declare const SUPPORTED_EXTENSIONS: string[];
124
124
  declare function loadConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta>(options: LoadConfigOptions<T, MT>): Promise<ResolvedConfig<T, MT>>;
125
125
 
126
126
  type DiffEntries = ReturnType<typeof diff>;
package/dist/index.mjs CHANGED
@@ -1,12 +1,13 @@
1
- import { l as loadConfig, S as SUPPORTED_EXTENSIONS } from './shared/c12.PQMoYrit.mjs';
2
- export { a as loadDotenv, s as setupDotenv } from './shared/c12.PQMoYrit.mjs';
1
+ import { l as loadConfig, S as SUPPORTED_EXTENSIONS } from './shared/c12.D3Kdt5zI.mjs';
2
+ export { a as loadDotenv, s as setupDotenv } from './shared/c12.D3Kdt5zI.mjs';
3
3
  import { debounce } from 'perfect-debounce';
4
4
  import { resolve } from 'pathe';
5
5
  import 'node:fs';
6
6
  import 'node:fs/promises';
7
+ import 'node:url';
7
8
  import 'node:os';
9
+ import 'exsolve';
8
10
  import 'jiti';
9
- import 'mlly';
10
11
  import 'rc9';
11
12
  import 'defu';
12
13
  import 'pkg-types';
@@ -1,9 +1,10 @@
1
1
  import { existsSync, promises } from 'node:fs';
2
2
  import { rm, readFile } from 'node:fs/promises';
3
+ import { pathToFileURL } from 'node:url';
3
4
  import { homedir } from 'node:os';
4
5
  import { resolve, join, dirname, basename, extname } from 'pathe';
6
+ import { resolveModulePath } from 'exsolve';
5
7
  import { createJiti } from 'jiti';
6
- import { fileURLToPath } from 'mlly';
7
8
  import * as rc9 from 'rc9';
8
9
  import { defu } from 'defu';
9
10
  import { findWorkspaceDir, readPackageJSON } from 'pkg-types';
@@ -89,7 +90,7 @@ const ASYNC_LOADERS = {
89
90
  ".json5": () => import('confbox/json5').then((r) => r.parseJSON5),
90
91
  ".toml": () => import('confbox/toml').then((r) => r.parseTOML)
91
92
  };
92
- const SUPPORTED_EXTENSIONS = [
93
+ const SUPPORTED_EXTENSIONS = Object.freeze([
93
94
  // with jiti
94
95
  ".js",
95
96
  ".ts",
@@ -104,7 +105,7 @@ const SUPPORTED_EXTENSIONS = [
104
105
  ".yaml",
105
106
  ".yml",
106
107
  ".toml"
107
- ];
108
+ ]);
108
109
  async function loadConfig(options) {
109
110
  options.cwd = resolve(process.cwd(), options.cwd || ".");
110
111
  options.name = options.name || "config";
@@ -286,7 +287,11 @@ async function resolveConfig(source, options, sourceOptions = {}) {
286
287
  }
287
288
  }
288
289
  const _merger = options.merger || defu;
289
- if (options.giget !== false && GIGET_PREFIXES.some((prefix) => source.startsWith(prefix))) {
290
+ const customProviderKeys = Object.keys(
291
+ sourceOptions.giget?.providers || {}
292
+ ).map((key) => `${key}:`);
293
+ const gigetPrefixes = customProviderKeys.length > 0 ? [.../* @__PURE__ */ new Set([...customProviderKeys, ...GIGET_PREFIXES])] : GIGET_PREFIXES;
294
+ if (options.giget !== false && gigetPrefixes.some((prefix) => source.startsWith(prefix))) {
290
295
  const { downloadTemplate } = await import('giget');
291
296
  const { digest } = await import('ohash');
292
297
  const cloneName = source.replace(/\W+/g, "_").split("_").splice(0, 3).join("_") + "_" + digest(source).slice(0, 10).replace(/[-_]/g, "");
@@ -313,12 +318,8 @@ async function resolveConfig(source, options, sourceOptions = {}) {
313
318
  });
314
319
  source = cloned.dir;
315
320
  }
316
- const tryResolve = (id) => {
317
- const resolved = options.jiti.esmResolve(id, { try: true });
318
- return resolved ? fileURLToPath(resolved) : void 0;
319
- };
320
321
  if (NPM_PACKAGE_RE.test(source)) {
321
- source = tryResolve(source) || source;
322
+ source = tryResolve(source, options) || source;
322
323
  }
323
324
  const ext = extname(source);
324
325
  const isDir = !ext || ext === basename(source);
@@ -333,7 +334,10 @@ async function resolveConfig(source, options, sourceOptions = {}) {
333
334
  source,
334
335
  sourceOptions
335
336
  };
336
- res.configFile = tryResolve(resolve(cwd, source)) || tryResolve(resolve(cwd, ".config", source.replace(/\.config$/, ""))) || tryResolve(resolve(cwd, ".config", source)) || source;
337
+ res.configFile = tryResolve(resolve(cwd, source), options) || tryResolve(
338
+ resolve(cwd, ".config", source.replace(/\.config$/, "")),
339
+ options
340
+ ) || tryResolve(resolve(cwd, ".config", source), options) || source;
337
341
  if (!existsSync(res.configFile)) {
338
342
  return res;
339
343
  }
@@ -368,5 +372,14 @@ async function resolveConfig(source, options, sourceOptions = {}) {
368
372
  res.source = _normalize(res.source);
369
373
  return res;
370
374
  }
375
+ function tryResolve(id, options) {
376
+ return resolveModulePath(id, {
377
+ try: true,
378
+ from: pathToFileURL(join(options.cwd || ".", options.configFile || "/")),
379
+ suffixes: ["", "/index"],
380
+ extensions: SUPPORTED_EXTENSIONS,
381
+ cache: false
382
+ });
383
+ }
371
384
 
372
385
  export { SUPPORTED_EXTENSIONS as S, loadDotenv as a, loadConfig as l, setupDotenv as s };
package/dist/update.mjs CHANGED
@@ -1,9 +1,10 @@
1
- import { resolvePath } from 'mlly';
2
- import { S as SUPPORTED_EXTENSIONS } from './shared/c12.PQMoYrit.mjs';
1
+ import { resolveModulePath } from 'exsolve';
2
+ import { S as SUPPORTED_EXTENSIONS } from './shared/c12.D3Kdt5zI.mjs';
3
3
  import { join } from 'pathe';
4
4
  import { mkdir, writeFile, readFile } from 'node:fs/promises';
5
5
  import { dirname, extname } from 'node:path';
6
6
  import 'node:fs';
7
+ import 'node:url';
7
8
  import 'node:os';
8
9
  import 'jiti';
9
10
  import 'rc9';
@@ -14,15 +15,11 @@ import 'dotenv';
14
15
  const UPDATABLE_EXTS = [".js", ".ts", ".mjs", ".cjs", ".mts", ".cts"];
15
16
  async function updateConfig(opts) {
16
17
  const { parseModule } = await import('magicast');
17
- let configFile = await _tryResolve(
18
- `./${opts.configFile}`,
19
- opts.cwd,
20
- SUPPORTED_EXTENSIONS
21
- ) || await _tryResolve(
18
+ let configFile = tryResolve(`./${opts.configFile}`, opts.cwd, SUPPORTED_EXTENSIONS) || tryResolve(
22
19
  `./.config/${opts.configFile}`,
23
20
  opts.cwd,
24
21
  SUPPORTED_EXTENSIONS
25
- ) || await _tryResolve(
22
+ ) || tryResolve(
26
23
  `./.config/${opts.configFile.split(".")[0]}`,
27
24
  opts.cwd,
28
25
  SUPPORTED_EXTENSIONS
@@ -63,11 +60,14 @@ async function updateConfig(opts) {
63
60
  created
64
61
  };
65
62
  }
66
- function _tryResolve(path, cwd, exts) {
67
- return resolvePath(path, {
68
- url: join(cwd, "_index.js"),
69
- extensions: exts
70
- }).catch(() => void 0);
63
+ function tryResolve(path, cwd, extensions) {
64
+ return resolveModulePath(path, {
65
+ try: true,
66
+ from: join(cwd, "/"),
67
+ extensions,
68
+ suffixes: ["", "/index"],
69
+ cache: false
70
+ });
71
71
  }
72
72
 
73
73
  export { updateConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c12",
3
- "version": "2.0.3",
3
+ "version": "3.0.0",
4
4
  "description": "Smart Config Loader",
5
5
  "repository": "unjs/c12",
6
6
  "license": "MIT",
@@ -8,32 +8,17 @@
8
8
  "type": "module",
9
9
  "exports": {
10
10
  ".": {
11
- "import": {
12
- "types": "./dist/index.d.mts",
13
- "default:": "./dist/index.mjs"
14
- },
15
- "require": {
16
- "types": "./dist/index.d.cts",
17
- "default:": "./dist/index.cjs"
18
- }
11
+ "types": "./dist/index.d.mts",
12
+ "default": "./dist/index.mjs"
19
13
  },
20
14
  "./update": {
21
- "import": {
22
- "types": "./dist/update.d.mts",
23
- "default:": "./dist/update.mjs"
24
- },
25
- "require": {
26
- "types": "./dist/update.d.cts",
27
- "default:": "./dist/update.cjs"
28
- }
15
+ "types": "./dist/update.d.mts",
16
+ "default": "./dist/update.mjs"
29
17
  }
30
18
  },
31
- "main": "./dist/index.cjs",
32
- "module": "./dist/index.mjs",
33
- "types": "./dist/index.d.ts",
19
+ "types": "./dist/index.d.mts",
34
20
  "files": [
35
- "dist",
36
- "update.d.ts"
21
+ "dist"
37
22
  ],
38
23
  "scripts": {
39
24
  "build": "automd && unbuild",
@@ -50,28 +35,28 @@
50
35
  "confbox": "^0.1.8",
51
36
  "defu": "^6.1.4",
52
37
  "dotenv": "^16.4.7",
53
- "giget": "^1.2.4",
38
+ "exsolve": "^0.4.1",
39
+ "giget": "^2.0.0",
54
40
  "jiti": "^2.4.2",
55
- "mlly": "^1.7.4",
56
- "ohash": "^2.0.4",
41
+ "ohash": "^2.0.5",
57
42
  "pathe": "^2.0.3",
58
43
  "perfect-debounce": "^1.0.0",
59
- "pkg-types": "^1.3.1",
44
+ "pkg-types": "^2.0.0",
60
45
  "rc9": "^2.1.2"
61
46
  },
62
47
  "devDependencies": {
63
- "@types/node": "^22.13.4",
64
- "@vitest/coverage-v8": "^3.0.6",
48
+ "@types/node": "^22.13.5",
49
+ "@vitest/coverage-v8": "^3.0.7",
65
50
  "automd": "^0.3.12",
66
51
  "changelogen": "^0.5.7",
67
- "eslint": "^9.20.1",
52
+ "eslint": "^9.21.0",
68
53
  "eslint-config-unjs": "^0.4.2",
69
54
  "expect-type": "^1.1.0",
70
55
  "magicast": "^0.3.5",
71
- "prettier": "^3.5.1",
56
+ "prettier": "^3.5.2",
72
57
  "typescript": "^5.7.3",
73
58
  "unbuild": "^3.3.1",
74
- "vitest": "^3.0.6"
59
+ "vitest": "^3.0.7"
75
60
  },
76
61
  "peerDependencies": {
77
62
  "magicast": "^0.3.5"
@@ -81,5 +66,5 @@
81
66
  "optional": true
82
67
  }
83
68
  },
84
- "packageManager": "pnpm@10.4.1"
69
+ "packageManager": "pnpm@10.5.0"
85
70
  }
package/dist/index.cjs DELETED
@@ -1,112 +0,0 @@
1
- 'use strict';
2
-
3
- const loader = require('./shared/c12.CMG3XLfD.cjs');
4
- const perfectDebounce = require('perfect-debounce');
5
- const pathe = require('pathe');
6
- require('node:fs');
7
- require('node:fs/promises');
8
- require('node:os');
9
- require('jiti');
10
- require('mlly');
11
- require('rc9');
12
- require('defu');
13
- require('pkg-types');
14
- require('dotenv');
15
-
16
- function createDefineConfig() {
17
- return (input) => input;
18
- }
19
-
20
- const eventMap = {
21
- add: "created",
22
- change: "updated",
23
- unlink: "removed"
24
- };
25
- async function watchConfig(options) {
26
- let config = await loader.loadConfig(options);
27
- const configName = options.name || "config";
28
- const configFileName = options.configFile ?? (options.name === "config" ? "config" : `${options.name}.config`);
29
- const watchingFiles = [
30
- ...new Set(
31
- (config.layers || []).filter((l) => l.cwd).flatMap((l) => [
32
- ...loader.SUPPORTED_EXTENSIONS.flatMap((ext) => [
33
- pathe.resolve(l.cwd, configFileName + ext),
34
- pathe.resolve(l.cwd, ".config", configFileName + ext),
35
- pathe.resolve(
36
- l.cwd,
37
- ".config",
38
- configFileName.replace(/\.config$/, "") + ext
39
- )
40
- ]),
41
- l.source && pathe.resolve(l.cwd, l.source),
42
- // TODO: Support watching rc from home and workspace
43
- options.rcFile && pathe.resolve(
44
- l.cwd,
45
- typeof options.rcFile === "string" ? options.rcFile : `.${configName}rc`
46
- ),
47
- options.packageJson && pathe.resolve(l.cwd, "package.json")
48
- ]).filter(Boolean)
49
- )
50
- ];
51
- const watch = await import('chokidar').then((r) => r.watch || r.default || r);
52
- const { diff } = await import('ohash/utils');
53
- const _fswatcher = watch(watchingFiles, {
54
- ignoreInitial: true,
55
- ...options.chokidarOptions
56
- });
57
- const onChange = async (event, path) => {
58
- const type = eventMap[event];
59
- if (!type) {
60
- return;
61
- }
62
- if (options.onWatch) {
63
- await options.onWatch({
64
- type,
65
- path
66
- });
67
- }
68
- const oldConfig = config;
69
- const newConfig = await loader.loadConfig(options);
70
- config = newConfig;
71
- const changeCtx = {
72
- newConfig,
73
- oldConfig,
74
- getDiff: () => diff(oldConfig.config, config.config)
75
- };
76
- if (options.acceptHMR) {
77
- const changeHandled = await options.acceptHMR(changeCtx);
78
- if (changeHandled) {
79
- return;
80
- }
81
- }
82
- if (options.onUpdate) {
83
- await options.onUpdate(changeCtx);
84
- }
85
- };
86
- if (options.debounce === false) {
87
- _fswatcher.on("all", onChange);
88
- } else {
89
- _fswatcher.on("all", perfectDebounce.debounce(onChange, options.debounce ?? 100));
90
- }
91
- const utils = {
92
- watchingFiles,
93
- unwatch: async () => {
94
- await _fswatcher.close();
95
- }
96
- };
97
- return new Proxy(utils, {
98
- get(_, prop) {
99
- if (prop in utils) {
100
- return utils[prop];
101
- }
102
- return config[prop];
103
- }
104
- });
105
- }
106
-
107
- exports.SUPPORTED_EXTENSIONS = loader.SUPPORTED_EXTENSIONS;
108
- exports.loadConfig = loader.loadConfig;
109
- exports.loadDotenv = loader.loadDotenv;
110
- exports.setupDotenv = loader.setupDotenv;
111
- exports.createDefineConfig = createDefineConfig;
112
- exports.watchConfig = watchConfig;
package/dist/index.d.cts DELETED
@@ -1,151 +0,0 @@
1
- import { Jiti, JitiOptions } from 'jiti';
2
- import { DownloadTemplateOptions } from 'giget';
3
- import { ChokidarOptions } from 'chokidar';
4
- import { diff } from 'ohash/utils';
5
-
6
- interface DotenvOptions {
7
- /**
8
- * The project root directory (either absolute or relative to the current working directory).
9
- */
10
- cwd: string;
11
- /**
12
- * What file to look in for environment variables (either absolute or relative
13
- * to the current working directory). For example, `.env`.
14
- */
15
- fileName?: string;
16
- /**
17
- * Whether to interpolate variables within .env.
18
- *
19
- * @example
20
- * ```env
21
- * BASE_DIR="/test"
22
- * # resolves to "/test/further"
23
- * ANOTHER_DIR="${BASE_DIR}/further"
24
- * ```
25
- */
26
- interpolate?: boolean;
27
- /**
28
- * An object describing environment variables (key, value pairs).
29
- */
30
- env?: NodeJS.ProcessEnv;
31
- }
32
- type Env = typeof process.env;
33
- /**
34
- * Load and interpolate environment variables into `process.env`.
35
- * If you need more control (or access to the values), consider using `loadDotenv` instead
36
- *
37
- */
38
- declare function setupDotenv(options: DotenvOptions): Promise<Env>;
39
- /** Load environment variables into an object. */
40
- declare function loadDotenv(options: DotenvOptions): Promise<Env>;
41
-
42
- interface ConfigLayerMeta {
43
- name?: string;
44
- [key: string]: any;
45
- }
46
- type UserInputConfig = Record<string, any>;
47
- interface C12InputConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> {
48
- $test?: T;
49
- $development?: T;
50
- $production?: T;
51
- $env?: Record<string, T>;
52
- $meta?: MT;
53
- }
54
- type InputConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> = C12InputConfig<T, MT> & T;
55
- interface SourceOptions<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> {
56
- /** Custom meta for layer */
57
- meta?: MT;
58
- /** Layer config overrides */
59
- overrides?: T;
60
- [key: string]: any;
61
- /**
62
- * Options for cloning remote sources
63
- *
64
- * @see https://giget.unjs.io
65
- */
66
- giget?: DownloadTemplateOptions;
67
- /**
68
- * Install dependencies after cloning
69
- *
70
- * @see https://nypm.unjs.io
71
- */
72
- install?: boolean;
73
- /**
74
- * Token for cloning private sources
75
- *
76
- * @see https://giget.unjs.io#providing-token-for-private-repositories
77
- */
78
- auth?: string;
79
- }
80
- interface ConfigLayer<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> {
81
- config: T | null;
82
- source?: string;
83
- sourceOptions?: SourceOptions<T, MT>;
84
- meta?: MT;
85
- cwd?: string;
86
- configFile?: string;
87
- }
88
- interface ResolvedConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> extends ConfigLayer<T, MT> {
89
- config: T;
90
- layers?: ConfigLayer<T, MT>[];
91
- cwd?: string;
92
- }
93
- interface ResolvableConfigContext<T extends UserInputConfig = UserInputConfig> {
94
- configs: Record<"overrides" | "main" | "rc" | "packageJson" | "defaultConfig", T | null | undefined>;
95
- }
96
- type MaybePromise<T> = T | Promise<T>;
97
- type ResolvableConfig<T extends UserInputConfig = UserInputConfig> = MaybePromise<T | null | undefined> | ((ctx: ResolvableConfigContext<T>) => MaybePromise<T | null | undefined>);
98
- interface LoadConfigOptions<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> {
99
- name?: string;
100
- cwd?: string;
101
- configFile?: string;
102
- rcFile?: false | string;
103
- globalRc?: boolean;
104
- dotenv?: boolean | DotenvOptions;
105
- envName?: string | false;
106
- packageJson?: boolean | string | string[];
107
- defaults?: T;
108
- defaultConfig?: ResolvableConfig<T>;
109
- overrides?: ResolvableConfig<T>;
110
- omit$Keys?: boolean;
111
- resolve?: (id: string, options: LoadConfigOptions<T, MT>) => null | undefined | ResolvedConfig<T, MT> | Promise<ResolvedConfig<T, MT> | undefined | null>;
112
- jiti?: Jiti;
113
- jitiOptions?: JitiOptions;
114
- giget?: false | DownloadTemplateOptions;
115
- merger?: (...sources: Array<T | null | undefined>) => T;
116
- extend?: false | {
117
- extendKey?: string | string[];
118
- };
119
- }
120
- type DefineConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> = (input: InputConfig<T, MT>) => InputConfig<T, MT>;
121
- declare function createDefineConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta>(): DefineConfig<T, MT>;
122
-
123
- declare const SUPPORTED_EXTENSIONS: readonly [".js", ".ts", ".mjs", ".cjs", ".mts", ".cts", ".json", ".jsonc", ".json5", ".yaml", ".yml", ".toml"];
124
- declare function loadConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta>(options: LoadConfigOptions<T, MT>): Promise<ResolvedConfig<T, MT>>;
125
-
126
- type DiffEntries = ReturnType<typeof diff>;
127
- type ConfigWatcher<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> = ResolvedConfig<T, MT> & {
128
- watchingFiles: string[];
129
- unwatch: () => Promise<void>;
130
- };
131
- interface WatchConfigOptions<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> extends LoadConfigOptions<T, MT> {
132
- chokidarOptions?: ChokidarOptions;
133
- debounce?: false | number;
134
- onWatch?: (event: {
135
- type: "created" | "updated" | "removed";
136
- path: string;
137
- }) => void | Promise<void>;
138
- acceptHMR?: (context: {
139
- getDiff: () => DiffEntries;
140
- newConfig: ResolvedConfig<T, MT>;
141
- oldConfig: ResolvedConfig<T, MT>;
142
- }) => void | boolean | Promise<void | boolean>;
143
- onUpdate?: (context: {
144
- getDiff: () => ReturnType<typeof diff>;
145
- newConfig: ResolvedConfig<T, MT>;
146
- oldConfig: ResolvedConfig<T, MT>;
147
- }) => void | Promise<void>;
148
- }
149
- declare function watchConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta>(options: WatchConfigOptions<T, MT>): Promise<ConfigWatcher<T, MT>>;
150
-
151
- export { type C12InputConfig, type ConfigLayer, type ConfigLayerMeta, type ConfigWatcher, type DefineConfig, type DotenvOptions, type Env, type InputConfig, type LoadConfigOptions, type ResolvableConfig, type ResolvableConfigContext, type ResolvedConfig, SUPPORTED_EXTENSIONS, type SourceOptions, type UserInputConfig, type WatchConfigOptions, createDefineConfig, loadConfig, loadDotenv, setupDotenv, watchConfig };
package/dist/index.d.ts DELETED
@@ -1,151 +0,0 @@
1
- import { Jiti, JitiOptions } from 'jiti';
2
- import { DownloadTemplateOptions } from 'giget';
3
- import { ChokidarOptions } from 'chokidar';
4
- import { diff } from 'ohash/utils';
5
-
6
- interface DotenvOptions {
7
- /**
8
- * The project root directory (either absolute or relative to the current working directory).
9
- */
10
- cwd: string;
11
- /**
12
- * What file to look in for environment variables (either absolute or relative
13
- * to the current working directory). For example, `.env`.
14
- */
15
- fileName?: string;
16
- /**
17
- * Whether to interpolate variables within .env.
18
- *
19
- * @example
20
- * ```env
21
- * BASE_DIR="/test"
22
- * # resolves to "/test/further"
23
- * ANOTHER_DIR="${BASE_DIR}/further"
24
- * ```
25
- */
26
- interpolate?: boolean;
27
- /**
28
- * An object describing environment variables (key, value pairs).
29
- */
30
- env?: NodeJS.ProcessEnv;
31
- }
32
- type Env = typeof process.env;
33
- /**
34
- * Load and interpolate environment variables into `process.env`.
35
- * If you need more control (or access to the values), consider using `loadDotenv` instead
36
- *
37
- */
38
- declare function setupDotenv(options: DotenvOptions): Promise<Env>;
39
- /** Load environment variables into an object. */
40
- declare function loadDotenv(options: DotenvOptions): Promise<Env>;
41
-
42
- interface ConfigLayerMeta {
43
- name?: string;
44
- [key: string]: any;
45
- }
46
- type UserInputConfig = Record<string, any>;
47
- interface C12InputConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> {
48
- $test?: T;
49
- $development?: T;
50
- $production?: T;
51
- $env?: Record<string, T>;
52
- $meta?: MT;
53
- }
54
- type InputConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> = C12InputConfig<T, MT> & T;
55
- interface SourceOptions<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> {
56
- /** Custom meta for layer */
57
- meta?: MT;
58
- /** Layer config overrides */
59
- overrides?: T;
60
- [key: string]: any;
61
- /**
62
- * Options for cloning remote sources
63
- *
64
- * @see https://giget.unjs.io
65
- */
66
- giget?: DownloadTemplateOptions;
67
- /**
68
- * Install dependencies after cloning
69
- *
70
- * @see https://nypm.unjs.io
71
- */
72
- install?: boolean;
73
- /**
74
- * Token for cloning private sources
75
- *
76
- * @see https://giget.unjs.io#providing-token-for-private-repositories
77
- */
78
- auth?: string;
79
- }
80
- interface ConfigLayer<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> {
81
- config: T | null;
82
- source?: string;
83
- sourceOptions?: SourceOptions<T, MT>;
84
- meta?: MT;
85
- cwd?: string;
86
- configFile?: string;
87
- }
88
- interface ResolvedConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> extends ConfigLayer<T, MT> {
89
- config: T;
90
- layers?: ConfigLayer<T, MT>[];
91
- cwd?: string;
92
- }
93
- interface ResolvableConfigContext<T extends UserInputConfig = UserInputConfig> {
94
- configs: Record<"overrides" | "main" | "rc" | "packageJson" | "defaultConfig", T | null | undefined>;
95
- }
96
- type MaybePromise<T> = T | Promise<T>;
97
- type ResolvableConfig<T extends UserInputConfig = UserInputConfig> = MaybePromise<T | null | undefined> | ((ctx: ResolvableConfigContext<T>) => MaybePromise<T | null | undefined>);
98
- interface LoadConfigOptions<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> {
99
- name?: string;
100
- cwd?: string;
101
- configFile?: string;
102
- rcFile?: false | string;
103
- globalRc?: boolean;
104
- dotenv?: boolean | DotenvOptions;
105
- envName?: string | false;
106
- packageJson?: boolean | string | string[];
107
- defaults?: T;
108
- defaultConfig?: ResolvableConfig<T>;
109
- overrides?: ResolvableConfig<T>;
110
- omit$Keys?: boolean;
111
- resolve?: (id: string, options: LoadConfigOptions<T, MT>) => null | undefined | ResolvedConfig<T, MT> | Promise<ResolvedConfig<T, MT> | undefined | null>;
112
- jiti?: Jiti;
113
- jitiOptions?: JitiOptions;
114
- giget?: false | DownloadTemplateOptions;
115
- merger?: (...sources: Array<T | null | undefined>) => T;
116
- extend?: false | {
117
- extendKey?: string | string[];
118
- };
119
- }
120
- type DefineConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> = (input: InputConfig<T, MT>) => InputConfig<T, MT>;
121
- declare function createDefineConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta>(): DefineConfig<T, MT>;
122
-
123
- declare const SUPPORTED_EXTENSIONS: readonly [".js", ".ts", ".mjs", ".cjs", ".mts", ".cts", ".json", ".jsonc", ".json5", ".yaml", ".yml", ".toml"];
124
- declare function loadConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta>(options: LoadConfigOptions<T, MT>): Promise<ResolvedConfig<T, MT>>;
125
-
126
- type DiffEntries = ReturnType<typeof diff>;
127
- type ConfigWatcher<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> = ResolvedConfig<T, MT> & {
128
- watchingFiles: string[];
129
- unwatch: () => Promise<void>;
130
- };
131
- interface WatchConfigOptions<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta> extends LoadConfigOptions<T, MT> {
132
- chokidarOptions?: ChokidarOptions;
133
- debounce?: false | number;
134
- onWatch?: (event: {
135
- type: "created" | "updated" | "removed";
136
- path: string;
137
- }) => void | Promise<void>;
138
- acceptHMR?: (context: {
139
- getDiff: () => DiffEntries;
140
- newConfig: ResolvedConfig<T, MT>;
141
- oldConfig: ResolvedConfig<T, MT>;
142
- }) => void | boolean | Promise<void | boolean>;
143
- onUpdate?: (context: {
144
- getDiff: () => ReturnType<typeof diff>;
145
- newConfig: ResolvedConfig<T, MT>;
146
- oldConfig: ResolvedConfig<T, MT>;
147
- }) => void | Promise<void>;
148
- }
149
- declare function watchConfig<T extends UserInputConfig = UserInputConfig, MT extends ConfigLayerMeta = ConfigLayerMeta>(options: WatchConfigOptions<T, MT>): Promise<ConfigWatcher<T, MT>>;
150
-
151
- export { type C12InputConfig, type ConfigLayer, type ConfigLayerMeta, type ConfigWatcher, type DefineConfig, type DotenvOptions, type Env, type InputConfig, type LoadConfigOptions, type ResolvableConfig, type ResolvableConfigContext, type ResolvedConfig, SUPPORTED_EXTENSIONS, type SourceOptions, type UserInputConfig, type WatchConfigOptions, createDefineConfig, loadConfig, loadDotenv, setupDotenv, watchConfig };
@@ -1,392 +0,0 @@
1
- 'use strict';
2
-
3
- const node_fs = require('node:fs');
4
- const promises = require('node:fs/promises');
5
- const node_os = require('node:os');
6
- const pathe = require('pathe');
7
- const jiti = require('jiti');
8
- const mlly = require('mlly');
9
- const rc9 = require('rc9');
10
- const defu = require('defu');
11
- const pkgTypes = require('pkg-types');
12
- const dotenv = require('dotenv');
13
-
14
- function _interopNamespaceCompat(e) {
15
- if (e && typeof e === 'object' && 'default' in e) return e;
16
- const n = Object.create(null);
17
- if (e) {
18
- for (const k in e) {
19
- n[k] = e[k];
20
- }
21
- }
22
- n.default = e;
23
- return n;
24
- }
25
-
26
- const rc9__namespace = /*#__PURE__*/_interopNamespaceCompat(rc9);
27
- const dotenv__namespace = /*#__PURE__*/_interopNamespaceCompat(dotenv);
28
-
29
- async function setupDotenv(options) {
30
- const targetEnvironment = options.env ?? process.env;
31
- const environment = await loadDotenv({
32
- cwd: options.cwd,
33
- fileName: options.fileName ?? ".env",
34
- env: targetEnvironment,
35
- interpolate: options.interpolate ?? true
36
- });
37
- for (const key in environment) {
38
- if (!key.startsWith("_") && targetEnvironment[key] === void 0) {
39
- targetEnvironment[key] = environment[key];
40
- }
41
- }
42
- return environment;
43
- }
44
- async function loadDotenv(options) {
45
- const environment = /* @__PURE__ */ Object.create(null);
46
- const dotenvFile = pathe.resolve(options.cwd, options.fileName);
47
- if (node_fs.existsSync(dotenvFile)) {
48
- const parsed = dotenv__namespace.parse(await node_fs.promises.readFile(dotenvFile, "utf8"));
49
- Object.assign(environment, parsed);
50
- }
51
- if (!options.env?._applied) {
52
- Object.assign(environment, options.env);
53
- environment._applied = true;
54
- }
55
- if (options.interpolate) {
56
- interpolate(environment);
57
- }
58
- return environment;
59
- }
60
- function interpolate(target, source = {}, parse = (v) => v) {
61
- function getValue(key) {
62
- return source[key] === void 0 ? target[key] : source[key];
63
- }
64
- function interpolate2(value, parents = []) {
65
- if (typeof value !== "string") {
66
- return value;
67
- }
68
- const matches = value.match(/(.?\${?(?:[\w:]+)?}?)/g) || [];
69
- return parse(
70
- // eslint-disable-next-line unicorn/no-array-reduce
71
- matches.reduce((newValue, match) => {
72
- const parts = /(.?)\${?([\w:]+)?}?/g.exec(match) || [];
73
- const prefix = parts[1];
74
- let value2, replacePart;
75
- if (prefix === "\\") {
76
- replacePart = parts[0] || "";
77
- value2 = replacePart.replace(String.raw`\$`, "$");
78
- } else {
79
- const key = parts[2];
80
- replacePart = (parts[0] || "").slice(prefix.length);
81
- if (parents.includes(key)) {
82
- console.warn(
83
- `Please avoid recursive environment variables ( loop: ${parents.join(
84
- " > "
85
- )} > ${key} )`
86
- );
87
- return "";
88
- }
89
- value2 = getValue(key);
90
- value2 = interpolate2(value2, [...parents, key]);
91
- }
92
- return value2 === void 0 ? newValue : newValue.replace(replacePart, value2);
93
- }, value)
94
- );
95
- }
96
- for (const key in target) {
97
- target[key] = interpolate2(getValue(key));
98
- }
99
- }
100
-
101
- const _normalize = (p) => p?.replace(/\\/g, "/");
102
- const ASYNC_LOADERS = {
103
- ".yaml": () => import('confbox/yaml').then((r) => r.parseYAML),
104
- ".yml": () => import('confbox/yaml').then((r) => r.parseYAML),
105
- ".jsonc": () => import('confbox/jsonc').then((r) => r.parseJSONC),
106
- ".json5": () => import('confbox/json5').then((r) => r.parseJSON5),
107
- ".toml": () => import('confbox/toml').then((r) => r.parseTOML)
108
- };
109
- const SUPPORTED_EXTENSIONS = [
110
- // with jiti
111
- ".js",
112
- ".ts",
113
- ".mjs",
114
- ".cjs",
115
- ".mts",
116
- ".cts",
117
- ".json",
118
- // with confbox
119
- ".jsonc",
120
- ".json5",
121
- ".yaml",
122
- ".yml",
123
- ".toml"
124
- ];
125
- async function loadConfig(options) {
126
- options.cwd = pathe.resolve(process.cwd(), options.cwd || ".");
127
- options.name = options.name || "config";
128
- options.envName = options.envName ?? process.env.NODE_ENV;
129
- options.configFile = options.configFile ?? (options.name === "config" ? "config" : `${options.name}.config`);
130
- options.rcFile = options.rcFile ?? `.${options.name}rc`;
131
- if (options.extend !== false) {
132
- options.extend = {
133
- extendKey: "extends",
134
- ...options.extend
135
- };
136
- }
137
- const _merger = options.merger || defu.defu;
138
- options.jiti = options.jiti || jiti.createJiti(pathe.join(options.cwd, options.configFile), {
139
- interopDefault: true,
140
- moduleCache: false,
141
- extensions: [...SUPPORTED_EXTENSIONS],
142
- ...options.jitiOptions
143
- });
144
- const r = {
145
- config: {},
146
- cwd: options.cwd,
147
- configFile: pathe.resolve(options.cwd, options.configFile),
148
- layers: []
149
- };
150
- const _configs = {
151
- overrides: options.overrides,
152
- main: void 0,
153
- rc: void 0,
154
- packageJson: void 0,
155
- defaultConfig: options.defaultConfig
156
- };
157
- if (options.dotenv) {
158
- await setupDotenv({
159
- cwd: options.cwd,
160
- ...options.dotenv === true ? {} : options.dotenv
161
- });
162
- }
163
- const _mainConfig = await resolveConfig(".", options);
164
- if (_mainConfig.configFile) {
165
- _configs.main = _mainConfig.config;
166
- r.configFile = _mainConfig.configFile;
167
- }
168
- if (_mainConfig.meta) {
169
- r.meta = _mainConfig.meta;
170
- }
171
- if (options.rcFile) {
172
- const rcSources = [];
173
- rcSources.push(rc9__namespace.read({ name: options.rcFile, dir: options.cwd }));
174
- if (options.globalRc) {
175
- const workspaceDir = await pkgTypes.findWorkspaceDir(options.cwd).catch(() => {
176
- });
177
- if (workspaceDir) {
178
- rcSources.push(rc9__namespace.read({ name: options.rcFile, dir: workspaceDir }));
179
- }
180
- rcSources.push(rc9__namespace.readUser({ name: options.rcFile, dir: options.cwd }));
181
- }
182
- _configs.rc = _merger({}, ...rcSources);
183
- }
184
- if (options.packageJson) {
185
- const keys = (Array.isArray(options.packageJson) ? options.packageJson : [
186
- typeof options.packageJson === "string" ? options.packageJson : options.name
187
- ]).filter((t) => t && typeof t === "string");
188
- const pkgJsonFile = await pkgTypes.readPackageJSON(options.cwd).catch(() => {
189
- });
190
- const values = keys.map((key) => pkgJsonFile?.[key]);
191
- _configs.packageJson = _merger({}, ...values);
192
- }
193
- const configs = {};
194
- for (const key in _configs) {
195
- const value = _configs[key];
196
- configs[key] = await (typeof value === "function" ? value({ configs }) : value);
197
- }
198
- r.config = _merger(
199
- configs.overrides,
200
- configs.main,
201
- configs.rc,
202
- configs.packageJson,
203
- configs.defaultConfig
204
- );
205
- if (options.extend) {
206
- await extendConfig(r.config, options);
207
- r.layers = r.config._layers;
208
- delete r.config._layers;
209
- r.config = _merger(r.config, ...r.layers.map((e) => e.config));
210
- }
211
- const baseLayers = [
212
- configs.overrides && {
213
- config: configs.overrides,
214
- configFile: void 0,
215
- cwd: void 0
216
- },
217
- { config: configs.main, configFile: options.configFile, cwd: options.cwd },
218
- configs.rc && { config: configs.rc, configFile: options.rcFile },
219
- configs.packageJson && {
220
- config: configs.packageJson,
221
- configFile: "package.json"
222
- }
223
- ].filter((l) => l && l.config);
224
- r.layers = [...baseLayers, ...r.layers];
225
- if (options.defaults) {
226
- r.config = _merger(r.config, options.defaults);
227
- }
228
- if (options.omit$Keys) {
229
- for (const key in r.config) {
230
- if (key.startsWith("$")) {
231
- delete r.config[key];
232
- }
233
- }
234
- }
235
- return r;
236
- }
237
- async function extendConfig(config, options) {
238
- config._layers = config._layers || [];
239
- if (!options.extend) {
240
- return;
241
- }
242
- let keys = options.extend.extendKey;
243
- if (typeof keys === "string") {
244
- keys = [keys];
245
- }
246
- const extendSources = [];
247
- for (const key of keys) {
248
- extendSources.push(
249
- ...(Array.isArray(config[key]) ? config[key] : [config[key]]).filter(
250
- Boolean
251
- )
252
- );
253
- delete config[key];
254
- }
255
- for (let extendSource of extendSources) {
256
- const originalExtendSource = extendSource;
257
- let sourceOptions = {};
258
- if (extendSource.source) {
259
- sourceOptions = extendSource.options || {};
260
- extendSource = extendSource.source;
261
- }
262
- if (Array.isArray(extendSource)) {
263
- sourceOptions = extendSource[1] || {};
264
- extendSource = extendSource[0];
265
- }
266
- if (typeof extendSource !== "string") {
267
- console.warn(
268
- `Cannot extend config from \`${JSON.stringify(
269
- originalExtendSource
270
- )}\` in ${options.cwd}`
271
- );
272
- continue;
273
- }
274
- const _config = await resolveConfig(extendSource, options, sourceOptions);
275
- if (!_config.config) {
276
- console.warn(
277
- `Cannot extend config from \`${extendSource}\` in ${options.cwd}`
278
- );
279
- continue;
280
- }
281
- await extendConfig(_config.config, { ...options, cwd: _config.cwd });
282
- config._layers.push(_config);
283
- if (_config.config._layers) {
284
- config._layers.push(..._config.config._layers);
285
- delete _config.config._layers;
286
- }
287
- }
288
- }
289
- const GIGET_PREFIXES = [
290
- "gh:",
291
- "github:",
292
- "gitlab:",
293
- "bitbucket:",
294
- "https://",
295
- "http://"
296
- ];
297
- const NPM_PACKAGE_RE = /^(@[\da-z~-][\d._a-z~-]*\/)?[\da-z~-][\d._a-z~-]*($|\/.*)/;
298
- async function resolveConfig(source, options, sourceOptions = {}) {
299
- if (options.resolve) {
300
- const res2 = await options.resolve(source, options);
301
- if (res2) {
302
- return res2;
303
- }
304
- }
305
- const _merger = options.merger || defu.defu;
306
- if (options.giget !== false && GIGET_PREFIXES.some((prefix) => source.startsWith(prefix))) {
307
- const { downloadTemplate } = await import('giget');
308
- const { digest } = await import('ohash');
309
- const cloneName = source.replace(/\W+/g, "_").split("_").splice(0, 3).join("_") + "_" + digest(source).slice(0, 10).replace(/[-_]/g, "");
310
- let cloneDir;
311
- const localNodeModules = pathe.resolve(options.cwd, "node_modules");
312
- const parentDir = pathe.dirname(options.cwd);
313
- if (pathe.basename(parentDir) === ".c12") {
314
- cloneDir = pathe.join(parentDir, cloneName);
315
- } else if (node_fs.existsSync(localNodeModules)) {
316
- cloneDir = pathe.join(localNodeModules, ".c12", cloneName);
317
- } else {
318
- cloneDir = process.env.XDG_CACHE_HOME ? pathe.resolve(process.env.XDG_CACHE_HOME, "c12", cloneName) : pathe.resolve(node_os.homedir(), ".cache/c12", cloneName);
319
- }
320
- if (node_fs.existsSync(cloneDir) && !sourceOptions.install) {
321
- await promises.rm(cloneDir, { recursive: true });
322
- }
323
- const cloned = await downloadTemplate(source, {
324
- dir: cloneDir,
325
- install: sourceOptions.install,
326
- force: sourceOptions.install,
327
- auth: sourceOptions.auth,
328
- ...options.giget,
329
- ...sourceOptions.giget
330
- });
331
- source = cloned.dir;
332
- }
333
- const tryResolve = (id) => {
334
- const resolved = options.jiti.esmResolve(id, { try: true });
335
- return resolved ? mlly.fileURLToPath(resolved) : void 0;
336
- };
337
- if (NPM_PACKAGE_RE.test(source)) {
338
- source = tryResolve(source) || source;
339
- }
340
- const ext = pathe.extname(source);
341
- const isDir = !ext || ext === pathe.basename(source);
342
- const cwd = pathe.resolve(options.cwd, isDir ? source : pathe.dirname(source));
343
- if (isDir) {
344
- source = options.configFile;
345
- }
346
- const res = {
347
- config: void 0,
348
- configFile: void 0,
349
- cwd,
350
- source,
351
- sourceOptions
352
- };
353
- res.configFile = tryResolve(pathe.resolve(cwd, source)) || tryResolve(pathe.resolve(cwd, ".config", source.replace(/\.config$/, ""))) || tryResolve(pathe.resolve(cwd, ".config", source)) || source;
354
- if (!node_fs.existsSync(res.configFile)) {
355
- return res;
356
- }
357
- const configFileExt = pathe.extname(res.configFile) || "";
358
- if (configFileExt in ASYNC_LOADERS) {
359
- const asyncLoader = await ASYNC_LOADERS[configFileExt]();
360
- const contents = await promises.readFile(res.configFile, "utf8");
361
- res.config = asyncLoader(contents);
362
- } else {
363
- res.config = await options.jiti.import(res.configFile, {
364
- default: true
365
- });
366
- }
367
- if (res.config instanceof Function) {
368
- res.config = await res.config();
369
- }
370
- if (options.envName) {
371
- const envConfig = {
372
- ...res.config["$" + options.envName],
373
- ...res.config.$env?.[options.envName]
374
- };
375
- if (Object.keys(envConfig).length > 0) {
376
- res.config = _merger(envConfig, res.config);
377
- }
378
- }
379
- res.meta = defu.defu(res.sourceOptions.meta, res.config.$meta);
380
- delete res.config.$meta;
381
- if (res.sourceOptions.overrides) {
382
- res.config = _merger(res.sourceOptions.overrides, res.config);
383
- }
384
- res.configFile = _normalize(res.configFile);
385
- res.source = _normalize(res.source);
386
- return res;
387
- }
388
-
389
- exports.SUPPORTED_EXTENSIONS = SUPPORTED_EXTENSIONS;
390
- exports.loadConfig = loadConfig;
391
- exports.loadDotenv = loadDotenv;
392
- exports.setupDotenv = setupDotenv;
package/dist/update.cjs DELETED
@@ -1,75 +0,0 @@
1
- 'use strict';
2
-
3
- const mlly = require('mlly');
4
- const loader = require('./shared/c12.CMG3XLfD.cjs');
5
- const pathe = require('pathe');
6
- const promises = require('node:fs/promises');
7
- const node_path = require('node:path');
8
- require('node:fs');
9
- require('node:os');
10
- require('jiti');
11
- require('rc9');
12
- require('defu');
13
- require('pkg-types');
14
- require('dotenv');
15
-
16
- const UPDATABLE_EXTS = [".js", ".ts", ".mjs", ".cjs", ".mts", ".cts"];
17
- async function updateConfig(opts) {
18
- const { parseModule } = await import('magicast');
19
- let configFile = await _tryResolve(
20
- `./${opts.configFile}`,
21
- opts.cwd,
22
- loader.SUPPORTED_EXTENSIONS
23
- ) || await _tryResolve(
24
- `./.config/${opts.configFile}`,
25
- opts.cwd,
26
- loader.SUPPORTED_EXTENSIONS
27
- ) || await _tryResolve(
28
- `./.config/${opts.configFile.split(".")[0]}`,
29
- opts.cwd,
30
- loader.SUPPORTED_EXTENSIONS
31
- );
32
- let created = false;
33
- if (!configFile) {
34
- configFile = pathe.join(
35
- opts.cwd,
36
- opts.configFile + (opts.createExtension || ".ts")
37
- );
38
- const createResult = await opts.onCreate?.({ configFile }) ?? true;
39
- if (!createResult) {
40
- throw new Error("Config file creation aborted.");
41
- }
42
- const content = typeof createResult === "string" ? createResult : `export default {}
43
- `;
44
- await promises.mkdir(node_path.dirname(configFile), { recursive: true });
45
- await promises.writeFile(configFile, content, "utf8");
46
- created = true;
47
- }
48
- const ext = node_path.extname(configFile);
49
- if (!UPDATABLE_EXTS.includes(ext)) {
50
- throw new Error(
51
- `Unsupported config file extension: ${ext} (${configFile}) (supported: ${UPDATABLE_EXTS.join(", ")})`
52
- );
53
- }
54
- const contents = await promises.readFile(configFile, "utf8");
55
- const _module = parseModule(contents, opts.magicast);
56
- const defaultExport = _module.exports.default;
57
- if (!defaultExport) {
58
- throw new Error("Default export is missing in the config file!");
59
- }
60
- const configObj = defaultExport.$type === "function-call" ? defaultExport.$args[0] : defaultExport;
61
- await opts.onUpdate?.(configObj);
62
- await promises.writeFile(configFile, _module.generate().code);
63
- return {
64
- configFile,
65
- created
66
- };
67
- }
68
- function _tryResolve(path, cwd, exts) {
69
- return mlly.resolvePath(path, {
70
- url: pathe.join(cwd, "_index.js"),
71
- extensions: exts
72
- }).catch(() => void 0);
73
- }
74
-
75
- exports.updateConfig = updateConfig;
package/dist/update.d.cts DELETED
@@ -1,52 +0,0 @@
1
- import * as magicast from 'magicast';
2
-
3
- /**
4
- * @experimental Update a config file or create a new one.
5
- */
6
- declare function updateConfig(opts: UpdateConfigOptions): Promise<UpdateConfigResult>;
7
- interface UpdateConfigResult {
8
- configFile?: string;
9
- created?: boolean;
10
- }
11
- type MaybePromise<T> = T | Promise<T>;
12
- type MagicAstOptions = Exclude<Parameters<(typeof magicast)["parseModule"]>[1], undefined>;
13
- interface UpdateConfigOptions {
14
- /**
15
- * Current working directory
16
- */
17
- cwd: string;
18
- /**
19
- * Config file name
20
- */
21
- configFile: string;
22
- /**
23
- * Extension used for new config file.
24
- */
25
- createExtension?: string;
26
- /**
27
- * Magicast options
28
- */
29
- magicast?: MagicAstOptions;
30
- /**
31
- * Update function.
32
- */
33
- onUpdate?: (config: any) => MaybePromise<void>;
34
- /**
35
- * Handle default config creation.
36
- *
37
- * Tip: you can use this option as a hook to prompt users about config creation.
38
- *
39
- * Context object:
40
- * - path: determined full path to the config file
41
- *
42
- * Returns types:
43
- * - string: custom config template
44
- * - true: write the template
45
- * - false: abort the operation
46
- */
47
- onCreate?: (ctx: {
48
- configFile: string;
49
- }) => MaybePromise<string | boolean>;
50
- }
51
-
52
- export { type UpdateConfigOptions, type UpdateConfigResult, updateConfig };
package/dist/update.d.ts DELETED
@@ -1,52 +0,0 @@
1
- import * as magicast from 'magicast';
2
-
3
- /**
4
- * @experimental Update a config file or create a new one.
5
- */
6
- declare function updateConfig(opts: UpdateConfigOptions): Promise<UpdateConfigResult>;
7
- interface UpdateConfigResult {
8
- configFile?: string;
9
- created?: boolean;
10
- }
11
- type MaybePromise<T> = T | Promise<T>;
12
- type MagicAstOptions = Exclude<Parameters<(typeof magicast)["parseModule"]>[1], undefined>;
13
- interface UpdateConfigOptions {
14
- /**
15
- * Current working directory
16
- */
17
- cwd: string;
18
- /**
19
- * Config file name
20
- */
21
- configFile: string;
22
- /**
23
- * Extension used for new config file.
24
- */
25
- createExtension?: string;
26
- /**
27
- * Magicast options
28
- */
29
- magicast?: MagicAstOptions;
30
- /**
31
- * Update function.
32
- */
33
- onUpdate?: (config: any) => MaybePromise<void>;
34
- /**
35
- * Handle default config creation.
36
- *
37
- * Tip: you can use this option as a hook to prompt users about config creation.
38
- *
39
- * Context object:
40
- * - path: determined full path to the config file
41
- *
42
- * Returns types:
43
- * - string: custom config template
44
- * - true: write the template
45
- * - false: abort the operation
46
- */
47
- onCreate?: (ctx: {
48
- configFile: string;
49
- }) => MaybePromise<string | boolean>;
50
- }
51
-
52
- export { type UpdateConfigOptions, type UpdateConfigResult, updateConfig };
package/update.d.ts DELETED
@@ -1 +0,0 @@
1
- export * from "./dist/update";