]> Lady’s Gitweb - Pisces/blob - object.js
Define names and lengths for iterator functions
[Pisces] / object.js
1 // SPDX-FileCopyrightText: 2022, 2023, 2025 Lady <https://www.ladys.computer/about/#lady>
2 // SPDX-License-Identifier: MPL-2.0
3 /**
4 * ⁌ ♓🧩 Piscēs ∷ object.js
5 *
6 * Copyright © 2022–2023, 2025 Lady [@ Ladys Computer].
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
11 */
12
13 import {
14 IS_CONCAT_SPREADABLE,
15 isAccessorDescriptor,
16 isDataDescriptor,
17 SPECIES,
18 toFunctionName,
19 toLength,
20 type,
21 UNDEFINED,
22 } from "./value.js";
23
24 const PISCĒS = "♓🧩 Piscēs";
25
26 const createArray = Array;
27 const { isArray } = Array;
28 const object = Object;
29 const {
30 assign,
31 create,
32 defineProperty,
33 defineProperties,
34 entries,
35 freeze: objectFreeze,
36 fromEntries,
37 getOwnPropertyDescriptor: objectGetOwnPropertyDescriptor,
38 getOwnPropertyNames,
39 getOwnPropertySymbols: objectGetOwnPropertySymbols,
40 getPrototypeOf,
41 hasOwn,
42 isExtensible,
43 isFrozen,
44 isSealed,
45 keys,
46 preventExtensions: objectPreventExtensions,
47 seal: objectSeal,
48 setPrototypeOf,
49 values,
50 } = Object;
51 const {
52 apply: call,
53 deleteProperty,
54 defineProperty: reflectDefineProperty,
55 get,
56 getOwnPropertyDescriptor: reflectGetOwnPropertyDescriptor,
57 has,
58 ownKeys,
59 set,
60 setPrototypeOf: reflectSetPrototypeOf,
61 } = Reflect;
62
63 /**
64 * An object whose properties are lazy‐loaded from the methods on the
65 * own properties of the provided object.
66 *
67 * This is useful when you are looking to reference properties on
68 * objects which, due to module dependency graphs, cannot be guaranteed
69 * to have been initialized yet.
70 *
71 * The resulting properties will have the same attributes (regarding
72 * configurability, enumerability, and writability) as the
73 * corresponding properties on the methods object. If a property is
74 * marked as writable, the method will never be called if it is set
75 * before it is gotten. By necessity, the resulting properties are all
76 * configurable before they are accessed for the first time.
77 *
78 * Methods will be called with the resulting object as their this
79 * value.
80 *
81 * `LazyLoader´ objects have the same prototype as the passed methods
82 * object.
83 */
84 export class LazyLoader extends null {
85 /**
86 * Constructs a new `LazyLoader´ object.
87 *
88 * ☡ This function throws if the provided value is not an object.
89 */
90 constructor(loadMethods) {
91 if (type(loadMethods) !== "object") {
92 // The provided value is not an object; this is an error.
93 throw new TypeError(
94 `${PISCĒS}: Cannot construct LazyLoader: Provided argument is not an object: ${loadMethods}.`,
95 );
96 } else {
97 // The provided value is an object.
98 //
99 // Process it and build the result.
100 const result = create(getPrototypeOf(loadMethods));
101 const methodKeys = ownKeys(loadMethods);
102 for (let index = 0; index < methodKeys.length; ++index) {
103 // Iterate over the property keys of the provided object and
104 // define getters and setters appropriately on the result.
105 const methodKey = methodKeys[index];
106 const { configurable, enumerable, writable } =
107 getOwnPropertyDescriptor(loadMethods, methodKey);
108 defineProperty(
109 result,
110 methodKey,
111 assign(create(null), {
112 configurable: true,
113 enumerable,
114 get: defineProperty(
115 () => {
116 const value = call(loadMethods[methodKey], result, []);
117 defineProperty(
118 result,
119 methodKey,
120 assign(create(null), {
121 configurable,
122 enumerable,
123 value,
124 writable,
125 }),
126 );
127 return value;
128 },
129 "name",
130 assign(create(null), {
131 value: toFunctionName(methodKey, "get"),
132 }),
133 ),
134 set: writable
135 ? defineProperty(
136 ($) =>
137 defineProperty(
138 result,
139 methodKey,
140 assign(create(null), {
141 configurable,
142 enumerable,
143 value: $,
144 writable,
145 }),
146 ),
147 "name",
148 assign(create(null), {
149 value: toFunctionName(methodKey, "set"),
150 }),
151 )
152 : UNDEFINED,
153 }),
154 );
155 }
156 return result;
157 }
158 }
159 }
160
161 /**
162 * Defines an own enumerable data property on the provided object with
163 * the provided property key and value.
164 */
165 export const defineOwnDataProperty = (O, P, V) =>
166 defineProperty(
167 O,
168 P,
169 assign(create(null), {
170 configurable: true,
171 enumerable: true,
172 value: V,
173 writable: true,
174 }),
175 );
176
177 /**
178 * Defines an own nonenumerable data property on the provided object
179 * with the provided property key and value.
180 */
181 export const defineOwnNonenumerableDataProperty = (O, P, V) =>
182 defineProperty(
183 O,
184 P,
185 assign(create(null), {
186 configurable: true,
187 enumerable: false,
188 value: V,
189 writable: true,
190 }),
191 );
192
193 /**
194 * Defines an own property on the provided object on the provided
195 * property key using the provided property descriptor.
196 *
197 * ※ This is effectively an alias for `Object.defineProperty´.
198 */
199 export const defineOwnProperty = (O, P, Desc) =>
200 defineProperty(O, P, Desc);
201
202 /**
203 * Defines own properties on the provided object using the descriptors
204 * on the enumerable own properties of the provided additional objects.
205 *
206 * ※ This function differs from `Object.defineProperties´ in that it
207 * can take multiple source objects.
208 */
209 export const defineOwnProperties = (O, ...sources) => {
210 const { length } = sources;
211 for (let k = 0; k < length; ++k) {
212 // Iterate over each source and define the appropriate properties
213 // on the provided object.
214 defineProperties(O, sources[k]);
215 }
216 return O;
217 };
218
219 /**
220 * Removes the provided property key from the provided object and
221 * returns the object.
222 *
223 * ※ This function differs from `Reflect.deleteProperty´ and the
224 * `delete´ operator in that it throws if the deletion is
225 * unsuccessful.
226 *
227 * ☡ This function throws if the first argument is not an object.
228 */
229 export const deleteOwnProperty = (O, P) => {
230 if (type(O) !== "object") {
231 // The provided value is not an object; this is an error.
232 throw new TypeError(
233 `${PISCĒS}: Tried to set property but provided value was not an object: ${V}`,
234 );
235 } else if (!deleteProperty(O, P)) {
236 // The provided property could not be deleted on the provided
237 // value; this is an error.
238 throw new TypeError(
239 `${PISCĒS}: Tried to delete property from object but [[Delete]] returned false: ${P}`,
240 );
241 } else {
242 // The provided property was successfully deleted.
243 //
244 // Return the provided value.
245 return O;
246 }
247 };
248
249 /**
250 * Marks the provided object as non·extensible and marks all its
251 * properties as nonconfigurable and (if data properties) nonwritable,
252 * and returns the object.
253 *
254 * ※ This is effectively an alias for `Object.freeze´.
255 */
256 export const freeze = (O) => objectFreeze(O);
257
258 /**
259 * Returns a new frozen shallow copy of the enumerable own properties
260 * of the provided object, according to the following rules :—
261 *
262 * - For data properties, create a nonconfigurable, nonwritable
263 * property with the same value.
264 *
265 * - For accessor properties, create a nonconfigurable accessor
266 * property with the same getter ⹐and⹑ setter.
267 *
268 * The prototype for the resulting object will be taken from the
269 * `.prototype´ property of the provided constructor, or the
270 * `.prototype´ of the `.constructor´ of the provided object if the
271 * provided constructor is undefined. If the used constructor has a
272 * nonnullish `.[Symbol.species]´, that will be used instead. If the
273 * used constructor or species is nullish or does not have a
274 * `.prototype´ property, the prototype is set to null.
275 *
276 * ※ The prototype of the provided object itself is ignored.
277 */
278 export const frozenCopy = (O, constructor = O?.constructor) => {
279 if (O == null) {
280 // O is null or undefined.
281 throw new TypeError(
282 `${PISCĒS}: Cannot copy properties of null or undefined.`,
283 );
284 } else {
285 // O is not null or undefined.
286 //
287 // (If not provided, the constructor will be the value of getting
288 // the `.constructor´ property of O.)
289 const species = constructor?.[SPECIES] ?? constructor;
290 const copy = create(
291 species == null || !("prototype" in species)
292 ? null
293 : species.prototype,
294 );
295 const keys = ownKeys(O);
296 for (let k = 0; k < keys.length; ++k) {
297 // Iterate over each key and define the appropriate value on the
298 // result.
299 const P = keys[k];
300 const Desc = getOwnPropertyDescriptor(O, P);
301 if (Desc.enumerable) {
302 // P is an enumerable property.
303 defineProperty(
304 copy,
305 P,
306 assign(
307 create(null),
308 isAccessorDescriptor(Desc)
309 ? {
310 configurable: false,
311 enumerable: true,
312 get: Desc.get,
313 set: Desc.set,
314 }
315 : {
316 configurable: false,
317 enumerable: true,
318 value: Desc.value,
319 writable: false,
320 },
321 ),
322 );
323 } else {
324 // P is not an enumerable property.
325 /* do nothing */
326 }
327 }
328 return objectPreventExtensions(copy);
329 }
330 };
331
332 /**
333 * Returns the function on the provided value at the provided property
334 * key.
335 *
336 * ☡ This function throws if the provided property key does not have an
337 * associated value which is either nullish or callable.
338 */
339 export const getMethod = (V, P) => {
340 const func = V[P];
341 if (func == null) {
342 // The value of the provided property is nullish.
343 //
344 // Return undefined.
345 return UNDEFINED;
346 } else if (typeof func !== "function") {
347 // The value of the provided property is not callable; this is an
348 // error.
349 throw new TypeError(`${PISCĒS}: Method not callable: ${P}`);
350 } else {
351 // The value of the provided property is callable.
352 //
353 // Return it.
354 return func;
355 }
356 };
357
358 /**
359 * Returns the property descriptor record for the own property with the
360 * provided property key on the provided value, or null if none exists.
361 *
362 * ※ This is effectively an alias for
363 * `Object.getOwnPropertyDescriptor´, but the return value is a proxied
364 * object with null prototype.
365 */
366 export const getOwnPropertyDescriptor = (O, P) => {
367 const desc = objectGetOwnPropertyDescriptor(O, P);
368 return desc === UNDEFINED
369 ? UNDEFINED
370 : toPropertyDescriptorRecord(desc);
371 };
372
373 /**
374 * Returns the property descriptors for the own properties on the
375 * provided value.
376 *
377 * ※ This is effectively an alias for
378 * `Object.getOwnPropertyDescriptors´, but the values on the resulting
379 * object are proxied objects with null prototypes.
380 */
381 export const getOwnPropertyDescriptors = (O) => {
382 const obj = toObject(O);
383 const keys = ownKeys(obj);
384 const descriptors = {};
385 for (let k = 0; k < keys.length; ++k) {
386 // Iterate over the keys of the provided object and collect its
387 // descriptors.
388 const key = keys[k];
389 defineOwnDataProperty(
390 descriptors,
391 key,
392 getOwnPropertyDescriptor(O, key),
393 );
394 }
395 return descriptors;
396 };
397
398 /**
399 * Returns an array of own property entries on the provided value,
400 * using the provided receiver if given.
401 */
402 export const getOwnPropertyEntries = (O, Receiver = O) => {
403 const obj = toObject(O);
404 const keys = ownKeys(obj);
405 const target = Receiver === UNDEFINED ? obj : toObject(Receiver);
406 const result = createArray(keys.length);
407 for (let k = 0; k < keys.length; ++k) {
408 // Iterate over each key and add the corresponding entry to the
409 // result.
410 const key = keys[k];
411 defineOwnDataProperty(
412 result,
413 k,
414 [key, getOwnPropertyValue(obj, keys[k], target)],
415 );
416 }
417 return result;
418 };
419
420 /**
421 * Returns an array of own property keys on the provided value.
422 *
423 * ※ This is effectively an alias for `Reflect.ownKeys´, except that
424 * it does not require that the argument be an object.
425 */
426 export const getOwnPropertyKeys = (O) => ownKeys(toObject(O));
427
428 /**
429 * Returns an array of string‐valued own property keys on the
430 * provided value.
431 *
432 * ☡ This includes both enumerable and non·enumerable properties.
433 *
434 * ※ This is effectively an alias for `Object.getOwnPropertyNames´.
435 */
436 export const getOwnPropertyStrings = (O) => getOwnPropertyNames(O);
437
438 /**
439 * Returns an array of symbol‐valued own property keys on the
440 * provided value.
441 *
442 * ☡ This includes both enumerable and non·enumerable properties.
443 *
444 * ※ This is effectively an alias for
445 * `Object.getOwnPropertySymbols´.
446 */
447 export const getOwnPropertySymbols = (O) =>
448 objectGetOwnPropertySymbols(O);
449
450 /**
451 * Returns the value of the provided own property on the provided
452 * value using the provided receiver, or undefined if the provided
453 * property is not an own property on the provided value.
454 *
455 * ※ If the receiver is not provided, it defaults to the provided
456 * value.
457 */
458 export const getOwnPropertyValue = (O, P, Receiver = UNDEFINED) => {
459 const obj = toObject(O);
460 const desc = getOwnPropertyDescriptor(O, P);
461 if (desc === UNDEFINED) {
462 // The provided property is not an own property on the provided
463 // value.
464 //
465 // Return undefined.
466 return UNDEFINED;
467 }
468 if (isDataDescriptor(desc)) {
469 // The provided property is a data property.
470 //
471 // Return its value.
472 return desc.value;
473 } else {
474 // The provided property is an accessor property.
475 //
476 // Get its value using the appropriate receiver.
477 const target = Receiver === UNDEFINED ? obj : toObject(Receiver);
478 return call(desc.get, target, []);
479 }
480 };
481
482 /**
483 * Returns an array of own property values on the provided value, using
484 * the provided receiver if given.
485 */
486 export const getOwnPropertyValues = (O, Receiver = O) => {
487 const obj = toObject(O);
488 const keys = ownKeys(obj);
489 const target = Receiver === UNDEFINED ? obj : toObject(Receiver);
490 const result = createArray(keys.length);
491 for (let k = 0; k < keys.length; ++k) {
492 // Iterate over each key and collect the values.
493 defineOwnDataProperty(
494 result,
495 k,
496 getOwnPropertyValue(obj, keys[k], target),
497 );
498 }
499 return result;
500 };
501
502 /**
503 * Returns the value of the provided property key on the provided
504 * value.
505 *
506 * ※ This is effectively an alias for `Reflect.get´, except that it
507 * does not require that the argument be an object.
508 */
509 export const getPropertyValue = (O, P, Receiver = O) =>
510 get(toObject(O), P, Receiver);
511
512 /**
513 * Returns the prototype of the provided value.
514 *
515 * ※ This is effectively an alias for `Object.getPrototypeOf´.
516 */
517 export const getPrototype = (O) => getPrototypeOf(O);
518
519 /**
520 * Returns whether the provided value has an own property with the
521 * provided property key.
522 *
523 * ※ This is effectively an alias for `Object.hasOwn´.
524 */
525 export const hasOwnProperty = (O, P) => hasOwn(O, P);
526
527 /**
528 * Returns whether the provided property key exists on the provided
529 * value.
530 *
531 * ※ This is effectively an alias for `Reflect.has´, except that it
532 * does not require that the argument be an object.
533 *
534 * ※ This includes properties present on the prototype chain.
535 */
536 export const hasProperty = (O, P) => has(toObject(O), P);
537
538 /** Returns whether the provided value is an arraylike object. */
539 export const isArraylikeObject = ($) => {
540 if (type($) !== "object") {
541 // The provided value is not an object.
542 return false;
543 } else {
544 // The provided value is an object.
545 try {
546 // Try to get the length and return true.
547 //
548 // ※ If this throws, the object is not arraylike.
549 lengthOfArraylike($);
550 return true;
551 } catch {
552 // Getting the length failed; return false.
553 return false;
554 }
555 }
556 };
557
558 /**
559 * Returns whether the provided value is spreadable during array
560 * concatenation.
561 *
562 * This is also used to determine which things should be treated as
563 * collections.
564 */
565 export const isConcatSpreadableObject = ($) => {
566 if (type($) !== "object") {
567 // The provided value is not an object.
568 return false;
569 } else {
570 // The provided value is an object.
571 const spreadable = $[IS_CONCAT_SPREADABLE];
572 return spreadable !== UNDEFINED ? !!spreadable : isArray($);
573 }
574 };
575
576 /**
577 * Returns whether the provided value is an extensible object.
578 *
579 * ※ This function returns false for nonobjects.
580 *
581 * ※ This is effectively an alias for `Object.isExtensible´.
582 */
583 export const isExtensibleObject = (O) => isExtensible(O);
584
585 export const {
586 /**
587 * Returns whether the provided value is a property descriptor record
588 * as created by `toPropertyDescriptor´.
589 *
590 * ※ This function is provided to enable inspection of whether an
591 * object uses the ♓🧩 Piscēs property descriptor record proxy
592 * implementation, not as a general test of whether an object
593 * satisfies the requirements for property descriptors. In most
594 * cases, a more specific test, like `isAccessorDescriptor´,
595 * `isDataDescriptor´, or `isGenericDescriptor´, is preferrable.
596 */
597 isPropertyDescriptorRecord,
598
599 /**
600 * Converts the provided value to a property descriptor record.
601 *
602 * ※ The prototype of a property descriptor record is always `null´.
603 *
604 * ※ Actually constructing a property descriptor object using this
605 * class is only necessary if you need strict guarantees about the
606 * types of its properties; the resulting object is proxied to ensure
607 * the types match what one would expect from composing
608 * `FromPropertyDescriptor´ and `ToPropertyDescriptor´ in the
609 * Ecmascript specification.
610 */
611 toPropertyDescriptorRecord,
612 } = (() => {
613 const proxyConstructor = Proxy;
614 const { add: weakSetAdd, has: weakSetHas } = WeakSet.prototype;
615 const propertyDescriptorRecords = new WeakSet();
616 const coercePropertyDescriptorValue = (P, V) => {
617 switch (P) {
618 case "configurable":
619 case "enumerable":
620 case "writable":
621 return !!V;
622 case "value":
623 return V;
624 case "get":
625 if (V !== UNDEFINED && typeof V !== "function") {
626 // The provided value is not callable; this is an error.
627 throw new TypeError(
628 `${PISCĒS}: Getters must be callable.`,
629 );
630 } else {
631 // The provided value is callable.
632 return V;
633 }
634 case "set":
635 if (V !== UNDEFINED && typeof V !== "function") {
636 // The provided value is not callable; this is an error.
637 throw new TypeError(
638 `${PISCĒS}: Setters must be callable.`,
639 );
640 } else {
641 // The provided value is callable.
642 return V;
643 }
644 default:
645 return V;
646 }
647 };
648 const propertyDescriptorProxyHandler = objectFreeze(
649 assign(
650 create(null),
651 {
652 defineProperty(O, P, Desc) {
653 if (
654 P === "configurable" || P === "enumerable"
655 || P === "writable" || P === "value"
656 || P === "get" || P === "set"
657 ) {
658 // `P´ is a property descriptor attribute.
659 const desc = assign(objectCreate(null), Desc);
660 if ("get" in desc || "set" in desc) {
661 // `Desc´ is an accessor property descriptor.
662 throw new TypeError(
663 `${PISCĒS}: Property descriptor attributes must be data properties.`,
664 );
665 } else if ("value" in desc || !(P in O)) {
666 // `Desc´ has a value or `P´ does not already exist on
667 // `O´.
668 desc.value = coercePropertyDescriptorValue(
669 P,
670 desc.value,
671 );
672 } else {
673 // `Desc´ is not an accessor property descriptor and has
674 // no value, but an existing value is present on `O´.
675 /* do nothing */
676 }
677 const isAccessorDescriptor = "get" === P || "set" === P
678 || "get" in O || "set" in O;
679 const isDataDescriptor = "value" === P
680 || "writable" === P
681 || "value" in O || "writable" in O;
682 if (isAccessorDescriptor && isDataDescriptor) {
683 // Both accessor and data attributes will be present on
684 // `O´ after defining `P´; this is an error.
685 throw new TypeError(
686 `${PISCĒS}: Property descriptors cannot specify both accessor and data attributes.`,
687 );
688 } else {
689 // `P´ can be safely defined on `O´.
690 return reflectDefineProperty(O, P, desc);
691 }
692 } else {
693 // `P´ is not a property descriptor attribute.
694 return reflectDefineProperty(O, P, Desc);
695 }
696 },
697 setPrototypeOf(O, V) {
698 if (V !== null) {
699 // `V´ is not the property descriptor prototype.
700 return false;
701 } else {
702 // `V´ is the property descriptor prototype.
703 return reflectSetPrototypeOf(O, V);
704 }
705 },
706 },
707 ),
708 );
709
710 return {
711 isPropertyDescriptorRecord: ($) =>
712 call(weakSetHas, propertyDescriptorRecords, [$]),
713 toPropertyDescriptorRecord: (Obj) => {
714 if (type(Obj) !== "object") {
715 // The provided value is not an object; this is an error.
716 throw new TypeError(
717 `${PISCĒS}: Cannot convert primitive to property descriptor: ${O}.`,
718 );
719 } else {
720 // The provided value is an object.
721 const desc = create(null);
722 if ("enumerable" in Obj) {
723 // An enumerable property is specified.
724 defineOwnDataProperty(desc, "enumerable", !!Obj.enumerable);
725 } else {
726 // An enumerable property is not specified.
727 /* do nothing */
728 }
729 if ("configurable" in Obj) {
730 // A configurable property is specified.
731 defineOwnDataProperty(
732 desc,
733 "configurable",
734 !!Obj.configurable,
735 );
736 } else {
737 // A configurable property is not specified.
738 /* do nothing */
739 }
740 if ("value" in Obj) {
741 // A value property is specified.
742 defineOwnDataProperty(desc, "value", Obj.value);
743 } else {
744 // A value property is not specified.
745 /* do nothing */
746 }
747 if ("writable" in Obj) {
748 // A writable property is specified.
749 defineOwnDataProperty(desc, "writable", !!Obj.writable);
750 } else {
751 // A writable property is not specified.
752 /* do nothing */
753 }
754 if ("get" in Obj) {
755 // A get property is specified.
756 const getter = Obj.get;
757 if (getter !== UNDEFINED && typeof getter !== "function") {
758 // The getter is not callable; this is an error.
759 throw new TypeError(
760 `${PISCĒS}: Getters must be callable.`,
761 );
762 } else {
763 // The getter is callable.
764 defineOwnDataProperty(desc, "get", Obj.get);
765 }
766 } else {
767 // A get property is not specified.
768 /* do nothing */
769 }
770 if ("set" in Obj) {
771 // A set property is specified.
772 const setter = Obj.set;
773 if (setter !== UNDEFINED && typeof setter !== "function") {
774 // The setter is not callable; this is an error.
775 throw new TypeError(
776 `${PISCĒS}: Setters must be callable.`,
777 );
778 } else {
779 // The setter is callable.
780 defineOwnDataProperty(desc, "set", Obj.set);
781 }
782 } else {
783 // A set property is not specified.
784 /* do nothing */
785 }
786 if (
787 ("get" in desc || "set" in desc)
788 && ("value" in desc || "writable" in desc)
789 ) {
790 // Both accessor and data attributes have been defined; this
791 // is an error.
792 throw new TypeError(
793 `${PISCĒS}: Property descriptors cannot specify both accessor and data attributes.`,
794 );
795 } else {
796 // The property descriptor is valid.
797 const record = new proxyConstructor(
798 desc,
799 propertyDescriptorProxyHandler,
800 );
801 call(weakSetAdd, propertyDescriptorRecords, [record]);
802 return record;
803 }
804 }
805 },
806 };
807 })();
808
809 /**
810 * Returns whether the provided value is an unfrozen object.
811 *
812 * ※ This function returns false for nonobjects.
813 *
814 * ※ This is effectively an alias for `!Object.isFrozen´.
815 */
816 export const isUnfrozenObject = (O) => !isFrozen(O);
817
818 /**
819 * Returns whether the provided value is an unsealed object.
820 *
821 * ※ This function returns false for nonobjects.
822 *
823 * ※ This is effectively an alias for `!Object.isSealed´.
824 */
825 export const isUnsealedObject = (O) => !isSealed(O);
826
827 /**
828 * Returns the length of the provided arraylike value.
829 *
830 * This can produce larger lengths than can actually be stored in
831 * arrays, because no such restrictions exist on arraylike methods.
832 *
833 * ☡ This function throws if the provided value is not arraylike.
834 */
835 export const lengthOfArraylike = ({ length }) => toLength(length);
836
837 /**
838 * Returns an array of key~value pairs for the enumerable,
839 * string‐valued property keys on the provided value.
840 *
841 * ※ This is effectively an alias for `Object.entries´.
842 */
843 export const namedEntries = (O) => entries(O);
844
845 /**
846 * Returns an array of the enumerable, string‐valued property keys on
847 * the provided value.
848 *
849 * ※ This is effectively an alias for `Object.keys´.
850 */
851 export const namedKeys = (O) => keys(O);
852
853 /**
854 * Returns an array of property values for the enumerable,
855 * string‐valued property keys on the provided value.
856 *
857 * ※ This is effectively an alias for `Object.values´.
858 */
859 export const namedValues = (O) => values(O);
860
861 /**
862 * Returns a new object with the provided prototype and property
863 * descriptors.
864 *
865 * ※ This is effectively an alias for `Object.create´.
866 */
867 export const objectCreate = (O, Properties) => create(O, Properties);
868
869 /**
870 * Returns a new object with property keys and values from the provided
871 * iterable value.
872 *
873 * ※ This is effectively an alias for `Object.fromEntries´.
874 */
875 export const objectFromEntries = (iterable) => fromEntries(iterable);
876
877 /**
878 * Marks the provided object as non·extensible, and returns the
879 * object.
880 *
881 * ※ This is effectively an alias for `Object.preventExtensions´.
882 */
883 export const preventExtensions = (O) => objectPreventExtensions(O);
884
885 /**
886 * Marks the provided object as non·extensible and marks all its
887 * properties as nonconfigurable, and returns the object.
888 *
889 * ※ This is effectively an alias for `Object.seal´.
890 */
891 export const seal = (O) => objectSeal(O);
892
893 /**
894 * Sets the provided property key to the provided value on the provided
895 * object and returns the object.
896 *
897 * ※ This function differs from `Reflect.set´ in that it throws if the
898 * setting is unsuccessful.
899 *
900 * ☡ This function throws if the first argument is not an object.
901 */
902 export const setPropertyValue = (O, P, V, Receiver = O) => {
903 if (type(O) !== "object") {
904 // The provided value is not an object; this is an error.
905 throw new TypeError(
906 `${PISCĒS}: Tried to set property but provided value was not an object: ${V}`,
907 );
908 } else if (!set(O, P, V, Receiver)) {
909 // Setting the property fails; this is an error.
910 throw new TypeError(
911 `${PISCĒS}: Tried to set property on object but [[Set]] returned false: ${P}`,
912 );
913 } else {
914 // The property was successfully set.
915 //
916 // Return the provided object.
917 return O;
918 }
919 };
920
921 /**
922 * Sets the values of the enumerable own properties of the provided
923 * additional objects on the provided values.
924 *
925 * ※ This is effectively an alias for `Object.assign´.
926 */
927 export const setPropertyValues = (target, source, ...sources) => {
928 const to = toObject(target);
929 for (let i = -1; i < sources.length; ++i) {
930 // Iterate over each source and set the appropriate property
931 // values.
932 const nextSource = i === -1 ? source : sources[i];
933 if (nextSource != null) {
934 // The current source is not nullish.
935 //
936 // Handle its own properties.
937 const from = toObject(nextSource);
938 const keys = ownKeys(from);
939 for (let k = 0; k < keys.length; ++k) {
940 // Iterate over each key in the current source and set it in
941 // the target object if it is enumerable.
942 const nextKey = keys[k];
943 const desc = reflectGetOwnPropertyDescriptor(from, nextKey);
944 if (desc !== UNDEFINED && desc.enumerable) {
945 // The current key is present and enumerable.
946 //
947 // Set it to its corresponding value.
948 const propValue = from[nextKey];
949 to[nextKey] = propValue;
950 } else {
951 // The current key is not present or not enumerable.
952 /* do nothing */
953 }
954 }
955 } else {
956 // The current source is nullish.
957 /* do nothing */
958 }
959 }
960 return to;
961 };
962
963 /**
964 * Sets the prototype of the provided object to the provided value and
965 * returns the object.
966 *
967 * ※ This is effectively an alias for `Object.setPrototypeOf´, but it
968 * won¦t throw when setting the prototype of a primitive to its current
969 * value.
970 */
971 export const setPrototype = (O, proto) => {
972 const obj = toObject(O);
973 if (O === obj) {
974 // The provided value is an object.
975 //
976 // Set its prototype normally.
977 return setPrototypeOf(O, proto);
978 } else {
979 // The provided value is not an object.
980 //
981 // Attempt to set the prototype on a coerced version with
982 // extensions prevented, then return the provided value.
983 //
984 // ☡ This will throw if the given prototype does not match the
985 // existing one on the coerced object.
986 setPrototypeOf(objectPreventExtensions(obj), proto);
987 return O;
988 }
989 };
990
991 /**
992 * Returns the provided value converted to an object.
993 *
994 * Existing objects are returned with no modification.
995 *
996 * ☡ This function throws if its argument is null or undefined.
997 */
998 export const toObject = ($) => {
999 if ($ == null) {
1000 // The provided value is nullish; this is an error.
1001 throw new TypeError(
1002 `${PISCĒS}: Cannot convert ${$} into an object.`,
1003 );
1004 } else {
1005 // The provided value is not nullish.
1006 //
1007 // Coerce it to an object.
1008 return object($);
1009 }
1010 };
This page took 0.859157 seconds and 5 git commands to generate.