]> Lady’s Gitweb - Pisces/blob - collection.js
4545321af94621bf4e7c35afde39f64b303c175a
[Pisces] / collection.js
1 // ♓🌟 Piscēs ∷ collection.js
2 // ====================================================================
3 //
4 // Copyright © 2020–2023 Lady [@ Lady’s Computer].
5 //
6 // This Source Code Form is subject to the terms of the Mozilla Public
7 // License, v. 2.0. If a copy of the MPL was not distributed with this
8 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
9
10 import { call, createCallableFunction } from "./function.js";
11 import {
12 isIntegralNumber,
13 MAXIMUM_SAFE_INTEGRAL_NUMBER,
14 } from "./numeric.js";
15 import {
16 canonicalNumericIndexString,
17 lengthOfArraylike,
18 sameValue,
19 toIndex,
20 toLength,
21 type,
22 } from "./value.js";
23
24 const { prototype: arrayPrototype } = Array;
25
26 export const {
27 /** Returns an array of the provided values. */
28 of: array,
29
30 /** Returns whether the provided value is an array. */
31 isArray,
32
33 /** Returns an array created from the provided arraylike. */
34 from: toArray,
35 } = Array;
36
37 /**
38 * Returns the result of catenating the provided arraylikes into a new
39 * collection according to the algorithm of `Array::concat`.
40 */
41 export const catenate = createCallableFunction(
42 arrayPrototype.concat,
43 "catenate",
44 );
45
46 /**
47 * Copies the items in the provided object to a new location according
48 * to the algorithm of `Array::copyWithin`.
49 */
50 export const copyWithin = createCallableFunction(
51 arrayPrototype.copyWithin,
52 );
53
54 /**
55 * Fills the provided object with the provided value according to the
56 * algorithm of `Array::fill`.
57 */
58 export const fill = createCallableFunction(arrayPrototype.fill);
59
60 /**
61 * Returns the result of filtering the provided object with the
62 * provided callback, according to the algorithm of `Array::filter`.
63 */
64 export const filter = createCallableFunction(arrayPrototype.filter);
65
66 /**
67 * Returns the first index in the provided object whose value satisfies
68 * the provided callback according to the algorithm of
69 * `Array::findIndex`.
70 */
71 export const findIndex = createCallableFunction(
72 arrayPrototype.findIndex,
73 );
74
75 /**
76 * Returns the first indexed entry in the provided object whose value
77 * satisfies the provided callback.
78 *
79 * If a third argument is supplied, it will be used as the this value
80 * of the callback.
81 */
82 export const findIndexedEntry = (
83 $,
84 callback,
85 thisArg = undefined,
86 ) => {
87 let result = undefined;
88 findItem($, (kValue, k, O) => {
89 if (call(callback, thisArg, [kValue, k, O])) {
90 // The callback succeeded.
91 result = [k, kValue];
92 return true;
93 } else {
94 // The callback failed.
95 return false;
96 }
97 });
98 return result;
99 };
100
101 /**
102 * Returns the first indexed value in the provided object which
103 * satisfies the provided callback, according to the algorithm of
104 * `Array::find`.
105 */
106 export const findItem = createCallableFunction(
107 arrayPrototype.find,
108 "findItem",
109 );
110
111 /**
112 * Returns the result of flatmapping the provided value with the
113 * provided callback according to the algorithm of `Array::flatMap`.
114 */
115 export const flatmap = createCallableFunction(
116 arrayPrototype.flatMap,
117 "flatmap",
118 );
119
120 /**
121 * Returns the result of flattening the provided object according to
122 * the algorithm of `Array::flat`.
123 */
124 export const flatten = createCallableFunction(
125 arrayPrototype.flat,
126 "flatten",
127 );
128
129 /**
130 * Returns the first index of the provided object with a value
131 * equivalent to the provided value according to the algorithm of
132 * `Array::indexOf`.
133 */
134 export const getFirstIndex = createCallableFunction(
135 arrayPrototype.indexOf,
136 "getFirstIndex",
137 );
138
139 /**
140 * Returns the item on the provided object at the provided index
141 * according to the algorithm of `Array::at`.
142 */
143 export const getItem = createCallableFunction(
144 arrayPrototype.at,
145 "getItem",
146 );
147
148 /**
149 * Returns the last index of the provided object with a value
150 * equivalent to the provided value according to the algorithm of
151 * `Array::lastIndexOf`.
152 */
153 export const getLastIndex = createCallableFunction(
154 arrayPrototype.lastIndexOf,
155 "getLastIndex",
156 );
157
158 /**
159 * Returns whether every indexed value in the provided object satisfies
160 * the provided function, according to the algorithm of `Array::every`.
161 */
162 export const hasEvery = createCallableFunction(
163 arrayPrototype.every,
164 "hasEvery",
165 );
166
167 /**
168 * Returns whether the provided object has an indexed value which
169 * satisfies the provided function, according to the algorithm of
170 * `Array::some`.
171 */
172 export const hasSome = createCallableFunction(
173 arrayPrototype.some,
174 "hasSome",
175 );
176
177 /**
178 * Returns whether the provided object has an indexed value equivalent
179 * to the provided value according to the algorithm of
180 * `Array::includes`.
181 *
182 * ※ This algorithm treats missing values as `undefined` rather than
183 * skipping them.
184 */
185 export const includes = createCallableFunction(
186 arrayPrototype.includes,
187 );
188
189 /**
190 * Returns an iterator over the indexed entries in the provided value
191 * according to the algorithm of `Array::entries`.
192 */
193 export const indexedEntries = createCallableFunction(
194 arrayPrototype.entries,
195 "indexedEntries",
196 );
197
198 /**
199 * Returns an iterator over the indices in the provided value according
200 * to the algorithm of `Array::keys`.
201 */
202 export const indices = createCallableFunction(
203 arrayPrototype.keys,
204 "indices",
205 );
206
207 /** Returns whether the provided value is an array index string. */
208 export const isArrayIndexString = ($) => {
209 const value = canonicalNumericIndexString($);
210 if (value !== undefined) {
211 // The provided value is a canonical numeric index string.
212 return sameValue(value, 0) || value > 0 && value < -1 >>> 0 &&
213 value === toLength(value);
214 } else {
215 // The provided value is not a canonical numeric index string.
216 return false;
217 }
218 };
219
220 /** Returns whether the provided value is arraylike. */
221 export const isArraylikeObject = ($) => {
222 if (type($) !== "object") {
223 return false;
224 } else {
225 try {
226 lengthOfArraylike($); // throws if not arraylike
227 return true;
228 } catch {
229 return false;
230 }
231 }
232 };
233
234 /**
235 * Returns whether the provided object is a collection.
236 *
237 * The definition of “collection” used by Piscēs is similar to
238 * Ecmascript’s definition of an arraylike object, but it differs in
239 * a few ways :—
240 *
241 * - It requires the provided value to be a proper object.
242 *
243 * - It requires the `length` property to be an integer index.
244 *
245 * - It requires the object to be concat‐spreadable, meaning it must
246 * either be an array or have `.[Symbol.isConcatSpreadable]` be true.
247 */
248 export const isCollection = ($) => {
249 if (!(type($) === "object" && "length" in $)) {
250 // The provided value is not an object or does not have a `length`.
251 return false;
252 } else {
253 try {
254 toIndex($.length); // will throw if `length` is not an index
255 return isConcatSpreadable($);
256 } catch {
257 return false;
258 }
259 }
260 };
261
262 /**
263 * Returns whether the provided value is spreadable during array
264 * concatenation.
265 *
266 * This is also used to determine which things should be treated as
267 * collections.
268 */
269 export const isConcatSpreadable = ($) => {
270 if (type($) !== "object") {
271 // The provided value is not an object.
272 return false;
273 } else {
274 // The provided value is an object.
275 const spreadable = $[Symbol.isConcatSpreadable];
276 return spreadable !== undefined ? !!spreadable : isArray($);
277 }
278 };
279
280 /** Returns whether the provided value is an integer index string. */
281 export const isIntegerIndexString = ($) => {
282 const value = canonicalNumericIndexString($);
283 if (value !== undefined && isIntegralNumber(value)) {
284 // The provided value is a canonical numeric index string.
285 return sameValue(value, 0) ||
286 value > 0 && value <= MAXIMUM_SAFE_INTEGRAL_NUMBER &&
287 value === toLength(value);
288 } else {
289 // The provided value is not a canonical numeric index string.
290 return false;
291 }
292 };
293
294 /**
295 * Returns an iterator over the items in the provided value according
296 * to the algorithm of `Array::values`.
297 */
298 export const items = createCallableFunction(
299 arrayPrototype.values,
300 "items",
301 );
302
303 /**
304 * Returns the result of mapping the provided value with the provided
305 * callback according to the algorithm of `Array::map`.
306 */
307 export const map = createCallableFunction(arrayPrototype.map);
308
309 /**
310 * Pops from the provided value according to the algorithm of
311 * `Array::pop`.
312 */
313 export const pop = createCallableFunction(arrayPrototype.pop);
314
315 /**
316 * Pushes onto the provided value according to the algorithm of
317 * `Array::push`.
318 */
319 export const push = createCallableFunction(arrayPrototype.push);
320
321 /**
322 * Returns the result of reducing the provided value with the provided
323 * callback, according to the algorithm of `Array::reduce`.
324 */
325 export const reduce = createCallableFunction(arrayPrototype.reduce);
326
327 /**
328 * Reverses the provided value according to the algorithm of
329 * `Array::reverse`.
330 */
331 export const reverse = createCallableFunction(arrayPrototype.reverse);
332
333 /**
334 * Shifts the provided value according to the algorithm of
335 * `Array::shift`.
336 */
337 export const shift = createCallableFunction(arrayPrototype.shift);
338
339 /**
340 * Returns a slice of the provided value according to the algorithm of
341 * `Array::slice`.
342 */
343 export const slice = createCallableFunction(arrayPrototype.slice);
344
345 /**
346 * Sorts the provided value in‐place according to the algorithm of
347 * `Array::sort`.
348 */
349 export const sort = createCallableFunction(arrayPrototype.sort);
350
351 /**
352 * Splices into and out of the provided value according to the
353 * algorithm of `Array::splice`.
354 */
355 export const splice = createCallableFunction(arrayPrototype.splice);
356
357 /**
358 * Unshifts the provided value according to the algorithm of
359 * `Array::unshift`.
360 */
361 export const unshift = createCallableFunction(arrayPrototype.unshift);
This page took 0.067951 seconds and 3 git commands to generate.