diff --git a/lib/rules/key-spacing.js b/lib/rules/key-spacing.js index 994c35627f7..6d1b9121c78 100644 --- a/lib/rules/key-spacing.js +++ b/lib/rules/key-spacing.js @@ -42,6 +42,18 @@ function isSingleLine(node) { return (node.loc.end.line === node.loc.start.line); } +/** + * Checks whether the properties on a single line. + * @param {ASTNode[]} properties List of Property AST nodes. + * @returns {boolean} True if all properies is on a single line. + */ +function isSingleLineProperties(properties) { + const [firstProp] = properties, + lastProp = last(properties); + + return firstProp.loc.start.line === lastProp.loc.end.line; +} + /** * Initializes a single option property from the configuration with defaults for undefined values * @param {Object} toOptions Object to be initialized @@ -583,17 +595,6 @@ module.exports = { } } - /** - * Verifies vertical alignment, taking into account groups of properties. - * @param {ASTNode} node ObjectExpression node being evaluated. - * @returns {void} - */ - function verifyAlignment(node) { - createGroups(node).forEach(group => { - verifyGroupAlignment(group.filter(isKeyValueProperty)); - }); - } - /** * Verifies spacing of property conforms to specified options. * @param {ASTNode} node Property node being evaluated. @@ -611,17 +612,35 @@ module.exports = { /** * Verifies spacing of each property in a list. - * @param {ASTNode[]} properties List of Property AST nodes. + * @param {ASTNode[]} properties List of Property AST nodes. + * @param {Object} lineOptions Configured singleLine or multiLine options * @returns {void} */ - function verifyListSpacing(properties) { + function verifyListSpacing(properties, lineOptions) { const length = properties.length; for (let i = 0; i < length; i++) { - verifySpacing(properties[i], singleLineOptions); + verifySpacing(properties[i], lineOptions); } } + /** + * Verifies vertical alignment, taking into account groups of properties. + * @param {ASTNode} node ObjectExpression node being evaluated. + * @returns {void} + */ + function verifyAlignment(node) { + createGroups(node).forEach(group => { + const properties = group.filter(isKeyValueProperty); + + if (properties.length > 0 && isSingleLineProperties(properties)) { + verifyListSpacing(properties, multiLineOptions); + } else { + verifyGroupAlignment(properties); + } + }); + } + //-------------------------------------------------------------------------- // Public API //-------------------------------------------------------------------------- @@ -631,7 +650,7 @@ module.exports = { return { ObjectExpression(node) { if (isSingleLine(node)) { - verifyListSpacing(node.properties.filter(isKeyValueProperty)); + verifyListSpacing(node.properties.filter(isKeyValueProperty), singleLineOptions); } else { verifyAlignment(node); } diff --git a/tests/lib/rules/key-spacing.js b/tests/lib/rules/key-spacing.js index a9ed533741c..29bbbe85781 100644 --- a/tests/lib/rules/key-spacing.js +++ b/tests/lib/rules/key-spacing.js @@ -757,6 +757,141 @@ ruleTester.run("key-spacing", rule, { } }], parserOptions: { ecmaVersion: 6 } + }, { + code: [ + "var obj = {", + " foo : 1, 'bar' : 2, baz : 3, longlonglong : 4", + "}" + ].join("\n"), + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + multiLine: { + beforeColon: true, + afterColon: true, + align: "colon" + } + }] + }, { + code: [ + "var obj = {", + " foo: 1, 'bar': 2, baz: 3", + "}" + ].join("\n"), + options: [{ + multiLine: { + align: "value" + } + }] + }, { + code: [ + "var obj = {", + " foo: 1", + "}" + ].join("\n"), + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + multiLine: { + align: "value" + } + }] + }, { + code: [ + "foo({", + " bar: 1", + "})" + ].join("\n"), + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + align: { + on: "colon" + } + }] + }, { + code: "var obj = { foo:1, 'bar':2, baz:3, longlonglong:4 }", + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + align: { + on: "colon" + } + }] + }, { + code: [ + "var obj = {", + " foo : 1,", + " 'bar' : 2, baz : 3, longlonglong: 4", + "}" + ].join("\n"), + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + align: { + on: "colon" + } + }] + }, { + code: [ + "var obj = {", + " foo: 1,", + " 'bar': 2, baz: 3, longlonglong: 4", + "}" + ].join("\n"), + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + align: { + on: "value" + } + }] + }, { + code: [ + "var obj = {", + " foo : 1,", + " 'bar' : 2, baz : 3,", + " longlonglong: 4", + "}" + ].join("\n"), + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + align: { + on: "colon" + } + }] + }, { + code: [ + "var obj = {", + " foo: 1,", + " 'bar': 2, baz: 3,", + " longlonglong: 4", + "}" + ].join("\n"), + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + align: { + on: "value" + } + }] }], invalid: [{ @@ -1769,5 +1904,206 @@ ruleTester.run("key-spacing", rule, { { messageId: "missingKey", data: { computed: "", key: "foo" }, line: 1, column: 7, type: "Identifier" }, { messageId: "missingValue", data: { computed: "", key: "foo" }, line: 1, column: 19, type: "Identifier" } ] + }, { + code: [ + "var obj = {", + " foo:1, 'bar':2, baz:3", + "}" + ].join("\n"), + output: [ + "var obj = {", + " foo : 1, 'bar' : 2, baz : 3", + "}" + ].join("\n"), + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + multiLine: { + beforeColon: true, + afterColon: true, + align: "colon" + } + }], + errors: [ + { messageId: "missingKey", data: { computed: "", key: "foo" }, line: 2, column: 5, type: "Identifier" }, + { messageId: "missingValue", data: { computed: "", key: "foo" }, line: 2, column: 9, type: "Literal" }, + { messageId: "missingKey", data: { computed: "", key: "bar" }, line: 2, column: 12, type: "Literal" }, + { messageId: "missingValue", data: { computed: "", key: "bar" }, line: 2, column: 18, type: "Literal" }, + { messageId: "missingKey", data: { computed: "", key: "baz" }, line: 2, column: 21, type: "Identifier" }, + { messageId: "missingValue", data: { computed: "", key: "baz" }, line: 2, column: 25, type: "Literal" } + ] + }, { + code: [ + "var obj = {", + " foo : 1, 'bar' : 2, baz : 3, longlonglong : 4", + "}" + ].join("\n"), + output: [ + "var obj = {", + " foo: 1, 'bar': 2, baz: 3, longlonglong: 4", + "}" + ].join("\n"), + options: [{ + multiLine: { + align: "value" + } + }], + errors: [ + { messageId: "extraKey", data: { computed: "", key: "foo" }, line: 2, column: 5, type: "Identifier" }, + { messageId: "extraKey", data: { computed: "", key: "bar" }, line: 2, column: 14, type: "Literal" }, + { messageId: "extraKey", data: { computed: "", key: "baz" }, line: 2, column: 25, type: "Identifier" }, + { messageId: "extraKey", data: { computed: "", key: "longlonglong" }, line: 2, column: 34, type: "Identifier" } + ] + }, { + code: [ + "var obj = {", + " foo:1", + "}" + ].join("\n"), + output: [ + "var obj = {", + " foo: 1", + "}" + ].join("\n"), + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + multiLine: { + align: "value" + } + }], + errors: [ + { messageId: "missingValue", data: { computed: "", key: "foo" }, line: 2, column: 9, type: "Literal" } + ] + }, { + code: [ + "foo({", + " bar:1", + "})" + ].join("\n"), + output: [ + "foo({", + " bar: 1", + "})" + ].join("\n"), + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + align: { + on: "colon" + } + }], + errors: [ + { messageId: "missingValue", data: { computed: "", key: "bar" }, line: 2, column: 9, type: "Literal" } + ] + }, { + code: "var obj = { foo: 1, 'bar': 2, baz :3, longlonglong :4 }", + output: "var obj = { foo:1, 'bar':2, baz:3, longlonglong:4 }", + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + align: { + on: "colon" + } + }], + errors: [ + { messageId: "extraValue", data: { computed: "", key: "foo" }, line: 1, column: 18, type: "Literal" }, + { messageId: "extraValue", data: { computed: "", key: "bar" }, line: 1, column: 28, type: "Literal" }, + { messageId: "extraKey", data: { computed: "", key: "baz" }, line: 1, column: 31, type: "Identifier" }, + { messageId: "extraKey", data: { computed: "", key: "longlonglong" }, line: 1, column: 39, type: "Identifier" } + ] + }, { + code: [ + "var obj = {", + " foo: 1,", + " 'bar': 2, baz: 3, longlonglong: 4", + "}" + ].join("\n"), + output: [ + "var obj = {", + " foo : 1,", + " 'bar' : 2, baz : 3, longlonglong: 4", + "}" + ].join("\n"), + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + align: { + on: "colon" + } + }], + errors: [ + { messageId: "missingKey", data: { computed: "", key: "foo" }, line: 2, column: 5, type: "Identifier" }, + { messageId: "missingKey", data: { computed: "", key: "bar" }, line: 3, column: 5, type: "Literal" }, + { messageId: "missingKey", data: { computed: "", key: "baz" }, line: 3, column: 15, type: "Identifier" } + ] + }, { + code: [ + "var obj = {", + " foo : 1,", + " 'bar' : 2, baz : 3,", + " longlonglong: 4", + "}" + ].join("\n"), + output: [ + "var obj = {", + " foo : 1,", + " 'bar' : 2, baz : 3,", + " longlonglong: 4", + "}" + ].join("\n"), + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + align: { + on: "colon" + } + }], + errors: [ + { messageId: "missingKey", data: { computed: "", key: "foo" }, line: 2, column: 5, type: "Identifier" }, + { messageId: "missingKey", data: { computed: "", key: "bar" }, line: 3, column: 5, type: "Literal" }, + { messageId: "missingKey", data: { computed: "", key: "baz" }, line: 3, column: 16, type: "Identifier" } + ] + }, { + code: [ + "var obj = {", + " foo: 1,", + " 'bar': 2, baz: 3,", + " longlonglong: 4", + "}" + ].join("\n"), + output: [ + "var obj = {", + " foo: 1,", + " 'bar': 2, baz: 3,", + " longlonglong: 4", + "}" + ].join("\n"), + options: [{ + singleLine: { + beforeColon: false, + afterColon: false + }, + align: { + on: "value" + } + }], + errors: [ + { messageId: "missingValue", data: { computed: "", key: "foo" }, line: 2, column: 10, type: "Literal" }, + { messageId: "missingValue", data: { computed: "", key: "bar" }, line: 3, column: 12, type: "Literal" }, + { messageId: "missingValue", data: { computed: "", key: "baz" }, line: 3, column: 20, type: "Literal" } + ] }] });