Skip to content

Commit

Permalink
Update: add fixer for wrap-iife (#7196)
Browse files Browse the repository at this point in the history
  • Loading branch information
not-an-aardvark authored and kaicataldo committed Sep 30, 2016
1 parent 558b444 commit f8e8fab
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 4 deletions.
2 changes: 2 additions & 0 deletions docs/rules/wrap-iife.md
@@ -1,5 +1,7 @@
# Require IIFEs to be Wrapped (wrap-iife)

(fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#fix) automatically fixes problems reported by this rule.

You can immediately invoke function expressions, but not function declarations. A common technique to create an immediately-invoked function expression (IIFE) is to wrap a function declaration in parentheses. The opening parentheses causes the contained function to be parsed as an expression, rather than a declaration.

```js
Expand Down
54 changes: 50 additions & 4 deletions lib/rules/wrap-iife.js
Expand Up @@ -21,7 +21,9 @@ module.exports = {
{
enum: ["outside", "inside", "any"]
}
]
],

fixable: "code"
},

create(context) {
Expand Down Expand Up @@ -52,11 +54,55 @@ module.exports = {
functionExpressionWrapped = wrapped(node.callee);

if (!callExpressionWrapped && !functionExpressionWrapped) {
context.report(node, "Wrap an immediate function invocation in parentheses.");
context.report({
node,
message: "Wrap an immediate function invocation in parentheses.",
fix(fixer) {
const nodeToSurround = style === "inside" ? node.callee : node;

return fixer.replaceText(nodeToSurround, `(${sourceCode.getText(nodeToSurround)})`);
}
});
} else if (style === "inside" && !functionExpressionWrapped) {
context.report(node, "Wrap only the function expression in parens.");
context.report({
node,
message: "Wrap only the function expression in parens.",
fix(fixer) {

/*
* The outer call expression will always be wrapped at this point.
* Replace the range between the end of the function expression and the end of the call expression.
* for example, in `(function(foo) {}(bar))`, the range `(bar))` should get replaced with `)(bar)`.
* Replace the parens from the outer expression, and parenthesize the function expression.
*/
const parenAfter = sourceCode.getTokenAfter(node);

return fixer.replaceTextRange(
[node.callee.range[1], parenAfter.range[1]],
`)${sourceCode.getText().slice(node.callee.range[1], parenAfter.range[0])}`
);
}
});
} else if (style === "outside" && !callExpressionWrapped) {
context.report(node, "Move the invocation into the parens that contain the function.");
context.report({
node,
message: "Move the invocation into the parens that contain the function.",
fix(fixer) {

/*
* The inner function expression will always be wrapped at this point.
* It's only necessary to replace the range between the end of the function expression
* and the call expression. For example, in `(function(foo) {})(bar)`, the range `)(bar)`
* should get replaced with `(bar))`.
*/
const parenAfter = sourceCode.getTokenAfter(node.callee);

return fixer.replaceTextRange(
[parenAfter.range[0], node.range[1]],
`${sourceCode.getText().slice(parenAfter.range[1], node.range[1])})`
);
}
});
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions tests/lib/rules/wrap-iife.js
Expand Up @@ -49,29 +49,49 @@ ruleTester.run("wrap-iife", rule, {
invalid: [
{
code: "0, function(){ }();",
output: "0, (function(){ }());",
errors: [{ message: "Wrap an immediate function invocation in parentheses.", type: "CallExpression"}]
},
{
code: "[function(){ }()];",
output: "[(function(){ }())];",
errors: [{ message: "Wrap an immediate function invocation in parentheses.", type: "CallExpression"}]
},
{
code: "var a = function(){ }();",
output: "var a = (function(){ }());",
errors: [{ message: "Wrap an immediate function invocation in parentheses.", type: "CallExpression"}]
},
{
code: "(function(){ }(), 0);",
output: "((function(){ }()), 0);",
errors: [{ message: "Wrap an immediate function invocation in parentheses.", type: "CallExpression"}]
},
{
code: "(function a(){ })();",
output: "(function a(){ }());",
options: ["outside"],
errors: [{ message: "Move the invocation into the parens that contain the function.", type: "CallExpression" }]
},
{
code: "(function a(){ }());",
output: "(function a(){ })();",
options: ["inside"],
errors: [{ message: "Wrap only the function expression in parens.", type: "CallExpression" }]
},
{

// Ensure all comments get preserved when autofixing.
code: "( /* a */ function /* b */ foo /* c */ ( /* d */ bar /* e */ ) /* f */ { /* g */ return; /* h */ } /* i */ ( /* j */ baz /* k */) /* l */ ) /* m */ ;",
output: "( /* a */ function /* b */ foo /* c */ ( /* d */ bar /* e */ ) /* f */ { /* g */ return; /* h */ }) /* i */ ( /* j */ baz /* k */) /* l */ /* m */ ;",
options: ["inside"],
errors: [{ message: "Wrap only the function expression in parens.", type: "CallExpression" }]
},
{
code: "( /* a */ function /* b */ foo /* c */ ( /* d */ bar /* e */ ) /* f */ { /* g */ return; /* h */ } /* i */ ) /* j */ ( /* k */ baz /* l */) /* m */ ;",
output: "( /* a */ function /* b */ foo /* c */ ( /* d */ bar /* e */ ) /* f */ { /* g */ return; /* h */ } /* i */ /* j */ ( /* k */ baz /* l */)) /* m */ ;",
options: ["outside"],
errors: [{ message: "Move the invocation into the parens that contain the function.", type: "CallExpression" }]
}
]
});

0 comments on commit f8e8fab

Please sign in to comment.