Skip to content

Commit 8a536d2

Browse files
authored
fix: program crashes in no-unsafe-values (#194)
1 parent 6a9abba commit 8a536d2

File tree

4 files changed

+176
-6
lines changed

4 files changed

+176
-6
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,5 +67,10 @@ package-lock.json
6767
# Build
6868
src/build
6969

70+
# Local test files
71+
test.json
72+
test.jsonc
73+
test.json5
74+
7075
# Automatically generated files by GitHub Actions workflow
7176
/.shared-workflows

eslint.config.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,18 @@ export default defineConfig([
103103
language: "json/json",
104104
extends: ["json/recommended"],
105105
},
106+
{
107+
name: "json/jsonc",
108+
plugins: { json },
109+
files: ["**/*.jsonc"],
110+
language: "json/jsonc",
111+
extends: ["json/recommended"],
112+
},
113+
{
114+
name: "json/json5",
115+
plugins: { json },
116+
files: ["**/*.json5"],
117+
language: "json/json5",
118+
extends: ["json/recommended"],
119+
},
106120
]);

src/rules/no-unsafe-values.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@
2121
* This rule is based on the JSON grammar from RFC 8259, section 6.
2222
* https://tools.ietf.org/html/rfc8259#section-6
2323
*
24+
* Also, this rule is based on the JSON5 grammar from json5.org, section 6.
25+
* https://spec.json5.org/#numbers
26+
*
2427
* We separately capture the integer and fractional parts of a number, so that
2528
* we can check for unsafe numbers that will evaluate to Infinity.
2629
*/
27-
const NUMBER = /^-?(?<int>0|([1-9]\d*))(?:\.(?<frac>\d+))?(?:e[+-]?\d+)?$/iu;
30+
const NUMBER =
31+
/^[+-]?(?<int>0|([1-9]\d*))?(?:\.(?<frac>\d*))?(?:e[+-]?\d+)?$/iu;
2832
const NON_ZERO = /[1-9]/u;
2933

3034
//-----------------------------------------------------------------------------
@@ -71,7 +75,10 @@ const rule = {
7175
// fraction or non-zero part before the e-, this is a very small
7276
// number that doesn't fit inside an f64.
7377
const match = value.match(NUMBER);
74-
// assert(match, "If the regex is right, match is always truthy")
78+
79+
if (match === null) {
80+
return;
81+
}
7582

7683
// If any part of the number other than the exponent has a
7784
// non-zero digit in it, this number was not intended to be
@@ -99,7 +106,7 @@ const rule = {
99106
});
100107
}
101108
} else {
102-
// Floating point. Check for subnormal.
109+
// Floating point. Check for subnormal.
103110
const buffer = new ArrayBuffer(8);
104111
const view = new DataView(buffer);
105112
view.setFloat64(0, node.value, false);
@@ -128,8 +135,11 @@ const rule = {
128135
// match any low surrogate not already matched
129136
const surrogatePattern =
130137
/[\uD800-\uDBFF][\uDC00-\uDFFF]?|[\uDC00-\uDFFF]/gu;
131-
let match = surrogatePattern.exec(node.value);
132-
while (match) {
138+
139+
/** @type {RegExpExecArray | null} */
140+
let match;
141+
142+
while ((match = surrogatePattern.exec(node.value)) !== null) {
133143
// only need to report non-paired surrogates
134144
if (match[0].length < 2) {
135145
context.report({
@@ -143,7 +153,6 @@ const rule = {
143153
},
144154
});
145155
}
146-
match = surrogatePattern.exec(node.value);
147156
}
148157
},
149158
};

tests/rules/no-unsafe-values.test.js

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,38 @@ ruleTester.run("no-unsafe-values", rule, {
3838
"0.00000",
3939
"0e0000000",
4040
"0.00000e0000",
41+
{
42+
code: "0x0",
43+
language: "json/json5",
44+
},
45+
{
46+
code: "0X0",
47+
language: "json/json5",
48+
},
49+
{
50+
code: "+0x0",
51+
language: "json/json5",
52+
},
53+
{
54+
code: "+0X0",
55+
language: "json/json5",
56+
},
57+
{
58+
code: "-0x0",
59+
language: "json/json5",
60+
},
61+
{
62+
code: "-0X0",
63+
language: "json/json5",
64+
},
65+
{
66+
code: ".0",
67+
language: "json/json5",
68+
},
69+
{
70+
code: "0.",
71+
language: "json/json5",
72+
},
4173
],
4274
invalid: [
4375
{
@@ -155,6 +187,37 @@ ruleTester.run("no-unsafe-values", rule, {
155187
},
156188
],
157189
},
190+
{
191+
code: "1E-400",
192+
errors: [
193+
{
194+
messageId: "unsafeZero",
195+
data: {
196+
value: "1E-400",
197+
},
198+
line: 1,
199+
column: 1,
200+
endLine: 1,
201+
endColumn: 7,
202+
},
203+
],
204+
},
205+
{
206+
code: "+1e-400",
207+
language: "json/json5",
208+
errors: [
209+
{
210+
messageId: "unsafeZero",
211+
data: {
212+
value: "+1e-400",
213+
},
214+
line: 1,
215+
column: 1,
216+
endLine: 1,
217+
endColumn: 8,
218+
},
219+
],
220+
},
158221
{
159222
code: "-1e-400",
160223
errors: [
@@ -185,6 +248,53 @@ ruleTester.run("no-unsafe-values", rule, {
185248
},
186249
],
187250
},
251+
{
252+
code: "+0.01e-400",
253+
language: "json/json5",
254+
errors: [
255+
{
256+
messageId: "unsafeZero",
257+
data: {
258+
value: "+0.01e-400",
259+
},
260+
line: 1,
261+
column: 1,
262+
endLine: 1,
263+
endColumn: 11,
264+
},
265+
],
266+
},
267+
{
268+
code: "-0.01e-400",
269+
errors: [
270+
{
271+
messageId: "unsafeZero",
272+
data: {
273+
value: "-0.01e-400",
274+
},
275+
line: 1,
276+
column: 1,
277+
endLine: 1,
278+
endColumn: 11,
279+
},
280+
],
281+
},
282+
{
283+
code: ".01e-400",
284+
language: "json/json5",
285+
errors: [
286+
{
287+
messageId: "unsafeZero",
288+
data: {
289+
value: ".01e-400",
290+
},
291+
line: 1,
292+
column: 1,
293+
endLine: 1,
294+
endColumn: 9,
295+
},
296+
],
297+
},
188298
{
189299
code: "-10.2e-402",
190300
errors: [
@@ -200,6 +310,38 @@ ruleTester.run("no-unsafe-values", rule, {
200310
},
201311
],
202312
},
313+
{
314+
code: "+10.e-402",
315+
language: "json/json5",
316+
errors: [
317+
{
318+
messageId: "unsafeZero",
319+
data: {
320+
value: "+10.e-402",
321+
},
322+
line: 1,
323+
column: 1,
324+
endLine: 1,
325+
endColumn: 10,
326+
},
327+
],
328+
},
329+
{
330+
code: "-10.e-402",
331+
language: "json/json5",
332+
errors: [
333+
{
334+
messageId: "unsafeZero",
335+
data: {
336+
value: "-10.e-402",
337+
},
338+
line: 1,
339+
column: 1,
340+
endLine: 1,
341+
endColumn: 10,
342+
},
343+
],
344+
},
203345
{
204346
code: `0.${"0".repeat(400)}1`,
205347
errors: [

0 commit comments

Comments
 (0)