Skip to content

Commit

Permalink
feat: add jsonc/no-irregular-whitespace rule (#199)
Browse files Browse the repository at this point in the history
* feat: add `jsonc/no-irregular-whitespace` rule

* Create shiny-dodos-relax.md
  • Loading branch information
ota-meshi authored Oct 24, 2022
1 parent 5b79da2 commit b3af910
Show file tree
Hide file tree
Showing 9 changed files with 343 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/shiny-dodos-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-jsonc": minor
---

feat: add `jsonc/no-irregular-whitespace` rule
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ The rules with the following star :star: are included in the config.
| [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: | | | |
| [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: |
| [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: | |
| [jsonc/no-irregular-whitespace](https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-irregular-whitespace.html) | disallow irregular whitespace | | | | |
| [jsonc/no-multi-str](https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-multi-str.html) | disallow multiline strings | | :star: | :star: | |
| [jsonc/no-octal-escape](https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-octal-escape.html) | disallow octal escape sequences in string literals | | | | |
| [jsonc/no-octal](https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-octal.html) | disallow legacy octal literals | | :star: | :star: | :star: |
Expand Down
1 change: 1 addition & 0 deletions docs/rules/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ The rules with the following star :star: are included in the `plugin:jsonc/recom
| [jsonc/key-spacing](./key-spacing.md) | enforce consistent spacing between keys and values in object literal properties | :wrench: | | | |
| [jsonc/no-dupe-keys](./no-dupe-keys.md) | disallow duplicate keys in object literals | | :star: | :star: | :star: |
| [jsonc/no-floating-decimal](./no-floating-decimal.md) | disallow leading or trailing decimal points in numeric literals | :wrench: | :star: | :star: | |
| [jsonc/no-irregular-whitespace](./no-irregular-whitespace.md) | disallow irregular whitespace | | | | |
| [jsonc/no-multi-str](./no-multi-str.md) | disallow multiline strings | | :star: | :star: | |
| [jsonc/no-octal-escape](./no-octal-escape.md) | disallow octal escape sequences in string literals | | | | |
| [jsonc/no-octal](./no-octal.md) | disallow legacy octal literals | | :star: | :star: | :star: |
Expand Down
2 changes: 1 addition & 1 deletion docs/rules/key-spacing.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ This rule enforces consistent spacing between keys and values in object literal
}
```

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

## :couple: Related rules

Expand Down
76 changes: 76 additions & 0 deletions docs/rules/no-irregular-whitespace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
pageClass: "rule-details"
sidebarDepth: 0
title: "jsonc/no-irregular-whitespace"
description: "disallow irregular whitespace"
---

# jsonc/no-irregular-whitespace

> disallow irregular whitespace
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> **_This rule has not been released yet._** </badge>

## :book: Rule Details

This rule is aimed at catching invalid whitespace that is not a normal tab and space.

<eslint-code-block>

<!-- eslint-skip -->

```json
/* eslint jsonc/no-irregular-whitespace: 'error' */
{
/* ✓ GOOD */
"GOOD": " ",

/* ✗ BAD */
"BAD": "foo",
}
```

</eslint-code-block>

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.

## :wrench: Options

Nothing.

```json
{
"overrides": [
{
"files": ["*.json", "*.json5"],
"rules": {
"no-irregular-whitespace": "off",
"jsonc/no-irregular-whitespace": [
"error",
{
"skipStrings": true,
"skipComments": false,
"skipRegExps": false,
"skipTemplates": false
}
]
}
}
]
}
```

Same as [no-irregular-whitespace] rule option. See [here](https://eslint.org/docs/rules/no-irregular-whitespace#options) for details.

## :couple: Related rules

- [no-irregular-whitespace]

[no-irregular-whitespace]: https://eslint.org/docs/rules/no-irregular-whitespace

## :mag: Implementation

- [Rule source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/lib/rules/no-irregular-whitespace.ts)
- [Test source](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/tests/lib/rules/no-irregular-whitespace.ts)

<sup>Taken with ❤️ [from ESLint core](https://eslint.org/docs/rules/no-irregular-whitespace)</sup>
23 changes: 23 additions & 0 deletions lib/rules/no-irregular-whitespace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createRule, defineWrapperListener, getCoreRule } from "../utils";
const coreRule = getCoreRule("no-irregular-whitespace");

export default createRule("no-irregular-whitespace", {
meta: {
docs: {
description: "disallow irregular whitespace",
// TODO: We will switch this in the next major version.
recommended: null,
// recommended: ["json", "jsonc", "json5"], // TODO: We need to turn off core `no-irregular-whitespace` rule in shared config.
extensionRule: true,
layout: false,
},
fixable: coreRule.meta?.fixable,
hasSuggestions: (coreRule.meta as any)?.hasSuggestions,
schema: coreRule.meta!.schema!,
messages: coreRule.meta!.messages!,
type: coreRule.meta!.type!,
},
create(context) {
return defineWrapperListener(coreRule, context, context.options);
},
});
2 changes: 1 addition & 1 deletion lib/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export function defineWrapperListener(
continue;
}
const jsonKey = key.replace(
/(?:^|\b)(ExpressionStatement|ArrayExpression|ObjectExpression|Property|Identifier|Literal|UnaryExpression)(?:\b|$)/gu,
/(?:^|\b)(ExpressionStatement|(?:Template)?Literal|(?:Array|Object|Unary)Expression|Property|Identifier|TemplateElement)(?:\b|$)/gu,
"JSON$1"
);
jsonListener[jsonKey] = function (node: AST.JSONNode, ...args) {
Expand Down
2 changes: 2 additions & 0 deletions lib/utils/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import noEscapeSequenceInIdentifier from "../rules/no-escape-sequence-in-identif
import noFloatingDecimal from "../rules/no-floating-decimal";
import noHexadecimalNumericLiterals from "../rules/no-hexadecimal-numeric-literals";
import noInfinity from "../rules/no-infinity";
import noIrregularWhitespace from "../rules/no-irregular-whitespace";
import noMultiStr from "../rules/no-multi-str";
import noNan from "../rules/no-nan";
import noNumberProps from "../rules/no-number-props";
Expand Down Expand Up @@ -62,6 +63,7 @@ export const rules = [
noFloatingDecimal,
noHexadecimalNumericLiterals,
noInfinity,
noIrregularWhitespace,
noMultiStr,
noNan,
noNumberProps,
Expand Down
233 changes: 233 additions & 0 deletions tests/lib/rules/no-irregular-whitespace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
import { RuleTester } from "eslint";
import rule from "../../../lib/rules/no-irregular-whitespace";

const tester = new RuleTester({
parser: require.resolve("jsonc-eslint-parser"),
parserOptions: {
ecmaVersion: 2020,
},
});

tester.run("no-irregular-whitespace", rule as any, {
valid: [
`"\u0020"`,
`"\u0009"`,
`"\\u000B"`,
`["\u0009"]`,
`["\\u000B"]`,
`{"\u0009": "\u0009"}`,
`{"\\u000B": "\\u000B"}`,

// String
`"\u000B"`,
`["\u000B"]`,
`{"\u000B": "\u000B"}`,
{
code: `"\u000B"`,
options: [{ skipStrings: true }],
},
{
code: `["\u000B"]`,
options: [{ skipStrings: true }],
},
{
code: `{"\u000B": "\u000B"}`,
options: [{ skipStrings: true }],
},
// Templates
{
code: `\`\u000B\``,
options: [{ skipTemplates: true }],
},
{
code: `[\`\u000B\`]`,
options: [{ skipTemplates: true }],
},
{
code: `{"\u000B": \`\u000B\`}`,
options: [{ skipTemplates: true }],
},
// RegExps
{
code: `/\u000B/`,
options: [{ skipRegExps: true }],
},
{
code: `[/\u000B/]`,
options: [{ skipRegExps: true }],
},
{
code: `{"\u000B": /\u000B/}`,
options: [{ skipRegExps: true }],
},
// Comments
{
code: `{} // \u000B`,
options: [{ skipComments: true }],
},
],
invalid: [
{
code: `{"\u000B": [\`\u000B\`, /\u000B/]} \u000B // \u000B`,
errors: [
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 9,
},
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 14,
},
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 19,
},
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 24,
},
],
},
{
code: `{"\u000B": [\`\u000B\`, /\u000B/]} \u000B // \u000B`,
options: [
{
skipStrings: true,
skipComments: true,
skipRegExps: true,
skipTemplates: true,
},
],
errors: [
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 19,
},
],
},
// String
{
code: `{"\u000B": "\u000B"}`,
options: [{ skipStrings: false }],
errors: [
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 3,
},
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 8,
},
],
},
{
code: `["\u000B"]`,
options: [{ skipStrings: false }],
errors: [
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 3,
},
],
},
{
code: `"\u000B"`,
options: [{ skipStrings: false }],
errors: [
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 2,
},
],
},
// Templates
{
code: `\`\u000B\``,
options: [{ skipTemplates: false }],
errors: [
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 2,
},
],
},
{
code: `[\`\u000B\`]`,
options: [{ skipTemplates: false }],
errors: [
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 3,
},
],
},
{
code: `{"\u000B": \`\u000B\`}`,
options: [{ skipTemplates: false }],
errors: [
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 8,
},
],
},
// RegExps
{
code: `/\u000B/`,
options: [{ skipRegExps: false }],
errors: [
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 2,
},
],
},
{
code: `[/\u000B/]`,
options: [{ skipRegExps: false }],
errors: [
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 3,
},
],
},
{
code: `{"\u000B": /\u000B/}`,
options: [{ skipRegExps: false }],
errors: [
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 8,
},
],
},
// Comments
{
code: `{} // \u000B`,
options: [{ skipComments: false }],
errors: [
{
message: "Irregular whitespace not allowed.",
line: 1,
column: 7,
},
],
},
],
});

0 comments on commit b3af910

Please sign in to comment.