diff --git a/transformations/__tests__/add-emit-declaration.spec.ts b/transformations/__tests__/add-emit-declaration.spec.ts new file mode 100644 index 0000000..c321897 --- /dev/null +++ b/transformations/__tests__/add-emit-declaration.spec.ts @@ -0,0 +1,81 @@ +import { defineInlineTest } from 'jscodeshift/src/testUtils' +const transform = require('../add-emit-declaration') + +defineInlineTest( + transform, + {}, + `export default { + props: ['text'], + methods: { + input: function() { + this.$emit('increment') + this.$emit('decrement') + } + } +}`, + `export default { + emits: ["increment", "decrement"], + props: ['text'], + + methods: { + input: function() { + this.$emit('increment') + this.$emit('decrement') + } + } +};`, + 'add emit declaration' +) + +defineInlineTest( + transform, + {}, + `export default { + emits: [], + props: ['text'], + methods: { + input: function() { + this.$emit('increment') + this.$emit('decrement') + } + } +}`, + `export default { + emits: ["increment", "decrement"], + props: ['text'], + methods: { + input: function() { + this.$emit('increment') + this.$emit('decrement') + } + } +}`, + 'add emit declaration(has emits property but empty)' +) + +defineInlineTest( + transform, + {}, + `export default { + emits: ['increment'], + props: ['text'], + methods: { + input: function() { + this.$emit('increment') + this.$emit('decrement') + } + } +} +`, + `export default { + emits: ['increment', "decrement"], + props: ['text'], + methods: { + input: function() { + this.$emit('increment') + this.$emit('decrement') + } + } +}`, + 'add emit declaration(has emits property and not empty)' +) diff --git a/transformations/add-emit-declaration.ts b/transformations/add-emit-declaration.ts new file mode 100644 index 0000000..d52f130 --- /dev/null +++ b/transformations/add-emit-declaration.ts @@ -0,0 +1,48 @@ +import wrap from '../src/wrapAstTransformation' +import type { ASTTransformation } from '../src/wrapAstTransformation' + +export const transformAST: ASTTransformation = ({ root, j }) => { +// find the export default + const defaultExportBody = root.find(j.ExportDefaultDeclaration) + +// find the CallExpression + const emitCalls = defaultExportBody.find(j.CallExpression, node => { + return node.callee.object?.type === 'ThisExpression' + && node.callee.property?.name === '$emit' + }) + + if (emitCalls.length) { + // find the $emit argument + const eventNames: string[] = [] + emitCalls.forEach(({ node }) => { + if (node.arguments[0]?.type === 'StringLiteral') { + eventNames.push(node.arguments[0].value) + } + }) + + // find the emit property + const emitsProperty = defaultExportBody.find(j.ObjectProperty, node => { + return node.key.name === 'emits' + && node.value.type === 'ArrayExpression' + }) + + const elements = emitsProperty.length ? emitsProperty.get(0).node.value.elements : [] + const emits = elements.map((r: { value: string }) => r.value) + const hasEmitsProperty = emitsProperty.length + + // push not declare event name into emits + eventNames.forEach(r => { + if (!emits.includes(r)) { + elements.push(j.stringLiteral(r)) + } + }) + + if(!hasEmitsProperty){ + // no emits property then create emits:[...] AST + defaultExportBody.get(0).node.declaration.properties.unshift(j.objectProperty(j.identifier('emits'),j.arrayExpression(elements))); + } + } +} + +export default wrap(transformAST) +export const parser = 'babylon' diff --git a/transformations/index.ts b/transformations/index.ts index 8ec4e18..61c4785 100644 --- a/transformations/index.ts +++ b/transformations/index.ts @@ -17,6 +17,7 @@ const transformationMap: { 'scoped-slots-to-slots': require('./scoped-slots-to-slots'), 'new-directive-api': require('./new-directive-api'), 'remove-vue-set-and-delete': require('./remove-vue-set-and-delete'), + 'add-emit-declaration': require('./add-emit-declaration'), // atomic ones 'remove-contextual-h-from-render': require('./remove-contextual-h-from-render'),