@fenge/eslint-plugin 0.1.0-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/CHANGELOG.md +7 -0
- package/LICENSE +21 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/rules/call-arguments-length.d.ts +6 -0
- package/dist/rules/call-arguments-length.d.ts.map +1 -0
- package/dist/rules/call-arguments-length.js +112 -0
- package/dist/rules/no-instanceof-builtin.d.ts +6 -0
- package/dist/rules/no-instanceof-builtin.d.ts.map +1 -0
- package/dist/rules/no-instanceof-builtin.js +32 -0
- package/dist/rules/no-restricted-loops.d.ts +6 -0
- package/dist/rules/no-restricted-loops.d.ts.map +1 -0
- package/dist/rules/no-restricted-loops.js +24 -0
- package/dist/rules/no-unnecessary-template-string.d.ts +6 -0
- package/dist/rules/no-unnecessary-template-string.d.ts.map +1 -0
- package/dist/rules/no-unnecessary-template-string.js +24 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +7 -0
- package/package.json +36 -0
- package/src/index.ts +11 -0
- package/src/rules/call-arguments-length.spec.ts +44 -0
- package/src/rules/call-arguments-length.ts +139 -0
- package/src/rules/no-instanceof-builtin.spec.ts +48 -0
- package/src/rules/no-instanceof-builtin.ts +39 -0
- package/src/rules/no-restricted-loops.spec.ts +13 -0
- package/src/rules/no-restricted-loops.ts +30 -0
- package/src/rules/no-unnecessary-template-string.spec.ts +25 -0
- package/src/rules/no-unnecessary-template-string.ts +29 -0
- package/src/test.spec.ts +51 -0
- package/src/utils.ts +7 -0
- package/tsconfig.build.json +5 -0
- package/tsconfig.json +3 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 曾明健
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,KAAK;;CAKjB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { callArgumentsLength } from "./rules/call-arguments-length.js";
|
|
2
|
+
import { noInstanceofBuiltin } from "./rules/no-instanceof-builtin.js";
|
|
3
|
+
import { noRestrictedLoops } from "./rules/no-restricted-loops.js";
|
|
4
|
+
import { noUnnecessaryTemplateString } from "./rules/no-unnecessary-template-string.js";
|
|
5
|
+
export const rules = {
|
|
6
|
+
[callArgumentsLength.name]: callArgumentsLength.rule,
|
|
7
|
+
[noInstanceofBuiltin.name]: noInstanceofBuiltin.rule,
|
|
8
|
+
[noRestrictedLoops.name]: noRestrictedLoops.rule,
|
|
9
|
+
[noUnnecessaryTemplateString.name]: noUnnecessaryTemplateString.rule,
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDdkUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDdkUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDbkUsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sMkNBQTJDLENBQUM7QUFFeEYsTUFBTSxDQUFDLE1BQU0sS0FBSyxHQUFHO0lBQ25CLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLEVBQUUsbUJBQW1CLENBQUMsSUFBSTtJQUNwRCxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxFQUFFLG1CQUFtQixDQUFDLElBQUk7SUFDcEQsQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsRUFBRSxpQkFBaUIsQ0FBQyxJQUFJO0lBQ2hELENBQUMsMkJBQTJCLENBQUMsSUFBSSxDQUFDLEVBQUUsMkJBQTJCLENBQUMsSUFBSTtDQUNyRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY2FsbEFyZ3VtZW50c0xlbmd0aCB9IGZyb20gXCIuL3J1bGVzL2NhbGwtYXJndW1lbnRzLWxlbmd0aC5qc1wiO1xuaW1wb3J0IHsgbm9JbnN0YW5jZW9mQnVpbHRpbiB9IGZyb20gXCIuL3J1bGVzL25vLWluc3RhbmNlb2YtYnVpbHRpbi5qc1wiO1xuaW1wb3J0IHsgbm9SZXN0cmljdGVkTG9vcHMgfSBmcm9tIFwiLi9ydWxlcy9uby1yZXN0cmljdGVkLWxvb3BzLmpzXCI7XG5pbXBvcnQgeyBub1VubmVjZXNzYXJ5VGVtcGxhdGVTdHJpbmcgfSBmcm9tIFwiLi9ydWxlcy9uby11bm5lY2Vzc2FyeS10ZW1wbGF0ZS1zdHJpbmcuanNcIjtcblxuZXhwb3J0IGNvbnN0IHJ1bGVzID0ge1xuICBbY2FsbEFyZ3VtZW50c0xlbmd0aC5uYW1lXTogY2FsbEFyZ3VtZW50c0xlbmd0aC5ydWxlLFxuICBbbm9JbnN0YW5jZW9mQnVpbHRpbi5uYW1lXTogbm9JbnN0YW5jZW9mQnVpbHRpbi5ydWxlLFxuICBbbm9SZXN0cmljdGVkTG9vcHMubmFtZV06IG5vUmVzdHJpY3RlZExvb3BzLnJ1bGUsXG4gIFtub1VubmVjZXNzYXJ5VGVtcGxhdGVTdHJpbmcubmFtZV06IG5vVW5uZWNlc3NhcnlUZW1wbGF0ZVN0cmluZy5ydWxlLFxufTtcbiJdfQ==
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-arguments-length.d.ts","sourceRoot":"","sources":["../../src/rules/call-arguments-length.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AA0InC,eAAO,MAAM,mBAAmB;;;CAAiB,CAAC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { getRuleName } from "../utils.js";
|
|
2
|
+
// TODO: If https://github.com/sindresorhus/eslint-plugin-unicorn/issues/1356 is implemented, migrate this rule to `eslint-plugin-unicorn`
|
|
3
|
+
const name = getRuleName(import.meta.url);
|
|
4
|
+
const rule = {
|
|
5
|
+
meta: {
|
|
6
|
+
docs: {
|
|
7
|
+
description: "Disallow calling a function with incorrect arguments length.",
|
|
8
|
+
},
|
|
9
|
+
messages: {
|
|
10
|
+
[`${name}/error`]: "The arguments length of calling `{{ functionPattern }}` should be {{ lengthMsg }}",
|
|
11
|
+
},
|
|
12
|
+
schema: [{ type: "object" }], // TODO: enhance schema for checking options
|
|
13
|
+
},
|
|
14
|
+
create: (context) => {
|
|
15
|
+
const getLengthMsg = (expectedLength) => {
|
|
16
|
+
if (typeof expectedLength === "number") {
|
|
17
|
+
return String(expectedLength);
|
|
18
|
+
}
|
|
19
|
+
if (Array.isArray(expectedLength)) {
|
|
20
|
+
return expectedLength.join(" or ");
|
|
21
|
+
}
|
|
22
|
+
const result = [];
|
|
23
|
+
if (typeof expectedLength === "object" &&
|
|
24
|
+
expectedLength &&
|
|
25
|
+
"min" in expectedLength) {
|
|
26
|
+
result.push(`>= ${expectedLength.min}`);
|
|
27
|
+
}
|
|
28
|
+
if (typeof expectedLength === "object" &&
|
|
29
|
+
expectedLength &&
|
|
30
|
+
"max" in expectedLength) {
|
|
31
|
+
result.push(`<= ${expectedLength.max}`);
|
|
32
|
+
}
|
|
33
|
+
return result.join(" and ");
|
|
34
|
+
};
|
|
35
|
+
const isLengthValid = (length, expectedLength) => {
|
|
36
|
+
if (typeof expectedLength === "number") {
|
|
37
|
+
return length === expectedLength;
|
|
38
|
+
}
|
|
39
|
+
if (Array.isArray(expectedLength)) {
|
|
40
|
+
return expectedLength.includes(length);
|
|
41
|
+
}
|
|
42
|
+
const result = [];
|
|
43
|
+
if (typeof expectedLength === "object" &&
|
|
44
|
+
expectedLength &&
|
|
45
|
+
"min" in expectedLength &&
|
|
46
|
+
typeof expectedLength.min === "number") {
|
|
47
|
+
result.push(length >= expectedLength.min);
|
|
48
|
+
}
|
|
49
|
+
if (typeof expectedLength === "object" &&
|
|
50
|
+
expectedLength &&
|
|
51
|
+
"max" in expectedLength &&
|
|
52
|
+
typeof expectedLength.max === "number") {
|
|
53
|
+
result.push(length <= expectedLength.max);
|
|
54
|
+
}
|
|
55
|
+
return result.every((item) => item);
|
|
56
|
+
};
|
|
57
|
+
const report = (node, functionPattern, expectedLength) => {
|
|
58
|
+
const argsLength = node.arguments.some((arg) => arg.type === "SpreadElement")
|
|
59
|
+
? Infinity
|
|
60
|
+
: node.arguments.length;
|
|
61
|
+
if (!isLengthValid(argsLength, expectedLength))
|
|
62
|
+
context.report({
|
|
63
|
+
node,
|
|
64
|
+
messageId: `${name}/error`,
|
|
65
|
+
data: {
|
|
66
|
+
functionPattern,
|
|
67
|
+
lengthMsg: getLengthMsg(expectedLength),
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
const options = Object.entries(context.options[0] ?? {
|
|
72
|
+
"*.reduce": 2,
|
|
73
|
+
"*.reduceRight": 2,
|
|
74
|
+
"*.push": { min: 1 },
|
|
75
|
+
"new Set": { max: 1 },
|
|
76
|
+
"new Map": { max: 1 },
|
|
77
|
+
});
|
|
78
|
+
return {
|
|
79
|
+
CallExpression: (node) => {
|
|
80
|
+
// function call
|
|
81
|
+
if (node.callee.type === "Identifier") {
|
|
82
|
+
for (const [pattern, expectedLength] of options.filter(([pattern]) => !pattern.startsWith("*.") && !pattern.startsWith("new "))) {
|
|
83
|
+
if (node.callee.name !== pattern)
|
|
84
|
+
continue;
|
|
85
|
+
report(node, pattern, expectedLength);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// method call
|
|
89
|
+
else if (node.callee.type === "MemberExpression" &&
|
|
90
|
+
node.callee.property.type === "Identifier") {
|
|
91
|
+
for (const [pattern, expectedLength] of options.filter(([pattern]) => pattern.startsWith("*."))) {
|
|
92
|
+
if (node.callee.property.name !== pattern.split(".")[1])
|
|
93
|
+
continue;
|
|
94
|
+
report(node, pattern, expectedLength);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
// new call
|
|
99
|
+
NewExpression: (node) => {
|
|
100
|
+
if (node.callee.type !== "Identifier")
|
|
101
|
+
return;
|
|
102
|
+
for (const [pattern, expectedLength] of options.filter(([pattern]) => pattern.startsWith("new "))) {
|
|
103
|
+
if (node.callee.name !== pattern.split(" ")[1])
|
|
104
|
+
continue;
|
|
105
|
+
report(node, pattern, expectedLength);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
export const callArgumentsLength = { name, rule };
|
|
112
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FsbC1hcmd1bWVudHMtbGVuZ3RoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bGVzL2NhbGwtYXJndW1lbnRzLWxlbmd0aC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRTFDLDBJQUEwSTtBQUMxSSxNQUFNLElBQUksR0FBRyxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUMxQyxNQUFNLElBQUksR0FBb0I7SUFDNUIsSUFBSSxFQUFFO1FBQ0osSUFBSSxFQUFFO1lBQ0osV0FBVyxFQUNULDhEQUE4RDtTQUNqRTtRQUNELFFBQVEsRUFBRTtZQUNSLENBQUMsR0FBRyxJQUFJLFFBQVEsQ0FBQyxFQUNmLG1GQUFtRjtTQUN0RjtRQUNELE1BQU0sRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLEVBQUUsNENBQTRDO0tBQzNFO0lBQ0QsTUFBTSxFQUFFLENBQUMsT0FBTyxFQUFFLEVBQUU7UUFDbEIsTUFBTSxZQUFZLEdBQUcsQ0FBQyxjQUF1QixFQUFFLEVBQUU7WUFDL0MsSUFBSSxPQUFPLGNBQWMsS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDdkMsT0FBTyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUM7WUFDaEMsQ0FBQztZQUNELElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDO2dCQUNsQyxPQUFPLGNBQWMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDckMsQ0FBQztZQUNELE1BQU0sTUFBTSxHQUFhLEVBQUUsQ0FBQztZQUM1QixJQUNFLE9BQU8sY0FBYyxLQUFLLFFBQVE7Z0JBQ2xDLGNBQWM7Z0JBQ2QsS0FBSyxJQUFJLGNBQWMsRUFDdkIsQ0FBQztnQkFDRCxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sY0FBYyxDQUFDLEdBQUcsRUFB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QU8sRUFBRSxjQUFjLENBQUMsSUFBSSxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxFQUFFLENBQ25FLE9BQU8sQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQzNCLEVBQUUsQ0FBQztvQkFDRixJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO3dCQUFFLFNBQVM7b0JBQ3pELE1BQU0sQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLGNBQWMsQ0FBQyxDQUFDO2dCQUN4QyxDQUFDO1lBQ0gsQ0FBQztTQUNGLENBQUM7SUFDSixDQUFDO0NBQ0YsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBSdWxlIH0gZnJvbSBcImVzbGludFwiO1xuaW1wb3J0IHR5cGUgeyBDYWxsRXhwcmVzc2lvbiwgTmV3RXhwcmVzc2lvbiB9IGZyb20gXCJlc3RyZWVcIjtcbmltcG9ydCB7IGdldFJ1bGVOYW1lIH0gZnJvbSBcIi4uL3V0aWxzLmpzXCI7XG5cbi8vIFRPRE86IElmIGh0dHBzOi8vZ2l0aHViLmNvbS9zaW5kcmVzb3JodXMvZXNsaW50LXBsdWdpbi11bmljb3JuL2lzc3Vlcy8xMzU2IGlzIGltcGxlbWVudGVkLCBtaWdyYXRlIHRoaXMgcnVsZSB0byBgZXNsaW50LXBsdWdpbi11bmljb3JuYFxuY29uc3QgbmFtZSA9IGdldFJ1bGVOYW1lKGltcG9ydC5tZXRhLnVybCk7XG5jb25zdCBydWxlOiBSdWxlLlJ1bGVNb2R1bGUgPSB7XG4gIG1ldGE6IHtcbiAgICBkb2NzOiB7XG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgXCJEaXNhbGxvdyBjYWxsaW5nIGEgZnVuY3Rpb24gd2l0aCBpbmNvcnJlY3QgYXJndW1lbnRzIGxlbmd0aC5cIixcbiAgICB9LFxuICAgIG1lc3NhZ2VzOiB7XG4gICAgICBbYCR7bmFtZX0vZXJyb3JgXTpcbiAgICAgICAgXCJUaGUgYXJndW1lbnRzIGxlbmd0aCBvZiBjYWxsaW5nIGB7eyBmdW5jdGlvblBhdHRlcm4gfX1gIHNob3VsZCBiZSB7eyBsZW5ndGhNc2cgfX1cIixcbiAgICB9LFxuICAgIHNjaGVtYTogW3sgdHlwZTogXCJvYmplY3RcIiB9XSwgLy8gVE9ETzogZW5oYW5jZSBzY2hlbWEgZm9yIGNoZWNraW5nIG9wdGlvbnNcbiAgfSxcbiAgY3JlYXRlOiAoY29udGV4dCkgPT4ge1xuICAgIGNvbnN0IGdldExlbmd0aE1zZyA9IChleHBlY3RlZExlbmd0aDogdW5rbm93bikgPT4ge1xuICAgICAgaWYgKHR5cGVvZiBleHBlY3RlZExlbmd0aCA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICByZXR1cm4gU3RyaW5nKGV4cGVjdGVkTGVuZ3RoKTtcbiAgICAgIH1cbiAgICAgIGlmIChBcnJheS5pc0FycmF5KGV4cGVjdGVkTGVuZ3RoKSkge1xuICAgICAgICByZXR1cm4gZXhwZWN0ZWRMZW5ndGguam9pbihcIiBvciBcIik7XG4gICAgICB9XG4gICAgICBjb25zdCByZXN1bHQ6IHN0cmluZ1tdID0gW107XG4gICAgICBpZiAoXG4gICAgICAgIHR5cGVvZiBleHBlY3RlZExlbmd0aCA9PT0gXCJvYmplY3RcIiAmJlxuICAgICAgICBleHBlY3RlZExlbmd0aCAmJlxuICAgICAgICBcIm1pblwiIGluIGV4cGVjdGVkTGVuZ3RoXG4gICAgICApIHtcbiAgICAgICAgcmVzdWx0LnB1c2goYD49ICR7ZXhwZWN0ZWRMZW5ndGgubWlufWApO1xuICAgICAgfVxuICAgICAgaWYgKFxuICAgICAgICB0eXBlb2YgZXhwZWN0ZWRMZW5ndGggPT09IFwib2JqZWN0XCIgJiZcbiAgICAgICAgZXhwZWN0ZWRMZW5ndGggJiZcbiAgICAgICAgXCJtYXhcIiBpbiBleHBlY3RlZExlbmd0aFxuICAgICAgKSB7XG4gICAgICAgIHJlc3VsdC5wdXNoKGA8PSAke2V4cGVjdGVkTGVuZ3RoLm1heH1gKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQuam9pbihcIiBhbmQgXCIpO1xuICAgIH07XG4gICAgY29uc3QgaXNMZW5ndGhWYWxpZCA9IChsZW5ndGg6IG51bWJlciwgZXhwZWN0ZWRMZW5ndGg6IHVua25vd24pID0+IHtcbiAgICAgIGlmICh0eXBlb2YgZXhwZWN0ZWRMZW5ndGggPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgcmV0dXJuIGxlbmd0aCA9PT0gZXhwZWN0ZWRMZW5ndGg7XG4gICAgICB9XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShleHBlY3RlZExlbmd0aCkpIHtcbiAgICAgICAgcmV0dXJuIGV4cGVjdGVkTGVuZ3RoLmluY2x1ZGVzKGxlbmd0aCk7XG4gICAgICB9XG4gICAgICBjb25zdCByZXN1bHQ6IGJvb2xlYW5bXSA9IFtdO1xuICAgICAgaWYgKFxuICAgICAgICB0eXBlb2YgZXhwZWN0ZWRMZW5ndGggPT09IFwib2JqZWN0XCIgJiZcbiAgICAgICAgZXhwZWN0ZWRMZW5ndGggJiZcbiAgICAgICAgXCJtaW5cIiBpbiBleHBlY3RlZExlbmd0aCAmJlxuICAgICAgICB0eXBlb2YgZXhwZWN0ZWRMZW5ndGgubWluID09PSBcIm51bWJlclwiXG4gICAgICApIHtcbiAgICAgICAgcmVzdWx0LnB1c2gobGVuZ3RoID49IGV4cGVjdGVkTGVuZ3RoLm1pbik7XG4gICAgICB9XG4gICAgICBpZiAoXG4gICAgICAgIHR5cGVvZiBleHBlY3RlZExlbmd0aCA9PT0gXCJvYmplY3RcIiAmJlxuICAgICAgICBleHBlY3RlZExlbmd0aCAmJlxuICAgICAgICBcIm1heFwiIGluIGV4cGVjdGVkTGVuZ3RoICYmXG4gICAgICAgIHR5cGVvZiBleHBlY3RlZExlbmd0aC5tYXggPT09IFwibnVtYmVyXCJcbiAgICAgICkge1xuICAgICAgICByZXN1bHQucHVzaChsZW5ndGggPD0gZXhwZWN0ZWRMZW5ndGgubWF4KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQuZXZlcnkoKGl0ZW0pID0+IGl0ZW0pO1xuICAgIH07XG4gICAgY29uc3QgcmVwb3J0ID0gKFxuICAgICAgbm9kZTogQ2FsbEV4cHJlc3Npb24gfCBOZXdFeHByZXNzaW9uLFxuICAgICAgZnVuY3Rpb25QYXR0ZXJuOiBzdHJpbmcsXG4gICAgICBleHBlY3RlZExlbmd0aDogdW5rbm93bixcbiAgICApID0+IHtcbiAgICAgIGNvbnN0IGFyZ3NMZW5ndGggPSBub2RlLmFyZ3VtZW50cy5zb21lKFxuICAgICAgICAoYXJnKSA9PiBhcmcudHlwZSA9PT0gXCJTcHJlYWRFbGVtZW50XCIsXG4gICAgICApXG4gICAgICAgID8gSW5maW5pdHlcbiAgICAgICAgOiBub2RlLmFyZ3VtZW50cy5sZW5ndGg7XG4gICAgICBpZiAoIWlzTGVuZ3RoVmFsaWQoYXJnc0xlbmd0aCwgZXhwZWN0ZWRMZW5ndGgpKVxuICAgICAgICBjb250ZXh0LnJlcG9ydCh7XG4gICAgICAgICAgbm9kZSxcbiAgICAgICAgICBtZXNzYWdlSWQ6IGAke25hbWV9L2Vycm9yYCxcbiAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICBmdW5jdGlvblBhdHRlcm4sXG4gICAgICAgICAgICBsZW5ndGhNc2c6IGdldExlbmd0aE1zZyhleHBlY3RlZExlbmd0aCksXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuZW50cmllcyhcbiAgICAgIGNvbnRleHQub3B0aW9uc1swXSA/PyB7XG4gICAgICAgIFwiKi5yZWR1Y2VcIjogMixcbiAgICAgICAgXCIqLnJlZHVjZVJpZ2h0XCI6IDIsXG4gICAgICAgIFwiKi5wdXNoXCI6IHsgbWluOiAxIH0sXG4gICAgICAgIFwibmV3IFNldFwiOiB7IG1heDogMSB9LFxuICAgICAgICBcIm5ldyBNYXBcIjogeyBtYXg6IDEgfSxcbiAgICAgIH0sXG4gICAgKTtcbiAgICByZXR1cm4ge1xuICAgICAgQ2FsbEV4cHJlc3Npb246IChub2RlKSA9PiB7XG4gICAgICAgIC8vIGZ1bmN0aW9uIGNhbGxcbiAgICAgICAgaWYgKG5vZGUuY2FsbGVlLnR5cGUgPT09IFwiSWRlbnRpZmllclwiKSB7XG4gICAgICAgICAgZm9yIChjb25zdCBbcGF0dGVybiwgZXhwZWN0ZWRMZW5ndGhdIG9mIG9wdGlvbnMuZmlsdGVyKFxuICAgICAgICAgICAgKFtwYXR0ZXJuXSkgPT5cbiAgICAgICAgICAgICAgIXBhdHRlcm4uc3RhcnRzV2l0aChcIiouXCIpICYmICFwYXR0ZXJuLnN0YXJ0c1dpdGgoXCJuZXcgXCIpLFxuICAgICAgICAgICkpIHtcbiAgICAgICAgICAgIGlmIChub2RlLmNhbGxlZS5uYW1lICE9PSBwYXR0ZXJuKSBjb250aW51ZTtcbiAgICAgICAgICAgIHJlcG9ydChub2RlLCBwYXR0ZXJuLCBleHBlY3RlZExlbmd0aCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIG1ldGhvZCBjYWxsXG4gICAgICAgIGVsc2UgaWYgKFxuICAgICAgICAgIG5vZGUuY2FsbGVlLnR5cGUgPT09IFwiTWVtYmVyRXhwcmVzc2lvblwiICYmXG4gICAgICAgICAgbm9kZS5jYWxsZWUucHJvcGVydHkudHlwZSA9PT0gXCJJZGVudGlmaWVyXCJcbiAgICAgICAgKSB7XG4gICAgICAgICAgZm9yIChjb25zdCBbcGF0dGVybiwgZXhwZWN0ZWRMZW5ndGhdIG9mIG9wdGlvbnMuZmlsdGVyKChbcGF0dGVybl0pID0+XG4gICAgICAgICAgICBwYXR0ZXJuLnN0YXJ0c1dpdGgoXCIqLlwiKSxcbiAgICAgICAgICApKSB7XG4gICAgICAgICAgICBpZiAobm9kZS5jYWxsZWUucHJvcGVydHkubmFtZSAhPT0gcGF0dGVybi5zcGxpdChcIi5cIilbMV0pIGNvbnRpbnVlO1xuICAgICAgICAgICAgcmVwb3J0KG5vZGUsIHBhdHRlcm4sIGV4cGVjdGVkTGVuZ3RoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICAvLyBuZXcgY2FsbFxuICAgICAgTmV3RXhwcmVzc2lvbjogKG5vZGUpID0+IHtcbiAgICAgICAgaWYgKG5vZGUuY2FsbGVlLnR5cGUgIT09IFwiSWRlbnRpZmllclwiKSByZXR1cm47XG4gICAgICAgIGZvciAoY29uc3QgW3BhdHRlcm4sIGV4cGVjdGVkTGVuZ3RoXSBvZiBvcHRpb25zLmZpbHRlcigoW3BhdHRlcm5dKSA9PlxuICAgICAgICAgIHBhdHRlcm4uc3RhcnRzV2l0aChcIm5ldyBcIiksXG4gICAgICAgICkpIHtcbiAgICAgICAgICBpZiAobm9kZS5jYWxsZWUubmFtZSAhPT0gcGF0dGVybi5zcGxpdChcIiBcIilbMV0pIGNvbnRpbnVlO1xuICAgICAgICAgIHJlcG9ydChub2RlLCBwYXR0ZXJuLCBleHBlY3RlZExlbmd0aCk7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgfTtcbiAgfSxcbn07XG5cbmV4cG9ydCBjb25zdCBjYWxsQXJndW1lbnRzTGVuZ3RoID0geyBuYW1lLCBydWxlIH07XG4iXX0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-instanceof-builtin.d.ts","sourceRoot":"","sources":["../../src/rules/no-instanceof-builtin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAsCnC,eAAO,MAAM,mBAAmB;;;CAAiB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getRuleName } from "../utils.js";
|
|
2
|
+
// TODO: If https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2452 is accepted, migrate this rule to `eslint-plugin-unicorn`
|
|
3
|
+
const name = getRuleName(import.meta.url);
|
|
4
|
+
const rule = {
|
|
5
|
+
meta: {
|
|
6
|
+
docs: {
|
|
7
|
+
description: "Right hand of `instanceof` can't be a builtin class.",
|
|
8
|
+
},
|
|
9
|
+
messages: {
|
|
10
|
+
[`${name}/error`]: "Right hand of `instanceof` can't be a builtin class.",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
create: (context) => {
|
|
14
|
+
let builtins = undefined;
|
|
15
|
+
return {
|
|
16
|
+
Program: (node) => {
|
|
17
|
+
builtins = new Set(context.sourceCode.getScope(node).variables.map((v) => v.name));
|
|
18
|
+
},
|
|
19
|
+
BinaryExpression: (node) => {
|
|
20
|
+
if (node.operator !== "instanceof" ||
|
|
21
|
+
node.right.type !== "Identifier") {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (builtins?.has(node.right.name) ?? true) {
|
|
25
|
+
context.report({ node: node.right, messageId: `${name}/error` });
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
export const noInstanceofBuiltin = { name, rule };
|
|
32
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm8taW5zdGFuY2VvZi1idWlsdGluLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bGVzL25vLWluc3RhbmNlb2YtYnVpbHRpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRTFDLHVJQUF1STtBQUN2SSxNQUFNLElBQUksR0FBRyxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUMxQyxNQUFNLElBQUksR0FBb0I7SUFDNUIsSUFBSSxFQUFFO1FBQ0osSUFBSSxFQUFFO1lBQ0osV0FBVyxFQUFFLHNEQUFzRDtTQUNwRTtRQUNELFFBQVEsRUFBRTtZQUNSLENBQUMsR0FBRyxJQUFJLFFBQVEsQ0FBQyxFQUFFLHNEQUFzRDtTQUMxRTtLQUNGO0lBQ0QsTUFBTSxFQUFFLENBQUMsT0FBTyxFQUFFLEVBQUU7UUFDbEIsSUFBSSxRQUFRLEdBQTRCLFNBQVMsQ0FBQztRQUNsRCxPQUFPO1lBQ0wsT0FBTyxFQUFFLENBQUMsSUFBSSxFQUFFLEVBQUU7Z0JBQ2hCLFFBQVEsR0FBRyxJQUFJLEdBQUcsQ0FDaEIsT0FBTyxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUMvRCxDQUFDO1lBQ0osQ0FBQztZQUNELGdCQUFnQixFQUFFLENBQUMsSUFBSSxFQUFFLEVBQUU7Z0JBQ3pCLElBQ0UsSUFBSSxDQUFDLFFBQVEsS0FBSyxZQUFZO29CQUM5QixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxZQUFZLEVBQ2hDLENBQUM7b0JBQ0QsT0FBTztnQkFDVCxDQUFDO2dCQUVELElBQUksUUFBUSxFQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDO29CQUMzQyxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLEdBQUcsSUFBSSxRQUFRLEVBQUUsQ0FBQyxDQUFDO2dCQUNuRSxDQUFDO1lBQ0gsQ0FBQztTQUNGLENBQUM7SUFDSixDQUFDO0NBQ0YsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBSdWxlIH0gZnJvbSBcImVzbGludFwiO1xuaW1wb3J0IHsgZ2V0UnVsZU5hbWUgfSBmcm9tIFwiLi4vdXRpbHMuanNcIjtcblxuLy8gVE9ETzogSWYgaHR0cHM6Ly9naXRodWIuY29tL3NpbmRyZXNvcmh1cy9lc2xpbnQtcGx1Z2luLXVuaWNvcm4vaXNzdWVzLzI0NTIgaXMgYWNjZXB0ZWQsIG1pZ3JhdGUgdGhpcyBydWxlIHRvIGBlc2xpbnQtcGx1Z2luLXVuaWNvcm5gXG5jb25zdCBuYW1lID0gZ2V0UnVsZU5hbWUoaW1wb3J0Lm1ldGEudXJsKTtcbmNvbnN0IHJ1bGU6IFJ1bGUuUnVsZU1vZHVsZSA9IHtcbiAgbWV0YToge1xuICAgIGRvY3M6IHtcbiAgICAgIGRlc2NyaXB0aW9uOiBcIlJpZ2h0IGhhbmQgb2YgYGluc3RhbmNlb2ZgIGNhbid0IGJlIGEgYnVpbHRpbiBjbGFzcy5cIixcbiAgICB9LFxuICAgIG1lc3NhZ2VzOiB7XG4gICAgICBbYCR7bmFtZX0vZXJyb3JgXTogXCJSaWdodCBoYW5kIG9mIGBpbnN0YW5jZW9mYCBjYW4ndCBiZSBhIGJ1aWx0aW4gY2xhc3MuXCIsXG4gICAgfSxcbiAgfSxcbiAgY3JlYXRlOiAoY29udGV4dCkgPT4ge1xuICAgIGxldCBidWlsdGluczogU2V0PHN0cmluZz4gfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHtcbiAgICAgIFByb2dyYW06IChub2RlKSA9PiB7XG4gICAgICAgIGJ1aWx0aW5zID0gbmV3IFNldChcbiAgICAgICAgICBjb250ZXh0LnNvdXJjZUNvZGUuZ2V0U2NvcGUobm9kZSkudmFyaWFibGVzLm1hcCgodikgPT4gdi5uYW1lKSxcbiAgICAgICAgKTtcbiAgICAgIH0sXG4gICAgICBCaW5hcnlFeHByZXNzaW9uOiAobm9kZSkgPT4ge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgbm9kZS5vcGVyYXRvciAhPT0gXCJpbnN0YW5jZW9mXCIgfHxcbiAgICAgICAgICBub2RlLnJpZ2h0LnR5cGUgIT09IFwiSWRlbnRpZmllclwiXG4gICAgICAgICkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChidWlsdGlucz8uaGFzKG5vZGUucmlnaHQubmFtZSkgPz8gdHJ1ZSkge1xuICAgICAgICAgIGNvbnRleHQucmVwb3J0KHsgbm9kZTogbm9kZS5yaWdodCwgbWVzc2FnZUlkOiBgJHtuYW1lfS9lcnJvcmAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgfTtcbiAgfSxcbn07XG5cbmV4cG9ydCBjb25zdCBub0luc3RhbmNlb2ZCdWlsdGluID0geyBuYW1lLCBydWxlIH07XG4iXX0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-restricted-loops.d.ts","sourceRoot":"","sources":["../../src/rules/no-restricted-loops.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AA6BnC,eAAO,MAAM,iBAAiB;;;CAAiB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { getRuleName } from "../utils.js";
|
|
2
|
+
// TODO: If https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2453 is accepted, migrate this rule to `eslint-plugin-unicorn`
|
|
3
|
+
const name = getRuleName(import.meta.url);
|
|
4
|
+
/**
|
|
5
|
+
* Only allow `while` and `for-of` loops. `for`, `for-in`, `do-while` and `for-await-of` loops are disallowed.
|
|
6
|
+
* Visit https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2453 for more details.
|
|
7
|
+
*/
|
|
8
|
+
const rule = {
|
|
9
|
+
meta: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: "Only allow `while` and `for-of` loops. `for`, `for-in`, `do-while` and `for-await-of` loops are disallowed.",
|
|
12
|
+
},
|
|
13
|
+
messages: {
|
|
14
|
+
[`${name}/error`]: "Only allow `while` and `for-of` loops. `for`, `for-in`, `do-while` and `for-await-of` loops are disallowed.",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
create: (context) => ({
|
|
18
|
+
":matches(ForStatement, ForInStatement, DoWhileStatement, ForOfStatement[await=true])": (node) => {
|
|
19
|
+
context.report({ node, messageId: `${name}/error` });
|
|
20
|
+
},
|
|
21
|
+
}),
|
|
22
|
+
};
|
|
23
|
+
export const noRestrictedLoops = { name, rule };
|
|
24
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm8tcmVzdHJpY3RlZC1sb29wcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydWxlcy9uby1yZXN0cmljdGVkLWxvb3BzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFMUMsdUlBQXVJO0FBQ3ZJLE1BQU0sSUFBSSxHQUFHLFdBQVcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQzFDOzs7R0FHRztBQUNILE1BQU0sSUFBSSxHQUFvQjtJQUM1QixJQUFJLEVBQUU7UUFDSixJQUFJLEVBQUU7WUFDSixXQUFXLEVBQ1QsNkdBQTZHO1NBQ2hIO1FBQ0QsUUFBUSxFQUFFO1lBQ1IsQ0FBQyxHQUFHLElBQUksUUFBUSxDQUFDLEVBQ2YsNkdBQTZHO1NBQ2hIO0tBQ0Y7SUFDRCxNQUFNLEVBQUUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDcEIsc0ZBQXNGLEVBQ3BGLENBQUMsSUFBVSxFQUFFLEVBQUU7WUFDYixPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxHQUFHLElBQUksUUFBUSxFQUFFLENBQUMsQ0FBQztRQUN2RCxDQUFDO0tBQ0osQ0FBQztDQUNILENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgUnVsZSB9IGZyb20gXCJlc2xpbnRcIjtcbmltcG9ydCB0eXBlIHsgTm9kZSB9IGZyb20gXCJlc3RyZWVcIjtcbmltcG9ydCB7IGdldFJ1bGVOYW1lIH0gZnJvbSBcIi4uL3V0aWxzLmpzXCI7XG5cbi8vIFRPRE86IElmIGh0dHBzOi8vZ2l0aHViLmNvbS9zaW5kcmVzb3JodXMvZXNsaW50LXBsdWdpbi11bmljb3JuL2lzc3Vlcy8yNDUzIGlzIGFjY2VwdGVkLCBtaWdyYXRlIHRoaXMgcnVsZSB0byBgZXNsaW50LXBsdWdpbi11bmljb3JuYFxuY29uc3QgbmFtZSA9IGdldFJ1bGVOYW1lKGltcG9ydC5tZXRhLnVybCk7XG4vKipcbiAqIE9ubHkgYWxsb3cgYHdoaWxlYCBhbmQgYGZvci1vZmAgbG9vcHMuIGBmb3JgLCBgZm9yLWluYCwgYGRvLXdoaWxlYCBhbmQgYGZvci1hd2FpdC1vZmAgbG9vcHMgYXJlIGRpc2FsbG93ZWQuXG4gKiBWaXNpdCBodHRwczovL2dpdGh1Yi5jb20vc2luZHJlc29yaHVzL2VzbGludC1wbHVnaW4tdW5pY29ybi9pc3N1ZXMvMjQ1MyBmb3IgbW9yZSBkZXRhaWxzLlxuICovXG5jb25zdCBydWxlOiBSdWxlLlJ1bGVNb2R1bGUgPSB7XG4gIG1ldGE6IHtcbiAgICBkb2NzOiB7XG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgXCJPbmx5IGFsbG93IGB3aGlsZWAgYW5kIGBmb3Itb2ZgIGxvb3BzLiBgZm9yYCwgYGZvci1pbmAsIGBkby13aGlsZWAgYW5kIGBmb3ItYXdhaXQtb2ZgIGxvb3BzIGFyZSBkaXNhbGxvd2VkLlwiLFxuICAgIH0sXG4gICAgbWVzc2FnZXM6IHtcbiAgICAgIFtgJHtuYW1lfS9lcnJvcmBdOlxuICAgICAgICBcIk9ubHkgYWxsb3cgYHdoaWxlYCBhbmQgYGZvci1vZmAgbG9vcHMuIGBmb3JgLCBgZm9yLWluYCwgYGRvLXdoaWxlYCBhbmQgYGZvci1hd2FpdC1vZmAgbG9vcHMgYXJlIGRpc2FsbG93ZWQuXCIsXG4gICAgfSxcbiAgfSxcbiAgY3JlYXRlOiAoY29udGV4dCkgPT4gKHtcbiAgICBcIjptYXRjaGVzKEZvclN0YXRlbWVudCwgRm9ySW5TdGF0ZW1lbnQsIERvV2hpbGVTdGF0ZW1lbnQsIEZvck9mU3RhdGVtZW50W2F3YWl0PXRydWVdKVwiOlxuICAgICAgKG5vZGU6IE5vZGUpID0+IHtcbiAgICAgICAgY29udGV4dC5yZXBvcnQoeyBub2RlLCBtZXNzYWdlSWQ6IGAke25hbWV9L2Vycm9yYCB9KTtcbiAgICAgIH0sXG4gIH0pLFxufTtcblxuZXhwb3J0IGNvbnN0IG5vUmVzdHJpY3RlZExvb3BzID0geyBuYW1lLCBydWxlIH07XG4iXX0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-unnecessary-template-string.d.ts","sourceRoot":"","sources":["../../src/rules/no-unnecessary-template-string.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AA4BnC,eAAO,MAAM,2BAA2B;;;CAAiB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { getRuleName } from "../utils.js";
|
|
2
|
+
// TODO deprecate this rule if https://github.com/sindresorhus/eslint-plugin-unicorn/issues/71 is implemented.
|
|
3
|
+
const name = getRuleName(import.meta.url);
|
|
4
|
+
const rule = {
|
|
5
|
+
meta: {
|
|
6
|
+
docs: {
|
|
7
|
+
description: "Disallow using template string when it's unnecessary. Use normal literal string expression instead.",
|
|
8
|
+
},
|
|
9
|
+
messages: {
|
|
10
|
+
[`${name}/error`]: "Disallow using template string when it's unnecessary. Use normal literal string expression instead.",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
create: (context) => ({
|
|
14
|
+
TemplateLiteral: (node) => {
|
|
15
|
+
if (node.quasis.length === 1 &&
|
|
16
|
+
node.expressions.length === 0 &&
|
|
17
|
+
node.loc?.start.line === node.loc?.end.line) {
|
|
18
|
+
context.report({ node, messageId: `${name}/error` });
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
}),
|
|
22
|
+
};
|
|
23
|
+
export const noUnnecessaryTemplateString = { name, rule };
|
|
24
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm8tdW5uZWNlc3NhcnktdGVtcGxhdGUtc3RyaW5nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bGVzL25vLXVubmVjZXNzYXJ5LXRlbXBsYXRlLXN0cmluZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRTFDLDhHQUE4RztBQUM5RyxNQUFNLElBQUksR0FBRyxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUMxQyxNQUFNLElBQUksR0FBb0I7SUFDNUIsSUFBSSxFQUFFO1FBQ0osSUFBSSxFQUFFO1lBQ0osV0FBVyxFQUNULHFHQUFxRztTQUN4RztRQUNELFFBQVEsRUFBRTtZQUNSLENBQUMsR0FBRyxJQUFJLFFBQVEsQ0FBQyxFQUNmLHFHQUFxRztTQUN4RztLQUNGO0lBQ0QsTUFBTSxFQUFFLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3BCLGVBQWUsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFO1lBQ3hCLElBQ0UsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQztnQkFDeEIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEtBQUssQ0FBQztnQkFDN0IsSUFBSSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxLQUFLLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLElBQUksRUFDM0MsQ0FBQztnQkFDRCxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxHQUFHLElBQUksUUFBUSxFQUFFLENBQUMsQ0FBQztZQUN2RCxDQUFDO1FBQ0gsQ0FBQztLQUNGLENBQUM7Q0FDSCxDQUFDO0FBQ0YsTUFBTSxDQUFDLE1BQU0sMkJBQTJCLEdBQUcsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IFJ1bGUgfSBmcm9tIFwiZXNsaW50XCI7XG5pbXBvcnQgeyBnZXRSdWxlTmFtZSB9IGZyb20gXCIuLi91dGlscy5qc1wiO1xuXG4vLyBUT0RPIGRlcHJlY2F0ZSB0aGlzIHJ1bGUgaWYgaHR0cHM6Ly9naXRodWIuY29tL3NpbmRyZXNvcmh1cy9lc2xpbnQtcGx1Z2luLXVuaWNvcm4vaXNzdWVzLzcxIGlzIGltcGxlbWVudGVkLlxuY29uc3QgbmFtZSA9IGdldFJ1bGVOYW1lKGltcG9ydC5tZXRhLnVybCk7XG5jb25zdCBydWxlOiBSdWxlLlJ1bGVNb2R1bGUgPSB7XG4gIG1ldGE6IHtcbiAgICBkb2NzOiB7XG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgXCJEaXNhbGxvdyB1c2luZyB0ZW1wbGF0ZSBzdHJpbmcgd2hlbiBpdCdzIHVubmVjZXNzYXJ5LiBVc2Ugbm9ybWFsIGxpdGVyYWwgc3RyaW5nIGV4cHJlc3Npb24gaW5zdGVhZC5cIixcbiAgICB9LFxuICAgIG1lc3NhZ2VzOiB7XG4gICAgICBbYCR7bmFtZX0vZXJyb3JgXTpcbiAgICAgICAgXCJEaXNhbGxvdyB1c2luZyB0ZW1wbGF0ZSBzdHJpbmcgd2hlbiBpdCdzIHVubmVjZXNzYXJ5LiBVc2Ugbm9ybWFsIGxpdGVyYWwgc3RyaW5nIGV4cHJlc3Npb24gaW5zdGVhZC5cIixcbiAgICB9LFxuICB9LFxuICBjcmVhdGU6IChjb250ZXh0KSA9PiAoe1xuICAgIFRlbXBsYXRlTGl0ZXJhbDogKG5vZGUpID0+IHtcbiAgICAgIGlmIChcbiAgICAgICAgbm9kZS5xdWFzaXMubGVuZ3RoID09PSAxICYmXG4gICAgICAgIG5vZGUuZXhwcmVzc2lvbnMubGVuZ3RoID09PSAwICYmXG4gICAgICAgIG5vZGUubG9jPy5zdGFydC5saW5lID09PSBub2RlLmxvYz8uZW5kLmxpbmVcbiAgICAgICkge1xuICAgICAgICBjb250ZXh0LnJlcG9ydCh7IG5vZGUsIG1lc3NhZ2VJZDogYCR7bmFtZX0vZXJyb3JgIH0pO1xuICAgICAgfVxuICAgIH0sXG4gIH0pLFxufTtcbmV4cG9ydCBjb25zdCBub1VubmVjZXNzYXJ5VGVtcGxhdGVTdHJpbmcgPSB7IG5hbWUsIHJ1bGUgfTtcbiJdfQ==
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,wBAAgB,WAAW,CAAC,aAAa,EAAE,MAAM,UAGhD"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
export function getRuleName(importMetaUrl) {
|
|
4
|
+
// remove '.js' extension
|
|
5
|
+
return path.basename(fileURLToPath(importMetaUrl)).slice(0, -3);
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxJQUFJLE1BQU0sV0FBVyxDQUFDO0FBQzdCLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFFekMsTUFBTSxVQUFVLFdBQVcsQ0FBQyxhQUFxQjtJQUMvQyx5QkFBeUI7SUFDekIsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNsRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHBhdGggZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gXCJub2RlOnVybFwiO1xuXG5leHBvcnQgZnVuY3Rpb24gZ2V0UnVsZU5hbWUoaW1wb3J0TWV0YVVybDogc3RyaW5nKSB7XG4gIC8vIHJlbW92ZSAnLmpzJyBleHRlbnNpb25cbiAgcmV0dXJuIHBhdGguYmFzZW5hbWUoZmlsZVVSTFRvUGF0aChpbXBvcnRNZXRhVXJsKSkuc2xpY2UoMCwgLTMpO1xufVxuIl19
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fenge/eslint-plugin",
|
|
3
|
+
"version": "0.1.0-beta.0",
|
|
4
|
+
"description": "ESLint plugin for JavaScript.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"opinionated",
|
|
7
|
+
"strict",
|
|
8
|
+
"eslint",
|
|
9
|
+
"config",
|
|
10
|
+
"eslint-config",
|
|
11
|
+
"eslint-plugin"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/zanminkian/fenge/tree/main/packages/eslint-plugin",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/zanminkian/fenge.git",
|
|
17
|
+
"directory": "packages/eslint-plugin"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "hellozmj@qq.com",
|
|
21
|
+
"type": "module",
|
|
22
|
+
"exports": "./dist/index.js",
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@swc-node/register": "1.10.0",
|
|
25
|
+
"@types/eslint": "8.56.11",
|
|
26
|
+
"@types/estree": "1.0.6",
|
|
27
|
+
"@types/json-schema": "7.0.15",
|
|
28
|
+
"@types/node": "22.7.5",
|
|
29
|
+
"@typescript-eslint/parser": "7.16.1",
|
|
30
|
+
"eslint": "8.57.0"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc -p tsconfig.build.json",
|
|
34
|
+
"test": "globstar -- node --test --import @swc-node/register/esm-register src/**/*.spec.ts"
|
|
35
|
+
}
|
|
36
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { callArgumentsLength } from "./rules/call-arguments-length.js";
|
|
2
|
+
import { noInstanceofBuiltin } from "./rules/no-instanceof-builtin.js";
|
|
3
|
+
import { noRestrictedLoops } from "./rules/no-restricted-loops.js";
|
|
4
|
+
import { noUnnecessaryTemplateString } from "./rules/no-unnecessary-template-string.js";
|
|
5
|
+
|
|
6
|
+
export const rules = {
|
|
7
|
+
[callArgumentsLength.name]: callArgumentsLength.rule,
|
|
8
|
+
[noInstanceofBuiltin.name]: noInstanceofBuiltin.rule,
|
|
9
|
+
[noRestrictedLoops.name]: noRestrictedLoops.rule,
|
|
10
|
+
[noUnnecessaryTemplateString.name]: noUnnecessaryTemplateString.rule,
|
|
11
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { test } from "../test.spec.js";
|
|
2
|
+
import { callArgumentsLength } from "./call-arguments-length.js";
|
|
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
|
+
|
|
22
|
+
"new foo.Set(...bar)",
|
|
23
|
+
"new Set(bar)",
|
|
24
|
+
"new Set()",
|
|
25
|
+
];
|
|
26
|
+
const invalid = [
|
|
27
|
+
"[].push()",
|
|
28
|
+
"foo.push()",
|
|
29
|
+
|
|
30
|
+
"foo.reduce()",
|
|
31
|
+
"[].reduce(()=>123)",
|
|
32
|
+
"foo.reduce(()=>123)",
|
|
33
|
+
"foo.reduce(bar)",
|
|
34
|
+
"[].reduceRight(()=>123)",
|
|
35
|
+
"foo.reduceRight(()=>123)",
|
|
36
|
+
"foo.reduceRight(bar)",
|
|
37
|
+
"[].reduce(...foo)",
|
|
38
|
+
"[].reduce(...foo, ...bar)",
|
|
39
|
+
|
|
40
|
+
"new Set(...foo)",
|
|
41
|
+
"new Set(foo,bar)",
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
test({ valid, invalid, ...callArgumentsLength });
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type { Rule } from "eslint";
|
|
2
|
+
import type { CallExpression, NewExpression } from "estree";
|
|
3
|
+
import { getRuleName } from "../utils.js";
|
|
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(`>= ${expectedLength.min}`);
|
|
34
|
+
}
|
|
35
|
+
if (
|
|
36
|
+
typeof expectedLength === "object" &&
|
|
37
|
+
expectedLength &&
|
|
38
|
+
"max" in expectedLength
|
|
39
|
+
) {
|
|
40
|
+
result.push(`<= ${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
|
+
"*.reduce": 2,
|
|
94
|
+
"*.reduceRight": 2,
|
|
95
|
+
"*.push": { min: 1 },
|
|
96
|
+
"new Set": { max: 1 },
|
|
97
|
+
"new Map": { max: 1 },
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
return {
|
|
101
|
+
CallExpression: (node) => {
|
|
102
|
+
// function call
|
|
103
|
+
if (node.callee.type === "Identifier") {
|
|
104
|
+
for (const [pattern, expectedLength] of options.filter(
|
|
105
|
+
([pattern]) =>
|
|
106
|
+
!pattern.startsWith("*.") && !pattern.startsWith("new "),
|
|
107
|
+
)) {
|
|
108
|
+
if (node.callee.name !== pattern) continue;
|
|
109
|
+
report(node, pattern, expectedLength);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// method call
|
|
113
|
+
else if (
|
|
114
|
+
node.callee.type === "MemberExpression" &&
|
|
115
|
+
node.callee.property.type === "Identifier"
|
|
116
|
+
) {
|
|
117
|
+
for (const [pattern, expectedLength] of options.filter(([pattern]) =>
|
|
118
|
+
pattern.startsWith("*."),
|
|
119
|
+
)) {
|
|
120
|
+
if (node.callee.property.name !== pattern.split(".")[1]) continue;
|
|
121
|
+
report(node, pattern, expectedLength);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
// new call
|
|
126
|
+
NewExpression: (node) => {
|
|
127
|
+
if (node.callee.type !== "Identifier") return;
|
|
128
|
+
for (const [pattern, expectedLength] of options.filter(([pattern]) =>
|
|
129
|
+
pattern.startsWith("new "),
|
|
130
|
+
)) {
|
|
131
|
+
if (node.callee.name !== pattern.split(" ")[1]) continue;
|
|
132
|
+
report(node, pattern, expectedLength);
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const callArgumentsLength = { name, rule };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { test } from "../test.spec.js";
|
|
2
|
+
import { noInstanceofBuiltin } from "./no-instanceof-builtin.js";
|
|
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", // Proxy does not exist in the default globals definition
|
|
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 });
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Rule } from "eslint";
|
|
2
|
+
import { getRuleName } from "../utils.js";
|
|
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
|
+
Program: (node) => {
|
|
19
|
+
builtins = new Set(
|
|
20
|
+
context.sourceCode.getScope(node).variables.map((v) => v.name),
|
|
21
|
+
);
|
|
22
|
+
},
|
|
23
|
+
BinaryExpression: (node) => {
|
|
24
|
+
if (
|
|
25
|
+
node.operator !== "instanceof" ||
|
|
26
|
+
node.right.type !== "Identifier"
|
|
27
|
+
) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (builtins?.has(node.right.name) ?? true) {
|
|
32
|
+
context.report({ node: node.right, messageId: `${name}/error` });
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const noInstanceofBuiltin = { name, rule };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { test } from "../test.spec.js";
|
|
2
|
+
import { noRestrictedLoops } from "./no-restricted-loops.js";
|
|
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 });
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Rule } from "eslint";
|
|
2
|
+
import type { Node } from "estree";
|
|
3
|
+
import { getRuleName } from "../utils.js";
|
|
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 };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { test } from "../test.spec.js";
|
|
2
|
+
import { noUnnecessaryTemplateString } from "./no-unnecessary-template-string.js";
|
|
3
|
+
|
|
4
|
+
const valid = [
|
|
5
|
+
"'abc'",
|
|
6
|
+
'"def"',
|
|
7
|
+
"`ab${cd}ef`", // eslint-disable-line no-template-curly-in-string
|
|
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 });
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Rule } from "eslint";
|
|
2
|
+
import { getRuleName } from "../utils.js";
|
|
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/test.spec.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import { RuleTester, type Rule } from "eslint";
|
|
4
|
+
|
|
5
|
+
export type TestCase = string | { code: string; filename?: string };
|
|
6
|
+
|
|
7
|
+
const tester = new RuleTester({
|
|
8
|
+
parser: createRequire(import.meta.url).resolve("@typescript-eslint/parser"),
|
|
9
|
+
parserOptions: { ecmaVersion: "latest", sourceType: "module" },
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export async function test({
|
|
13
|
+
name,
|
|
14
|
+
rule,
|
|
15
|
+
valid,
|
|
16
|
+
invalid,
|
|
17
|
+
errors = 1,
|
|
18
|
+
}: {
|
|
19
|
+
name: string;
|
|
20
|
+
rule: Rule.RuleModule;
|
|
21
|
+
valid: TestCase[];
|
|
22
|
+
invalid: TestCase[];
|
|
23
|
+
errors?: number;
|
|
24
|
+
}) {
|
|
25
|
+
await describe(name, async () => {
|
|
26
|
+
await Promise.all(
|
|
27
|
+
valid.map(async (testCase) => {
|
|
28
|
+
await it(JSON.stringify(testCase), () => {
|
|
29
|
+
tester.run(name, rule, {
|
|
30
|
+
valid: [testCase],
|
|
31
|
+
invalid: [],
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
await Promise.all(
|
|
38
|
+
invalid.map(async (testCase) => {
|
|
39
|
+
await it(JSON.stringify(testCase), () => {
|
|
40
|
+
const code = typeof testCase === "string" ? testCase : testCase.code;
|
|
41
|
+
const filename =
|
|
42
|
+
typeof testCase === "string" ? undefined : testCase.filename;
|
|
43
|
+
tester.run(name, rule, {
|
|
44
|
+
valid: [],
|
|
45
|
+
invalid: [{ code, errors, filename }],
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}),
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
}
|
package/src/utils.ts
ADDED
package/tsconfig.json
ADDED