Skip to content

Commit fd6ed35

Browse files
authored
Improve error messages in jsonc/valid-json-number rule (#40)
1 parent 3f03f73 commit fd6ed35

File tree

2 files changed

+96
-13
lines changed

2 files changed

+96
-13
lines changed

lib/rules/valid-json-number.ts

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { Rule } from "eslint"
12
import type { AST } from "jsonc-eslint-parser"
23
import { isNumberIdentifier } from "jsonc-eslint-parser"
34
import type { RuleListener } from "../types"
@@ -7,9 +8,6 @@ import { createRule } from "../utils"
78
* Checks if the given string is valid number as JSON.
89
*/
910
function isValidNumber(text: string): boolean {
10-
if (text.startsWith(".") || text.endsWith(".")) {
11-
return false
12-
}
1311
try {
1412
JSON.parse(text)
1513
} catch {
@@ -32,6 +30,13 @@ export default createRule("valid-json-number", {
3230
invalidSpace: "Spaces after minus sign are not allowed in JSON.",
3331
invalidPlus: "Plus signs are not allowed in JSON.",
3432
invalidIdentifier: "`{{name}}` are not allowed in JSON.",
33+
invalidLeadingDecimalPoint:
34+
"Leading decimal point is not allowed in JSON.",
35+
invalidTrailingDecimalPoint:
36+
"Trailing decimal point is not allowed in JSON.",
37+
invalidHex: "Hexadecimal literals are not allowed in JSON.",
38+
invalidOctal: "Octal literals are not allowed in JSON.",
39+
invalidBinary: "Binary literals are not allowed in JSON.",
3540
},
3641
type: "problem",
3742
},
@@ -83,17 +88,52 @@ export default createRule("valid-json-number", {
8388
return
8489
}
8590
const text = sourceCode.text.slice(...node.range)
86-
if (!isValidNumber(text)) {
91+
92+
if (text.startsWith(".")) {
8793
context.report({
8894
loc: node.loc,
89-
messageId: "invalid",
95+
messageId: "invalidLeadingDecimalPoint",
9096
fix(fixer) {
91-
return fixer.replaceTextRange(
92-
node.range,
93-
`${node.value}`,
94-
)
97+
return fixer.insertTextBeforeRange(node.range, "0")
9598
},
9699
})
100+
return
101+
}
102+
if (text.endsWith(".")) {
103+
context.report({
104+
loc: node.loc,
105+
messageId: "invalidTrailingDecimalPoint",
106+
fix(fixer) {
107+
return fixer.removeRange([
108+
node.range[1] - 1,
109+
node.range[1],
110+
])
111+
},
112+
})
113+
return
114+
}
115+
if (
116+
text.startsWith("0x") ||
117+
text.startsWith("0o") ||
118+
text.startsWith("0b")
119+
) {
120+
context.report({
121+
loc: node.loc,
122+
messageId: text.startsWith("0x")
123+
? "invalidHex"
124+
: text.startsWith("0o")
125+
? "invalidOctal"
126+
: "invalidBinary",
127+
fix: buildFix(node),
128+
})
129+
return
130+
}
131+
if (!isValidNumber(text)) {
132+
context.report({
133+
loc: node.loc,
134+
messageId: "invalid",
135+
fix: buildFix(node),
136+
})
97137
}
98138
},
99139
JSONIdentifier(node: AST.JSONIdentifier) {
@@ -109,5 +149,16 @@ export default createRule("valid-json-number", {
109149
})
110150
},
111151
}
152+
153+
/**
154+
* Build fixer for number
155+
*/
156+
function buildFix(
157+
node: AST.JSONLiteral,
158+
): (fixer: Rule.RuleFixer) => Rule.Fix {
159+
return (fixer) => {
160+
return fixer.replaceTextRange(node.range, `${node.value}`)
161+
}
162+
}
112163
},
113164
})

tests/lib/rules/valid-json-number.ts

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import rule from "../../../lib/rules/valid-json-number"
33

44
const tester = new RuleTester({
55
parser: require.resolve("jsonc-eslint-parser"),
6+
parserOptions: {
7+
ecmaVersion: 2020,
8+
},
69
})
710

811
tester.run("valid-json-number", rule as any, {
@@ -22,7 +25,7 @@ tester.run("valid-json-number", rule as any, {
2225
output: "[0.4, 42]",
2326
errors: [
2427
{
25-
message: "Invalid number for JSON.",
28+
message: "Leading decimal point is not allowed in JSON.",
2629
line: 1,
2730
column: 2,
2831
endLine: 1,
@@ -40,7 +43,7 @@ tester.run("valid-json-number", rule as any, {
4043
{
4144
code: "123.",
4245
output: "123",
43-
errors: ["Invalid number for JSON."],
46+
errors: ["Trailing decimal point is not allowed in JSON."],
4447
},
4548
{
4649
filename: "test.json5",
@@ -114,19 +117,48 @@ tester.run("valid-json-number", rule as any, {
114117
output: "291",
115118
errors: [
116119
{
117-
message: "Invalid number for JSON.",
120+
message: "Hexadecimal literals are not allowed in JSON.",
118121
line: 1,
119122
column: 1,
120123
endColumn: 6,
121124
},
122125
],
123126
},
127+
{
128+
code: "[-0x123, +0x123]",
129+
output: "[-291, 0x123]",
130+
errors: [
131+
"Hexadecimal literals are not allowed in JSON.",
132+
"Plus signs are not allowed in JSON.",
133+
"Hexadecimal literals are not allowed in JSON.",
134+
],
135+
},
136+
{
137+
code: "[0o123,-0o123,+0o123]",
138+
output: "[83,-83,0o123]",
139+
errors: [
140+
"Octal literals are not allowed in JSON.",
141+
"Octal literals are not allowed in JSON.",
142+
"Plus signs are not allowed in JSON.",
143+
"Octal literals are not allowed in JSON.",
144+
],
145+
},
146+
{
147+
code: "[0b1001,-0b1001,+0b1001]",
148+
output: "[9,-9,0b1001]",
149+
errors: [
150+
"Binary literals are not allowed in JSON.",
151+
"Binary literals are not allowed in JSON.",
152+
"Plus signs are not allowed in JSON.",
153+
"Binary literals are not allowed in JSON.",
154+
],
155+
},
124156
{
125157
filename: "test.vue",
126158
code: `<custom-block lang="json">0x123</custom-block>`,
127159
output: `<custom-block lang="json">291</custom-block>`,
128160
parser: require.resolve("vue-eslint-parser"),
129-
errors: ["Invalid number for JSON."],
161+
errors: ["Hexadecimal literals are not allowed in JSON."],
130162
},
131163
],
132164
})

0 commit comments

Comments
 (0)