Skip to content

Commit 83ae454

Browse files
authored
feat: detect $slots.* usage in script (#31)
1 parent 8ce51dd commit 83ae454

File tree

6 files changed

+39
-17
lines changed

6 files changed

+39
-17
lines changed

src/utils/parseComponent.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,24 @@ export function parseComponent (name: string, source: string) {
88
// Parse component source
99
const { descriptor } = parse(source)
1010
let props: ComponentProp[] = []
11+
let slots
1112

1213
// Parse script
1314
if (descriptor.scriptSetup) {
1415
const setupScrip = parseSetupScript(name, descriptor)
1516
props = setupScrip.props
17+
slots = setupScrip.slots
1618
} else if (descriptor.script) {
1719
const script = parseScript(name, descriptor)
1820
props = script.props
21+
slots = script.slots
1922
}
2023

21-
const { slots } = parseTemplate(name, descriptor)
24+
const template = parseTemplate(name, descriptor)
2225

2326
return {
2427
name,
2528
props,
26-
slots
29+
slots: Array.from(new Set(template.slots.concat(slots)))
2730
}
2831
}

src/utils/parseScript.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ import type { SFCDescriptor } from '@vue/compiler-sfc'
22
import { compileScript } from '@vue/compiler-sfc'
33
import { ComponentProp } from '../types'
44
import { getType, getValue, visit } from './ast'
5+
import { findSlotUsage } from './source'
56

67
export function parseScript (id: string, descriptor: SFCDescriptor) {
78
const props: ComponentProp[] = []
89
const script = compileScript(descriptor, { id })
910

11+
const slots = findSlotUsage(script.content)
12+
1013
visit(script.scriptAst, node => node.type === 'CallExpression' && node.callee?.name === 'defineComponent', (node) => {
1114
const nodeProps = node.arguments?.[0]?.properties?.find(prop => prop.key.name === 'props')
1215
if (!nodeProps) {
@@ -33,6 +36,7 @@ export function parseScript (id: string, descriptor: SFCDescriptor) {
3336
})
3437

3538
return {
36-
props
39+
props,
40+
slots
3741
}
3842
}

src/utils/parseSetupScript.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ import type { SFCDescriptor } from '@vue/compiler-sfc'
22
import { compileScript } from '@vue/compiler-sfc'
33
import { ComponentProp } from '../types'
44
import { getType, getValue, visit } from './ast'
5+
import { findSlotUsage } from './source'
56

67
export function parseSetupScript (id: string, descriptor: SFCDescriptor) {
78
const props: ComponentProp[] = []
89
const script = compileScript(descriptor, { id })
910

11+
const slots = findSlotUsage(script.content)
12+
1013
visit(script.scriptSetupAst, node => node.type === 'CallExpression' && node.callee?.name === 'defineProps', (node) => {
1114
const properties = node.arguments[0]?.properties || []
1215
properties.reduce((props, p) => {
@@ -29,6 +32,7 @@ export function parseSetupScript (id: string, descriptor: SFCDescriptor) {
2932
})
3033

3134
return {
32-
props
35+
props,
36+
slots
3337
}
3438
}

src/utils/parseTemplate.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { SFCDescriptor } from '@vue/compiler-sfc'
22
import { compileTemplate } from '@vue/compiler-sfc'
3+
import { findSlotUsage } from './source'
34

45
export function parseTemplate (id: string, descriptor: SFCDescriptor) {
56
const slots = []
@@ -26,20 +27,14 @@ export function parseTemplate (id: string, descriptor: SFCDescriptor) {
2627
]
2728
}
2829

29-
// Detect `$slots` usage
30-
const $slots = template.source.matchAll(/\$slots(\.([-_\w]+)|\[['"]([-_\w]+)['"]\])/g)
31-
let $slot = $slots.next()
32-
while (!$slot.done) {
33-
slots.push({
34-
name: $slot.value[2] || $slot.value[3]
35-
})
36-
$slot = $slots.next()
37-
}
38-
3930
// Detect `<slot>` usage
4031
const slotsAst = findSlots(template.ast.children)
4132
slots.push(...slotsAst)
4233

34+
// Detect `$slots` usage
35+
const slotUsages = findSlotUsage(template.source)
36+
slots.push(...slotUsages)
37+
4338
return {
4439
slots
4540
}

src/utils/source.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* find `$slots.*` usage in the source code
3+
*/
4+
export function findSlotUsage (source: string) {
5+
const slots: any[] = []
6+
// Detect `$slots` usage
7+
const $slots = source.matchAll(/\$slots(\.([-_\w]+)|\[['"]([-_\w]+)['"]\])/g)
8+
let $slot = $slots.next()
9+
while (!$slot.done) {
10+
slots.push({
11+
name: $slot.value[2] || $slot.value[3]
12+
})
13+
$slot = $slots.next()
14+
}
15+
return slots
16+
}

test/basic-component.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ describe('Basic Component', async () => {
1212

1313
test('Slots', () => {
1414
expect(slots).toEqual([
15-
{ name: 'variable' },
16-
{ name: 'foo-bar' },
1715
{ name: 'default' },
18-
{ name: 'nuxt' }
16+
{ name: 'nuxt' },
17+
{ name: 'variable' },
18+
{ name: 'foo-bar' }
1919
])
2020
})
2121

0 commit comments

Comments
 (0)