From 4eb500c970f7f19f35d5335ed6186b3bdc8f8d6d Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Fri, 12 May 2023 11:19:06 +0900 Subject: [PATCH 1/2] Add support for new `defineEmits` type syntax in `vue/require-explicit-emits` rule --- lib/utils/ts-ast-utils.js | 45 +++++++++---- tests/lib/rules/require-explicit-emits.js | 66 +++++++++++++++++++ typings/eslint-plugin-vue/util-types/utils.ts | 12 +++- 3 files changed, 110 insertions(+), 13 deletions(-) diff --git a/lib/utils/ts-ast-utils.js b/lib/utils/ts-ast-utils.js index e7cc52420..330e6b985 100644 --- a/lib/utils/ts-ast-utils.js +++ b/lib/utils/ts-ast-utils.js @@ -10,6 +10,7 @@ const { findVariable } = require('@eslint-community/eslint-utils') /** * @typedef {import('../../typings/eslint-plugin-vue/util-types/utils').ComponentTypeProp} ComponentTypeProp * @typedef {import('../../typings/eslint-plugin-vue/util-types/utils').ComponentTypeEmit} ComponentTypeEmit + * @typedef {import('../../typings/eslint-plugin-vue/util-types/utils').ComponentUnknownEmit} ComponentUnknownEmit */ module.exports = { @@ -147,22 +148,42 @@ function* extractRuntimeProps(context, node) { /** * @see https://github.com/vuejs/vue-next/blob/348c3b01e56383ffa70b180d1376fdf4ac12e274/packages/compiler-sfc/src/compileScript.ts#L1632 * @param {TSTypeLiteral | TSInterfaceBody | TSFunctionType} node - * @returns {IterableIterator} + * @returns {IterableIterator} */ function* extractRuntimeEmits(node) { - if (node.type === 'TSTypeLiteral' || node.type === 'TSInterfaceBody') { - const members = node.type === 'TSTypeLiteral' ? node.members : node.body - for (const t of members) { - if (t.type === 'TSCallSignatureDeclaration') { - yield* extractEventNames( - t.params[0], - /** @type {TSCallSignatureDeclaration} */ (t) - ) + if (node.type === 'TSFunctionType') { + yield* extractEventNames(node.params[0], node) + return + } + const members = node.type === 'TSTypeLiteral' ? node.members : node.body + for (const member of members) { + if (member.type === 'TSCallSignatureDeclaration') { + yield* extractEventNames( + member.params[0], + /** @type {TSCallSignatureDeclaration} */ (member) + ) + } else if ( + member.type === 'TSPropertySignature' || + member.type === 'TSMethodSignature' + ) { + if (member.key.type !== 'Identifier' && member.key.type !== 'Literal') { + yield { + type: 'unknown', + node: member.key + } + continue + } + yield { + type: 'type', + key: /** @type {Identifier | Literal} */ (member.key), + emitName: + member.key.type === 'Identifier' + ? member.key.name + : `${member.key.value}`, + value: null, + node: /** @type {TSPropertySignature | TSMethodSignature} */ (member) } } - return - } else { - yield* extractEventNames(node.params[0], node) } } diff --git a/tests/lib/rules/require-explicit-emits.js b/tests/lib/rules/require-explicit-emits.js index 9a22c74a9..c7356bb04 100644 --- a/tests/lib/rules/require-explicit-emits.js +++ b/tests/lib/rules/require-explicit-emits.js @@ -593,6 +593,31 @@ tester.run('require-explicit-emits', rule, { `, options: [{ allowProps: true }] + }, + { + // new syntax in Vue 3.3 + filename: 'test.vue', + code: ` + + `, + parserOptions: { parser: require.resolve('@typescript-eslint/parser') } + }, + { + // new syntax in Vue 3.3 + filename: 'test.vue', + code: ` + + `, + parserOptions: { parser: require.resolve('@typescript-eslint/parser') } } ], invalid: [ @@ -1886,6 +1911,47 @@ emits: {'foo': null} ] } ] + }, + { + // new syntax in Vue 3.3 + filename: 'test.vue', + code: ` + + `, + parserOptions: { parser: require.resolve('@typescript-eslint/parser') }, + errors: [ + { + message: + 'The "bar" event has been triggered but not declared on `defineEmits`.', + line: 5, + suggestions: [] + } + ] + }, + { + // new syntax in Vue 3.3 + filename: 'test.vue', + code: ` + + `, + parserOptions: { parser: require.resolve('@typescript-eslint/parser') }, + errors: [ + { + message: + 'The "bar" event has been triggered but not declared on `defineEmits`.', + line: 6, + suggestions: [] + } + ] } ] }) diff --git a/typings/eslint-plugin-vue/util-types/utils.ts b/typings/eslint-plugin-vue/util-types/utils.ts index d998761be..ef76b6cdb 100644 --- a/typings/eslint-plugin-vue/util-types/utils.ts +++ b/typings/eslint-plugin-vue/util-types/utils.ts @@ -152,13 +152,23 @@ export type ComponentUnknownEmit = { node: Expression | SpreadElement | null } -export type ComponentTypeEmit = { +export type ComponentTypeEmitCallSignature = { type: 'type' key: TSLiteralType emitName: string value: null node: TSCallSignatureDeclaration | TSFunctionType } +export type ComponentTypeEmitPropertySignature = { + type: 'type' + key: Identifier | Literal + emitName: string + value: null + node: TSPropertySignature | TSMethodSignature +} +export type ComponentTypeEmit = + | ComponentTypeEmitCallSignature + | ComponentTypeEmitPropertySignature export type ComponentEmit = | ComponentArrayEmit From 2a535e2a01741b7b1a435722f7a26a88692ffc4e Mon Sep 17 00:00:00 2001 From: ota-meshi Date: Fri, 12 May 2023 11:38:32 +0900 Subject: [PATCH 2/2] fix --- tests/lib/rules/require-explicit-emits.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/lib/rules/require-explicit-emits.js b/tests/lib/rules/require-explicit-emits.js index c7356bb04..a5bc5114c 100644 --- a/tests/lib/rules/require-explicit-emits.js +++ b/tests/lib/rules/require-explicit-emits.js @@ -1927,8 +1927,7 @@ emits: {'foo': null} { message: 'The "bar" event has been triggered but not declared on `defineEmits`.', - line: 5, - suggestions: [] + line: 5 } ] }, @@ -1948,8 +1947,7 @@ emits: {'foo': null} { message: 'The "bar" event has been triggered but not declared on `defineEmits`.', - line: 6, - suggestions: [] + line: 6 } ] }