X-Git-Url: https://git.ladys.computer/Pisces/blobdiff_plain/e8d0d3ab4f8a844e15873345c0564929c80fdb74..HEAD:/collection.js diff --git a/collection.js b/collection.js index 38b048c..d340709 100644 --- a/collection.js +++ b/collection.js @@ -1,22 +1,17 @@ // ♓🌟 Piscēs ∷ collection.js // ==================================================================== // -// Copyright © 2020–2022 Lady [@ Lady’s Computer]. +// Copyright © 2020–2023 Lady [@ Lady’s Computer]. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at . -import { call, makeCallable } from "./function.js"; -import { - floor, - isIntegralNumber, - isNan, - max, - MAXIMUM_SAFE_INTEGRAL_NUMBER, - min, -} from "./numeric.js"; -import { sameValue, type } from "./value.js"; +import { call, createCallableFunction } from "./function.js"; +import { isConcatSpreadableObject } from "./object.js"; +import { toIndex, type } from "./value.js"; + +const { prototype: arrayPrototype } = Array; export const { /** Returns an array of the provided values. */ @@ -30,53 +25,42 @@ export const { } = Array; /** - * Returns -0 if the provided argument is "-0"; returns a number - * representing the index if the provided argument is a canonical - * numeric index string; otherwise, returns undefined. - * - * There is no clamping of the numeric index, but note that numbers - * above 2^53 − 1 are not safe nor valid integer indices. - */ -export const canonicalNumericIndexString = ($) => { - if (typeof $ !== "string") { - return undefined; - } else if ($ === "-0") { - return -0; - } else { - const n = +$; - return $ === `${n}` ? n : undefined; - } -}; - -/** - * Returns the result of catenating the provided arraylikes, returning - * a new collection according to the algorithm of Array::concat. + * Returns the result of catenating the provided arraylikes into a new + * collection according to the algorithm of `Array::concat`. */ -export const catenate = makeCallable(Array.prototype.concat); +export const catenate = createCallableFunction( + arrayPrototype.concat, + "catenate", +); /** * Copies the items in the provided object to a new location according - * to the algorithm of Array::copyWithin. + * to the algorithm of `Array::copyWithin`. */ -export const copyWithin = makeCallable(Array.prototype.copyWithin); +export const copyWithin = createCallableFunction( + arrayPrototype.copyWithin, +); /** - * Fills the provided object with the provided value using the - * algorithm of Array::fill. + * Fills the provided object with the provided value according to the + * algorithm of `Array::fill`. */ -export const fill = makeCallable(Array.prototype.fill); +export const fill = createCallableFunction(arrayPrototype.fill); /** * Returns the result of filtering the provided object with the - * provided callback, using the algorithm of Array::filter. + * provided callback, according to the algorithm of `Array::filter`. */ -export const filter = makeCallable(Array.prototype.filter); +export const filter = createCallableFunction(arrayPrototype.filter); /** * Returns the first index in the provided object whose value satisfies - * the provided callback using the algorithm of Array::findIndex. + * the provided callback according to the algorithm of + * `Array::findIndex`. */ -export const findIndex = makeCallable(Array.prototype.findIndex); +export const findIndex = createCallableFunction( + arrayPrototype.findIndex, +); /** * Returns the first indexed entry in the provided object whose value @@ -106,115 +90,123 @@ export const findIndexedEntry = ( /** * Returns the first indexed value in the provided object which - * satisfies the provided callback, using the algorithm of Array::find. + * satisfies the provided callback, according to the algorithm of + * `Array::find`. */ -export const findItem = makeCallable(Array.prototype.find); +export const findItem = createCallableFunction( + arrayPrototype.find, + "findItem", +); /** * Returns the result of flatmapping the provided value with the - * provided callback using the algorithm of Array::flatMap. + * provided callback according to the algorithm of `Array::flatMap`. */ -export const flatmap = makeCallable(Array.prototype.flatMap); +export const flatmap = createCallableFunction( + arrayPrototype.flatMap, + "flatmap", +); /** - * Returns the result of flattening the provided object using the - * algorithm of Array::flat. + * Returns the result of flattening the provided object according to + * the algorithm of `Array::flat`. */ -export const flatten = makeCallable(Array.prototype.flat); +export const flatten = createCallableFunction( + arrayPrototype.flat, + "flatten", +); /** * Returns the first index of the provided object with a value * equivalent to the provided value according to the algorithm of - * Array::indexOf. + * `Array::indexOf`. */ -export const getFirstIndex = makeCallable(Array.prototype.indexOf); +export const getFirstIndex = createCallableFunction( + arrayPrototype.indexOf, + "getFirstIndex", +); /** - * Returns the item on the provided object at the provided index using - * the algorithm of Array::at. + * Returns the item on the provided object at the provided index + * according to the algorithm of `Array::at`. */ -export const getItem = makeCallable(Array.prototype.at); +export const getItem = createCallableFunction( + arrayPrototype.at, + "getItem", +); /** * Returns the last index of the provided object with a value * equivalent to the provided value according to the algorithm of - * Array::lastIndexOf. + * `Array::lastIndexOf`. */ -export const getLastIndex = makeCallable(Array.prototype.lastIndexOf); +export const getLastIndex = createCallableFunction( + arrayPrototype.lastIndexOf, + "getLastIndex", +); /** * Returns whether every indexed value in the provided object satisfies - * the provided function, using the algorithm of Array::every. + * the provided function, according to the algorithm of `Array::every`. */ -export const hasEvery = makeCallable(Array.prototype.every); +export const hasEvery = createCallableFunction( + arrayPrototype.every, + "hasEvery", +); /** * Returns whether the provided object has an indexed value which - * satisfies the provided function, using the algorithm of Array::some. + * satisfies the provided function, according to the algorithm of + * `Array::some`. */ -export const hasSome = makeCallable(Array.prototype.some); +export const hasSome = createCallableFunction( + arrayPrototype.some, + "hasSome", +); /** * Returns whether the provided object has an indexed value equivalent - * to the provided value according to the algorithm of Array::includes. + * to the provided value according to the algorithm of + * `Array::includes`. * - * > ☡ This algorithm treats missing values as `undefined` rather than - * > skipping them. + * ※ This algorithm treats missing values as `undefined` rather than + * skipping them. */ -export const includes = makeCallable(Array.prototype.includes); +export const includes = createCallableFunction( + arrayPrototype.includes, +); /** * Returns an iterator over the indexed entries in the provided value - * according to the algorithm of Array::entries. + * according to the algorithm of `Array::entries`. */ -export const indexedEntries = makeCallable(Array.prototype.entries); +export const indexedEntries = createCallableFunction( + arrayPrototype.entries, + "indexedEntries", +); /** * Returns an iterator over the indices in the provided value according - * to the algorithm of Array::keys. + * to the algorithm of `Array::keys`. */ -export const indices = makeCallable(Array.prototype.keys); - -/** Returns whether the provided value is an array index string. */ -export const isArrayIndexString = ($) => { - const value = canonicalNumericIndexString($); - if (value !== undefined) { - // The provided value is a canonical numeric index string. - return sameValue(value, 0) || value > 0 && value < -1 >>> 0 && - value === toLength(value); - } else { - // The provided value is not a canonical numeric index string. - return false; - } -}; - -/** Returns whether the provided value is arraylike. */ -export const isArraylikeObject = ($) => { - if (type($) !== "object") { - return false; - } else { - try { - lengthOfArraylike($); // throws if not arraylike - return true; - } catch { - return false; - } - } -}; +export const indices = createCallableFunction( + arrayPrototype.keys, + "indices", +); /** * Returns whether the provided object is a collection. * * The definition of “collection” used by Piscēs is similar to * Ecmascript’s definition of an arraylike object, but it differs in - * a few ways :— + * a few ways :— * * - It requires the provided value to be a proper object. * * - It requires the `length` property to be an integer index. * * - It requires the object to be concat‐spreadable, meaning it must - * either be an array or have `[Symbol.isConcatSpreadable]` be true. + * either be an array or have `.[Symbol.isConcatSpreadable]` be true. */ export const isCollection = ($) => { if (!(type($) === "object" && "length" in $)) { @@ -223,138 +215,78 @@ export const isCollection = ($) => { } else { try { toIndex($.length); // will throw if `length` is not an index - return isConcatSpreadable($); + return isConcatSpreadableObject($); } catch { return false; } } }; -/** - * Returns whether the provided value is spreadable during array - * concatenation. - * - * This is also used to determine which things should be treated as - * collections. - */ -export const isConcatSpreadable = ($) => { - if (type($) !== "object") { - // The provided value is not an object. - return false; - } else { - // The provided value is an object. - const spreadable = $[Symbol.isConcatSpreadable]; - return spreadable !== undefined ? !!spreadable : isArray($); - } -}; - -/** Returns whether the provided value is an integer index string. */ -export const isIntegerIndexString = ($) => { - const value = canonicalNumericIndexString($); - if (value !== undefined && isIntegralNumber(value)) { - // The provided value is a canonical numeric index string. - return sameValue(value, 0) || - value > 0 && value <= MAXIMUM_SAFE_INTEGRAL_NUMBER && - value === toLength(value); - } else { - // The provided value is not a canonical numeric index string. - return false; - } -}; - /** * Returns an iterator over the items in the provided value according - * to the algorithm of Array::values. + * to the algorithm of `Array::values`. */ -export const items = makeCallable(Array.prototype.values); +export const items = createCallableFunction( + arrayPrototype.values, + "items", +); /** - * Returns the length of the provided arraylike object. - * - * Will throw if the provided object is not arraylike. - * - * This can produce larger lengths than can actually be stored in - * arrays, because no such restrictions exist on arraylike methods. + * Returns the result of mapping the provided value with the provided + * callback according to the algorithm of `Array::map`. */ -export const lengthOfArraylike = ({ length }) => toLength(length); +export const map = createCallableFunction(arrayPrototype.map); /** - * Returns the result of mapping the provided value with the provided - * callback using the algorithm of Array::map. + * Pops from the provided value according to the algorithm of + * `Array::pop`. */ -export const map = makeCallable(Array.prototype.map); - -/** Pops from the provided value using the algorithm of Array::pop. */ -export const pop = makeCallable(Array.prototype.pop); +export const pop = createCallableFunction(arrayPrototype.pop); /** - * Pushes onto the provided value using the algorithm of Array::push. + * Pushes onto the provided value according to the algorithm of + * `Array::push`. */ -export const push = makeCallable(Array.prototype.push); +export const push = createCallableFunction(arrayPrototype.push); /** * Returns the result of reducing the provided value with the provided - * callback, using the algorithm of Array::reduce. + * callback, according to the algorithm of `Array::reduce`. */ -export const reduce = makeCallable(Array.prototype.reduce); +export const reduce = createCallableFunction(arrayPrototype.reduce); /** - * Reverses the provided value using the algorithm of Array::reverse. + * Reverses the provided value according to the algorithm of + * `Array::reverse`. */ -export const reverse = makeCallable(Array.prototype.reverse); - -/** Shifts the provided value using the algorithm of Array::shift. */ -export const shift = makeCallable(Array.prototype.shift); +export const reverse = createCallableFunction(arrayPrototype.reverse); /** - * Returns a slice of the provided value using the algorithm of - * Array::slice. + * Shifts the provided value according to the algorithm of + * `Array::shift`. */ -export const slice = makeCallable(Array.prototype.slice); +export const shift = createCallableFunction(arrayPrototype.shift); /** - * Sorts the provided value in‐place using the algorithm of - * Array::sort. + * Returns a slice of the provided value according to the algorithm of + * `Array::slice`. */ -export const sort = makeCallable(Array.prototype.sort); +export const slice = createCallableFunction(arrayPrototype.slice); /** - * Splices into and out of the provided value using the algorithm of - * Array::splice. + * Sorts the provided value in‐place according to the algorithm of + * `Array::sort`. */ -export const splice = makeCallable(Array.prototype.splice); +export const sort = createCallableFunction(arrayPrototype.sort); /** - * Returns the result of converting the provided value to an array - * index, or throws an error if it is out of range. + * Splices into and out of the provided value according to the + * algorithm of `Array::splice`. */ -export const toIndex = ($) => { - const integer = floor($); - if (isNan(integer) || integer == 0) { - // The value is zero·like. - return 0; - } else { - // The value is not zero·like. - const clamped = toLength(integer); - if (clamped !== integer) { - // Clamping the value changes it. - throw new RangeError(`Piscēs: Index out of range: ${$}.`); - } else { - // The value is within appropriate bounds. - return integer; - } - } -}; - -/** Returns the result of converting the provided value to a length. */ -export const toLength = ($) => { - const len = floor($); - return isNan(len) || len == 0 - ? 0 - : max(min(len, MAXIMUM_SAFE_INTEGRAL_NUMBER), 0); -}; +export const splice = createCallableFunction(arrayPrototype.splice); /** - * Unshifts the provided value using the algorithm of Array::unshift. + * Unshifts the provided value according to the algorithm of + * `Array::unshift`. */ -export const unshift = makeCallable(Array.prototype.unshift); +export const unshift = createCallableFunction(arrayPrototype.unshift);