From 0b55cdee4e8d13c434f78d921a773a2b25f67480 Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Wed, 14 May 2025 14:22:30 +0900 Subject: [PATCH 1/8] chore: introduce changesets (#2740) --- .changeset/README.md | 8 ++++++++ .changeset/config.json | 15 +++++++++++++++ .github/workflows/Release.yml | 35 +++++++++++++++++++++++++++++++++++ package.json | 9 +++++++-- 4 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 .changeset/README.md create mode 100644 .changeset/config.json create mode 100644 .github/workflows/Release.yml diff --git a/.changeset/README.md b/.changeset/README.md new file mode 100644 index 000000000..e5b6d8d6a --- /dev/null +++ b/.changeset/README.md @@ -0,0 +1,8 @@ +# Changesets + +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works +with multi-package repos, or single-package repos to help you version and publish your code. You can +find the full documentation for it [in our repository](https://github.com/changesets/changesets) + +We have a quick list of common questions to get you started engaging with this project in +[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 000000000..43b72b358 --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://unpkg.com/@changesets/config/schema.json", + "changelog": [ + "@svitejs/changesets-changelog-github-compact", + { + "repo": "vuejs/eslint-plugin-vue" + } + ], + "commit": false, + "linked": [], + "access": "public", + "baseBranch": "master", + "bumpVersionsWithWorkspaceProtocolOnly": true, + "ignore": [] +} diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml new file mode 100644 index 000000000..260b73582 --- /dev/null +++ b/.github/workflows/Release.yml @@ -0,0 +1,35 @@ +name: Release + +on: + push: + branches: + - master + +permissions: {} + +jobs: + release: + # prevents this action from running on forks + if: github.repository == 'vuejs/eslint-plugin-vue' + permissions: + contents: write # to create release (changesets/action) + pull-requests: write # to create pull request (changesets/action) + name: Release + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + - name: Install Dependencies + run: npm install -f + + - name: Create Release Pull Request or Publish to npm + id: changesets + uses: changesets/action@v1 + with: + version: npm run changeset:version + publish: npm run changeset:publish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/package.json b/package.json index 7e44aeb84..ff0a4b00a 100644 --- a/package.json +++ b/package.json @@ -18,12 +18,15 @@ "lint:fix": "eslint . --fix && markdownlint \"**/*.md\" --fix", "tsc": "tsc", "preversion": "npm test && git add .", - "version": "env-cmd -e version npm run update && npm run lint -- --fix && git add .", + "version": "npm run generate:version && git add .", "update": "node ./tools/update.js", "update-resources": "node ./tools/update-resources.js", "docs:watch": "vitepress dev docs", "predocs:build": "npm run update", - "docs:build": "vitepress build docs" + "docs:build": "vitepress build docs", + "generate:version": "env-cmd -e version npm run update && npm run lint -- --fix", + "changeset:version": "changeset version && npm run generate:version && git add --all", + "changeset:publish": "changeset publish" }, "files": [ "lib" @@ -66,8 +69,10 @@ "xml-name-validator": "^4.0.0" }, "devDependencies": { + "@changesets/cli": "^2.29.2", "@ota-meshi/site-kit-eslint-editor-vue": "^0.2.4", "@stylistic/eslint-plugin": "^2.12.1", + "@svitejs/changesets-changelog-github-compact": "^1.2.0", "@types/eslint": "^8.56.2", "@types/natural-compare": "^1.4.3", "@types/node": "^14.18.63", From 87793a579d80c8127e1e272a7ab9e33126550a4f Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Wed, 14 May 2025 14:36:01 +0900 Subject: [PATCH 2/8] chore: fix ci error in eqeqeq (#2743) --- tests/lib/rules/eqeqeq.js | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/tests/lib/rules/eqeqeq.js b/tests/lib/rules/eqeqeq.js index afd458248..8089ebaaa 100644 --- a/tests/lib/rules/eqeqeq.js +++ b/tests/lib/rules/eqeqeq.js @@ -3,7 +3,8 @@ */ 'use strict' -const RuleTester = require('../../eslint-compat').RuleTester +const semver = require('semver') +const { RuleTester, ESLint } = require('../../eslint-compat') const rule = require('../../../lib/rules/eqeqeq') const tester = new RuleTester({ @@ -24,7 +25,19 @@ tester.run('eqeqeq', rule, { invalid: [ { code: '', - errors: ["Expected '===' and instead saw '=='."] + errors: [ + { + message: "Expected '===' and instead saw '=='.", + suggestions: semver.gte(ESLint.version, '9.26.0') + ? [ + { + desc: "Use '===' instead of '=='.", + output: `` + } + ] + : null + } + ] }, // CSS vars injection { @@ -34,7 +47,24 @@ tester.run('eqeqeq', rule, { color: v-bind(a == 1 ? 'red' : 'blue') } `, - errors: ["Expected '===' and instead saw '=='."] + errors: [ + { + message: "Expected '===' and instead saw '=='.", + suggestions: semver.gte(ESLint.version, '9.26.0') + ? [ + { + desc: "Use '===' instead of '=='.", + output: ` + ` + } + ] + : null + } + ] } ] }) From 31b30c4b08c829d9e431fb916feb6aa5fc16c9ef Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 18 May 2025 13:59:17 +0900 Subject: [PATCH 3/8] Updates resources (#2747) Co-authored-by: ota-meshi <16508807+ota-meshi@users.noreply.github.com> Co-authored-by: Yosuke Ota --- .changeset/grumpy-humans-tickle.md | 5 +++++ lib/utils/vue3-export-names.json | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 .changeset/grumpy-humans-tickle.md diff --git a/.changeset/grumpy-humans-tickle.md b/.changeset/grumpy-humans-tickle.md new file mode 100644 index 000000000..e5f3a14a8 --- /dev/null +++ b/.changeset/grumpy-humans-tickle.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-vue": patch +--- + +Updates resources diff --git a/lib/utils/vue3-export-names.json b/lib/utils/vue3-export-names.json index 349779da1..395090026 100644 --- a/lib/utils/vue3-export-names.json +++ b/lib/utils/vue3-export-names.json @@ -235,6 +235,7 @@ "AsyncComponentOptions", "defineAsyncComponent", "useModel", + "TemplateRef", "useTemplateRef", "useId", "h", @@ -263,8 +264,8 @@ "devtools", "setDevtoolsHook", "DeprecationTypes", - "WatchOptionsBase", "createElementVNode", + "WatchOptionsBase", "TransitionProps", "Transition", "TransitionGroupProps", From cf261fbf554368791f7eb4fc4aae30c36991e45a Mon Sep 17 00:00:00 2001 From: Shayan Zamani Date: Fri, 6 Jun 2025 06:20:09 +0330 Subject: [PATCH 4/8] feat(no-restricted-html-elements): support array of elements (#2750) --- .changeset/crazy-impalas-pick.md | 5 ++++ docs/rules/no-restricted-html-elements.md | 18 ++++++------- lib/rules/no-restricted-html-elements.js | 16 ++++++++--- .../lib/rules/no-restricted-html-elements.js | 27 +++++++++++++++++++ 4 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 .changeset/crazy-impalas-pick.md diff --git a/.changeset/crazy-impalas-pick.md b/.changeset/crazy-impalas-pick.md new file mode 100644 index 000000000..834a6ec8f --- /dev/null +++ b/.changeset/crazy-impalas-pick.md @@ -0,0 +1,5 @@ +--- +'eslint-plugin-vue': minor +--- + +[vue/no-restricted-html-elements](https://eslint.vuejs.org/rules/no-restricted-html-elements.html) now accepts multiple elements in each entry. diff --git a/docs/rules/no-restricted-html-elements.md b/docs/rules/no-restricted-html-elements.md index 2a6d6c997..fef08aeb2 100644 --- a/docs/rules/no-restricted-html-elements.md +++ b/docs/rules/no-restricted-html-elements.md @@ -37,16 +37,16 @@ This rule takes a list of strings, where each string is an HTML element name to ```json { - "vue/no-restricted-html-elements": ["error", "button", "marquee"] + "vue/no-restricted-html-elements": ["error", "a", "marquee"] } ``` - + ```vue ``` @@ -60,8 +60,8 @@ Alternatively, the rule also accepts objects. "vue/no-restricted-html-elements": [ "error", { - "element": "button", - "message": "Prefer use of our custom component" + "element": ["a", "RouterLink"], + "message": "Prefer the use of component" }, { "element": "marquee", @@ -73,18 +73,18 @@ Alternatively, the rule also accepts objects. The following properties can be specified for the object. -- `element` ... Specify the html element. +- `element` ... Specify the HTML element or an array of HTML elements. - `message` ... Specify an optional custom message. -### `{ "element": "marquee" }, { "element": "button" }` +### `{ "element": "marquee" }, { "element": "a" }` - + ```vue ``` diff --git a/lib/rules/no-restricted-html-elements.js b/lib/rules/no-restricted-html-elements.js index e906d86f2..8d5f3c300 100644 --- a/lib/rules/no-restricted-html-elements.js +++ b/lib/rules/no-restricted-html-elements.js @@ -23,7 +23,12 @@ module.exports = { { type: 'object', properties: { - element: { type: 'string' }, + element: { + oneOf: [ + { type: 'string' }, + { type: 'array', items: { type: 'string' } } + ] + }, message: { type: 'string', minLength: 1 } }, required: ['element'], @@ -55,9 +60,12 @@ module.exports = { } for (const option of context.options) { - const element = option.element || option + const restrictedItem = option.element || option + const elementsToRestrict = Array.isArray(restrictedItem) + ? restrictedItem + : [restrictedItem] - if (element === node.rawName) { + if (elementsToRestrict.includes(node.rawName)) { context.report({ messageId: option.message ? 'customMessage' : 'forbiddenElement', data: { @@ -66,6 +74,8 @@ module.exports = { }, node: node.startTag }) + + return } } } diff --git a/tests/lib/rules/no-restricted-html-elements.js b/tests/lib/rules/no-restricted-html-elements.js index c3e3e9eeb..6180b046b 100644 --- a/tests/lib/rules/no-restricted-html-elements.js +++ b/tests/lib/rules/no-restricted-html-elements.js @@ -31,6 +31,11 @@ tester.run('no-restricted-html-elements', rule, { filename: 'test.vue', code: '', options: ['button'] + }, + { + filename: 'test.vue', + code: '', + options: [{ element: ['div', 'span'] }] } ], invalid: [ @@ -69,6 +74,28 @@ tester.run('no-restricted-html-elements', rule, { column: 11 } ] + }, + { + filename: 'test.vue', + code: '', + options: [ + { + element: ['a', 'RouterLink'], + message: 'Prefer the use of component' + } + ], + errors: [ + { + message: 'Prefer the use of component', + line: 1, + column: 11 + }, + { + message: 'Prefer the use of component', + line: 1, + column: 18 + } + ] } ] }) From 2a4336b1f9365b30045304fb5c966db865fba870 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 6 Jun 2025 12:07:30 +0900 Subject: [PATCH 5/8] Version Packages (#2748) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changeset/crazy-impalas-pick.md | 5 ----- .changeset/grumpy-humans-tickle.md | 5 ----- CHANGELOG.md | 11 +++++++++++ package.json | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) delete mode 100644 .changeset/crazy-impalas-pick.md delete mode 100644 .changeset/grumpy-humans-tickle.md create mode 100644 CHANGELOG.md diff --git a/.changeset/crazy-impalas-pick.md b/.changeset/crazy-impalas-pick.md deleted file mode 100644 index 834a6ec8f..000000000 --- a/.changeset/crazy-impalas-pick.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'eslint-plugin-vue': minor ---- - -[vue/no-restricted-html-elements](https://eslint.vuejs.org/rules/no-restricted-html-elements.html) now accepts multiple elements in each entry. diff --git a/.changeset/grumpy-humans-tickle.md b/.changeset/grumpy-humans-tickle.md deleted file mode 100644 index e5f3a14a8..000000000 --- a/.changeset/grumpy-humans-tickle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"eslint-plugin-vue": patch ---- - -Updates resources diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..b21ab6f6f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +# eslint-plugin-vue + +## 10.2.0 + +### Minor Changes + +- [vue/no-restricted-html-elements](https://eslint.vuejs.org/rules/no-restricted-html-elements.html) now accepts multiple elements in each entry. ([#2750](https://github.com/vuejs/eslint-plugin-vue/pull/2750)) + +### Patch Changes + +- Updates resources ([#2747](https://github.com/vuejs/eslint-plugin-vue/pull/2747)) diff --git a/package.json b/package.json index ff0a4b00a..da1053c00 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-vue", - "version": "10.1.0", + "version": "10.2.0", "description": "Official ESLint plugin for Vue.js", "main": "lib/index.js", "types": "lib/index.d.ts", From aeef72c8d2d0dec637e33e5df8fa6178bae89d74 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 8 Jun 2025 11:36:58 +0900 Subject: [PATCH 6/8] Updates resources (#2752) Co-authored-by: ota-meshi <16508807+ota-meshi@users.noreply.github.com> Co-authored-by: Yosuke Ota --- .changeset/smooth-jokes-eat.md | 5 +++++ lib/utils/svg-elements.json | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 .changeset/smooth-jokes-eat.md diff --git a/.changeset/smooth-jokes-eat.md b/.changeset/smooth-jokes-eat.md new file mode 100644 index 000000000..e5f3a14a8 --- /dev/null +++ b/.changeset/smooth-jokes-eat.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-vue": patch +--- + +Updates resources diff --git a/lib/utils/svg-elements.json b/lib/utils/svg-elements.json index eedbf0d07..f214aad24 100644 --- a/lib/utils/svg-elements.json +++ b/lib/utils/svg-elements.json @@ -7,7 +7,6 @@ "clipPath", "defs", "desc", - "discard", "ellipse", "feBlend", "feColorMatrix", From 66dab39a878b77a1884633b78bcaec6d3a5c3820 Mon Sep 17 00:00:00 2001 From: yosuke ota Date: Sun, 8 Jun 2025 14:24:34 +0900 Subject: [PATCH 7/8] chore: ignore CHANGELOG.md from markdownlint --- .markdownlintignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.markdownlintignore b/.markdownlintignore index 3c3629e64..e7becf85b 100644 --- a/.markdownlintignore +++ b/.markdownlintignore @@ -1 +1,2 @@ node_modules +CHANGELOG.md From ca973010b511755488eeac2851ffd6597f23ccb2 Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Tue, 10 Jun 2025 20:41:24 +0800 Subject: [PATCH 8/8] feat(no-restricted-html-elements): support all element types (#2755) --- .changeset/true-oranges-heal.md | 5 ++ docs/rules/index.md | 2 +- docs/rules/no-restricted-html-elements.md | 10 +-- lib/rules/no-restricted-html-elements.js | 10 ++- .../lib/rules/no-restricted-html-elements.js | 73 ++++++++++++++++++- 5 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 .changeset/true-oranges-heal.md diff --git a/.changeset/true-oranges-heal.md b/.changeset/true-oranges-heal.md new file mode 100644 index 000000000..eba8b9a99 --- /dev/null +++ b/.changeset/true-oranges-heal.md @@ -0,0 +1,5 @@ +--- +'eslint-plugin-vue': patch +--- + +[vue/no-restricted-html-elements](https://eslint.vuejs.org/rules/no-restricted-html-elements.html) now also checks SVG and MathML elements. diff --git a/docs/rules/index.md b/docs/rules/index.md index 7828b58bb..149f877ad 100644 --- a/docs/rules/index.md +++ b/docs/rules/index.md @@ -245,7 +245,7 @@ For example: | [vue/no-restricted-component-names] | disallow specific component names | :bulb: | :hammer: | | [vue/no-restricted-component-options] | disallow specific component option | | :hammer: | | [vue/no-restricted-custom-event] | disallow specific custom event | :bulb: | :hammer: | -| [vue/no-restricted-html-elements] | disallow specific HTML elements | | :hammer: | +| [vue/no-restricted-html-elements] | disallow specific elements | | :hammer: | | [vue/no-restricted-props] | disallow specific props | :bulb: | :hammer: | | [vue/no-restricted-static-attribute] | disallow specific attribute | | :hammer: | | [vue/no-restricted-v-bind] | disallow specific argument in `v-bind` | | :hammer: | diff --git a/docs/rules/no-restricted-html-elements.md b/docs/rules/no-restricted-html-elements.md index fef08aeb2..9adc7a6ab 100644 --- a/docs/rules/no-restricted-html-elements.md +++ b/docs/rules/no-restricted-html-elements.md @@ -2,17 +2,17 @@ pageClass: rule-details sidebarDepth: 0 title: vue/no-restricted-html-elements -description: disallow specific HTML elements +description: disallow specific elements since: v8.6.0 --- # vue/no-restricted-html-elements -> disallow specific HTML elements +> disallow specific elements ## :book: Rule Details -This rule allows you to specify HTML elements that you don't want to use in your application. +This rule allows you to specify HTML, SVG, and MathML elements that you don't want to use in your application. @@ -33,7 +33,7 @@ This rule allows you to specify HTML elements that you don't want to use in your ## :wrench: Options -This rule takes a list of strings, where each string is an HTML element name to be restricted: +This rule takes a list of strings, where each string is an element name to be restricted: ```json { @@ -73,7 +73,7 @@ Alternatively, the rule also accepts objects. The following properties can be specified for the object. -- `element` ... Specify the HTML element or an array of HTML elements. +- `element` ... Specify the element name or an array of element names. - `message` ... Specify an optional custom message. ### `{ "element": "marquee" }, { "element": "a" }` diff --git a/lib/rules/no-restricted-html-elements.js b/lib/rules/no-restricted-html-elements.js index 8d5f3c300..ab52abde3 100644 --- a/lib/rules/no-restricted-html-elements.js +++ b/lib/rules/no-restricted-html-elements.js @@ -10,7 +10,7 @@ module.exports = { meta: { type: 'suggestion', docs: { - description: 'disallow specific HTML elements', + description: 'disallow specific elements', categories: undefined, url: 'https://eslint.vuejs.org/rules/no-restricted-html-elements.html' }, @@ -40,7 +40,7 @@ module.exports = { minItems: 0 }, messages: { - forbiddenElement: 'Unexpected use of forbidden HTML element {{name}}.', + forbiddenElement: 'Unexpected use of forbidden element {{name}}.', // eslint-disable-next-line eslint-plugin/report-message-format customMessage: '{{message}}' } @@ -55,7 +55,11 @@ module.exports = { * @param {VElement} node */ VElement(node) { - if (!utils.isHtmlElementNode(node)) { + if ( + !utils.isHtmlElementNode(node) && + !utils.isSvgElementNode(node) && + !utils.isMathElementNode(node) + ) { return } diff --git a/tests/lib/rules/no-restricted-html-elements.js b/tests/lib/rules/no-restricted-html-elements.js index 6180b046b..f89f58a11 100644 --- a/tests/lib/rules/no-restricted-html-elements.js +++ b/tests/lib/rules/no-restricted-html-elements.js @@ -36,6 +36,18 @@ tester.run('no-restricted-html-elements', rule, { filename: 'test.vue', code: '', options: [{ element: ['div', 'span'] }] + }, + // SVG + { + filename: 'test.vue', + code: '', + options: ['circle'] + }, + // Math + { + filename: 'test.vue', + code: '', + options: ['mi'] } ], invalid: [ @@ -45,7 +57,7 @@ tester.run('no-restricted-html-elements', rule, { options: ['button'], errors: [ { - message: 'Unexpected use of forbidden HTML element button.', + message: 'Unexpected use of forbidden element button.', line: 1, column: 16 } @@ -57,7 +69,7 @@ tester.run('no-restricted-html-elements', rule, { options: ['div'], errors: [ { - message: 'Unexpected use of forbidden HTML element div.', + message: 'Unexpected use of forbidden element div.', line: 1, column: 11 } @@ -96,6 +108,63 @@ tester.run('no-restricted-html-elements', rule, { column: 18 } ] + }, + // SVG + { + filename: 'test.vue', + code: '', + options: ['circle'], + errors: [ + { + message: 'Unexpected use of forbidden element circle.', + line: 1, + column: 16 + } + ] + }, + { + filename: 'test.vue', + code: '', + options: [ + { element: ['rect', 'path'], message: 'Use simplified shapes instead' } + ], + errors: [ + { + message: 'Use simplified shapes instead', + line: 1, + column: 16 + }, + { + message: 'Use simplified shapes instead', + line: 1, + column: 54 + } + ] + }, + // Math + { + filename: 'test.vue', + code: '', + options: ['mfrac'], + errors: [ + { + message: 'Unexpected use of forbidden element mfrac.', + line: 1, + column: 17 + } + ] + }, + { + filename: 'test.vue', + code: '', + options: [{ element: 'mo', message: 'Avoid using operators directly' }], + errors: [ + { + message: 'Avoid using operators directly', + line: 1, + column: 27 + } + ] } ] })