diff --git a/docs/rules/jsx-no-script-url.md b/docs/rules/jsx-no-script-url.md
index 53f9202ef4..f3e1247bcf 100644
--- a/docs/rules/jsx-no-script-url.md
+++ b/docs/rules/jsx-no-script-url.md
@@ -20,3 +20,38 @@ The following patterns are **not** considered warnings:
```
+
+## Rule Options
+```json
+{
+ "react/jsx-no-script-url": [
+ "error",
+ [
+ {
+ "name": "Link",
+ "props": ["to"]
+ },
+ {
+ "name": "Foo",
+ "props": ["href", "to"]
+ }
+ ]
+ ]
+}
+```
+
+Allows you to indicate a specific list of properties used by a custom component to be checked.
+
+### name
+Component name.
+
+### props
+List of properties that should be validated.
+
+The following patterns are considered warnings with the options listed above:
+
+```jsx
+
+
+
+```
diff --git a/lib/rules/jsx-no-script-url.js b/lib/rules/jsx-no-script-url.js
index 660672ca90..0bbce3d8cc 100644
--- a/lib/rules/jsx-no-script-url.js
+++ b/lib/rules/jsx-no-script-url.js
@@ -11,11 +11,6 @@ const docsUrl = require('../util/docsUrl');
// Rule Definition
// ------------------------------------------------------------------------------
-function isHref(attr) {
- return attr.name &&
- attr.name.name === 'href';
-}
-
// https://github.com/facebook/react/blob/d0ebde77f6d1232cefc0da184d731943d78e86f2/packages/react-dom/src/shared/sanitizeURL.js#L30
/* eslint-disable-next-line max-len, no-control-regex */
const isJavaScriptProtocol = /^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*:/i;
@@ -33,13 +28,59 @@ module.exports = {
recommended: false,
url: docsUrl('jsx-no-script-url')
},
- schema: []
+ schema: [{
+ type: 'array',
+ items: {
+ type: 'object',
+ properties: {
+ name: {
+ type: 'string'
+ },
+ props: {
+ type: 'array',
+ items: {
+ type: 'string',
+ uniqueItems: true
+ }
+ }
+ },
+ required: ['name', 'props'],
+ additionalProperties: false
+ }
+ }]
},
create(context) {
+ const configuration = context.options[0] || [];
+ const elements = configuration.map(i => i.name);
+
+ function shouldVerifyElement(node) {
+ const name = node.name && node.name.name;
+ return name === 'a' || elements.indexOf(name) !== -1;
+ }
+
+ function shouldVerifyProp(node) {
+ const name = node.name && node.name.name;
+ const parentName = node.parent.name && node.parent.name.name;
+
+ if (parentName === 'a' && name === 'href') {
+ return true;
+ }
+
+ if (elements.indexOf(parentName) === -1) {
+ return false;
+ }
+
+ const el = configuration.find(i => i.name === parentName);
+ const props = el && el.props || [];
+
+ return node.name && props.indexOf(name) !== -1;
+ }
+
return {
JSXAttribute(node) {
- if (node.parent.name.name === 'a' && isHref(node) && hasJavaScriptProtocol(node)) {
+ const parent = node.parent;
+ if (shouldVerifyElement(parent) && shouldVerifyProp(node) && hasJavaScriptProtocol(node)) {
context.report(node, 'A future version of React will block javascript: URLs as a security precaution. ' +
'Use event handlers instead if you can. If you need to generate unsafe HTML try using dangerouslySetInnerHTML instead.');
}
diff --git a/tests/lib/rules/jsx-no-script-url.js b/tests/lib/rules/jsx-no-script-url.js
index a6aeb6c650..edb800aa42 100644
--- a/tests/lib/rules/jsx-no-script-url.js
+++ b/tests/lib/rules/jsx-no-script-url.js
@@ -25,10 +25,9 @@ const parserOptions = {
// ------------------------------------------------------------------------------
const ruleTester = new RuleTester({parserOptions});
-const defaultErrors = [{
- message: 'A future version of React will block javascript: URLs as a security precaution. ' +
- 'Use event handlers instead if you can. If you need to generate unsafe HTML try using dangerouslySetInnerHTML instead.'
-}];
+const message = 'A future version of React will block javascript: URLs as a security precaution. ' +
+ 'Use event handlers instead if you can. If you need to generate unsafe HTML try using dangerouslySetInnerHTML instead.';
+const defaultErrors = [{message}];
ruleTester.run('jsx-no-script-url', rule, {
valid: [
@@ -49,5 +48,22 @@ ruleTester.run('jsx-no-script-url', rule, {
}, {
code: '',
errors: defaultErrors
+ }, {
+ code: '',
+ errors: defaultErrors,
+ options: [[{name: 'Foo', props: ['to', 'href']}]]
+ }, {
+ code: '',
+ errors: defaultErrors,
+ options: [[{name: 'Foo', props: ['to', 'href']}]]
+ }, {
+ code: `
+
+
+
+
+ `,
+ errors: [{message}, {message}],
+ options: [[{name: 'Foo', props: ['to', 'href']}, {name: 'Bar', props: ['link']}]]
}]
});