@rstackjs/load-config 0.1.2 → 1.0.1
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 +21 -0
- package/dist/cachedImport.d.ts +2 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +45 -11
- package/dist/meta.d.ts +8 -0
- package/dist/types.d.ts +18 -4
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -235,6 +235,27 @@ await loadConfig({
|
|
|
235
235
|
|
|
236
236
|
When using the `native` loader and `fresh` is enabled, `dependencies` contains absolute paths for files imported by the config file.
|
|
237
237
|
|
|
238
|
+
### withConfigMeta
|
|
239
|
+
|
|
240
|
+
Preserve the original config path and dependencies when loading through an adapter:
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
import { withConfigMeta } from '@rstackjs/load-config';
|
|
244
|
+
|
|
245
|
+
const config = { name: 'my-tool' };
|
|
246
|
+
|
|
247
|
+
export default withConfigMeta(config, {
|
|
248
|
+
filePath: '/project/project.config.ts',
|
|
249
|
+
dependencies: ['/project/shared.ts'],
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
`loadConfig` uses the supplied `filePath` and merges `dependencies` with the adapter file and its collected dependencies, removing duplicates.
|
|
254
|
+
|
|
255
|
+
- Use absolute paths. `filePath: null` means no underlying config was found; `dependencies` is optional.
|
|
256
|
+
- The helper modifies and returns the original config object. Repeated calls replace its metadata. Frozen or non-extensible objects are not supported.
|
|
257
|
+
- Call it on the final config object: object spread and JSON serialization discard the metadata.
|
|
258
|
+
|
|
238
259
|
## License
|
|
239
260
|
|
|
240
261
|
[MIT](./LICENSE).
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { LoadConfigOptions, LoadConfigResult } from './types.js';
|
|
2
|
-
export
|
|
2
|
+
export { withConfigMeta } from './meta.js';
|
|
3
|
+
export type { ConfigDefinition, ConfigFileMeta, ConfigLoader, LoadConfigOptions, LoadConfigResult, } from './types.js';
|
|
3
4
|
export declare function loadConfig<Config = unknown, Params extends unknown[] = []>({ cwd, path, configFileNames, loader, exportName, configParams, fresh, }?: LoadConfigOptions<Params>): Promise<LoadConfigResult<Config>>;
|
package/dist/index.js
CHANGED
|
@@ -9,10 +9,18 @@ const getConfigExport = (configModule, exportName, configPath)=>{
|
|
|
9
9
|
if (canReadExport(configModule) && Object.hasOwn(configModule, exportName)) return configModule[exportName];
|
|
10
10
|
throw new Error(`Cannot find export ${exportName} in config file: ${configPath}`);
|
|
11
11
|
};
|
|
12
|
+
const cachedImport = (importer)=>{
|
|
13
|
+
let promise;
|
|
14
|
+
return ()=>promise ??= importer().catch((error)=>{
|
|
15
|
+
promise = void 0;
|
|
16
|
+
throw error;
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
const getJiti = cachedImport(()=>import("jiti"));
|
|
12
20
|
const loadWithJiti = async (configPath, exportName, fresh)=>{
|
|
13
21
|
let createJiti;
|
|
14
22
|
try {
|
|
15
|
-
({ createJiti } = await
|
|
23
|
+
({ createJiti } = await getJiti());
|
|
16
24
|
} catch (error) {
|
|
17
25
|
throw new Error('The "jiti" package is required to load this config. Install it with your package manager.', {
|
|
18
26
|
cause: error
|
|
@@ -37,6 +45,23 @@ const loadWithJiti = async (configPath, exportName, fresh)=>{
|
|
|
37
45
|
dependencies: []
|
|
38
46
|
};
|
|
39
47
|
};
|
|
48
|
+
const CONFIG_META = Symbol.for('@rstackjs/load-config/meta');
|
|
49
|
+
function withConfigMeta(config, meta) {
|
|
50
|
+
Object.defineProperty(config, CONFIG_META, {
|
|
51
|
+
configurable: true,
|
|
52
|
+
value: {
|
|
53
|
+
filePath: meta.filePath,
|
|
54
|
+
dependencies: [
|
|
55
|
+
...meta.dependencies ?? []
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return config;
|
|
60
|
+
}
|
|
61
|
+
function getConfigMeta(config) {
|
|
62
|
+
if (null !== config && 'object' == typeof config && Object.hasOwn(config, CONFIG_META)) return config[CONFIG_META];
|
|
63
|
+
}
|
|
64
|
+
const getFreshImport = cachedImport(()=>import("./freshImport.js"));
|
|
40
65
|
const JS_CONFIG_REGEXP = /\.(?:js|mjs|cjs)$/;
|
|
41
66
|
const loadWithNative = async (configPath, fresh)=>{
|
|
42
67
|
const configFileURL = pathToFileURL(configPath).href;
|
|
@@ -47,7 +72,7 @@ const loadWithNative = async (configPath, fresh)=>{
|
|
|
47
72
|
dependencies: []
|
|
48
73
|
};
|
|
49
74
|
}
|
|
50
|
-
const { freshImport } = await
|
|
75
|
+
const { freshImport } = await getFreshImport();
|
|
51
76
|
const freshImportResult = await freshImport(configFileURL);
|
|
52
77
|
if (freshImportResult) return {
|
|
53
78
|
configModule: freshImportResult.result,
|
|
@@ -95,19 +120,28 @@ async function loadConfig({ cwd = process.cwd(), path, configFileNames = [], loa
|
|
|
95
120
|
}
|
|
96
121
|
if (!loadedConfig) loadedConfig = await loadWithJiti(configPath, exportName, fresh);
|
|
97
122
|
const { configExport, dependencies } = loadedConfig;
|
|
123
|
+
let content;
|
|
98
124
|
if (isConfigFunction(configExport)) {
|
|
99
125
|
const result = await configExport(...configParams);
|
|
100
126
|
if (void 0 === result) throw new Error('The config function must return a config object.');
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
return {
|
|
108
|
-
content: configExport,
|
|
127
|
+
content = result;
|
|
128
|
+
} else content = configExport;
|
|
129
|
+
const meta = getConfigMeta(content);
|
|
130
|
+
const result = {
|
|
131
|
+
content,
|
|
109
132
|
filePath: configPath,
|
|
110
133
|
dependencies
|
|
111
134
|
};
|
|
135
|
+
if (meta) {
|
|
136
|
+
result.filePath = meta.filePath;
|
|
137
|
+
result.dependencies = [
|
|
138
|
+
...new Set([
|
|
139
|
+
...meta.dependencies ?? [],
|
|
140
|
+
configPath,
|
|
141
|
+
...dependencies
|
|
142
|
+
])
|
|
143
|
+
];
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
112
146
|
}
|
|
113
|
-
export { loadConfig };
|
|
147
|
+
export { loadConfig, withConfigMeta };
|
package/dist/meta.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ConfigFileMeta } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Attach file metadata in place and return the original configuration object.
|
|
4
|
+
* Repeated calls replace the metadata. Requires an extensible, unfrozen object.
|
|
5
|
+
* Call this after merging the config: object spread does not preserve metadata.
|
|
6
|
+
*/
|
|
7
|
+
export declare function withConfigMeta<Config extends object>(config: Config, meta: ConfigFileMeta): Config;
|
|
8
|
+
export declare function getConfigMeta(config: unknown): ConfigFileMeta | undefined;
|
package/dist/types.d.ts
CHANGED
|
@@ -43,19 +43,33 @@ export type LoadConfigOptions<Params extends unknown[] = []> = {
|
|
|
43
43
|
*/
|
|
44
44
|
fresh?: boolean;
|
|
45
45
|
};
|
|
46
|
+
export type ConfigFileMeta = {
|
|
47
|
+
/**
|
|
48
|
+
* Absolute path of the actual configuration file.
|
|
49
|
+
* Use `null` when no underlying configuration file was found.
|
|
50
|
+
*/
|
|
51
|
+
filePath: string | null;
|
|
52
|
+
/**
|
|
53
|
+
* Absolute paths of additional configuration dependencies.
|
|
54
|
+
* These are merged with the adapter file and its collected dependencies.
|
|
55
|
+
*/
|
|
56
|
+
dependencies?: readonly string[];
|
|
57
|
+
};
|
|
46
58
|
export type LoadConfigResult<Config = unknown> = {
|
|
47
59
|
/**
|
|
48
60
|
* The loaded configuration object.
|
|
49
61
|
*/
|
|
50
62
|
content: Config;
|
|
51
63
|
/**
|
|
52
|
-
* The path to the loaded configuration file
|
|
53
|
-
*
|
|
64
|
+
* The path to the loaded configuration file, or the source set by `withConfigMeta`.
|
|
65
|
+
* Returns `null` if no configuration file was found, including an explicit
|
|
66
|
+
* `null` source set by `withConfigMeta`.
|
|
54
67
|
*/
|
|
55
68
|
filePath: string | null;
|
|
56
69
|
/**
|
|
57
|
-
* Absolute
|
|
58
|
-
*
|
|
70
|
+
* Absolute paths of collected configuration dependencies. When `withConfigMeta`
|
|
71
|
+
* is used, also includes explicit dependencies and the loaded adapter file,
|
|
72
|
+
* with duplicates removed.
|
|
59
73
|
*/
|
|
60
74
|
dependencies: string[];
|
|
61
75
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rstackjs/load-config",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/rstackjs/load-config"
|
|
@@ -21,8 +21,7 @@
|
|
|
21
21
|
"@types/node": "^24.13.2",
|
|
22
22
|
"fresh-import": "^0.2.1",
|
|
23
23
|
"jiti": "^2.7.0",
|
|
24
|
-
"
|
|
25
|
-
"rstack": "0.0.2",
|
|
24
|
+
"rstack": "^0.6.4",
|
|
26
25
|
"typescript": "^7.0.2"
|
|
27
26
|
},
|
|
28
27
|
"peerDependencies": {
|
|
@@ -39,10 +38,11 @@
|
|
|
39
38
|
},
|
|
40
39
|
"scripts": {
|
|
41
40
|
"build": "rs lib",
|
|
41
|
+
"check": "rs check --type-check",
|
|
42
42
|
"dev": "rs lib -w",
|
|
43
|
-
"
|
|
44
|
-
"lint
|
|
43
|
+
"format": "rs fmt",
|
|
44
|
+
"lint": "rs lint",
|
|
45
45
|
"test": "rs test",
|
|
46
|
-
"bump": "
|
|
46
|
+
"bump": "pnpm version -m \"release: v%s\""
|
|
47
47
|
}
|
|
48
48
|
}
|