From c7e2ba898d3c6f103be0a67c268bf49890910b30 Mon Sep 17 00:00:00 2001 From: Bradley Meck Farias Date: Thu, 3 Oct 2024 11:41:08 -0500 Subject: [PATCH 1/3] feat: rule no-unsafe-values Fixes #29 --- src/rules/no-unsafe-values.js | 54 ++++++++++++ tests/rules/no-unsafe-values.test.js | 125 +++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 src/rules/no-unsafe-values.js create mode 100644 tests/rules/no-unsafe-values.test.js diff --git a/src/rules/no-unsafe-values.js b/src/rules/no-unsafe-values.js new file mode 100644 index 0000000..8fb9686 --- /dev/null +++ b/src/rules/no-unsafe-values.js @@ -0,0 +1,54 @@ +/** + * @fileoverview Rule to unsafe values in JSON. + * @author Bradley Meck Farias + */ + +export default { + meta: { + type: "problem", + + docs: { + description: "Disallow JSON values that are unsafe for interchange", + }, + + messages: { + unsafeNumber: "Number outside safe range found.", + loneSurrogate: "Lone surrogate found.", + }, + }, + + create(context) { + return { + Number(node) { + if (Number.isFinite(node.value) !== true) { + context.report({ + loc: node.loc, + messageId: "unsafeNumber", + }); + } + }, + String(node) { + if (node.value.isWellFormed) { + if (node.value.isWellFormed()) { + return; + } + } + // match any high surrogate and, if it exists, a paired low surrogate + // match any low surrogate not already matched + const surrogatePattern = + /[\uD800-\uDBFF][\uDC00-\uDFFF]?|[\uDC00-\uDFFF]/gu; + let match = surrogatePattern.exec(node.value); + while (match) { + // only need to report non-paired surrogates + if (match[0].length < 2) { + context.report({ + loc: node.loc, + messageId: "loneSurrogate", + }); + } + match = surrogatePattern.exec(node.value); + } + }, + }; + }, +}; diff --git a/tests/rules/no-unsafe-values.test.js b/tests/rules/no-unsafe-values.test.js new file mode 100644 index 0000000..2052b8f --- /dev/null +++ b/tests/rules/no-unsafe-values.test.js @@ -0,0 +1,125 @@ +/** + * @fileoverview Tests for no-empty-keys rule. + * @author Bradley Meck Farias + */ + +//------------------------------------------------------------------------------ +// Imports +//------------------------------------------------------------------------------ + +import rule from "../../src/rules/no-unsafe-values.js"; +import json from "../../src/index.js"; +import { RuleTester } from "eslint"; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({ + plugins: { + json, + }, + language: "json/json", +}); + +ruleTester.run("no-unsafe-values", rule, { + valid: [ + "123", + { + code: "1234", + language: "json/json5", + }, + { + code: "12345", + language: "json/json5", + }, + '"🔥"', + '"\\ud83d\\udd25"', + ], + invalid: [ + { + code: "2e308", + errors: [ + { + messageId: "unsafeNumber", + line: 1, + column: 1, + endLine: 1, + endColumn: 6, + }, + ], + }, + { + code: "-2e308", + errors: [ + { + messageId: "unsafeNumber", + line: 1, + column: 1, + endLine: 1, + endColumn: 7, + }, + ], + }, + { + code: '"\ud83d"', + errors: [ + { + messageId: "loneSurrogate", + line: 1, + column: 1, + endLine: 1, + endColumn: 4, + }, + ], + }, + { + code: '"\\ud83d"', + errors: [ + { + messageId: "loneSurrogate", + line: 1, + column: 1, + endLine: 1, + endColumn: 9, + }, + ], + }, + { + code: '"\udd25"', + errors: [ + { + messageId: "loneSurrogate", + line: 1, + column: 1, + endLine: 1, + endColumn: 4, + }, + ], + }, + { + code: '"\\udd25"', + errors: [ + { + messageId: "loneSurrogate", + line: 1, + column: 1, + endLine: 1, + endColumn: 9, + }, + ], + }, + { + code: '"\ud83d\ud83d"', + errors: [ + { + messageId: "loneSurrogate", + line: 1, + column: 1, + endLine: 1, + endColumn: 5, + }, + ], + }, + ], +}); From 3f35f97178897ae5987c80fa9f4599d515541f03 Mon Sep 17 00:00:00 2001 From: Bradley Farias Date: Mon, 7 Oct 2024 17:42:09 -0500 Subject: [PATCH 2/3] Update src/rules/no-unsafe-values.js Co-authored-by: Nicholas C. Zakas --- src/rules/no-unsafe-values.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/no-unsafe-values.js b/src/rules/no-unsafe-values.js index 8fb9686..5a38394 100644 --- a/src/rules/no-unsafe-values.js +++ b/src/rules/no-unsafe-values.js @@ -1,5 +1,5 @@ /** - * @fileoverview Rule to unsafe values in JSON. + * @fileoverview Rule to detect unsafe values in JSON. * @author Bradley Meck Farias */ From fd0ac0bc87cc18acfd637bc9f4bc01e4525e4026 Mon Sep 17 00:00:00 2001 From: Bradley Meck Farias Date: Mon, 7 Oct 2024 17:45:18 -0500 Subject: [PATCH 3/3] fixups --- src/rules/no-unsafe-values.js | 8 +++++++- tests/rules/no-unsafe-values.test.js | 9 ++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/rules/no-unsafe-values.js b/src/rules/no-unsafe-values.js index 5a38394..85a21f5 100644 --- a/src/rules/no-unsafe-values.js +++ b/src/rules/no-unsafe-values.js @@ -13,7 +13,7 @@ export default { messages: { unsafeNumber: "Number outside safe range found.", - loneSurrogate: "Lone surrogate found.", + loneSurrogate: "Lone surrogate '{{ surrogate }}' found.", }, }, @@ -44,6 +44,12 @@ export default { context.report({ loc: node.loc, messageId: "loneSurrogate", + data: { + surrogate: JSON.stringify(match[0]).slice( + 1, + -1, + ), + }, }); } match = surrogatePattern.exec(node.value); diff --git a/tests/rules/no-unsafe-values.test.js b/tests/rules/no-unsafe-values.test.js index 2052b8f..4cc9426 100644 --- a/tests/rules/no-unsafe-values.test.js +++ b/tests/rules/no-unsafe-values.test.js @@ -113,7 +113,14 @@ ruleTester.run("no-unsafe-values", rule, { code: '"\ud83d\ud83d"', errors: [ { - messageId: "loneSurrogate", + message: "Lone surrogate '\\ud83d' found.", + line: 1, + column: 1, + endLine: 1, + endColumn: 5, + }, + { + message: "Lone surrogate '\\ud83d' found.", line: 1, column: 1, endLine: 1,