Skip to content

Commit 259eb49

Browse files
committed
feat: implement render to resolveComponent
1 parent f396fe2 commit 259eb49

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { defineInlineTest } from 'jscodeshift/src/testUtils'
2+
const transform = require('../render-to-resolveComponent')
3+
4+
defineInlineTest(
5+
transform,
6+
{},
7+
`export default {
8+
render(h){
9+
return h('button-counter')
10+
}
11+
}`,
12+
`
13+
import { resolveComponent } from "vue";
14+
export default {
15+
render() {
16+
const buttonCounter = resolveComponent('button-counter')
17+
return buttonCounter;
18+
}
19+
}`,
20+
'transform render-to-resolveComponent'
21+
)

transformations/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const transformationMap: {
1717
'scoped-slots-to-slots': require('./scoped-slots-to-slots'),
1818
'new-directive-api': require('./new-directive-api'),
1919
'remove-vue-set-and-delete': require('./remove-vue-set-and-delete'),
20+
'render-to-resolveComponent': require('./render-to-resolveComponent'),
2021

2122
// atomic ones
2223
'remove-contextual-h-from-render': require('./remove-contextual-h-from-render'),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import wrap from '../src/wrapAstTransformation'
2+
import type { ASTTransformation } from '../src/wrapAstTransformation'
3+
import { transformAST as addImport } from './add-import'
4+
5+
export const transformAST: ASTTransformation = (context) => {
6+
7+
const { root, j } = context
8+
// find render function
9+
const renderCollections = root.find(j.ObjectMethod, node => {
10+
return node.key.name === 'render'
11+
&& node.params.length === 1
12+
})
13+
.filter(nodePath => nodePath.parent.parent.node.type === 'ExportDefaultDeclaration')
14+
if (!renderCollections) return
15+
16+
// add import
17+
addImport(context, {
18+
specifier: { type: 'named', imported: 'resolveComponent' },
19+
source: 'vue'
20+
})
21+
22+
renderCollections.forEach(({ node }) => {
23+
// @ts-ignore
24+
const paramName = node.params[0].name
25+
// remove render function param
26+
node.params = []
27+
const callExpressionCollection = j(node).find(j.CallExpression, node => {
28+
return node.callee.name === paramName
29+
&& node.arguments.length === 1
30+
})
31+
32+
if (!callExpressionCollection.length) return
33+
// find the component name
34+
const componentName = callExpressionCollection.get(0).node.arguments[0].value
35+
// remove non-letter for complying variable name rules
36+
const componentVariableName = removeNonLetter(componentName)
37+
callExpressionCollection.get(0).parent.insertBefore(j(`const ${componentVariableName} = resolveComponent('${componentName}')`).find(j.VariableDeclaration).get().node)
38+
// replace h('xxx') with resolveComponent('xxx')
39+
// @ts-ignore
40+
callExpressionCollection.replaceWith(nodePath => nodePath.node.callee.name = componentVariableName)
41+
})
42+
}
43+
44+
/**
45+
* remove non-letter and uppercase the first letter after non-letter
46+
* button-component => buttonComponent
47+
* @param str
48+
*/
49+
function removeNonLetter(str: string): string | undefined {
50+
51+
if (str) {
52+
let returnValue: string = ''
53+
for (let i = 0; i < str.length; i++) {
54+
// letter
55+
if ((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z')) {
56+
returnValue += str[i]
57+
} else {
58+
// non-letter , remove and uppercase the first letter after non-letter
59+
i++
60+
if (str[i] >= 'a' && str[i] <= 'z') {
61+
returnValue += String.fromCharCode(str[i].charCodeAt(0) - 32)
62+
}
63+
}
64+
}
65+
return returnValue
66+
}
67+
}
68+
69+
export default wrap(transformAST)
70+
export const parser = 'babylon'

0 commit comments

Comments
 (0)