Skip to content

Commit fe3cb96

Browse files
authored
feat: implement router-view-transition-keep-alive transformation (#44)
1 parent 4304a2b commit fe3cb96

File tree

5 files changed

+125
-1
lines changed

5 files changed

+125
-1
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { runTest } from '../../src/testUtils'
2+
3+
runTest(
4+
'router-view keep-alive transition',
5+
'router-view-keep-alive-transition',
6+
'router-view-keep-alive-transition',
7+
'vue',
8+
'vue'
9+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<template>
2+
<transition>
3+
<keep-alive>
4+
<router-view class="class one"></router-view>
5+
</keep-alive>
6+
</transition>
7+
8+
<transition>
9+
<router-view class="class two"></router-view>
10+
</transition>
11+
</template>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<template>
2+
<router-view class="class one" v-slot="{ Component }"><transition>
3+
<keep-alive>
4+
<component :is="Component" />
5+
</keep-alive>
6+
</transition></router-view>
7+
8+
<router-view class="class two" v-slot="{ Component }"><transition>
9+
<component :is="Component" />
10+
</transition></router-view>
11+
</template>

vue-transformations/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ const transformationMap: {
1919
'v-bind-sync': require('./v-bind-sync'),
2020
'remove-v-on-native': require('./remove-v-on-native'),
2121
'router-link-event-tag': require('./router-link-event-tag'),
22-
'router-link-exact': require('./router-link-exact')
22+
'router-link-exact': require('./router-link-exact'),
23+
'router-view-keep-alive-transition': require('router-view-keep-alive-transition')
2324
}
2425

2526
export const excludedVueTransformations = ['v-bind-order-sensitive']
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { Node, VElement } from 'vue-eslint-parser/ast/nodes'
2+
import * as OperationUtils from '../src/operationUtils'
3+
import type { Operation } from '../src/operationUtils'
4+
import type { VueASTTransformation } from '../src/wrapVueTransformation'
5+
import * as parser from 'vue-eslint-parser'
6+
import wrap from '../src/wrapVueTransformation'
7+
8+
export const transformAST: VueASTTransformation = context => {
9+
let fixOperations: Operation[] = []
10+
const { file } = context
11+
const source = file.source
12+
const toFixNodes: Node[] = findNodes(context)
13+
toFixNodes.forEach(node => {
14+
fixOperations = fixOperations.concat(fix(node, source))
15+
})
16+
return fixOperations
17+
}
18+
19+
export default wrap(transformAST)
20+
21+
function findNodes(context: any): Node[] {
22+
const { file } = context
23+
const source = file.source
24+
const options = { sourceType: 'module' }
25+
const ast = parser.parse(source, options)
26+
let toFixNodes: Node[] = []
27+
let root: Node = <Node>ast.templateBody
28+
29+
// find transition nodes
30+
parser.AST.traverseNodes(root, {
31+
enterNode(node: Node) {
32+
if (
33+
node.type === 'VElement' &&
34+
node.name === 'transition' &&
35+
node.children.length
36+
) {
37+
toFixNodes.push(node)
38+
}
39+
},
40+
leaveNode(node: Node) {}
41+
})
42+
43+
return toFixNodes
44+
}
45+
46+
function fix(node: Node, source: string): Operation[] {
47+
let fixOperations: Operation[] = []
48+
49+
// find transition nodes which contain router-view node.
50+
// note that router-view tag may under the keep-alive tag
51+
let routerView
52+
const children = (<VElement>node).children
53+
const keepAlive = children.find(child => {
54+
return (
55+
child.type === 'VElement' &&
56+
child.name === 'keep-alive' &&
57+
child.children.length
58+
)
59+
})
60+
if (keepAlive) {
61+
routerView = (<VElement>keepAlive).children.find(child => {
62+
return child.type === 'VElement' && child.name === 'router-view'
63+
})
64+
} else {
65+
routerView = (<VElement>node).children.find(child => {
66+
return child.type === 'VElement' && child.name === 'router-view'
67+
})
68+
}
69+
70+
// replace with vue-router-next syntax
71+
if (routerView) {
72+
routerView = <VElement>routerView
73+
// get attributes text
74+
let attributeText = ''
75+
routerView.startTag.attributes.forEach(
76+
node => (attributeText += OperationUtils.getText(node, source))
77+
)
78+
// replace with vue-router-next syntax
79+
fixOperations.push(
80+
OperationUtils.replaceText(routerView, '<component :is="Component" />')
81+
)
82+
fixOperations.push(
83+
OperationUtils.insertTextBefore(
84+
node,
85+
`<router-view ${attributeText} v-slot="{ Component }">`
86+
)
87+
)
88+
fixOperations.push(OperationUtils.insertTextAfter(node, '</router-view>'))
89+
}
90+
91+
return fixOperations
92+
}

0 commit comments

Comments
 (0)