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 +1 -1
- package/dist/index.cjs +50 -39
- package/dist/index.d.ts +10 -3
- package/dist/index.mjs +50 -39
- package/package.json +1 -1
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
|
|
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
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
-
|
|
134
|
-
async function extendConfig(config, configFile, cwd) {
|
|
141
|
+
async function extendConfig(config, opts) {
|
|
135
142
|
config._layers = config._layers || [];
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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,
|
|
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
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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,
|
|
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
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
110
|
-
async function extendConfig(config, configFile, cwd) {
|
|
117
|
+
async function extendConfig(config, opts) {
|
|
111
118
|
config._layers = config._layers || [];
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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,
|
|
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
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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,
|
|
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();
|