source: imaps-frontend/node_modules/eslint/lib/rules/no-unused-expressions.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 6.1 KB
Line 
1/**
2 * @fileoverview Flag expressions in statement position that do not side effect
3 * @author Michael Ficarra
4 */
5"use strict";
6
7const astUtils = require("./utils/ast-utils");
8
9//------------------------------------------------------------------------------
10// Rule Definition
11//------------------------------------------------------------------------------
12
13/**
14 * Returns `true`.
15 * @returns {boolean} `true`.
16 */
17function alwaysTrue() {
18 return true;
19}
20
21/**
22 * Returns `false`.
23 * @returns {boolean} `false`.
24 */
25function alwaysFalse() {
26 return false;
27}
28
29/** @type {import('../shared/types').Rule} */
30module.exports = {
31 meta: {
32 type: "suggestion",
33
34 docs: {
35 description: "Disallow unused expressions",
36 recommended: false,
37 url: "https://eslint.org/docs/latest/rules/no-unused-expressions"
38 },
39
40 schema: [
41 {
42 type: "object",
43 properties: {
44 allowShortCircuit: {
45 type: "boolean",
46 default: false
47 },
48 allowTernary: {
49 type: "boolean",
50 default: false
51 },
52 allowTaggedTemplates: {
53 type: "boolean",
54 default: false
55 },
56 enforceForJSX: {
57 type: "boolean",
58 default: false
59 }
60 },
61 additionalProperties: false
62 }
63 ],
64
65 messages: {
66 unusedExpression: "Expected an assignment or function call and instead saw an expression."
67 }
68 },
69
70 create(context) {
71 const config = context.options[0] || {},
72 allowShortCircuit = config.allowShortCircuit || false,
73 allowTernary = config.allowTernary || false,
74 allowTaggedTemplates = config.allowTaggedTemplates || false,
75 enforceForJSX = config.enforceForJSX || false;
76
77 /**
78 * Has AST suggesting a directive.
79 * @param {ASTNode} node any node
80 * @returns {boolean} whether the given node structurally represents a directive
81 */
82 function looksLikeDirective(node) {
83 return node.type === "ExpressionStatement" &&
84 node.expression.type === "Literal" && typeof node.expression.value === "string";
85 }
86
87 /**
88 * Gets the leading sequence of members in a list that pass the predicate.
89 * @param {Function} predicate ([a] -> Boolean) the function used to make the determination
90 * @param {a[]} list the input list
91 * @returns {a[]} the leading sequence of members in the given list that pass the given predicate
92 */
93 function takeWhile(predicate, list) {
94 for (let i = 0; i < list.length; ++i) {
95 if (!predicate(list[i])) {
96 return list.slice(0, i);
97 }
98 }
99 return list.slice();
100 }
101
102 /**
103 * Gets leading directives nodes in a Node body.
104 * @param {ASTNode} node a Program or BlockStatement node
105 * @returns {ASTNode[]} the leading sequence of directive nodes in the given node's body
106 */
107 function directives(node) {
108 return takeWhile(looksLikeDirective, node.body);
109 }
110
111 /**
112 * Detect if a Node is a directive.
113 * @param {ASTNode} node any node
114 * @returns {boolean} whether the given node is considered a directive in its current position
115 */
116 function isDirective(node) {
117
118 /**
119 * https://tc39.es/ecma262/#directive-prologue
120 *
121 * Only `FunctionBody`, `ScriptBody` and `ModuleBody` can have directive prologue.
122 * Class static blocks do not have directive prologue.
123 */
124 return astUtils.isTopLevelExpressionStatement(node) && directives(node.parent).includes(node);
125 }
126
127 /**
128 * The member functions return `true` if the type has no side-effects.
129 * Unknown nodes are handled as `false`, then this rule ignores those.
130 */
131 const Checker = Object.assign(Object.create(null), {
132 isDisallowed(node) {
133 return (Checker[node.type] || alwaysFalse)(node);
134 },
135
136 ArrayExpression: alwaysTrue,
137 ArrowFunctionExpression: alwaysTrue,
138 BinaryExpression: alwaysTrue,
139 ChainExpression(node) {
140 return Checker.isDisallowed(node.expression);
141 },
142 ClassExpression: alwaysTrue,
143 ConditionalExpression(node) {
144 if (allowTernary) {
145 return Checker.isDisallowed(node.consequent) || Checker.isDisallowed(node.alternate);
146 }
147 return true;
148 },
149 FunctionExpression: alwaysTrue,
150 Identifier: alwaysTrue,
151 JSXElement() {
152 return enforceForJSX;
153 },
154 JSXFragment() {
155 return enforceForJSX;
156 },
157 Literal: alwaysTrue,
158 LogicalExpression(node) {
159 if (allowShortCircuit) {
160 return Checker.isDisallowed(node.right);
161 }
162 return true;
163 },
164 MemberExpression: alwaysTrue,
165 MetaProperty: alwaysTrue,
166 ObjectExpression: alwaysTrue,
167 SequenceExpression: alwaysTrue,
168 TaggedTemplateExpression() {
169 return !allowTaggedTemplates;
170 },
171 TemplateLiteral: alwaysTrue,
172 ThisExpression: alwaysTrue,
173 UnaryExpression(node) {
174 return node.operator !== "void" && node.operator !== "delete";
175 }
176 });
177
178 return {
179 ExpressionStatement(node) {
180 if (Checker.isDisallowed(node.expression) && !isDirective(node)) {
181 context.report({ node, messageId: "unusedExpression" });
182 }
183 }
184 };
185 }
186};
Note: See TracBrowser for help on using the repository browser.