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