source: imaps-frontend/node_modules/eslint/lib/rules/wrap-iife.js@ d565449

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

Update repo after prototype presentation

  • Property mode set to 100644
File size: 7.8 KB
Line 
1/**
2 * @fileoverview Rule to flag when IIFE is not wrapped in parens
3 * @author Ilya Volodin
4 * @deprecated in ESLint v8.53.0
5 */
6
7"use strict";
8
9//------------------------------------------------------------------------------
10// Requirements
11//------------------------------------------------------------------------------
12
13const astUtils = require("./utils/ast-utils");
14const eslintUtils = require("@eslint-community/eslint-utils");
15
16//----------------------------------------------------------------------
17// Helpers
18//----------------------------------------------------------------------
19
20/**
21 * Check if the given node is callee of a `NewExpression` node
22 * @param {ASTNode} node node to check
23 * @returns {boolean} True if the node is callee of a `NewExpression` node
24 * @private
25 */
26function isCalleeOfNewExpression(node) {
27 const maybeCallee = node.parent.type === "ChainExpression"
28 ? node.parent
29 : node;
30
31 return (
32 maybeCallee.parent.type === "NewExpression" &&
33 maybeCallee.parent.callee === maybeCallee
34 );
35}
36
37//------------------------------------------------------------------------------
38// Rule Definition
39//------------------------------------------------------------------------------
40
41/** @type {import('../shared/types').Rule} */
42module.exports = {
43 meta: {
44 deprecated: true,
45 replacedBy: [],
46 type: "layout",
47
48 docs: {
49 description: "Require parentheses around immediate `function` invocations",
50 recommended: false,
51 url: "https://eslint.org/docs/latest/rules/wrap-iife"
52 },
53
54 schema: [
55 {
56 enum: ["outside", "inside", "any"]
57 },
58 {
59 type: "object",
60 properties: {
61 functionPrototypeMethods: {
62 type: "boolean",
63 default: false
64 }
65 },
66 additionalProperties: false
67 }
68 ],
69
70 fixable: "code",
71 messages: {
72 wrapInvocation: "Wrap an immediate function invocation in parentheses.",
73 wrapExpression: "Wrap only the function expression in parens.",
74 moveInvocation: "Move the invocation into the parens that contain the function."
75 }
76 },
77
78 create(context) {
79
80 const style = context.options[0] || "outside";
81 const includeFunctionPrototypeMethods = context.options[1] && context.options[1].functionPrototypeMethods;
82
83 const sourceCode = context.sourceCode;
84
85 /**
86 * Check if the node is wrapped in any (). All parens count: grouping parens and parens for constructs such as if()
87 * @param {ASTNode} node node to evaluate
88 * @returns {boolean} True if it is wrapped in any parens
89 * @private
90 */
91 function isWrappedInAnyParens(node) {
92 return astUtils.isParenthesised(sourceCode, node);
93 }
94
95 /**
96 * Check if the node is wrapped in grouping (). Parens for constructs such as if() don't count
97 * @param {ASTNode} node node to evaluate
98 * @returns {boolean} True if it is wrapped in grouping parens
99 * @private
100 */
101 function isWrappedInGroupingParens(node) {
102 return eslintUtils.isParenthesized(1, node, sourceCode);
103 }
104
105 /**
106 * Get the function node from an IIFE
107 * @param {ASTNode} node node to evaluate
108 * @returns {ASTNode} node that is the function expression of the given IIFE, or null if none exist
109 */
110 function getFunctionNodeFromIIFE(node) {
111 const callee = astUtils.skipChainExpression(node.callee);
112
113 if (callee.type === "FunctionExpression") {
114 return callee;
115 }
116
117 if (includeFunctionPrototypeMethods &&
118 callee.type === "MemberExpression" &&
119 callee.object.type === "FunctionExpression" &&
120 (astUtils.getStaticPropertyName(callee) === "call" || astUtils.getStaticPropertyName(callee) === "apply")
121 ) {
122 return callee.object;
123 }
124
125 return null;
126 }
127
128
129 return {
130 CallExpression(node) {
131 const innerNode = getFunctionNodeFromIIFE(node);
132
133 if (!innerNode) {
134 return;
135 }
136
137 const isCallExpressionWrapped = isWrappedInAnyParens(node),
138 isFunctionExpressionWrapped = isWrappedInAnyParens(innerNode);
139
140 if (!isCallExpressionWrapped && !isFunctionExpressionWrapped) {
141 context.report({
142 node,
143 messageId: "wrapInvocation",
144 fix(fixer) {
145 const nodeToSurround = style === "inside" ? innerNode : node;
146
147 return fixer.replaceText(nodeToSurround, `(${sourceCode.getText(nodeToSurround)})`);
148 }
149 });
150 } else if (style === "inside" && !isFunctionExpressionWrapped) {
151 context.report({
152 node,
153 messageId: "wrapExpression",
154 fix(fixer) {
155
156 // The outer call expression will always be wrapped at this point.
157
158 if (isWrappedInGroupingParens(node) && !isCalleeOfNewExpression(node)) {
159
160 /*
161 * Parenthesize the function expression and remove unnecessary grouping parens around the call expression.
162 * Replace the range between the end of the function expression and the end of the call expression.
163 * for example, in `(function(foo) {}(bar))`, the range `(bar))` should get replaced with `)(bar)`.
164 */
165
166 const parenAfter = sourceCode.getTokenAfter(node);
167
168 return fixer.replaceTextRange(
169 [innerNode.range[1], parenAfter.range[1]],
170 `)${sourceCode.getText().slice(innerNode.range[1], parenAfter.range[0])}`
171 );
172 }
173
174 /*
175 * Call expression is wrapped in mandatory parens such as if(), or in necessary grouping parens.
176 * These parens cannot be removed, so just parenthesize the function expression.
177 */
178
179 return fixer.replaceText(innerNode, `(${sourceCode.getText(innerNode)})`);
180 }
181 });
182 } else if (style === "outside" && !isCallExpressionWrapped) {
183 context.report({
184 node,
185 messageId: "moveInvocation",
186 fix(fixer) {
187
188 /*
189 * The inner function expression will always be wrapped at this point.
190 * It's only necessary to replace the range between the end of the function expression
191 * and the call expression. For example, in `(function(foo) {})(bar)`, the range `)(bar)`
192 * should get replaced with `(bar))`.
193 */
194 const parenAfter = sourceCode.getTokenAfter(innerNode);
195
196 return fixer.replaceTextRange(
197 [parenAfter.range[0], node.range[1]],
198 `${sourceCode.getText().slice(parenAfter.range[1], node.range[1])})`
199 );
200 }
201 });
202 }
203 }
204 };
205
206 }
207};
Note: See TracBrowser for help on using the repository browser.