@fenge/eslint-plugin 0.4.0 → 0.4.2-beta.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/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/rules/call-arguments-length.d.ts.map +1 -1
- package/dist/rules/call-arguments-length.js +24 -3
- package/dist/rules/consistent-hashbang-and-filename.d.ts +6 -0
- package/dist/rules/consistent-hashbang-and-filename.d.ts.map +1 -0
- package/dist/rules/consistent-hashbang-and-filename.js +39 -0
- package/dist/rules/no-instanceof-builtin.d.ts.map +1 -1
- package/dist/rules/no-instanceof-builtin.js +3 -2
- package/dist/rules/no-nested-class.js +3 -2
- package/dist/rules/no-nested-function.js +3 -2
- package/dist/rules/no-restricted-loops.d.ts.map +1 -1
- package/dist/rules/no-restricted-loops.js +3 -3
- package/dist/rules/no-top-level-arrow-function.d.ts.map +1 -1
- package/dist/rules/no-top-level-arrow-function.js +3 -2
- package/dist/rules/no-triple-slash-directive.d.ts +6 -0
- package/dist/rules/no-triple-slash-directive.d.ts.map +1 -0
- package/dist/rules/no-triple-slash-directive.js +34 -0
- package/dist/rules/no-unnecessary-template-string.d.ts.map +1 -1
- package/dist/rules/no-unnecessary-template-string.js +3 -2
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +4 -1
- package/package.json +7 -5
- package/CHANGELOG.md +0 -46
- package/doc/rules/call-arguments-length.md +0 -52
- package/doc/rules/no-instanceof-builtin.md +0 -50
- package/doc/rules/no-nested-class.md +0 -31
- package/doc/rules/no-nested-function.md +0 -42
- package/doc/rules/no-restricted-loops.md +0 -23
- package/doc/rules/no-top-level-arrow-function.md +0 -45
- package/doc/rules/no-unnecessary-template-string.md +0 -34
- package/src/index.ts +0 -17
- package/src/rules/call-arguments-length.test.ts +0 -48
- package/src/rules/call-arguments-length.ts +0 -163
- package/src/rules/no-instanceof-builtin.test.ts +0 -48
- package/src/rules/no-instanceof-builtin.ts +0 -46
- package/src/rules/no-nested-class.test.ts +0 -27
- package/src/rules/no-nested-class.ts +0 -31
- package/src/rules/no-nested-function.test.ts +0 -49
- package/src/rules/no-nested-function.ts +0 -32
- package/src/rules/no-restricted-loops.test.ts +0 -13
- package/src/rules/no-restricted-loops.ts +0 -30
- package/src/rules/no-top-level-arrow-function.test.ts +0 -32
- package/src/rules/no-top-level-arrow-function.ts +0 -35
- package/src/rules/no-unnecessary-template-string.test.ts +0 -25
- package/src/rules/no-unnecessary-template-string.ts +0 -29
- package/src/utils.ts +0 -7
- package/tsconfig.json +0 -5
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
<!-- prettier-ignore-start -->
|
|
2
|
-
# call-arguments-length
|
|
3
|
-
|
|
4
|
-
Disallow calling a function with incorrect arguments length.
|
|
5
|
-
|
|
6
|
-
## Rule Details
|
|
7
|
-
|
|
8
|
-
### Fail
|
|
9
|
-
|
|
10
|
-
```ts
|
|
11
|
-
[].push()
|
|
12
|
-
foo.push()
|
|
13
|
-
foo.reduce()
|
|
14
|
-
[].reduce(()=>123)
|
|
15
|
-
foo.reduce(()=>123)
|
|
16
|
-
foo.reduce(bar)
|
|
17
|
-
[].reduceRight(()=>123)
|
|
18
|
-
foo.reduceRight(()=>123)
|
|
19
|
-
foo.reduceRight(bar)
|
|
20
|
-
[].reduce(...foo)
|
|
21
|
-
[].reduce(...foo, ...bar)
|
|
22
|
-
Math.max()
|
|
23
|
-
Math.max(1)
|
|
24
|
-
Math.min(foo)
|
|
25
|
-
new Set(...foo)
|
|
26
|
-
new Set(foo,bar)
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### Pass
|
|
30
|
-
|
|
31
|
-
```ts
|
|
32
|
-
push()
|
|
33
|
-
[].push('')
|
|
34
|
-
foo.push('')
|
|
35
|
-
foo.push(bar)
|
|
36
|
-
[].push('', '', '')
|
|
37
|
-
[].push(...foo)
|
|
38
|
-
foo.push(...([]))
|
|
39
|
-
[].reduce(()=>123, 0)
|
|
40
|
-
foo.reduce(()=>123, 0)
|
|
41
|
-
foo.reduce(bar, baz)
|
|
42
|
-
[].reduceRight(()=>123, 0)
|
|
43
|
-
foo.reduceRight(()=>123, 0)
|
|
44
|
-
foo.reduceRight(bar, baz)
|
|
45
|
-
reduce(()=>123)
|
|
46
|
-
foo.reduceLeft(()=>123)
|
|
47
|
-
Math.max(...foo)
|
|
48
|
-
new foo.Set(...bar)
|
|
49
|
-
new Set(bar)
|
|
50
|
-
new Set()
|
|
51
|
-
```
|
|
52
|
-
<!-- prettier-ignore-end -->
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
<!-- prettier-ignore-start -->
|
|
2
|
-
# no-instanceof-builtin
|
|
3
|
-
|
|
4
|
-
Right hand of `instanceof` can't be a builtin class.
|
|
5
|
-
|
|
6
|
-
## Rule Details
|
|
7
|
-
|
|
8
|
-
### Fail
|
|
9
|
-
|
|
10
|
-
```ts
|
|
11
|
-
const i = {} instanceof Number
|
|
12
|
-
const i = {} instanceof String
|
|
13
|
-
const i = {} instanceof Boolean
|
|
14
|
-
const i = {} instanceof Symbol
|
|
15
|
-
const i = {} instanceof BigInt
|
|
16
|
-
const i = {} instanceof Object
|
|
17
|
-
const i = {} instanceof Array
|
|
18
|
-
const i = {} instanceof Function
|
|
19
|
-
const i = {} instanceof ArrayBuffer
|
|
20
|
-
const i = {} instanceof BigInt64Array
|
|
21
|
-
const i = {} instanceof BigUint64Array
|
|
22
|
-
const i = {} instanceof DataView
|
|
23
|
-
const i = {} instanceof Date
|
|
24
|
-
const i = {} instanceof Float32Array
|
|
25
|
-
const i = {} instanceof Float64Array
|
|
26
|
-
const i = {} instanceof Int16Array
|
|
27
|
-
const i = {} instanceof Int32Array
|
|
28
|
-
const i = {} instanceof Int8Array
|
|
29
|
-
const i = {} instanceof Map
|
|
30
|
-
const i = {} instanceof Error
|
|
31
|
-
const i = {} instanceof Promise
|
|
32
|
-
const i = {} instanceof Proxy
|
|
33
|
-
const i = {} instanceof RegExp
|
|
34
|
-
const i = {} instanceof Set
|
|
35
|
-
const i = {} instanceof SharedArrayBuffer
|
|
36
|
-
const i = {} instanceof Uint16Array
|
|
37
|
-
const i = {} instanceof Uint32Array
|
|
38
|
-
const i = {} instanceof Uint8Array
|
|
39
|
-
const i = {} instanceof Uint8ClampedArray
|
|
40
|
-
const i = {} instanceof WeakMap
|
|
41
|
-
const i = {} instanceof WeakSet
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### Pass
|
|
45
|
-
|
|
46
|
-
```ts
|
|
47
|
-
const i = Math.random() > 0.5 ? true: false
|
|
48
|
-
const i = {} instanceof await import('http')
|
|
49
|
-
```
|
|
50
|
-
<!-- prettier-ignore-end -->
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
<!-- prettier-ignore-start -->
|
|
2
|
-
# no-nested-class
|
|
3
|
-
|
|
4
|
-
Disallow nested class. Classes are expected to place at top level.
|
|
5
|
-
|
|
6
|
-
## Rule Details
|
|
7
|
-
|
|
8
|
-
### Fail
|
|
9
|
-
|
|
10
|
-
```ts
|
|
11
|
-
if(true) class Foo{}
|
|
12
|
-
if(true) const foo = class {}
|
|
13
|
-
function foo(){class Foo{}}
|
|
14
|
-
function foo(){const foo = class {}}
|
|
15
|
-
function foo(){return class Foo{}}
|
|
16
|
-
function foo(){return class{}}
|
|
17
|
-
const Foo = class{}
|
|
18
|
-
let Foo = class Bar{}
|
|
19
|
-
let Foo; Foo = class{}
|
|
20
|
-
(class {})
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### Pass
|
|
24
|
-
|
|
25
|
-
```ts
|
|
26
|
-
class Foo{}
|
|
27
|
-
export class Foo{}
|
|
28
|
-
export default class Foo{}
|
|
29
|
-
export default class {}
|
|
30
|
-
```
|
|
31
|
-
<!-- prettier-ignore-end -->
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
<!-- prettier-ignore-start -->
|
|
2
|
-
# no-nested-function
|
|
3
|
-
|
|
4
|
-
Non top-level functions are expected to be arrow functions instead of function declarations.
|
|
5
|
-
|
|
6
|
-
## Rule Details
|
|
7
|
-
|
|
8
|
-
### Fail
|
|
9
|
-
|
|
10
|
-
```ts
|
|
11
|
-
Foo.prototype.bar = function(){}
|
|
12
|
-
Foo.prototype.bar = function bar(){}
|
|
13
|
-
const foo = function(){}
|
|
14
|
-
const foo = function foo(){}
|
|
15
|
-
let foo; foo = function(){}
|
|
16
|
-
let foo; foo = function foo(){}
|
|
17
|
-
(function(){})
|
|
18
|
-
const foo = () => {function bar(){}}
|
|
19
|
-
function foo() {function bar(){}}
|
|
20
|
-
function foo() {let bar = function(){}}
|
|
21
|
-
function foo() {let bar = function bar(){}}
|
|
22
|
-
if(true) function foo(){}
|
|
23
|
-
class Foo{bar = function(){}}
|
|
24
|
-
class Foo{bar = function bar(){}}
|
|
25
|
-
const foo = {bar: function() {}}
|
|
26
|
-
const foo = {bar: function bar() {}}
|
|
27
|
-
const foo = {bar() {}}
|
|
28
|
-
setTimeout(function(){},100)
|
|
29
|
-
setTimeout(function callback(){},100)
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### Pass
|
|
33
|
-
|
|
34
|
-
```ts
|
|
35
|
-
function foo(){}
|
|
36
|
-
const foo = () => {}
|
|
37
|
-
export function foo() {}
|
|
38
|
-
export default function foo() {}
|
|
39
|
-
export default function() {}
|
|
40
|
-
class Foo{bar(){}}
|
|
41
|
-
```
|
|
42
|
-
<!-- prettier-ignore-end -->
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<!-- prettier-ignore-start -->
|
|
2
|
-
# no-restricted-loops
|
|
3
|
-
|
|
4
|
-
Only allow `while` and `for-of` loops. `for`, `for-in`, `do-while` and `for-await-of` loops are disallowed.
|
|
5
|
-
|
|
6
|
-
## Rule Details
|
|
7
|
-
|
|
8
|
-
### Fail
|
|
9
|
-
|
|
10
|
-
```ts
|
|
11
|
-
for(let i = 0; i < foo.length; i++) {}
|
|
12
|
-
for(const bar in foo) {}
|
|
13
|
-
do{}while(condition)
|
|
14
|
-
for await (const bar of foo()) {}
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
### Pass
|
|
18
|
-
|
|
19
|
-
```ts
|
|
20
|
-
for(const bar of foo) {}
|
|
21
|
-
while(condition){}
|
|
22
|
-
```
|
|
23
|
-
<!-- prettier-ignore-end -->
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
<!-- prettier-ignore-start -->
|
|
2
|
-
# no-top-level-arrow-function
|
|
3
|
-
|
|
4
|
-
Top-level functions are expected to be function declarations instead of arrow functions.
|
|
5
|
-
|
|
6
|
-
## Rule Details
|
|
7
|
-
|
|
8
|
-
### Fail
|
|
9
|
-
|
|
10
|
-
```ts
|
|
11
|
-
let foo = () => {}
|
|
12
|
-
const foo = () => {}
|
|
13
|
-
let foo = () => {
|
|
14
|
-
}
|
|
15
|
-
const foo = () => {
|
|
16
|
-
}
|
|
17
|
-
let foo; foo = () => {
|
|
18
|
-
}
|
|
19
|
-
export const foo = () => {
|
|
20
|
-
}
|
|
21
|
-
export let foo = () => {
|
|
22
|
-
}
|
|
23
|
-
export default () => {
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### Pass
|
|
28
|
-
|
|
29
|
-
```ts
|
|
30
|
-
function foo(){}
|
|
31
|
-
const foo = function(){}
|
|
32
|
-
const foo = function foo(){}
|
|
33
|
-
if(true) const foo = () => {
|
|
34
|
-
}
|
|
35
|
-
let foo = () => ''
|
|
36
|
-
let foo = () => [
|
|
37
|
-
]
|
|
38
|
-
let foo = () => ({})
|
|
39
|
-
const foo = () => ({})
|
|
40
|
-
let foo; foo = () => ({})
|
|
41
|
-
export const foo = () => ({})
|
|
42
|
-
export let foo = () => ({})
|
|
43
|
-
export default () => ({})
|
|
44
|
-
```
|
|
45
|
-
<!-- prettier-ignore-end -->
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
<!-- prettier-ignore-start -->
|
|
2
|
-
# no-unnecessary-template-string
|
|
3
|
-
|
|
4
|
-
Disallow using template string when it's unnecessary. Use normal literal string expression instead.
|
|
5
|
-
|
|
6
|
-
## Rule Details
|
|
7
|
-
|
|
8
|
-
### Fail
|
|
9
|
-
|
|
10
|
-
```ts
|
|
11
|
-
outdent`foo`
|
|
12
|
-
``
|
|
13
|
-
`abc`
|
|
14
|
-
`abc\n`
|
|
15
|
-
`\nabc`
|
|
16
|
-
`a\nbc`
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
### Pass
|
|
20
|
-
|
|
21
|
-
```ts
|
|
22
|
-
'abc'
|
|
23
|
-
"def"
|
|
24
|
-
`ab${cd}ef`
|
|
25
|
-
`
|
|
26
|
-
`
|
|
27
|
-
`abc
|
|
28
|
-
`
|
|
29
|
-
`
|
|
30
|
-
abc`
|
|
31
|
-
`a
|
|
32
|
-
bc`
|
|
33
|
-
```
|
|
34
|
-
<!-- prettier-ignore-end -->
|
package/src/index.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { callArgumentsLength } from "./rules/call-arguments-length.ts";
|
|
2
|
-
import { noInstanceofBuiltin } from "./rules/no-instanceof-builtin.ts";
|
|
3
|
-
import { noNestedClass } from "./rules/no-nested-class.ts";
|
|
4
|
-
import { noNestedFunction } from "./rules/no-nested-function.ts";
|
|
5
|
-
import { noRestrictedLoops } from "./rules/no-restricted-loops.ts";
|
|
6
|
-
import { noTopLevelArrowFunction } from "./rules/no-top-level-arrow-function.ts";
|
|
7
|
-
import { noUnnecessaryTemplateString } from "./rules/no-unnecessary-template-string.ts";
|
|
8
|
-
|
|
9
|
-
export const rules = {
|
|
10
|
-
[callArgumentsLength.name]: callArgumentsLength.rule,
|
|
11
|
-
[noInstanceofBuiltin.name]: noInstanceofBuiltin.rule,
|
|
12
|
-
[noNestedClass.name]: noNestedClass.rule,
|
|
13
|
-
[noNestedFunction.name]: noNestedFunction.rule,
|
|
14
|
-
[noRestrictedLoops.name]: noRestrictedLoops.rule,
|
|
15
|
-
[noTopLevelArrowFunction.name]: noTopLevelArrowFunction.rule,
|
|
16
|
-
[noUnnecessaryTemplateString.name]: noUnnecessaryTemplateString.rule,
|
|
17
|
-
};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { test } from "@fenge/dev-utils";
|
|
2
|
-
import { callArgumentsLength } from "./call-arguments-length.ts";
|
|
3
|
-
|
|
4
|
-
const valid = [
|
|
5
|
-
"push()",
|
|
6
|
-
"[].push('')",
|
|
7
|
-
"foo.push('')",
|
|
8
|
-
"foo.push(bar)",
|
|
9
|
-
"[].push('', '', '')",
|
|
10
|
-
"[].push(...foo)",
|
|
11
|
-
"foo.push(...([]))",
|
|
12
|
-
|
|
13
|
-
"[].reduce(()=>123, 0)",
|
|
14
|
-
"foo.reduce(()=>123, 0)",
|
|
15
|
-
"foo.reduce(bar, baz)",
|
|
16
|
-
"[].reduceRight(()=>123, 0)",
|
|
17
|
-
"foo.reduceRight(()=>123, 0)",
|
|
18
|
-
"foo.reduceRight(bar, baz)",
|
|
19
|
-
"reduce(()=>123)",
|
|
20
|
-
"foo.reduceLeft(()=>123)",
|
|
21
|
-
"Math.max(...foo)",
|
|
22
|
-
|
|
23
|
-
"new foo.Set(...bar)",
|
|
24
|
-
"new Set(bar)",
|
|
25
|
-
"new Set()",
|
|
26
|
-
];
|
|
27
|
-
const invalid = [
|
|
28
|
-
"[].push()",
|
|
29
|
-
"foo.push()",
|
|
30
|
-
|
|
31
|
-
"foo.reduce()",
|
|
32
|
-
"[].reduce(()=>123)",
|
|
33
|
-
"foo.reduce(()=>123)",
|
|
34
|
-
"foo.reduce(bar)",
|
|
35
|
-
"[].reduceRight(()=>123)",
|
|
36
|
-
"foo.reduceRight(()=>123)",
|
|
37
|
-
"foo.reduceRight(bar)",
|
|
38
|
-
"[].reduce(...foo)",
|
|
39
|
-
"[].reduce(...foo, ...bar)",
|
|
40
|
-
"Math.max()",
|
|
41
|
-
"Math.max(1)",
|
|
42
|
-
"Math.min(foo)",
|
|
43
|
-
|
|
44
|
-
"new Set(...foo)",
|
|
45
|
-
"new Set(foo,bar)",
|
|
46
|
-
];
|
|
47
|
-
|
|
48
|
-
test({ valid, invalid, ...callArgumentsLength });
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import type { Rule } from "eslint";
|
|
2
|
-
import type { CallExpression, NewExpression } from "estree";
|
|
3
|
-
import { getRuleName } from "../utils.ts";
|
|
4
|
-
|
|
5
|
-
// TODO: If https://github.com/sindresorhus/eslint-plugin-unicorn/issues/1356 is implemented, migrate this rule to `eslint-plugin-unicorn`
|
|
6
|
-
const name = getRuleName(import.meta.url);
|
|
7
|
-
const rule: Rule.RuleModule = {
|
|
8
|
-
meta: {
|
|
9
|
-
docs: {
|
|
10
|
-
description:
|
|
11
|
-
"Disallow calling a function with incorrect arguments length.",
|
|
12
|
-
},
|
|
13
|
-
messages: {
|
|
14
|
-
[`${name}/error`]:
|
|
15
|
-
"The arguments length of calling `{{ functionPattern }}` should be {{ lengthMsg }}",
|
|
16
|
-
},
|
|
17
|
-
schema: [{ type: "object" }], // TODO: enhance schema for checking options
|
|
18
|
-
},
|
|
19
|
-
create: (context) => {
|
|
20
|
-
const getLengthMsg = (expectedLength: unknown) => {
|
|
21
|
-
if (typeof expectedLength === "number") {
|
|
22
|
-
return String(expectedLength);
|
|
23
|
-
}
|
|
24
|
-
if (Array.isArray(expectedLength)) {
|
|
25
|
-
return expectedLength.join(" or ");
|
|
26
|
-
}
|
|
27
|
-
const result: string[] = [];
|
|
28
|
-
if (
|
|
29
|
-
typeof expectedLength === "object" &&
|
|
30
|
-
expectedLength &&
|
|
31
|
-
"min" in expectedLength
|
|
32
|
-
) {
|
|
33
|
-
result.push(`>= ${String(expectedLength.min)}`);
|
|
34
|
-
}
|
|
35
|
-
if (
|
|
36
|
-
typeof expectedLength === "object" &&
|
|
37
|
-
expectedLength &&
|
|
38
|
-
"max" in expectedLength
|
|
39
|
-
) {
|
|
40
|
-
result.push(`<= ${String(expectedLength.max)}`);
|
|
41
|
-
}
|
|
42
|
-
return result.join(" and ");
|
|
43
|
-
};
|
|
44
|
-
const isLengthValid = (length: number, expectedLength: unknown) => {
|
|
45
|
-
if (typeof expectedLength === "number") {
|
|
46
|
-
return length === expectedLength;
|
|
47
|
-
}
|
|
48
|
-
if (Array.isArray(expectedLength)) {
|
|
49
|
-
return expectedLength.includes(length);
|
|
50
|
-
}
|
|
51
|
-
const result: boolean[] = [];
|
|
52
|
-
if (
|
|
53
|
-
typeof expectedLength === "object" &&
|
|
54
|
-
expectedLength &&
|
|
55
|
-
"min" in expectedLength &&
|
|
56
|
-
typeof expectedLength.min === "number"
|
|
57
|
-
) {
|
|
58
|
-
result.push(length >= expectedLength.min);
|
|
59
|
-
}
|
|
60
|
-
if (
|
|
61
|
-
typeof expectedLength === "object" &&
|
|
62
|
-
expectedLength &&
|
|
63
|
-
"max" in expectedLength &&
|
|
64
|
-
typeof expectedLength.max === "number"
|
|
65
|
-
) {
|
|
66
|
-
result.push(length <= expectedLength.max);
|
|
67
|
-
}
|
|
68
|
-
return result.every((item) => item);
|
|
69
|
-
};
|
|
70
|
-
const report = (
|
|
71
|
-
node: CallExpression | NewExpression,
|
|
72
|
-
functionPattern: string,
|
|
73
|
-
expectedLength: unknown,
|
|
74
|
-
) => {
|
|
75
|
-
const argsLength = node.arguments.some(
|
|
76
|
-
(arg) => arg.type === "SpreadElement",
|
|
77
|
-
)
|
|
78
|
-
? Infinity
|
|
79
|
-
: node.arguments.length;
|
|
80
|
-
if (!isLengthValid(argsLength, expectedLength))
|
|
81
|
-
context.report({
|
|
82
|
-
node,
|
|
83
|
-
messageId: `${name}/error`,
|
|
84
|
-
data: {
|
|
85
|
-
functionPattern,
|
|
86
|
-
lengthMsg: getLengthMsg(expectedLength),
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const options = Object.entries(
|
|
92
|
-
context.options[0] ?? {
|
|
93
|
-
// 1
|
|
94
|
-
"*.reduce": 2,
|
|
95
|
-
"*.reduceRight": 2,
|
|
96
|
-
"*.push": { min: 1 },
|
|
97
|
-
"Math.max": { min: 2 },
|
|
98
|
-
"Math.min": { min: 2 },
|
|
99
|
-
// 2
|
|
100
|
-
"new Set": { max: 1 },
|
|
101
|
-
"new Map": { max: 1 },
|
|
102
|
-
},
|
|
103
|
-
).map(([pattern, expectedLength]) => ({
|
|
104
|
-
regex: new RegExp(
|
|
105
|
-
`^${pattern.replaceAll(".", "\\.").replaceAll("*", ".*")}$`,
|
|
106
|
-
),
|
|
107
|
-
pattern,
|
|
108
|
-
expectedLength,
|
|
109
|
-
}));
|
|
110
|
-
|
|
111
|
-
const handle = (node: CallExpression | NewExpression) => {
|
|
112
|
-
const prefix = node.type === "NewExpression" ? "new " : "";
|
|
113
|
-
|
|
114
|
-
const { callee } = node;
|
|
115
|
-
// function call
|
|
116
|
-
if (callee.type === "Identifier") {
|
|
117
|
-
// code like `foo()` or `new Foo()`
|
|
118
|
-
options
|
|
119
|
-
.filter((option) => option.regex.test(`${prefix}${callee.name}`))
|
|
120
|
-
.forEach(({ pattern, expectedLength }) => {
|
|
121
|
-
report(node, pattern, expectedLength);
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
// method call
|
|
125
|
-
else if (
|
|
126
|
-
callee.type === "MemberExpression" &&
|
|
127
|
-
callee.property.type === "Identifier"
|
|
128
|
-
) {
|
|
129
|
-
const { object: calleeObject, property: calleeProperty } = callee;
|
|
130
|
-
options
|
|
131
|
-
.filter((option) => {
|
|
132
|
-
// code like `Math.max()` or `new Foo.Bar()`, the calleeObject is `Math` or `Foo`
|
|
133
|
-
if (
|
|
134
|
-
"name" in calleeObject &&
|
|
135
|
-
option.regex.test(
|
|
136
|
-
`${prefix}${calleeObject.name}.${calleeProperty.name}`,
|
|
137
|
-
)
|
|
138
|
-
) {
|
|
139
|
-
return true;
|
|
140
|
-
}
|
|
141
|
-
// code like `[].reduce()` or `new ({Foo: class{}}).Foo()`, the calleeObject is `[]` or `{Foo: class{}}`
|
|
142
|
-
if (
|
|
143
|
-
!("name" in calleeObject) &&
|
|
144
|
-
option.regex.test(`${prefix}.${calleeProperty.name}`)
|
|
145
|
-
) {
|
|
146
|
-
return true;
|
|
147
|
-
}
|
|
148
|
-
return false;
|
|
149
|
-
})
|
|
150
|
-
.forEach(({ pattern, expectedLength }) => {
|
|
151
|
-
report(node, pattern, expectedLength);
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
return {
|
|
157
|
-
CallExpression: handle,
|
|
158
|
-
NewExpression: handle,
|
|
159
|
-
};
|
|
160
|
-
},
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
export const callArgumentsLength = { name, rule };
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { test } from "@fenge/dev-utils";
|
|
2
|
-
import { noInstanceofBuiltin } from "./no-instanceof-builtin.ts";
|
|
3
|
-
|
|
4
|
-
const invalid = [
|
|
5
|
-
// Primitive
|
|
6
|
-
"Number",
|
|
7
|
-
"String",
|
|
8
|
-
"Boolean",
|
|
9
|
-
"Symbol",
|
|
10
|
-
"BigInt",
|
|
11
|
-
|
|
12
|
-
// Object
|
|
13
|
-
"Object",
|
|
14
|
-
"Array",
|
|
15
|
-
"Function",
|
|
16
|
-
|
|
17
|
-
// Builtin
|
|
18
|
-
"ArrayBuffer",
|
|
19
|
-
"BigInt64Array",
|
|
20
|
-
"BigUint64Array",
|
|
21
|
-
"DataView",
|
|
22
|
-
"Date",
|
|
23
|
-
"Float32Array",
|
|
24
|
-
"Float64Array",
|
|
25
|
-
"Int16Array",
|
|
26
|
-
"Int32Array",
|
|
27
|
-
"Int8Array",
|
|
28
|
-
"Map",
|
|
29
|
-
"Error",
|
|
30
|
-
"Promise",
|
|
31
|
-
"Proxy",
|
|
32
|
-
"RegExp",
|
|
33
|
-
"Set",
|
|
34
|
-
"SharedArrayBuffer",
|
|
35
|
-
"Uint16Array",
|
|
36
|
-
"Uint32Array",
|
|
37
|
-
"Uint8Array",
|
|
38
|
-
"Uint8ClampedArray",
|
|
39
|
-
"WeakMap",
|
|
40
|
-
"WeakSet",
|
|
41
|
-
].map((i) => `const i = {} instanceof ${i}`);
|
|
42
|
-
|
|
43
|
-
const valid = [
|
|
44
|
-
"const i = Math.random() > 0.5 ? true: false",
|
|
45
|
-
"const i = {} instanceof await import('http')",
|
|
46
|
-
];
|
|
47
|
-
|
|
48
|
-
test({ valid, invalid, ...noInstanceofBuiltin });
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type { Rule } from "eslint";
|
|
2
|
-
import { getRuleName } from "../utils.ts";
|
|
3
|
-
|
|
4
|
-
// TODO: If https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2452 is accepted, migrate this rule to `eslint-plugin-unicorn`
|
|
5
|
-
const name = getRuleName(import.meta.url);
|
|
6
|
-
const rule: Rule.RuleModule = {
|
|
7
|
-
meta: {
|
|
8
|
-
docs: {
|
|
9
|
-
description: "Right hand of `instanceof` can't be a builtin class.",
|
|
10
|
-
},
|
|
11
|
-
messages: {
|
|
12
|
-
[`${name}/error`]: "Right hand of `instanceof` can't be a builtin class.",
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
create: (context) => {
|
|
16
|
-
let builtins: Set<string> | undefined = undefined;
|
|
17
|
-
return {
|
|
18
|
-
// ESLint visit the Node from root to leaf. The Program Node is the root.
|
|
19
|
-
// Therefore, Program will be called before BinaryExpression.
|
|
20
|
-
// https://eslint.org/docs/latest/extend/code-path-analysis
|
|
21
|
-
Program: (node) => {
|
|
22
|
-
const scope = context.sourceCode.getScope(node);
|
|
23
|
-
builtins = new Set([
|
|
24
|
-
// Variables declared in `globals`
|
|
25
|
-
...scope.variables.map((v) => v.name),
|
|
26
|
-
// Variables not declared at all
|
|
27
|
-
...scope.through.map((ref) => ref.identifier.name),
|
|
28
|
-
]);
|
|
29
|
-
},
|
|
30
|
-
BinaryExpression: (node) => {
|
|
31
|
-
if (
|
|
32
|
-
node.operator !== "instanceof" ||
|
|
33
|
-
node.right.type !== "Identifier"
|
|
34
|
-
) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (builtins?.has(node.right.name) ?? true) {
|
|
39
|
-
context.report({ node: node.right, messageId: `${name}/error` });
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export const noInstanceofBuiltin = { name, rule };
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { test } from "@fenge/dev-utils";
|
|
2
|
-
import { noNestedClass } from "./no-nested-class.ts";
|
|
3
|
-
|
|
4
|
-
const valid = [
|
|
5
|
-
"class Foo{}",
|
|
6
|
-
"export class Foo{}",
|
|
7
|
-
"export default class Foo{}",
|
|
8
|
-
"export default class {}",
|
|
9
|
-
];
|
|
10
|
-
|
|
11
|
-
const invalid = [
|
|
12
|
-
// nested
|
|
13
|
-
"if(true) class Foo{}",
|
|
14
|
-
"if(true) const foo = class {}",
|
|
15
|
-
"function foo(){class Foo{}}",
|
|
16
|
-
"function foo(){const foo = class {}}",
|
|
17
|
-
"function foo(){return class Foo{}}",
|
|
18
|
-
"function foo(){return class{}}",
|
|
19
|
-
|
|
20
|
-
// normal
|
|
21
|
-
"const Foo = class{}",
|
|
22
|
-
"let Foo = class Bar{}",
|
|
23
|
-
"let Foo; Foo = class{}",
|
|
24
|
-
"(class {})",
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
test({ valid, invalid, ...noNestedClass });
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { Rule } from "eslint";
|
|
2
|
-
import type { Node } from "estree";
|
|
3
|
-
import { getRuleName } from "../utils.ts";
|
|
4
|
-
|
|
5
|
-
const name = getRuleName(import.meta.url);
|
|
6
|
-
const rule: Rule.RuleModule = {
|
|
7
|
-
meta: {
|
|
8
|
-
docs: {
|
|
9
|
-
description:
|
|
10
|
-
"Disallow nested class. Classes are expected to place at top level.",
|
|
11
|
-
},
|
|
12
|
-
messages: {
|
|
13
|
-
[`${name}/error`]:
|
|
14
|
-
"Disallow nested class. Classes are expected to place at top level.",
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
create: (context) => {
|
|
18
|
-
const handle = (node: Node) =>
|
|
19
|
-
context.report({ node, messageId: `${name}/error` });
|
|
20
|
-
return {
|
|
21
|
-
// ClassDeclaration is only allowed when parent is Program, or parent is ExportNamedDeclaration, or parent is ExportDefaultDeclaration
|
|
22
|
-
"ClassDeclaration[parent.type!='Program'][parent.type!='ExportNamedDeclaration'][parent.type!='ExportDefaultDeclaration']":
|
|
23
|
-
handle,
|
|
24
|
-
// ClassExpression is only allowed when parent is ExportNamedDeclaration, or parent is ExportDefaultDeclaration
|
|
25
|
-
"ClassExpression[parent.type!='ExportNamedDeclaration'][parent.type!='ExportDefaultDeclaration']":
|
|
26
|
-
handle,
|
|
27
|
-
};
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export const noNestedClass = { name, rule };
|