]> Lady’s Gitweb - Pisces/blobdiff - object.js
De‐classify property descriptors; move to value.js
[Pisces] / object.js
index a4037951fcd77fa746e8aabe23a974948e29ed9a..aa3538d28cf821d91c72f16244db4668f6f3fda7 100644 (file)
--- a/object.js
+++ b/object.js
@@ -7,8 +7,16 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
 
-import { bind, call } from "./function.js";
-import { ITERATOR, SPECIES, toPrimitive, type } from "./value.js";
+import { bind, call, createArrowFunction } from "./function.js";
+import {
+  IS_CONCAT_SPREADABLE,
+  ITERATOR,
+  SPECIES,
+  toFunctionName,
+  toLength,
+  toPrimitive,
+  type,
+} from "./value.js";
 
 /**
  * An object whose properties are lazy‐loaded from the methods on the
@@ -39,37 +47,50 @@ export class LazyLoader extends null {
    */
   constructor(loadMethods) {
     if (type(loadMethods) !== "object") {
+      // The provided value is not an object; throw an error.
       throw new TypeError(
         `Piscēs: Cannot construct LazyLoader: Provided argument is not an object: ${loadMethods}.`,
       );
     } else {
+      // The provided value is an object; process it and build the
+      // result.
       const result = objectCreate(getPrototype(loadMethods));
       const methodKeys = getOwnPropertyKeys(loadMethods);
       for (let index = 0; index < methodKeys.length; ++index) {
+        // Iterate over the property keys of the provided object and
+        // define getters and setters appropriately on the result.
         const methodKey = methodKeys[index];
         const { configurable, enumerable, writable } =
           getOwnPropertyDescriptor(loadMethods, methodKey);
         defineOwnProperty(result, methodKey, {
           configurable: true,
           enumerable,
-          get: () => {
-            const value = call(loadMethods[methodKey], result, []);
-            defineOwnProperty(result, methodKey, {
-              configurable,
-              enumerable,
-              value,
-              writable,
-            });
-            return value;
-          },
-          set: writable
-            ? ($) =>
+          get: defineOwnProperty(
+            () => {
+              const value = call(loadMethods[methodKey], result, []);
               defineOwnProperty(result, methodKey, {
                 configurable,
                 enumerable,
-                value: $,
+                value,
                 writable,
-              })
+              });
+              return value;
+            },
+            "name",
+            { value: toFunctionName(methodKey, "get") },
+          ),
+          set: writable
+            ? defineOwnProperty(
+              ($) =>
+                defineOwnProperty(result, methodKey, {
+                  configurable,
+                  enumerable,
+                  value: $,
+                  writable,
+                }),
+              "name",
+              { value: toFunctionName(methodKey, "set") },
+            )
             : void {},
         });
       }
@@ -79,315 +100,15 @@ export class LazyLoader extends null {
 }
 
 /**
- * A property descriptor object.
+ * Defines an own property on the provided object on the provided
+ * property key using the provided property descriptor.
  *
- * Actually constructing a property descriptor object using this class
- * is only necessary if you need strict guarantees about the types of
- * its properties; the resulting object is proxied to ensure the types
- * match what one would expect from composing FromPropertyDescriptor
- * and ToPropertyDescriptor in the Ecmascript specification.
- *
- * Otherwise, the instance properties and methods are generic.
+ * ※ This is effectively an alias for `Object.defineProperty`.
  */
