Skip to content

Commit e1f7bdc

Browse files
committed
feat(api): support mutating intersection type
1 parent 385d9bb commit e1f7bdc

File tree

5 files changed

+198
-10
lines changed

5 files changed

+198
-10
lines changed

.changeset/calm-llamas-report.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@vue-macros/api': patch
3+
---
4+
5+
support mutating intersection type

packages/api/src/vue/emits.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,13 @@ export async function handleTSEmitsDefinition({
6060
const addEmit: TSEmits['addEmit'] = (name, signature) => {
6161
const key = keyToString(name)
6262

63-
if (definitionsAst.scope === file)
64-
// TODO: intersection
65-
s.appendLeft(definitionsAst.ast.end! + offset - 1, ` ${signature}\n`)
66-
63+
if (definitionsAst.scope === file) {
64+
if (definitionsAst.ast.type === 'TSIntersectionType') {
65+
s.appendLeft(definitionsAst.ast.end! + offset, ` & { ${signature} }`)
66+
} else {
67+
s.appendLeft(definitionsAst.ast.end! + offset - 1, ` ${signature}\n`)
68+
}
69+
}
6770
if (!definitions[key]) definitions[key] = []
6871
const ast = parseSignature(signature)
6972
definitions[key].push({

packages/api/src/vue/props.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,13 @@ export async function handleTSPropsDefinition({
7575
)
7676
if (definitions[key]) return false
7777

78-
if (definitionsAst.scope === file)
79-
// TODO: intersection
80-
s.appendLeft(definitionsAst.ast.end! + offset - 1, ` ${signature}\n`)
78+
if (definitionsAst.scope === file) {
79+
if (definitionsAst.ast.type === 'TSIntersectionType') {
80+
s.appendLeft(definitionsAst.ast.end! + offset, ` & { ${signature} }`)
81+
} else {
82+
s.appendLeft(definitionsAst.ast.end! + offset - 1, ` ${signature}\n`)
83+
}
84+
}
8185

8286
definitions[key] = {
8387
type: 'property',

packages/api/tests/__snapshots__/analyzeSFC.test.ts.snap

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,65 @@
11
// Vitest Snapshot v1
22

3+
exports[`analyzeSFC > defineEmits > addEmit should work 1`] = `
4+
{
5+
"change": [
6+
{
7+
"ast": "TSCallSignatureDeclaration...",
8+
"code": "(evt: 'change'): void",
9+
},
10+
],
11+
"click": [
12+
{
13+
"ast": "TSCallSignatureDeclaration...",
14+
"code": "(evt: 'click'): void",
15+
},
16+
{
17+
"ast": "TSCallSignatureDeclaration...",
18+
"code": "(evt: 'click', param: string): void",
19+
},
20+
],
21+
}
22+
`;
23+
24+
exports[`analyzeSFC > defineEmits > addEmit should work 2`] = `
25+
"<script setup lang=\\"ts\\">
26+
defineEmits<{
27+
(evt: 'click'): void
28+
(evt: 'change'): void
29+
(evt: 'click', param: string): void
30+
}>()</script>"
31+
`;
32+
33+
exports[`analyzeSFC > defineEmits > addEmit should work in intersection 1`] = `
34+
{
35+
"change": [
36+
{
37+
"ast": "TSCallSignatureDeclaration...",
38+
"code": "(evt: 'change'): void",
39+
},
40+
],
41+
"click": [
42+
{
43+
"ast": "TSCallSignatureDeclaration...",
44+
"code": "(evt: 'click'): void",
45+
},
46+
],
47+
"update": [
48+
{
49+
"ast": "TSCallSignatureDeclaration...",
50+
"code": "(evt: 'update'): void",
51+
},
52+
],
53+
}
54+
`;
55+
56+
exports[`analyzeSFC > defineEmits > addEmit should work in intersection 2`] = `
57+
"<script setup lang=\\"ts\\">
58+
defineEmits<{
59+
(evt: 'click'): void
60+
} & { (evt: 'change'): void } & { (evt: 'update'): void }>()</script>"
61+
`;
62+
363
exports[`analyzeSFC > defineEmits > definitions should be correct 1`] = `
464
{
565
"1": [
@@ -112,6 +172,67 @@ exports[`analyzeSFC > defineProps > addProp should work 1`] = `
112172
}
113173
`;
114174
175+
exports[`analyzeSFC > defineProps > addProp should work 2`] = `
176+
"<script setup lang=\\"ts\\">
177+
defineProps<{
178+
foo: string
179+
newProp: number | string
180+
newProp2?: string
181+
}>()</script>"
182+
`;
183+
184+
exports[`analyzeSFC > defineProps > addProp should work in intersection 1`] = `
185+
{
186+
"bar": {
187+
"addByAPI": false,
188+
"optional": false,
189+
"signature": {
190+
"ast": "TSPropertySignature...",
191+
"code": "bar: number",
192+
},
193+
"type": "property",
194+
"value": {
195+
"ast": "TSNumberKeyword...",
196+
"code": "number",
197+
},
198+
},
199+
"foo": {
200+
"addByAPI": false,
201+
"optional": false,
202+
"signature": {
203+
"ast": "TSPropertySignature...",
204+
"code": "foo: string",
205+
},
206+
"type": "property",
207+
"value": {
208+
"ast": "TSStringKeyword...",
209+
"code": "string",
210+
},
211+
},
212+
"newProp": {
213+
"addByAPI": true,
214+
"optional": false,
215+
"signature": {
216+
"ast": "TSPropertySignature...",
217+
"code": "newProp: number | string",
218+
},
219+
"type": "property",
220+
"value": {
221+
"ast": "TSUnionType...",
222+
"code": "number | string",
223+
},
224+
},
225+
}
226+
`;
227+
228+
exports[`analyzeSFC > defineProps > addProp should work in intersection 2`] = `
229+
"<script setup lang=\\"ts\\">
230+
231+
type Foo = { foo: string }
232+
type Bar = { bar: number }
233+
defineProps<Foo & Bar & { newProp: number | string }>()</script>"
234+
`;
235+
115236
exports[`analyzeSFC > defineProps > definitions should be correct 1`] = `
116237
{
117238
"bar": {

packages/api/tests/analyzeSFC.test.ts

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,20 @@ describe('analyzeSFC', () => {
172172
)
173173

174174
snapshot(hideAstLocation(props!.definitions))
175+
snapshot(s.toString())
175176
})
176177

177-
test.todo('add props in intersection')
178+
test('addProp should work in intersection', async () => {
179+
const { props, s } = await complie(`
180+
type Foo = { foo: string }
181+
type Bar = { bar: number }
182+
defineProps<Foo & Bar>()`)
183+
expect(props!.addProp('newProp', 'number | string')).toBe(true)
184+
expect(s.toString()).toContain(`Foo & Bar`)
185+
186+
snapshot(hideAstLocation(props!.definitions))
187+
snapshot(s.toString())
188+
})
178189

179190
describe('removeProp should work', () => {
180191
test('remove property prop', async () => {
@@ -480,8 +491,52 @@ describe('analyzeSFC', () => {
480491
snapshot(hideAstLocation(emits!.definitions))
481492
})
482493

483-
test.todo('addEmit should work')
484-
test.todo('add emit in intersection')
494+
test('addEmit should work', async () => {
495+
const { emits, s } = await complie(`defineEmits<{
496+
(evt: 'click'): void
497+
}>()`)
498+
emits!.addEmit('change', `(evt: 'change'): void`)
499+
emits!.addEmit('click', `(evt: 'click', param: string): void`)
500+
expect(s.toString()).toContain(`(evt: 'change'): void\n`)
501+
expect(s.toString()).toContain(`(evt: 'click', param: string): void\n`)
502+
503+
expect(hideAstLocation(emits!.definitions.click)).toEqual([
504+
{
505+
ast: 'TSCallSignatureDeclaration...',
506+
code: "(evt: 'click'): void",
507+
},
508+
{
509+
ast: 'TSCallSignatureDeclaration...',
510+
code: "(evt: 'click', param: string): void",
511+
},
512+
])
513+
expect(hideAstLocation(emits!.definitions.change)).toEqual([
514+
{
515+
ast: 'TSCallSignatureDeclaration...',
516+
code: "(evt: 'change'): void",
517+
},
518+
])
519+
520+
snapshot(hideAstLocation(emits!.definitions))
521+
snapshot(s.toString())
522+
})
523+
524+
test('addEmit should work in intersection', async () => {
525+
const { emits, s } = await complie(`defineEmits<{
526+
(evt: 'click'): void
527+
} & { (evt: 'change'): void }>()`)
528+
emits!.addEmit('update', `(evt: 'update'): void`)
529+
expect(s.toString()).toContain(` & { (evt: 'update'): void }`)
530+
531+
expect(hideAstLocation(emits!.definitions.update)).toEqual([
532+
{
533+
ast: 'TSCallSignatureDeclaration...',
534+
code: "(evt: 'update'): void",
535+
},
536+
])
537+
snapshot(hideAstLocation(emits!.definitions))
538+
snapshot(s.toString())
539+
})
485540

486541
describe.todo('removeProp should work', () => {
487542
test.todo('remove property prop')

0 commit comments

Comments
 (0)