]>
git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/no-unused-expressions.js
d34d5844d97f6a080c8dcd41d1371980d58c2a6e
2 * @fileoverview Flag expressions in statement position that do not side effect
3 * @author Michael Ficarra
7 //------------------------------------------------------------------------------
9 //------------------------------------------------------------------------------
13 * @returns {boolean} `true`.
15 function alwaysTrue() {
21 * @returns {boolean} `false`.
23 function alwaysFalse() {
27 /** @type {import('../shared/types').Rule} */
33 description
: "Disallow unused expressions",
35 url
: "https://eslint.org/docs/rules/no-unused-expressions"
50 allowTaggedTemplates
: {
59 additionalProperties
: false
64 unusedExpression
: "Expected an assignment or function call and instead saw an expression."
69 const config
= context
.options
[0] || {},
70 allowShortCircuit
= config
.allowShortCircuit
|| false,
71 allowTernary
= config
.allowTernary
|| false,
72 allowTaggedTemplates
= config
.allowTaggedTemplates
|| false,
73 enforceForJSX
= config
.enforceForJSX
|| false;
76 * Has AST suggesting a directive.
77 * @param {ASTNode} node any node
78 * @returns {boolean} whether the given node structurally represents a directive
80 function looksLikeDirective(node
) {
81 return node
.type
=== "ExpressionStatement" &&
82 node
.expression
.type
=== "Literal" && typeof node
.expression
.value
=== "string";
86 * Gets the leading sequence of members in a list that pass the predicate.
87 * @param {Function} predicate ([a] -> Boolean) the function used to make the determination
88 * @param {a[]} list the input list
89 * @returns {a[]} the leading sequence of members in the given list that pass the given predicate
91 function takeWhile(predicate
, list
) {
92 for (let i
= 0; i
< list
.length
; ++i
) {
93 if (!predicate(list
[i
])) {
94 return list
.slice(0, i
);
101 * Gets leading directives nodes in a Node body.
102 * @param {ASTNode} node a Program or BlockStatement node
103 * @returns {ASTNode[]} the leading sequence of directive nodes in the given node's body
105 function directives(node
) {
106 return takeWhile(looksLikeDirective
, node
.body
);
110 * Detect if a Node is a directive.
111 * @param {ASTNode} node any node
112 * @param {ASTNode[]} ancestors the given node's ancestors
113 * @returns {boolean} whether the given node is considered a directive in its current position
115 function isDirective(node
, ancestors
) {
116 const parent
= ancestors
[ancestors
.length
- 1],
117 grandparent
= ancestors
[ancestors
.length
- 2];
120 * https://tc39.es/ecma262/#directive-prologue
122 * Only `FunctionBody`, `ScriptBody` and `ModuleBody` can have directive prologue.
123 * Class static blocks do not have directive prologue.
125 return (parent
.type
=== "Program" || parent
.type
=== "BlockStatement" &&
126 (/Function/u.test(grandparent
.type
))) &&
127 directives(parent
).includes(node
);
131 * The member functions return `true` if the type has no side-effects.
132 * Unknown nodes are handled as `false`, then this rule ignores those.
134 const Checker
= Object
.assign(Object
.create(null), {
136 return (Checker
[node
.type
] || alwaysFalse
)(node
);
139 ArrayExpression
: alwaysTrue
,
140 ArrowFunctionExpression
: alwaysTrue
,
141 BinaryExpression
: alwaysTrue
,
142 ChainExpression(node
) {
143 return Checker
.isDisallowed(node
.expression
);
145 ClassExpression
: alwaysTrue
,
146 ConditionalExpression(node
) {
148 return Checker
.isDisallowed(node
.consequent
) || Checker
.isDisallowed(node
.alternate
);
152 FunctionExpression
: alwaysTrue
,
153 Identifier
: alwaysTrue
,
155 return enforceForJSX
;
158 return enforceForJSX
;
161 LogicalExpression(node
) {
162 if (allowShortCircuit
) {
163 return Checker
.isDisallowed(node
.right
);
167 MemberExpression
: alwaysTrue
,
168 MetaProperty
: alwaysTrue
,
169 ObjectExpression
: alwaysTrue
,
170 SequenceExpression
: alwaysTrue
,
171 TaggedTemplateExpression() {
172 return !allowTaggedTemplates
;
174 TemplateLiteral
: alwaysTrue
,
175 ThisExpression
: alwaysTrue
,
176 UnaryExpression(node
) {
177 return node
.operator
!== "void" && node
.operator
!== "delete";
182 ExpressionStatement(node
) {
183 if (Checker
.isDisallowed(node
.expression
) && !isDirective(node
, context
.getAncestors())) {
184 context
.report({ node
, messageId
: "unusedExpression" });