From dbf6ab09dfe90a1cf09fd3befac81de5f162a201 Mon Sep 17 00:00:00 2001 From: Tony Quetano Date: Mon, 18 Dec 2023 13:03:27 -0500 Subject: [PATCH] prevent `forEach` methods from hoisting early returns, instead just converting to `continue` statements (#33) --- .../complex/for-each-early-return/code.js | 12 ++++++++++++ .../complex/for-each-early-return/output.js | 10 ++++++++++ .../__fixtures__/complex/for-each-hoisted/code.js | 2 +- .../__fixtures__/complex/for-each-hoisted/output.js | 2 +- .../complex/for-each-right-early-return/code.js | 12 ++++++++++++ .../complex/for-each-right-early-return/output.js | 10 ++++++++++ .../complex/for-each-right-hoisted/code.js | 2 +- .../complex/for-each-right-hoisted/output.js | 2 +- src/handlers.ts | 9 +++++++++ 9 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 __tests__/__fixtures__/complex/for-each-early-return/code.js create mode 100644 __tests__/__fixtures__/complex/for-each-early-return/output.js create mode 100644 __tests__/__fixtures__/complex/for-each-right-early-return/code.js create mode 100644 __tests__/__fixtures__/complex/for-each-right-early-return/output.js diff --git a/__tests__/__fixtures__/complex/for-each-early-return/code.js b/__tests__/__fixtures__/complex/for-each-early-return/code.js new file mode 100644 index 0000000..73193b8 --- /dev/null +++ b/__tests__/__fixtures__/complex/for-each-early-return/code.js @@ -0,0 +1,12 @@ +const { forEach } = require('../../../../src/inline-loops.macro'); +import { log } from './log'; + +function logItems(items) { + forEach(items, (item) => { + if (!item.position) { + return; + } + + log(item); + }); +} diff --git a/__tests__/__fixtures__/complex/for-each-early-return/output.js b/__tests__/__fixtures__/complex/for-each-early-return/output.js new file mode 100644 index 0000000..f57610c --- /dev/null +++ b/__tests__/__fixtures__/complex/for-each-early-return/output.js @@ -0,0 +1,10 @@ +import { log } from './log'; +function logItems(items) { + for (let _key = 0, _length = items.length, _item; _key < _length; ++_key) { + _item = items[_key]; + if (!_item.position) { + continue; + } + log(_item); + } +} \ No newline at end of file diff --git a/__tests__/__fixtures__/complex/for-each-hoisted/code.js b/__tests__/__fixtures__/complex/for-each-hoisted/code.js index 73193b8..072aa67 100644 --- a/__tests__/__fixtures__/complex/for-each-hoisted/code.js +++ b/__tests__/__fixtures__/complex/for-each-hoisted/code.js @@ -3,7 +3,7 @@ import { log } from './log'; function logItems(items) { forEach(items, (item) => { - if (!item.position) { + if (!this.position) { return; } diff --git a/__tests__/__fixtures__/complex/for-each-hoisted/output.js b/__tests__/__fixtures__/complex/for-each-hoisted/output.js index 912e46e..4bbbc24 100644 --- a/__tests__/__fixtures__/complex/for-each-hoisted/output.js +++ b/__tests__/__fixtures__/complex/for-each-hoisted/output.js @@ -2,7 +2,7 @@ import { log } from './log'; function logItems(items) { (() => { const _fn = (_item) => { - if (!_item.position) { + if (!this.position) { return; } log(_item); diff --git a/__tests__/__fixtures__/complex/for-each-right-early-return/code.js b/__tests__/__fixtures__/complex/for-each-right-early-return/code.js new file mode 100644 index 0000000..6e0f46d --- /dev/null +++ b/__tests__/__fixtures__/complex/for-each-right-early-return/code.js @@ -0,0 +1,12 @@ +const { forEachRight } = require('../../../../src/inline-loops.macro'); +import { log } from './log'; + +function logItems(items) { + forEachRight(items, (item) => { + if (!item.position) { + return; + } + + log(item); + }); +} diff --git a/__tests__/__fixtures__/complex/for-each-right-early-return/output.js b/__tests__/__fixtures__/complex/for-each-right-early-return/output.js new file mode 100644 index 0000000..1c71804 --- /dev/null +++ b/__tests__/__fixtures__/complex/for-each-right-early-return/output.js @@ -0,0 +1,10 @@ +import { log } from './log'; +function logItems(items) { + for (let _key = items.length, _item; --_key >= 0; ) { + _item = items[_key]; + if (!_item.position) { + continue; + } + log(_item); + } +} \ No newline at end of file diff --git a/__tests__/__fixtures__/complex/for-each-right-hoisted/code.js b/__tests__/__fixtures__/complex/for-each-right-hoisted/code.js index 6e0f46d..8aab36f 100644 --- a/__tests__/__fixtures__/complex/for-each-right-hoisted/code.js +++ b/__tests__/__fixtures__/complex/for-each-right-hoisted/code.js @@ -3,7 +3,7 @@ import { log } from './log'; function logItems(items) { forEachRight(items, (item) => { - if (!item.position) { + if (!this.position) { return; } diff --git a/__tests__/__fixtures__/complex/for-each-right-hoisted/output.js b/__tests__/__fixtures__/complex/for-each-right-hoisted/output.js index 63615c5..0cd2c0a 100644 --- a/__tests__/__fixtures__/complex/for-each-right-hoisted/output.js +++ b/__tests__/__fixtures__/complex/for-each-right-hoisted/output.js @@ -2,7 +2,7 @@ import { log } from './log'; function logItems(items) { (() => { const _fn = (_item) => { - if (!_item.position) { + if (!this.position) { return; } log(_item); diff --git a/src/handlers.ts b/src/handlers.ts index c643546..9f1a79f 100644 --- a/src/handlers.ts +++ b/src/handlers.ts @@ -91,6 +91,15 @@ export function createHandlers(babel: MacroParams['babel']) { if (body.isBlockStatement()) { if (!callbackContainsThis) { + if (isForEach) { + body.traverse(traverseConfigs.stripReturn, { isForEach }); + + return { + injectedBody: body.node.body, + returned: t.identifier('undefined'), + }; + } + if (returnCount < 2) { body.traverse(traverseConfigs.stripReturn, { isForEach }); }