Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"presets": ["es2015"],
"presets": ["@babel/preset-env"],
"plugins": ["strict-equality"]
}
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
node_modules
lib

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a particular reason why lib is commented out in the gitignore instead of perhaps npmignore? On the flipside, unprocessed sources can be npm ignored

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ $ babel --plugins implicit-return script.js
### Via Node API

```javascript
require("babel-core").transform("code", {
require("@babel/core").transform("code", {
plugins: ["implicit-return"]
});
```
Expand Down
118 changes: 118 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"use strict";

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;

var _default = function _default(_ref) {
var t = _ref.types;
var unreturnableStatements = new Set(["DebuggerStatement", "WithStatement", "ReturnStatement", "LabeledStatement", "BreakStatement", "ContinueStatement", "ThrowStatement"]);
var returnableStatements = new Set(["IfStatement", "SwitchStatement", "TryStatement", "WhileStatement", "DoWhileStatement", "ForStatement", "ForInStatement", "ForOfStatement"]);

var last = function last(array) {
return array[array.length - 1];
};

var lastNotEmptyIndex = function lastNotEmptyIndex(nodes) {
for (var index = nodes.length - 1; index >= 0; index -= 1) {
if (!t.isEmptyStatement(nodes[index])) return index;
}
}; // like babel-types#toExpression, but preserves function expressions


var toExpression = function toExpression(node) {
if (t.isExpressionStatement(node)) node = node.expression;

if (t.isClass(node)) {
node.type = "ClassExpression";
} else if (t.isFunctionDeclaration(node)) {
node.type = "FunctionExpression";
}

if (t.isExpression(node)) return node;
throw new Error("cannot turn ".concat(node.type, " to an expression"));
};

return {
visitor: {
Function: function Function(path) {
var node = path.node; // arrow function expression

if (node.expression) return;
var _node$body = node.body,
body = _node$body.body,
directives = _node$body.directives;

try {
if (body.length === 0) {
// empty function
if (directives.length === 0) return; // function with directives only

var directive = directives.pop();
body.push(t.returnStatement(t.stringLiteral(directive.value.value)));
return;
}
} catch (error) {
return;
}

var lastIndex = lastNotEmptyIndex(body);
var lastPath = path.get("body.body.".concat(lastIndex));
var lastNode = body[lastIndex]; // skip unreturnable statements

try {
if (unreturnableStatements.has(lastNode.type)) return;
} catch (error) {
return;
} // convert returnable statements


if (returnableStatements.has(lastNode.type)) {
var completionRecords = lastPath.getCompletionRecords();
var returnUid = null;
completionRecords.forEach(function (subPath) {
if (!subPath.isExpressionStatement()) return;
var isLoop = subPath.findParent(function (subPath) {
return subPath.isLoop();
});

if (isLoop) {
if (!returnUid) returnUid = path.scope.generateDeclaredUidIdentifier("ret");
subPath.get("expression").replaceWith(t.assignmentExpression("=", returnUid, subPath.node.expression));
} else {
subPath.replaceWith(t.returnStatement(subPath.node.expression));
}
});

if (returnUid) {
path.get("body").pushContainer("body", t.returnStatement(returnUid));
}

return;
} // variables declaration


if (t.isVariableDeclaration(lastNode)) {
var _last = last(lastNode.declarations),
id = _last.id;

if (t.isArrayPattern(id)) {
id = last(id.elements).argument;
}

if (t.isObjectPattern(id)) {
id = last(id.properties).argument;
}

body.push(t.returnStatement(id));
return;
}

body[lastIndex] = t.returnStatement(toExpression(lastNode));
}
}
};
};

