@vitus-labs/tools-core 1.5.2-alpha.4 → 1.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitus-labs/tools-core",
3
- "version": "1.5.2-alpha.4+45b8634",
3
+ "version": "1.6.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,16 +26,17 @@
26
26
  },
27
27
  "scripts": {
28
28
  "prepublish": "bun run build",
29
- "build": "tsc"
29
+ "build": "tsc",
30
+ "typecheck": "tsc --noEmit"
30
31
  },
31
32
  "dependencies": {
32
- "find-up": "^7.0.0",
33
- "lodash-es": "^4.17.22"
33
+ "find-up": "^8.0.0",
34
+ "lodash-es": "^4.17.23"
34
35
  },
35
36
  "devDependencies": {
36
37
  "@types/lodash-es": "^4.17.12",
37
- "@vitus-labs/tools-typescript": "1.5.2-alpha.4+45b8634",
38
+ "@vitus-labs/tools-typescript": "1.6.0",
38
39
  "typescript": "^5.9.3"
39
40
  },
40
- "gitHead": "45b863472eafa888f12f8f56d347dd20b72cd4f9"
41
+ "gitHead": "cb7b3bfa4e5730ecb95b3c886d23074a3ce9e85f"
41
42
  }
@@ -0,0 +1,280 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+
3
+ const mockFindUpSync = vi.fn()
4
+ vi.mock('find-up', () => ({
5
+ findUpSync: mockFindUpSync,
6
+ }))
7
+
8
+ const mockReadFileSync = vi.fn()
9
+ vi.mock('node:fs', () => ({
10
+ default: { readFileSync: mockReadFileSync },
11
+ readFileSync: mockReadFileSync,
12
+ }))
13
+
14
+ const mockRequireFn = vi.fn()
15
+ vi.mock('node:module', () => ({
16
+ createRequire: vi.fn(() => mockRequireFn),
17
+ }))
18
+
19
+ // Default mock setup that satisfies module-level getPkgData() —
20
+ // package.json must always be found with a valid `name` field,
21
+ // otherwise camelspaceBundleName(undefined) crashes at import time.
22
+ const setupDefaultMocks = () => {
23
+ mockFindUpSync.mockImplementation((filename: string) => {
24
+ if (filename === 'package.json') return '/mock/package.json'
25
+ return undefined
26
+ })
27
+ mockRequireFn.mockImplementation((path: string) => {
28
+ if (path === '/mock/package.json') return { name: 'mock-pkg' }
29
+ return null
30
+ })
31
+ }
32
+
33
+ describe('tools-core', () => {
34
+ beforeEach(() => {
35
+ mockFindUpSync.mockReset()
36
+ mockReadFileSync.mockReset()
37
+ mockRequireFn.mockReset()
38
+ })
39
+
40
+ describe('swapGlobals', () => {
41
+ let swapGlobals: (globals: Record<string, string>) => Record<string, string>
42
+
43
+ beforeEach(async () => {
44
+ vi.resetModules()
45
+ setupDefaultMocks()
46
+ const mod = await import('./index.js')
47
+ swapGlobals = mod.swapGlobals
48
+ })
49
+
50
+ it('should invert key/value pairs', () => {
51
+ const input = { react: 'React', 'react-dom': 'ReactDOM' }
52
+ const result = swapGlobals(input)
53
+ expect(result).toEqual({ React: 'react', ReactDOM: 'react-dom' })
54
+ })
55
+
56
+ it('should return empty object for empty input', () => {
57
+ expect(swapGlobals({})).toEqual({})
58
+ })
59
+ })
60
+
61
+ describe('findFile', () => {
62
+ let findFile: (filename: string) => string | undefined
63
+
64
+ beforeEach(async () => {
65
+ vi.resetModules()
66
+ setupDefaultMocks()
67
+ const mod = await import('./index.js')
68
+ findFile = mod.findFile
69
+ })
70
+
71
+ it('should call findUpSync with the filename', () => {
72
+ mockFindUpSync.mockReturnValue('/path/to/file.json')
73
+ findFile('file.json')
74
+ expect(mockFindUpSync).toHaveBeenCalledWith('file.json', { type: 'file' })
75
+ })
76
+
77
+ it('should return the path when file is found', () => {
78
+ mockFindUpSync.mockReturnValue('/path/to/file.json')
79
+ expect(findFile('file.json')).toBe('/path/to/file.json')
80
+ })
81
+
82
+ it('should return undefined when file is not found', () => {
83
+ mockFindUpSync.mockReturnValue(undefined)
84
+ expect(findFile('missing.json')).toBeUndefined()
85
+ })
86
+ })
87
+
88
+ describe('loadFileToJSON', () => {
89
+ let loadFileToJSON: (filename: string) => Record<string, any>
90
+
91
+ beforeEach(async () => {
92
+ vi.resetModules()
93
+ setupDefaultMocks()
94
+ const mod = await import('./index.js')
95
+ loadFileToJSON = mod.loadFileToJSON
96
+ })
97
+
98
+ it('should return empty object when file is not found', () => {
99
+ mockFindUpSync.mockReturnValue(undefined)
100
+ expect(loadFileToJSON('missing.json')).toEqual({})
101
+ })
102
+
103
+ it('should load file using require when available', () => {
104
+ mockFindUpSync.mockReturnValue('/path/to/config.js')
105
+ mockRequireFn.mockReturnValue({ key: 'value' })
106
+ expect(loadFileToJSON('config.js')).toEqual({ key: 'value' })
107
+ })
108
+
109
+ it('should return empty object when require returns falsy', () => {
110
+ mockFindUpSync.mockReturnValue('/path/to/config.json')
111
+ mockRequireFn.mockReturnValue(null)
112
+ expect(loadFileToJSON('config.json')).toEqual({})
113
+ })
114
+
115
+ it('should return empty object when require throws', () => {
116
+ mockFindUpSync.mockReturnValue('/path/to/bad.json')
117
+ mockRequireFn.mockImplementation(() => {
118
+ throw new Error('require failed')
119
+ })
120
+ expect(loadFileToJSON('bad.json')).toEqual({})
121
+ })
122
+ })
123
+
124
+ describe('loadConfigParam', () => {
125
+ let loadConfigParam: (
126
+ filename: string,
127
+ ) => (key: string, defaultValue?: any) => any
128
+
129
+ beforeEach(async () => {
130
+ vi.resetModules()
131
+ setupDefaultMocks()
132
+ const mod = await import('./index.js')
133
+ loadConfigParam = mod.loadConfigParam
134
+ })
135
+
136
+ it('should return a function that gets a nested config value', () => {
137
+ mockFindUpSync.mockReturnValue('/path/to/config.js')
138
+ mockRequireFn.mockReturnValue({ build: { sourceDir: 'src' } })
139
+ const getParam = loadConfigParam('config.js')
140
+ expect(getParam('build.sourceDir')).toBe('src')
141
+ })
142
+
143
+ it('should return defaultValue when key is not found', () => {
144
+ mockFindUpSync.mockReturnValue('/path/to/config.js')
145
+ mockRequireFn.mockReturnValue({})
146
+ const getParam = loadConfigParam('config.js')
147
+ expect(getParam('missing.key', 'default')).toBe('default')
148
+ })
149
+ })
150
+
151
+ describe('loadVLToolsConfig', () => {
152
+ let loadVLToolsConfig: () => (key: string) => any
153
+
154
+ beforeEach(async () => {
155
+ vi.resetModules()
156
+ setupDefaultMocks()
157
+ const mod = await import('./index.js')
158
+ loadVLToolsConfig = mod.loadVLToolsConfig
159
+ })
160
+
161
+ it('should return a function that provides .config, .get(), .merge()', () => {
162
+ mockFindUpSync.mockReturnValue('/path/to/vl-tools.config.js')
163
+ mockRequireFn.mockReturnValue({ build: { sourceDir: 'src' } })
164
+ const vlConfig = loadVLToolsConfig()
165
+ const buildConfig = vlConfig('build')
166
+ expect(buildConfig.config).toEqual({ sourceDir: 'src' })
167
+ expect(buildConfig.get('sourceDir')).toBe('src')
168
+ })
169
+
170
+ it('should support chained merge calls', () => {
171
+ mockFindUpSync.mockReturnValue('/path/to/vl-tools.config.js')
172
+ mockRequireFn.mockReturnValue({ build: { sourceDir: 'src' } })
173
+ const vlConfig = loadVLToolsConfig()
174
+ const merged = vlConfig('build').merge({ outputDir: 'lib' })
175
+ expect(merged.config).toEqual({ sourceDir: 'src', outputDir: 'lib' })
176
+ })
177
+
178
+ it('should return empty config when file is not found', () => {
179
+ mockFindUpSync.mockReturnValue(undefined)
180
+ const vlConfig = loadVLToolsConfig()
181
+ const result = vlConfig('build')
182
+ expect(result.config).toEqual({})
183
+ })
184
+
185
+ it('should return default value with get when key is missing', () => {
186
+ mockFindUpSync.mockReturnValue(undefined)
187
+ const vlConfig = loadVLToolsConfig()
188
+ const result = vlConfig('build')
189
+ expect(result.get('missing')).toEqual({})
190
+ })
191
+ })
192
+
193
+ describe('module-level constants', () => {
194
+ it('should export PKG with bundleName from scoped package name', async () => {
195
+ vi.resetModules()
196
+ mockFindUpSync.mockImplementation((filename: string) => {
197
+ if (filename === 'package.json') return '/path/to/package.json'
198
+ return undefined
199
+ })
200
+ mockRequireFn.mockImplementation((path: string) => {
201
+ if (path === '/path/to/package.json') {
202
+ return {
203
+ name: '@test/pkg',
204
+ version: '1.0.0',
205
+ dependencies: { react: '^19' },
206
+ }
207
+ }
208
+ return null
209
+ })
210
+
211
+ const mod = await import('./index.js')
212
+ expect(mod.PKG.name).toBe('@test/pkg')
213
+ expect(mod.PKG.bundleName).toBe('testPkg')
214
+ expect(mod.PKG.externalDependencies).toContain('react')
215
+ })
216
+
217
+ it('should handle simple hyphenated package names in bundleName', async () => {
218
+ vi.resetModules()
219
+ mockFindUpSync.mockImplementation((filename: string) => {
220
+ if (filename === 'package.json') return '/path/to/package.json'
221
+ return undefined
222
+ })
223
+ mockRequireFn.mockImplementation((path: string) => {
224
+ if (path === '/path/to/package.json') {
225
+ return { name: 'my-cool-library' }
226
+ }
227
+ return null
228
+ })
229
+
230
+ const mod = await import('./index.js')
231
+ expect(mod.PKG.bundleName).toBe('myCoolLibrary')
232
+ })
233
+
234
+ it('should include peerDependencies in externalDependencies', async () => {
235
+ vi.resetModules()
236
+ mockFindUpSync.mockImplementation((filename: string) => {
237
+ if (filename === 'package.json') return '/path/to/package.json'
238
+ return undefined
239
+ })
240
+ mockRequireFn.mockImplementation((path: string) => {
241
+ if (path === '/path/to/package.json') {
242
+ return {
243
+ name: 'my-lib',
244
+ peerDependencies: { 'styled-components': '^6' },
245
+ }
246
+ }
247
+ return null
248
+ })
249
+
250
+ const mod = await import('./index.js')
251
+ expect(mod.PKG.externalDependencies).toContain('styled-components')
252
+ })
253
+
254
+ it('should export VL_CONFIG as a function', async () => {
255
+ vi.resetModules()
256
+ setupDefaultMocks()
257
+ const mod = await import('./index.js')
258
+ expect(typeof mod.VL_CONFIG).toBe('function')
259
+ })
260
+
261
+ it('should export TS_CONFIG from tsconfig.json', async () => {
262
+ vi.resetModules()
263
+ mockFindUpSync.mockImplementation((filename: string) => {
264
+ if (filename === 'package.json') return '/mock/package.json'
265
+ if (filename === 'tsconfig.json') return '/path/to/tsconfig.json'
266
+ return undefined
267
+ })
268
+ mockRequireFn.mockImplementation((path: string) => {
269
+ if (path === '/mock/package.json') return { name: 'mock-pkg' }
270
+ if (path === '/path/to/tsconfig.json') {
271
+ return { compilerOptions: { strict: true } }
272
+ }
273
+ return null
274
+ })
275
+
276
+ const mod = await import('./index.js')
277
+ expect(mod.TS_CONFIG).toEqual({ compilerOptions: { strict: true } })
278
+ })
279
+ })
280
+ })
package/tsconfig.json CHANGED
@@ -11,5 +11,5 @@
11
11
  }
12
12
  },
13
13
  "include": ["typings", "src"],
14
- "exclude": ["node_modules", "__stories__", "lib"]
14
+ "exclude": ["node_modules", "__stories__", "lib", "**/*.test.ts"]
15
15
  }
@@ -0,0 +1,3 @@
1
+ import { createVitestConfig } from '../../vitest.shared.js'
2
+
3
+ export default createVitestConfig()