@vitus-labs/tools-core 1.8.1-alpha.2 → 1.9.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/lib/index.js +20 -30
- package/lib/index.js.map +1 -1
- package/lib/types/index.d.ts +2 -2
- package/lib/types/index.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/index.test.ts +201 -246
- package/src/index.ts +23 -33
package/lib/index.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import { createRequire } from 'node:module';
|
|
3
2
|
import path from 'node:path';
|
|
4
|
-
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
const VL_CONFIG_FILES = ['vl-tools.config.mjs'];
|
|
5
5
|
const PACKAGE_FILE_NAME = 'package.json';
|
|
6
6
|
const TYPESCRIPT_FILE_NAME = 'tsconfig.json';
|
|
7
|
-
const require = createRequire(import.meta.url);
|
|
8
7
|
// --------------------------------------------------------
|
|
9
8
|
// Utility helpers (replaces lodash-es and find-up)
|
|
10
9
|
// --------------------------------------------------------
|
|
@@ -61,40 +60,31 @@ const findFileUp = (names, cwd = process.cwd()) => {
|
|
|
61
60
|
// FIND & READ file helpers
|
|
62
61
|
// --------------------------------------------------------
|
|
63
62
|
const findFile = (filename) => findFileUp(filename);
|
|
64
|
-
const loadModule = (filePath) => {
|
|
65
|
-
try {
|
|
66
|
-
const imported = require(filePath);
|
|
67
|
-
// Handle ESM default export wrapping
|
|
68
|
-
return imported?.default ?? imported ?? {};
|
|
69
|
-
}
|
|
70
|
-
catch (_e) {
|
|
71
|
-
return {};
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
63
|
const loadFileToJSON = (filename) => {
|
|
75
64
|
const file = findFile(filename);
|
|
76
65
|
if (!file)
|
|
77
66
|
return {};
|
|
78
|
-
// try to read an exported module first
|
|
79
|
-
const data = loadModule(file);
|
|
80
|
-
if (data && Object.keys(data).length > 0)
|
|
81
|
-
return data;
|
|
82
|
-
// try to read a plain json file like tsconfig.json
|
|
83
67
|
try {
|
|
84
68
|
return JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
85
69
|
}
|
|
86
70
|
catch (_e) {
|
|
87
|
-
|
|
71
|
+
return {};
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const loadModuleAsync = async (filePath) => {
|
|
75
|
+
try {
|
|
76
|
+
const mod = await import(pathToFileURL(filePath).href);
|
|
77
|
+
return mod?.default ?? mod ?? {};
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
console.warn(`[tools-core] Failed to load config: ${filePath}\n ${e.message}`);
|
|
81
|
+
return {};
|
|
88
82
|
}
|
|
89
|
-
return {};
|
|
90
83
|
};
|
|
91
84
|
// --------------------------------------------------------
|
|
92
85
|
// GET PACKAGE.JSON info
|
|
93
86
|
// --------------------------------------------------------
|
|
94
|
-
const getPackageJSON = () =>
|
|
95
|
-
const data = loadFileToJSON(PACKAGE_FILE_NAME);
|
|
96
|
-
return data;
|
|
97
|
-
};
|
|
87
|
+
const getPackageJSON = () => loadFileToJSON(PACKAGE_FILE_NAME);
|
|
98
88
|
// --------------------------------------------------------
|
|
99
89
|
// PACKAGE.json parsing functions
|
|
100
90
|
// --------------------------------------------------------
|
|
@@ -136,7 +126,7 @@ const getPkgData = () => {
|
|
|
136
126
|
};
|
|
137
127
|
// --------------------------------------------------------
|
|
138
128
|
// LOAD EXTERNAL CONFIGURATION
|
|
139
|
-
// Cascading: finds all vl-tools.config.
|
|
129
|
+
// Cascading: finds all vl-tools.config.mjs files from
|
|
140
130
|
// cwd upward, then deep-merges them (root first, closest
|
|
141
131
|
// package config wins).
|
|
142
132
|
// --------------------------------------------------------
|
|
@@ -156,11 +146,11 @@ const findAllConfigFiles = () => {
|
|
|
156
146
|
// Root config first, closest config last (overrides)
|
|
157
147
|
return files.reverse();
|
|
158
148
|
};
|
|
159
|
-
const getExternalConfig = () => {
|
|
149
|
+
const getExternalConfig = async () => {
|
|
160
150
|
const files = findAllConfigFiles();
|
|
161
151
|
let config = {};
|
|
162
152
|
for (const file of files) {
|
|
163
|
-
const loaded =
|
|
153
|
+
const loaded = await loadModuleAsync(file);
|
|
164
154
|
config = deepMerge(config, loaded);
|
|
165
155
|
}
|
|
166
156
|
return config;
|
|
@@ -169,8 +159,8 @@ const loadConfigParam = (filename) => (key, defaultValue = {}) => {
|
|
|
169
159
|
const externalConfig = loadFileToJSON(filename);
|
|
170
160
|
return get(externalConfig, key, defaultValue);
|
|
171
161
|
};
|
|
172
|
-
const loadVLToolsConfig = () => {
|
|
173
|
-
const externalConfig = getExternalConfig();
|
|
162
|
+
const loadVLToolsConfig = async () => {
|
|
163
|
+
const externalConfig = await getExternalConfig();
|
|
174
164
|
const cloneAndEnhance = (object) => ({
|
|
175
165
|
get config() {
|
|
176
166
|
return object;
|
|
@@ -190,7 +180,7 @@ const swapGlobals = (globals) => Object.entries(globals).reduce((acc, [key, valu
|
|
|
190
180
|
return acc;
|
|
191
181
|
}, {});
|
|
192
182
|
const PKG = getPkgData();
|
|
193
|
-
const VL_CONFIG = loadVLToolsConfig();
|
|
183
|
+
const VL_CONFIG = await loadVLToolsConfig();
|
|
194
184
|
const TS_CONFIG = loadFileToJSON(TYPESCRIPT_FILE_NAME);
|
|
195
185
|
export { defineConfig, findFile, loadConfigParam, loadFileToJSON, loadVLToolsConfig, swapGlobals, PKG, VL_CONFIG, TS_CONFIG, };
|
|
196
186
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
declare const findFile: (filename: string) => string | undefined;
|
|
2
2
|
declare const loadFileToJSON: (filename: string) => Record<string, any>;
|
|
3
3
|
declare const loadConfigParam: (filename: string) => (key: string, defaultValue?: {}) => any;
|
|
4
|
-
declare const loadVLToolsConfig: () => (key: string) => {
|
|
4
|
+
declare const loadVLToolsConfig: () => Promise<(key: string) => {
|
|
5
5
|
readonly config: Record<string, any>;
|
|
6
6
|
get: (param: string, defaultValue?: any) => any;
|
|
7
7
|
merge: (param: Record<string, any>) => /*elided*/ any;
|
|
8
|
-
}
|
|
8
|
+
}>;
|
|
9
9
|
declare const defineConfig: <T extends Record<string, any>>(config: T) => T;
|
|
10
10
|
declare const swapGlobals: (globals: Record<string, string>) => Record<string, string>;
|
|
11
11
|
declare const PKG: Record<string, any>;
|
package/lib/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AA4EA,QAAA,MAAM,QAAQ,GAAI,UAAU,MAAM,uBAAyB,CAAA;AAE3D,QAAA,MAAM,cAAc,GAAI,UAAU,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAS5D,CAAA;AA0GD,QAAA,MAAM,eAAe,GAClB,UAAU,MAAM,MAChB,KAAK,MAAM,EAAE,iBAAiB,QAI9B,CAAA;AAEH,QAAA,MAAM,iBAAiB,sBAaG,MAAM;;iBANf,MAAM,iBAAiB,GAAG;mBAExB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;EAWrC,CAAA;AAED,QAAA,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,QAAQ,CAAC,KAAG,CAAW,CAAA;AAE5E,QAAA,MAAM,WAAW,GAAI,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,2BAOjD,CAAA;AAEH,QAAA,MAAM,GAAG,qBAAe,CAAA;AACxB,QAAA,MAAM,SAAS,QArBW,MAAM;;iBANf,MAAM,iBAAiB,GAAG;mBAExB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;CAyBK,CAAA;AAC3C,QAAA,MAAM,SAAS,qBAAuC,CAAA;AAEtD,OAAO,EACL,YAAY,EACZ,QAAQ,EACR,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,WAAW,EACX,GAAG,EACH,SAAS,EACT,SAAS,GACV,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitus-labs/tools-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"typecheck": "tsc --noEmit"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@vitus-labs/tools-typescript": "1.
|
|
33
|
+
"@vitus-labs/tools-typescript": "1.9.0",
|
|
34
34
|
"typescript": "^5.9.3"
|
|
35
35
|
},
|
|
36
|
-
"gitHead": "
|
|
36
|
+
"gitHead": "167c6e3a00ad6e9bcec14dfdb7aaef3ffbdb42e9"
|
|
37
37
|
}
|
package/src/index.test.ts
CHANGED
|
@@ -1,300 +1,260 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
1
|
+
import { mkdirSync, rmSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
|
+
|
|
6
|
+
const BASE_TMP = path.join(tmpdir(), `vl-core-test-${Date.now()}`)
|
|
7
|
+
let testId = 0
|
|
8
|
+
|
|
9
|
+
const createTestDir = (opts: {
|
|
10
|
+
packageJson?: Record<string, any>
|
|
11
|
+
tsConfig?: Record<string, any>
|
|
12
|
+
vlConfig?: Record<string, any>
|
|
13
|
+
parent?: { vlConfig?: Record<string, any> }
|
|
14
|
+
}) => {
|
|
15
|
+
testId++
|
|
16
|
+
const root = path.join(BASE_TMP, `t${testId}`)
|
|
17
|
+
const projectDir = opts.parent ? path.join(root, 'packages', 'child') : root
|
|
18
|
+
|
|
19
|
+
mkdirSync(projectDir, { recursive: true })
|
|
20
|
+
|
|
21
|
+
writeFileSync(
|
|
22
|
+
path.join(projectDir, 'package.json'),
|
|
23
|
+
JSON.stringify(opts.packageJson ?? { name: 'test-pkg' }),
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
if (opts.tsConfig) {
|
|
27
|
+
writeFileSync(
|
|
28
|
+
path.join(projectDir, 'tsconfig.json'),
|
|
29
|
+
JSON.stringify(opts.tsConfig),
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (opts.vlConfig) {
|
|
34
|
+
writeFileSync(
|
|
35
|
+
path.join(projectDir, 'vl-tools.config.mjs'),
|
|
36
|
+
`export default ${JSON.stringify(opts.vlConfig)}`,
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (opts.parent?.vlConfig) {
|
|
41
|
+
writeFileSync(
|
|
42
|
+
path.join(root, 'vl-tools.config.mjs'),
|
|
43
|
+
`export default ${JSON.stringify(opts.parent.vlConfig)}`,
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return projectDir
|
|
25
48
|
}
|
|
26
49
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const setupDefaultMocks = () => {
|
|
31
|
-
vi.spyOn(process, 'cwd').mockReturnValue('/mock/project')
|
|
32
|
-
makeFilesExist(['/mock/project/package.json'])
|
|
33
|
-
mockRequireFn.mockImplementation((p: string) => {
|
|
34
|
-
if (p === '/mock/project/package.json') return { name: 'mock-pkg' }
|
|
35
|
-
return null
|
|
36
|
-
})
|
|
37
|
-
}
|
|
50
|
+
afterAll(() => {
|
|
51
|
+
rmSync(BASE_TMP, { recursive: true, force: true })
|
|
52
|
+
})
|
|
38
53
|
|
|
39
54
|
describe('tools-core', () => {
|
|
40
55
|
beforeEach(() => {
|
|
41
|
-
mockStatSync.mockReset()
|
|
42
|
-
mockReadFileSync.mockReset()
|
|
43
|
-
mockRequireFn.mockReset()
|
|
44
56
|
vi.restoreAllMocks()
|
|
45
57
|
})
|
|
46
58
|
|
|
47
59
|
describe('swapGlobals', () => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
beforeEach(async () => {
|
|
60
|
+
it('should invert key/value pairs', async () => {
|
|
51
61
|
vi.resetModules()
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
swapGlobals = mod.swapGlobals
|
|
55
|
-
})
|
|
62
|
+
const dir = createTestDir({})
|
|
63
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
56
64
|
|
|
57
|
-
|
|
65
|
+
const mod = await import('./index.js')
|
|
58
66
|
const input = { react: 'React', 'react-dom': 'ReactDOM' }
|
|
59
|
-
|
|
60
|
-
|
|
67
|
+
expect(mod.swapGlobals(input)).toEqual({
|
|
68
|
+
React: 'react',
|
|
69
|
+
ReactDOM: 'react-dom',
|
|
70
|
+
})
|
|
61
71
|
})
|
|
62
72
|
|
|
63
|
-
it('should return empty object for empty input', () => {
|
|
64
|
-
|
|
73
|
+
it('should return empty object for empty input', async () => {
|
|
74
|
+
vi.resetModules()
|
|
75
|
+
const dir = createTestDir({})
|
|
76
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
77
|
+
|
|
78
|
+
const mod = await import('./index.js')
|
|
79
|
+
expect(mod.swapGlobals({})).toEqual({})
|
|
65
80
|
})
|
|
66
81
|
})
|
|
67
82
|
|
|
68
83
|
describe('defineConfig', () => {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
beforeEach(async () => {
|
|
84
|
+
it('should return the same config object', async () => {
|
|
72
85
|
vi.resetModules()
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
defineConfig = mod.defineConfig
|
|
76
|
-
})
|
|
86
|
+
const dir = createTestDir({})
|
|
87
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
77
88
|
|
|
78
|
-
|
|
89
|
+
const mod = await import('./index.js')
|
|
79
90
|
const config = { stories: { framework: 'next' } }
|
|
80
|
-
expect(defineConfig(config)).toBe(config)
|
|
91
|
+
expect(mod.defineConfig(config)).toBe(config)
|
|
81
92
|
})
|
|
82
93
|
})
|
|
83
94
|
|
|
84
95
|
describe('findFile', () => {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
beforeEach(async () => {
|
|
96
|
+
it('should return the path when file is found in cwd', async () => {
|
|
88
97
|
vi.resetModules()
|
|
89
|
-
|
|
98
|
+
const dir = createTestDir({ tsConfig: { strict: true } })
|
|
99
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
100
|
+
|
|
90
101
|
const mod = await import('./index.js')
|
|
91
|
-
|
|
102
|
+
expect(mod.findFile('tsconfig.json')).toBe(
|
|
103
|
+
path.join(dir, 'tsconfig.json'),
|
|
104
|
+
)
|
|
92
105
|
})
|
|
93
106
|
|
|
94
|
-
it('should
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
it('should walk up directories to find the file', async () => {
|
|
108
|
+
vi.resetModules()
|
|
109
|
+
testId++
|
|
110
|
+
const root = path.join(BASE_TMP, `t${testId}`)
|
|
111
|
+
const child = path.join(root, 'sub', 'deep')
|
|
112
|
+
mkdirSync(child, { recursive: true })
|
|
113
|
+
writeFileSync(
|
|
114
|
+
path.join(child, 'package.json'),
|
|
115
|
+
JSON.stringify({ name: 'deep' }),
|
|
116
|
+
)
|
|
117
|
+
writeFileSync(path.join(root, 'target.json'), '{}')
|
|
118
|
+
vi.spyOn(process, 'cwd').mockReturnValue(child)
|
|
98
119
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
expect(findFile('some.json')).toBe('/mock/some.json')
|
|
120
|
+
const mod = await import('./index.js')
|
|
121
|
+
expect(mod.findFile('target.json')).toBe(path.join(root, 'target.json'))
|
|
102
122
|
})
|
|
103
123
|
|
|
104
|
-
it('should return undefined when file is not found', () => {
|
|
105
|
-
|
|
124
|
+
it('should return undefined when file is not found', async () => {
|
|
125
|
+
vi.resetModules()
|
|
126
|
+
const dir = createTestDir({})
|
|
127
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
128
|
+
|
|
129
|
+
const mod = await import('./index.js')
|
|
130
|
+
expect(mod.findFile('nonexistent.xyz')).toBeUndefined()
|
|
106
131
|
})
|
|
107
132
|
})
|
|
108
133
|
|
|
109
134
|
describe('loadFileToJSON', () => {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
beforeEach(async () => {
|
|
135
|
+
it('should return empty object when file is not found', async () => {
|
|
113
136
|
vi.resetModules()
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
loadFileToJSON = mod.loadFileToJSON
|
|
117
|
-
})
|
|
137
|
+
const dir = createTestDir({})
|
|
138
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
118
139
|
|
|
119
|
-
|
|
120
|
-
expect(loadFileToJSON('missing.json')).toEqual({})
|
|
140
|
+
const mod = await import('./index.js')
|
|
141
|
+
expect(mod.loadFileToJSON('missing.json')).toEqual({})
|
|
121
142
|
})
|
|
122
143
|
|
|
123
|
-
it('should
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return null
|
|
144
|
+
it('should parse JSON files', async () => {
|
|
145
|
+
vi.resetModules()
|
|
146
|
+
const dir = createTestDir({
|
|
147
|
+
tsConfig: { compilerOptions: { strict: true } },
|
|
128
148
|
})
|
|
129
|
-
|
|
130
|
-
})
|
|
149
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
131
150
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (p === '/mock/project/config.mjs')
|
|
136
|
-
return { default: { key: 'value' } }
|
|
137
|
-
return null
|
|
151
|
+
const mod = await import('./index.js')
|
|
152
|
+
expect(mod.loadFileToJSON('tsconfig.json')).toEqual({
|
|
153
|
+
compilerOptions: { strict: true },
|
|
138
154
|
})
|
|
139
|
-
expect(loadFileToJSON('config.mjs')).toEqual({ key: 'value' })
|
|
140
155
|
})
|
|
141
156
|
|
|
142
|
-
it('should
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
})
|
|
148
|
-
mockReadFileSync.mockReturnValue('{"parsed": true}')
|
|
149
|
-
expect(loadFileToJSON('data.json')).toEqual({ parsed: true })
|
|
150
|
-
})
|
|
157
|
+
it('should return empty object for invalid JSON', async () => {
|
|
158
|
+
vi.resetModules()
|
|
159
|
+
const dir = createTestDir({})
|
|
160
|
+
writeFileSync(path.join(dir, 'bad.json'), 'not json{{{')
|
|
161
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
151
162
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
mockRequireFn.mockImplementation(() => {
|
|
155
|
-
throw new Error('require failed')
|
|
156
|
-
})
|
|
157
|
-
mockReadFileSync.mockImplementation(() => {
|
|
158
|
-
throw new Error('read failed')
|
|
159
|
-
})
|
|
160
|
-
expect(loadFileToJSON('bad.json')).toEqual({})
|
|
163
|
+
const mod = await import('./index.js')
|
|
164
|
+
expect(mod.loadFileToJSON('bad.json')).toEqual({})
|
|
161
165
|
})
|
|
162
166
|
})
|
|
163
167
|
|
|
164
168
|
describe('loadConfigParam', () => {
|
|
165
|
-
|
|
166
|
-
filename: string,
|
|
167
|
-
) => (key: string, defaultValue?: any) => any
|
|
168
|
-
|
|
169
|
-
beforeEach(async () => {
|
|
169
|
+
it('should return a function that gets a nested config value', async () => {
|
|
170
170
|
vi.resetModules()
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
171
|
+
const dir = createTestDir({})
|
|
172
|
+
writeFileSync(
|
|
173
|
+
path.join(dir, 'config.json'),
|
|
174
|
+
JSON.stringify({ build: { sourceDir: 'src' } }),
|
|
175
|
+
)
|
|
176
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
175
177
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
mockRequireFn.mockImplementation((p: string) => {
|
|
179
|
-
if (p === '/mock/project/config.js')
|
|
180
|
-
return { build: { sourceDir: 'src' } }
|
|
181
|
-
return null
|
|
182
|
-
})
|
|
183
|
-
const getParam = loadConfigParam('config.js')
|
|
178
|
+
const mod = await import('./index.js')
|
|
179
|
+
const getParam = mod.loadConfigParam('config.json')
|
|
184
180
|
expect(getParam('build.sourceDir')).toBe('src')
|
|
185
181
|
})
|
|
186
182
|
|
|
187
|
-
it('should return defaultValue when key is not found', () => {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const
|
|
183
|
+
it('should return defaultValue when key is not found', async () => {
|
|
184
|
+
vi.resetModules()
|
|
185
|
+
const dir = createTestDir({})
|
|
186
|
+
writeFileSync(path.join(dir, 'config.json'), JSON.stringify({}))
|
|
187
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
188
|
+
|
|
189
|
+
const mod = await import('./index.js')
|
|
190
|
+
const getParam = mod.loadConfigParam('config.json')
|
|
194
191
|
expect(getParam('missing.key', 'default')).toBe('default')
|
|
195
192
|
})
|
|
196
193
|
})
|
|
197
194
|
|
|
198
195
|
describe('loadVLToolsConfig', () => {
|
|
199
|
-
|
|
196
|
+
it('should load .mjs config and provide .config, .get(), .merge()', async () => {
|
|
200
197
|
vi.resetModules()
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
it('should return a function that provides .config, .get(), .merge()', async () => {
|
|
205
|
-
makeFilesExist([
|
|
206
|
-
'/mock/project/package.json',
|
|
207
|
-
'/mock/project/vl-tools.config.js',
|
|
208
|
-
])
|
|
209
|
-
mockRequireFn.mockImplementation((p: string) => {
|
|
210
|
-
if (p === '/mock/project/package.json') return { name: 'mock-pkg' }
|
|
211
|
-
if (p === '/mock/project/vl-tools.config.js')
|
|
212
|
-
return { build: { sourceDir: 'src' } }
|
|
213
|
-
return null
|
|
198
|
+
const dir = createTestDir({
|
|
199
|
+
vlConfig: { build: { sourceDir: 'src' } },
|
|
214
200
|
})
|
|
201
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
215
202
|
|
|
216
203
|
const mod = await import('./index.js')
|
|
217
|
-
const vlConfig = mod.loadVLToolsConfig()
|
|
204
|
+
const vlConfig = await mod.loadVLToolsConfig()
|
|
218
205
|
const buildConfig = vlConfig('build')
|
|
219
206
|
expect(buildConfig.config).toEqual({ sourceDir: 'src' })
|
|
220
207
|
expect(buildConfig.get('sourceDir')).toBe('src')
|
|
221
208
|
})
|
|
222
209
|
|
|
223
210
|
it('should support chained merge calls', async () => {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
'
|
|
227
|
-
])
|
|
228
|
-
mockRequireFn.mockImplementation((p: string) => {
|
|
229
|
-
if (p === '/mock/project/package.json') return { name: 'mock-pkg' }
|
|
230
|
-
if (p === '/mock/project/vl-tools.config.js')
|
|
231
|
-
return { build: { sourceDir: 'src' } }
|
|
232
|
-
return null
|
|
211
|
+
vi.resetModules()
|
|
212
|
+
const dir = createTestDir({
|
|
213
|
+
vlConfig: { build: { sourceDir: 'src' } },
|
|
233
214
|
})
|
|
215
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
234
216
|
|
|
235
217
|
const mod = await import('./index.js')
|
|
236
|
-
const vlConfig = mod.loadVLToolsConfig()
|
|
218
|
+
const vlConfig = await mod.loadVLToolsConfig()
|
|
237
219
|
const merged = vlConfig('build').merge({ outputDir: 'lib' })
|
|
238
220
|
expect(merged.config).toEqual({ sourceDir: 'src', outputDir: 'lib' })
|
|
239
221
|
})
|
|
240
222
|
|
|
241
|
-
it('should return empty config when
|
|
242
|
-
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
expect(result.config).toEqual({})
|
|
246
|
-
})
|
|
223
|
+
it('should return empty config when no config file exists', async () => {
|
|
224
|
+
vi.resetModules()
|
|
225
|
+
const dir = createTestDir({})
|
|
226
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
247
227
|
|
|
248
|
-
it('should return default value with get when key is missing', async () => {
|
|
249
228
|
const mod = await import('./index.js')
|
|
250
|
-
const vlConfig = mod.loadVLToolsConfig()
|
|
251
|
-
|
|
252
|
-
expect(result.get('missing')).toEqual({})
|
|
229
|
+
const vlConfig = await mod.loadVLToolsConfig()
|
|
230
|
+
expect(vlConfig('build').config).toEqual({})
|
|
253
231
|
})
|
|
254
232
|
|
|
255
|
-
it('should
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
'/mock/project/vl-tools.config.js',
|
|
260
|
-
])
|
|
261
|
-
mockRequireFn.mockImplementation((p: string) => {
|
|
262
|
-
if (p === '/mock/project/package.json') return { name: 'mock-pkg' }
|
|
263
|
-
if (p === '/mock/project/vl-tools.config.mjs')
|
|
264
|
-
return { build: { sourceDir: 'mjs-src' } }
|
|
265
|
-
if (p === '/mock/project/vl-tools.config.js')
|
|
266
|
-
return { build: { sourceDir: 'js-src' } }
|
|
267
|
-
return null
|
|
268
|
-
})
|
|
233
|
+
it('should return default value with get when key is missing', async () => {
|
|
234
|
+
vi.resetModules()
|
|
235
|
+
const dir = createTestDir({})
|
|
236
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
269
237
|
|
|
270
238
|
const mod = await import('./index.js')
|
|
271
|
-
const vlConfig = mod.loadVLToolsConfig()
|
|
272
|
-
expect(vlConfig('build').
|
|
239
|
+
const vlConfig = await mod.loadVLToolsConfig()
|
|
240
|
+
expect(vlConfig('build').get('missing')).toEqual({})
|
|
273
241
|
})
|
|
274
242
|
|
|
275
243
|
it('should cascade configs from root to package (deep merge)', async () => {
|
|
276
|
-
vi.
|
|
277
|
-
|
|
278
|
-
'
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
])
|
|
282
|
-
mockRequireFn.mockImplementation((p: string) => {
|
|
283
|
-
if (p === '/mock/packages/ui/package.json') return { name: 'mock-pkg' }
|
|
284
|
-
// Root config: base settings
|
|
285
|
-
if (p === '/mock/vl-tools.config.js')
|
|
286
|
-
return {
|
|
244
|
+
vi.resetModules()
|
|
245
|
+
const dir = createTestDir({
|
|
246
|
+
vlConfig: { stories: { framework: 'next' } },
|
|
247
|
+
parent: {
|
|
248
|
+
vlConfig: {
|
|
287
249
|
stories: { framework: 'vite', port: 6006 },
|
|
288
250
|
build: { sourceDir: 'src' },
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (p === '/mock/packages/ui/vl-tools.config.js')
|
|
292
|
-
return { stories: { framework: 'next' } }
|
|
293
|
-
return null
|
|
251
|
+
},
|
|
252
|
+
},
|
|
294
253
|
})
|
|
254
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
295
255
|
|
|
296
256
|
const mod = await import('./index.js')
|
|
297
|
-
const vlConfig = mod.loadVLToolsConfig()
|
|
257
|
+
const vlConfig = await mod.loadVLToolsConfig()
|
|
298
258
|
const stories = vlConfig('stories')
|
|
299
259
|
|
|
300
260
|
// framework overridden by package config
|
|
@@ -309,18 +269,14 @@ describe('tools-core', () => {
|
|
|
309
269
|
describe('module-level constants', () => {
|
|
310
270
|
it('should export PKG with bundleName from scoped package name', async () => {
|
|
311
271
|
vi.resetModules()
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
version: '1.0.0',
|
|
319
|
-
dependencies: { react: '^19' },
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return null
|
|
272
|
+
const dir = createTestDir({
|
|
273
|
+
packageJson: {
|
|
274
|
+
name: '@test/pkg',
|
|
275
|
+
version: '1.0.0',
|
|
276
|
+
dependencies: { react: '^19' },
|
|
277
|
+
},
|
|
323
278
|
})
|
|
279
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
324
280
|
|
|
325
281
|
const mod = await import('./index.js')
|
|
326
282
|
expect(mod.PKG.name).toBe('@test/pkg')
|
|
@@ -330,14 +286,10 @@ describe('tools-core', () => {
|
|
|
330
286
|
|
|
331
287
|
it('should handle simple hyphenated package names in bundleName', async () => {
|
|
332
288
|
vi.resetModules()
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
mockRequireFn.mockImplementation((p: string) => {
|
|
336
|
-
if (p === '/path/to/package.json') {
|
|
337
|
-
return { name: 'my-cool-library' }
|
|
338
|
-
}
|
|
339
|
-
return null
|
|
289
|
+
const dir = createTestDir({
|
|
290
|
+
packageJson: { name: 'my-cool-library' },
|
|
340
291
|
})
|
|
292
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
341
293
|
|
|
342
294
|
const mod = await import('./index.js')
|
|
343
295
|
expect(mod.PKG.bundleName).toBe('myCoolLibrary')
|
|
@@ -345,17 +297,13 @@ describe('tools-core', () => {
|
|
|
345
297
|
|
|
346
298
|
it('should include peerDependencies in externalDependencies', async () => {
|
|
347
299
|
vi.resetModules()
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
name: 'my-lib',
|
|
354
|
-
peerDependencies: { 'styled-components': '^6' },
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
return null
|
|
300
|
+
const dir = createTestDir({
|
|
301
|
+
packageJson: {
|
|
302
|
+
name: 'my-lib',
|
|
303
|
+
peerDependencies: { 'styled-components': '^6' },
|
|
304
|
+
},
|
|
358
305
|
})
|
|
306
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
359
307
|
|
|
360
308
|
const mod = await import('./index.js')
|
|
361
309
|
expect(mod.PKG.externalDependencies).toContain('styled-components')
|
|
@@ -363,28 +311,35 @@ describe('tools-core', () => {
|
|
|
363
311
|
|
|
364
312
|
it('should export VL_CONFIG as a function', async () => {
|
|
365
313
|
vi.resetModules()
|
|
366
|
-
|
|
314
|
+
const dir = createTestDir({})
|
|
315
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
316
|
+
|
|
367
317
|
const mod = await import('./index.js')
|
|
368
318
|
expect(typeof mod.VL_CONFIG).toBe('function')
|
|
369
319
|
})
|
|
370
320
|
|
|
371
321
|
it('should export TS_CONFIG from tsconfig.json', async () => {
|
|
372
322
|
vi.resetModules()
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
'/mock/project/package.json',
|
|
376
|
-
'/mock/project/tsconfig.json',
|
|
377
|
-
])
|
|
378
|
-
mockRequireFn.mockImplementation((p: string) => {
|
|
379
|
-
if (p === '/mock/project/package.json') return { name: 'mock-pkg' }
|
|
380
|
-
if (p === '/mock/project/tsconfig.json') {
|
|
381
|
-
return { compilerOptions: { strict: true } }
|
|
382
|
-
}
|
|
383
|
-
return null
|
|
323
|
+
const dir = createTestDir({
|
|
324
|
+
tsConfig: { compilerOptions: { strict: true } },
|
|
384
325
|
})
|
|
326
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
385
327
|
|
|
386
328
|
const mod = await import('./index.js')
|
|
387
329
|
expect(mod.TS_CONFIG).toEqual({ compilerOptions: { strict: true } })
|
|
388
330
|
})
|
|
331
|
+
|
|
332
|
+
it('should resolve VL_CONFIG from .mjs config at module level', async () => {
|
|
333
|
+
vi.resetModules()
|
|
334
|
+
const dir = createTestDir({
|
|
335
|
+
vlConfig: { stories: { framework: 'next', port: 3000 } },
|
|
336
|
+
})
|
|
337
|
+
vi.spyOn(process, 'cwd').mockReturnValue(dir)
|
|
338
|
+
|
|
339
|
+
const mod = await import('./index.js')
|
|
340
|
+
const stories = mod.VL_CONFIG('stories')
|
|
341
|
+
expect(stories.get('framework')).toBe('next')
|
|
342
|
+
expect(stories.get('port')).toBe(3000)
|
|
343
|
+
})
|
|
389
344
|
})
|
|
390
345
|
})
|
package/src/index.ts
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs'
|
|
2
|
-
import { createRequire } from 'node:module'
|
|
3
2
|
import path from 'node:path'
|
|
3
|
+
import { pathToFileURL } from 'node:url'
|
|
4
4
|
|
|
5
|
-
const VL_CONFIG_FILES = ['vl-tools.config.mjs'
|
|
5
|
+
const VL_CONFIG_FILES = ['vl-tools.config.mjs']
|
|
6
6
|
const PACKAGE_FILE_NAME = 'package.json'
|
|
7
7
|
const TYPESCRIPT_FILE_NAME = 'tsconfig.json'
|
|
8
8
|
|
|
9
|
-
const require = createRequire(import.meta.url)
|
|
10
|
-
|
|
11
9
|
// --------------------------------------------------------
|
|
12
10
|
// Utility helpers (replaces lodash-es and find-up)
|
|
13
11
|
// --------------------------------------------------------
|
|
@@ -78,43 +76,35 @@ const findFileUp = (
|
|
|
78
76
|
// --------------------------------------------------------
|
|
79
77
|
const findFile = (filename: string) => findFileUp(filename)
|
|
80
78
|
|
|
81
|
-
const loadModule = (filePath: string): Record<string, any> => {
|
|
82
|
-
try {
|
|
83
|
-
const imported = require(filePath)
|
|
84
|
-
// Handle ESM default export wrapping
|
|
85
|
-
return imported?.default ?? imported ?? {}
|
|
86
|
-
} catch (_e) {
|
|
87
|
-
return {}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
79
|
const loadFileToJSON = (filename: string): Record<string, any> => {
|
|
92
80
|
const file = findFile(filename)
|
|
93
|
-
|
|
94
81
|
if (!file) return {}
|
|
95
82
|
|
|
96
|
-
// try to read an exported module first
|
|
97
|
-
const data = loadModule(file)
|
|
98
|
-
if (data && Object.keys(data).length > 0) return data
|
|
99
|
-
|
|
100
|
-
// try to read a plain json file like tsconfig.json
|
|
101
83
|
try {
|
|
102
84
|
return JSON.parse(fs.readFileSync(file, 'utf-8'))
|
|
103
85
|
} catch (_e) {
|
|
104
|
-
|
|
86
|
+
return {}
|
|
105
87
|
}
|
|
88
|
+
}
|
|
106
89
|
|
|
107
|
-
|
|
90
|
+
const loadModuleAsync = async (
|
|
91
|
+
filePath: string,
|
|
92
|
+
): Promise<Record<string, any>> => {
|
|
93
|
+
try {
|
|
94
|
+
const mod = await import(pathToFileURL(filePath).href)
|
|
95
|
+
return mod?.default ?? mod ?? {}
|
|
96
|
+
} catch (e: any) {
|
|
97
|
+
console.warn(
|
|
98
|
+
`[tools-core] Failed to load config: ${filePath}\n ${e.message}`,
|
|
99
|
+
)
|
|
100
|
+
return {}
|
|
101
|
+
}
|
|
108
102
|
}
|
|
109
103
|
|
|
110
104
|
// --------------------------------------------------------
|
|
111
105
|
// GET PACKAGE.JSON info
|
|
112
106
|
// --------------------------------------------------------
|
|
113
|
-
const getPackageJSON = () =>
|
|
114
|
-
const data = loadFileToJSON(PACKAGE_FILE_NAME)
|
|
115
|
-
|
|
116
|
-
return data
|
|
117
|
-
}
|
|
107
|
+
const getPackageJSON = () => loadFileToJSON(PACKAGE_FILE_NAME)
|
|
118
108
|
|
|
119
109
|
// --------------------------------------------------------
|
|
120
110
|
// PACKAGE.json parsing functions
|
|
@@ -168,7 +158,7 @@ const getPkgData = (): Record<string, any> => {
|
|
|
168
158
|
|
|
169
159
|
// --------------------------------------------------------
|
|
170
160
|
// LOAD EXTERNAL CONFIGURATION
|
|
171
|
-
// Cascading: finds all vl-tools.config.
|
|
161
|
+
// Cascading: finds all vl-tools.config.mjs files from
|
|
172
162
|
// cwd upward, then deep-merges them (root first, closest
|
|
173
163
|
// package config wins).
|
|
174
164
|
// --------------------------------------------------------
|
|
@@ -189,12 +179,12 @@ const findAllConfigFiles = (): string[] => {
|
|
|
189
179
|
return files.reverse()
|
|
190
180
|
}
|
|
191
181
|
|
|
192
|
-
const getExternalConfig = (): Record<string, any
|
|
182
|
+
const getExternalConfig = async (): Promise<Record<string, any>> => {
|
|
193
183
|
const files = findAllConfigFiles()
|
|
194
184
|
let config: Record<string, any> = {}
|
|
195
185
|
|
|
196
186
|
for (const file of files) {
|
|
197
|
-
const loaded =
|
|
187
|
+
const loaded = await loadModuleAsync(file)
|
|
198
188
|
config = deepMerge(config, loaded)
|
|
199
189
|
}
|
|
200
190
|
|
|
@@ -209,8 +199,8 @@ const loadConfigParam =
|
|
|
209
199
|
return get(externalConfig, key, defaultValue)
|
|
210
200
|
}
|
|
211
201
|
|
|
212
|
-
const loadVLToolsConfig = () => {
|
|
213
|
-
const externalConfig = getExternalConfig()
|
|
202
|
+
const loadVLToolsConfig = async () => {
|
|
203
|
+
const externalConfig = await getExternalConfig()
|
|
214
204
|
|
|
215
205
|
const cloneAndEnhance = (object: Record<string, any>) => ({
|
|
216
206
|
get config() {
|
|
@@ -243,7 +233,7 @@ const swapGlobals = (globals: Record<string, string>) =>
|
|
|
243
233
|
)
|
|
244
234
|
|
|
245
235
|
const PKG = getPkgData()
|
|
246
|
-
const VL_CONFIG = loadVLToolsConfig()
|
|
236
|
+
const VL_CONFIG = await loadVLToolsConfig()
|
|
247
237
|
const TS_CONFIG = loadFileToJSON(TYPESCRIPT_FILE_NAME)
|
|
248
238
|
|
|
249
239
|
export {
|