From 73a61adffbf6824d68ed862499542066833f17b8 Mon Sep 17 00:00:00 2001 From: Bradley Meck Farias Date: Mon, 7 Oct 2024 18:38:48 -0500 Subject: [PATCH] feat: rule no-unormalized-keys Fixes #32 --- src/rules/no-unnormalized-keys.js | 48 +++++++++++++++++++++++ tests/rules/no-unnormalized-keys.js | 61 +++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 src/rules/no-unnormalized-keys.js create mode 100644 tests/rules/no-unnormalized-keys.js diff --git a/src/rules/no-unnormalized-keys.js b/src/rules/no-unnormalized-keys.js new file mode 100644 index 0000000..898dc05 --- /dev/null +++ b/src/rules/no-unnormalized-keys.js @@ -0,0 +1,48 @@ +/** + * @fileoverview Rule to detect unnormalized keys in JSON. + * @author Bradley Meck Farias + */ + +export default { + meta: { + type: "problem", + + docs: { + description: "Disallow JSON keys that are not normalized", + }, + + messages: { + unnormalizedKey: "Unnormalized key found.", + }, + + schema: { + type: "array", + minItems: 0, + maxItems: 1, + items: { + enum: ["NFC", "NFD", "NFKC", "NFKD"], + }, + }, + }, + + create(context) { + const normalization = context.options.length + ? s => s.normalize(context.options[0]) + : s => s.normalize(); + return { + Member(node) { + const key = + node.name.type === "String" + ? node.name.value + : node.name.name; + + if (normalization(key) !== key) { + context.report({ + loc: node.name.loc, + messageId: "unnormalizedKey", + }); + } + }, + }; + }, +}; diff --git a/tests/rules/no-unnormalized-keys.js b/tests/rules/no-unnormalized-keys.js new file mode 100644 index 0000000..867e86c --- /dev/null +++ b/tests/rules/no-unnormalized-keys.js @@ -0,0 +1,61 @@ +/** + * @fileoverview Tests for no-empty-keys rule. + * @author Bradley Meck Farias + */ + +//------------------------------------------------------------------------------ +// Imports +//------------------------------------------------------------------------------ + +import rule from "../../src/rules/no-unnormalized-keys.js"; +import json from "../../src/index.js"; +import { RuleTester } from "eslint"; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({ + plugins: { + json, + }, + language: "json/json", +}); + +const o = "\u1E9B\u0323"; + +ruleTester.run("no-unnormalized-keys", rule, { + valid: [ + `{"${o}":"NFC"}`, + { + code: `{"${o}":"NFC"}`, + options: ["NFC"], + }, + { + code: `{"${o.normalize("NFD")}":"NFD"}`, + options: ["NFD"], + }, + { + code: `{"${o.normalize("NFKC")}":"NFKC"}`, + options: ["NFKC"], + }, + { + code: `{"${o.normalize("NFKD")}":"NFKD"}`, + options: ["NFKD"], + }, + ], + invalid: [ + { + code: `{"${o.normalize("NFD")}":"NFD"}`, + errors: [ + { + messageId: "unnormalizedKey", + line: 1, + column: 2, + endLine: 1, + endColumn: 7, + }, + ], + }, + ], +});