exports.default = _default;
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"build": "babel src/index.js -o lib/index.js",
"watch-build": "npm run build -- -w",
"test": "mocha --compilers js:babel-register",
"test": "mocha --compilers js:@babel/register",
"watch-test": "npm test -- -w",
"lint": "eslint **/*.js --quiet"
},
Expand All @@ -27,19 +27,19 @@
},
"homepage": "https://github.com/miraks/babel-plugin-implicit-return",
"devDependencies": {
"babel-cli": "^6.18.0",
"babel-core": "^6.21.0",
"@babel/cli": "^7.2.3",
"@babel/core": "^7.2.2",
"@babel/preset-env": "^7.3.1",
"@babel/register": "^7.0.0",
"babel-eslint": "^7.1.1",
"babel-plugin-strict-equality": "^1.0.0",
"babel-plugin-syntax-async-functions": "^6.13.0",
"babel-plugin-syntax-async-generators": "^6.13.0",
"babel-plugin-syntax-flow": "^6.18.0",
"babel-plugin-syntax-object-rest-spread": "^6.13.0",
"babel-plugin-transform-react-jsx": "^6.8.0",
"babel-preset-es2015": "^6.18.0",
"babel-register": "^6.18.0",
"chai": "^3.5.0",
"eslint": "^3.12.2",
"mocha": "^3.2.0"
"mocha": "^5.2.0"
}
}
22 changes: 15 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,18 @@ export default ({ types: t }) => {

const { body, directives } = node.body

if (body.length == 0) {
// empty function
if (directives.length == 0) return
try {
if (body.length == 0) {
// empty function
if (directives.length == 0) return

// function with directives only
const directive = directives.pop()
body.push(t.returnStatement(t.stringLiteral(directive.value.value)))
// function with directives only
const directive = directives.pop()
body.push(t.returnStatement(t.stringLiteral(directive.value.value)))

return
}
} catch (error) {
return
}

Expand All @@ -52,7 +56,11 @@ export default ({ types: t }) => {
const lastNode = body[lastIndex]

// skip unreturnable statements
if (unreturnableStatements.has(lastNode.type)) return
try {
if (unreturnableStatements.has(lastNode.type)) return

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The obvious perceivable error here would be something along the lines of Cannot read property 'type' of null or undefined, so is a try/catch and using errors for control flow needed here?

} catch (error) {
return
}

// convert returnable statements
if (returnableStatements.has(lastNode.type)) {
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/class-methods/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ class Thing {
static fn() {
return 1;
}

}
2 changes: 2 additions & 0 deletions test/fixtures/object-properties/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ const obj = {
return 2;
},
c: () => 3,

d() {
return 4;
},

["a" + "b"]: () => {
return 5;
}
Expand Down
2 changes: 2 additions & 0 deletions test/fixtures/return-class-with-methods/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ function fn() {
constructor() {
return super();
}

fn() {
return 1;
}

};
}
2 changes: 2 additions & 0 deletions test/fixtures/return-do-while/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ function fn() {
var _ret;

let n = 0;

do {
_ret = n += 1;
} while (n < 5);

return _ret;
}
2 changes: 2 additions & 0 deletions test/fixtures/return-for-in/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ function fn() {
var _ret;

const arr = [1, 2, 3];

for (let n in arr) {
_ret = n + 1;
}

return _ret;
}
7 changes: 6 additions & 1 deletion test/fixtures/return-for-of/expected.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
function fn() {
var _ret;

const obj = { a: 1, b: 2 };
const obj = {
a: 1,
b: 2
};

for (let entry of obj) {
_ret = entry[0] + entry[1];
}

return _ret;
}
1 change: 1 addition & 0 deletions test/fixtures/return-for/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ function fn() {
for (let n = 0; n < 5; n += 1) {
_ret = n - 1;
}

return _ret;
}
1 change: 1 addition & 0 deletions test/fixtures/return-function-call-result/expected.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
function fn() {
const fn = () => 1;

return fn();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
function fn() {
const a = 1,
b = "str",
c = { key: "value", other: 1 };
c = {
key: "value",
other: 1
};
return c;
}
1 change: 1 addition & 0 deletions test/fixtures/return-nested-for/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ function fn() {
_ret = n + k;
}
}

return _ret;
}
1 change: 1 addition & 0 deletions test/fixtures/return-nested-if-else-for/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ function foo() {
_ret = res *= b;
}
}

return _ret;
}
5 changes: 4 additions & 1 deletion test/fixtures/return-object-in-braces/expected.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
function fn() {
return { key: "value", other: 1 };
return {
key: "value",
other: 1
};
}
10 changes: 8 additions & 2 deletions test/fixtures/return-object-spread/expected.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
function fn() {
const obj = { a: 1, b: 2 };
const { a, ...c } = obj;
const obj = {
a: 1,
b: 2
};
const {
a,
...c
} = obj;
return c;
}
10 changes: 1 addition & 9 deletions test/fixtures/return-react-element/expected.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
function fn() {
const content = "content";
return React.createElement(
"div",
null,
React.createElement(
"span",
null,
content
)
);
return React.createElement("div", null, React.createElement("span", null, content));
}
3 changes: 3 additions & 0 deletions test/fixtures/return-switch-case/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ function fn(a) {
switch (a) {
case "a":
1;

case "b":
2;
break;

case "c":
3;

default:
4;
}
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/return-try-catch-finally/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ function fn() {
try {
return 1;
} catch (e) {
2;
return 2;
} finally {
return 3;
}
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/return-try-catch/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ function fn() {
try {
return 1;
} catch (e) {
2;
return 2;
}
}
5 changes: 4 additions & 1 deletion test/fixtures/return-variable-declaration/expected.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
function fn() {
const obj = { key: "value", other: 1 };
const obj = {
key: "value",
other: 1
};
return obj;
}
Loading