Skip to content

Commit

Permalink
Conditionally include link components defined in settings
Browse files Browse the repository at this point in the history
  • Loading branch information
burtek committed Jan 11, 2024
1 parent 15c3f18 commit b5674e9
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 43 deletions.
45 changes: 40 additions & 5 deletions docs/rules/jsx-no-script-url.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ This rule takes the `linkComponents` setting into account.

## Rule Options

This rule accepts array option (optional) and object option (optional).

### Array option (default `[]`)

```json
{
"react/jsx-no-script-url": [
Expand All @@ -47,14 +51,11 @@ This rule takes the `linkComponents` setting into account.

Allows you to indicate a specific list of properties used by a custom component to be checked.

NOTE: This rule now takes into account the `linkComponents` config in [global shared settings](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/README.md#configuration), which should be used as the sole source of truth for link components.
The rule still allows passing link components as rule option for backwards compatibility, but this option is deprecated. If specified, this option will be used together with global `linkComponents` config.

### name
#### name

Component name.

### props
#### props

List of properties that should be validated.

Expand All @@ -65,3 +66,37 @@ Examples of **incorrect** code for this rule, when configured with the above opt
<Foo href="javascript:void(0)"></Foo>
<Foo to="javascript:void(0)"></Foo>
```

### Object option

#### includeFromSettings (default `false`)

Indicates if the `linkComponents` config in [global shared settings](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/README.md#configuration) should also be taken into account. If enabled, components and properties defined in settings will be added to the list provided in first option (if provided):

```json
{
"react/jsx-no-script-url": [
"error",
[
{
"name": "Link",
"props": ["to"]
},
{
"name": "Foo",
"props": ["href", "to"]
}
],
{ "includeFromSettings": true }
]
}
```

If only global settings should be used for this rule, the array option can be omitted:

```jsonc
{
// same as ["error", [], { "includeFromSettings": true }]
"react/jsx-no-script-url": ["error", { "includeFromSettings": true }]
}
```
84 changes: 63 additions & 21 deletions lib/rules/jsx-no-script-url.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,34 +54,76 @@ module.exports = {

messages,

schema: [{
type: 'array',
uniqueItems: true,
items: {
type: 'object',
properties: {
name: {
type: 'string',
},
props: {
type: 'array',
items: {
type: 'string',
schema: {
anyOf: [
{
type: 'array',
items: [
{
type: 'array',
uniqueItems: true,
items: {
type: 'object',
properties: {
name: {
type: 'string',
},
props: {
type: 'array',
items: {
type: 'string',
uniqueItems: true,
},
},
},
required: ['name', 'props'],
additionalProperties: false,
},
},
},
{
type: 'object',
properties: {
includeFromSettings: {
type: 'boolean',
},
},
},
],
additionalItems: false,
},
required: ['name', 'props'],
additionalProperties: false,
},
}],
{
type: 'array',
items: [
{
type: 'object',
properties: {
includeFromSettings: {
type: 'boolean',
},
},
},
],
additionalItems: false,
},
],
},
},

create(context) {
const linkComponents = linkComponentsUtil.getLinkComponents(context);
if (context.options[0]) {
parseLegacyOption(linkComponents, context.options[0]);
const options = context.options.slice();
let legacyOptions = [];
let includeFromSettings = false;

if (Array.isArray(options[0])) {
legacyOptions = options.shift();
}
if (typeof options[0] === 'object') {
const objOption = options.shift();
includeFromSettings = objOption.includeFromSettings || includeFromSettings;
}

const linkComponents = linkComponentsUtil.getLinkComponents(includeFromSettings ? context : {});
parseLegacyOption(linkComponents, legacyOptions);

return {
JSXAttribute(node) {
Expand Down
56 changes: 39 additions & 17 deletions tests/lib/rules/jsx-no-script-url.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,22 @@ ruleTester.run('jsx-no-script-url', rule, {
{ code: '<a href={"javascript:"}></a>' },
{ code: '<Foo href="javascript:"></Foo>' },
{ code: '<a href />' },
{
code: '<Foo href="javascript:"></Foo>',
settings: {
linkComponents: [{ name: 'Foo', linkAttribute: ['to', 'href'] }],
},
},
{
code: '<Foo href="javascript:"></Foo>',
options: [[], { includeFromSettings: false }],
settings: {
linkComponents: [{ name: 'Foo', linkAttribute: ['to', 'href'] }],
},
},
]),
invalid: parsers.all([
// defaults
{
code: '<a href="javascript:"></a>',
errors: [{ messageId: 'noScriptURL' }],
Expand All @@ -52,6 +66,8 @@ ruleTester.run('jsx-no-script-url', rule, {
code: '<a href="j\n\n\na\rv\tascript:"></a>',
errors: [{ messageId: 'noScriptURL' }],
},

// with component passed by options
{
code: '<Foo to="javascript:"></Foo>',
errors: [{ messageId: 'noScriptURL' }],
Expand All @@ -66,22 +82,32 @@ ruleTester.run('jsx-no-script-url', rule, {
[{ name: 'Foo', props: ['to', 'href'] }],
],
},
{ // make sure it still uses defaults when passed options
code: '<a href="javascript:void(0)"></a>',
errors: [{ messageId: 'noScriptURL' }],
options: [
[{ name: 'Foo', props: ['to', 'href'] }],
],
},

// with components passed by settings
{
code: '<Foo to="javascript:"></Foo>',
errors: [{ messageId: 'noScriptURL' }],
options: [
[{ name: 'Bar', props: ['to', 'href'] }],
{ includeFromSettings: true },
],
settings: {
linkComponents: [
{ name: 'Foo', linkAttribute: 'to' },
],
linkComponents: [{ name: 'Foo', linkAttribute: 'to' }],
},
},
{
code: '<Foo href="javascript:"></Foo>',
errors: [{ messageId: 'noScriptURL' }],
options: [{ includeFromSettings: true }],
settings: {
linkComponents: [
{ name: 'Foo', linkAttribute: ['to', 'href'] },
],
linkComponents: [{ name: 'Foo', linkAttribute: ['to', 'href'] }],
},
},
{
Expand All @@ -96,11 +122,12 @@ ruleTester.run('jsx-no-script-url', rule, {
{ messageId: 'noScriptURL' },
],
options: [
[
{ name: 'Foo', props: ['to', 'href'] },
{ name: 'Bar', props: ['link'] },
],
[{ name: 'Bar', props: ['link'] }],
{ includeFromSettings: true },
],
settings: {
linkComponents: [{ name: 'Foo', linkAttribute: ['to', 'href'] }],
},
},
{
code: `
Expand All @@ -111,17 +138,12 @@ ruleTester.run('jsx-no-script-url', rule, {
`,
errors: [
{ messageId: 'noScriptURL' },
{ messageId: 'noScriptURL' },
],
options: [
[
{ name: 'Bar', props: ['link'] },
],
[{ name: 'Bar', props: ['link'] }],
],
settings: {
linkComponents: [
{ name: 'Foo', linkAttribute: ['to', 'href'] },
],
linkComponents: [{ name: 'Foo', linkAttribute: ['to', 'href'] }],
},
},
]),
Expand Down

0 comments on commit b5674e9

Please sign in to comment.