Skip to content

Commit b3af910

Browse files
authored
feat: add jsonc/no-irregular-whitespace rule (#199)
* feat: add `jsonc/no-irregular-whitespace` rule * Create shiny-dodos-relax.md
1 parent 5b79da2 commit b3af910

File tree

9 files changed

+343
-2
lines changed

9 files changed

+343
-2
lines changed

.changeset/shiny-dodos-relax.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-jsonc": minor
3+
---
4+
5+
feat: add `jsonc/no-irregular-whitespace` rule

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ The rules with the following star :star: are included in the config.
212212
| [jsonc/key-spacing](https://ota-meshi.github.io/eslint-plugin-jsonc/rules/key-spacing.html) | enforce consistent spacing between keys and values in object literal properties | :wrench: | | | |
213213
| [jsonc/no-dupe-keys](https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-dupe-keys.html) | disallow duplicate keys in object literals | | :star: | :star: | :star: |
214214
| [jsonc/no-floating-decimal](https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-floating-decimal.html) | disallow leading or trailing decimal points in numeric literals | :wrench: | :star: | :star: | |
215+
| [jsonc/no-irregular-whitespace](https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-irregular-whitespace.html) | disallow irregular whitespace | | | | |
215216
| [jsonc/no-multi-str](https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-multi-str.html) | disallow multiline strings | | :star: | :star: | |
216217
| [jsonc/no-octal-escape](https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-octal-escape.html) | disallow octal escape sequences in string literals | | | | |
217218
| [jsonc/no-octal](https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-octal.html) | disallow legacy octal literals | | :star: | :star: | :star: |

docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ The rules with the following star :star: are included in the `plugin:jsonc/recom
5050
| [jsonc/key-spacing](./key-spacing.md) | enforce consistent spacing between keys and values in object literal properties | :wrench: | | | |
5151
| [jsonc/no-dupe-keys](./no-dupe-keys.md) | disallow duplicate keys in object literals | | :star: | :star: | :star: |
5252
| [jsonc/no-floating-decimal](./no-floating-decimal.md) | disallow leading or trailing decimal points in numeric literals | :wrench: | :star: | :star: | |
53+
| [jsonc/no-irregular-whitespace](./no-irregular-whitespace.md) | disallow irregular whitespace | | | | |
5354
| [jsonc/no-multi-str](./no-multi-str.md) | disallow multiline strings | | :star: | :star: | |
5455
| [jsonc/no-octal-escape](./no-octal-escape.md) | disallow octal escape sequences in string literals | | | | |
5556
| [jsonc/no-octal](./no-octal.md) | disallow legacy octal literals | | :star: | :star: | :star: |

docs/rules/key-spacing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ This rule enforces consistent spacing between keys and values in object literal
4747
}
4848
```
4949

50-
Same as [key-spacing] rule option. See [here](https://eslint.org/docs/rules/key-spacing#options) for details.
50+
Same as [key-spacing] rule option. See [here](https://eslint.org/docs/rules/key-spacing#options) for details.
5151

5252
## :couple: Related rules
5353

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
---
2+
pageClass: "rule-details"
3+
sidebarDepth: 0
4+
title: "jsonc/no-irregular-whitespace"
5+
description: "disallow irregular whitespace"
6+
---
7+
8+
# jsonc/no-irregular-whitespace
9+
10+
> disallow irregular whitespace
11+
12+
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> **_This rule has not been released yet._** </badge>
13+
14+
## :book: Rule Details
15+
16+
This rule is aimed at catching invalid whitespace that is not a normal tab and space.
17+
18+
<eslint-code-block>
19+
20+
<!-- eslint-skip -->
21+
22+
```json
23+
/* eslint jsonc/no-irregular-whitespace: 'error' */
24+
{
25+
/* ✓ GOOD */
26+
"GOOD": " ",
27+
28+
/* ✗ BAD */
29+
"BAD": "foo",
30+
}
31+
```
32+
33+
</eslint-code-block>
34+
35+
ESLint core [no-irregular-whitespace] rule don't work well in JSON. Turn off that rule in JSON files and use `jsonc/no-irregular-whitespace` rule.
36+
37+
## :wrench: Options
38+
39+
Nothing.
40+
41+
```json
42+
{
43+
"overrides": [
44+
{
45+
"files": ["*.json", "*.json5"],
46+
"rules": {
47+
"no-irregular-whitespace": "off",
48+
"jsonc/no-irregular-whitespace": [
49+
"error",
50+
{
51+
"skipStrings": true,
52+
"skipComments": false,
53+
"skipRegExps": false,
54+
"skipTemplates": false
55+
}
56+
]
57+
}
58+
}
59+
]
60+
}
61+
```
62+
63+
Same as [no-irregular-whitespace] rule option. See [here](https://eslint.org/docs/rules/no-irregular-whitespace#options) for details.
64+
65+
## :couple: Related rules
66+
67+
- [no-irregular-whitespace]
68+
69+
[no-irregular-whitespace]: https://eslint.org/docs/rules/no-irregular-whitespace
70+
71+
## :mag: Implementation
72+
73+
- [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-irregular-whitespace.ts)
74+
- [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-irregular-whitespace.ts)
75+
76+
<sup>Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/no-irregular-whitespace)</sup>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { createRule, defineWrapperListener, getCoreRule } from "../utils";
2+
const coreRule = getCoreRule("no-irregular-whitespace");
3+
4+
export default createRule("no-irregular-whitespace", {
5+
meta: {
6+
docs: {
7+
description: "disallow irregular whitespace",
8+
// TODO: We will switch this in the next major version.
9+
recommended: null,
10+
// recommended: ["json", "jsonc", "json5"], // TODO: We need to turn off core `no-irregular-whitespace` rule in shared config.
11+
extensionRule: true,
12+
layout: false,
13+
},
14+
fixable: coreRule.meta?.fixable,
15+
hasSuggestions: (coreRule.meta as any)?.hasSuggestions,
16+
schema: coreRule.meta!.schema!,
17+
messages: coreRule.meta!.messages!,
18+
type: coreRule.meta!.type!,
19+
},
20+
create(context) {
21+
return defineWrapperListener(coreRule, context, context.options);
22+
},
23+
});

lib/utils/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export function defineWrapperListener(
8181
continue;
8282
}
8383
const jsonKey = key.replace(
84-
/(?:^|\b)(ExpressionStatement|ArrayExpression|ObjectExpression|Property|Identifier|Literal|UnaryExpression)(?:\b|$)/gu,
84+
/(?:^|\b)(ExpressionStatement|(?:Template)?Literal|(?:Array|Object|Unary)Expression|Property|Identifier|TemplateElement)(?:\b|$)/gu,
8585
"JSON$1"
8686
);
8787
jsonListener[jsonKey] = function (node: AST.JSONNode, ...args) {

lib/utils/rules.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import noEscapeSequenceInIdentifier from "../rules/no-escape-sequence-in-identif
1717
import noFloatingDecimal from "../rules/no-floating-decimal";
1818
import noHexadecimalNumericLiterals from "../rules/no-hexadecimal-numeric-literals";
1919
import noInfinity from "../rules/no-infinity";
20+
import noIrregularWhitespace from "../rules/no-irregular-whitespace";
2021
import noMultiStr from "../rules/no-multi-str";
2122
import noNan from "../rules/no-nan";
2223
import noNumberProps from "../rules/no-number-props";
@@ -62,6 +63,7 @@ export const rules = [
6263
noFloatingDecimal,
6364
noHexadecimalNumericLiterals,
6465
noInfinity,
66+
noIrregularWhitespace,
6567
noMultiStr,
6668
noNan,
6769
noNumberProps,
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
import { RuleTester } from "eslint";
2+
import rule from "../../../lib/rules/no-irregular-whitespace";
3+
4+
const tester = new RuleTester({
5+
parser: require.resolve("jsonc-eslint-parser"),
6+
parserOptions: {
7+
ecmaVersion: 2020,
8+
},
9+
});
10+
11+
tester.run("no-irregular-whitespace", rule as any, {
12+
valid: [
13+
`"\u0020"`,
14+
`"\u0009"`,
15+
`"\\u000B"`,
16+
`["\u0009"]`,
17+
`["\\u000B"]`,
18+
`{"\u0009": "\u0009"}`,
19+
`{"\\u000B": "\\u000B"}`,
20+
21+
// String
22+
`"\u000B"`,
23+
`["\u000B"]`,
24+
`{"\u000B": "\u000B"}`,
25+
{
26+
code: `"\u000B"`,
27+
options: [{ skipStrings: true }],
28+
},
29+
{
30+
code: `["\u000B"]`,
31+
options: [{ skipStrings: true }],
32+
},
33+
{
34+
code: `{"\u000B": "\u000B"}`,
35+
options: [{ skipStrings: true }],
36+
},
37+
// Templates
38+
{
39+
code: `\`\u000B\``,
40+
options: [{ skipTemplates: true }],
41+
},
42+
{
43+
code: `[\`\u000B\`]`,
44+
options: [{ skipTemplates: true }],
45+
},
46+
{
47+
code: `{"\u000B": \`\u000B\`}`,
48+
options: [{ skipTemplates: true }],
49+
},
50+
// RegExps
51+
{
52+
code: `/\u000B/`,
53+
options: [{ skipRegExps: true }],
54+
},
55+
{
56+
code: `[/\u000B/]`,
57+
options: [{ skipRegExps: true }],
58+
},
59+
{
60+
code: `{"\u000B": /\u000B/}`,
61+
options: [{ skipRegExps: true }],
62+
},
63+
// Comments
64+
{
65+
code: `{} // \u000B`,
66+
options: [{ skipComments: true }],
67+
},
68+
],
69+
invalid: [
70+
{
71+
code: `{"\u000B": [\`\u000B\`, /\u000B/]} \u000B // \u000B`,
72+
errors: [
73+
{
74+
message: "Irregular whitespace not allowed.",
75+
line: 1,
76+
column: 9,
77+
},
78+
{
79+
message: "Irregular whitespace not allowed.",
80+
line: 1,
81+
column: 14,
82+
},
83+
{
84+
message: "Irregular whitespace not allowed.",
85+
line: 1,
86+
column: 19,
87+
},
88+
{
89+
message: "Irregular whitespace not allowed.",
90+
line: 1,
91+
column: 24,
92+
},
93+
],
94+
},
95+
{
96+
code: `{"\u000B": [\`\u000B\`, /\u000B/]} \u000B // \u000B`,
97+
options: [
98+
{
99+
skipStrings: true,
100+
skipComments: true,
101+
skipRegExps: true,
102+
skipTemplates: true,
103+
},
104+
],
105+
errors: [
106+
{
107+
message: "Irregular whitespace not allowed.",
108+
line: 1,
109+
column: 19,
110+
},
111+
],
112+
},
113+
// String
114+
{
115+
code: `{"\u000B": "\u000B"}`,
116+
options: [{ skipStrings: false }],
117+
errors: [
118+
{
119+
message: "Irregular whitespace not allowed.",
120+
line: 1,
121+
column: 3,
122+
},
123+
{
124+
message: "Irregular whitespace not allowed.",
125+
line: 1,
126+
column: 8,
127+
},
128+
],
129+
},
130+
{
131+
code: `["\u000B"]`,
132+
options: [{ skipStrings: false }],
133+
errors: [
134+
{
135+
message: "Irregular whitespace not allowed.",
136+
line: 1,
137+
column: 3,
138+
},
139+
],
140+
},
141+
{
142+
code: `"\u000B"`,
143+
options: [{ skipStrings: false }],
144+
errors: [
145+
{
146+
message: "Irregular whitespace not allowed.",
147+
line: 1,
148+
column: 2,
149+
},
150+
],
151+
},
152+
// Templates
153+
{
154+
code: `\`\u000B\``,
155+
options: [{ skipTemplates: false }],
156+
errors: [
157+
{
158+
message: "Irregular whitespace not allowed.",
159+
line: 1,
160+
column: 2,
161+
},
162+
],
163+
},
164+
{
165+
code: `[\`\u000B\`]`,
166+
options: [{ skipTemplates: false }],
167+
errors: [
168+
{
169+
message: "Irregular whitespace not allowed.",
170+
line: 1,
171+
column: 3,
172+
},
173+
],
174+
},
175+
{
176+
code: `{"\u000B": \`\u000B\`}`,
177+
options: [{ skipTemplates: false }],
178+
errors: [
179+
{
180+
message: "Irregular whitespace not allowed.",
181+
line: 1,
182+
column: 8,
183+
},
184+
],
185+
},
186+
// RegExps
187+
{
188+
code: `/\u000B/`,
189+
options: [{ skipRegExps: false }],
190+
errors: [
191+
{
192+
message: "Irregular whitespace not allowed.",
193+
line: 1,
194+
column: 2,
195+
},
196+
],
197+
},
198+
{
199+
code: `[/\u000B/]`,
200+
options: [{ skipRegExps: false }],
201+
errors: [
202+
{
203+
message: "Irregular whitespace not allowed.",
204+
line: 1,
205+
column: 3,
206+
},
207+
],
208+
},
209+
{
210+
code: `{"\u000B": /\u000B/}`,
211+
options: [{ skipRegExps: false }],
212+
errors: [
213+
{
214+
message: "Irregular whitespace not allowed.",
215+
line: 1,
216+
column: 8,
217+
},
218+
],
219+
},
220+
// Comments
221+
{
222+
code: `{} // \u000B`,
223+
options: [{ skipComments: false }],
224+
errors: [
225+
{
226+
message: "Irregular whitespace not allowed.",
227+
line: 1,
228+
column: 7,
229+
},
230+
],
231+
},
232+
],
233+
});

0 commit comments

Comments
 (0)