From 9b9d6951ce2b28cde7c2c7268e492394aff132be Mon Sep 17 00:00:00 2001 From: RiESAEX <2597245950@qq.com> Date: Thu, 21 Mar 2024 17:06:29 +0800 Subject: [PATCH] feat: no-props-shadow --- docs/rules/no-props-shadow.md | 40 ++++++++++++++ lib/rules/no-props-shadow.js | 76 ++++++++++++++++++++++++++ tests/lib/rules/no-props-shadow.js | 87 ++++++++++++++++++++++++++++++ 3 files changed, 203 insertions(+) create mode 100644 docs/rules/no-props-shadow.md create mode 100644 lib/rules/no-props-shadow.js create mode 100644 tests/lib/rules/no-props-shadow.js diff --git a/docs/rules/no-props-shadow.md b/docs/rules/no-props-shadow.md new file mode 100644 index 000000000..911bfe9c1 --- /dev/null +++ b/docs/rules/no-props-shadow.md @@ -0,0 +1,40 @@ +--- +pageClass: rule-details +sidebarDepth: 0 +title: vue/no-props-shadow +description: disallow shadowing a prop +--- +# vue/no-props-shadow + +> disallow shadowing a prop + +- :exclamation: _**This rule has not been released yet.**_ + +## :book: Rule Details + +This rule disallow shadowing a prop + + + +```vue + +``` + + + +## :wrench: Options + +Nothing. diff --git a/lib/rules/no-props-shadow.js b/lib/rules/no-props-shadow.js new file mode 100644 index 000000000..be659a081 --- /dev/null +++ b/lib/rules/no-props-shadow.js @@ -0,0 +1,76 @@ +/** + * @author XWBX + * See LICENSE file in root directory for full license. + */ +'use strict' + +const utils = require('../utils') +// https://github.com/vuejs/core/blob/caeb8a68811a1b0f799632582289fcf169fb673c/packages/shared/src/globalsAllowList.ts +const GLOBALS_WHITE_LISTED = new Set( + ( + 'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' + + 'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' + + 'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error' + ).split(',') +) +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'disallow shadowing a prop', + categories: undefined, + url: 'https://eslint.vuejs.org/rules/no-props-shadow.html' + }, + fixable: null, + schema: [], + messages: { + shadowedProp: 'This binding will shadow `{{ key }}` prop in template.' + } + }, + /** @param {RuleContext} context */ + create(context) { + /** @type {Set} */ + let propSet = new Set() + return utils.defineScriptSetupVisitor(context, { + onDefinePropsEnter(_, props) { + propSet = new Set( + props + .map((p) => p.propName) + .filter( + /** + * @returns {propName is string} + */ + (propName) => + utils.isDef(propName) && !GLOBALS_WHITE_LISTED.has(propName) + ) + ) + }, + 'Program:exit': (program) => { + for (const node of program.body) { + if ( + node.type === 'ImportDeclaration' || + node.type === 'ClassDeclaration' || + node.type === 'FunctionDeclaration' || + node.type === 'VariableDeclaration' + ) { + const vars = context + .getSourceCode() + .scopeManager?.getDeclaredVariables?.(node) + if (vars) { + for (const variable of vars) { + const name = variable.name + if (propSet.has(name)) { + context.report({ + node, + messageId: 'shadowedProp', + data: { key: name } + }) + } + } + } + } + } + } + }) + } +} diff --git a/tests/lib/rules/no-props-shadow.js b/tests/lib/rules/no-props-shadow.js new file mode 100644 index 000000000..beaf446ed --- /dev/null +++ b/tests/lib/rules/no-props-shadow.js @@ -0,0 +1,87 @@ +/** + * @author XWBX + * See LICENSE file in root directory for full license. + */ +'use strict' + +const RuleTester = require('../../eslint-compat').RuleTester +const rule = require('../../../lib/rules/no-props-shadow') + +const tester = new RuleTester({ + languageOptions: { + parserOptions: { + parser: require.resolve('@typescript-eslint/parser') + }, + parser: require('vue-eslint-parser'), + ecmaVersion: 2020, + sourceType: 'module' + } +}) + +tester.run('no-props-shadow', rule, { + valid: [ + { + filename: 'test.vue', + code: ` + + ` + } + ], + invalid: [ + { + filename: 'import.vue', + code: ` + + `, + errors: [ + { + message: 'This binding will shadow `foo` prop in template.', + line: 3, + column: 7 + } + ] + }, + { + filename: 'var.vue', + code: ` + + `, + errors: [ + { + message: 'This binding will shadow `foo` prop in template.', + line: 5, + column: 7 + } + ] + }, + { + filename: 'func.vue', + code: ` + + `, + errors: [ + { + message: 'This binding will shadow `foo` prop in template.', + line: 4, + column: 7 + } + ] + } + ] +})