diff --git a/docs/rules/dot-notation.md b/docs/rules/dot-notation.md index 881e819d839..388465d23a8 100644 --- a/docs/rules/dot-notation.md +++ b/docs/rules/dot-notation.md @@ -1,5 +1,7 @@ # Require Dot Notation (dot-notation) +(fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#fix) automatically fixes problems reported by this rule. + In JavaScript, one can access properties using the dot notation (`foo.bar`) or square-bracket notation (`foo["bar"]`). However, the dot notation is often preferred because it is easier to read, less verbose, and works better with aggressive JavaScript minimizers. ```js diff --git a/lib/rules/dot-notation.js b/lib/rules/dot-notation.js index 849b8f7429a..d55b098b25b 100644 --- a/lib/rules/dot-notation.js +++ b/lib/rules/dot-notation.js @@ -32,12 +32,15 @@ module.exports = { }, additionalProperties: false } - ] + ], + + fixable: "code" }, create(context) { const options = context.options[0] || {}; const allowKeywords = options.allowKeywords === void 0 || !!options.allowKeywords; + const sourceCode = context.getSourceCode(); let allowPattern; @@ -59,6 +62,23 @@ module.exports = { message: "[{{propertyValue}}] is better written in dot notation.", data: { propertyValue: JSON.stringify(node.property.value) + }, + fix(fixer) { + const leftBracket = sourceCode.getTokenBefore(node.property); + const rightBracket = sourceCode.getTokenAfter(node.property); + const textBeforeProperty = sourceCode.text.slice(leftBracket.range[1], node.property.range[0]); + const textAfterProperty = sourceCode.text.slice(node.property.range[1], rightBracket.range[0]); + + if (textBeforeProperty.trim() || textAfterProperty.trim()) { + + // Don't perform any fixes if there are comments inside the brackets. + return null; + } + + return fixer.replaceTextRange( + [leftBracket.range[0], rightBracket.range[1]], + `.${node.property.value}` + ); } }); } @@ -73,6 +93,21 @@ module.exports = { message: ".{{propertyName}} is a syntax error.", data: { propertyName: node.property.name + }, + fix(fixer) { + const dot = sourceCode.getTokenBefore(node.property); + const textAfterDot = sourceCode.text.slice(dot.range[1], node.property.range[0]); + + if (textAfterDot.trim()) { + + // Don't perform any fixes if there are comments between the dot and the property name. + return null; + } + + return fixer.replaceTextRange( + [dot.range[0], node.property.range[1]], + `[${textAfterDot}"${node.property.name}"]` + ); } }); } diff --git a/tests/lib/rules/dot-notation.js b/tests/lib/rules/dot-notation.js index c9b342d94a7..e384e5551ea 100644 --- a/tests/lib/rules/dot-notation.js +++ b/tests/lib/rules/dot-notation.js @@ -47,13 +47,43 @@ ruleTester.run("dot-notation", rule, { "a[b()];" ], invalid: [ - { code: "a.true;", options: [{allowKeywords: false}], errors: [{ message: ".true is a syntax error." }] }, - { code: "a['true'];", errors: [{ message: "[\"true\"] is better written in dot notation." }] }, - { code: "a[null];", errors: [{ message: "[null] is better written in dot notation." }] }, - { code: "a['b'];", errors: [{ message: "[\"b\"] is better written in dot notation." }] }, - { code: "a.b['c'];", errors: [{ message: "[\"c\"] is better written in dot notation." }] }, - { code: "a['_dangle'];", options: [{allowPattern: "^[a-z]+(_[a-z]+)+$"}], errors: [{ message: "[\"_dangle\"] is better written in dot notation." }] }, - { code: "a['SHOUT_CASE'];", options: [{allowPattern: "^[a-z]+(_[a-z]+)+$"}], errors: [{ message: "[\"SHOUT_CASE\"] is better written in dot notation." }] }, + { + code: "a.true;", + options: [{allowKeywords: false}], + errors: [{ message: ".true is a syntax error." }], + output: "a[\"true\"];" + }, + { + code: "a['true'];", + errors: [{ message: "[\"true\"] is better written in dot notation." }], + output: "a.true;" + }, + { + code: "a[null];", + errors: [{ message: "[null] is better written in dot notation." }], + output: "a.null;" + }, + { + code: "a['b'];", + errors: [{ message: "[\"b\"] is better written in dot notation." }], + output: "a.b;" + }, + { + code: "a.b['c'];", + errors: [{ message: "[\"c\"] is better written in dot notation." }], + output: "a.b.c;" + }, + { + code: "a['_dangle'];", + options: [{allowPattern: "^[a-z]+(_[a-z]+)+$"}], errors: [{ message: "[\"_dangle\"] is better written in dot notation." }], + output: "a._dangle;" + }, + { + code: "a['SHOUT_CASE'];", + options: [{allowPattern: "^[a-z]+(_[a-z]+)+$"}], + errors: [{ message: "[\"SHOUT_CASE\"] is better written in dot notation." }], + output: "a.SHOUT_CASE;" + }, { code: "a\n" + @@ -62,7 +92,10 @@ ruleTester.run("dot-notation", rule, { message: "[\"SHOUT_CASE\"] is better written in dot notation.", line: 2, column: 4 - }] + }], + output: + "a\n" + + " .SHOUT_CASE;" }, { code: @@ -82,7 +115,44 @@ ruleTester.run("dot-notation", rule, { line: 5, column: 6 } - ] + ], + output: + "getResource()\n" + + " .then(function(){})\n" + + " .catch(function(){})\n" + + " .then(function(){})\n" + + " .catch(function(){});" + }, + { + code: + "foo\n" + + " .while;", + options: [{ allowKeywords: false }], + errors: [{ message: ".while is a syntax error." }], + output: + "foo\n" + + " [\"while\"];" + }, + { + code: "foo[ /* comment */ 'bar' ]", + errors: [{ message: "[\"bar\"] is better written in dot notation." }], + output: "foo[ /* comment */ 'bar' ]" // Not fixed due to comment + }, + { + code: "foo[ 'bar' /* comment */ ]", + errors: [{ message: "[\"bar\"] is better written in dot notation." }], + output: "foo[ 'bar' /* comment */ ]" // Not fixed due to comment + }, + { + code: "foo[ 'bar' ];", + errors: [{ message: "[\"bar\"] is better written in dot notation." }], + output: "foo.bar;" + }, + { + code: "foo. /* comment */ while", + options: [{ allowKeywords: false }], + errors: [{ message: ".while is a syntax error." }], + output: "foo. /* comment */ while" // Not fixed due to comment } ] });