Skip to content

Commit

Permalink
support usage in conditionals
Browse files Browse the repository at this point in the history
  • Loading branch information
planttheidea committed Dec 16, 2023
1 parent 928a0eb commit f04aa41
Show file tree
Hide file tree
Showing 20 changed files with 332 additions and 259 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

## Enhancements

- Support for conditional usage in ternaries / logical expressions
- Better TS typing
- Better inline handling of complex logic

Expand Down
51 changes: 0 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ Iteration helpers that inline to native loops for performance
- [Aggressive inlining](#aggressive-inlining)
- [Bailout scenarios](#bailout-scenarios)
- [Gotchas](#gotchas)
- [Conditionals do not delay execution](#conditionals-do-not-delay-execution)
- [`*Object` methods do not perform `hasOwnProperty` check](#object-methods-do-not-perform-hasownproperty-check)
- [`find*` methods](#find-methods)
- [Development](#development)
Expand Down Expand Up @@ -181,56 +180,6 @@ const inlined = map(array, (value) => (value % 2 === 0 ? 'even' : 'odd'));
Some aspects of implementing this macro that you should be aware of:
### Conditionals do not delay execution
If you do something like this with standard JS:
```js
return isFoo ? array.map((v) => v * 2) : array;
```
The `array` is only mapped over if `isFoo` is true. However, because we are inlining these calls into `for` loops in the scope they operate in, this conditional calling does not apply with this macro.
```js
// this
return isFoo ? map(array, (v) => v * 2) : array;

// turns into this
const _length = array.length;
const _results = Array(_length);
for (let _key = 0, _value; _key < _length; ++_key) {
_value = array[_key];
_results[_key] = fn(_value, _key, array);
}
return isFoo ? _results : array;
```
Notice the mapping occurs whether the condition is met or not. If you want to ensure this conditionality is maintained, you should use an `if` block instead:
```js
// this
if (isFoo) {
return map(array, (v) => v * 2);
}

return array;

// turns into this
if (isFoo) {
const _length = array.length;
const _results = Array(_length);
for (let _key = 0, _value; _key < _length; ++_key) {
_value = array[_key];
_results[_key] = fn(_value, _key, array);
}
return _results;
}

return array;
```
This will ensure the potentially-expensive computation only occurs when necessary.
### `*Object` methods do not perform `hasOwnProperty` check
The object methods will do operations in `for-in` loop, but will not guard via a `hasOwnProperty` check. For example:
Expand Down
14 changes: 9 additions & 5 deletions __tests__/__fixtures__/bailout/early-return/code.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { filter } from '../../../../src/inline-loops.macro';

const result = filter([1, 2, 3], (value) => {
if (value === 2) {
return true;
}
});
function getFoo(config) {
const collection = config.collection || [1, 2, 3];

return filter(collection, (value) => {
if (value === 2) {
return true;
}
});
}
42 changes: 23 additions & 19 deletions __tests__/__fixtures__/bailout/early-return/output.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
const _collection = [1, 2, 3];
const _fn = (_value) => {
if (_value === 2) {
return true;
}
};
const _results = [];
for (
let _key = 0, _length = _collection.length, _value, _result;
_key < _length;
++_key
) {
_value = _collection[_key];
_result = _fn(_value, _key, _collection);
if (_result) {
_results.push(_value);
}
}
const result = _results;
function getFoo(config) {
const collection = config.collection || [1, 2, 3];
return (() => {
const _fn = (_value) => {
if (_value === 2) {
return true;
}
};
const _results = [];
for (
let _key = 0, _length = collection.length, _value, _result;
_key < _length;
++_key
) {
_value = collection[_key];
_result = _fn(_value, _key, collection);
if (_result) {
_results.push(_value);
}
}
return _results;
})();
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { map } from '../../../../src/inline-loops.macro';

function getStuff() {
function getStuff(array, foo) {
if (foo === 'bar') {
return map(array, v => v * 2);
return map(array, (v) => v * 2);
}

return array;
Expand Down
14 changes: 14 additions & 0 deletions __tests__/__fixtures__/complex/conditional-if/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
function getStuff(array, foo) {
if (foo === 'bar') {
return (() => {
const _length = array.length;
const _results = Array(_length);
for (let _key = 0, _v; _key < _length; ++_key) {
_v = array[_key];
_results[_key] = _v * 2;
}
return _results;
})();
}
return array;
}
5 changes: 5 additions & 0 deletions __tests__/__fixtures__/complex/conditional-logical/code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { map } from '../../../../src/inline-loops.macro';

function getStuff(array) {
return array || map(array, (v) => v * 2);
}
14 changes: 14 additions & 0 deletions __tests__/__fixtures__/complex/conditional-logical/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
function getStuff(array) {
return (
array ||
(() => {
const _length = array.length;
const _results = Array(_length);
for (let _key = 0, _v; _key < _length; ++_key) {
_v = array[_key];
_results[_key] = _v * 2;
}
return _results;
})()
);
}
5 changes: 5 additions & 0 deletions __tests__/__fixtures__/complex/conditional-ternary/code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { map } from '../../../../src/inline-loops.macro';

function getStuff(array, foo) {
return foo === 'bar' ? map(array, (v) => v * 2) : array;
}
13 changes: 13 additions & 0 deletions __tests__/__fixtures__/complex/conditional-ternary/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
function getStuff(array, foo) {
return foo === 'bar'
? (() => {
const _length = array.length;
const _results = Array(_length);
for (let _key = 0, _v; _key < _length; ++_key) {
_v = array[_key];
_results[_key] = _v * 2;
}
return _results;
})()
: array;
}
12 changes: 0 additions & 12 deletions __tests__/__fixtures__/complex/conditional/output.js

This file was deleted.

34 changes: 20 additions & 14 deletions __tests__/__fixtures__/complex/jsx/output.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import React from 'react';
function List(props) {
const _collection = props.items;
const _length = _collection.length;
const _results = Array(_length);
for (let _key = 0, _item; _key < _length; ++_key) {
_item = _collection[_key];
_results[_key] = /*#__PURE__*/ React.createElement(
'li',
{
key: _item.id,
},
_item.value,
);
}
return /*#__PURE__*/ React.createElement('ul', null, _results);
return /*#__PURE__*/ React.createElement(
'ul',
null,
(() => {
const _collection = props.items;
const _length = _collection.length;
const _results = Array(_length);
for (let _key = 0, _item; _key < _length; ++_key) {
_item = _collection[_key];
_results[_key] = /*#__PURE__*/ React.createElement(
'li',
{
key: _item.id,
},
_item.value,
);
}
return _results;
})(),
);
}
22 changes: 12 additions & 10 deletions __tests__/__fixtures__/complex/this/output.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
function foo(array) {
const _fn = function (_value) {
return this && this.foo ? _value : null;
};
const _length = array.length;
const _results = Array(_length);
for (let _key = 0, _value; _key < _length; ++_key) {
_value = array[_key];
_results[_key] = _fn(_value, _key, array);
}
return _results;
return (() => {
const _fn = function (_value) {
return this && this.foo ? _value : null;
};
const _length = array.length;
const _results = Array(_length);
for (let _key = 0, _value; _key < _length; ++_key) {
_value = array[_key];
_results[_key] = _fn(_value, _key, array);
}
return _results;
})();
}
Loading

0 comments on commit f04aa41

Please sign in to comment.