-export const { PropertyDescriptor } = (() => {
-  class PropertyDescriptor extends null {
-    /**
-     * Constructs a new property descriptor object from the provided
-     * object.
-     *
-     * The resulting object is proxied to enforce types (for example,
-     * its `.enumerable` property, if defined, will always be a
-     * boolean).
-     */
-    constructor(O) {
-      if (type(O) !== "object") {
-        // The provided value is not an object.
-        throw new TypeError(
-          `Piscēs: Cannot convert primitive to property descriptor: ${O}.`,
-        );
-      } else {
-        // The provided value is an object.
-        const desc = objectCreate(propertyDescriptorPrototype);
-        if ("enumerable" in O) {
-          // An enumerable property is specified.
-          desc.enumerable = !!O.enumerable;
-        } else {
-          // An enumerable property is not specified.
-          /* do nothing */
-        }
-        if ("configurable" in O) {
-          // A configurable property is specified.
-          desc.configurable = !!O.configurable;
-        } else {
-          // A configurable property is not specified.
-          /* do nothing */
-        }
-        if ("value" in O) {
-          // A value property is specified.
-          desc.value = O.value;
-        } else {
-          // A value property is not specified.
-          /* do nothing */
-        }
-        if ("writable" in O) {
-          // A writable property is specified.
-          desc.writable = !!O.writable;
-        } else {
-          // A writable property is not specified.
-          /* do nothing */
-        }
-        if ("get" in O) {
-          // A get property is specified.
-          const getter = O.get;
-          if (getter !== undefined && typeof getter !== "function") {
-            // The getter is not callable.
-            throw new TypeError("Piscēs: Getters must be callable.");
-          } else {
-            // The getter is callable.
-            desc.get = getter;
-          }
-        } else {
-          // A get property is not specified.
-          /* do nothing */
-        }
-        if ("set" in O) {
-          // A set property is specified.
-          const setter = O.set;
-          if (setter !== undefined && typeof setter !== "function") {
-            // The setter is not callable.
-            throw new TypeError("Piscēs: Setters must be callable.");
-          } else {
-            // The setter is callable.
-            desc.set = setter;
-          }
-        } else {
-          // A set property is not specified.
-          /* do nothing */
-        }
-        if (
-          ("get" in desc || "set" in desc) &&
-          ("value" in desc || "writable" in desc)
-        ) {
-          // Both accessor and data attributes have been defined.
-          throw new TypeError(
-            "Piscēs: Property descriptors cannot specify both accessor and data attributes.",
-          );
-        } else {
-          // The property descriptor is valid.
-          return new Proxy(desc, propertyDescriptorProxyHandler);
-        }
-      }
-    }
-
-    /**
-     * Completes this property descriptor by setting missing values to
-     * their defaults.
-     *
-     * This method modifies this object and returns undefined.
-     */
-    complete() {
-      if (this !== undefined && !("get" in this || "set" in this)) {
-        // This is a generic or data descriptor.
-        if (!("value" in this)) {
-          // `value` is not defined on this.
-          this.value = undefined;
-        } else {
-          // `value` is already defined on this.
-          /* do nothing */
-        }
-        if (!("writable" in this)) {
-          // `writable` is not defined on this.
-          this.writable = false;
-        } else {
-          // `writable` is already defined on this.
-          /* do nothing */
-        }
-      } else {
-        // This is not a generic or data descriptor.
-        if (!("get" in this)) {
-          // `get` is not defined on this.
-          this.get = undefined;
-        } else {
-          // `get` is already defined on this.
-          /* do nothing */
-        }
-        if (!("set" in this)) {
-          // `set` is not defined on this.
-          this.set = undefined;
-        } else {
-          // `set` is already defined on this.
-          /* do nothing */
-        }
-      }
-      if (!("enumerable" in this)) {
-        // `enumerable` is not defined on this.
-        this.enumerable = false;
-      } else {
-        // `enumerable` is already defined on this.
-        /* do nothing */
-      }
-      if (!("configurable" in this)) {
-        // `configurable` is not defined on this.
-        this.configurable = false;
-      } else {
-        // `configurable` is already defined on this.
-        /* do nothing */
-      }
-    }
-
-    /** Gets whether this is an accessor descrtiptor. */
-    get isAccessorDescriptor() {
-      return this !== undefined && ("get" in this || "set" in this);
-    }
-
-    /** Gets whether this is a data descrtiptor. */
-    get isDataDescriptor() {
-      return this !== undefined &&
-        ("value" in this || "writable" in this);
-    }
-
-    /** Gets whether this is a fully‐populated property descriptor. */
-    get isFullyPopulated() {
-      return this !== undefined &&
-        ("value" in this && "writable" in this ||
-          "get" in this && "set" in this) &&
-        "enumerable" in this && "configurable" in this;
-    }
-
-    /**
-     * Gets whether this is a generic (not accessor or data)
-     * descrtiptor.
-     */
-    get isGenericDescriptor() {
-      return this !== undefined &&
-        !("get" in this || "set" in this || "value" in this ||
-          "writable" in this);
-    }
-  }
-
-  const coercePropertyDescriptorValue = (P, V) => {
-    switch (P) {
-      case "configurable":
-      case "enumerable":
-      case "writable":
-        return !!V;
-      case "value":
-        return V;
-      case "get":
-        if (V !== undefined && typeof V !== "function") {
-          throw new TypeError(
-            "Piscēs: Getters must be callable.",
-          );
-        } else {
-          return V;
-        }
-      case "set":
-        if (V !== undefined && typeof V !== "function") {
-          throw new TypeError(
-            "Piscēs: Setters must be callable.",
-          );
-        } else {
-          return V;
-        }
-      default:
-        return V;
-    }
-  };
-
-  const {
-    prototype: propertyDescriptorPrototype,
-  } = PropertyDescriptor;
-
-  const propertyDescriptorProxyHandler = Object.assign(
-    Object.create(null),
-    {
-      defineProperty(O, P, Desc) {
-        if (
-          P === "configurable" || P === "enumerable" ||
-          P === "writable" || P === "value" ||
-          P === "get" || P === "set"
-        ) {
-          // P is a property descriptor attribute.
-          const desc = new PropertyDescriptor(Desc);
-          if ("get" in desc || "set" in desc) {
-            // Desc is an accessor property descriptor.
-            throw new TypeError(
-              "Piscēs: Property descriptor attributes must be data properties.",
-            );
-          } else if ("value" in desc || !(P in O)) {
-            // Desc has a value or P does not already exist on O.
-            desc.value = coercePropertyDescriptorValue(P, desc.value);
-          } else {
-            // Desc is not an accessor property descriptor and has no
-            // value.
-            /* do nothing */
-          }
-          const isAccessorDescriptor = "get" === P || "set" === P ||
-            "get" in O || "set" in O;
-          const isDataDescriptor = "value" === P || "writable" === P ||
-            "value" in O || "writable" in O;
-          if (isAccessorDescriptor && isDataDescriptor) {
-            // Both accessor and data attributes will be present on O
-            // after defining P.
-            throw new TypeError(
-              "Piscēs: Property descriptors cannot specify both accessor and data attributes.",
-            );
-          } else {
-            // P can be safely defined on O.
-            return defineOwnProperty(O, P, desc);
-          }
-        } else {
-          // P is not a property descriptor attribute.
-          return defineOwnProperty(O, P, Desc);
-        }
-      },
-      set(O, P, V, Receiver) {
-        if (
-          P === "configurable" || P === "enumerable" ||
-          P === "writable" || P === "value" ||
-          P === "get" || P === "set"
-        ) {
-          // P is a property descriptor attribute.
-          const newValue = coercePropertyDescriptorValue(P, V);
-          const isAccessorDescriptor = "get" === P || "set" === P ||
-            "get" in O || "set" in O;
-          const isDataDescriptor = "value" === P || "writable" === P ||
-            "value" in O || "writable" in O;
-          if (isAccessorDescriptor && isDataDescriptor) {
-            // Both accessor and data attributes will be present on O
-            // after defining P.
-            throw new TypeError(
-              "Piscēs: Property descriptors cannot specify both accessor and data attributes.",
-            );
-          } else {
-            // P can be safely defined on O.
-            //
-            // ☡ Receiver will be the *proxied* object, so passing it
-            // through to setPropertyValue here would produce an
-            // infinite loop.
-            //
-            // ☡ This has implications on objects with a proxied
-            // PropertyDescriptor in their prototype.
-            return setPropertyValue(O, P, newValue, O);
-          }
-        } else {
-          return setPropertyValue(O, P, V, Receiver);
-        }
-      },
-      setPrototypeOf(O, V) {
-        if (V !== propertyDescriptorPrototype) {
-          // V is not the property descriptor prototype.
-          return false;
-        } else {
-          // V is the property descriptor prototype.
-          return setPrototype(O, V);
-        }
-      },
-    },
-  );
-
-  return { PropertyDescriptor };
-})();
+export const defineOwnProperty = createArrowFunction(
+  Object.defineProperty,
+  { name: "defineOwnProperty" },
+);
 
 export const {
   /**
@@ -399,183 +120,183 @@ export const {
    * multiple source objects.
    */
   defineOwnProperties,
-} = (() => {
-  const { defineProperties } = Object;
-  const { forEach: arrayForEach } = Array.prototype;
-  return {
-    defineOwnProperties: (O, ...sources) => {
-      call(
-        arrayForEach,
-        sources,
-        [(source) => defineProperties(O, source)],
-      );
-      return O;
-    },
-  };
-})();
-
-export const {
-  /**
-   * Defines an own property on the provided object on the provided
-   * property key using the provided property descriptor.
-   *
-   * ※ This is an alias for `Object.defineProperty`.
-   */
-  defineProperty: defineOwnProperty,
-
-  /**
-   * Marks the provided object as non·extensible and marks all its
-   * properties as nonconfigurable and (if data properties)
-   * nonwritable, and returns the object.
-   *
-   * ※ This is an alias for `Object.freeze`.
-   */
-  freeze,
-
-  /**
-   * Returns the property descriptor for the own property with the
-   * provided property key on the provided object, or null if none
-   * exists.
-   *
-   * ※ This is an alias for `Object.getOwnPropertyDescriptor`.
-   */
-  getOwnPropertyDescriptor,
-
-  /**
-   * Returns the property descriptors for the own properties on the
-   * provided object.
-   *
-   * ※ This is an alias for `Object.getOwnPropertyDescriptors`.
-   */
-  getOwnPropertyDescriptors,
-
-  /**
-   * Returns an array of string‐valued own property keys on the
-   * provided object.
-   *
-   * ☡ This includes both enumerable and non·enumerable properties.
-   *
-   * ※ This is an alias for `Object.getOwnPropertyNames`.
-   */
-  getOwnPropertyNames: getOwnPropertyStrings,
 
   /**
-   * Returns an array of symbol‐valued own property keys on the
-   * provided object.
-   *
-   * ☡ This includes both enumerable and non·enumerable properties.
+   * Returns a new frozen shallow copy of the enumerable own properties
+   * of the provided object, according to the following rules :—
    *
-   * ※ This is an alias for `Object.getOwnPropertySymbols`.
-   */
-  getOwnPropertySymbols,
-
-  /**
-   * Returns the prototype of the provided object.
+   * - For data properties, create a nonconfigurable, nonwritable
+   *   property with the same value.
    *
-   * ※ This is an alias for `Object.getPrototypeOf`.
-   */
-  getPrototypeOf: getPrototype,
-
-  /**
-   * Returns whether the provided object has an own property with the
-   * provided property key.
+   * - For accessor properties, create a nonconfigurable accessor
+   *   property with the same getter *and* setter.
    *
-   * ※ This is an alias for `Object.hasOwn`.
-   */
-  hasOwn: hasOwnProperty,
-
-  /**
-   * Returns whether the provided object is extensible.
+   * The prototype for the resulting object will be taken from the
+   * `.prototype` property of the provided constructor, or the
+   * `.prototype` of the `.constructor` of the provided object if the
+   * provided constructor is undefined. If the used constructor has a
+   * nonnullish `.[Symbol.species]`, that will be used instead. If the
+   * used constructor or species is nullish or does not have a
+   * `.prototype` property, the prototype is set to null.
    *
-   * ※ This is an alias for `Object.isExtensible`.
+   * ※ The prototype of the provided object itself is ignored.
    */
-  isExtensible: isExtensibleObject,
+  frozenCopy,
 
   /**
    * Returns whether the provided object is frozen.
    *
-   * ※ This is an alias for `Object.isFrozen`.
-   */
-  isFrozen: isFrozenObject,
-
-  /**
-   * Returns whether the provided object is sealed.
-   *
-   * ※ This is an alias for `Object.isSealed`.
-   */
-  isSealed: isSealedObject,
-
-  /**
-   * Returns an array of key~value pairs for the enumerable,
-   * string‐valued property keys on the provided object.
-   *
-   * ※ This is an alias for `Object.entries`.
-   */
-  entries: namedEntries,
-
-  /**
-   * Returns an array of the enumerable, string‐valued property keys on
-   * the provided object.
-   *
-   * ※ This is an alias for `Object.keys`.
-   */
-  keys: namedKeys,
-
-  /**
-   * Returns an array of property values for the enumerable,
-   * string‐valued property keys on the provided object.
+   * ※ This function returns false for nonobjects.
    *
-   * ※ This is an alias for `Object.values`.
+   * ※ This is effectively an alias for `!Object.isFrozen`.
    */
-  values: namedValues,
+  isUnfrozenObject,
 
   /**
-   * Returns a new object with the provided prototype and property
-   * descriptors.
+   * Returns whether the provided object is sealed.
    *
-   * ※ This is an alias for `Object.create`.
-   */
-  create: objectCreate,
-
-  /**
-   * Returns a new object with the provided property keys and values.
+   * ※ This function returns false for nonobjects.
    *
-   * ※ This is an alias for `Object.fromEntries`.
+   * ※ This is effectively an alias for `!Object.isSealed`.
    */
-  fromEntries: objectFromEntries,
+  isUnsealedObject,
 
   /**
-   * Marks the provided object as non·extensible, and returns the
-   * object.
+   * Sets the prototype of the provided object to the provided value
+   * and returns the object.
    *
-   * ※ This is an alias for `Object.preventExtensions`.
+   * ※ This is effectively an alias for `Object.setPrototypeOf`.
    */
-  preventExtensions,
+  setPrototype,
 
   /**
-   * Marks the provided object as non·extensible and marks all its
-   * properties as nonconfigurable, and returns the object.
+   * Returns the provided value converted to an object.
    *
-   * ※ This is an alias for `Object.seal`.
-   */
-  seal,
-
-  /**
-   * Sets the values of the enumerable own properties of the provided
-   * additional objects on the provided object.
+   * Existing objects are returned with no modification.
    *
-   * ※ This is an alias for `Object.assign`.
+   * ☡ This function throws if its argument is null or undefined.
    */
-  assign: setPropertyValues,
+  toObject,
+} = (() => {
+  const createObject = Object;
+  const {
+    create,
+    defineProperties,
+    getPrototypeOf,
+    isFrozen,
+    isSealed,
+    setPrototypeOf,
+  } = Object;
+  const {
+    next: generatorIteratorNext,
+  } = getPrototypeOf(function* () {}.prototype);
+  const propertyDescriptorEntryIterablePrototype = {
+    [ITERATOR]() {
+      return {
+        next: bind(generatorIteratorNext, this.generator(), []),
+      };
+    },
+  };
+  const propertyDescriptorEntryIterable = ($) =>
+    create(propertyDescriptorEntryIterablePrototype, {
+      generator: { value: $ },
+    });
 
-  /**
-   * Sets the prototype of the provided object to the provided value
-   * and returns the object.
-   *
-   * ※ This is an alias for `Object.setPrototypeOf`.
-   */
-  setPrototypeOf: setPrototype,
-} = Object;
+  return {
+    defineOwnProperties: (O, ...sources) => {
+      const { length } = sources;
+      for (let index = 0; index < length; ++index) {
+        defineProperties(O, sources[index]);
+      }
+      return O;
+    },
+    frozenCopy: (O, constructor = O?.constructor) => {
+      if (O == null) {
+        // O is null or undefined.
+        throw new TypeError(
+          "Piscēs: Cannot copy properties of null or undefined.",
+        );
+      } else {
+        // O is not null or undefined.
+        //
+        // (If not provided, the constructor will be the value of
+        // getting the `.constructor` property of O.)
+        const species = constructor?.[SPECIES] ?? constructor;
+        return preventExtensions(
+          objectCreate(
+            species == null || !("prototype" in species)
+              ? null
+              : species.prototype,
+            objectFromEntries(
+              propertyDescriptorEntryIterable(function* () {
+                const ownPropertyKeys = getOwnPropertyKeys(O);
+                for (
+                  let i = 0;
+                  i < ownPropertyKeys.length;
+                  ++i
+                ) {
+                  const P = ownPropertyKeys[i];
+                  const Desc = getOwnPropertyDescriptor(O, P);
+                  if (Desc.enumerable) {
+                    // P is an enumerable property.
+                    yield [
+                      P,
+                      "get" in Desc || "set" in Desc
+                        ? {
+                          configurable: false,
+                          enumerable: true,
+                          get: Desc.get,
+                          set: Desc.set,
+                        }
+                        : {
+                          configurable: false,
+                          enumerable: true,
+                          value: Desc.value,
+                          writable: false,
+                        },
+                    ];
+                  } else {
+                    // P is not an enumerable property.
+                    /* do nothing */
+                  }
+                }
+              }),
+            ),
+          ),
+        );
+      }
+    },
+    isUnfrozenObject: (O) => !isFrozen(O),
+    isUnsealedObject: (O) => !isSealed(O),
+    setPrototype: (O, proto) => {
+      const obj = toObject(O);
+      if (O === obj) {
+        // The provided value is an object; set its prototype normally.
+        return setPrototypeOf(O, proto);
+      } else {
+        // The provided value is not an object; attempt to set the
+        // prototype on a coerced version with extensions prevented,
+        // then return the provided value.
+        //
+        // This will throw if the given prototype does not match the
+        // existing one on the coerced object.
+        setPrototypeOf(preventExtensions(obj), proto);
+        return O;
+      }
+    },
+    toObject: ($) => {
+      if ($ == null) {
+        // The provided value is nullish; this is an error.
+        throw new TypeError(
+          `Piscēs: Cannot convert ${$} into an object.`,
+        );
+      } else {
+        // The provided value is not nullish; coerce it to an object.
+        return createObject($);
+      }
+    },
+  };
+})();
 
 export const {
   /**
@@ -665,105 +386,14 @@ export const {
   };
 })();
 
-export const {
-  /**
-   * Returns a new frozen shallow copy of the enumerable own properties
-   * of the provided object, according to the following rules :—
-   *
-   * - For data properties, create a nonconfigurable, nonwritable
-   *   property with the same value.
-   *
-   * - For accessor properties, create a nonconfigurable accessor
-   *   property with the same getter *and* setter.
-   *
-   * The prototype for the resulting object will be taken from the
-   * `.prototype` property of the provided constructor, or the
-   * `.prototype` of the `.constructor` of the provided object if the
-   * provided constructor is undefined. If the used constructor has a
-   * nonnullish `.[Symbol.species]`, that will be used instead. If the
-   * used constructor or species is nullish or does not have a
-   * `.prototype` property, the prototype is set to null.
-   *
-   * ※ The prototype of the provided object itself is ignored.
-   */
-  frozenCopy,
-} = (() => {
-  const {
-    next: generatorIteratorNext,
-  } = getPrototype(function* () {}.prototype);
-  const propertyDescriptorEntryIterablePrototype = {
-    [ITERATOR]() {
-      return {
-        next: bind(generatorIteratorNext, this.generator(), []),
-      };
-    },
-  };
-  return {
-    frozenCopy: (O, constructor = O?.constructor) => {
-      if (O == null) {
-        // O is null or undefined.
-        throw new TypeError(
-          "Piscēs: Cannot copy properties of null or undefined.",
-        );
-      } else {
-        // O is not null or undefined.
-        //
-        // (If not provided, the constructor will be the value of
-        // getting the `.constructor` property of O.)
-        const species = constructor?.[SPECIES] ?? constructor;
-        return preventExtensions(
-          objectCreate(
-            species == null || !("prototype" in species)
-              ? null
-              : species.prototype,
-            objectFromEntries(
-              objectCreate(
-                propertyDescriptorEntryIterablePrototype,
-                {
-                  generator: {
-                    value: function* () {
-                      const ownPropertyKeys = getOwnPropertyKeys(O);
-                      for (
-                        let i = 0;
-                        i < ownPropertyKeys.length;
-                        ++i
-                      ) {
-                        const P = ownPropertyKeys[i];
-                        const Desc = getOwnPropertyDescriptor(O, P);
-                        if (Desc.enumerable) {
-                          // P is an enumerable property.
-                          yield [
-                            P,
-                            "get" in Desc || "set" in Desc
-                              ? {
-                                configurable: false,
-                                enumerable: true,
-                                get: Desc.get,
-                                set: Desc.set,
-                              }
-                              : {
-                                configurable: false,
-                                enumerable: true,
-                                value: Desc.value,
-                                writable: false,
-                              },
-                          ];
-                        } else {
-                          // P is not an enumerable property.
-                          /* do nothing */
-                        }
-                      }
-                    },
-                  },
-                },
-              ),
-            ),
-          ),
-        );
-      }
-    },
-  };
-})();
+/**
+ * Marks the provided object as non·extensible and marks all its
+ * properties as nonconfigurable and (if data properties) nonwritable,
+ * and returns the object.
+ *
+ * ※ This is effectively an alias for `Object.freeze`.
+ */
+export const freeze = createArrowFunction(Object.freeze);
 
 /**
  * Returns the function on the provided value at the provided property
@@ -784,32 +414,219 @@ export const getMethod = (V, P) => {
 };
 
 /**
- * Returns the provided value converted to an object.
+ * Returns the property descriptor for the own property with the
+ * provided property key on the provided object, or null if none
+ * exists.
  *
- * Existing objects are returned with no modification.
+ * ※ This is effectively an alias for
+ * `Object.getOwnPropertyDescriptor`.
+ */
+export const getOwnPropertyDescriptor = createArrowFunction(
+  Object.getOwnPropertyDescriptor,
+);
+
+/**
+ * Returns the property descriptors for the own properties on the
+ * provided object.
+ *
+ * ※ This is effectively an alias for
+ * `Object.getOwnPropertyDescriptors`.
+ */
+export const getOwnPropertyDescriptors = createArrowFunction(
+  Object.getOwnPropertyDescriptors,
+);
+
+/**
+ * Returns an array of string‐valued own property keys on the
+ * provided object.
+ *
+ * ☡ This includes both enumerable and non·enumerable properties.
+ *
+ * ※ This is effectively an alias for `Object.getOwnPropertyNames`.
+ */
+export const getOwnPropertyStrings = createArrowFunction(
+  Object.getOwnPropertyNames,
+  { name: "getOwnPropertyStrings" },
+);
+
+/**
+ * Returns an array of symbol‐valued own property keys on the
+ * provided object.
  *
- * ☡ This function throws if its argument is null or undefined.
+ * ☡ This includes both enumerable and non·enumerable properties.
+ *
+ * ※ This is effectively an alias for
+ * `Object.getOwnPropertySymbols`.
+ */
+export const getOwnPropertySymbols = createArrowFunction(
+  Object.getOwnPropertySymbols,
+);
+
+/**
+ * Returns the prototype of the provided object.
+ *
+ * ※ This is effectively an alias for `Object.getPrototypeOf`.
  */
