@nullvoxpopuli/ember-composable-helpers
Version:
Composable helpers for Ember
109 lines (100 loc) • 3.35 kB
text/typescript
import EmberArray, { isArray } from '@ember/array';
import EmberObject, { get } from '@ember/object';
import type ArrayProxy from '@ember/array/proxy';
function isIterable(value: unknown) {
return Symbol.iterator in Object(value);
}
// from https://github.com/flexyford/ember-power-select/blob/78a5430c1ac89daf315d0801fd5201e444e82434/addon/components/power-select.ts
function isArrayable<T>(thing: unknown): thing is EmberArray<T> {
return typeof (thing as EmberArray<T>).toArray === 'function';
}
function isPromiseLike<T>(thing: unknown) {
return typeof (thing as Promise<T>).then === 'function';
}
function isPromiseProxyLike<T>(thing: unknown): thing is ArrayProxy<T> {
return (
isPromiseLike(thing as Promise<T>) &&
Object.hasOwnProperty.call(thing, 'content')
);
}
function toExtendable<T>(array: T[]) {
if (!Object.isExtensible(array)) {
return Array.from(array);
} else {
return array;
}
}
export default function asArray<T>(maybeArray: T[]): T[] {
return toExtendable(_asArray(maybeArray));
}
function _asArray<T>(maybeArray: unknown): T[] {
if (typeof maybeArray === 'number') {
throw new Error(
'Numbers not supported as arrays [ember-composable-helpers]',
);
}
if (typeof maybeArray === 'string') {
return maybeArray.split('') as T[];
}
// for perf-reasons falling back to e-array, instead of using it first
if (Array.isArray(maybeArray)) {
return maybeArray;
} else if (isArray(maybeArray)) {
return maybeArray as T[];
} else if (typeof maybeArray === 'object' && maybeArray === null) {
return [];
} else if (typeof maybeArray === 'undefined') {
return [];
} else if (maybeArray instanceof Set) {
return Array.from(maybeArray.values());
} else if (maybeArray instanceof Map) {
return Array.from(maybeArray.values());
} else if (maybeArray instanceof WeakMap) {
throw new Error(
'WeakMaps is not supported as arrays [ember-composable-helpers]',
);
} else if (maybeArray instanceof WeakSet) {
throw new Error(
'WeakSets is not supported as arrays [ember-composable-helpers]',
);
}
if (typeof maybeArray === 'object') {
if (isPromiseProxyLike(maybeArray)) {
// eslint-disable-next-line ember/no-get -- TODO: Revisit this
const content = get(maybeArray, 'content');
if (typeof content !== 'object' || content === null) {
throw new Error(
'Unknown content type in array-like object [ember-composable-helpers]',
);
}
if (isArrayable(content)) {
return (content as EmberArray<T>).toArray();
} else {
return _asArray(content);
}
}
if (isPromiseLike(maybeArray)) {
throw new Error(
'Promise-like objects is not supported as arrays [ember-composable-helpers]',
);
}
if (isArrayable(maybeArray)) {
return (maybeArray as EmberArray<T>).toArray();
}
if (maybeArray instanceof EmberObject) {
throw new Error(
'EmberObjects is not supported as arrays [ember-composable-helpers]',
);
}
return Array.from(Object.values(maybeArray));
}
if (!maybeArray) {
return [];
}
if (!isIterable(maybeArray)) {
throw new Error(
'Argument, passed as array is not iterable [ember-composable-helpers]',
);
}
return maybeArray as T[];
}