@poveste/shared 0.3.2 → 0.4.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/dist/setup.d.ts +1 -1
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +11 -2
- package/package.json +2 -2
- package/src/__tests__/setup.spec.ts +60 -0
- package/src/setup.ts +16 -3
package/dist/setup.d.ts
CHANGED
|
@@ -9,5 +9,5 @@ export type SetupModule = Record<string, unknown> | undefined;
|
|
|
9
9
|
* consumer build. Passing the namespace through a call forces it to be
|
|
10
10
|
* materialized, so the lookup happens at runtime where it belongs.
|
|
11
11
|
*/
|
|
12
|
-
export declare function getSetupHook<T>(mod: SetupModule, name: string): T | undefined;
|
|
12
|
+
export declare function getSetupHook<T>(mod: SetupModule, name: string | string[]): T | undefined;
|
|
13
13
|
//# sourceMappingURL=setup.d.ts.map
|
package/dist/setup.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;AAE7D;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;AAE7D;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAgBxF"}
|
package/dist/setup.js
CHANGED
|
@@ -9,6 +9,15 @@
|
|
|
9
9
|
* materialized, so the lookup happens at runtime where it belongs.
|
|
10
10
|
*/
|
|
11
11
|
export function getSetupHook(mod, name) {
|
|
12
|
-
const
|
|
13
|
-
|
|
12
|
+
const names = typeof name === 'string' ? [name] : name;
|
|
13
|
+
const present = names.filter(candidate => typeof mod?.[candidate] === 'function');
|
|
14
|
+
// Earlier names win, so a plugin lists its established hook first and a newer
|
|
15
|
+
// alias after it: an existing setup file keeps the exact behaviour it had.
|
|
16
|
+
// Running both instead would apply the same setup twice, which for Vue means
|
|
17
|
+
// a second `app.use()` for every plugin the user registers.
|
|
18
|
+
if (present.length > 1) {
|
|
19
|
+
console.warn(`[poveste] Setup file exports ${present.length} interchangeable setup hooks (${present.join(', ')}). `
|
|
20
|
+
+ `Only ${present[0]} runs. Keep one — they are aliases, not separate hooks.`);
|
|
21
|
+
}
|
|
22
|
+
return present.length > 0 ? mod[present[0]] : undefined;
|
|
14
23
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poveste/shared",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.0",
|
|
5
5
|
"description": "Shared utilities for Poveste",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Sorin Gitlan"
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"pathe": "^1.1.2",
|
|
35
35
|
"picocolors": "^1.1.1",
|
|
36
36
|
"unhead": "^3.1.0",
|
|
37
|
-
"@poveste/vendors": "^0.
|
|
37
|
+
"@poveste/vendors": "^0.4.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"typescript": "5.6.3",
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { getSetupHook } from '../setup.js'
|
|
3
|
+
|
|
4
|
+
afterEach(() => {
|
|
5
|
+
vi.restoreAllMocks()
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
describe('getSetupHook', () => {
|
|
9
|
+
it('reads a hook by a single name', () => {
|
|
10
|
+
const hook = () => {}
|
|
11
|
+
expect(getSetupHook({ setupVanilla: hook }, 'setupVanilla')).toBe(hook)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('ignores a non-function export of the right name', () => {
|
|
15
|
+
expect(getSetupHook({ setupVanilla: 'not a function' }, 'setupVanilla')).toBeUndefined()
|
|
16
|
+
expect(getSetupHook({ setupVanilla: undefined }, 'setupVanilla')).toBeUndefined()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('tolerates a missing module', () => {
|
|
20
|
+
expect(getSetupHook(undefined, 'setupVanilla')).toBeUndefined()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it.each([
|
|
24
|
+
['the established name', 'setupVue3'],
|
|
25
|
+
['the unnumbered alias', 'setupVue'],
|
|
26
|
+
])('finds a hook exported under %s', (_label, name) => {
|
|
27
|
+
const hook = () => {}
|
|
28
|
+
expect(getSetupHook({ [name]: hook }, ['setupVue3', 'setupVue'])).toBe(hook)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('returns undefined when none of the names are exported', () => {
|
|
32
|
+
expect(getSetupHook({ setupSvelte5: () => {} }, ['setupVue3', 'setupVue'])).toBeUndefined()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
describe('when a setup file exports more than one alias', () => {
|
|
36
|
+
// The whole point of the alias is that existing files keep working, so the
|
|
37
|
+
// established name has to win regardless of the order they are declared in.
|
|
38
|
+
it('runs the earlier name in the list, not the first declared', () => {
|
|
39
|
+
const legacy = () => {}
|
|
40
|
+
const renamed = () => {}
|
|
41
|
+
expect(getSetupHook({ setupVue: renamed, setupVue3: legacy }, ['setupVue3', 'setupVue'])).toBe(legacy)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('warns, naming which one actually runs', () => {
|
|
45
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
46
|
+
getSetupHook({ setupVue3: () => {}, setupVue: () => {} }, ['setupVue3', 'setupVue'])
|
|
47
|
+
|
|
48
|
+
expect(warn).toHaveBeenCalledOnce()
|
|
49
|
+
const message = warn.mock.calls[0][0] as string
|
|
50
|
+
expect(message).toContain('setupVue3, setupVue')
|
|
51
|
+
expect(message).toContain('Only setupVue3 runs')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('stays quiet when only one is exported', () => {
|
|
55
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
56
|
+
getSetupHook({ setupVue: () => {} }, ['setupVue3', 'setupVue'])
|
|
57
|
+
expect(warn).not.toHaveBeenCalled()
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
})
|
package/src/setup.ts
CHANGED
|
@@ -10,7 +10,20 @@ export type SetupModule = Record<string, unknown> | undefined
|
|
|
10
10
|
* consumer build. Passing the namespace through a call forces it to be
|
|
11
11
|
* materialized, so the lookup happens at runtime where it belongs.
|
|
12
12
|
*/
|
|
13
|
-
export function getSetupHook<T>(mod: SetupModule, name: string): T | undefined {
|
|
14
|
-
const
|
|
15
|
-
|
|
13
|
+
export function getSetupHook<T>(mod: SetupModule, name: string | string[]): T | undefined {
|
|
14
|
+
const names = typeof name === 'string' ? [name] : name
|
|
15
|
+
const present = names.filter(candidate => typeof mod?.[candidate] === 'function')
|
|
16
|
+
|
|
17
|
+
// Earlier names win, so a plugin lists its established hook first and a newer
|
|
18
|
+
// alias after it: an existing setup file keeps the exact behaviour it had.
|
|
19
|
+
// Running both instead would apply the same setup twice, which for Vue means
|
|
20
|
+
// a second `app.use()` for every plugin the user registers.
|
|
21
|
+
if (present.length > 1) {
|
|
22
|
+
console.warn(
|
|
23
|
+
`[poveste] Setup file exports ${present.length} interchangeable setup hooks (${present.join(', ')}). `
|
|
24
|
+
+ `Only ${present[0]} runs. Keep one — they are aliases, not separate hooks.`,
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return present.length > 0 ? mod![present[0]] as T : undefined
|
|
16
29
|
}
|