接着上一篇 gogocode AST 抽象语法树修改器使用例子 (四)
背景
由于项目中大量使用了 vue 的 options api,并且由不同的开发者维护,导致 options api 的顺序非常混乱。
具体请查看 #1841
解决方案
我们使用 gogocode 来转换下 options api 的排序
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()
}