diff --git a/CHANGELOG.md b/CHANGELOG.md index 47b4fabe41..4e9fc569dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel ## Unreleased +### Added +* add [`no-namespace`] rule ([#2640] @yacinehmito @ljharb) + +[#2640]: https://github.com/yannickcr/eslint-plugin-react/pull/2640 + ## [7.25.3] - 2021.09.19 ### Fixed @@ -3437,6 +3442,7 @@ If you're still not using React 15 you can keep the old behavior by setting the [`no-find-dom-node`]: docs/rules/no-find-dom-node.md [`no-is-mounted`]: docs/rules/no-is-mounted.md [`no-multi-comp`]: docs/rules/no-multi-comp.md +[`no-namespace`]: docs/rules/no-namespace.md [`no-redundant-should-component-update`]: docs/rules/no-redundant-should-component-update.md [`no-render-return-value`]: docs/rules/no-render-return-value.md [`no-set-state`]: docs/rules/no-set-state.md diff --git a/README.md b/README.md index 193920c819..6c5af3db27 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,7 @@ Enable the rules that you would like to use. | ✔ | | [react/no-find-dom-node](docs/rules/no-find-dom-node.md) | Prevent usage of findDOMNode | | ✔ | | [react/no-is-mounted](docs/rules/no-is-mounted.md) | Prevent usage of isMounted | | | | [react/no-multi-comp](docs/rules/no-multi-comp.md) | Prevent multiple component definition per file | +| | | [react/no-namespace](docs/rules/no-namespace.md) | Enforce that namespaces are not used in React elements | | | | [react/no-redundant-should-component-update](docs/rules/no-redundant-should-component-update.md) | Flag shouldComponentUpdate when extending PureComponent | | ✔ | | [react/no-render-return-value](docs/rules/no-render-return-value.md) | Prevent usage of the return value of React.render | | | | [react/no-set-state](docs/rules/no-set-state.md) | Prevent usage of setState | diff --git a/docs/rules/no-namespace.md b/docs/rules/no-namespace.md new file mode 100644 index 0000000000..7ba843e6cc --- /dev/null +++ b/docs/rules/no-namespace.md @@ -0,0 +1,29 @@ +# Enforce that namespaces are not used in React elements (react/no-namespace) + +Enforces the absence of a namespace in React elements, such as with `svg:circle`, as they are not supported in React. + +## Rule Details + +The following patterns are considered warnings: + +```jsx + +``` + +```jsx + +``` + +The following patterns are **not** considered warnings: + +```jsx + +``` + +```jsx + +``` + +## When not to use + +If you are not using React. diff --git a/index.js b/index.js index 15fa8f0465..198af7b37f 100644 --- a/index.js +++ b/index.js @@ -67,6 +67,7 @@ const allRules = { 'no-find-dom-node': require('./lib/rules/no-find-dom-node'), 'no-is-mounted': require('./lib/rules/no-is-mounted'), 'no-multi-comp': require('./lib/rules/no-multi-comp'), + 'no-namespace': require('./lib/rules/no-namespace'), 'no-set-state': require('./lib/rules/no-set-state'), 'no-string-refs': require('./lib/rules/no-string-refs'), 'no-redundant-should-component-update': require('./lib/rules/no-redundant-should-component-update'), diff --git a/lib/rules/no-namespace.js b/lib/rules/no-namespace.js new file mode 100644 index 0000000000..8694e589c8 --- /dev/null +++ b/lib/rules/no-namespace.js @@ -0,0 +1,49 @@ +/** + * @fileoverview Enforce that namespaces are not used in React elements + * @author Yacine Hmito + */ + +'use strict'; + +const elementType = require('jsx-ast-utils/elementType'); +const docsUrl = require('../util/docsUrl'); +const isCreateElement = require('../util/isCreateElement'); + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + meta: { + docs: { + description: 'Enforce that namespaces are not used in React elements', + category: 'Possible Errors', + recommended: false, + url: docsUrl('no-namespace') + }, + + schema: [{ + type: 'object', + additionalProperties: false + }] + }, + + create(context) { + return { + CallExpression(node) { + if (isCreateElement(node, context) && node.arguments.length > 0 && node.arguments[0].type === 'Literal') { + const name = node.arguments[0].value; + if (name.indexOf(':') === -1) return undefined; + const message = `React component ${name} must not be in a namespace as React does not support them`; + context.report({node, message}); + } + }, + JSXOpeningElement(node) { + const name = elementType(node); + if (name.indexOf(':') === -1) return undefined; + const message = `React component ${name} must not be in a namespace as React does not support them`; + context.report({node, message}); + } + }; + } +}; diff --git a/tests/lib/rules/no-namespace.js b/tests/lib/rules/no-namespace.js new file mode 100644 index 0000000000..b7c8c434b7 --- /dev/null +++ b/tests/lib/rules/no-namespace.js @@ -0,0 +1,128 @@ +/** + * @fileoverview Tests for jsx-no-namespace + * @author Yacine Hmito + */ + +'use strict'; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const RuleTester = require('eslint').RuleTester; +const rule = require('../../../lib/rules/no-namespace'); + +const parserOptions = { + ecmaVersion: 2018, + sourceType: 'module', + ecmaFeatures: { + jsx: true + } +}; + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({parserOptions}); +ruleTester.run('jsx-no-namespace', rule, { + valid: [{ + code: '' + }, { + code: 'React.createElement("testcomponent")' + }, { + code: '' + }, { + code: 'React.createElement("testComponent")' + }, { + code: '' + }, { + code: 'React.createElement("test_component")' + }, { + code: '' + }, { + code: 'React.createElement("TestComponent")' + }, { + code: '' + }, { + code: 'React.createElement("object.testcomponent")' + }, { + code: '' + }, { + code: 'React.createElement("object.testComponent")' + }, { + code: '' + }, { + code: 'React.createElement("object.test_component")' + }, { + code: '' + }, { + code: 'React.createElement("object.TestComponent")' + }, { + code: '' + }, { + code: 'React.createElement("Object.testcomponent")' + }, { + code: '' + }, { + code: 'React.createElement("Object.testComponent")' + }, { + code: '' + }, { + code: 'React.createElement("Object.test_component")' + }, { + code: '' + }, { + code: 'React.createElement("Object.TestComponent")' + }], + + invalid: [{ + code: '', + errors: [{message: 'React component ns:testcomponent must not be in a namespace as React does not support them'}] + }, { + code: 'React.createElement("ns:testcomponent")', + errors: [{message: 'React component ns:testcomponent must not be in a namespace as React does not support them'}] + }, { + code: '', + errors: [{message: 'React component ns:testComponent must not be in a namespace as React does not support them'}] + }, { + code: 'React.createElement("ns:testComponent")', + errors: [{message: 'React component ns:testComponent must not be in a namespace as React does not support them'}] + }, { + code: '', + errors: [{message: 'React component ns:test_component must not be in a namespace as React does not support them'}] + }, { + code: 'React.createElement("ns:test_component")', + errors: [{message: 'React component ns:test_component must not be in a namespace as React does not support them'}] + }, { + code: '', + errors: [{message: 'React component ns:TestComponent must not be in a namespace as React does not support them'}] + }, { + code: 'React.createElement("ns:TestComponent")', + errors: [{message: 'React component ns:TestComponent must not be in a namespace as React does not support them'}] + }, { + code: '', + errors: [{message: 'React component Ns:testcomponent must not be in a namespace as React does not support them'}] + }, { + code: 'React.createElement("Ns:testcomponent")', + errors: [{message: 'React component Ns:testcomponent must not be in a namespace as React does not support them'}] + }, { + code: '', + errors: [{message: 'React component Ns:testComponent must not be in a namespace as React does not support them'}] + }, { + code: 'React.createElement("Ns:testComponent")', + errors: [{message: 'React component Ns:testComponent must not be in a namespace as React does not support them'}] + }, { + code: '', + errors: [{message: 'React component Ns:test_component must not be in a namespace as React does not support them'}] + }, { + code: 'React.createElement("Ns:test_component")', + errors: [{message: 'React component Ns:test_component must not be in a namespace as React does not support them'}] + }, { + code: '', + errors: [{message: 'React component Ns:TestComponent must not be in a namespace as React does not support them'}] + }, { + code: 'React.createElement("Ns:TestComponent")', + errors: [{message: 'React component Ns:TestComponent must not be in a namespace as React does not support them'}] + }] +});