From 95046a08fcb8d40f0be5571e9a366592de998fe6 Mon Sep 17 00:00:00 2001 From: Pankaj Kataria Date: Tue, 30 Jan 2024 16:16:45 +0530 Subject: [PATCH 1/7] feat: add isSliceable to as array --- addon/utils/as-array.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/addon/utils/as-array.js b/addon/utils/as-array.js index 3890b8f9..5b4afbde 100644 --- a/addon/utils/as-array.js +++ b/addon/utils/as-array.js @@ -10,6 +10,10 @@ function isArrayable(thing) { return typeof thing.toArray === 'function'; } +function isSliceable(thing) { + return typeof thing.slice === 'function'; +} + function isPromiseLike(thing) { return typeof thing.then === 'function'; } @@ -40,6 +44,8 @@ function _asArray(maybeArray) { // for perf-reasons falling back to e-array, instead of using it first if (Array.isArray(maybeArray)) { return maybeArray; + } else if (isSliceable(maybeArray)) { + return maybeArray.slice(); } else if (isArray(maybeArray)) { return maybeArray; } else if (typeof maybeArray === 'object' && maybeArray === null) { From 0cc4b8990e483044e79ba373de45b8f301b7c7c2 Mon Sep 17 00:00:00 2001 From: Pankaj Kataria Date: Tue, 30 Jan 2024 16:17:46 +0530 Subject: [PATCH 2/7] feat: use asArray in helerps --- addon/helpers/append.js | 3 ++- addon/helpers/chunk.js | 1 + addon/helpers/object-at.js | 4 ++++ addon/helpers/previous.js | 2 ++ addon/helpers/toggle.js | 2 ++ addon/helpers/without.js | 3 +++ 6 files changed, 14 insertions(+), 1 deletion(-) diff --git a/addon/helpers/append.js b/addon/helpers/append.js index e92c9703..468cdeb4 100644 --- a/addon/helpers/append.js +++ b/addon/helpers/append.js @@ -1,7 +1,8 @@ import { helper } from '@ember/component/helper'; +import asArray from '../utils/as-array'; export function append([...arrays]) { - return [].concat(...arrays); + return [].concat(...arrays.map(asArray)); } export default helper(append); diff --git a/addon/helpers/chunk.js b/addon/helpers/chunk.js index 915ec481..200a0070 100644 --- a/addon/helpers/chunk.js +++ b/addon/helpers/chunk.js @@ -8,6 +8,7 @@ export function chunk(num, array) { let size = max(integer, 0); let length = 0; + array = asArray(array); if (isEmberArray(array)) { length = array.length; } diff --git a/addon/helpers/object-at.js b/addon/helpers/object-at.js index 547df354..47100212 100644 --- a/addon/helpers/object-at.js +++ b/addon/helpers/object-at.js @@ -1,7 +1,11 @@ import { helper } from '@ember/component/helper'; import { A, isArray as isEmberArray } from '@ember/array'; +import asArray from '../utils/as-array'; export function objectAt(index, array) { + if (array) { + array = asArray(array); + } if (!isEmberArray(array)) { return undefined; } diff --git a/addon/helpers/previous.js b/addon/helpers/previous.js index ec4a8e18..83d0b485 100644 --- a/addon/helpers/previous.js +++ b/addon/helpers/previous.js @@ -3,8 +3,10 @@ import getIndex from '../utils/get-index'; import { isEmpty } from '@ember/utils'; import { A as emberArray } from '@ember/array'; import getValueArrayAndUseDeepEqualFromParams from '../-private/get-value-array-and-use-deep-equal-from-params'; +import asArray from '../utils/as-array'; export function previous(currentValue, array, useDeepEqual = false) { + array = asArray(array); let currentIndex = getIndex(array, currentValue, useDeepEqual); if (isEmpty(currentIndex)) { diff --git a/addon/helpers/toggle.js b/addon/helpers/toggle.js index 4d6042d5..5650adc1 100644 --- a/addon/helpers/toggle.js +++ b/addon/helpers/toggle.js @@ -2,6 +2,7 @@ import { helper } from '@ember/component/helper'; import { get } from '@ember/object'; import { set } from '@ember/object'; import { isPresent } from '@ember/utils'; +import asArray from '../utils/as-array'; function nextIndex(length, currentIdx) { if (currentIdx === -1 || currentIdx + 1 === length) { @@ -16,6 +17,7 @@ export function toggle([prop, obj, ...values]) { let currentValue = get(obj, prop); if (isPresent(values)) { + values = asArray(values); let currentIdx = values.indexOf(currentValue); let nextIdx = nextIndex(values.length, currentIdx); diff --git a/addon/helpers/without.js b/addon/helpers/without.js index 67b7356a..54129c4d 100644 --- a/addon/helpers/without.js +++ b/addon/helpers/without.js @@ -1,11 +1,14 @@ import { helper } from '@ember/component/helper'; import { A as emberArray, isArray as isEmberArray } from '@ember/array'; +import asArray from '../utils/as-array'; function contains(needle, haystack) { return emberArray(haystack).includes(needle); } export function without(needle, haystack) { + needle = asArray(needle); + haystack = asArray(haystack); if (!isEmberArray(haystack)) { return false; } From d49ca4fd8470ca3771f151f477e4d3aa858291ac Mon Sep 17 00:00:00 2001 From: Pankaj Kataria Date: Tue, 30 Jan 2024 16:27:43 +0530 Subject: [PATCH 3/7] fix: use isSliceable to pass tests --- addon/helpers/append.js | 4 ++-- addon/helpers/object-at.js | 6 +++--- addon/helpers/without.js | 10 +++++++--- addon/utils/as-array.js | 4 ++-- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/addon/helpers/append.js b/addon/helpers/append.js index 468cdeb4..a9cf9e44 100644 --- a/addon/helpers/append.js +++ b/addon/helpers/append.js @@ -1,8 +1,8 @@ import { helper } from '@ember/component/helper'; -import asArray from '../utils/as-array'; +import { isSliceable } from '../utils/as-array'; export function append([...arrays]) { - return [].concat(...arrays.map(asArray)); + return [].concat(...arrays.map((array) => isSliceable(array) ? array.slice() : array)); } export default helper(append); diff --git a/addon/helpers/object-at.js b/addon/helpers/object-at.js index 47100212..0e88585c 100644 --- a/addon/helpers/object-at.js +++ b/addon/helpers/object-at.js @@ -1,10 +1,10 @@ import { helper } from '@ember/component/helper'; import { A, isArray as isEmberArray } from '@ember/array'; -import asArray from '../utils/as-array'; +import { isSliceable } from '../utils/as-array'; export function objectAt(index, array) { - if (array) { - array = asArray(array); + if (isSliceable(array)) { + array = array.slice(); } if (!isEmberArray(array)) { return undefined; diff --git a/addon/helpers/without.js b/addon/helpers/without.js index 54129c4d..1e750254 100644 --- a/addon/helpers/without.js +++ b/addon/helpers/without.js @@ -1,14 +1,18 @@ import { helper } from '@ember/component/helper'; import { A as emberArray, isArray as isEmberArray } from '@ember/array'; -import asArray from '../utils/as-array'; +import { isSliceable } from '../utils/as-array'; function contains(needle, haystack) { return emberArray(haystack).includes(needle); } export function without(needle, haystack) { - needle = asArray(needle); - haystack = asArray(haystack); + if (isSliceable(haystack)) { + haystack = haystack.slice(); + } + if (isSliceable(needle)) { + needle = needle.slice(); + } if (!isEmberArray(haystack)) { return false; } diff --git a/addon/utils/as-array.js b/addon/utils/as-array.js index 5b4afbde..73555c25 100644 --- a/addon/utils/as-array.js +++ b/addon/utils/as-array.js @@ -10,8 +10,8 @@ function isArrayable(thing) { return typeof thing.toArray === 'function'; } -function isSliceable(thing) { - return typeof thing.slice === 'function'; +export function isSliceable(thing) { + return typeof thing?.slice === 'function'; } function isPromiseLike(thing) { From 15ae9fec481ecad8e0d867f3c8882cd1bdc668a0 Mon Sep 17 00:00:00 2001 From: Pankaj Kataria Date: Tue, 30 Jan 2024 16:35:24 +0530 Subject: [PATCH 4/7] fix: deprecate toArray usage --- addon/helpers/sort-by.js | 6 +++--- addon/utils/as-array.js | 6 +++--- tests/integration/helpers/next-test.js | 2 +- tests/integration/helpers/previous-test.js | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/addon/helpers/sort-by.js b/addon/helpers/sort-by.js index 0d1511de..cb6d6da9 100644 --- a/addon/helpers/sort-by.js +++ b/addon/helpers/sort-by.js @@ -1,7 +1,7 @@ import { get } from '@ember/object'; import { isEmpty } from '@ember/utils'; import { helper } from '@ember/component/helper'; -import asArray from '../utils/as-array'; +import asArray, { isSliceable } from '../utils/as-array'; const collator = new Intl.Collator(undefined, { sensitivity: 'base' @@ -109,8 +109,8 @@ function sortAsc(key, a, b) { class SortBy { constructor(...args) { let [array] = args; - if (typeof array.toArray === "function") { - array = array.toArray(); + if (isSliceable(array)) { + array = array.slice(); } this.array = [...array]; diff --git a/addon/utils/as-array.js b/addon/utils/as-array.js index 73555c25..dae54679 100644 --- a/addon/utils/as-array.js +++ b/addon/utils/as-array.js @@ -7,7 +7,7 @@ function isIterable(value) { // from https://github.com/flexyford/ember-power-select/blob/78a5430c1ac89daf315d0801fd5201e444e82434/addon/components/power-select.ts function isArrayable(thing) { - return typeof thing.toArray === 'function'; + return isSliceable(thing); } export function isSliceable(thing) { @@ -67,7 +67,7 @@ function _asArray(maybeArray) { throw new Error('Unknown content type in array-like object [ember-composable-helpers]'); } if (isArrayable(content)) { - return content.toArray(); + return content.slice(); } else { return _asArray(content); } @@ -76,7 +76,7 @@ function _asArray(maybeArray) { throw new Error('Promise-like objects is not supported as arrays [ember-composable-helpers]'); } if (isArrayable(maybeArray)) { - return maybeArray.toArray(); + return maybeArray.slice(); } if (maybeArray instanceof EmberObject) { throw new Error('EmberObjects is not supported as arrays [ember-composable-helpers]') diff --git a/tests/integration/helpers/next-test.js b/tests/integration/helpers/next-test.js index b6ae43cc..0f330a67 100644 --- a/tests/integration/helpers/next-test.js +++ b/tests/integration/helpers/next-test.js @@ -69,7 +69,7 @@ module('Integration | Helper | {{next}}', function(hooks) { store.createRecord('pet', { name: 'Jake' }) ]); - this.set('pets', person.pets.toArray()); + this.set('pets', person.pets.slice()); this.set('currentPet', person.get('pets.firstObject')); await render(hbs` diff --git a/tests/integration/helpers/previous-test.js b/tests/integration/helpers/previous-test.js index 2c06e48c..0e8a1ef0 100644 --- a/tests/integration/helpers/previous-test.js +++ b/tests/integration/helpers/previous-test.js @@ -69,7 +69,7 @@ module('Integration | Helper | {{previous}}', function(hooks) { store.createRecord('pet', { name: 'Jake' }) ]); - this.set('pets', person.pets.toArray()); + this.set('pets', person.pets.slice()); this.set('currentPet', person.get('pets.lastObject')); await render(hbs` From 10028c222ee376b541d67a8b13211fae43f47d86 Mon Sep 17 00:00:00 2001 From: Pankaj Kataria Date: Tue, 30 Jan 2024 18:42:28 +0530 Subject: [PATCH 5/7] feat: add check for PromiseManyArray --- addon/utils/as-array.js | 6 ++++-- tests/unit/utils/as-array-test.js | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/addon/utils/as-array.js b/addon/utils/as-array.js index dae54679..69534d18 100644 --- a/addon/utils/as-array.js +++ b/addon/utils/as-array.js @@ -1,11 +1,11 @@ import { isArray } from '@ember/array'; import EmberObject, { get } from '@ember/object'; +import { PromiseManyArray } from '@ember-data/model/-private'; function isIterable(value) { return Symbol.iterator in Object(value); } -// from https://github.com/flexyford/ember-power-select/blob/78a5430c1ac89daf315d0801fd5201e444e82434/addon/components/power-select.ts function isArrayable(thing) { return isSliceable(thing); } @@ -15,7 +15,7 @@ export function isSliceable(thing) { } function isPromiseLike(thing) { - return typeof thing.then === 'function'; + return typeof thing?.then === 'function'; } function isPromiseProxyLike(thing) { @@ -46,6 +46,8 @@ function _asArray(maybeArray) { return maybeArray; } else if (isSliceable(maybeArray)) { return maybeArray.slice(); + } else if (maybeArray instanceof PromiseManyArray) { + return get(maybeArray, 'content')?.slice() ?? []; } else if (isArray(maybeArray)) { return maybeArray; } else if (typeof maybeArray === 'object' && maybeArray === null) { diff --git a/tests/unit/utils/as-array-test.js b/tests/unit/utils/as-array-test.js index 5d5f5f0c..3ad6f653 100644 --- a/tests/unit/utils/as-array-test.js +++ b/tests/unit/utils/as-array-test.js @@ -33,9 +33,9 @@ module('Unit | Utility | as-array', function () { assert.equal(result.length, 3); }); - test('it works for [Object.toArray()]', function (assert) { + test('it works for [Object.slice()]', function (assert) { let result = asArray({ - a: 1, toArray() { + a: 1, slice() { return [1, 2, 3]; } }); @@ -86,10 +86,10 @@ module('Unit | Utility | as-array', function () { assert.equal(asArray(item).length, 3); }); - test('it works for object-like content in array-proxy-like items [objects toArray]', function (assert) { + test('it works for object-like content in array-proxy-like items [objects slice]', function (assert) { const item = new Promise((r) => r()); item.content = { - a: 1, toArray() { + a: 1, slice() { return [1, 2, 3] } }; @@ -102,8 +102,8 @@ module('Unit | Utility | as-array', function () { assert.equal(asArray(item).length, 3); }); - test('it works for ember object with toArray property [EmberObject]', function (assert) { - const item = EmberObject.extend({ toArray() { return [1, 2, 3] } }).create(); + test('it works for ember object with slice property [EmberObject]', function (assert) { + const item = EmberObject.extend({ slice() { return [1, 2, 3] } }).create(); assert.equal(asArray(item).length, 3); }); From 7b148dba4724100f516d32b5d8a4f4aae8d57e67 Mon Sep 17 00:00:00 2001 From: Pankaj Kataria Date: Thu, 1 Feb 2024 16:43:14 +0530 Subject: [PATCH 6/7] fix: don't force slice --- addon/utils/as-array.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/addon/utils/as-array.js b/addon/utils/as-array.js index 69534d18..93273d03 100644 --- a/addon/utils/as-array.js +++ b/addon/utils/as-array.js @@ -44,8 +44,6 @@ function _asArray(maybeArray) { // for perf-reasons falling back to e-array, instead of using it first if (Array.isArray(maybeArray)) { return maybeArray; - } else if (isSliceable(maybeArray)) { - return maybeArray.slice(); } else if (maybeArray instanceof PromiseManyArray) { return get(maybeArray, 'content')?.slice() ?? []; } else if (isArray(maybeArray)) { From 3b2e53952fe83b52cd8ed816013fd3bb1f8821bf Mon Sep 17 00:00:00 2001 From: Hassan Shaikh <31429974+hassanshaikh7466@users.noreply.github.com> Date: Tue, 20 Feb 2024 23:11:57 +0530 Subject: [PATCH 7/7] use asArray --- addon/helpers/object-at.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/helpers/object-at.js b/addon/helpers/object-at.js index 0e88585c..d0167a5f 100644 --- a/addon/helpers/object-at.js +++ b/addon/helpers/object-at.js @@ -1,6 +1,7 @@ import { helper } from '@ember/component/helper'; import { A, isArray as isEmberArray } from '@ember/array'; import { isSliceable } from '../utils/as-array'; +import asArray from '../utils/as-array'; export function objectAt(index, array) { if (isSliceable(array)) { @@ -12,7 +13,7 @@ export function objectAt(index, array) { index = parseInt(index, 10); - return A(array).objectAt(index); + return A(asArray(array)).objectAt(index); } export default helper(function([index, array]) {