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