Skip to content

Commit

Permalink
[New] jsx-pascal-case: support allowNamespace option
Browse files Browse the repository at this point in the history
  • Loading branch information
Kev-Y-Huang authored and ljharb committed Feb 1, 2021
1 parent 91e21ac commit acf7d62
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 22 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
### Added
* [`jsx-no-target-blank`]: add fixer ([#2862][] @Nokel81)
* [`jsx-pascal-case`]: support minimatch `ignore` option ([#2906][] @bcherny)
* [`jsx-pascal-case`]: support `allowNamespace` option ([#2917][] @kev-y-huang)

### Fixed
* [`jsx-no-constructed-context-values`]: avoid a crash with `as X` TS code ([#2894][] @ljharb)
Expand All @@ -29,6 +30,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
[#2929]: https://github.com/yannickcr/eslint-plugin-react/pull/2929
[#2925]: https://github.com/yannickcr/eslint-plugin-react/pull/2925
[#2923]: https://github.com/yannickcr/eslint-plugin-react/pull/2923
[#2917]: https://github.com/yannickcr/eslint-plugin-react/pull/2917
[#2910]: https://github.com/yannickcr/eslint-plugin-react/pull/2910
[#2908]: https://github.com/yannickcr/eslint-plugin-react/pull/2908
[#2906]: https://github.com/yannickcr/eslint-plugin-react/pull/2906
Expand Down
12 changes: 11 additions & 1 deletion docs/rules/jsx-pascal-case.md
Expand Up @@ -40,12 +40,13 @@ Examples of **correct** code for this rule:

```js
...
"react/jsx-pascal-case": [<enabled>, { allowAllCaps: <allowAllCaps>, ignore: <ignore> }]
"react/jsx-pascal-case": [<enabled>, { allowAllCaps: <allowAllCaps>, allowNamespace: <allowNamespace>, ignore: <ignore> }]
...
```

* `enabled`: for enabling the rule. 0=off, 1=warn, 2=error. Defaults to 0.
* `allowAllCaps`: optional boolean set to `true` to allow components name in all caps (default to `false`).
* `allowNamespace`: optional boolean set to `true` to ignore namespaced components (default to `false`).
* `ignore`: optional string-array of component names to ignore during validation (supports [minimatch](https://github.com/isaacs/minimatch)-style globs).

### `allowAllCaps`
Expand All @@ -57,6 +58,15 @@ Examples of **correct** code for this rule, when `allowAllCaps` is `true`:
<TEST_COMPONENT />
```

### `allowNamespace`

Examples of **correct** code for this rule, when `allowNamespace` is `true`:

```jsx
<Allowed.div />
<TestComponent.p />
```

## When Not To Use It

If you are not using JSX.
55 changes: 34 additions & 21 deletions lib/rules/jsx-pascal-case.js
Expand Up @@ -60,6 +60,12 @@ function testAllCaps(name) {
return true;
}

function ignoreCheck(ignore, name) {
return ignore.some(
(entry) => name === entry || minimatch(name, entry, {noglobstar: true})
);
}

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
Expand All @@ -84,6 +90,9 @@ module.exports = {
allowAllCaps: {
type: 'boolean'
},
allowNamespace: {
type: 'boolean'
},
ignore: {
items: [
{
Expand All @@ -102,39 +111,43 @@ module.exports = {
create(context) {
const configuration = context.options[0] || {};
const allowAllCaps = configuration.allowAllCaps || false;
const allowNamespace = configuration.allowNamespace || false;
const ignore = configuration.ignore || [];

return {
JSXOpeningElement(node) {
const isCompatTag = jsxUtil.isDOMComponent(node);
if (isCompatTag) return undefined;

let name = elementType(node);
const name = elementType(node);
let checkNames = [name];
let index = 0;

// Get JSXIdentifier if the type is JSXNamespacedName or JSXMemberExpression
if (name.lastIndexOf(':') > -1) {
name = name.substring(name.lastIndexOf(':') + 1);
checkNames = name.split(':');
} else if (name.lastIndexOf('.') > -1) {
name = name.substring(name.lastIndexOf('.') + 1);
checkNames = name.split('.');
}

if (name.length === 1) return undefined;

const isPascalCase = testPascalCase(name);
const isAllowedAllCaps = allowAllCaps && testAllCaps(name);
const isIgnored = ignore.some(
(entry) => name === entry || minimatch(name, entry, {noglobstar: true})
);

if (!isPascalCase && !isAllowedAllCaps && !isIgnored) {
context.report({
node,
messageId: allowAllCaps ? 'usePascalOrSnakeCase' : 'usePascalCase',
data: {
name
}
});
}
do {
const splitName = checkNames[index];
if (splitName.length === 1) return undefined;
const isPascalCase = testPascalCase(splitName);
const isAllowedAllCaps = allowAllCaps && testAllCaps(splitName);
const isIgnored = ignoreCheck(ignore, splitName);

if (!isPascalCase && !isAllowedAllCaps && !isIgnored) {
context.report({
node,
messageId: allowAllCaps ? 'usePascalOrSnakeCase' : 'usePascalCase',
data: {
name: splitName
}
});
break;
}
index++;
} while (index < checkNames.length && !allowNamespace);
}
};
}
Expand Down
22 changes: 22 additions & 0 deletions tests/lib/rules/jsx-pascal-case.js
Expand Up @@ -90,6 +90,9 @@ ruleTester.run('jsx-pascal-case', rule, {
code: '<H1>Hello!</H1>'
}, {
code: '<Typography.P />'
}, {
code: '<Styled.h1 />',
options: [{allowNamespace: true}]
}],

invalid: [{
Expand Down Expand Up @@ -144,5 +147,24 @@ ruleTester.run('jsx-pascal-case', rule, {
messageId: 'usePascalCase',
data: {name: 'Foo_DEPRECATED'}
}]
}, {
code: '<Styled.h1 />',
errors: [{
messageId: 'usePascalCase',
data: {name: 'h1'}
}]
}, {
code: '<$Typography.P />',
errors: [{
messageId: 'usePascalCase',
data: {name: '$Typography'}
}]
}, {
code: '<STYLED.h1 />',
options: [{allowNamespace: true}],
errors: [{
messageId: 'usePascalCase',
data: {name: 'STYLED'}
}]
}]
});

0 comments on commit acf7d62

Please sign in to comment.