Skip to content

Commit 8fe2fbc

Browse files
authored
feat: add transformation report (#74)
1 parent 9d6e99a commit 8fe2fbc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+321
-78
lines changed

bin/vue-codemod.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import runTransformation from '../src/runTransformation'
1818
import { transform as packageTransform } from '../src/packageTransformation'
1919

2020
import type { TransformationModule } from '../src/runTransformation'
21+
import { formatterOutput } from '../src/report'
2122

2223
const debug = createDebug('vue-codemod:cli')
2324
const log = console.log.bind(console)
@@ -27,6 +28,7 @@ const {
2728
_: files,
2829
transformation: transformationName,
2930
runAllTransformation: runAllTransformation,
31+
reportFormatter: formatter,
3032
params
3133
} = yargs
3234
.usage('Usage: vue-codemod [file pattern] <option>')
@@ -46,6 +48,12 @@ const {
4648
conflicts: 'transformation',
4749
describe: 'run all transformation module'
4850
})
51+
.option('reportFormatter', {
52+
alias: 'f',
53+
type: 'string',
54+
describe: 'Specify an output report formatter',
55+
default: 'detail'
56+
})
4957
.example([
5058
[
5159
'npx vue-codemod ./src -a',
@@ -85,6 +93,7 @@ async function main() {
8593

8694
// init global params
8795
global.globalApi = []
96+
global.outputReport = {}
8897

8998
const resolvedPaths = globby.sync(files as string[])
9099
if (transformationName != undefined) {
@@ -97,6 +106,7 @@ async function main() {
97106
)
98107
if (packageTransform()) {
99108
processFilePath.push('package.json')
109+
global.outputReport['package.json'] = 1
100110
}
101111
}
102112

@@ -125,10 +135,8 @@ async function main() {
125135
processFilePath.push('package.json')
126136
}
127137
}
128-
const processFilePathList = processFilePath.join('\n')
129-
console.log(`--------------------------------------------------`)
130-
console.log(`Processed file:\n${processFilePathList}`)
131-
console.log(`Processed ${processFilePath.length} files`)
138+
139+
formatterOutput(processFilePath, formatter)
132140
}
133141
/**
134142
* process files by Transformation

src/global.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ export type GlobalApi = {
77
declare global {
88
// Use to add global variables used by components to main.js
99
var globalApi: GlobalApi[]
10+
var outputReport: { [key: string]: number }
11+
var subRules: { [key: string]: number }
1012
}
1113

1214
export {}

src/report.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import * as fs from 'fs'
2+
3+
export function getCntFunc(key: string, outputObj: { [key: string]: number }) {
4+
if (!outputObj) {
5+
outputObj = { key: 0 }
6+
}
7+
if (!outputObj.hasOwnProperty(key)) {
8+
outputObj[key] = 0
9+
}
10+
function cntFunc(quantity: number = 1) {
11+
outputObj[key] += quantity
12+
}
13+
return cntFunc
14+
}
15+
16+
export function formatterOutput(processFilePath: string[], formatter: string) {
17+
// normal output
18+
const processFilePathList = processFilePath.join('\n')
19+
const totalChanged = Object.keys(global.outputReport).reduce(
20+
(sum, key) => sum + global.outputReport[key],
21+
0
22+
)
23+
const totalDetected = totalChanged
24+
const transRate =
25+
totalDetected == totalChanged ? 100 : (100 * totalChanged) / totalDetected
26+
27+
console.log(`--------------------------------------------------`)
28+
console.log(`Processed file:\n${processFilePathList}`)
29+
console.log(`Processed ${processFilePath.length} files`)
30+
31+
console.log(
32+
'\x1B[44;37;4m%s\x1B[0m',
33+
`${totalDetected} places`,
34+
`need to be transformed`
35+
)
36+
console.log(
37+
'\x1B[44;37;4m%s\x1B[0m',
38+
`${totalChanged} places`,
39+
`was transformed`
40+
)
41+
console.log(`The transformation rate is \x1B[44;37;4m${transRate}%\x1B[0m`)
42+
43+
if (formatter === 'all') {
44+
console.log('The transformation stats: \n')
45+
console.log(global.outputReport)
46+
}
47+
48+
Object.keys(outputReport).forEach(item => {
49+
if (!outputReport[item]) delete outputReport[item]
50+
})
51+
52+
if (formatter === 'detail') {
53+
console.log('The transformation stats: \n')
54+
console.log(global.outputReport)
55+
}
56+
57+
if (formatter === 'table') {
58+
console.log('The transformation stats: \n')
59+
console.table(global.outputReport)
60+
}
61+
62+
if (formatter === 'log') {
63+
logOutput(
64+
processFilePathList,
65+
processFilePath,
66+
totalDetected,
67+
totalChanged,
68+
transRate
69+
)
70+
}
71+
}
72+
73+
export function logOutput(
74+
processFilePathList: string,
75+
processFilePath: string[],
76+
totalDetected: number,
77+
totalChanged: number,
78+
transRate: number
79+
) {
80+
let options = {
81+
flags: 'w', //
82+
encoding: 'utf8' // utf8编码
83+
}
84+
85+
let stdout = fs.createWriteStream('./vue_codemod.log', options)
86+
87+
let logger = new console.Console(stdout)
88+
89+
logger.log(`--------------------------------------------------`)
90+
logger.log(`Processed file:\n${processFilePathList}\n`)
91+
logger.log(`Processed ${processFilePath.length} files`)
92+
logger.log(`${totalDetected} places`, `need to be transformed`)
93+
logger.log(`${totalChanged} places`, `was transformed`)
94+
logger.log(`The transformation rate is ${transRate}%`)
95+
logger.log('The transformation stats: \n', global.outputReport)
96+
}

src/wrapAstTransformation.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export type ASTTransformation<Params = void> = {
1010
(context: Context, params: Params): void
1111
}
1212

13+
global.subRules = {}
14+
1315
export default function astTransformationToJSCodeshiftModule<Params = any>(
1416
transformAST: ASTTransformation<Params>
1517
): Transform {

src/wrapVueTransformation.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { Operation } from './operationUtils'
22
import type VueTransformation from './VueTransformation'
33
import { Node } from 'vue-eslint-parser/ast/nodes'
44
import * as parser from 'vue-eslint-parser'
5+
import { getCntFunc } from './report'
56

67
const BOM = '\uFEFF'
78

@@ -21,7 +22,8 @@ export type VueASTTransformation<Params = void> = {
2122

2223
export function createTransformAST(
2324
nodeFilter: (node: Node) => boolean,
24-
fix: (node: Node, source?: string) => Operation[]
25+
fix: (node: Node, source?: string) => Operation[],
26+
ruleName: string
2527
) {
2628
function findNodes(context: any): Node[] {
2729
const { file } = context
@@ -44,12 +46,17 @@ export function createTransformAST(
4446
}
4547

4648
const transformAST: VueASTTransformation = context => {
49+
const cntFunc = getCntFunc(ruleName, global.outputReport)
4750
let fixOperations: Operation[] = []
4851
const { file } = context
4952
const source = file.source
5053
const toFixNodes: Node[] = findNodes(context)
5154
toFixNodes.forEach(node => {
52-
fixOperations = fixOperations.concat(fix(node, source))
55+
const operations = fix(node, source)
56+
if (operations.length) {
57+
cntFunc()
58+
fixOperations = fixOperations.concat(operations)
59+
}
5360
})
5461
return fixOperations
5562
}

transformations/add-emit-declaration.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import wrap from '../src/wrapAstTransformation'
22
import type { ASTTransformation } from '../src/wrapAstTransformation'
3+
import { getCntFunc } from '../src/report'
34

45
export const transformAST: ASTTransformation = ({ root, j }) => {
56
// find the export default
67
const defaultExportBody = root.find(j.ExportDefaultDeclaration)
7-
8+
// stats
9+
const cntFunc = getCntFunc('add-emit-declarations', global.outputReport)
810
// find the CallExpression
911
const emitCalls = defaultExportBody.find(j.CallExpression, node => {
1012
return (
@@ -47,6 +49,8 @@ export const transformAST: ASTTransformation = ({ root, j }) => {
4749
.node.declaration.properties?.unshift(
4850
j.objectProperty(j.identifier('emits'), j.arrayExpression(elements))
4951
)
52+
53+
cntFunc()
5054
}
5155
}
5256
}

transformations/global-filter.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import wrap from '../src/wrapAstTransformation'
22
import type { ASTTransformation } from '../src/wrapAstTransformation'
3+
import { getCntFunc } from '../src/report'
34

45
export const transformAST: ASTTransformation = ({ root, j }) => {
6+
const cntFunc = getCntFunc('global-filter', global.outputReport)
57
// find the createApp()
68
const appDeclare = root.find(j.VariableDeclarator, {
79
id: { type: 'Identifier' },
@@ -53,6 +55,7 @@ export const transformAST: ASTTransformation = ({ root, j }) => {
5355
return
5456
}
5557

58+
cntFunc()
5659
const methods = []
5760
for (let i = 0; i < filters.length; i++) {
5861
const filter = filters.at(i)

transformations/new-component-api.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import type { ASTTransformation } from '../src/wrapAstTransformation'
33
import { transformAST as removeExtraneousImport } from './remove-extraneous-import'
44
import type { GlobalApi } from '../src/global'
55
import * as _ from 'lodash'
6+
import { getCntFunc } from '../src/report'
67

78
export const transformAST: ASTTransformation = context => {
89
const { root, j, filename } = context
10+
const cntFunc = getCntFunc('new-component-api', global.outputReport)
911
const rootExpressionStatement = root
1012
.find(j.ExpressionStatement)
1113
.filter(path => path.parent.value.type === 'Program')
@@ -34,6 +36,7 @@ export const transformAST: ASTTransformation = context => {
3436
if (node.arguments.length === 2) {
3537
componentArgs = node.arguments
3638
let componentApi: GlobalApi
39+
cntFunc()
3740
if (j.Identifier.check(componentArgs[1])) {
3841
componentApi = { name: componentArgs[1].name, path: filename }
3942
} else {

transformations/new-directive-api.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import wrap from '../src/wrapAstTransformation'
22
import type { ASTTransformation } from '../src/wrapAstTransformation'
3+
import { getCntFunc } from '../src/report'
34

45
const hookNameMap: { [key: string]: string } = {
56
bind: 'beforeMount',
@@ -9,6 +10,7 @@ const hookNameMap: { [key: string]: string } = {
910
}
1011

1112
export const transformAST: ASTTransformation = ({ root, j }) => {
13+
const cntFunc = getCntFunc('new-directive-api', global.outputReport)
1214
const directiveRegistration = root.find(j.CallExpression, {
1315
callee: {
1416
type: 'MemberExpression',
@@ -40,6 +42,7 @@ export const transformAST: ASTTransformation = ({ root, j }) => {
4042

4143
if (hookNameMap[prop.key.name]) {
4244
prop.key.name = hookNameMap[prop.key.name]
45+
cntFunc()
4346
}
4447
if (prop.key.name === 'update') {
4548
updateIndex = index

transformations/new-global-api.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,16 @@ import { transformAST as removeVueUse } from './remove-vue-use'
1111
import { transformAST as removeContextualHFromRender } from './remove-contextual-h-from-render'
1212

1313
import { transformAST as removeExtraneousImport } from './remove-extraneous-import'
14+
import { getCntFunc } from '../src/report'
1415

1516
export const transformAST: ASTTransformation = context => {
17+
const newVueCount = subRules['new-vue-to-create-app']
18+
? subRules['new-vue-to-create-app']
19+
: 0
20+
const remHCount = subRules['remove-contextual-h-from-render']
21+
? subRules['remove-contextual-h-from-render']
22+
: 0
23+
const beforeCount = newVueCount + remHCount
1624
vueAsNamespaceImport(context)
1725
importCompositionApiFromVue(context)
1826
newVueTocreateApp(context)
@@ -29,11 +37,17 @@ export const transformAST: ASTTransformation = context => {
2937
removeVueUse(context, {
3038
removablePlugins: ['VueRouter', 'Vuex', 'VueCompositionApi', 'VueI18n']
3139
})
32-
removeContextualHFromRender(context)
40+
removeContextualHFromRender(context) // count
3341

3442
removeExtraneousImport(context, { localBinding: 'Vue' })
3543
removeExtraneousImport(context, { localBinding: 'Vuex' })
3644
removeExtraneousImport(context, { localBinding: 'VueRouter' })
45+
const afterCount =
46+
subRules['new-vue-to-create-app'] +
47+
subRules['remove-contextual-h-from-render']
48+
const change = afterCount - beforeCount
49+
const cntFunc = getCntFunc('new-global-api', outputReport)
50+
cntFunc(change)
3751
}
3852

3953
export default wrap(transformAST)

0 commit comments

Comments
 (0)