0%

gogocode AST 抽象语法树修改器使用例子 (五)

接着上一篇 gogocode AST 抽象语法树修改器使用例子 (四)

背景

由于项目中大量使用了 vue 的 options api,并且由不同的开发者维护,导致 options api 的顺序非常混乱。

具体请查看 #1841

解决方案

我们使用 gogocode 来转换下 options api 的排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
function transform(fileInfo, api, options) {
const $ = api.gogocode
const source = fileInfo.source
const ast = $(source, {
parseOptions: { language: 'vue', sourceType: 'module' },
})
const script = ast.find('<script></script>')
script
.replace('export default defineComponent({$$$})', (match) => {
match['$$$$'].sort((left, right) => {
const orders = propsOrder()
let leftName = left.key.name
let rightName = right.key.name
let leftIndex = orders.indexOf(leftName)
let rightIndex = orders.indexOf(rightName)

return leftIndex - rightIndex
})

let propsCode = match['$$$$'].map((prop) => $(prop).generate())

return `export default defineComponent({${propsCode.join(
','
)}})`
})
.generate()
// return your transformed code here
return ast.generate()
}

function propsOrder() {
// https://github.com/vuejs/eslint-plugin-vue/blob/124cc371645dbb56a80ddcbc8bf37af6efccd044/lib/rules/order-in-components.js#L14
return [
// Side Effects (triggers effects outside the component)
'el',

// Global Awareness (requires knowledge beyond the component)
'name',
'key', // for Nuxt
'parent',

// Component Type (changes the type of the component)
'functional',

// Template Modifiers (changes the way templates are compiled)
['delimiters', 'comments'],

// Template Dependencies (assets used in the template)
['components', 'directives', 'filters'],

// Composition (merges properties into the options)
'extends',
'mixins',
['provide', 'inject'], // for Vue.js 2.2.0+

// Page Options (component rendered as a router page)
'ROUTER_GUARDS', // for Vue Router
'layout', // for Nuxt
'middleware', // for Nuxt
'validate', // for Nuxt
'scrollToTop', // for Nuxt
'transition', // for Nuxt
'loading', // for Nuxt

// Interface (the interface to the component)
'inheritAttrs',
'model',
['props', 'propsData'],
'emits', // for Vue.js 3.x

// Note:
// The `setup` option is included in the "Composition" category,
// but the behavior of the `setup` option requires the definition of "Interface",
// so we prefer to put the `setup` option after the "Interface".
'setup', // for Vue 3.x

// Local State (local reactive properties)
'asyncData', // for Nuxt
'data',
'fetch', // for Nuxt
'head', // for Nuxt
'computed',

// Events (callbacks triggered by reactive events)
'watch',
'watchQuery', // for Nuxt
[
'beforeCreate',
'created',
'beforeMount',
'mounted',
'beforeUpdate',
'updated',
'activated',
'deactivated',
'beforeUnmount', // for Vue.js 3.x
'unmounted', // for Vue.js 3.x
'beforeDestroy',
'destroyed',
'renderTracked', // for Vue.js 3.x
'renderTriggered', // for Vue.js 3.x
'errorCaptured', // for Vue.js 2.5.0+
],

// Non-Reactive Properties (instance properties independent of the reactivity system)
'methods',

// Rendering (the declarative description of the component output)
['template', 'render'],
'renderError',
].flat()
}