@codelaw/rules-js 0.0.0-stage → 0.1.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.
- package/LICENSE +23 -0
- package/NOTICE +19 -0
- package/README.md +90 -2
- package/codelaw-pack.toml +6 -0
- package/data/globals/browser.json +1209 -0
- package/data/globals/commonjs.json +6 -0
- package/data/globals/jest.json +15 -0
- package/data/globals/mocha.json +22 -0
- package/data/globals/node.json +83 -0
- package/data/globals/serviceworker.json +328 -0
- package/data/globals/shared-node-browser.json +73 -0
- package/data/globals/vitest.json +19 -0
- package/data/globals/worker.json +349 -0
- package/data/node/deprecated-api.json +83 -0
- package/data/react/dom-property-aliases.json +131 -0
- package/package.json +14 -4
- package/presets/js/conventions.toml +10 -0
- package/presets/js/recommended.toml +67 -0
- package/presets/node/recommended.toml +13 -0
- package/presets/react/recommended.toml +22 -0
- package/presets/stencil/recommended.toml +18 -0
- package/presets/ts/recommended.toml +27 -0
- package/rules/graph/no-unused-exports.md +135 -0
- package/rules/js/constructor-super.md +77 -0
- package/rules/js/exports-at-end.md +134 -0
- package/rules/js/for-direction.md +106 -0
- package/rules/js/getter-return.md +74 -0
- package/rules/js/import-groups.md +117 -0
- package/rules/js/no-async-promise-executor.md +95 -0
- package/rules/js/no-case-declarations.md +134 -0
- package/rules/js/no-class-assign.md +61 -0
- package/rules/js/no-compare-neg-zero.md +105 -0
- package/rules/js/no-cond-assign.md +135 -0
- package/rules/js/no-const-assign.md +61 -0
- package/rules/js/no-constant-binary-expression.md +83 -0
- package/rules/js/no-constant-condition.md +150 -0
- package/rules/js/no-control-regex.md +84 -0
- package/rules/js/no-debugger.md +99 -0
- package/rules/js/no-default-export.md +88 -0
- package/rules/js/no-delete-var.md +93 -0
- package/rules/js/no-dupe-args.md +61 -0
- package/rules/js/no-dupe-class-members.md +82 -0
- package/rules/js/no-dupe-else-if.md +113 -0
- package/rules/js/no-dupe-keys.md +66 -0
- package/rules/js/no-duplicate-case.md +137 -0
- package/rules/js/no-empty-character-class.md +98 -0
- package/rules/js/no-empty-pattern.md +86 -0
- package/rules/js/no-empty-static-block.md +99 -0
- package/rules/js/no-empty.md +116 -0
- package/rules/js/no-ex-assign.md +121 -0
- package/rules/js/no-extra-boolean-cast.md +107 -0
- package/rules/js/no-fallthrough.md +178 -0
- package/rules/js/no-func-assign.md +62 -0
- package/rules/js/no-global-assign.md +85 -0
- package/rules/js/no-import-assign.md +60 -0
- package/rules/js/no-invalid-regexp.md +86 -0
- package/rules/js/no-irregular-whitespace.md +87 -0
- package/rules/js/no-loss-of-precision.md +82 -0
- package/rules/js/no-misleading-character-class.md +83 -0
- package/rules/js/no-new-native-nonconstructor.md +55 -0
- package/rules/js/no-nonoctal-decimal-escape.md +84 -0
- package/rules/js/no-obj-calls.md +61 -0
- package/rules/js/no-octal.md +84 -0
- package/rules/js/no-prototype-builtins.md +99 -0
- package/rules/js/no-redeclare.md +61 -0
- package/rules/js/no-regex-spaces.md +75 -0
- package/rules/js/no-self-assign.md +91 -0
- package/rules/js/no-setter-return.md +69 -0
- package/rules/js/no-shadow-restricted-names.md +102 -0
- package/rules/js/no-sparse-arrays.md +82 -0
- package/rules/js/no-this-before-super.md +74 -0
- package/rules/js/no-unassigned-vars.md +102 -0
- package/rules/js/no-undef.md +76 -0
- package/rules/js/no-unexpected-multiline.md +91 -0
- package/rules/js/no-unreachable.md +59 -0
- package/rules/js/no-unsafe-finally.md +145 -0
- package/rules/js/no-unsafe-negation.md +71 -0
- package/rules/js/no-unsafe-optional-chaining.md +83 -0
- package/rules/js/no-unused-labels.md +102 -0
- package/rules/js/no-unused-private-class-members.md +126 -0
- package/rules/js/no-unused-vars.md +69 -0
- package/rules/js/no-useless-assignment.md +115 -0
- package/rules/js/no-useless-backreference.md +83 -0
- package/rules/js/no-useless-catch.md +105 -0
- package/rules/js/no-useless-escape.md +81 -0
- package/rules/js/no-var.md +76 -0
- package/rules/js/no-with.md +60 -0
- package/rules/js/prefer-const.md +83 -0
- package/rules/js/prefer-rest-params.md +103 -0
- package/rules/js/prefer-spread.md +95 -0
- package/rules/js/preserve-caught-error.md +122 -0
- package/rules/js/require-yield.md +107 -0
- package/rules/js/use-isnan.md +105 -0
- package/rules/js/valid-typeof.md +111 -0
- package/rules/node/hashbang.md +71 -0
- package/rules/node/no-deprecated-api.md +91 -0
- package/rules/node/no-exports-assign.md +92 -0
- package/rules/node/no-extraneous-import.md +118 -0
- package/rules/node/no-extraneous-require.md +117 -0
- package/rules/node/no-missing-import.md +118 -0
- package/rules/node/no-missing-require.md +117 -0
- package/rules/node/no-process-exit.md +99 -0
- package/rules/node/no-unpublished-import.md +134 -0
- package/rules/node/no-unpublished-require.md +133 -0
- package/rules/react/display-name.md +91 -0
- package/rules/react/exhaustive-deps.md +116 -0
- package/rules/react/hook-prefix.md +108 -0
- package/rules/react/jsx-key.md +99 -0
- package/rules/react/jsx-no-comment-textnodes.md +87 -0
- package/rules/react/jsx-no-duplicate-props.md +66 -0
- package/rules/react/jsx-no-target-blank.md +78 -0
- package/rules/react/jsx-no-undef.md +78 -0
- package/rules/react/no-children-prop.md +80 -0
- package/rules/react/no-danger-with-children.md +83 -0
- package/rules/react/no-deprecated.md +84 -0
- package/rules/react/no-direct-mutation-state.md +102 -0
- package/rules/react/no-find-dom-node.md +72 -0
- package/rules/react/no-is-mounted.md +109 -0
- package/rules/react/no-render-return-value.md +75 -0
- package/rules/react/no-string-refs.md +72 -0
- package/rules/react/no-unescaped-entities.md +69 -0
- package/rules/react/no-unknown-property.md +69 -0
- package/rules/react/props-type-name.md +43 -0
- package/rules/react/require-render-return.md +91 -0
- package/rules/react/rules-of-hooks.md +128 -0
- package/rules/stencil/ban-default-true.md +70 -0
- package/rules/stencil/ban-exported-const-enums.md +60 -0
- package/rules/stencil/ban-prefix.md +76 -0
- package/rules/stencil/decorators-context.md +61 -0
- package/rules/stencil/host-data-deprecated.md +73 -0
- package/rules/stencil/methods-must-be-public.md +69 -0
- package/rules/stencil/no-unused-watch.md +68 -0
- package/rules/stencil/own-methods-must-be-private.md +68 -0
- package/rules/stencil/own-props-must-be-private.md +60 -0
- package/rules/stencil/prefer-vdom-listener.md +67 -0
- package/rules/stencil/prop-readonly.md +63 -0
- package/rules/stencil/props-must-be-public.md +68 -0
- package/rules/stencil/required-jsdoc.md +66 -0
- package/rules/stencil/reserved-member-names.md +70 -0
- package/rules/stencil/strict-mutable.md +75 -0
- package/rules/stencil/tag-prefix.md +75 -0
- package/rules/ts/ban-ts-comment.md +64 -0
- package/rules/ts/no-array-constructor.md +58 -0
- package/rules/ts/no-duplicate-enum-values.md +65 -0
- package/rules/ts/no-empty-object-type.md +65 -0
- package/rules/ts/no-explicit-any.md +61 -0
- package/rules/ts/no-extra-non-null-assertion.md +50 -0
- package/rules/ts/no-misused-new.md +70 -0
- package/rules/ts/no-namespace.md +65 -0
- package/rules/ts/no-non-null-asserted-optional-chain.md +55 -0
- package/rules/ts/no-require-imports.md +54 -0
- package/rules/ts/no-this-alias.md +68 -0
- package/rules/ts/no-unnecessary-type-constraint.md +64 -0
- package/rules/ts/no-unsafe-declaration-merging.md +73 -0
- package/rules/ts/no-unsafe-function-type.md +57 -0
- package/rules/ts/no-unused-expressions.md +61 -0
- package/rules/ts/no-unused-vars.md +68 -0
- package/rules/ts/no-wrapper-object-types.md +49 -0
- package/rules/ts/prefer-as-const.md +47 -0
- package/rules/ts/prefer-namespace-keyword.md +63 -0
- package/rules/ts/triple-slash-reference.md +60 -0
- package/rules/ts/type-only-imports.md +57 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
description = "eslint-plugin-react 7.37.5 recommended with jsx-runtime, and eslint-plugin-react-hooks 7.1.1 rules-of-hooks and exhaustive-deps, reimplemented"
|
|
2
|
+
|
|
3
|
+
[rules]
|
|
4
|
+
"react/display-name" = "error"
|
|
5
|
+
"react/exhaustive-deps" = "error"
|
|
6
|
+
"react/jsx-key" = "error"
|
|
7
|
+
"react/jsx-no-comment-textnodes" = "error"
|
|
8
|
+
"react/jsx-no-duplicate-props" = "error"
|
|
9
|
+
"react/jsx-no-target-blank" = "error"
|
|
10
|
+
"react/jsx-no-undef" = "error"
|
|
11
|
+
"react/no-children-prop" = "error"
|
|
12
|
+
"react/no-danger-with-children" = "error"
|
|
13
|
+
"react/no-deprecated" = "error"
|
|
14
|
+
"react/no-direct-mutation-state" = "error"
|
|
15
|
+
"react/no-find-dom-node" = "error"
|
|
16
|
+
"react/no-is-mounted" = "error"
|
|
17
|
+
"react/no-render-return-value" = "error"
|
|
18
|
+
"react/no-string-refs" = "error"
|
|
19
|
+
"react/no-unescaped-entities" = "error"
|
|
20
|
+
"react/no-unknown-property" = "error"
|
|
21
|
+
"react/require-render-return" = "error"
|
|
22
|
+
"react/rules-of-hooks" = "error"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
description = "@stencil/eslint-plugin 1.4.0 recommended without its type-checked rules, reimplemented"
|
|
2
|
+
|
|
3
|
+
[rules]
|
|
4
|
+
"stencil/ban-default-true" = "error"
|
|
5
|
+
"stencil/ban-exported-const-enums" = "error"
|
|
6
|
+
"stencil/ban-prefix" = "error"
|
|
7
|
+
"stencil/decorators-context" = "error"
|
|
8
|
+
"stencil/host-data-deprecated" = "error"
|
|
9
|
+
"stencil/methods-must-be-public" = "error"
|
|
10
|
+
"stencil/no-unused-watch" = "error"
|
|
11
|
+
"stencil/own-methods-must-be-private" = "error"
|
|
12
|
+
"stencil/own-props-must-be-private" = "error"
|
|
13
|
+
"stencil/prefer-vdom-listener" = "error"
|
|
14
|
+
"stencil/prop-readonly" = "error"
|
|
15
|
+
"stencil/props-must-be-public" = "error"
|
|
16
|
+
"stencil/required-jsdoc" = "error"
|
|
17
|
+
"stencil/reserved-member-names" = "error"
|
|
18
|
+
"stencil/strict-mutable" = "error"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
description = "typescript-eslint's recommended preset (8.71.2, not type-checked), reimplemented, with the core rules it switches on for TypeScript"
|
|
2
|
+
|
|
3
|
+
[rules]
|
|
4
|
+
"ts/ban-ts-comment" = "error"
|
|
5
|
+
"ts/no-array-constructor" = "error"
|
|
6
|
+
"ts/no-duplicate-enum-values" = "error"
|
|
7
|
+
"ts/no-empty-object-type" = "error"
|
|
8
|
+
"ts/no-explicit-any" = "error"
|
|
9
|
+
"ts/no-extra-non-null-assertion" = "error"
|
|
10
|
+
"ts/no-misused-new" = "error"
|
|
11
|
+
"ts/no-namespace" = "error"
|
|
12
|
+
"ts/no-non-null-asserted-optional-chain" = "error"
|
|
13
|
+
"ts/no-require-imports" = "error"
|
|
14
|
+
"ts/no-this-alias" = "error"
|
|
15
|
+
"ts/no-unnecessary-type-constraint" = "error"
|
|
16
|
+
"ts/no-unsafe-declaration-merging" = "error"
|
|
17
|
+
"ts/no-unsafe-function-type" = "error"
|
|
18
|
+
"ts/no-unused-expressions" = "error"
|
|
19
|
+
"ts/no-unused-vars" = "error"
|
|
20
|
+
"ts/no-wrapper-object-types" = "error"
|
|
21
|
+
"ts/prefer-as-const" = "error"
|
|
22
|
+
"ts/prefer-namespace-keyword" = "error"
|
|
23
|
+
"ts/triple-slash-reference" = "error"
|
|
24
|
+
"js/no-var" = "error"
|
|
25
|
+
"js/prefer-const" = "error"
|
|
26
|
+
"js/prefer-rest-params" = "error"
|
|
27
|
+
"js/prefer-spread" = "error"
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: graph/no-unused-exports
|
|
3
|
+
title: Exported symbols must be used somewhere
|
|
4
|
+
languages: [javascript, jsx, typescript, tsx]
|
|
5
|
+
scope: project
|
|
6
|
+
severity: error
|
|
7
|
+
fix: suggest
|
|
8
|
+
fix_reason: "Static analysis can't rule out reflective or external use, so removal needs a human or agent to accept the diff."
|
|
9
|
+
stability: preview
|
|
10
|
+
ported_from: [knip/exports, knip/types]
|
|
11
|
+
since: 0.1.0
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
Every exported symbol is imported by another module, is reachable from an entry point, or is marked `@public` / `@keep`.
|
|
15
|
+
|
|
16
|
+
**Why:** an export nothing imports is dead code that still looks like API: readers keep it, refactors carry it, and it hides what a module is really for.
|
|
17
|
+
|
|
18
|
+
```codelaw
|
|
19
|
+
graph:
|
|
20
|
+
symbol:
|
|
21
|
+
exported: true
|
|
22
|
+
kind: [function, class, variable, type, interface, enum]
|
|
23
|
+
unless:
|
|
24
|
+
- reachable_from: entry
|
|
25
|
+
- tagged: [public, keep]
|
|
26
|
+
when:
|
|
27
|
+
external_references: 0
|
|
28
|
+
certainty_from: module.dynamic
|
|
29
|
+
message: "`$SYMBOL` is exported but never used outside `$FILE`"
|
|
30
|
+
fix:
|
|
31
|
+
- when: { local_references: ">0" }
|
|
32
|
+
do: [strip-export-keyword]
|
|
33
|
+
- else:
|
|
34
|
+
do: [remove-declaration]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## How to fix
|
|
38
|
+
|
|
39
|
+
1. Run `codelaw graph why-unused <symbol>` (`<file>#<export>` or `<module>:<name>`) to see each entry, keep and import clause.
|
|
40
|
+
2. If something outside the repo uses it, add the file to `[graph] entry` or `[graph] keep`, add its decorator to `[graph] registrars`, or tag it `/** @public */` / `# codelaw: keep`.
|
|
41
|
+
3. Otherwise delete the declaration (and its `__all__` or `export { … }` entry), or drop `export` if its own file still uses it.
|
|
42
|
+
|
|
43
|
+
## Examples
|
|
44
|
+
|
|
45
|
+
### JavaScript
|
|
46
|
+
|
|
47
|
+
#### Don't
|
|
48
|
+
|
|
49
|
+
```js files
|
|
50
|
+
// src/date.js
|
|
51
|
+
export function formatDate(d) { return d.toISOString(); }
|
|
52
|
+
export function parseDate(s) { return new Date(s); }
|
|
53
|
+
// src/app.js
|
|
54
|
+
import { formatDate } from "./date";
|
|
55
|
+
console.log(formatDate(new Date()));
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### Do
|
|
59
|
+
|
|
60
|
+
```js files
|
|
61
|
+
// src/date.js
|
|
62
|
+
export function formatDate(d) { return d.toISOString(); }
|
|
63
|
+
// src/app.js
|
|
64
|
+
import { formatDate } from "./date";
|
|
65
|
+
console.log(formatDate(new Date()));
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### JSX
|
|
69
|
+
|
|
70
|
+
#### Don't
|
|
71
|
+
|
|
72
|
+
```jsx files
|
|
73
|
+
// src/Button.jsx
|
|
74
|
+
export function Button() { return <button />; }
|
|
75
|
+
export function Unused() { return <span />; }
|
|
76
|
+
// src/App.jsx
|
|
77
|
+
import { Button } from "./Button";
|
|
78
|
+
console.log(<Button />);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### Do
|
|
82
|
+
|
|
83
|
+
```jsx files
|
|
84
|
+
// src/Button.jsx
|
|
85
|
+
export function Button() { return <button />; }
|
|
86
|
+
// src/App.jsx
|
|
87
|
+
import { Button } from "./Button";
|
|
88
|
+
console.log(<Button />);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### TypeScript
|
|
92
|
+
|
|
93
|
+
#### Don't
|
|
94
|
+
|
|
95
|
+
```ts files
|
|
96
|
+
// packages/utils/src/date.ts
|
|
97
|
+
export function formatDate(d: Date) { return d.toISOString(); }
|
|
98
|
+
export function parseDate(s: string) { return new Date(s); }
|
|
99
|
+
// packages/web/src/app.ts
|
|
100
|
+
import { formatDate } from "../../utils/src/date";
|
|
101
|
+
console.log(formatDate(new Date()));
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### Do
|
|
105
|
+
|
|
106
|
+
```ts files
|
|
107
|
+
// packages/utils/src/date.ts
|
|
108
|
+
export function formatDate(d: Date) { return d.toISOString(); }
|
|
109
|
+
// packages/web/src/app.ts
|
|
110
|
+
import { formatDate } from "../../utils/src/date";
|
|
111
|
+
console.log(formatDate(new Date()));
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### TSX
|
|
115
|
+
|
|
116
|
+
#### Don't
|
|
117
|
+
|
|
118
|
+
```tsx files
|
|
119
|
+
// src/theme.tsx
|
|
120
|
+
export const theme = { dark: false };
|
|
121
|
+
export const unusedTheme = { dark: true };
|
|
122
|
+
// src/main.tsx
|
|
123
|
+
import { theme } from "./theme";
|
|
124
|
+
console.log(theme);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Do
|
|
128
|
+
|
|
129
|
+
```tsx files
|
|
130
|
+
// src/theme.tsx
|
|
131
|
+
export const theme = { dark: false };
|
|
132
|
+
// src/main.tsx
|
|
133
|
+
import { theme } from "./theme";
|
|
134
|
+
console.log(theme);
|
|
135
|
+
```
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: js/constructor-super
|
|
3
|
+
title: "A derived class's constructor calls super(); a base class's does not"
|
|
4
|
+
languages: [javascript, jsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "what `super()` must receive depends on the base class"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [eslint/constructor-super]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
A class that extends another must call `super()` in its constructor before it returns, and a class
|
|
13
|
+
that extends nothing must not call `super()` at all.
|
|
14
|
+
|
|
15
|
+
**Why:** Without `super()` the instance is never initialised and the constructor throws; in a base
|
|
16
|
+
class `super()` is a syntax error.
|
|
17
|
+
|
|
18
|
+
```codelaw
|
|
19
|
+
native: js/constructor-super
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## How to fix
|
|
23
|
+
|
|
24
|
+
1. In a class with `extends`, call `super(...)` with the arguments the base class expects, before any use of `this`.
|
|
25
|
+
2. In a class without `extends`, remove the `super()` call.
|
|
26
|
+
|
|
27
|
+
## Examples
|
|
28
|
+
|
|
29
|
+
### JavaScript
|
|
30
|
+
|
|
31
|
+
#### Don't
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
class Cat extends Animal {
|
|
35
|
+
constructor() {
|
|
36
|
+
this.lives = 9;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
#### Do
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
class Cat extends Animal {
|
|
45
|
+
constructor() {
|
|
46
|
+
super();
|
|
47
|
+
this.lives = 9;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### JSX
|
|
53
|
+
|
|
54
|
+
#### Don't
|
|
55
|
+
|
|
56
|
+
```jsx
|
|
57
|
+
class Cat extends Animal {
|
|
58
|
+
constructor() {
|
|
59
|
+
this.lives = 9;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### Do
|
|
65
|
+
|
|
66
|
+
```jsx
|
|
67
|
+
class Cat extends Animal {
|
|
68
|
+
constructor() {
|
|
69
|
+
super();
|
|
70
|
+
this.lives = 9;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Differences from the source
|
|
76
|
+
|
|
77
|
+
Paths are followed in straight-line order: a `super()` on any branch counts as called.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: js/exports-at-end
|
|
3
|
+
title: "Exports are gathered at the end of the file"
|
|
4
|
+
languages: [javascript, jsx, typescript, tsx]
|
|
5
|
+
fix: auto
|
|
6
|
+
stability: preview
|
|
7
|
+
invariant: exports-unchanged
|
|
8
|
+
since: 0.1.0
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Declarations are written without `export`, and the module's exports are listed in one `export { … }`
|
|
12
|
+
(and `export type { … }`) block at the end of the file.
|
|
13
|
+
|
|
14
|
+
**Why:** A reader or an agent sees the module's whole public API in one place.
|
|
15
|
+
|
|
16
|
+
```codelaw
|
|
17
|
+
match:
|
|
18
|
+
kind: export_statement
|
|
19
|
+
has: { field: declaration, pattern: $DECL }
|
|
20
|
+
not:
|
|
21
|
+
any:
|
|
22
|
+
- has: { regex: ^default$ }
|
|
23
|
+
- has: { field: declaration, kind: internal_module }
|
|
24
|
+
- has: { field: declaration, kind: ambient_declaration }
|
|
25
|
+
- has: { field: declaration, kind: module }
|
|
26
|
+
message: "Export at the end of the file, in one `export { … }` block"
|
|
27
|
+
fix:
|
|
28
|
+
- strip-export-keyword: $DECL
|
|
29
|
+
- collect-into-block:
|
|
30
|
+
target: $DECL
|
|
31
|
+
block: "export { $$$NAMES };"
|
|
32
|
+
type_block: "export type { $$$TYPE_NAMES };"
|
|
33
|
+
position: end-of-file
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Examples
|
|
37
|
+
|
|
38
|
+
### JavaScript
|
|
39
|
+
|
|
40
|
+
#### Don't
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
export function add(a, b) {
|
|
44
|
+
return a + b;
|
|
45
|
+
}
|
|
46
|
+
export const zero = 0;
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
#### Do
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
function add(a, b) {
|
|
53
|
+
return a + b;
|
|
54
|
+
}
|
|
55
|
+
const zero = 0;
|
|
56
|
+
export { add, zero };
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### JSX
|
|
60
|
+
|
|
61
|
+
#### Don't
|
|
62
|
+
|
|
63
|
+
```jsx
|
|
64
|
+
export function add(a, b) {
|
|
65
|
+
return a + b;
|
|
66
|
+
}
|
|
67
|
+
export const zero = 0;
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
#### Do
|
|
71
|
+
|
|
72
|
+
```jsx
|
|
73
|
+
function add(a, b) {
|
|
74
|
+
return a + b;
|
|
75
|
+
}
|
|
76
|
+
const zero = 0;
|
|
77
|
+
export { add, zero };
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### TypeScript
|
|
81
|
+
|
|
82
|
+
#### Don't
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
export function add(a: number, b: number) {
|
|
86
|
+
return a + b;
|
|
87
|
+
}
|
|
88
|
+
export interface Point {
|
|
89
|
+
x: number;
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### Do
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
function add(a: number, b: number) {
|
|
97
|
+
return a + b;
|
|
98
|
+
}
|
|
99
|
+
interface Point {
|
|
100
|
+
x: number;
|
|
101
|
+
}
|
|
102
|
+
export { add };
|
|
103
|
+
export type { Point };
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### TSX
|
|
107
|
+
|
|
108
|
+
#### Don't
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
export function add(a: number, b: number) {
|
|
112
|
+
return a + b;
|
|
113
|
+
}
|
|
114
|
+
export interface Point {
|
|
115
|
+
x: number;
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### Do
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
function add(a: number, b: number) {
|
|
123
|
+
return a + b;
|
|
124
|
+
}
|
|
125
|
+
interface Point {
|
|
126
|
+
x: number;
|
|
127
|
+
}
|
|
128
|
+
export { add };
|
|
129
|
+
export type { Point };
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Differences from the source
|
|
133
|
+
|
|
134
|
+
`export default`, namespaces and `declare` blocks are left alone.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: js/for-direction
|
|
3
|
+
title: "A for loop's counter moves toward its end condition"
|
|
4
|
+
languages: [javascript, jsx, typescript, tsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "whether the condition or the update is wrong needs the author"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [eslint/for-direction]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
A `for` loop whose condition tests `i < n` counts up, and one that tests `i > n` counts down.
|
|
13
|
+
|
|
14
|
+
**Why:** A counter that moves the wrong way never meets its end condition, so the loop never ends.
|
|
15
|
+
|
|
16
|
+
```codelaw
|
|
17
|
+
match:
|
|
18
|
+
kind: for_statement
|
|
19
|
+
any:
|
|
20
|
+
- all:
|
|
21
|
+
- has: { field: condition, any: [{ pattern: $I < $END }, { pattern: $I <= $END }] }
|
|
22
|
+
- has: { field: increment, any: [{ pattern: $I-- }, { pattern: --$I }] }
|
|
23
|
+
- all:
|
|
24
|
+
- has: { field: condition, any: [{ pattern: $I > $END }, { pattern: $I >= $END }] }
|
|
25
|
+
- has: { field: increment, any: [{ pattern: $I++ }, { pattern: ++$I }] }
|
|
26
|
+
message: "The counter `$I` moves away from the condition that ends this loop"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## How to fix
|
|
30
|
+
|
|
31
|
+
1. Decide which way the loop should count.
|
|
32
|
+
2. Fix the update (`i++` or `i--`) or the comparison to match.
|
|
33
|
+
|
|
34
|
+
## Examples
|
|
35
|
+
|
|
36
|
+
### JavaScript
|
|
37
|
+
|
|
38
|
+
#### Don't
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
for (let i = 0; i < 10; i--) {
|
|
42
|
+
draw(i);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
#### Do
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
for (let i = 0; i < 10; i++) {
|
|
50
|
+
draw(i);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### JSX
|
|
55
|
+
|
|
56
|
+
#### Don't
|
|
57
|
+
|
|
58
|
+
```jsx
|
|
59
|
+
for (let i = 0; i < 10; i--) {
|
|
60
|
+
draw(i);
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### Do
|
|
65
|
+
|
|
66
|
+
```jsx
|
|
67
|
+
for (let i = 0; i < 10; i++) {
|
|
68
|
+
draw(i);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### TypeScript
|
|
73
|
+
|
|
74
|
+
#### Don't
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
for (let i = 0; i < 10; i--) {
|
|
78
|
+
draw(i);
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### Do
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
for (let i = 0; i < 10; i++) {
|
|
86
|
+
draw(i);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### TSX
|
|
91
|
+
|
|
92
|
+
#### Don't
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
for (let i = 0; i < 10; i--) {
|
|
96
|
+
draw(i);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### Do
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
for (let i = 0; i < 10; i++) {
|
|
104
|
+
draw(i);
|
|
105
|
+
}
|
|
106
|
+
```
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: js/getter-return
|
|
3
|
+
title: "A getter returns a value on every path"
|
|
4
|
+
languages: [javascript, jsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "the value a getter should return is the author's decision"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [eslint/getter-return]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Every path through a getter ends in `return <value>` or a `throw`.
|
|
13
|
+
|
|
14
|
+
**Why:** A getter that falls off its end returns `undefined`, which is almost always a forgotten
|
|
15
|
+
`return`.
|
|
16
|
+
|
|
17
|
+
```codelaw
|
|
18
|
+
native: js/getter-return
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## How to fix
|
|
22
|
+
|
|
23
|
+
1. Find the path that ends without a `return`.
|
|
24
|
+
2. Return the value the property should have there, or throw.
|
|
25
|
+
|
|
26
|
+
## Examples
|
|
27
|
+
|
|
28
|
+
### JavaScript
|
|
29
|
+
|
|
30
|
+
#### Don't
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
const box = {
|
|
34
|
+
get size() {
|
|
35
|
+
if (this.items) {
|
|
36
|
+
return this.items.length;
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### Do
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
const box = {
|
|
46
|
+
get size() {
|
|
47
|
+
return this.items ? this.items.length : 0;
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### JSX
|
|
53
|
+
|
|
54
|
+
#### Don't
|
|
55
|
+
|
|
56
|
+
```jsx
|
|
57
|
+
const box = {
|
|
58
|
+
get size() {
|
|
59
|
+
if (this.items) {
|
|
60
|
+
return this.items.length;
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
#### Do
|
|
67
|
+
|
|
68
|
+
```jsx
|
|
69
|
+
const box = {
|
|
70
|
+
get size() {
|
|
71
|
+
return this.items ? this.items.length : 0;
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
```
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: js/import-groups
|
|
3
|
+
title: "Imports are grouped builtin, external, internal, relative"
|
|
4
|
+
languages: [javascript, jsx, typescript, tsx]
|
|
5
|
+
fix: auto
|
|
6
|
+
stability: preview
|
|
7
|
+
options:
|
|
8
|
+
internal: { type: "string[]", default: ["@/", "~/"], description: "prefixes of internal imports" }
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
The file's leading imports come in four groups, in order — Node.js built-ins, packages, internal
|
|
13
|
+
aliases (the `internal` option, `@/` and `~/` by default), relative paths — with a blank line
|
|
14
|
+
between groups.
|
|
15
|
+
|
|
16
|
+
**Why:** Grouped imports show at a glance what a module depends on, and keep diffs of the import
|
|
17
|
+
block small.
|
|
18
|
+
|
|
19
|
+
```codelaw
|
|
20
|
+
native: js/import-groups
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Examples
|
|
24
|
+
|
|
25
|
+
### JavaScript
|
|
26
|
+
|
|
27
|
+
#### Don't
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
import { helper } from "./helper";
|
|
31
|
+
import fs from "node:fs";
|
|
32
|
+
import React from "react";
|
|
33
|
+
helper(fs, React);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
#### Do
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
import fs from "node:fs";
|
|
40
|
+
|
|
41
|
+
import React from "react";
|
|
42
|
+
|
|
43
|
+
import { helper } from "./helper";
|
|
44
|
+
helper(fs, React);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### JSX
|
|
48
|
+
|
|
49
|
+
#### Don't
|
|
50
|
+
|
|
51
|
+
```jsx
|
|
52
|
+
import { helper } from "./helper";
|
|
53
|
+
import fs from "node:fs";
|
|
54
|
+
import React from "react";
|
|
55
|
+
helper(fs, React);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### Do
|
|
59
|
+
|
|
60
|
+
```jsx
|
|
61
|
+
import fs from "node:fs";
|
|
62
|
+
|
|
63
|
+
import React from "react";
|
|
64
|
+
|
|
65
|
+
import { helper } from "./helper";
|
|
66
|
+
helper(fs, React);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### TypeScript
|
|
70
|
+
|
|
71
|
+
#### Don't
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { helper } from "./helper";
|
|
75
|
+
import fs from "node:fs";
|
|
76
|
+
import React from "react";
|
|
77
|
+
helper(fs, React);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
#### Do
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import fs from "node:fs";
|
|
84
|
+
|
|
85
|
+
import React from "react";
|
|
86
|
+
|
|
87
|
+
import { helper } from "./helper";
|
|
88
|
+
helper(fs, React);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### TSX
|
|
92
|
+
|
|
93
|
+
#### Don't
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
import { helper } from "./helper";
|
|
97
|
+
import fs from "node:fs";
|
|
98
|
+
import React from "react";
|
|
99
|
+
helper(fs, React);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### Do
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
import fs from "node:fs";
|
|
106
|
+
|
|
107
|
+
import React from "react";
|
|
108
|
+
|
|
109
|
+
import { helper } from "./helper";
|
|
110
|
+
helper(fs, React);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Differences from the source
|
|
114
|
+
|
|
115
|
+
A block of imports with a comment inside is left alone, so no comment is moved away from the import
|
|
116
|
+
it describes. A side-effect import (`import './polyfills'`, a stylesheet) stays where it is, since moving it
|
|
117
|
+
changes what runs first; only the imports between two of them are ordered.
|