eslint-plugin-unicorn-ts 0.0.1-security → 50.0.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.
Potentially problematic release.
This version of eslint-plugin-unicorn-ts might be problematic. Click here for more details.
- package/configs/all.js +6 -0
- package/configs/flat-config-base.js +10 -0
- package/configs/legacy-config-base.js +10 -0
- package/configs/recommended.js +117 -0
- package/index.js +91 -0
- package/license +9 -0
- package/package.json +186 -4
- package/readme.md +356 -0
- package/rules/ast/call-or-new-expression.js +127 -0
- package/rules/ast/function-types.js +5 -0
- package/rules/ast/index.js +39 -0
- package/rules/ast/is-arrow-function-body.js +7 -0
- package/rules/ast/is-empty-node.js +20 -0
- package/rules/ast/is-expression-statement.js +11 -0
- package/rules/ast/is-function.js +8 -0
- package/rules/ast/is-member-expression.js +101 -0
- package/rules/ast/is-method-call.js +65 -0
- package/rules/ast/is-reference-identifier.js +156 -0
- package/rules/ast/is-static-require.js +14 -0
- package/rules/ast/is-undefined.js +7 -0
- package/rules/ast/literal.js +29 -0
- package/rules/better-regex.js +144 -0
- package/rules/catch-error-name.js +136 -0
- package/rules/consistent-destructuring.js +168 -0
- package/rules/consistent-function-scoping.js +223 -0
- package/rules/custom-error-definition.js +215 -0
- package/rules/empty-brace-spaces.js +72 -0
- package/rules/error-message.js +104 -0
- package/rules/escape-case.js +63 -0
- package/rules/expiring-todo-comments.js +580 -0
- package/rules/explicit-length-check.js +229 -0
- package/rules/filename-case.js +258 -0
- package/rules/fix/add-parenthesizes-to-return-or-throw-expression.js +21 -0
- package/rules/fix/append-argument.js +20 -0
- package/rules/fix/extend-fix-range.js +15 -0
- package/rules/fix/fix-space-around-keywords.js +35 -0
- package/rules/fix/index.js +23 -0
- package/rules/fix/remove-argument.js +32 -0
- package/rules/fix/remove-member-expression-property.js +11 -0
- package/rules/fix/remove-method-call.js +20 -0
- package/rules/fix/remove-parentheses.js +11 -0
- package/rules/fix/remove-spaces-after.js +14 -0
- package/rules/fix/rename-variable.js +9 -0
- package/rules/fix/replace-argument.js +8 -0
- package/rules/fix/replace-node-or-token-and-spaces-before.js +21 -0
- package/rules/fix/replace-reference-identifier.js +35 -0
- package/rules/fix/replace-string-literal.js +11 -0
- package/rules/fix/replace-string-raw.js +14 -0
- package/rules/fix/replace-template-element.js +11 -0
- package/rules/fix/switch-call-expression-to-new-expression.js +18 -0
- package/rules/fix/switch-new-expression-to-call-expression.js +34 -0
- package/rules/import-style.js +364 -0
- package/rules/new-for-builtins.js +85 -0
- package/rules/no-abusive-eslint-disable.js +48 -0
- package/rules/no-array-callback-reference.js +256 -0
- package/rules/no-array-for-each.js +473 -0
- package/rules/no-array-method-this-argument.js +188 -0
- package/rules/no-array-push-push.js +144 -0
- package/rules/no-array-reduce.js +126 -0
- package/rules/no-await-expression-member.js +90 -0
- package/rules/no-console-spaces.js +86 -0
- package/rules/no-document-cookie.js +25 -0
- package/rules/no-empty-file.js +57 -0
- package/rules/no-for-loop.js +427 -0
- package/rules/no-hex-escape.js +46 -0
- package/rules/no-instanceof-array.js +65 -0
- package/rules/no-invalid-remove-event-listener.js +60 -0
- package/rules/no-keyword-prefix.js +199 -0
- package/rules/no-lonely-if.js +151 -0
- package/rules/no-negated-condition.js +144 -0
- package/rules/no-nested-ternary.js +58 -0
- package/rules/no-new-array.js +104 -0
- package/rules/no-new-buffer.js +98 -0
- package/rules/no-null.js +153 -0
- package/rules/no-object-as-default-parameter.js +50 -0
- package/rules/no-process-exit.js +104 -0
- package/rules/no-static-only-class.js +224 -0
- package/rules/no-thenable.js +198 -0
- package/rules/no-this-assignment.js +38 -0
- package/rules/no-typeof-undefined.js +143 -0
- package/rules/no-unnecessary-await.js +107 -0
- package/rules/no-unnecessary-polyfills.js +176 -0
- package/rules/no-unreadable-array-destructuring.js +83 -0
- package/rules/no-unreadable-iife.js +45 -0
- package/rules/no-unused-properties.js +238 -0
- package/rules/no-useless-fallback-in-spread.js +68 -0
- package/rules/no-useless-length-check.js +152 -0
- package/rules/no-useless-promise-resolve-reject.js +212 -0
- package/rules/no-useless-spread.js +381 -0
- package/rules/no-useless-switch-case.js +71 -0
- package/rules/no-useless-undefined.js +301 -0
- package/rules/no-zero-fractions.js +79 -0
- package/rules/number-literal-case.js +52 -0
- package/rules/numeric-separators-style.js +181 -0
- package/rules/prefer-add-event-listener.js +188 -0
- package/rules/prefer-array-find.js +423 -0
- package/rules/prefer-array-flat-map.js +82 -0
- package/rules/prefer-array-flat.js +279 -0
- package/rules/prefer-array-index-of.js +32 -0
- package/rules/prefer-array-some.js +157 -0
- package/rules/prefer-at.js +374 -0
- package/rules/prefer-blob-reading-methods.js +45 -0
- package/rules/prefer-code-point.js +67 -0
- package/rules/prefer-date-now.js +135 -0
- package/rules/prefer-default-parameters.js +219 -0
- package/rules/prefer-dom-node-append.js +48 -0
- package/rules/prefer-dom-node-dataset.js +120 -0
- package/rules/prefer-dom-node-remove.js +122 -0
- package/rules/prefer-dom-node-text-content.js +75 -0
- package/rules/prefer-event-target.js +117 -0
- package/rules/prefer-export-from.js +413 -0
- package/rules/prefer-includes.js +98 -0
- package/rules/prefer-json-parse-buffer.js +159 -0
- package/rules/prefer-keyboard-event-key.js +186 -0
- package/rules/prefer-logical-operator-over-ternary.js +159 -0
- package/rules/prefer-math-trunc.js +109 -0
- package/rules/prefer-modern-dom-apis.js +141 -0
- package/rules/prefer-modern-math-apis.js +212 -0
- package/rules/prefer-module.js +349 -0
- package/rules/prefer-native-coercion-functions.js +185 -0
- package/rules/prefer-negative-index.js +213 -0
- package/rules/prefer-node-protocol.js +61 -0
- package/rules/prefer-number-properties.js +126 -0
- package/rules/prefer-object-from-entries.js +252 -0
- package/rules/prefer-optional-catch-binding.js +75 -0
- package/rules/prefer-prototype-methods.js +88 -0
- package/rules/prefer-query-selector.js +135 -0
- package/rules/prefer-reflect-apply.js +97 -0
- package/rules/prefer-regexp-test.js +156 -0
- package/rules/prefer-set-has.js +186 -0
- package/rules/prefer-set-size.js +103 -0
- package/rules/prefer-spread.js +529 -0
- package/rules/prefer-string-replace-all.js +145 -0
- package/rules/prefer-string-slice.js +182 -0
- package/rules/prefer-string-starts-ends-with.js +199 -0
- package/rules/prefer-string-trim-start-end.js +44 -0
- package/rules/prefer-switch.js +344 -0
- package/rules/prefer-ternary.js +282 -0
- package/rules/prefer-top-level-await.js +152 -0
- package/rules/prefer-type-error.js +151 -0
- package/rules/prevent-abbreviations.js +645 -0
- package/rules/relative-url-style.js +168 -0
- package/rules/require-array-join-separator.js +63 -0
- package/rules/require-number-to-fixed-digits-argument.js +54 -0
- package/rules/require-post-message-target-origin.js +71 -0
- package/rules/shared/abbreviations.js +262 -0
- package/rules/shared/dom-events.js +275 -0
- package/rules/shared/event-keys.js +52 -0
- package/rules/shared/negative-index.js +46 -0
- package/rules/shared/simple-array-search-rule.js +128 -0
- package/rules/shared/typed-array.js +16 -0
- package/rules/string-content.js +187 -0
- package/rules/switch-case-braces.js +109 -0
- package/rules/template-indent.js +219 -0
- package/rules/text-encoding-identifier-case.js +108 -0
- package/rules/throw-new-error.js +53 -0
- package/rules/utils/array-or-object-prototype-property.js +63 -0
- package/rules/utils/assert-token.js +32 -0
- package/rules/utils/avoid-capture.js +146 -0
- package/rules/utils/boolean.js +92 -0
- package/rules/utils/builtins.js +36 -0
- package/rules/utils/cartesian-product-samples.js +24 -0
- package/rules/utils/create-deprecated-rules.js +25 -0
- package/rules/utils/escape-string.js +26 -0
- package/rules/utils/escape-template-element-raw.js +6 -0
- package/rules/utils/get-ancestor.js +20 -0
- package/rules/utils/get-builtin-rule.js +7 -0
- package/rules/utils/get-call-expression-arguments-text.js +21 -0
- package/rules/utils/get-class-head-location.js +22 -0
- package/rules/utils/get-documentation-url.js +10 -0
- package/rules/utils/get-indent-string.js +11 -0
- package/rules/utils/get-previous-node.js +24 -0
- package/rules/utils/get-references.js +9 -0
- package/rules/utils/get-scopes.js +14 -0
- package/rules/utils/get-switch-case-head-location.js +21 -0
- package/rules/utils/get-variable-identifiers.js +7 -0
- package/rules/utils/global-reference-tracker.js +72 -0
- package/rules/utils/has-optional-chain-element.js +21 -0
- package/rules/utils/has-same-range.js +7 -0
- package/rules/utils/index.js +53 -0
- package/rules/utils/is-function-self-used-inside.js +43 -0
- package/rules/utils/is-left-hand-side.js +22 -0
- package/rules/utils/is-logical-expression.js +16 -0
- package/rules/utils/is-method-named.js +9 -0
- package/rules/utils/is-new-expression-with-parentheses.js +26 -0
- package/rules/utils/is-node-matches.js +53 -0
- package/rules/utils/is-node-value-not-dom-node.js +21 -0
- package/rules/utils/is-node-value-not-function.js +42 -0
- package/rules/utils/is-number.js +224 -0
- package/rules/utils/is-object-method.js +11 -0
- package/rules/utils/is-on-same-line.js +7 -0
- package/rules/utils/is-same-identifier.js +8 -0
- package/rules/utils/is-same-reference.js +173 -0
- package/rules/utils/is-shadowed.js +33 -0
- package/rules/utils/is-shorthand-export-local.js +9 -0
- package/rules/utils/is-shorthand-import-local.js +9 -0
- package/rules/utils/is-shorthand-property-assignment-pattern-left.js +10 -0
- package/rules/utils/is-shorthand-property-value.js +8 -0
- package/rules/utils/is-value-not-usable.js +5 -0
- package/rules/utils/lodash.js +1589 -0
- package/rules/utils/needs-semicolon.js +114 -0
- package/rules/utils/numeric.js +53 -0
- package/rules/utils/parentheses.js +73 -0
- package/rules/utils/resolve-variable-name.js +20 -0
- package/rules/utils/rule.js +190 -0
- package/rules/utils/should-add-parentheses-to-conditional-expression-child.js +17 -0
- package/rules/utils/should-add-parentheses-to-expression-statement-expression.js +26 -0
- package/rules/utils/should-add-parentheses-to-logical-expression-child.js +47 -0
- package/rules/utils/should-add-parentheses-to-member-expression-object.js +47 -0
- package/rules/utils/should-add-parentheses-to-new-expression-callee.js +32 -0
- package/rules/utils/should-add-parentheses-to-spread-element-argument.js +22 -0
- package/rules/utils/singular.js +18 -0
- package/rules/utils/to-location.js +21 -0
- package/README.md +0 -5
@@ -0,0 +1,146 @@
|
|
1
|
+
'use strict';
|
2
|
+
const {
|
3
|
+
isIdentifierName,
|
4
|
+
isStrictReservedWord,
|
5
|
+
isKeyword,
|
6
|
+
} = require('@babel/helper-validator-identifier');
|
7
|
+
const resolveVariableName = require('./resolve-variable-name.js');
|
8
|
+
const getReferences = require('./get-references.js');
|
9
|
+
|
10
|
+
// https://github.com/microsoft/TypeScript/issues/2536#issuecomment-87194347
|
11
|
+
const typescriptReservedWords = new Set([
|
12
|
+
'break',
|
13
|
+
'case',
|
14
|
+
'catch',
|
15
|
+
'class',
|
16
|
+
'const',
|
17
|
+
'continue',
|
18
|
+
'debugger',
|
19
|
+
'default',
|
20
|
+
'delete',
|
21
|
+
'do',
|
22
|
+
'else',
|
23
|
+
'enum',
|
24
|
+
'export',
|
25
|
+
'extends',
|
26
|
+
'false',
|
27
|
+
'finally',
|
28
|
+
'for',
|
29
|
+
'function',
|
30
|
+
'if',
|
31
|
+
'import',
|
32
|
+
'in',
|
33
|
+
'instanceof',
|
34
|
+
'new',
|
35
|
+
'null',
|
36
|
+
'return',
|
37
|
+
'super',
|
38
|
+
'switch',
|
39
|
+
'this',
|
40
|
+
'throw',
|
41
|
+
'true',
|
42
|
+
'try',
|
43
|
+
'typeof',
|
44
|
+
'var',
|
45
|
+
'void',
|
46
|
+
'while',
|
47
|
+
'with',
|
48
|
+
'as',
|
49
|
+
'implements',
|
50
|
+
'interface',
|
51
|
+
'let',
|
52
|
+
'package',
|
53
|
+
'private',
|
54
|
+
'protected',
|
55
|
+
'public',
|
56
|
+
'static',
|
57
|
+
'yield',
|
58
|
+
'any',
|
59
|
+
'boolean',
|
60
|
+
'constructor',
|
61
|
+
'declare',
|
62
|
+
'get',
|
63
|
+
'module',
|
64
|
+
'require',
|
65
|
+
'number',
|
66
|
+
'set',
|
67
|
+
'string',
|
68
|
+
'symbol',
|
69
|
+
'type',
|
70
|
+
'from',
|
71
|
+
'of',
|
72
|
+
]);
|
73
|
+
|
74
|
+
// Copied from https://github.com/babel/babel/blob/fce35af69101c6b316557e28abf60bdbf77d6a36/packages/babel-types/src/validators/isValidIdentifier.ts#L7
|
75
|
+
// Use this function instead of `require('@babel/types').isIdentifier`, since `@babel/helper-validator-identifier` package is much smaller
|
76
|
+
const isValidIdentifier = name =>
|
77
|
+
typeof name === 'string'
|
78
|
+
&& !isKeyword(name)
|
79
|
+
&& !isStrictReservedWord(name, true)
|
80
|
+
&& isIdentifierName(name)
|
81
|
+
&& name !== 'arguments'
|
82
|
+
&& !typescriptReservedWords.has(name);
|
83
|
+
|
84
|
+
/*
|
85
|
+
Unresolved reference is probably from the global scope. We should avoid using that name.
|
86
|
+
|
87
|
+
For example, like `foo` and `bar` below.
|
88
|
+
|
89
|
+
```
|
90
|
+
function unicorn() {
|
91
|
+
return foo;
|
92
|
+
}
|
93
|
+
|
94
|
+
function unicorn() {
|
95
|
+
return function() {
|
96
|
+
return bar;
|
97
|
+
};
|
98
|
+
}
|
99
|
+
```
|
100
|
+
*/
|
101
|
+
const isUnresolvedName = (name, scope) =>
|
102
|
+
getReferences(scope).some(({identifier, resolved}) => identifier?.name === name && !resolved);
|
103
|
+
|
104
|
+
const isSafeName = (name, scopes) =>
|
105
|
+
!scopes.some(scope => resolveVariableName(name, scope) || isUnresolvedName(name, scope));
|
106
|
+
|
107
|
+
const alwaysTrue = () => true;
|
108
|
+
|
109
|
+
/**
|
110
|
+
Rule-specific name check function.
|
111
|
+
|
112
|
+
@callback isSafe
|
113
|
+
@param {string} name - The generated candidate name.
|
114
|
+
@param {Scope[]} scopes - The same list of scopes you pass to `avoidCapture`.
|
115
|
+
@returns {boolean} - `true` if the `name` is ok.
|
116
|
+
*/
|
117
|
+
|
118
|
+
/**
|
119
|
+
Generates a unique name prefixed with `name` such that:
|
120
|
+
- it is not defined in any of the `scopes`,
|
121
|
+
- it is not a reserved word,
|
122
|
+
- it is not `arguments` in strict scopes (where `arguments` is not allowed),
|
123
|
+
- it does not collide with the actual `arguments` (which is always defined in function scopes).
|
124
|
+
|
125
|
+
Useful when you want to rename a variable (or create a new variable) while being sure not to shadow any other variables in the code.
|
126
|
+
|
127
|
+
@param {string} name - The desired name for a new variable.
|
128
|
+
@param {Scope[]} scopes - The list of scopes the new variable will be referenced in.
|
129
|
+
@param {isSafe} [isSafe] - Rule-specific name check function.
|
130
|
+
@returns {string} - Either `name` as is, or a string like `${name}_` suffixed with underscores to make the name unique.
|
131
|
+
*/
|
132
|
+
module.exports = (name, scopes, isSafe = alwaysTrue) => {
|
133
|
+
if (!isValidIdentifier(name)) {
|
134
|
+
name += '_';
|
135
|
+
|
136
|
+
if (!isValidIdentifier(name)) {
|
137
|
+
return;
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
while (!isSafeName(name, scopes) || !isSafe(name, scopes)) {
|
142
|
+
name += '_';
|
143
|
+
}
|
144
|
+
|
145
|
+
return name;
|
146
|
+
};
|
@@ -0,0 +1,92 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
const isLogicalExpression = require('./is-logical-expression.js');
|
4
|
+
|
5
|
+
const isLogicNot = node => node?.type === 'UnaryExpression' && node.operator === '!';
|
6
|
+
const isLogicNotArgument = node => isLogicNot(node.parent) && node.parent.argument === node;
|
7
|
+
const isBooleanCallArgument = node => isBooleanCall(node.parent) && node.parent.arguments[0] === node;
|
8
|
+
const isBooleanCall = node =>
|
9
|
+
node?.type === 'CallExpression'
|
10
|
+
&& node.callee.type === 'Identifier'
|
11
|
+
&& node.callee.name === 'Boolean'
|
12
|
+
&& node.arguments.length === 1;
|
13
|
+
const isVueBooleanAttributeValue = node =>
|
14
|
+
node?.type === 'VExpressionContainer'
|
15
|
+
&& node.parent.type === 'VAttribute'
|
16
|
+
&& node.parent.directive
|
17
|
+
&& node.parent.value === node
|
18
|
+
&& node.parent.key.type === 'VDirectiveKey'
|
19
|
+
&& node.parent.key.name.type === 'VIdentifier'
|
20
|
+
&& (
|
21
|
+
node.parent.key.name.rawName === 'if'
|
22
|
+
|| node.parent.key.name.rawName === 'else-if'
|
23
|
+
|| node.parent.key.name.rawName === 'show'
|
24
|
+
);
|
25
|
+
|
26
|
+
/**
|
27
|
+
Check if the value of node is a `boolean`.
|
28
|
+
|
29
|
+
@param {Node} node
|
30
|
+
@returns {boolean}
|
31
|
+
*/
|
32
|
+
function isBooleanNode(node) {
|
33
|
+
if (
|
34
|
+
isLogicNot(node)
|
35
|
+
|| isLogicNotArgument(node)
|
36
|
+
|| isBooleanCall(node)
|
37
|
+
|| isBooleanCallArgument(node)
|
38
|
+
) {
|
39
|
+
return true;
|
40
|
+
}
|
41
|
+
|
42
|
+
const {parent} = node;
|
43
|
+
if (isVueBooleanAttributeValue(parent)) {
|
44
|
+
return true;
|
45
|
+
}
|
46
|
+
|
47
|
+
if (
|
48
|
+
(
|
49
|
+
parent.type === 'IfStatement'
|
50
|
+
|| parent.type === 'ConditionalExpression'
|
51
|
+
|| parent.type === 'WhileStatement'
|
52
|
+
|| parent.type === 'DoWhileStatement'
|
53
|
+
|| parent.type === 'ForStatement'
|
54
|
+
)
|
55
|
+
&& parent.test === node
|
56
|
+
) {
|
57
|
+
return true;
|
58
|
+
}
|
59
|
+
|
60
|
+
if (isLogicalExpression(parent)) {
|
61
|
+
return isBooleanNode(parent);
|
62
|
+
}
|
63
|
+
|
64
|
+
return false;
|
65
|
+
}
|
66
|
+
|
67
|
+
/**
|
68
|
+
Get the boolean type-casting ancestor.
|
69
|
+
|
70
|
+
@typedef {{ node: Node, isNegative: boolean }} Result
|
71
|
+
|
72
|
+
@param {Node} node
|
73
|
+
@returns {Result}
|
74
|
+
*/
|
75
|
+
function getBooleanAncestor(node) {
|
76
|
+
let isNegative = false;
|
77
|
+
// eslint-disable-next-line no-constant-condition
|
78
|
+
while (true) {
|
79
|
+
if (isLogicNotArgument(node)) {
|
80
|
+
isNegative = !isNegative;
|
81
|
+
node = node.parent;
|
82
|
+
} else if (isBooleanCallArgument(node)) {
|
83
|
+
node = node.parent;
|
84
|
+
} else {
|
85
|
+
break;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
return {node, isNegative};
|
90
|
+
}
|
91
|
+
|
92
|
+
module.exports = {isBooleanNode, getBooleanAncestor};
|
@@ -0,0 +1,36 @@
|
|
1
|
+
'use strict';
|
2
|
+
const typedArray = require('../shared/typed-array.js');
|
3
|
+
|
4
|
+
const enforceNew = [
|
5
|
+
'Object',
|
6
|
+
'Array',
|
7
|
+
'ArrayBuffer',
|
8
|
+
'DataView',
|
9
|
+
'Date',
|
10
|
+
'Error',
|
11
|
+
'Function',
|
12
|
+
'Map',
|
13
|
+
'WeakMap',
|
14
|
+
'Set',
|
15
|
+
'WeakSet',
|
16
|
+
'Promise',
|
17
|
+
'RegExp',
|
18
|
+
'SharedArrayBuffer',
|
19
|
+
'Proxy',
|
20
|
+
'WeakRef',
|
21
|
+
'FinalizationRegistry',
|
22
|
+
...typedArray,
|
23
|
+
];
|
24
|
+
|
25
|
+
const disallowNew = [
|
26
|
+
'BigInt',
|
27
|
+
'Boolean',
|
28
|
+
'Number',
|
29
|
+
'String',
|
30
|
+
'Symbol',
|
31
|
+
];
|
32
|
+
|
33
|
+
module.exports = {
|
34
|
+
enforceNew,
|
35
|
+
disallowNew,
|
36
|
+
};
|
@@ -0,0 +1,24 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
module.exports = (combinations, length = Number.POSITIVE_INFINITY) => {
|
4
|
+
const total = combinations.reduce((total, {length}) => total * length, 1);
|
5
|
+
|
6
|
+
const samples = Array.from({length: Math.min(total, length)}, (_, sampleIndex) => {
|
7
|
+
let indexRemaining = sampleIndex;
|
8
|
+
const combination = [];
|
9
|
+
for (let combinationIndex = combinations.length - 1; combinationIndex >= 0; combinationIndex--) {
|
10
|
+
const items = combinations[combinationIndex];
|
11
|
+
const {length} = items;
|
12
|
+
const index = indexRemaining % length;
|
13
|
+
indexRemaining = (indexRemaining - index) / length;
|
14
|
+
combination.unshift(items[index]);
|
15
|
+
}
|
16
|
+
|
17
|
+
return combination;
|
18
|
+
});
|
19
|
+
|
20
|
+
return {
|
21
|
+
total,
|
22
|
+
samples,
|
23
|
+
};
|
24
|
+
};
|
@@ -0,0 +1,25 @@
|
|
1
|
+
'use strict';
|
2
|
+
const packageJson = require('../../package.json');
|
3
|
+
|
4
|
+
const repoUrl = 'https://github.com/sindresorhus/eslint-plugin-unicorn';
|
5
|
+
|
6
|
+
/** @returns {{ [ruleName: string]: import('eslint').Rule.RuleModule }} */
|
7
|
+
function createDeprecatedRules(data) {
|
8
|
+
return Object.fromEntries(
|
9
|
+
Object.entries(data).map(([ruleId, replacedBy = []]) => [
|
10
|
+
ruleId,
|
11
|
+
{
|
12
|
+
create: () => ({}),
|
13
|
+
meta: {
|
14
|
+
docs: {
|
15
|
+
url: `${repoUrl}/blob/v${packageJson.version}/docs/deprecated-rules.md#${ruleId}`,
|
16
|
+
},
|
17
|
+
deprecated: true,
|
18
|
+
replacedBy: Array.isArray(replacedBy) ? replacedBy : [replacedBy],
|
19
|
+
},
|
20
|
+
},
|
21
|
+
]),
|
22
|
+
);
|
23
|
+
}
|
24
|
+
|
25
|
+
module.exports = createDeprecatedRules;
|
@@ -0,0 +1,26 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
const jsesc = require('jsesc');
|
4
|
+
|
5
|
+
/**
|
6
|
+
Escape string and wrap the result in quotes.
|
7
|
+
|
8
|
+
@param {string} string - The string to be quoted.
|
9
|
+
@param {string} [quote] - The quote character.
|
10
|
+
@returns {string} - The quoted and escaped string.
|
11
|
+
*/
|
12
|
+
module.exports = (string, quote = '\'') => {
|
13
|
+
/* c8 ignore start */
|
14
|
+
if (typeof string !== 'string') {
|
15
|
+
throw new TypeError('Unexpected string.');
|
16
|
+
}
|
17
|
+
/* c8 ignore end */
|
18
|
+
|
19
|
+
return jsesc(string, {
|
20
|
+
quotes: quote === '"' ? 'double' : 'single',
|
21
|
+
wrap: true,
|
22
|
+
es6: true,
|
23
|
+
minimal: true,
|
24
|
+
lowercaseHex: false,
|
25
|
+
});
|
26
|
+
};
|
@@ -0,0 +1,20 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
// TODO: Support more types
|
4
|
+
function getPredicate(options) {
|
5
|
+
if (typeof options === 'string') {
|
6
|
+
return node => node.type === options;
|
7
|
+
}
|
8
|
+
}
|
9
|
+
|
10
|
+
function getAncestor(node, options) {
|
11
|
+
const predicate = getPredicate(options);
|
12
|
+
|
13
|
+
for (;node.parent; node = node.parent) {
|
14
|
+
if (predicate(node)) {
|
15
|
+
return node;
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
module.exports = getAncestor;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
'use strict';
|
2
|
+
const {isOpeningParenToken} = require('@eslint-community/eslint-utils');
|
3
|
+
|
4
|
+
/**
|
5
|
+
Get the text of the arguments list of `CallExpression`.
|
6
|
+
|
7
|
+
@param {Node} node - The `CallExpression` node.
|
8
|
+
@param {SourceCode} sourceCode - The source code object.
|
9
|
+
@returns {string}
|
10
|
+
*/
|
11
|
+
const getCallExpressionArgumentsText = (node, sourceCode) => {
|
12
|
+
const openingParenthesisToken = sourceCode.getTokenAfter(node.callee, isOpeningParenToken);
|
13
|
+
const closingParenthesisToken = sourceCode.getLastToken(node);
|
14
|
+
|
15
|
+
return sourceCode.text.slice(
|
16
|
+
openingParenthesisToken.range[1],
|
17
|
+
closingParenthesisToken.range[0],
|
18
|
+
);
|
19
|
+
};
|
20
|
+
|
21
|
+
module.exports = getCallExpressionArgumentsText;
|
@@ -0,0 +1,22 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
/**
|
4
|
+
@typedef {line: number, column: number} Position
|
5
|
+
|
6
|
+
Get the location of the given class node for reporting.
|
7
|
+
|
8
|
+
@param {Node} node - The class node to get.
|
9
|
+
@param {SourceCode} sourceCode - The source code object to get tokens.
|
10
|
+
@returns {{start: Position, end: Position}} The location of the class node for reporting.
|
11
|
+
*/
|
12
|
+
function getClassHeadLocation(node, sourceCode) {
|
13
|
+
const {loc, body} = node;
|
14
|
+
const tokenBeforeBody = sourceCode.getTokenBefore(body);
|
15
|
+
|
16
|
+
const {start} = loc;
|
17
|
+
const {end} = tokenBeforeBody.loc;
|
18
|
+
|
19
|
+
return {start, end};
|
20
|
+
}
|
21
|
+
|
22
|
+
module.exports = getClassHeadLocation;
|
@@ -0,0 +1,10 @@
|
|
1
|
+
'use strict';
|
2
|
+
const path = require('node:path');
|
3
|
+
const packageJson = require('../../package.json');
|
4
|
+
|
5
|
+
const repoUrl = 'https://github.com/sindresorhus/eslint-plugin-unicorn';
|
6
|
+
|
7
|
+
module.exports = filename => {
|
8
|
+
const ruleName = path.basename(filename, '.js');
|
9
|
+
return `${repoUrl}/blob/v${packageJson.version}/docs/rules/${ruleName}.md`;
|
10
|
+
};
|
@@ -0,0 +1,11 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
function getIndentString(node, sourceCode) {
|
4
|
+
const {line, column} = sourceCode.getLocFromIndex(node.range[0]);
|
5
|
+
const lines = sourceCode.getLines();
|
6
|
+
const before = lines[line - 1].slice(0, column);
|
7
|
+
|
8
|
+
return before.match(/\s*$/)[0];
|
9
|
+
}
|
10
|
+
|
11
|
+
module.exports = getIndentString;
|
@@ -0,0 +1,24 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
function getPreviousNode(node, sourceCode) {
|
4
|
+
const {parent} = node;
|
5
|
+
const visitorKeys = sourceCode.visitorKeys[parent.type] || Object.keys(parent);
|
6
|
+
|
7
|
+
for (const property of visitorKeys) {
|
8
|
+
const value = parent[property];
|
9
|
+
|
10
|
+
if (value === node) {
|
11
|
+
return;
|
12
|
+
}
|
13
|
+
|
14
|
+
if (Array.isArray(value)) {
|
15
|
+
const index = value.indexOf(node);
|
16
|
+
|
17
|
+
if (index !== -1) {
|
18
|
+
return value[index - 1];
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
module.exports = getPreviousNode;
|
@@ -0,0 +1,14 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
/**
|
4
|
+
Gather a list of all Scopes starting recursively from the input Scope.
|
5
|
+
|
6
|
+
@param {Scope} scope - The Scope to start checking from.
|
7
|
+
@returns {Scope[]} - The resulting Scopes.
|
8
|
+
*/
|
9
|
+
const getScopes = scope => [
|
10
|
+
scope,
|
11
|
+
...scope.childScopes.flatMap(scope => getScopes(scope)),
|
12
|
+
];
|
13
|
+
|
14
|
+
module.exports = getScopes;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
const {isColonToken} = require('@eslint-community/eslint-utils');
|
4
|
+
|
5
|
+
/**
|
6
|
+
@typedef {line: number, column: number} Position
|
7
|
+
|
8
|
+
Get the location of the given `SwitchCase` node for reporting.
|
9
|
+
|
10
|
+
@param {Node} node - The `SwitchCase` node to get.
|
11
|
+
@param {SourceCode} sourceCode - The source code object to get tokens from.
|
12
|
+
@returns {{start: Position, end: Position}} The location of the class node for reporting.
|
13
|
+
*/
|
14
|
+
function getSwitchCaseHeadLocation(node, sourceCode) {
|
15
|
+
const startToken = node.test || sourceCode.getFirstToken(node);
|
16
|
+
const colonToken = sourceCode.getTokenAfter(startToken, isColonToken);
|
17
|
+
|
18
|
+
return {start: node.loc.start, end: colonToken.loc.end};
|
19
|
+
}
|
20
|
+
|
21
|
+
module.exports = getSwitchCaseHeadLocation;
|
@@ -0,0 +1,72 @@
|
|
1
|
+
'use strict';
|
2
|
+
const {ReferenceTracker} = require('@eslint-community/eslint-utils');
|
3
|
+
|
4
|
+
const createTraceMap = (object, type) => {
|
5
|
+
let map = {[type]: true};
|
6
|
+
|
7
|
+
const path = object.split('.').reverse();
|
8
|
+
for (const name of path) {
|
9
|
+
map = {[name]: map};
|
10
|
+
}
|
11
|
+
|
12
|
+
return map;
|
13
|
+
};
|
14
|
+
|
15
|
+
class GlobalReferenceTracker {
|
16
|
+
#traceMap = {};
|
17
|
+
#filter;
|
18
|
+
#handle;
|
19
|
+
|
20
|
+
constructor({
|
21
|
+
object,
|
22
|
+
objects = [object],
|
23
|
+
filter,
|
24
|
+
handle,
|
25
|
+
type = ReferenceTracker.READ,
|
26
|
+
}) {
|
27
|
+
for (const object of objects) {
|
28
|
+
Object.assign(this.#traceMap, createTraceMap(object, type));
|
29
|
+
}
|
30
|
+
|
31
|
+
this.#filter = filter;
|
32
|
+
this.#handle = handle;
|
33
|
+
}
|
34
|
+
|
35
|
+
* track(globalScope) {
|
36
|
+
const tracker = new ReferenceTracker(globalScope);
|
37
|
+
|
38
|
+
for (const reference of tracker.iterateGlobalReferences(this.#traceMap)) {
|
39
|
+
if (this.#filter && !this.#filter(reference)) {
|
40
|
+
continue;
|
41
|
+
}
|
42
|
+
|
43
|
+
const problems = this.#handle(reference);
|
44
|
+
|
45
|
+
if (!problems) {
|
46
|
+
continue;
|
47
|
+
}
|
48
|
+
|
49
|
+
if (problems[Symbol.iterator]) {
|
50
|
+
yield * problems;
|
51
|
+
} else {
|
52
|
+
yield problems;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
createListeners(context) {
|
58
|
+
return {
|
59
|
+
'Program:exit': program => this.track(context.sourceCode.getScope(program)),
|
60
|
+
};
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
Object.assign(GlobalReferenceTracker, {
|
65
|
+
READ: ReferenceTracker.READ,
|
66
|
+
CALL: ReferenceTracker.CALL,
|
67
|
+
CONSTRUCT: ReferenceTracker.CONSTRUCT,
|
68
|
+
});
|
69
|
+
|
70
|
+
module.exports = {
|
71
|
+
GlobalReferenceTracker,
|
72
|
+
};
|
@@ -0,0 +1,21 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
const isChainElement = node => node.type === 'MemberExpression' || node.type === 'CallExpression';
|
4
|
+
|
5
|
+
function hasOptionalChainElement(node) {
|
6
|
+
if (!isChainElement(node)) {
|
7
|
+
return false;
|
8
|
+
}
|
9
|
+
|
10
|
+
if (node.optional) {
|
11
|
+
return true;
|
12
|
+
}
|
13
|
+
|
14
|
+
if (node.type === 'MemberExpression') {
|
15
|
+
return hasOptionalChainElement(node.object);
|
16
|
+
}
|
17
|
+
|
18
|
+
return false;
|
19
|
+
}
|
20
|
+
|
21
|
+
module.exports = hasOptionalChainElement;
|