Skip to content

Commit bdaa981

Browse files
author
Guillaume Chau
committed
refactor(generator): router codemod
1 parent cb24a40 commit bdaa981

File tree

5 files changed

+105
-18
lines changed

5 files changed

+105
-18
lines changed

generator/codemod/router.js

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
const { parse, types: { namedTypes, builders }, print } = require('recast')
2+
const { isVueGlobalCall } = require('./util')
3+
4+
exports.wrapRouterToExportedFunction = (contents) => {
5+
// @TODO remove when esprima supports dynamic imports
6+
contents = contents.replace(/import\(/g, '__webpack_dynamic_import__(')
7+
const ast = parse(contents)
8+
9+
const outside = []
10+
const inside = []
11+
let origDefaultExportDeclaration
12+
13+
ast.program.body.forEach(node => {
14+
if (namedTypes.ExportDefaultDeclaration.check(node)) {
15+
origDefaultExportDeclaration = node
16+
} else if (
17+
namedTypes.ImportDeclaration.check(node) ||
18+
namedTypes.ExportAllDeclaration.check(node) ||
19+
namedTypes.ExportNamedDeclaration.check(node) ||
20+
namedTypes.ExportDeclaration.check(node) ||
21+
isVueGlobalCall(node)
22+
) {
23+
outside.push(node)
24+
} else {
25+
inside.push(node)
26+
}
27+
})
28+
29+
const returnStatement = builders.returnStatement(
30+
origDefaultExportDeclaration.declaration,
31+
)
32+
33+
const functionDeclaration = builders.functionDeclaration(
34+
builders.identifier('createRouter'),
35+
[],
36+
builders.blockStatement([
37+
...inside,
38+
returnStatement,
39+
]),
40+
)
41+
42+
const newProgram = builders.program([
43+
...outside,
44+
builders.exportNamedDeclaration(
45+
functionDeclaration,
46+
),
47+
])
48+
49+
contents = print(newProgram).code
50+
51+
// @TODO remove when esprima supports dynamic imports
52+
contents = contents.replace(/__webpack_dynamic_import__\(/g, 'import(')
53+
return contents
54+
}

generator/codemod/util.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const { types: { namedTypes } } = require('recast')
2+
3+
exports.isVueGlobalCall = (node) => {
4+
if (namedTypes.ExpressionStatement.check(node)) {
5+
node = node.expression
6+
if (namedTypes.CallExpression.check(node)) {
7+
if (node.callee.object.name === 'Vue') {
8+
return true
9+
}
10+
}
11+
}
12+
return false
13+
}

generator/index.js

+20-16
Original file line numberDiff line numberDiff line change
@@ -82,32 +82,36 @@ module.exports = (api, options, rootOptions) => {
8282
}
8383

8484
// Router
85-
{
85+
try {
8686
const file = getFile(api, './src/router.js')
8787
if (file) {
8888
let contents = fs.readFileSync(file, { encoding: 'utf8' })
89-
contents = contents.replace(/export default new Router\({((.|\s)+)}\)/, `export function createRouter () {
90-
return new Router({
91-
${contents.includes('mode:') ? '' : 'mode: \'history\','}$1})
92-
}`)
89+
const { wrapRouterToExportedFunction } = require('./codemod/router')
90+
contents = wrapRouterToExportedFunction(contents)
9391
contents = contents.replace(/mode:\s*("|')(hash|abstract)("|'),/, '')
9492
fs.writeFileSync(file, contents, { encoding: 'utf8' })
9593
}
94+
} catch (e) {
95+
console.error('An error occured while transforming router code', e.stack)
9696
}
9797

9898
// Vuex
9999
if (api.hasPlugin('vuex')) {
100-
const file = getFile(api, './src/store.js')
101-
if (file) {
102-
let contents = fs.readFileSync(file, { encoding: 'utf8' })
103-
contents = contents.replace(/export default new Vuex\.Store\({((.|\s)+)}\)/, `export function createStore () {
104-
return new Vuex.Store({$1})
105-
}`)
106-
contents = contents.replace(/state:\s*{((.|\s)*?)},\s*(getters|mutations|actions|modules|namespaced):/, `state () {
107-
return {$1}
108-
},
109-
$3:`)
110-
fs.writeFileSync(file, contents, { encoding: 'utf8' })
100+
try {
101+
const file = getFile(api, './src/store.js')
102+
if (file) {
103+
let contents = fs.readFileSync(file, { encoding: 'utf8' })
104+
contents = contents.replace(/export default new Vuex\.Store\({((.|\s)+)}\)/, `export function createStore () {
105+
return new Vuex.Store({$1})
106+
}`)
107+
contents = contents.replace(/state:\s*{((.|\s)*?)},\s*(getters|mutations|actions|modules|namespaced):/, `state () {
108+
return {$1}
109+
},
110+
$3:`)
111+
fs.writeFileSync(file, contents, { encoding: 'utf8' })
112+
}
113+
} catch (e) {
114+
console.error('An error occured while transforming vuex code', e.stack)
111115
}
112116
}
113117

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"memory-fs": "^0.5.0",
4343
"portfinder": "^1.0.25",
4444
"querystring": "^0.2.0",
45+
"recast": "^0.18.5",
4546
"rimraf": "^3.0.0",
4647
"serve-favicon": "^2.5.0",
4748
"webpack-dev-middleware": "^3.7.2",

yarn.lock

+17-2
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,11 @@ assign-symbols@^1.0.0:
12911291
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
12921292
integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
12931293

1294+
1295+
version "0.13.2"
1296+
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.2.tgz#df39b677a911a83f3a049644fb74fdded23cea48"
1297+
integrity sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA==
1298+
12941299
astral-regex@^1.0.0:
12951300
version "1.0.0"
12961301
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
@@ -3127,7 +3132,7 @@ esprima@^2.6.0:
31273132
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
31283133
integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=
31293134

3130-
esprima@^4.0.0:
3135+
esprima@^4.0.0, esprima@~4.0.0:
31313136
version "4.0.1"
31323137
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
31333138
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
@@ -6573,7 +6578,7 @@ prismjs@^1.13.0:
65736578
optionalDependencies:
65746579
clipboard "^2.0.0"
65756580

6576-
private@^0.1.6:
6581+
private@^0.1.6, private@^0.1.8:
65776582
version "0.1.8"
65786583
resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
65796584
integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==
@@ -6836,6 +6841,16 @@ readdirp@^2.0.0:
68366841
micromatch "^3.1.10"
68376842
readable-stream "^2.0.2"
68386843

6844+
recast@^0.18.5:
6845+
version "0.18.5"
6846+
resolved "https://registry.yarnpkg.com/recast/-/recast-0.18.5.tgz#9d5adbc07983a3c8145f3034812374a493e0fe4d"
6847+
integrity sha512-sD1WJrpLQAkXGyQZyGzTM75WJvyAd98II5CHdK3IYbt/cZlU0UzCRVU11nUFNXX9fBVEt4E9ajkMjBlUlG+Oog==
6848+
dependencies:
6849+
ast-types "0.13.2"
6850+
esprima "~4.0.0"
6851+
private "^0.1.8"
6852+
source-map "~0.6.1"
6853+
68396854
redent@^2.0.0:
68406855
version "2.0.0"
68416856
resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa"

0 commit comments

Comments
 (0)