@codelaw/rules-js 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/LICENSE +23 -0
  2. package/NOTICE +10 -0
  3. package/README.md +57 -2
  4. package/codelaw-pack.toml +6 -0
  5. package/corpus.toml +76 -0
  6. package/data/globals/browser.json +1209 -0
  7. package/data/globals/commonjs.json +6 -0
  8. package/data/globals/jest.json +15 -0
  9. package/data/globals/mocha.json +22 -0
  10. package/data/globals/node.json +83 -0
  11. package/data/globals/serviceworker.json +328 -0
  12. package/data/globals/shared-node-browser.json +73 -0
  13. package/data/globals/vitest.json +19 -0
  14. package/data/globals/worker.json +349 -0
  15. package/package.json +14 -4
  16. package/presets/js/conventions.toml +6 -0
  17. package/presets/js/project.toml +4 -0
  18. package/presets/js/recommended.toml +67 -0
  19. package/presets/js/typescript.toml +7 -0
  20. package/rules/graph/no-unused-exports.md +135 -0
  21. package/rules/js/constructor-super.md +77 -0
  22. package/rules/js/exports-at-end.md +134 -0
  23. package/rules/js/for-direction.md +106 -0
  24. package/rules/js/getter-return.md +74 -0
  25. package/rules/js/import-groups.md +117 -0
  26. package/rules/js/no-async-promise-executor.md +95 -0
  27. package/rules/js/no-case-declarations.md +134 -0
  28. package/rules/js/no-class-assign.md +61 -0
  29. package/rules/js/no-compare-neg-zero.md +105 -0
  30. package/rules/js/no-cond-assign.md +135 -0
  31. package/rules/js/no-const-assign.md +61 -0
  32. package/rules/js/no-constant-binary-expression.md +83 -0
  33. package/rules/js/no-constant-condition.md +150 -0
  34. package/rules/js/no-control-regex.md +84 -0
  35. package/rules/js/no-debugger.md +99 -0
  36. package/rules/js/no-default-export.md +88 -0
  37. package/rules/js/no-delete-var.md +93 -0
  38. package/rules/js/no-dupe-args.md +61 -0
  39. package/rules/js/no-dupe-class-members.md +82 -0
  40. package/rules/js/no-dupe-else-if.md +113 -0
  41. package/rules/js/no-dupe-keys.md +66 -0
  42. package/rules/js/no-duplicate-case.md +137 -0
  43. package/rules/js/no-empty-character-class.md +98 -0
  44. package/rules/js/no-empty-pattern.md +86 -0
  45. package/rules/js/no-empty-static-block.md +99 -0
  46. package/rules/js/no-empty.md +116 -0
  47. package/rules/js/no-ex-assign.md +121 -0
  48. package/rules/js/no-extra-boolean-cast.md +107 -0
  49. package/rules/js/no-fallthrough.md +178 -0
  50. package/rules/js/no-func-assign.md +62 -0
  51. package/rules/js/no-global-assign.md +85 -0
  52. package/rules/js/no-import-assign.md +60 -0
  53. package/rules/js/no-invalid-regexp.md +86 -0
  54. package/rules/js/no-irregular-whitespace.md +87 -0
  55. package/rules/js/no-loss-of-precision.md +82 -0
  56. package/rules/js/no-misleading-character-class.md +83 -0
  57. package/rules/js/no-new-native-nonconstructor.md +55 -0
  58. package/rules/js/no-nonoctal-decimal-escape.md +84 -0
  59. package/rules/js/no-obj-calls.md +61 -0
  60. package/rules/js/no-octal.md +84 -0
  61. package/rules/js/no-prototype-builtins.md +99 -0
  62. package/rules/js/no-redeclare.md +61 -0
  63. package/rules/js/no-regex-spaces.md +75 -0
  64. package/rules/js/no-self-assign.md +91 -0
  65. package/rules/js/no-setter-return.md +69 -0
  66. package/rules/js/no-shadow-restricted-names.md +102 -0
  67. package/rules/js/no-sparse-arrays.md +82 -0
  68. package/rules/js/no-this-before-super.md +74 -0
  69. package/rules/js/no-unassigned-vars.md +102 -0
  70. package/rules/js/no-undef.md +76 -0
  71. package/rules/js/no-unexpected-multiline.md +91 -0
  72. package/rules/js/no-unreachable.md +59 -0
  73. package/rules/js/no-unsafe-finally.md +145 -0
  74. package/rules/js/no-unsafe-negation.md +71 -0
  75. package/rules/js/no-unsafe-optional-chaining.md +83 -0
  76. package/rules/js/no-unused-labels.md +102 -0
  77. package/rules/js/no-unused-private-class-members.md +126 -0
  78. package/rules/js/no-unused-vars.md +69 -0
  79. package/rules/js/no-useless-assignment.md +115 -0
  80. package/rules/js/no-useless-backreference.md +83 -0
  81. package/rules/js/no-useless-catch.md +105 -0
  82. package/rules/js/no-useless-escape.md +81 -0
  83. package/rules/js/no-var.md +76 -0
  84. package/rules/js/no-with.md +60 -0
  85. package/rules/js/prefer-const.md +83 -0
  86. package/rules/js/prefer-rest-params.md +103 -0
  87. package/rules/js/prefer-spread.md +95 -0
  88. package/rules/js/preserve-caught-error.md +122 -0
  89. package/rules/js/require-yield.md +107 -0
  90. package/rules/js/use-isnan.md +105 -0
  91. package/rules/js/valid-typeof.md +111 -0
