From 8262223105e8c226b7e920f2c37a194734944c91 Mon Sep 17 00:00:00 2001 From: Ian Christian Myers Date: Thu, 18 Jul 2013 22:23:36 -0700 Subject: [PATCH] Created no-dangle rule. Created the no-dangle rule, which warns when it encounters a trailing comma in an object literal. The following will raise warnings: var foo = { bar: "baz", } Fixes issue #13 --- conf/eslint.json | 1 + docs/Rules.md | 1 + docs/no-dangle.md | 50 +++++++++++++++++ lib/rules/no-dangle.js | 36 ++++++++++++ tests/lib/rules/no-dangle.js | 106 +++++++++++++++++++++++++++++++++++ 5 files changed, 194 insertions(+) create mode 100644 docs/no-dangle.md create mode 100644 lib/rules/no-dangle.js create mode 100644 tests/lib/rules/no-dangle.js diff --git a/conf/eslint.json b/conf/eslint.json index 570498df988..21a5bd36ca9 100644 --- a/conf/eslint.json +++ b/conf/eslint.json @@ -5,6 +5,7 @@ "no-caller": 1, "no-bitwise": 0, "no-console": 1, + "no-dangle": 1, "no-debugger": 1, "no-empty": 1, "no-eval": 1, diff --git a/docs/Rules.md b/docs/Rules.md index 70072c23577..c7ee92e37dc 100644 --- a/docs/Rules.md +++ b/docs/Rules.md @@ -7,6 +7,7 @@ Rules in ESLint are divided into several categories to help you better understan The following rules point out areas where you might have made mistakes. * [no-console](no-console.md) - disallow use of `console` +* [no-dangle](no-dangle.md) - disallow trailing commas in object literals * [no-debugger](No-debugger.md) - disallow use of `debugger` * [no-empty](No-empty.md) - disallow empty statements * [no-unreachable](No-unreachable.md) - disallow unreachable statements after a return, throw, continue, or break statement diff --git a/docs/no-dangle.md b/docs/no-dangle.md new file mode 100644 index 00000000000..a7521d27376 --- /dev/null +++ b/docs/no-dangle.md @@ -0,0 +1,50 @@ +# no dangle + +Trailing commas in object literals are valid according to the ECMAScript 5 (and ECMAScript 3!) spec, however IE8 (when not in IE8 document mode) and below will throw an error when it encounters trailing commas in JavaScript. + +```js +var foo = { + bar: "baz", + qux: "quux", +}; +``` + +## Rule Details + +This rule is aimed at detecting trailing commas in object literals. As such, it will warn whenever it encounters a trailing comma in an object literal. + +The following are considered warnings: + +```js +var foo = { + bar: "baz", + qux: "quux", +}; + +var arr = [1,2,]; + +foo({ + bar: "baz", + qux: "quux", +}); +``` + +The following are okay and will not raise warnings: + +```js +var foo = { + bar: "baz", + qux: "quux" +}; + +var arr = [1,2]; + +foo({ + bar: "baz", + qux: "quux" +}); +``` + +## When Not To Use It + +If your code will not be run in IE8 or below (a NodeJS application, for example) and you'd prefer to allow trailing commas, turn this rule off. diff --git a/lib/rules/no-dangle.js b/lib/rules/no-dangle.js new file mode 100644 index 00000000000..55f3b68531b --- /dev/null +++ b/lib/rules/no-dangle.js @@ -0,0 +1,36 @@ +/** + * @fileoverview Rule to flag trailing commas in object literals. + * @author Ian Christian Myers + */ + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + + //------------------------------------------------------------------------- + // Helpers + //------------------------------------------------------------------------- + + function checkForTrailingComma(node) { + var tokens = context.getTokens(node), + secondToLastToken = tokens[tokens.length - 2]; + + // The last token in an object/array literal will always be a closing + // curly, so we check the second to last token for a comma. + if (secondToLastToken.value === ",") { + context.report(node, "Found trailing comma in object literal."); + } + } + + //-------------------------------------------------------------------------- + // Public API + //-------------------------------------------------------------------------- + + return { + "ObjectExpression": checkForTrailingComma, + "ArrayExpression": checkForTrailingComma + }; + +}; diff --git a/tests/lib/rules/no-dangle.js b/tests/lib/rules/no-dangle.js new file mode 100644 index 00000000000..c3688d79bfd --- /dev/null +++ b/tests/lib/rules/no-dangle.js @@ -0,0 +1,106 @@ +/** + * @fileoverview Tests for no-dangle rule. + * @author Ian Christian Myers + */ + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var vows = require("vows"), + assert = require("assert"), + eslint = require("../../../lib/eslint"); + +//------------------------------------------------------------------------------ +// Constants +//------------------------------------------------------------------------------ + +var RULE_ID = "no-dangle"; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +vows.describe(RULE_ID).addBatch({ + + "when evaluating object literal with a dangling comma": { + + topic: "var foo = { bar: \"baz\", }", + + "should report a violation": function(topic) { + var config = { rules: {} }; + config.rules[RULE_ID] = 1; + + var messages = eslint.verify(topic, config); + + assert.equal(messages.length, 1); + assert.equal(messages[0].ruleId, RULE_ID); + assert.equal(messages[0].message, "Found trailing comma in object literal."); + assert.include(messages[0].node.type, "ObjectExpression"); + } + }, + + "when evaluating object literal passed to a function with a dangling comma": { + + topic: "foo({ bar: \"baz\", qux: \"quux\", });", + + "should report a violation": function(topic) { + var config = { rules: {} }; + config.rules[RULE_ID] = 1; + + var messages = eslint.verify(topic, config); + + assert.equal(messages.length, 1); + assert.equal(messages[0].ruleId, RULE_ID); + assert.equal(messages[0].message, "Found trailing comma in object literal."); + assert.include(messages[0].node.type, "ObjectExpression"); + } + }, + + + "when evaluating object literal without a dangling comma": { + + topic: "var foo = { bar: \"baz\" }", + + "should not report a violation": function(topic) { + var config = { rules: {} }; + config.rules[RULE_ID] = 1; + + var messages = eslint.verify(topic, config); + + assert.equal(messages.length, 0); + } + }, + + "when evaluating array literal with a dangling comma": { + + topic: "var foo = [ \"baz\", ]", + + "should report a violation": function(topic) { + var config = { rules: {} }; + config.rules[RULE_ID] = 1; + + var messages = eslint.verify(topic, config); + + assert.equal(messages.length, 1); + assert.equal(messages[0].ruleId, RULE_ID); + assert.equal(messages[0].message, "Found trailing comma in object literal."); + assert.include(messages[0].node.type, "ArrayExpression"); + } + }, + + "when evaluating array literal without a dangling comma": { + + topic: "var foo = [ \"baz\" ]", + + "should not report a violation": function(topic) { + var config = { rules: {} }; + config.rules[RULE_ID] = 1; + + var messages = eslint.verify(topic, config); + + assert.equal(messages.length, 0); + } + } + +}).export(module);