diff --git a/lib/rules/key-spacing.js b/lib/rules/key-spacing.js index a33ef29891e..b764b7282ef 100644 --- a/lib/rules/key-spacing.js +++ b/lib/rules/key-spacing.js @@ -9,6 +9,9 @@ //------------------------------------------------------------------------------ const astUtils = require("./utils/ast-utils"); +const GraphemeSplitter = require("grapheme-splitter"); + +const splitter = new GraphemeSplitter(); //------------------------------------------------------------------------------ // Helpers @@ -508,7 +511,7 @@ module.exports = { const startToken = sourceCode.getFirstToken(property); const endToken = getLastTokenBeforeColon(property.key); - return endToken.range[1] - startToken.range[0]; + return splitter.countGraphemes(sourceCode.getText().slice(startToken.range[0], endToken.range[1])); } /** diff --git a/package.json b/package.json index 0cac453903f..d2306de9205 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", "globals": "^13.15.0", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", diff --git a/tests/lib/rules/key-spacing.js b/tests/lib/rules/key-spacing.js index fde9673a63b..dd0fcbc4dcf 100644 --- a/tests/lib/rules/key-spacing.js +++ b/tests/lib/rules/key-spacing.js @@ -896,8 +896,82 @@ ruleTester.run("key-spacing", rule, { on: "value" } }] - } - ], + }, + + // https://github.com/eslint/eslint/issues/15914 + { + code: ` + var foo = { + "a": "bar", + "𐌘": "baz" + }; + `, + options: [{ + align: { + on: "value" + } + }] + }, + { + code: ` + var foo = { + "a": "bar", + "Á": "baz", + "o͂": "qux", + "mĖ…": "xyz", + "ř": "abc" + + }; + `, + options: [{ + align: { + on: "value" + } + }] + }, + { + code: ` + var foo = { + "🌷": "bar", // 2 code points + "🎁": "baz", // 2 code points + "ðŸ‡ŪðŸ‡ģ": "qux", // 4 code points + "ðŸģïļâ€ðŸŒˆ": "xyz", // 6 code points + }; + `, + options: [{ + align: { + on: "value" + } + }] + }, + { + code: ` + const foo = { + "a": "bar", + [𐌘]: "baz" + }; + `, + options: [{ + align: { + on: "value" + } + }], + parserOptions: { ecmaVersion: 6 } + }, + { + code: ` + const foo = { + "abc": "bar", + [ 𐌘 ]: "baz" + }; + `, + options: [{ + align: { + on: "value" + } + }], + parserOptions: { ecmaVersion: 6 } + }], invalid: [{ code: "var a ={'key' : value };", output: "var a ={'key':value };", @@ -2203,5 +2277,103 @@ ruleTester.run("key-spacing", rule, { { messageId: "missingValue", data: { computed: "", key: "bar" }, line: 3, column: 12, type: "Literal" }, { messageId: "missingValue", data: { computed: "", key: "baz" }, line: 3, column: 20, type: "Literal" } ] - }] + }, + { + code: ` + const foo = { + "a": "bar", + [ 𐌘 ]: "baz" + }; + `, + output: ` + const foo = { + "a": "bar", + [ 𐌘 ]: "baz" + }; + `, + options: [{ + align: { + on: "value" + } + }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { messageId: "missingValue", data: { computed: "", key: "a" }, line: 3, column: 22, type: "Literal" } + ] + }, + { + code: ` + const foo = { + "a": "bar", + [ 𐌘 ]: "baz" + }; + `, + output: ` + const foo = { + "a" : "bar", + [ 𐌘 ]: "baz" + }; + `, + options: [{ + align: { + on: "colon" + } + }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { messageId: "missingKey", data: { computed: "", key: "a" }, line: 3, column: 17, type: "Literal" } + ] + }, + { + code: ` + const foo = { + "a": "bar", + "𐌘": "baz" + }; + `, + output: ` + const foo = { + "a": "bar", + "𐌘": "baz" + }; + `, + options: [{ + align: { + on: "value" + } + }], + parserOptions: { ecmaVersion: 6 }, + errors: [ + { messageId: "extraValue", data: { computed: "", key: "a" }, line: 3, column: 20, type: "Literal" } + ] + }, + { + code: ` + var foo = { + "🌷": "bar", // 2 code points + "🎁": "baz", // 2 code points + "ðŸ‡ŪðŸ‡ģ": "qux", // 4 code points + "ðŸģïļâ€ðŸŒˆ": "xyz", // 6 code points + }; + `, + output: ` + var foo = { + "🌷": "bar", // 2 code points + "🎁": "baz", // 2 code points + "ðŸ‡ŪðŸ‡ģ": "qux", // 4 code points + "ðŸģïļâ€ðŸŒˆ": "xyz", // 6 code points + }; + `, + options: [{ + align: { + on: "value" + } + }], + errors: [ + { messageId: "extraValue", data: { computed: "", key: "🌷" }, line: 3, column: 21, type: "Literal" }, + { messageId: "extraValue", data: { computed: "", key: "🎁" }, line: 4, column: 21, type: "Literal" }, + { messageId: "extraValue", data: { computed: "", key: "ðŸ‡ŪðŸ‡ģ" }, line: 5, column: 23, type: "Literal" } + ] + } + ] });