diff --git a/lib/rules/jsx-pascal-case.js b/lib/rules/jsx-pascal-case.js
index e6e1339cc2..343bcd3b55 100644
--- a/lib/rules/jsx-pascal-case.js
+++ b/lib/rules/jsx-pascal-case.js
@@ -54,22 +54,24 @@ module.exports = {
return {
JSXOpeningElement(node) {
+ const isCompatTag = jsxUtil.isDOMComponent(node);
+ if (isCompatTag) return undefined;
+
let name = elementType(node);
if (name.length === 1) return undefined;
- // Get namespace if the type is JSXNamespacedName or JSXMemberExpression
- if (name.indexOf(':') > -1) {
- name = name.substring(0, name.indexOf(':'));
- } else if (name.indexOf('.') > -1) {
- name = name.substring(0, name.indexOf('.'));
+ // Get JSXIdentifier if the type is JSXNamespacedName or JSXMemberExpression
+ if (name.lastIndexOf(':') > -1) {
+ name = name.substring(name.lastIndexOf(':') + 1);
+ } else if (name.lastIndexOf('.') > -1) {
+ name = name.substring(name.lastIndexOf('.') + 1);
}
const isPascalCase = PASCAL_CASE_REGEX.test(name);
- const isCompatTag = jsxUtil.isDOMComponent(node);
const isAllowedAllCaps = allowAllCaps && ALL_CAPS_TAG_REGEX.test(name);
const isIgnored = ignore.indexOf(name) !== -1;
- if (!isPascalCase && !isCompatTag && !isAllowedAllCaps && !isIgnored) {
+ if (!isPascalCase && !isAllowedAllCaps && !isIgnored) {
let message = `Imported JSX component ${name} must be in PascalCase`;
if (allowAllCaps) {
diff --git a/lib/util/jsx.js b/lib/util/jsx.js
index e3bcc23e3a..f41c3b42fe 100644
--- a/lib/util/jsx.js
+++ b/lib/util/jsx.js
@@ -6,23 +6,17 @@
const elementType = require('jsx-ast-utils/elementType');
-const COMPAT_TAG_REGEX = /^[a-z]|-/;
+// See https://github.com/babel/babel/blob/ce420ba51c68591e057696ef43e028f41c6e04cd/packages/babel-types/src/validators/react/isCompatTag.js
+// for why we only test for the first character
+const COMPAT_TAG_REGEX = /^[a-z]/;
/**
- * Checks if a node represents a DOM element.
+ * Checks if a node represents a DOM element according to React.
* @param {object} node - JSXOpeningElement to check.
* @returns {boolean} Whether or not the node corresponds to a DOM element.
*/
function isDOMComponent(node) {
- let name = elementType(node);
-
- // Get namespace if the type is JSXNamespacedName or JSXMemberExpression
- if (name.indexOf(':') > -1) {
- name = name.slice(0, name.indexOf(':'));
- } else if (name.indexOf('.') > -1) {
- name = name.slice(0, name.indexOf('.'));
- }
-
+ const name = elementType(node);
return COMPAT_TAG_REGEX.test(name);
}
diff --git a/tests/lib/rules/jsx-pascal-case.js b/tests/lib/rules/jsx-pascal-case.js
index 8428783818..af9d914d55 100644
--- a/tests/lib/rules/jsx-pascal-case.js
+++ b/tests/lib/rules/jsx-pascal-case.js
@@ -29,6 +29,10 @@ const parserOptions = {
const ruleTester = new RuleTester({parserOptions});
ruleTester.run('jsx-pascal-case', rule, {
valid: [{
+ // The rule must not warn on components that start with a lowercase
+ // because they are interpreted as HTML elements by React
+ code: ''
+ }, {
code: ''
}, {
code: ''
@@ -52,6 +56,8 @@ ruleTester.run('jsx-pascal-case', rule, {
code: ''
}, {
code: ''
+ }, {
+ code: ''
}, {
code: '',
parser: parsers.BABEL_ESLINT