From 76149245d8d33bd935ff761261ee672705469b01 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Wed, 5 Mar 2025 09:24:35 +0100 Subject: [PATCH 01/20] Add vue-eslint-parser to Yarn install instructions (#2698) --- docs/user-guide/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user-guide/index.md b/docs/user-guide/index.md index fcd7ff45c..30432d511 100644 --- a/docs/user-guide/index.md +++ b/docs/user-guide/index.md @@ -11,7 +11,7 @@ npm install --save-dev eslint eslint-plugin-vue Via [yarn](https://yarnpkg.com/): ```bash -yarn add -D eslint eslint-plugin-vue globals +yarn add -D eslint eslint-plugin-vue vue-eslint-parser globals ``` ::: tip Requirements From 7bd1d9a1b4cc72d6a9078ee0f40384fbd68f3ef3 Mon Sep 17 00:00:00 2001 From: ntnyq Date: Wed, 5 Mar 2025 16:24:54 +0800 Subject: [PATCH 02/20] fix: sync `.eslintrc` configs name changes (#2700) --- lib/index.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/index.d.ts b/lib/index.d.ts index 19bbc8a9d..8cbff659f 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -9,9 +9,9 @@ declare const vue: { 'vue2-strongly-recommended': Linter.LegacyConfig 'vue2-recommended': Linter.LegacyConfig - 'vue3-essential': Linter.LegacyConfig - 'vue3-strongly-recommended': Linter.LegacyConfig - 'vue3-recommended': Linter.LegacyConfig + essential: Linter.LegacyConfig + 'strongly-recommended': Linter.LegacyConfig + recommended: Linter.LegacyConfig 'flat/base': Linter.FlatConfig[] From 9fab6bd6f646847d5c91727524773c0859410015 Mon Sep 17 00:00:00 2001 From: ntnyq Date: Wed, 5 Mar 2025 19:13:27 +0800 Subject: [PATCH 03/20] fix: fix walking program AST when multiple script blocks (#2703) --- lib/utils/index.js | 2 +- tests/lib/rules/prefer-use-template-ref.js | 88 ++++++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/lib/utils/index.js b/lib/utils/index.js index 8d0dfa80d..769362966 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -1380,7 +1380,7 @@ module.exports = { * @param {any[]} args */ function callVisitor(key, node, ...args) { - if (visitor[key] && inScriptSetup(node)) { + if (visitor[key] && (node.type === 'Program' || inScriptSetup(node))) { // @ts-expect-error visitor[key](node, ...args) } diff --git a/tests/lib/rules/prefer-use-template-ref.js b/tests/lib/rules/prefer-use-template-ref.js index 414c69830..afc6d6a11 100644 --- a/tests/lib/rules/prefer-use-template-ref.js +++ b/tests/lib/rules/prefer-use-template-ref.js @@ -263,6 +263,40 @@ tester.run('prefer-use-template-ref', rule, { }) ` + }, + { + filename: 'multiple-scripts-setup-first.vue', + code: ` + + + + + + ` + }, + { + filename: 'multiple-scripts-setup-last.vue', + code: ` + + + + + + ` } ], invalid: [ @@ -420,6 +454,60 @@ tester.run('prefer-use-template-ref', rule, { column: 28 } ] + }, + { + filename: 'multiple-scripts-setup-first.vue', + code: ` + + + + + + `, + errors: [ + { + messageId: 'preferUseTemplateRef', + data: { + name: 'ref' + }, + line: 8, + column: 20 + } + ] + }, + { + filename: 'multiple-scripts-setup-last.vue', + code: ` + + + + + + `, + errors: [ + { + messageId: 'preferUseTemplateRef', + data: { + name: 'ref' + }, + line: 12, + column: 20 + } + ] } ] }) From 87bb3ec5edceffa6eea1ea95b87bb6316d343504 Mon Sep 17 00:00:00 2001 From: chouchouji <70570907+chouchouji@users.noreply.github.com> Date: Wed, 5 Mar 2025 21:49:44 +0800 Subject: [PATCH 04/20] fix(no-export-in-script-setup): better report location (#2701) --- lib/rules/no-export-in-script-setup.js | 23 ++++-- tests/lib/rules/no-export-in-script-setup.js | 78 +++++++++++++++++--- 2 files changed, 87 insertions(+), 14 deletions(-) diff --git a/lib/rules/no-export-in-script-setup.js b/lib/rules/no-export-in-script-setup.js index 66286375a..98d41ae38 100644 --- a/lib/rules/no-export-in-script-setup.js +++ b/lib/rules/no-export-in-script-setup.js @@ -28,8 +28,11 @@ module.exports = { }, /** @param {RuleContext} context */ create(context) { - /** @param {ExportAllDeclaration | ExportDefaultDeclaration | ExportNamedDeclaration} node */ - function verify(node) { + /** + * @param {ExportAllDeclaration | ExportDefaultDeclaration | ExportNamedDeclaration} node + * @param {SourceLocation} loc + */ + function verify(node, loc) { const tsNode = /** @type {TSESTreeExportAllDeclaration | TSESTreeExportDefaultDeclaration | TSESTreeExportNamedDeclaration} */ ( node @@ -46,14 +49,24 @@ module.exports = { } context.report({ node, + loc, messageId: 'forbidden' }) } return utils.defineScriptSetupVisitor(context, { - ExportAllDeclaration: verify, - ExportDefaultDeclaration: verify, - ExportNamedDeclaration: verify + ExportAllDeclaration: (node) => verify(node, node.loc), + ExportDefaultDeclaration: (node) => verify(node, node.loc), + ExportNamedDeclaration: (node) => { + // export let foo = 'foo', export class Foo {}, export function foo() {} + if (node.declaration) { + verify(node, context.getSourceCode().getFirstToken(node).loc) + } + // export { foo }, export { foo } from 'bar' + else { + verify(node, node.loc) + } + } }) } } diff --git a/tests/lib/rules/no-export-in-script-setup.js b/tests/lib/rules/no-export-in-script-setup.js index 8703dc74a..bf24b8682 100644 --- a/tests/lib/rules/no-export-in-script-setup.js +++ b/tests/lib/rules/no-export-in-script-setup.js @@ -92,20 +92,62 @@ ruleTester.run('no-export-in-script-setup', rule, { export * from 'foo' export default {} export class A {} + export const test = '123' + export function foo() {} + const a = 1 + export { a } + export { fao } from 'bar' `, errors: [ { message: '` `, + ` + + `, + ` + + `, ` + `, + languageOptions: { + parser: require('vue-eslint-parser'), + ...languageOptions + } + }, + { + filename: 'test.vue', + code: ` + + `, + languageOptions: { + parser: require('vue-eslint-parser'), + ...languageOptions, + parserOptions: { parser: require.resolve('@typescript-eslint/parser') } + } } ], @@ -700,6 +725,26 @@ ruleTester.run('require-default-prop', rule, { line: 3 } ] + }, + { + // https://github.com/vuejs/eslint-plugin-vue/issues/2725 + filename: 'type-with-props-destructure.vue', + code: ` + + `, + languageOptions: { + parser: require('vue-eslint-parser'), + ...languageOptions, + parserOptions: { parser: require.resolve('@typescript-eslint/parser') } + }, + errors: [ + { + message: "Prop 'foo' requires default value to be set.", + line: 3 + } + ] } ] }) From 7dec48d730a7889154915e3a043c2dcfedd0cf65 Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Thu, 3 Apr 2025 15:10:58 +0800 Subject: [PATCH 15/20] fix(no-dupe-keys): detect props destructure rename (#2731) --- lib/rules/no-dupe-keys.js | 33 +++++++++++++++++++++++++++++++++ tests/lib/rules/no-dupe-keys.js | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/lib/rules/no-dupe-keys.js b/lib/rules/no-dupe-keys.js index 01b85d9f5..ecfa787cf 100644 --- a/lib/rules/no-dupe-keys.js +++ b/lib/rules/no-dupe-keys.js @@ -58,6 +58,33 @@ function isInsideInitializer(node, references) { ) } +/** + * Collects all renamed props from a pattern + * @param {Pattern | null} pattern - The destructuring pattern + * @returns {Set} - Set of prop names that have been renamed + */ +function collectRenamedProps(pattern) { + const renamedProps = new Set() + + if (!pattern || pattern.type !== 'ObjectPattern') { + return renamedProps + } + + for (const prop of pattern.properties) { + if (prop.type !== 'Property') continue + + if ( + prop.key.type === 'Identifier' && + prop.value.type === 'Identifier' && + prop.key.name !== prop.value.name + ) { + renamedProps.add(prop.key.name) + } + } + + return renamedProps +} + module.exports = { meta: { type: 'problem', @@ -115,9 +142,15 @@ module.exports = { node ] + const renamedProps = collectRenamedProps(propsNode) + for (const prop of props) { if (!prop.propName) continue + if (renamedProps.has(prop.propName)) { + continue + } + const variable = findVariable( utils.getScope(context, node), prop.propName diff --git a/tests/lib/rules/no-dupe-keys.js b/tests/lib/rules/no-dupe-keys.js index 124442ec2..2df95908c 100644 --- a/tests/lib/rules/no-dupe-keys.js +++ b/tests/lib/rules/no-dupe-keys.js @@ -466,7 +466,7 @@ ruleTester.run('no-dupe-keys', rule, { { filename: 'test.vue', code: ` - + `, @@ -475,7 +475,7 @@ ruleTester.run('no-dupe-keys', rule, { { filename: 'test.vue', code: ` - + `, @@ -500,6 +500,17 @@ ruleTester.run('no-dupe-keys', rule, { parser: require('vue-eslint-parser'), parserOptions: { parser: require.resolve('@typescript-eslint/parser') } } + }, + { + filename: 'test.vue', + code: ` + + `, + languageOptions: { parser: require('vue-eslint-parser') } } ], @@ -1105,6 +1116,24 @@ ruleTester.run('no-dupe-keys', rule, { line: 5 } ] + }, + { + filename: 'test.vue', + code: ` + + `, + languageOptions: { parser: require('vue-eslint-parser') }, + errors: [ + { + message: + "Duplicate key 'bar'. May cause name collision in script or template tag.", + line: 5 + } + ] } ] }) From 654c3cba946a34a94a938abf1811432ee4fa4078 Mon Sep 17 00:00:00 2001 From: yosuke ota Date: Tue, 29 Apr 2025 09:53:56 +0900 Subject: [PATCH 16/20] 10.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b9d2c00be..5eb6e8113 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-vue", - "version": "10.0.0", + "version": "10.0.1", "description": "Official ESLint plugin for Vue.js", "main": "lib/index.js", "types": "lib/index.d.ts", From c68cb1a49f6dcaede556490b391631aac4940cca Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Tue, 29 Apr 2025 09:08:31 +0800 Subject: [PATCH 17/20] feat(no-bare-strings-in-template): `allowlist` support regex (#2734) Co-authored-by: Flo Edelmann --- docs/rules/no-bare-strings-in-template.md | 6 +- lib/rules/no-bare-strings-in-template.js | 48 ++++++++++++--- .../lib/rules/no-bare-strings-in-template.js | 60 +++++++++++++++++++ 3 files changed, 102 insertions(+), 12 deletions(-) diff --git a/docs/rules/no-bare-strings-in-template.md b/docs/rules/no-bare-strings-in-template.md index df1fae123..23a23c116 100644 --- a/docs/rules/no-bare-strings-in-template.md +++ b/docs/rules/no-bare-strings-in-template.md @@ -12,7 +12,7 @@ since: v7.0.0 ## :book: Rule Details -This rule disallows the use of bare strings in ` ` + }, + { + filename: 'test.vue', + code: ` + + `, + options: [{ disallowComments: false }] + }, + { + filename: 'test.vue', + code: ` + + `, + options: [{ disallowComments: false }] + }, + { + filename: 'test.vue', + code: ` + + `, + options: [{ disallowComments: true }] + }, + { + filename: 'test.vue', + code: ` + + `, + options: [{ disallowComments: true }] } ], invalid: [ @@ -104,6 +164,132 @@ ruleTester.run('no-multiple-template-root', rule, { filename: 'test.vue', code: '', errors: ["The template root disallows '