+ * ※ This is effectively an alias for `Object.defineProperty`.
+ */
+export const defineOwnProperty = createArrowFunction(
+ Object.defineProperty,
+ { name: "defineOwnProperty" },
+);
+
+export const {
+ /**
+ * Defines own properties on the provided object using the
+ * descriptors on the enumerable own properties of the provided
+ * additional objects.
+ *
+ * ※ This differs from `Object.defineProperties` in that it can take
+ * multiple source objects.
+ */
+ defineOwnProperties,
+
+ /**
+ * 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,
+
+ /**
+ * Returns whether the provided object is frozen.
+ *
+ * ※ This function returns false for nonobjects.
+ *
+ * ※ This is effectively an alias for `!Object.isFrozen`.
+ */
+ isUnfrozenObject,
+
+ /**
+ * Returns whether the provided object is sealed.
+ *
+ * ※ This function returns false for nonobjects.
+ *
+ * ※ This is effectively an alias for `!Object.isSealed`.
+ */
+ isUnsealedObject,
+
+ /**
+ * Sets the prototype of the provided object to the provided value
+ * and returns the object.
+ *
+ * ※ This is effectively an alias for `Object.setPrototypeOf`.
+ */
+ setPrototype,
+
+ /**
+ * Returns the provided value converted to an object.
+ *
+ * Existing objects are returned with no modification.
+ *
+ * ☡ This function throws if its argument is null or undefined.
+ */
+ 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: $ },
+ });
+
+ 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 {
+ /**
+ * Removes the provided property key from the provided object and
+ * returns the object.
+ *
+ * ※ This function differs from `Reflect.deleteProperty` and the
+ * `delete` operator in that it throws if the deletion is
+ * unsuccessful.
+ *
+ * ☡ This function throws if the first argument is not an object.
+ */
+ deleteOwnProperty,
+
+ /**
+ * Returns an array of property keys on the provided object.
+ *
+ * ※ This is effectively an alias for `Reflect.ownKeys`, except that
+ * it does not require that the argument be an object.
+ */
+ getOwnPropertyKeys,
+
+ /**
+ * Returns the value of the provided property key on the provided
+ * object.
+ *
+ * ※ This is effectively an alias for `Reflect.get`, except that it
+ * does not require that the argument be an object.
+ */
+ getPropertyValue,
+
+ /**
+ * Returns whether the provided property key exists on the provided
+ * object.
+ *
+ * ※ This is effectively an alias for `Reflect.has`, except that it
+ * does not require that the argument be an object.
+ *
+ * ※ This includes properties present on the prototype chain.
+ */
+ hasProperty,
+
+ /**
+ * Sets the provided property key to the provided value on the
+ * provided object and returns the object.
+ *
+ * ※ This function differs from `Reflect.set` in that it throws if
+ * the setting is unsuccessful.
+ *
+ * ☡ This function throws if the first argument is not an object.
+ */
+ setPropertyValue,
+} = (() => {
+ const { deleteProperty, get, has, ownKeys, set } = Reflect;
+
+ return {
+ deleteOwnProperty: (O, P) => {
+ if (type(O) !== "object") {
+ throw new TypeError(
+ `Piscēs: Tried to set property but provided value was not an object: ${V}`,
+ );
+ } else if (!deleteProperty(O, P)) {
+ throw new TypeError(
+ `Piscēs: Tried to delete property from object but [[Delete]] returned false: ${P}`,
+ );
+ } else {
+ return O;
+ }
+ },
+ getOwnPropertyKeys: (O) => ownKeys(toObject(O)),
+ getPropertyValue: (O, P, Receiver = O) =>
+ get(toObject(O), P, Receiver),
+ hasProperty: (O, P) => has(toObject(O), P),
+ setPropertyValue: (O, P, V, Receiver = O) => {
+ if (type(O) !== "object") {
+ throw new TypeError(
+ `Piscēs: Tried to set property but provided value was not an object: ${V}`,
+ );
+ } else if (!set(O, P, V, Receiver)) {
+ throw new TypeError(
+ `Piscēs: Tried to set property on object but [[Set]] returned false: ${P}`,
+ );
+ } else {
+ return O;
+ }
+ },
+ };
+})();
+
+/**
+ * Marks the provided object as non·extensible and marks all its
+ * properties as nonconfigurable and (if data properties) nonwritable,
+ * and returns the object.