Skip to content

Commit f4a845a

Browse files
authored
fix: remove componentless routes from routes in _RouteFileInfoMap (#686)
1 parent 04b17c5 commit f4a845a

File tree

3 files changed

+79
-9
lines changed

3 files changed

+79
-9
lines changed

src/codegen/generateDTS.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ ${normalizeLines(routeNamedMap)}
6565
6666
/**
6767
* Route file to route info map by unplugin-vue-router.
68-
* Used by the volar plugin to automatically type useRoute()
68+
* Used by the \`sfc-typed-router\` Volar plugin to automatically type \`useRoute()\`.
6969
*
7070
* Each key is a file path relative to the project root with 2 properties:
7171
* - routes: union of route names of the possible routes when in this page (passed to useRoute<...>())
@@ -77,7 +77,7 @@ ${normalizeLines(routeFileInfoMap)}
7777
7878
/**
7979
* Get a union of possible route names in a certain route component file.
80-
* Used by the volar plugin to automatically type useRoute()
80+
* Used by the \`sfc-typed-router\` Volar plugin to automatically type \`useRoute()\`.
8181
*
8282
* @internal
8383
*/

src/codegen/generateRouteFileInfoMap.spec.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,65 @@ describe('generateRouteFileInfoMap', () => {
108108
}"
109109
`)
110110
})
111+
112+
it('does not contain routes without components', () => {
113+
const tree = new PrefixTree(DEFAULT_OPTIONS)
114+
tree.insert('optional/[[id]]', 'optional/[[id]].vue')
115+
tree.insert(
116+
'optional-repeatable/[[id]]+',
117+
'optional-repeatable/[[id]]+.vue'
118+
)
119+
tree.insert('repeatable/[id]+', 'repeatable/[id]+.vue')
120+
121+
expect(formatExports(generateRouteFileInfoMap(tree, { root: '' })))
122+
.toMatchInlineSnapshot(`
123+
"export interface _RouteFileInfoMap {
124+
'optional/[[id]].vue': {
125+
routes: '/optional/[[id]]'
126+
views: never
127+
}
128+
'optional-repeatable/[[id]]+.vue': {
129+
routes: '/optional-repeatable/[[id]]+'
130+
views: never
131+
}
132+
'repeatable/[id]+.vue': {
133+
routes: '/repeatable/[id]+'
134+
views: never
135+
}
136+
}"
137+
`)
138+
})
139+
140+
it('does not contain nested routes without components', () => {
141+
const tree = new PrefixTree(DEFAULT_OPTIONS)
142+
tree.insert('parent', 'parent.vue')
143+
tree.insert('parent/optional/[[id]]', 'parent/optional/[[id]].vue')
144+
tree.insert(
145+
'parent/optional-repeatable/[[id]]+',
146+
'parent/optional-repeatable/[[id]]+.vue'
147+
)
148+
tree.insert('parent/repeatable/[id]+', 'parent/repeatable/[id]+.vue')
149+
150+
expect(formatExports(generateRouteFileInfoMap(tree, { root: '' })))
151+
.toMatchInlineSnapshot(`
152+
"export interface _RouteFileInfoMap {
153+
'parent.vue': {
154+
routes: '/parent' | '/parent/optional/[[id]]' | '/parent/optional-repeatable/[[id]]+' | '/parent/repeatable/[id]+'
155+
views: 'default'
156+
}
157+
'parent/optional/[[id]].vue': {
158+
routes: '/parent/optional/[[id]]'
159+
views: never
160+
}
161+
'parent/optional-repeatable/[[id]]+.vue': {
162+
routes: '/parent/optional-repeatable/[[id]]+'
163+
views: never
164+
}
165+
'parent/repeatable/[id]+.vue': {
166+
routes: '/parent/repeatable/[id]+'
167+
views: never
168+
}
169+
}"
170+
`)
171+
})
111172
})

src/codegen/generateRouteFileInfoMap.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,28 @@ function generateRouteFileInfoLines(
6464
routeNames: string[]
6565
childrenNamedViews: string[] | null
6666
}> {
67-
const children = node.children.size > 0 ? node.getChildrenDeepSorted() : null
67+
const deepChildren =
68+
node.children.size > 0 ? node.getChildrenDeepSorted() : null
6869

69-
const childrenNamedViews = children
70+
const deepChildrenNamedViews = deepChildren
7071
? Array.from(
7172
new Set(
72-
children.flatMap((child) => Array.from(child.value.components.keys()))
73+
deepChildren.flatMap((child) =>
74+
Array.from(child.value.components.keys())
75+
)
7376
)
7477
)
7578
: null
7679

77-
const routeNames = [node, ...node.getChildrenDeepSorted()]
78-
// an unnamed route cannot be accessed in types
79-
.filter((node): node is TreeNode & { name: string } => !!node.name)
80+
const routeNames: Array<Extract<TreeNode['name'], string>> = [
81+
node,
82+
...(deepChildren ?? []),
83+
]
84+
// unnamed routes and routes that don't correspond to certain components cannot be accessed in types
85+
.filter(
86+
(node): node is TreeNode & { name: string } =>
87+
node.value.components.size > 0 && !!node.name
88+
)
8089
.map((node) => node.name)
8190

8291
// Most of the time we only have one view, but with named views we can have multiple.
@@ -86,7 +95,7 @@ function generateRouteFileInfoLines(
8695
: Array.from(node.value.components.values()).map((file) => ({
8796
key: relative(rootDir, file).replaceAll('\\', '/'),
8897
routeNames,
89-
childrenNamedViews,
98+
childrenNamedViews: deepChildrenNamedViews,
9099
}))
91100

92101
const childrenRouteInfo = node

0 commit comments

Comments
 (0)