c12 0.1.1 → 0.1.2

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
@@ -13,7 +13,7 @@
13
13
  - RC config support with [unjs/rc9](https://github.com/unjs/rc9)
14
14
  - Multiple sources merged with [unjs/defu](https://github.com/unjs/defu)
15
15
  - `.env` support with [dotenv](https://www.npmjs.com/package/dotenv)
16
- - Support extending nested configurations from multiple local or git sourecs
16
+ - Support extending nested configurations from multiple local or git sources
17
17
 
18
18
  ## Usage
19
19
 
package/dist/index.cjs CHANGED
@@ -100,6 +100,12 @@ async function loadConfig(opts) {
100
100
  opts.name = opts.name || "config";
101
101
  opts.configFile = opts.configFile ?? (opts.name !== "config" ? `${opts.name}.config` : "config");
102
102
  opts.rcFile = opts.rcFile ?? `.${opts.name}rc`;
103
+ if (opts.extend !== false) {
104
+ opts.extend = {
105
+ extendKey: "extends",
106
+ ...opts.extend
107
+ };
108
+ }
103
109
  const r = {
104
110
  config: {},
105
111
  cwd: opts.cwd,
@@ -112,7 +118,7 @@ async function loadConfig(opts) {
112
118
  ...opts.dotenv === true ? {} : opts.dotenv
113
119
  });
114
120
  }
115
- const { config, configFile } = await loadConfigFile(opts.cwd, opts.configFile);
121
+ const { config, configFile } = await resolveConfig(".", opts);
116
122
  if (configFile) {
117
123
  r.configFile = configFile;
118
124
  }
@@ -124,59 +130,64 @@ async function loadConfig(opts) {
124
130
  Object.assign(configRC, rc9__namespace.read({ name: opts.rcFile, dir: opts.cwd }));
125
131
  }
126
132
  r.config = defu__default(opts.overrides, config, configRC, opts.defaults);
127
- await extendConfig(r.config, opts.configFile, opts.cwd);
128
- r.layers = r.config._layers;
129
- delete r.config._layers;
130
- r.config = defu__default(r.config, ...r.layers.map((e) => e.config));
133
+ if (opts.extend) {
134
+ await extendConfig(r.config, opts);
135
+ r.layers = r.config._layers;
136
+ delete r.config._layers;
137
+ r.config = defu__default(r.config, ...r.layers.map((e) => e.config));
138
+ }
131
139
  return r;
132
140
  }
133
- const GIT_PREFIXES = ["github:", "gitlab:", "bitbucket:", "https://"];
134
- async function extendConfig(config, configFile, cwd) {
141
+ async function extendConfig(config, opts) {
135
142
  config._layers = config._layers || [];
136
- const extendSources = (Array.isArray(config.extends) ? config.extends : [config.extends]).filter(Boolean);
137
- delete config.extends;
138
- for (let extendSource of extendSources) {
139
- if (GIT_PREFIXES.some((prefix) => extendSource.startsWith(prefix))) {
140
- const url = new URL(extendSource);
141
- const subPath = url.pathname.split("/").slice(2).join("/");
142
- const gitRepo = url.protocol + url.pathname.split("/").slice(0, 2).join("/");
143
- const tmpdir = pathe.resolve(os__default.tmpdir(), "c12/", gitRepo.replace(/[#:@/\\]/g, "_"));
144
- await fs.promises.rm(tmpdir, { recursive: true }).catch(() => {
145
- });
146
- const gittar = await import('gittar').then((r) => r.default || r);
147
- const tarFile = await gittar.fetch(gitRepo);
148
- await gittar.extract(tarFile, tmpdir);
149
- extendSource = pathe.resolve(tmpdir, subPath);
150
- }
151
- const isDir = !pathe.extname(extendSource);
152
- const _cwd = pathe.resolve(cwd, isDir ? extendSource : pathe.dirname(extendSource));
153
- const _config = await loadConfigFile(_cwd, isDir ? configFile : extendSource);
143
+ if (!opts.extend) {
144
+ return;
145
+ }
146
+ const key = opts.extend.extendKey;
147
+ const extendSources = (Array.isArray(config[key]) ? config[key] : [config[key]]).filter(Boolean);
148
+ delete config[key];
149
+ for (const extendSource of extendSources) {
150
+ const _config = await resolveConfig(extendSource, opts);
154
151
  if (!_config.config) {
155
152
  continue;
156
153
  }
157
- await extendConfig(_config.config, configFile, _cwd);
158
- config._layers.push({
159
- config: _config.config,
160
- cwd: _cwd,
161
- configFile: _config.configFile
162
- });
154
+ await extendConfig(_config.config, { ...opts, cwd: _config.cwd });
155
+ config._layers.push(_config);
163
156
  if (_config.config._layers) {
164
157
  config._layers.push(..._config.config._layers);
165
158
  delete _config.config._layers;
166
159
  }
167
160
  }
168
161
  }
162
+ const GIT_PREFIXES = ["github:", "gitlab:", "bitbucket:", "https://"];
169
163
  const jiti = createJiti__default(null, { cache: false, interopDefault: true });
170
- async function loadConfigFile(cwd, configFile) {
171
- const res = {
172
- configFile: null,
173
- config: null
174
- };
175
- if (!configFile) {
176
- return res;
164
+ async function resolveConfig(source, opts) {
165
+ if (opts.resolve) {
166
+ const res2 = await opts.resolve(source, opts);
167
+ if (res2) {
168
+ return res2;
169
+ }
170
+ }
171
+ if (GIT_PREFIXES.some((prefix) => source.startsWith(prefix))) {
172
+ const url = new URL(source);
173
+ const subPath = url.pathname.split("/").slice(2).join("/");
174
+ const gitRepo = url.protocol + url.pathname.split("/").slice(0, 2).join("/");
175
+ const tmpdir = pathe.resolve(os__default.tmpdir(), "c12/", gitRepo.replace(/[#:@/\\]/g, "_"));
176
+ await fs.promises.rm(tmpdir, { recursive: true }).catch(() => {
177
+ });
178
+ const gittar = await import('gittar').then((r) => r.default || r);
179
+ const tarFile = await gittar.fetch(gitRepo);
180
+ await gittar.extract(tarFile, tmpdir);
181
+ source = pathe.resolve(tmpdir, subPath);
182
+ }
183
+ const isDir = !pathe.extname(source);
184
+ const cwd = pathe.resolve(opts.cwd, isDir ? source : pathe.dirname(source));
185
+ if (isDir) {
186
+ source = opts.configFile;
177
187
  }
188
+ const res = { config: {}, cwd };
178
189
  try {
179
- res.configFile = jiti.resolve(pathe.resolve(cwd, configFile), { paths: [cwd] });
190
+ res.configFile = jiti.resolve(pathe.resolve(cwd, source), { paths: [cwd] });
180
191
  res.config = jiti(res.configFile);
181
192
  if (typeof res.config === "function") {
182
193
  res.config = await res.config();
package/dist/index.d.ts CHANGED
@@ -38,9 +38,12 @@ interface InputConfig extends Record<string, any> {
38
38
  }
39
39
  interface ResolvedConfig<T extends InputConfig = InputConfig> {
40
40
  config: T;
41
+ cwd?: string;
42
+ configFile?: string;
43
+ layers?: ResolvedConfig<T>[];
44
+ }
45
+ interface ResolveConfigOptions {
41
46
  cwd: string;
42
- configFile: string;
43
- layers: ResolvedConfig<T>[];
44
47
  }
45
48
  interface LoadConfigOptions<T extends InputConfig = InputConfig> {
46
49
  name?: string;
@@ -51,7 +54,11 @@ interface LoadConfigOptions<T extends InputConfig = InputConfig> {
51
54
  dotenv?: boolean | DotenvOptions;
52
55
  defaults?: T;
53
56
  overrides?: T;
57
+ resolve?: (id: string, opts: LoadConfigOptions) => null | ResolvedConfig | Promise<ResolvedConfig | null>;
58
+ extend?: false | {
59
+ extendKey?: string;
60
+ };
54
61
  }
55
62
  declare function loadConfig<T extends InputConfig = InputConfig>(opts: LoadConfigOptions<T>): Promise<ResolvedConfig<T>>;
56
63
 
57
- export { DotenvOptions, Env, InputConfig, LoadConfigOptions, ResolvedConfig, loadConfig, loadDotenv, setupDotenv };
64
+ export { DotenvOptions, Env, InputConfig, LoadConfigOptions, ResolveConfigOptions, ResolvedConfig, loadConfig, loadDotenv, setupDotenv };
package/dist/index.mjs CHANGED
@@ -76,6 +76,12 @@ async function loadConfig(opts) {
76
76
  opts.name = opts.name || "config";
77
77
  opts.configFile = opts.configFile ?? (opts.name !== "config" ? `${opts.name}.config` : "config");
78
78
  opts.rcFile = opts.rcFile ?? `.${opts.name}rc`;
79
+ if (opts.extend !== false) {
80
+ opts.extend = {
81
+ extendKey: "extends",
82
+ ...opts.extend
83
+ };
84
+ }
79
85
  const r = {
80
86
  config: {},
81
87
  cwd: opts.cwd,
@@ -88,7 +94,7 @@ async function loadConfig(opts) {
88
94
  ...opts.dotenv === true ? {} : opts.dotenv
89
95
  });
90
96
  }
91
- const { config, configFile } = await loadConfigFile(opts.cwd, opts.configFile);
97
+ const { config, configFile } = await resolveConfig(".", opts);
92
98
  if (configFile) {
93
99
  r.configFile = configFile;
94
100
  }
@@ -100,59 +106,64 @@ async function loadConfig(opts) {
100
106
  Object.assign(configRC, rc9.read({ name: opts.rcFile, dir: opts.cwd }));
101
107
  }
102
108
  r.config = defu(opts.overrides, config, configRC, opts.defaults);
103
- await extendConfig(r.config, opts.configFile, opts.cwd);
104
- r.layers = r.config._layers;
105
- delete r.config._layers;
106
- r.config = defu(r.config, ...r.layers.map((e) => e.config));
109
+ if (opts.extend) {
110
+ await extendConfig(r.config, opts);
111
+ r.layers = r.config._layers;
112
+ delete r.config._layers;
113
+ r.config = defu(r.config, ...r.layers.map((e) => e.config));
114
+ }
107
115
  return r;
108
116
  }
109
- const GIT_PREFIXES = ["github:", "gitlab:", "bitbucket:", "https://"];
110
- async function extendConfig(config, configFile, cwd) {
117
+ async function extendConfig(config, opts) {
111
118
  config._layers = config._layers || [];
112
- const extendSources = (Array.isArray(config.extends) ? config.extends : [config.extends]).filter(Boolean);
113
- delete config.extends;
114
- for (let extendSource of extendSources) {
115
- if (GIT_PREFIXES.some((prefix) => extendSource.startsWith(prefix))) {
116
- const url = new URL(extendSource);
117
- const subPath = url.pathname.split("/").slice(2).join("/");
118
- const gitRepo = url.protocol + url.pathname.split("/").slice(0, 2).join("/");
119
- const tmpdir = resolve(os.tmpdir(), "c12/", gitRepo.replace(/[#:@/\\]/g, "_"));
120
- await promises.rm(tmpdir, { recursive: true }).catch(() => {
121
- });
122
- const gittar = await import('gittar').then((r) => r.default || r);
123
- const tarFile = await gittar.fetch(gitRepo);
124
- await gittar.extract(tarFile, tmpdir);
125
- extendSource = resolve(tmpdir, subPath);
126
- }
127
- const isDir = !extname(extendSource);
128
- const _cwd = resolve(cwd, isDir ? extendSource : dirname(extendSource));
129
- const _config = await loadConfigFile(_cwd, isDir ? configFile : extendSource);
119
+ if (!opts.extend) {
120
+ return;
121
+ }
122
+ const key = opts.extend.extendKey;
123
+ const extendSources = (Array.isArray(config[key]) ? config[key] : [config[key]]).filter(Boolean);
124
+ delete config[key];
125
+ for (const extendSource of extendSources) {
126
+ const _config = await resolveConfig(extendSource, opts);
130
127
  if (!_config.config) {
131
128
  continue;
132
129
  }
133
- await extendConfig(_config.config, configFile, _cwd);
134
- config._layers.push({
135
- config: _config.config,
136
- cwd: _cwd,
137
- configFile: _config.configFile
138
- });
130
+ await extendConfig(_config.config, { ...opts, cwd: _config.cwd });
131
+ config._layers.push(_config);
139
132
  if (_config.config._layers) {
140
133
  config._layers.push(..._config.config._layers);
141
134
  delete _config.config._layers;
142
135
  }
143
136
  }
144
137
  }
138
+ const GIT_PREFIXES = ["github:", "gitlab:", "bitbucket:", "https://"];
145
139
  const jiti = createJiti(null, { cache: false, interopDefault: true });
146
- async function loadConfigFile(cwd, configFile) {
147
- const res = {
148
- configFile: null,
149
- config: null
150
- };
151
- if (!configFile) {
152
- return res;
140
+ async function resolveConfig(source, opts) {
141
+ if (opts.resolve) {
142
+ const res2 = await opts.resolve(source, opts);
143
+ if (res2) {
144
+ return res2;
145
+ }
146
+ }
147
+ if (GIT_PREFIXES.some((prefix) => source.startsWith(prefix))) {
148
+ const url = new URL(source);
149
+ const subPath = url.pathname.split("/").slice(2).join("/");
150
+ const gitRepo = url.protocol + url.pathname.split("/").slice(0, 2).join("/");
151
+ const tmpdir = resolve(os.tmpdir(), "c12/", gitRepo.replace(/[#:@/\\]/g, "_"));
152
+ await promises.rm(tmpdir, { recursive: true }).catch(() => {
153
+ });
154
+ const gittar = await import('gittar').then((r) => r.default || r);
155
+ const tarFile = await gittar.fetch(gitRepo);
156
+ await gittar.extract(tarFile, tmpdir);
157
+ source = resolve(tmpdir, subPath);
158
+ }
159
+ const isDir = !extname(source);
160
+ const cwd = resolve(opts.cwd, isDir ? source : dirname(source));
161
+ if (isDir) {
162
+ source = opts.configFile;
153
163
  }
164
+ const res = { config: {}, cwd };
154
165
  try {
155
- res.configFile = jiti.resolve(resolve(cwd, configFile), { paths: [cwd] });
166
+ res.configFile = jiti.resolve(resolve(cwd, source), { paths: [cwd] });
156
167
  res.config = jiti(res.configFile);
157
168
  if (typeof res.config === "function") {
158
169
  res.config = await res.config();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c12",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Smart Config Loader",
5
5
  "repository": "unjs/c12",
6
6
  "license": "MIT",