diff --git a/CHANGELOG.md b/CHANGELOG.md index 4aad7555d7..a418675738 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange * [`no-unknown-property`]: do not check `fbs` elements ([#3494][] @brianogilvie) * [`jsx-newline`]: No newline between comments and jsx elements ([#3493][] @justmejulian) * [`jsx-no-leaked-render`]: Don't report errors on empty strings if React >= v18 ([#3488][] @himanshu007-creator) +* [`no-invalid-html-attribute`]: convert autofix to suggestion ([#3474][] @himanshu007-creator @ljharb) ### Changed * [Docs] [`jsx-no-leaked-render`]: Remove mentions of empty strings for React 18 ([#3468][] @karlhorky) @@ -24,6 +25,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange [#3494]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3494 [#3493]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3493 [#3488]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3488 +[#3474]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3474 [#3471]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3471 [#3468]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3468 [#3461]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3461 diff --git a/README.md b/README.md index ccdcb2bc0d..9bb7d2c9e8 100644 --- a/README.md +++ b/README.md @@ -352,7 +352,7 @@ module.exports = [ | [no-did-update-set-state](docs/rules/no-did-update-set-state.md) | Disallow usage of setState in componentDidUpdate | | | | | | [no-direct-mutation-state](docs/rules/no-direct-mutation-state.md) | Disallow direct mutation of this.state | πŸ’Ό | | | | | [no-find-dom-node](docs/rules/no-find-dom-node.md) | Disallow usage of findDOMNode | πŸ’Ό | | | | -| [no-invalid-html-attribute](docs/rules/no-invalid-html-attribute.md) | Disallow usage of invalid attributes | | πŸ”§ | | | +| [no-invalid-html-attribute](docs/rules/no-invalid-html-attribute.md) | Disallow usage of invalid attributes | | | πŸ’‘ | | | [no-is-mounted](docs/rules/no-is-mounted.md) | Disallow usage of isMounted | πŸ’Ό | | | | | [no-multi-comp](docs/rules/no-multi-comp.md) | Disallow multiple component definition per file | | | | | | [no-namespace](docs/rules/no-namespace.md) | Enforce that namespaces are not used in React elements | | | | | diff --git a/docs/rules/no-invalid-html-attribute.md b/docs/rules/no-invalid-html-attribute.md index 12614ff900..d749ead037 100644 --- a/docs/rules/no-invalid-html-attribute.md +++ b/docs/rules/no-invalid-html-attribute.md @@ -1,6 +1,6 @@ # Disallow usage of invalid attributes (`react/no-invalid-html-attribute`) -πŸ”§ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). +πŸ’‘ This rule is manually fixable by [editor suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions). diff --git a/lib/rules/hook-use-state.js b/lib/rules/hook-use-state.js index ba0785495c..a9deed4fd6 100644 --- a/lib/rules/hook-use-state.js +++ b/lib/rules/hook-use-state.js @@ -114,16 +114,12 @@ module.exports = { getMessageData('suggestPair', messages.suggestPair), { fix(fixer) { - if (expectedSetterVariableNames.length === 0) { - return; + if (expectedSetterVariableNames.length > 0) { + return fixer.replaceTextRange( + node.parent.id.range, + `[${valueVariableName}, ${expectedSetterVariableNames[0]}]` + ); } - - const fix = fixer.replaceTextRange( - node.parent.id.range, - `[${valueVariableName}, ${expectedSetterVariableNames[0]}]` - ); - - return fix; }, } ), diff --git a/lib/rules/no-invalid-html-attribute.js b/lib/rules/no-invalid-html-attribute.js index 9ba7bfa163..997afc2c81 100644 --- a/lib/rules/no-invalid-html-attribute.js +++ b/lib/rules/no-invalid-html-attribute.js @@ -8,6 +8,7 @@ const matchAll = require('string.prototype.matchall'); const docsUrl = require('../util/docsUrl'); const report = require('../util/report'); +const getMessageData = require('../util/message'); // ------------------------------------------------------------------------------ // Rule Definition @@ -232,6 +233,11 @@ const messages = { onlyMeaningfulFor: 'The ”{{attributeName}}β€œ attribute only has meaning on the tags: {{tagNames}}', onlyStrings: 'β€œ{{attributeName}}” attribute only supports strings.', spaceDelimited: '”{{attributeName}}β€œ attribute values should be space delimited.', + suggestRemoveDefault: '"remove {{attributeName}}"', + suggestRemoveEmpty: '"remove empty attribute {{attributeName}}"', + suggestRemoveInvalid: 'β€œremove invalid attribute {{reportingValue}}”', + suggestRemoveWhitespaces: 'remove whitespaces in β€œ{{reportingValue}}”', + suggestRemoveNonString: 'remove non-string value in β€œ{{reportingValue}}”', }; function splitIntoRangedParts(node, regex) { @@ -254,9 +260,12 @@ function checkLiteralValueNode(context, attributeName, node, parentNode, parentN report(context, messages.onlyStrings, 'onlyStrings', { node, data: { attributeName }, - fix(fixer) { - return fixer.remove(parentNode); - }, + suggest: [ + Object.assign( + getMessageData('suggestRemoveNonString', messages.suggestRemoveNonString), + { fix(fixer) { return fixer.remove(parentNode); } } + ), + ], }); return; } @@ -265,9 +274,12 @@ function checkLiteralValueNode(context, attributeName, node, parentNode, parentN report(context, messages.noEmpty, 'noEmpty', { node, data: { attributeName }, - fix(fixer) { - return fixer.remove(parentNode); - }, + suggest: [ + Object.assign( + getMessageData('suggestRemoveEmpty', messages.suggestRemoveEmpty), + { fix(fixer) { return fixer.remove(node.parent); } } + ), + ], }); return; } @@ -276,16 +288,23 @@ function checkLiteralValueNode(context, attributeName, node, parentNode, parentN for (const singlePart of singleAttributeParts) { const allowedTags = VALID_VALUES.get(attributeName).get(singlePart.value); const reportingValue = singlePart.reportingValue; + + const suggest = [ + Object.assign( + getMessageData('suggestRemoveInvalid', messages.suggestRemoveInvalid), + { fix(fixer) { return fixer.removeRange(singlePart.range); } } + ), + ]; + if (!allowedTags) { + const data = { + attributeName, + reportingValue, + }; report(context, messages.neverValid, 'neverValid', { node, - data: { - attributeName, - reportingValue, - }, - fix(fixer) { - return fixer.removeRange(singlePart.range); - }, + data, + suggest, }); } else if (!allowedTags.has(parentNodeName)) { report(context, messages.notValidFor, 'notValidFor', { @@ -295,9 +314,7 @@ function checkLiteralValueNode(context, attributeName, node, parentNode, parentN reportingValue, elementName: parentNodeName, }, - fix(fixer) { - return fixer.removeRange(singlePart.range); - }, + suggest, }); } } @@ -324,6 +341,7 @@ function checkLiteralValueNode(context, attributeName, node, parentNode, parentN secondValue, missingValue: Array.from(siblings).join(', '), }, + suggest: false, }); } } @@ -337,17 +355,23 @@ function checkLiteralValueNode(context, attributeName, node, parentNode, parentN report(context, messages.spaceDelimited, 'spaceDelimited', { node, data: { attributeName }, - fix(fixer) { - return fixer.removeRange(whitespacePart.range); - }, + suggest: [ + Object.assign( + getMessageData('suggestRemoveWhitespaces', messages.suggestRemoveWhitespaces), + { fix(fixer) { return fixer.removeRange(whitespacePart.range); } } + ), + ], }); } else if (whitespacePart.value !== '\u0020') { report(context, messages.spaceDelimited, 'spaceDelimited', { node, data: { attributeName }, - fix(fixer) { - return fixer.replaceTextRange(whitespacePart.range, '\u0020'); - }, + suggest: [ + Object.assign( + getMessageData('suggestRemoveWhitespaces', messages.suggestRemoveWhitespaces), + { fix(fixer) { return fixer.replaceTextRange(whitespacePart.range, '\u0020'); } } + ), + ], }); } } @@ -358,10 +382,6 @@ const DEFAULT_ATTRIBUTES = ['rel']; function checkAttribute(context, node) { const attribute = node.name.name; - function fix(fixer) { - return fixer.remove(node); - } - const parentNodeName = node.parent.name.name; if (!COMPONENT_ATTRIBUTE_MAP.has(attribute) || !COMPONENT_ATTRIBUTE_MAP.get(attribute).has(parentNodeName)) { const tagNames = Array.from( @@ -374,16 +394,28 @@ function checkAttribute(context, node) { attributeName: attribute, tagNames, }, - fix, + suggest: [ + Object.assign( + getMessageData('suggestRemoveDefault', messages.suggestRemoveDefault), + { fix(fixer) { return fixer.remove(node); } } + ), + ], }); return; } + function fix(fixer) { return fixer.remove(node); } + if (!node.value) { report(context, messages.emptyIsMeaningless, 'emptyIsMeaningless', { node, data: { attributeName: attribute }, - fix, + suggest: [ + Object.assign( + getMessageData('suggestRemoveEmpty', messages.suggestRemoveEmpty), + { fix } + ), + ], }); return; } @@ -404,16 +436,23 @@ function checkAttribute(context, node) { report(context, messages.onlyStrings, 'onlyStrings', { node, data: { attributeName: attribute }, - fix, + suggest: [ + Object.assign( + getMessageData('suggestRemoveDefault', messages.suggestRemoveDefault), + { fix } + ), + ], }); - return; - } - - if (node.value.expression.type === 'Identifier' && node.value.expression.name === 'undefined') { + } else if (node.value.expression.type === 'Identifier' && node.value.expression.name === 'undefined') { report(context, messages.onlyStrings, 'onlyStrings', { node, data: { attributeName: attribute }, - fix, + suggest: [ + Object.assign( + getMessageData('suggestRemoveDefault', messages.suggestRemoveDefault), + { fix } + ), + ], }); } } @@ -441,11 +480,14 @@ function checkPropValidValue(context, node, value, attribute) { attributeName: attribute, reportingValue: value.value, }, + suggest: [ + Object.assign( + getMessageData('suggestRemoveInvalid', messages.suggestRemoveInvalid), + { fix(fixer) { return fixer.replaceText(value, value.raw.replace(value.value, '')); } } + ), + ], }); - return; - } - - if (!validTagSet.has(node.arguments[0].value)) { + } else if (!validTagSet.has(node.arguments[0].value)) { report(context, messages.notValidFor, 'notValidFor', { node: value, data: { @@ -453,6 +495,7 @@ function checkPropValidValue(context, node, value, attribute) { reportingValue: value.raw, elementName: node.arguments[0].value, }, + suggest: false, }); } } @@ -493,6 +536,7 @@ function checkCreateProps(context, node, attribute) { attributeName: attribute, tagNames, }, + suggest: false, }); // eslint-disable-next-line no-continue @@ -505,6 +549,7 @@ function checkCreateProps(context, node, attribute) { data: { attributeName: attribute, }, + suggest: false, }); // eslint-disable-next-line no-continue @@ -531,7 +576,6 @@ function checkCreateProps(context, node, attribute) { module.exports = { meta: { - fixable: 'code', docs: { description: 'Disallow usage of invalid attributes', category: 'Possible Errors', @@ -545,6 +589,8 @@ module.exports = { enum: ['rel'], }, }], + type: 'suggestion', + hasSuggestions: true, // eslint-disable-line eslint-plugin/require-meta-has-suggestions }, create(context) { diff --git a/tests/helpers/parsers.js b/tests/helpers/parsers.js index 1403f114c0..1d05610c6d 100644 --- a/tests/helpers/parsers.js +++ b/tests/helpers/parsers.js @@ -174,6 +174,8 @@ const parsers = { tsNew ? addComment(Object.assign({}, test, { parser: parsers['@TYPESCRIPT_ESLINT'] }), '@typescript-eslint/parser') : [] ); }); + + // console.log(require('util').inspect(t, { depth: null })); return t; }, }; diff --git a/tests/lib/rules/no-invalid-html-attribute.js b/tests/lib/rules/no-invalid-html-attribute.js index 2ba5b16883..cde601ba31 100644 --- a/tests/lib/rules/no-invalid-html-attribute.js +++ b/tests/lib/rules/no-invalid-html-attribute.js @@ -11,6 +11,7 @@ const RuleTester = require('eslint').RuleTester; const rule = require('../../../lib/rules/no-invalid-html-attribute'); +const parsers = require('../../helpers/parsers'); const parserOptions = { ecmaVersion: 2018, @@ -27,7 +28,7 @@ const parserOptions = { const ruleTester = new RuleTester({ parserOptions }); ruleTester.run('no-invalid-html-attribute', rule, { - valid: [ + valid: parsers.all([ { code: '' }, { code: 'React.createElement("a", { rel: "alternate" })' }, { code: 'React.createElement("a", { rel: ["alternate"] })' }, @@ -232,11 +233,10 @@ ruleTester.run('no-invalid-html-attribute', rule, { { code: '', }, - ], - invalid: [ + ]), + invalid: parsers.all([ { code: '', - output: '', errors: [ { messageId: 'neverValid', @@ -244,12 +244,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'alternatex', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: 'React.createElement("a", { rel: "alternatex" })', - output: null, errors: [ { messageId: 'neverValid', @@ -257,12 +262,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'alternatex', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: 'React.createElement("a", { rel: "" })', + }, + ], }, ], }, { code: 'React.createElement("a", { rel: ["alternatex"] })', - output: null, errors: [ { messageId: 'neverValid', @@ -270,12 +280,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'alternatex', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: 'React.createElement("a", { rel: [""] })', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'neverValid', @@ -283,6 +298,12 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'alternatex', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, @@ -295,6 +316,12 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'alternatex alternate', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: 'React.createElement("a", { rel: "" })', + }, + ], }, ], }, @@ -307,12 +334,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'alternatex alternate', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: 'React.createElement("a", { rel: [""] })', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'neverValid', @@ -320,6 +352,12 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'alternatex', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, @@ -332,6 +370,12 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'alternate alternatex', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: 'React.createElement("a", { rel: "" })', + }, + ], }, ], }, @@ -344,12 +388,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'alternate alternatex', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: 'React.createElement("a", { rel: [""] })', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'onlyMeaningfulFor', @@ -357,6 +406,12 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', tagNames: '"", "", "", "
"', }, + suggestions: [ + { + messageId: 'suggestRemoveDefault', + output: '', + }, + ], }, ], }, @@ -369,16 +424,27 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', tagNames: '"", "", "", ""', }, + // suggestions: [ + // { + // messageId: 'suggestRemoveDefault', + // output: 'React.createElement("html", { })', + // }, + // ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'emptyIsMeaningless', data: { attributeName: 'rel' }, + suggestions: [ + { + messageId: 'suggestRemoveEmpty', + output: '', + }, + ], }, ], }, @@ -391,6 +457,12 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', reportingValue: 1, }, + // suggestions: [ + // { + // messageId: 'suggestRemoveDefault', + // output: 'React.createElement("a", { })', + // }, + // ], }, ], }, @@ -405,7 +477,6 @@ ruleTester.run('no-invalid-html-attribute', rule, { }, { code: '', - output: '', errors: [ { messageId: 'onlyMeaningfulFor', @@ -413,62 +484,92 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', tagNames: '"", "", "", ""', }, + suggestions: [ + { + messageId: 'suggestRemoveDefault', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'onlyStrings', data: { attributeName: 'rel' }, + suggestions: [ + { + messageId: 'suggestRemoveNonString', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'onlyStrings', data: { attributeName: 'rel' }, + suggestions: [ + { + messageId: 'suggestRemoveNonString', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'onlyStrings', data: { attributeName: 'rel' }, + suggestions: [ + { + messageId: 'suggestRemoveNonString', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'onlyStrings', data: { attributeName: 'rel' }, + suggestions: [ + { + messageId: 'suggestRemoveDefault', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'onlyStrings', data: { attributeName: 'rel' }, + suggestions: [ + { + messageId: 'suggestRemoveDefault', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'neverValid', @@ -476,42 +577,62 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', reportingValue: 'foobar', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'spaceDelimited', data: { attributeName: 'rel' }, + suggestions: [ + { + messageId: 'suggestRemoveWhitespaces', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'spaceDelimited', data: { attributeName: 'rel' }, + suggestions: [ + { + messageId: 'suggestRemoveWhitespaces', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'spaceDelimited', data: { attributeName: 'rel' }, + suggestions: [ + { + messageId: 'suggestRemoveWhitespaces', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'neverValid', @@ -519,6 +640,12 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'foobar', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, @@ -531,12 +658,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'foobar', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: 'React.createElement("a", { rel: ["noreferrer", "noopener", "" ] })', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'neverValid', @@ -544,12 +676,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'foobar', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'neverValid', @@ -557,6 +694,12 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'foobar', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, { messageId: 'neverValid', @@ -564,6 +707,12 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'batgo', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, { messageId: 'spaceDelimited', @@ -573,27 +722,36 @@ ruleTester.run('no-invalid-html-attribute', rule, { }, { code: '', - output: '', errors: [ { messageId: 'spaceDelimited', data: { attributeName: 'rel' }, + suggestions: [ + { + messageId: 'suggestRemoveWhitespaces', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'spaceDelimited', data: { attributeName: 'rel' }, + suggestions: [ + { + messageId: 'suggestRemoveWhitespaces', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'neverValid', @@ -601,6 +759,12 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'batgo', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, { messageId: 'spaceDelimited', @@ -610,7 +774,6 @@ ruleTester.run('no-invalid-html-attribute', rule, { }, { code: '', - output: '', errors: [ { messageId: 'neverValid', @@ -618,22 +781,32 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'batgo', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'spaceDelimited', data: { attributeName: 'rel' }, + suggestions: [ + { + messageId: 'suggestRemoveWhitespaces', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -642,12 +815,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'a', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -656,12 +834,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'a', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -670,6 +853,12 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'a', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, @@ -687,7 +876,6 @@ ruleTester.run('no-invalid-html-attribute', rule, { }, { code: '', - output: '', errors: [ { messageId: 'neverValid', @@ -695,6 +883,12 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'foo', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, { messageId: 'notPaired', @@ -708,17 +902,21 @@ ruleTester.run('no-invalid-html-attribute', rule, { }, { code: '', - output: '', errors: [ { messageId: 'spaceDelimited', data: { attributeName: 'rel' }, + suggestions: [ + { + messageId: 'suggestRemoveWhitespaces', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'neverValid', @@ -726,6 +924,12 @@ ruleTester.run('no-invalid-html-attribute', rule, { reportingValue: 'foo', attributeName: 'rel', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, { messageId: 'notAlone', @@ -737,12 +941,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { { messageId: 'spaceDelimited', data: { attributeName: 'rel' }, + suggestions: [ + { + messageId: 'suggestRemoveWhitespaces', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -751,12 +960,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'a', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -765,12 +979,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'a', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -779,12 +998,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'a', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -793,12 +1017,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'a', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -807,12 +1036,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'a', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -821,12 +1055,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'a', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -835,12 +1074,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'a', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -849,12 +1093,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'a', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -863,12 +1112,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'area', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -877,12 +1131,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'area', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -891,12 +1150,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'area', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -905,12 +1169,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'area', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -919,12 +1188,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'area', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -933,12 +1207,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'area', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -947,12 +1226,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'area', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -961,12 +1245,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'area', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -975,12 +1264,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'area', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -989,12 +1283,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'area', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -1003,12 +1302,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'area', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -1017,12 +1321,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'link', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -1031,12 +1340,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'link', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -1045,12 +1359,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'link', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -1059,12 +1378,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'link', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -1073,12 +1397,16 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'link', }, + suggestions: [ + { + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -1087,12 +1415,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'link', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '', - output: '', errors: [ { messageId: 'notValidFor', @@ -1101,12 +1434,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'link', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '', + }, + ], }, ], }, { code: '
', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1115,12 +1453,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, { code: '', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1129,12 +1472,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, { code: '
', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1143,12 +1491,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, { code: '
', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1157,12 +1510,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, { code: '
', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1171,12 +1529,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, { code: '', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1185,12 +1548,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, { code: '
', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1199,12 +1567,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, { code: '
', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1213,12 +1586,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, { code: '
', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1227,12 +1605,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, { code: '
', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1241,12 +1624,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, { code: '
', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1255,12 +1643,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, { code: '
', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1269,12 +1662,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, { code: '
', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1283,12 +1681,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, { code: '
', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1297,12 +1700,17 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, { code: '', - output: '
', errors: [ { messageId: 'notValidFor', @@ -1311,8 +1719,33 @@ ruleTester.run('no-invalid-html-attribute', rule, { attributeName: 'rel', elementName: 'form', }, + suggestions: [ + { + messageId: 'suggestRemoveInvalid', + output: '
', + }, + ], }, ], }, - ], + { + code: '
', + errors: [ + { + messageId: 'noEmpty', + data: { + reportingValue: 'tag', + attributeName: 'rel', + elementName: 'form', + }, + suggestions: [ + { + messageId: 'suggestRemoveEmpty', + output: '
', + }, + ], + }, + ], + }, + ]), });