@@ -0,0 +1,102 @@
1
+ ---
2
+ id: js/no-unused-labels
3
+ title: "Every label is used"
4
+ languages: [javascript, jsx, typescript, tsx]
5
+ fix: auto
6
+ stability: preview
7
+ ported_from: [eslint/no-unused-labels]
8
+ since: 0.1.0
9
+ ---
10
+
11
+ Every statement label is the target of a `break` or `continue`.
12
+
13
+ **Why:** An unused label is leftover from a refactor and makes the reader look for a jump that isn't
14
+ there.
15
+
16
+ ```codelaw
17
+ match:
18
+ kind: labeled_statement
19
+ all:
20
+ - has: { field: label, pattern: $L }
21
+ - has: { field: body, pattern: $BODY }
22
+ not:
23
+ has:
24
+ stopBy: end
25
+ any: [{ pattern: "break $L;" }, { pattern: "continue $L;" }]
26
+ message: "The label `$L` is never used"
27
+ fix: "$BODY"
28
+ ```
29
+
30
+ ## Examples
31
+
32
+ ### JavaScript
33
+
34
+ #### Don't
35
+
36
+ ```js
37
+ outer: for (const row of rows) {
38
+ draw(row);
39
+ }
40
+ ```
41
+
42
+ #### Do
43
+
44
+ ```js
45
+ for (const row of rows) {
46
+ draw(row);
47
+ }
48
+ ```
49
+
50
+ ### JSX
51
+
52
+ #### Don't
53
+
54
+ ```jsx
55
+ outer: for (const row of rows) {
56
+ draw(row);
57
+ }
58
+ ```
59
+
60
+ #### Do
61
+
62
+ ```jsx
63
+ for (const row of rows) {
64
+ draw(row);
65
+ }
66
+ ```
67
+
68
+ ### TypeScript
69
+
70
+ #### Don't
71
+
72
+ ```ts
73
+ outer: for (const row of rows) {
74
+ draw(row);
75
+ }
76
+ ```
77
+
78
+ #### Do
79
+
80
+ ```ts
81
+ for (const row of rows) {
82
+ draw(row);
83
+ }
84
+ ```
85
+
86
+ ### TSX
87
+
88
+ #### Don't
89
+
90
+ ```tsx
91
+ outer: for (const row of rows) {
92
+ draw(row);
93
+ }
94
+ ```
95
+
96
+ #### Do
97
+
98
+ ```tsx
99
+ for (const row of rows) {
100
+ draw(row);
101
+ }
102
+ ```
@@ -0,0 +1,126 @@
1
+ ---
2
+ id: js/no-unused-private-class-members
3
+ title: "Every private class member is read"
4
+ languages: [javascript, jsx, typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "removing a member may also remove writes that matter, so it's a reader's call"
7
+ stability: preview
8
+ ported_from: [eslint/no-unused-private-class-members]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A private field, method or accessor (`#name`) is read somewhere in its class; only being written
13
+ doesn't count.
14
+
15
+ **Why:** A private member nothing reads is dead code, since nothing outside the class can reach it.
16
+
17
+ ```codelaw
18
+ native: js/no-unused-private-class-members
19
+ ```
20
+
21
+ ## How to fix
22
+
23
+ 1. Check that nothing needs the member's value.
24
+ 2. Remove the member and the writes to it, or read it where it was meant to be used.
25
+
26
+ ## Examples
27
+
28
+ ### JavaScript
29
+
30
+ #### Don't
31
+
32
+ ```js
33
+ class Counter {
34
+ #count = 0;
35
+ #unused = 1;
36
+ get value() {
37
+ return this.#count;
38
+ }
39
+ }
40
+ ```
41
+
42
+ #### Do
43
+
44
+ ```js
45
+ class Counter {
46
+ #count = 0;
47
+ get value() {
48
+ return this.#count;
49
+ }
50
+ }
51
+ ```
52
+
53
+ ### JSX
54
+
55
+ #### Don't
56
+
57
+ ```jsx
58
+ class Counter {
59
+ #count = 0;
60
+ #unused = 1;
61
+ get value() {
62
+ return this.#count;
63
+ }
64
+ }
65
+ ```
66
+
67
+ #### Do
68
+
69
+ ```jsx
70
+ class Counter {
71
+ #count = 0;
72
+ get value() {
73
+ return this.#count;
74
+ }
75
+ }
76
+ ```
77
+
78
+ ### TypeScript
79
+
80
+ #### Don't
81
+
82
+ ```ts
83
+ class Counter {
84
+ #count = 0;
85
+ #unused = 1;
86
+ get value() {
87
+ return this.#count;
88
+ }
89
+ }
90
+ ```
91
+
92
+ #### Do
93
+
94
+ ```ts
95
+ class Counter {
96
+ #count = 0;
97
+ get value() {
98
+ return this.#count;
99
+ }
100
+ }
101
+ ```
102
+
103
+ ### TSX
104
+
105
+ #### Don't
106
+
107
+ ```tsx
108
+ class Counter {
109
+ #count = 0;
110
+ #unused = 1;
111
+ get value() {
112
+ return this.#count;
113
+ }
114
+ }
115
+ ```
116
+
117
+ #### Do
118
+
119
+ ```tsx
120
+ class Counter {
121
+ #count = 0;
122
+ get value() {
123
+ return this.#count;
124
+ }
125
+ }
126
+ ```
@@ -0,0 +1,69 @@
1
+ ---
2
+ id: js/no-unused-vars
3
+ title: "Every declared name is used"
4
+ languages: [javascript, jsx]
5
+ fix: manual
6
+ fix_reason: "removing a declaration can drop the side effects of its initialiser"
7
+ stability: preview
8
+ options:
9
+ vars: { type: string, default: all, description: "all, or local to skip module-level names" }
10
+ args: { type: string, default: after-used, description: "after-used, all or none" }
11
+ caughtErrors: { type: string, default: all, description: "all or none" }
12
+ ignoreRestSiblings: { type: boolean, default: false }
13
+ varsIgnorePattern: { type: string, description: "a regular expression of names to skip" }
14
+ argsIgnorePattern: { type: string }
15
+ caughtErrorsIgnorePattern: { type: string }
16
+ destructuredArrayIgnorePattern: { type: string }
17
+ ported_from: [eslint/no-unused-vars]
18
+ since: 0.1.0
19
+ ---
20
+
21
+ Every variable, function, class, import, parameter and caught error is read somewhere. Parameters
22
+ before the last used one are allowed (`args: after-used`).
23
+
24
+ **Why:** An unused declaration is either dead code or a sign the code doesn't do what it was meant
25
+ to.
26
+
27
+ ```codelaw
28
+ native: js/no-unused-vars
29
+ ```
30
+
31
+ ## How to fix
32
+
33
+ 1. Check the initialiser has no side effect that matters.
34
+ 2. Remove the declaration, or use it where it was meant to be used.
35
+ 3. For a parameter that must stay for its position, prefix it with `_` and set `argsIgnorePattern: "^_"`.
36
+
37
+ ## Examples
38
+
39
+ ### JavaScript
40
+
41
+ #### Don't
42
+
43
+ ```js
44
+ import { readFile, writeFile } from "node:fs";
45
+ export const load = (path) => readFile(path);
46
+ ```
47
+
48
+ #### Do
49
+
50
+ ```js
51
+ import { readFile } from "node:fs";
52
+ export const load = (path) => readFile(path);
53
+ ```
54
+
55
+ ### JSX
56
+
57
+ #### Don't
58
+
59
+ ```jsx
60
+ import { readFile, writeFile } from "node:fs";
61
+ export const load = (path) => readFile(path);
62
+ ```
63
+
64
+ #### Do
65
+
66
+ ```jsx
67
+ import { readFile } from "node:fs";
68
+ export const load = (path) => readFile(path);
69
+ ```
@@ -0,0 +1,115 @@
1
+ ---
2
+ id: js/no-useless-assignment
3
+ title: "No value is stored that nothing reads"
4
+ languages: [javascript, jsx, typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "whether the store is dead or the read is missing needs the author"
7
+ stability: preview
8
+ ported_from: [eslint/no-useless-assignment]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A variable is not assigned a value that is overwritten before anything reads it, or that nothing
13
+ reads after the assignment.
14
+
15
+ **Why:** A dead store is wasted work and usually means the code reads the wrong variable.
16
+
17
+ ```codelaw
18
+ native: js/no-useless-assignment
19
+ ```
20
+
21
+ ## How to fix
22
+
23
+ 1. If the value is not needed, remove the assignment.
24
+ 2. If it should be read, read it where it was meant to be used.
25
+
26
+ ## Examples
27
+
28
+ ### JavaScript
29
+
30
+ #### Don't
31
+
32
+ ```js
33
+ function total(items) {
34
+ let sum = 0;
35
+ sum = items.length;
36
+ return sum;
37
+ }
38
+ ```
39
+
40
+ #### Do
41
+
42
+ ```js
43
+ function total(items) {
44
+ const sum = items.length;
45
+ return sum;
46
+ }
47
+ ```
48
+
49
+ ### JSX
50
+
51
+ #### Don't
52
+
53
+ ```jsx
54
+ function total(items) {
55
+ let sum = 0;
56
+ sum = items.length;
57
+ return sum;
58
+ }
59
+ ```
60
+
61
+ #### Do
62
+
63
+ ```jsx
64
+ function total(items) {
65
+ const sum = items.length;
66
+ return sum;
67
+ }
68
+ ```
69
+
70
+ ### TypeScript
71
+
72
+ #### Don't
73
+
74
+ ```ts
75
+ function total(items) {
76
+ let sum = 0;
77
+ sum = items.length;
78
+ return sum;
79
+ }
80
+ ```
81
+
82
+ #### Do
83
+
84
+ ```ts
85
+ function total(items) {
86
+ const sum = items.length;
87
+ return sum;
88
+ }
89
+ ```
90
+
91
+ ### TSX
92
+
93
+ #### Don't
94
+
95
+ ```tsx
96
+ function total(items) {
97
+ let sum = 0;
98
+ sum = items.length;
99
+ return sum;
100
+ }
101
+ ```
102
+
103
+ #### Do
104
+
105
+ ```tsx
106
+ function total(items) {
107
+ const sum = items.length;
108
+ return sum;
109
+ }
110
+ ```
111
+
112
+ ## Differences from the source
113
+
114
+ Only stores a straight-line reading proves dead are reported: an overwrite in the same block, or a
115
+ last assignment outside any loop. A variable a nested function touches is skipped.
@@ -0,0 +1,83 @@
1
+ ---
2
+ id: js/no-useless-backreference
3
+ title: "No backreference that can only match the empty string"
4
+ languages: [javascript, jsx, typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "what the reference was meant to repeat needs the author"
7
+ stability: preview
8
+ ported_from: [eslint/no-useless-backreference]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A backreference such as `\1` or `\k<name>` appears after its group closes, in the same alternative,
13
+ and not into a negative lookaround.
14
+
15
+ **Why:** A backreference that comes first, sits inside its own group or in another alternative
16
+ always matches the empty string.
17
+
18
+ ```codelaw
19
+ native: js/no-useless-backreference
20
+ ```
21
+
22
+ ## How to fix
23
+
24
+ 1. Move the backreference after the group it refers to.
25
+ 2. Or remove it if it was meant to be literal text.
26
+
27
+ ## Examples
28
+
29
+ ### JavaScript
30
+
31
+ #### Don't
32
+
33
+ ```js
34
+ const re = /\1(a)/;
35
+ ```
36
+
37
+ #### Do
38
+
39
+ ```js
40
+ const re = /(a)\1/;
41
+ ```
42
+
43
+ ### JSX
44
+
45
+ #### Don't
46
+
47
+ ```jsx
48
+ const re = /\1(a)/;
49
+ ```
50
+
51
+ #### Do
52
+
53
+ ```jsx
54
+ const re = /(a)\1/;
55
+ ```
56
+
57
+ ### TypeScript
58
+
59
+ #### Don't
60
+
61
+ ```ts
62
+ const re = /\1(a)/;
63
+ ```
64
+
65
+ #### Do
66
+
67
+ ```ts
68
+ const re = /(a)\1/;
69
+ ```
70
+
71
+ ### TSX
72
+
73
+ #### Don't
74
+
75
+ ```tsx
76
+ const re = /\1(a)/;
77
+ ```
78
+
79
+ #### Do
80
+
81
+ ```tsx
82
+ const re = /(a)\1/;
83
+ ```
@@ -0,0 +1,105 @@
1
+ ---
2
+ id: js/no-useless-catch
3
+ title: "No catch that only rethrows"
4
+ languages: [javascript, jsx, typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "removing the try block changes the scope of declarations inside it"
7
+ stability: preview
8
+ ported_from: [eslint/no-useless-catch]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A `catch` clause does more than rethrow the error it caught.
13
+
14
+ **Why:** `catch (e) { throw e; }` does nothing but add noise and a level of nesting.
15
+
16
+ ```codelaw
17
+ match:
18
+ kind: catch_clause
19
+ all:
20
+ - has: { field: parameter, pattern: $E }
21
+ - has:
22
+ field: body
23
+ regex: ^\{\s*throw\s+[A-Za-z_$][A-Za-z0-9_$]*\s*;?\s*\}$
24
+ has: { kind: throw_statement, has: { pattern: $E }, stopBy: end }
25
+ message: "This catch only rethrows `$E`; remove it"
26
+ ```
27
+
28
+ ## How to fix
29
+
30
+ 1. If there is no `finally`, replace the `try` statement with the statements of its block.
31
+ 2. If there is a `finally`, remove only the `catch` clause.
32
+
33
+ ## Examples
34
+
35
+ ### JavaScript
36
+
37
+ #### Don't
38
+
39
+ ```js
40
+ try {
41
+ load();
42
+ } catch (e) {
43
+ throw e;
44
+ }
45
+ ```
46
+
47
+ #### Do
48
+
49
+ ```js
50
+ load();
51
+ ```
52
+
53
+ ### JSX
54
+
55
+ #### Don't
56
+
57
+ ```jsx
58
+ try {
59
+ load();
60
+ } catch (e) {
61
+ throw e;
62
+ }
63
+ ```
64
+
65
+ #### Do
66
+
67
+ ```jsx
68
+ load();
69
+ ```
70
+
71
+ ### TypeScript
72
+
73
+ #### Don't
74
+
75
+ ```ts
76
+ try {
77
+ load();
78
+ } catch (e) {
79
+ throw e;
80
+ }
81
+ ```
82
+
83
+ #### Do
84
+
85
+ ```ts
86
+ load();
87
+ ```
88
+
89
+ ### TSX
90
+
91
+ #### Don't
92
+
93
+ ```tsx
94
+ try {
95
+ load();
96
+ } catch (e) {
97
+ throw e;
98
+ }
99
+ ```
100
+
101
+ #### Do
102
+
103
+ ```tsx
104
+ load();
105
+ ```
@@ -0,0 +1,81 @@
1
+ ---
2
+ id: js/no-useless-escape
3
+ title: "No backslash that changes nothing"
4
+ languages: [javascript, jsx, typescript, tsx]
5
+ fix: auto
6
+ stability: preview
7
+ ported_from: [eslint/no-useless-escape]
8
+ since: 0.1.0
9
+ ---
10
+
11
+ A string or template literal escapes only characters that need it: quotes that match the delimiter,
12
+ `\\`, line breaks and the escape letters.
13
+
14
+ **Why:** A useless escape suggests the author meant something else, and makes the string harder to
15
+ read.
16
+
17
+ ```codelaw
18
+ native: js/no-useless-escape
19
+ ```
20
+
21
+ ## Examples
22
+
23
+ ### JavaScript
24
+
25
+ #### Don't
26
+
27
+ ```js
28
+ const path = "a\.b";
29
+ ```
30
+
31
+ #### Do
32
+
33
+ ```js
34
+ const path = "a.b";
35
+ ```
36
+
37
+ ### JSX
38
+
39
+ #### Don't
40
+
41
+ ```jsx
42
+ const path = "a\.b";
43
+ ```
44
+
45
+ #### Do
46
+
47
+ ```jsx
48
+ const path = "a.b";
49
+ ```
50
+
51
+ ### TypeScript
52
+
53
+ #### Don't
54
+
55
+ ```ts
56
+ const path = "a\.b";
57
+ ```
58
+
59
+ #### Do
60
+
61
+ ```ts
62
+ const path = "a.b";
63
+ ```
64
+
65
+ ### TSX
66
+
67
+ #### Don't
68
+
69
+ ```tsx
70
+ const path = "a\.b";
71
+ ```
72
+
73
+ #### Do
74
+
75
+ ```tsx
76
+ const path = "a.b";
77
+ ```
78
+
79
+ ## Differences from the source
80
+
81
+ Escapes inside regular expressions are not checked yet. A tagged template (`String.raw`, `html`) is not checked: its tag sees the raw text, backslashes included, as in ESLint.