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
+ }
+ ]
+ }
+ ]
+})