-export const { toObject } = (() => {
-  const makeObject = Object;
+export const getPrototype = createArrowFunction(
+  Object.getPrototypeOf,
+  { name: "getPrototype" },
+);
+
+/**
+ * Returns whether the provided object has an own property with the
+ * provided property key.
+ *
+ * ※ This is effectively an alias for `Object.hasOwn`.
+ */
+export const hasOwnProperty = createArrowFunction(Object.hasOwn, {
+  name: "hasOwnProperty",
+});
+
+/** Returns whether the provided value is an arraylike object. */
+export const isArraylikeObject = ($) => {
+  if (type($) !== "object") {
+    return false;
+  } else {
+    try {
+      lengthOfArraylike($); // throws if not arraylike
+      return true;
+    } catch {
+      return false;
+    }
+  }
+};
+
+export const {
+  /**
+   * Returns whether the provided value is spreadable during array
+   * concatenation.
+   *
+   * This is also used to determine which things should be treated as
+   * collections.
+   */
+  isConcatSpreadableObject,
+} = (() => {
+  const { isArray } = Array;
+
   return {
-    toObject: ($) => {
-      if ($ == null) {
-        throw new TypeError(
-          `Piscēs: Cannot convert ${$} into an object.`,
-        );
+    isConcatSpreadableObject: ($) => {
+      if (type($) !== "object") {
+        // The provided value is not an object.
+        return false;
       } else {
-        return makeObject($);
+        // The provided value is an object.
+        const spreadable = $[IS_CONCAT_SPREADABLE];
+        return spreadable !== undefined ? !!spreadable : isArray($);
       }
     },
   };
 })();
 
+/**
+ * Returns whether the provided object is extensible.
+ *
+ * ※ This function returns false for nonobjects.
+ *
+ * ※ This is effectively an alias for `Object.isExtensible`.
+ */
+export const isExtensibleObject = createArrowFunction(
+  Object.isExtensible,
+  { name: "isExtensibleObject" },
+);
+
+/**
+ * Returns the length of the provided arraylike value.
+ *
+ * This can produce larger lengths than can actually be stored in
+ * arrays, because no such restrictions exist on arraylike methods.
+ *
+ * ☡ This function throws if the provided value is not arraylike.
+ */
+export const lengthOfArraylike = ({ length }) => toLength(length);
+
+/**
+ * Returns an array of key~value pairs for the enumerable,
+ * string‐valued property keys on the provided object.
+ *
+ * ※ This is effectively an alias for `Object.entries`.
+ */
+export const namedEntries = createArrowFunction(Object.entries, {
+  name: "namedEntries",
+});
+
+/**
+ * Returns an array of the enumerable, string‐valued property keys on
+ * the provided object.
+ *
+ * ※ This is effectively an alias for `Object.keys`.
+ */
+export const namedKeys = createArrowFunction(Object.keys, {
+  name: "namedKeys",
+});
+
+/**
+ * Returns an array of property values for the enumerable,
+ * string‐valued property keys on the provided object.
+ *
+ * ※ This is effectively an alias for `Object.values`.
+ */
+export const namedValues = createArrowFunction(Object.values, {
+  name: "namedValues",
+});
+
+/**
+ * Returns a new object with the provided prototype and property
+ * descriptors.
+ *
+ * ※ This is effectively an alias for `Object.create`.
+ */
+export const objectCreate = createArrowFunction(Object.create, {
+  name: "objectCreate",
+});
+
+/**
+ * Returns a new object with the provided property keys and values.
+ *
+ * ※ This is effectively an alias for `Object.fromEntries`.
+ */
+export const objectFromEntries = createArrowFunction(
+  Object.fromEntries,
+  { name: "objectFromEntries" },
+);
+
+/**
+ * Marks the provided object as non·extensible, and returns the
+ * object.
+ *
+ * ※ This is effectively an alias for `Object.preventExtensions`.
+ */
+export const preventExtensions = createArrowFunction(
+  Object.preventExtensions,
+);
+
+/**
+ * Marks the provided object as non·extensible and marks all its
+ * properties as nonconfigurable, and returns the object.
+ *
+ * ※ This is effectively an alias for `Object.seal`.
+ */
+export const seal = createArrowFunction(Object.seal);
+
+/**
+ * Sets the values of the enumerable own properties of the provided
+ * additional objects on the provided object.
+ *
+ * ※ This is effectively an alias for `Object.assign`.
+ */
+export const setPropertyValues = createArrowFunction(Object.assign, {
+  name: "setPropertyValues",
+});
+
 /**
  * Returns the property key (symbol or string) corresponding to the
  * provided value.
  */
 export const toPropertyKey = ($) => {
   const key = toPrimitive($, "string");
-  return typeof key == "symbol" ? key : `${key}`;
+  return typeof key === "symbol" ? key : `${key}`;
 };
This page took 0.042911 seconds and 4 git commands to generate.