- /**
- * 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;
+/**
+ * Defines an own nonenumerable data property on the provided object
+ * with the provided property key and value.
+ */
+export const defineOwnNonenumerableDataProperty = (O, P, V) =>
+ defineProperty(
+ O,
+ P,
+ assign(create(null), {
+ configurable: true,
+ enumerable: false,
+ value: V,
+ writable: true,
+ }),
+ );
+
+/**
+ * Defines an own property on the provided object on the provided
+ * property key using the provided property descriptor.
+ *
+ * ※ This is effectively an alias for `Object.defineProperty´.
+ */
+export const defineOwnProperty = (O, P, Desc) =>
+ defineProperty(O, P, Desc);
+
+/**
+ * Defines own properties on the provided object using the descriptors
+ * on the enumerable own properties of the provided additional objects.
+ *
+ * ※ This function differs from `Object.defineProperties´ in that it
+ * can take multiple source objects.
+ */
+export const defineOwnProperties = (O, ...sources) => {
+ const { length } = sources;
+ for (let k = 0; k < length; ++k) {
+ // Iterate over each source and define the appropriate properties
+ // on the provided object.
+ defineProperties(O, sources[k]);
+ }
+ return O;
+};
+
+/**
+ * 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.
+ */
+export const deleteOwnProperty = (O, P) => {
+ if (type(O) !== "object") {
+ // The provided value is not an object; this is an error.
+ throw new TypeError(
+ `${PISCĒS}: Tried to set property but provided value was not an object: ${V}`,
+ );
+ } else if (!deleteProperty(O, P)) {
+ // The provided property could not be deleted on the provided
+ // value; this is an error.
+ throw new TypeError(
+ `${PISCĒS}: Tried to delete property from object but [[Delete]] returned false: ${P}`,
+ );
+ } else {
+ // The provided property was successfully deleted.
+ //
+ // Return the provided value.
+ 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.
+ *
+ * ※ This is effectively an alias for `Object.freeze´.
+ */
+export const freeze = (O) => objectFreeze(O);
+
+/**
+ * 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.
+ */
+export const 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;
+ const copy = create(
+ species == null || !("prototype" in species)
+ ? null
+ : species.prototype,
+ );
+ const keys = ownKeys(O);
+ for (let k = 0; k < keys.length; ++k) {
+ // Iterate over each key and define the appropriate value on the
+ // result.
+ const P = keys[k];
+ const Desc = getOwnPropertyDescriptor(O, P);
+ if (Desc.enumerable) {
+ // P is an enumerable property.
+ defineProperty(
+ copy,
+ P,
+ assign(
+ create(null),
+ isAccessorDescriptor(Desc)
+ ? {
+ configurable: false,
+ enumerable: true,
+ get: Desc.get,
+ set: Desc.set,
+ }
+ : {
+ configurable: false,
+ enumerable: true,
+ value: Desc.value,
+ writable: false,
+ },
+ ),
+ );