@fenge/eslint-plugin 0.3.0 → 0.4.1
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 +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/rules/call-arguments-length.d.ts.map +1 -1
- package/dist/rules/call-arguments-length.js +1 -1
- package/dist/rules/no-nested-class.d.ts.map +1 -1
- package/dist/rules/no-nested-class.js +1 -1
- package/dist/rules/no-nested-function.d.ts.map +1 -1
- package/dist/rules/no-nested-function.js +1 -1
- package/dist/rules/no-restricted-loops.d.ts.map +1 -1
- package/dist/rules/no-restricted-loops.js +1 -1
- package/dist/rules/no-top-level-arrow-function.d.ts.map +1 -1
- package/dist/rules/no-top-level-arrow-function.js +1 -1
- 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 +33 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +1 -1
- package/package.json +9 -4
- package/CHANGELOG.md +0 -40
- 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.spec.ts +0 -48
- package/src/rules/call-arguments-length.ts +0 -163
- package/src/rules/no-instanceof-builtin.spec.ts +0 -48
- package/src/rules/no-instanceof-builtin.ts +0 -46
- package/src/rules/no-nested-class.spec.ts +0 -27
- package/src/rules/no-nested-class.ts +0 -31
- package/src/rules/no-nested-function.spec.ts +0 -49
- package/src/rules/no-nested-function.ts +0 -32
- package/src/rules/no-restricted-loops.spec.ts +0 -13
- package/src/rules/no-restricted-loops.ts +0 -30
- package/src/rules/no-top-level-arrow-function.spec.ts +0 -32
- package/src/rules/no-top-level-arrow-function.ts +0 -35
- package/src/rules/no-unnecessary-template-string.spec.ts +0 -25
- package/src/rules/no-unnecessary-template-string.ts +0 -29
- package/src/utils.ts +0 -7
- package/tsconfig.json +0 -5
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 };
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { test } from "@fenge/dev-utils";
|
|
2
|
-
import { noNestedFunction } from "./no-nested-function.ts";
|
|
3
|
-
|
|
4
|
-
const valid = [
|
|
5
|
-
// normal
|
|
6
|
-
"function foo(){}",
|
|
7
|
-
"const foo = () => {}",
|
|
8
|
-
|
|
9
|
-
// export
|
|
10
|
-
"export function foo() {}",
|
|
11
|
-
"export default function foo() {}",
|
|
12
|
-
"export default function() {}",
|
|
13
|
-
|
|
14
|
-
// class
|
|
15
|
-
"class Foo{bar(){}}",
|
|
16
|
-
];
|
|
17
|
-
|
|
18
|
-
const invalid = [
|
|
19
|
-
// normal
|
|
20
|
-
"Foo.prototype.bar = function(){}",
|
|
21
|
-
"Foo.prototype.bar = function bar(){}",
|
|
22
|
-
"const foo = function(){}",
|
|
23
|
-
"const foo = function foo(){}",
|
|
24
|
-
"let foo; foo = function(){}",
|
|
25
|
-
"let foo; foo = function foo(){}",
|
|
26
|
-
"(function(){})",
|
|
27
|
-
|
|
28
|
-
// nested
|
|
29
|
-
"const foo = () => {function bar(){}}",
|
|
30
|
-
"function foo() {function bar(){}}",
|
|
31
|
-
"function foo() {let bar = function(){}}",
|
|
32
|
-
"function foo() {let bar = function bar(){}}",
|
|
33
|
-
"if(true) function foo(){}",
|
|
34
|
-
|
|
35
|
-
// class
|
|
36
|
-
"class Foo{bar = function(){}}",
|
|
37
|
-
"class Foo{bar = function bar(){}}",
|
|
38
|
-
|
|
39
|
-
// object
|
|
40
|
-
"const foo = {bar: function() {}}",
|
|
41
|
-
"const foo = {bar: function bar() {}}",
|
|
42
|
-
"const foo = {bar() {}}", // disallow this case
|
|
43
|
-
|
|
44
|
-
// callback
|
|
45
|
-
"setTimeout(function(){},100)",
|
|
46
|
-
"setTimeout(function callback(){},100)",
|
|
47
|
-
];
|
|
48
|
-
|
|
49
|
-
test({ valid, invalid, ...noNestedFunction });
|
|
@@ -1,32 +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
|
-
"Non top-level functions are expected to be arrow functions instead of function declarations.",
|
|
11
|
-
},
|
|
12
|
-
messages: {
|
|
13
|
-
[`${name}/error`]:
|
|
14
|
-
"Non top-level functions are expected to be arrow functions instead of function declarations.",
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
create: (context) => {
|
|
18
|
-
const handle = (node: Node) =>
|
|
19
|
-
context.report({ node, messageId: `${name}/error` });
|
|
20
|
-
return {
|
|
21
|
-
// FunctionDeclaration is only allowed when parent is Program, or parent is ExportNamedDeclaration, or parent is ExportDefaultDeclaration
|
|
22
|
-
// function foo(){}
|
|
23
|
-
"FunctionDeclaration[parent.type!='Program'][parent.type!='ExportNamedDeclaration'][parent.type!='ExportDefaultDeclaration']":
|
|
24
|
-
handle,
|
|
25
|
-
// FunctionExpression is only allowed when parent is MethodDefinition
|
|
26
|
-
// function (){}
|
|
27
|
-
"FunctionExpression[parent.type!='MethodDefinition']": handle,
|
|
28
|
-
};
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export const noNestedFunction = { name, rule };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { test } from "@fenge/dev-utils";
|
|
2
|
-
import { noRestrictedLoops } from "./no-restricted-loops.ts";
|
|
3
|
-
|
|
4
|
-
const valid = ["for(const bar of foo) {}", "while(condition){}"];
|
|
5
|
-
|
|
6
|
-
const invalid = [
|
|
7
|
-
"for(let i = 0; i < foo.length; i++) {}",
|
|
8
|
-
"for(const bar in foo) {}",
|
|
9
|
-
"do{}while(condition)",
|
|
10
|
-
"for await (const bar of foo()) {}",
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
test({ valid, invalid, ...noRestrictedLoops });
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { Rule } from "eslint";
|
|
2
|
-
import type { Node } from "estree";
|
|
3
|
-
import { getRuleName } from "../utils.ts";
|
|
4
|
-
|
|
5
|
-
// TODO: If https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2453 is accepted, migrate this rule to `eslint-plugin-unicorn`
|
|
6
|
-
const name = getRuleName(import.meta.url);
|
|
7
|
-
/**
|
|
8
|
-
* Only allow `while` and `for-of` loops. `for`, `for-in`, `do-while` and `for-await-of` loops are disallowed.
|
|
9
|
-
* Visit https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2453 for more details.
|
|
10
|
-
*/
|
|
11
|
-
const rule: Rule.RuleModule = {
|
|
12
|
-
meta: {
|
|
13
|
-
docs: {
|
|
14
|
-
description:
|
|
15
|
-
"Only allow `while` and `for-of` loops. `for`, `for-in`, `do-while` and `for-await-of` loops are disallowed.",
|
|
16
|
-
},
|
|
17
|
-
messages: {
|
|
18
|
-
[`${name}/error`]:
|
|
19
|
-
"Only allow `while` and `for-of` loops. `for`, `for-in`, `do-while` and `for-await-of` loops are disallowed.",
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
create: (context) => ({
|
|
23
|
-
":matches(ForStatement, ForInStatement, DoWhileStatement, ForOfStatement[await=true])":
|
|
24
|
-
(node: Node) => {
|
|
25
|
-
context.report({ node, messageId: `${name}/error` });
|
|
26
|
-
},
|
|
27
|
-
}),
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export const noRestrictedLoops = { name, rule };
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { test } from "@fenge/dev-utils";
|
|
2
|
-
import { noTopLevelArrowFunction } from "./no-top-level-arrow-function.ts";
|
|
3
|
-
|
|
4
|
-
const valid = [
|
|
5
|
-
"function foo(){}",
|
|
6
|
-
"const foo = function(){}",
|
|
7
|
-
"const foo = function foo(){}",
|
|
8
|
-
"if(true) const foo = () => {\n}",
|
|
9
|
-
|
|
10
|
-
// allow one-line function
|
|
11
|
-
"let foo = () => ''",
|
|
12
|
-
"let foo = () => [\n]",
|
|
13
|
-
"let foo = () => ({})",
|
|
14
|
-
"const foo = () => ({})",
|
|
15
|
-
"let foo; foo = () => ({})",
|
|
16
|
-
"export const foo = () => ({})",
|
|
17
|
-
"export let foo = () => ({})",
|
|
18
|
-
"export default () => ({})",
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
const invalid = [
|
|
22
|
-
"let foo = () => {}",
|
|
23
|
-
"const foo = () => {}",
|
|
24
|
-
"let foo = () => {\n}",
|
|
25
|
-
"const foo = () => {\n}",
|
|
26
|
-
"let foo; foo = () => {\n}",
|
|
27
|
-
"export const foo = () => {\n}",
|
|
28
|
-
"export let foo = () => {\n}",
|
|
29
|
-
"export default () => {\n}",
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
test({ valid, invalid, ...noTopLevelArrowFunction });
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { Rule } from "eslint";
|
|
2
|
-
import type { ArrowFunctionExpression } 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
|
-
"Top-level functions are expected to be function declarations instead of arrow functions.",
|
|
11
|
-
},
|
|
12
|
-
messages: {
|
|
13
|
-
[`${name}/error`]:
|
|
14
|
-
"Top-level functions are expected to be function declarations instead of arrow functions.",
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
create: (context) => {
|
|
18
|
-
const handle = (node: ArrowFunctionExpression) => {
|
|
19
|
-
if (node.body.type === "BlockStatement") {
|
|
20
|
-
context.report({ node, messageId: `${name}/error` });
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
return {
|
|
24
|
-
"VariableDeclaration[parent.type='Program'] > VariableDeclarator > ArrowFunctionExpression":
|
|
25
|
-
handle,
|
|
26
|
-
"ExpressionStatement[parent.type='Program'] > AssignmentExpression > ArrowFunctionExpression":
|
|
27
|
-
handle,
|
|
28
|
-
"ExportNamedDeclaration > VariableDeclaration > VariableDeclarator > ArrowFunctionExpression":
|
|
29
|
-
handle,
|
|
30
|
-
"ExportDefaultDeclaration > ArrowFunctionExpression": handle,
|
|
31
|
-
};
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export const noTopLevelArrowFunction = { name, rule };
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { test } from "@fenge/dev-utils";
|
|
2
|
-
import { noUnnecessaryTemplateString } from "./no-unnecessary-template-string.ts";
|
|
3
|
-
|
|
4
|
-
const valid = [
|
|
5
|
-
"'abc'",
|
|
6
|
-
'"def"',
|
|
7
|
-
"`ab${cd}ef`",
|
|
8
|
-
"`\n`",
|
|
9
|
-
"`abc\n`",
|
|
10
|
-
"`\nabc`",
|
|
11
|
-
"`a\nbc`",
|
|
12
|
-
];
|
|
13
|
-
|
|
14
|
-
const invalid = [
|
|
15
|
-
// Currently, tagged template string should be reported as well.
|
|
16
|
-
// Moving it to `valid` part is also reasonable.
|
|
17
|
-
"outdent`foo`",
|
|
18
|
-
"``",
|
|
19
|
-
"`abc`",
|
|
20
|
-
"`abc\\n`",
|
|
21
|
-
"`\\nabc`",
|
|
22
|
-
"`a\\nbc`",
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
test({ valid, invalid, ...noUnnecessaryTemplateString });
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { Rule } from "eslint";
|
|
2
|
-
import { getRuleName } from "../utils.ts";
|
|
3
|
-
|
|
4
|
-
// TODO deprecate this rule if https://github.com/sindresorhus/eslint-plugin-unicorn/issues/71 is implemented.
|
|
5
|
-
const name = getRuleName(import.meta.url);
|
|
6
|
-
const rule: Rule.RuleModule = {
|
|
7
|
-
meta: {
|
|
8
|
-
docs: {
|
|
9
|
-
description:
|
|
10
|
-
"Disallow using template string when it's unnecessary. Use normal literal string expression instead.",
|
|
11
|
-
},
|
|
12
|
-
messages: {
|
|
13
|
-
[`${name}/error`]:
|
|
14
|
-
"Disallow using template string when it's unnecessary. Use normal literal string expression instead.",
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
create: (context) => ({
|
|
18
|
-
TemplateLiteral: (node) => {
|
|
19
|
-
if (
|
|
20
|
-
node.quasis.length === 1 &&
|
|
21
|
-
node.expressions.length === 0 &&
|
|
22
|
-
node.loc?.start.line === node.loc?.end.line
|
|
23
|
-
) {
|
|
24
|
-
context.report({ node, messageId: `${name}/error` });
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
}),
|
|
28
|
-
};
|
|
29
|
-
export const noUnnecessaryTemplateString = { name, rule };
|
package/src/utils.ts
DELETED