X-Git-Url: https://git.ladys.computer/Pisces/blobdiff_plain/f6b84c13c5c539dbac4f4b9b530eeec95d683475..e1cb83c479df2a3e4a5e918867a135ff9dde8121:/object.js diff --git a/object.js b/object.js index aa94bc5..d382b31 100644 --- a/object.js +++ b/object.js @@ -1,24 +1,29 @@ -// ♓🌟 Piscēs ∷ object.js -// ==================================================================== -// -// Copyright © 2022–2023 Lady [@ Lady’s Computer]. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at . +// SPDX-FileCopyrightText: 2022, 2023, 2025 Lady +// SPDX-License-Identifier: MPL-2.0 +/** + * ⁌ ♓🧩 Piscēs ∷ object.js + * + * Copyright © 2022–2023, 2025 Lady [@ Ladys Computer]. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . + */ import { IS_CONCAT_SPREADABLE, isAccessorDescriptor, + isDataDescriptor, SPECIES, toFunctionName, toLength, - toPrimitive, - toPropertyDescriptor, type, UNDEFINED, } from "./value.js"; +const PISCĒS = "♓🧩 Piscēs"; + +const createArray = Array; const { isArray } = Array; const object = Object; const { @@ -46,11 +51,13 @@ const { const { apply: call, deleteProperty, + defineProperty: reflectDefineProperty, get, getOwnPropertyDescriptor: reflectGetOwnPropertyDescriptor, has, ownKeys, set, + setPrototypeOf: reflectSetPrototypeOf, } = Reflect; /** @@ -71,24 +78,25 @@ const { * Methods will be called with the resulting object as their this * value. * - * `LazyLoader` objects have the same prototype as the passed methods + * `LazyLoader´ objects have the same prototype as the passed methods * object. */ export class LazyLoader extends null { /** - * Constructs a new `LazyLoader` object. + * Constructs a new `LazyLoader´ object. * * ☡ This function throws if the provided value is not an object. */ constructor(loadMethods) { if (type(loadMethods) !== "object") { - // The provided value is not an object; throw an error. + // The provided value is not an object; this is an error. throw new TypeError( - `Piscēs: Cannot construct LazyLoader: Provided argument is not an object: ${loadMethods}.`, + `${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. + // The provided value is an object. + // + // Process it and build the result. const result = create(getPrototypeOf(loadMethods)); const methodKeys = ownKeys(loadMethods); for (let index = 0; index < methodKeys.length; ++index) { @@ -186,7 +194,7 @@ export const defineOwnNonenumerableDataProperty = (O, P, V) => * 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`. + * ※ This is effectively an alias for `Object.defineProperty´. */ export const defineOwnProperty = (O, P, Desc) => defineProperty(O, P, Desc); @@ -195,12 +203,14 @@ export const defineOwnProperty = (O, P, Desc) => * 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. + * ※ 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; @@ -210,22 +220,28 @@ export const defineOwnProperties = (O, ...sources) => { * 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 + * ※ 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}`, + `${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}`, + `${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; } }; @@ -235,7 +251,7 @@ export const deleteOwnProperty = (O, P) => { * properties as nonconfigurable and (if data properties) nonwritable, * and returns the object. * - * ※ This is effectively an alias for `Object.freeze`. + * ※ This is effectively an alias for `Object.freeze´. */ export const freeze = (O) => objectFreeze(O); @@ -247,15 +263,15 @@ export const freeze = (O) => objectFreeze(O); * property with the same value. * * - For accessor properties, create a nonconfigurable accessor - * property with the same getter *and* setter. + * 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 + * `.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 + * 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. + * `.prototype´ property, the prototype is set to null. * * ※ The prototype of the provided object itself is ignored. */ @@ -263,13 +279,13 @@ 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.", + `${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.) + // the `.constructor´ property of O.) const species = constructor?.[SPECIES] ?? constructor; const copy = create( species == null || !("prototype" in species) @@ -278,6 +294,8 @@ export const frozenCopy = (O, constructor = O?.constructor) => { ); 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) { @@ -316,15 +334,23 @@ export const frozenCopy = (O, constructor = O?.constructor) => { * key. * * ☡ This function throws if the provided property key does not have an - * associated value which is callable. + * associated value which is either nullish or callable. */ export const getMethod = (V, P) => { const func = V[P]; if (func == null) { - return undefined; + // The value of the provided property is nullish. + // + // Return undefined. + return UNDEFINED; } else if (typeof func !== "function") { - throw new TypeError(`Piscēs: Method not callable: ${P}`); + // The value of the provided property is not callable; this is an + // error. + throw new TypeError(`${PISCĒS}: Method not callable: ${P}`); } else { + // The value of the provided property is callable. + // + // Return it. return func; } }; @@ -334,12 +360,14 @@ export const getMethod = (V, P) => { * provided property key on the provided value, or null if none exists. * * ※ This is effectively an alias for - * `Object.getOwnPropertyDescriptor`, but the return value is a proxied + * `Object.getOwnPropertyDescriptor´, but the return value is a proxied * object with null prototype. */ export const getOwnPropertyDescriptor = (O, P) => { const desc = objectGetOwnPropertyDescriptor(O, P); - return desc === UNDEFINED ? UNDEFINED : toPropertyDescriptor(desc); + return desc === UNDEFINED + ? UNDEFINED + : toPropertyDescriptorRecord(desc); }; /** @@ -347,7 +375,7 @@ export const getOwnPropertyDescriptor = (O, P) => { * provided value. * * ※ This is effectively an alias for - * `Object.getOwnPropertyDescriptors`, but the values on the resulting + * `Object.getOwnPropertyDescriptors´, but the values on the resulting * object are proxied objects with null prototypes. */ export const getOwnPropertyDescriptors = (O) => { @@ -355,6 +383,8 @@ export const getOwnPropertyDescriptors = (O) => { const keys = ownKeys(obj); const descriptors = {}; for (let k = 0; k < keys.length; ++k) { + // Iterate over the keys of the provided object and collect its + // descriptors. const key = keys[k]; defineOwnDataProperty( descriptors, @@ -366,9 +396,31 @@ export const getOwnPropertyDescriptors = (O) => { }; /** - * Returns an array of property keys on the provided value. + * Returns an array of own property entries on the provided value, + * using the provided receiver if given. + */ +export const getOwnPropertyEntries = (O, Receiver = O) => { + const obj = toObject(O); + const keys = ownKeys(obj); + const target = Receiver === UNDEFINED ? obj : toObject(Receiver); + const result = createArray(keys.length); + for (let k = 0; k < keys.length; ++k) { + // Iterate over each key and add the corresponding entry to the + // result. + const key = keys[k]; + defineOwnDataProperty( + result, + k, + [key, getOwnPropertyValue(obj, keys[k], target)], + ); + } + return result; +}; + +/** + * Returns an array of own property keys on the provided value. * - * ※ This is effectively an alias for `Reflect.ownKeys`, except that + * ※ This is effectively an alias for `Reflect.ownKeys´, except that * it does not require that the argument be an object. */ export const getOwnPropertyKeys = (O) => ownKeys(toObject(O)); @@ -379,7 +431,7 @@ export const getOwnPropertyKeys = (O) => ownKeys(toObject(O)); * * ☡ This includes both enumerable and non·enumerable properties. * - * ※ This is effectively an alias for `Object.getOwnPropertyNames`. + * ※ This is effectively an alias for `Object.getOwnPropertyNames´. */ export const getOwnPropertyStrings = (O) => getOwnPropertyNames(O); @@ -390,16 +442,68 @@ export const getOwnPropertyStrings = (O) => getOwnPropertyNames(O); * ☡ This includes both enumerable and non·enumerable properties. * * ※ This is effectively an alias for - * `Object.getOwnPropertySymbols`. + * `Object.getOwnPropertySymbols´. */ export const getOwnPropertySymbols = (O) => objectGetOwnPropertySymbols(O); +/** + * Returns the value of the provided own property on the provided + * value using the provided receiver, or undefined if the provided + * property is not an own property on the provided value. + * + * ※ If the receiver is not provided, it defaults to the provided + * value. + */ +export const getOwnPropertyValue = (O, P, Receiver = UNDEFINED) => { + const obj = toObject(O); + const desc = getOwnPropertyDescriptor(O, P); + if (desc === UNDEFINED) { + // The provided property is not an own property on the provided + // value. + // + // Return undefined. + return UNDEFINED; + } + if (isDataDescriptor(desc)) { + // The provided property is a data property. + // + // Return its value. + return desc.value; + } else { + // The provided property is an accessor property. + // + // Get its value using the appropriate receiver. + const target = Receiver === UNDEFINED ? obj : toObject(Receiver); + return call(desc.get, target, []); + } +}; + +/** + * Returns an array of own property values on the provided value, using + * the provided receiver if given. + */ +export const getOwnPropertyValues = (O, Receiver = O) => { + const obj = toObject(O); + const keys = ownKeys(obj); + const target = Receiver === UNDEFINED ? obj : toObject(Receiver); + const result = createArray(keys.length); + for (let k = 0; k < keys.length; ++k) { + // Iterate over each key and collect the values. + defineOwnDataProperty( + result, + k, + getOwnPropertyValue(obj, keys[k], target), + ); + } + return result; +}; + /** * Returns the value of the provided property key on the provided * value. * - * ※ This is effectively an alias for `Reflect.get`, except that it + * ※ This is effectively an alias for `Reflect.get´, except that it * does not require that the argument be an object. */ export const getPropertyValue = (O, P, Receiver = O) => @@ -408,7 +512,7 @@ export const getPropertyValue = (O, P, Receiver = O) => /** * Returns the prototype of the provided value. * - * ※ This is effectively an alias for `Object.getPrototypeOf`. + * ※ This is effectively an alias for `Object.getPrototypeOf´. */ export const getPrototype = (O) => getPrototypeOf(O); @@ -416,7 +520,7 @@ export const getPrototype = (O) => getPrototypeOf(O); * Returns whether the provided value has an own property with the * provided property key. * - * ※ This is effectively an alias for `Object.hasOwn`. + * ※ This is effectively an alias for `Object.hasOwn´. */ export const hasOwnProperty = (O, P) => hasOwn(O, P); @@ -424,7 +528,7 @@ export const hasOwnProperty = (O, P) => hasOwn(O, P); * Returns whether the provided property key exists on the provided * value. * - * ※ This is effectively an alias for `Reflect.has`, except that it + * ※ 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. @@ -434,12 +538,18 @@ export const hasProperty = (O, P) => has(toObject(O), P); /** Returns whether the provided value is an arraylike object. */ export const isArraylikeObject = ($) => { if (type($) !== "object") { + // The provided value is not an object. return false; } else { + // The provided value is an object. try { - lengthOfArraylike($); // throws if not arraylike + // Try to get the length and return true. + // + // ※ If this throws, the object is not arraylike. + lengthOfArraylike($); return true; } catch { + // Getting the length failed; return false. return false; } } @@ -468,16 +578,240 @@ export const isConcatSpreadableObject = ($) => { * * ※ This function returns false for nonobjects. * - * ※ This is effectively an alias for `Object.isExtensible`. + * ※ This is effectively an alias for `Object.isExtensible´. */ export const isExtensibleObject = (O) => isExtensible(O); +export const { + /** + * Returns whether the provided value is a property descriptor record + * as created by `toPropertyDescriptor´. + * + * ※ This function is provided to enable inspection of whether an + * object uses the ♓🧩 Piscēs property descriptor record proxy + * implementation, not as a general test of whether an object + * satisfies the requirements for property descriptors. In most + * cases, a more specific test, like `isAccessorDescriptor´, + * `isDataDescriptor´, or `isGenericDescriptor´, is preferrable. + */ + isPropertyDescriptorRecord, + + /** + * Converts the provided value to a property descriptor record. + * + * ※ The prototype of a property descriptor record is always `null´. + * + * ※ 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. + */ + toPropertyDescriptorRecord, +} = (() => { + const proxyConstructor = Proxy; + const { add: weakSetAdd, has: weakSetHas } = WeakSet.prototype; + const propertyDescriptorRecords = new WeakSet(); + 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") { + // The provided value is not callable; this is an error. + throw new TypeError( + `${PISCĒS}: Getters must be callable.`, + ); + } else { + // The provided value is callable. + return V; + } + case "set": + if (V !== UNDEFINED && typeof V !== "function") { + // The provided value is not callable; this is an error. + throw new TypeError( + `${PISCĒS}: Setters must be callable.`, + ); + } else { + // The provided value is callable. + return V; + } + default: + return V; + } + }; + const propertyDescriptorProxyHandler = objectFreeze( + assign( + 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 = assign(objectCreate(null), 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, but an existing value is present on `O´. + /* 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´; this is an error. + throw new TypeError( + `${PISCĒS}: Property descriptors cannot specify both accessor and data attributes.`, + ); + } else { + // `P´ can be safely defined on `O´. + return reflectDefineProperty(O, P, desc); + } + } else { + // `P´ is not a property descriptor attribute. + return reflectDefineProperty(O, P, Desc); + } + }, + setPrototypeOf(O, V) { + if (V !== null) { + // `V´ is not the property descriptor prototype. + return false; + } else { + // `V´ is the property descriptor prototype. + return reflectSetPrototypeOf(O, V); + } + }, + }, + ), + ); + + return { + isPropertyDescriptorRecord: ($) => + call(weakSetHas, propertyDescriptorRecords, [$]), + toPropertyDescriptorRecord: (Obj) => { + if (type(Obj) !== "object") { + // The provided value is not an object; this is an error. + throw new TypeError( + `${PISCĒS}: Cannot convert primitive to property descriptor: ${O}.`, + ); + } else { + // The provided value is an object. + const desc = create(null); + if ("enumerable" in Obj) { + // An enumerable property is specified. + defineOwnDataProperty(desc, "enumerable", !!Obj.enumerable); + } else { + // An enumerable property is not specified. + /* do nothing */ + } + if ("configurable" in Obj) { + // A configurable property is specified. + defineOwnDataProperty( + desc, + "configurable", + !!Obj.configurable, + ); + } else { + // A configurable property is not specified. + /* do nothing */ + } + if ("value" in Obj) { + // A value property is specified. + defineOwnDataProperty(desc, "value", Obj.value); + } else { + // A value property is not specified. + /* do nothing */ + } + if ("writable" in Obj) { + // A writable property is specified. + defineOwnDataProperty(desc, "writable", !!Obj.writable); + } else { + // A writable property is not specified. + /* do nothing */ + } + if ("get" in Obj) { + // A get property is specified. + const getter = Obj.get; + if (getter !== UNDEFINED && typeof getter !== "function") { + // The getter is not callable; this is an error. + throw new TypeError( + `${PISCĒS}: Getters must be callable.`, + ); + } else { + // The getter is callable. + defineOwnDataProperty(desc, "get", Obj.get); + } + } else { + // A get property is not specified. + /* do nothing */ + } + if ("set" in Obj) { + // A set property is specified. + const setter = Obj.set; + if (setter !== UNDEFINED && typeof setter !== "function") { + // The setter is not callable; this is an error. + throw new TypeError( + `${PISCĒS}: Setters must be callable.`, + ); + } else { + // The setter is callable. + defineOwnDataProperty(desc, "set", Obj.set); + } + } 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; this + // is an error. + throw new TypeError( + `${PISCĒS}: Property descriptors cannot specify both accessor and data attributes.`, + ); + } else { + // The property descriptor is valid. + const record = new proxyConstructor( + desc, + propertyDescriptorProxyHandler, + ); + call(weakSetAdd, propertyDescriptorRecords, [record]); + return record; + } + } + }, + }; +})(); + /** * Returns whether the provided value is an unfrozen object. * * ※ This function returns false for nonobjects. * - * ※ This is effectively an alias for `!Object.isFrozen`. + * ※ This is effectively an alias for `!Object.isFrozen´. */ export const isUnfrozenObject = (O) => !isFrozen(O); @@ -486,7 +820,7 @@ export const isUnfrozenObject = (O) => !isFrozen(O); * * ※ This function returns false for nonobjects. * - * ※ This is effectively an alias for `!Object.isSealed`. + * ※ This is effectively an alias for `!Object.isSealed´. */ export const isUnsealedObject = (O) => !isSealed(O); @@ -504,7 +838,7 @@ export const lengthOfArraylike = ({ length }) => toLength(length); * Returns an array of key~value pairs for the enumerable, * string‐valued property keys on the provided value. * - * ※ This is effectively an alias for `Object.entries`. + * ※ This is effectively an alias for `Object.entries´. */ export const namedEntries = (O) => entries(O); @@ -512,7 +846,7 @@ export const namedEntries = (O) => entries(O); * Returns an array of the enumerable, string‐valued property keys on * the provided value. * - * ※ This is effectively an alias for `Object.keys`. + * ※ This is effectively an alias for `Object.keys´. */ export const namedKeys = (O) => keys(O); @@ -520,7 +854,7 @@ export const namedKeys = (O) => keys(O); * Returns an array of property values for the enumerable, * string‐valued property keys on the provided value. * - * ※ This is effectively an alias for `Object.values`. + * ※ This is effectively an alias for `Object.values´. */ export const namedValues = (O) => values(O); @@ -528,7 +862,7 @@ export const namedValues = (O) => values(O); * Returns a new object with the provided prototype and property * descriptors. * - * ※ This is effectively an alias for `Object.create`. + * ※ This is effectively an alias for `Object.create´. */ export const objectCreate = (O, Properties) => create(O, Properties); @@ -536,7 +870,7 @@ export const objectCreate = (O, Properties) => create(O, Properties); * Returns a new object with property keys and values from the provided * iterable value. * - * ※ This is effectively an alias for `Object.fromEntries`. + * ※ This is effectively an alias for `Object.fromEntries´. */ export const objectFromEntries = (iterable) => fromEntries(iterable); @@ -544,7 +878,7 @@ export const objectFromEntries = (iterable) => fromEntries(iterable); * Marks the provided object as non·extensible, and returns the * object. * - * ※ This is effectively an alias for `Object.preventExtensions`. + * ※ This is effectively an alias for `Object.preventExtensions´. */ export const preventExtensions = (O) => objectPreventExtensions(O); @@ -552,7 +886,7 @@ export const preventExtensions = (O) => objectPreventExtensions(O); * 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`. + * ※ This is effectively an alias for `Object.seal´. */ export const seal = (O) => objectSeal(O); @@ -560,21 +894,26 @@ export const seal = (O) => objectSeal(O); * 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 + * ※ 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. */ export const setPropertyValue = (O, P, V, Receiver = O) => { 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}`, + `${PISCĒS}: Tried to set property but provided value was not an object: ${V}`, ); } else if (!set(O, P, V, Receiver)) { + // Setting the property fails; this is an error. throw new TypeError( - `Piscēs: Tried to set property on object but [[Set]] returned false: ${P}`, + `${PISCĒS}: Tried to set property on object but [[Set]] returned false: ${P}`, ); } else { + // The property was successfully set. + // + // Return the provided object. return O; } }; @@ -583,7 +922,7 @@ export const setPropertyValue = (O, P, V, Receiver = O) => { * Sets the values of the enumerable own properties of the provided * additional objects on the provided values. * - * ※ This is effectively an alias for `Object.assign`. + * ※ This is effectively an alias for `Object.assign´. */ export const setPropertyValues = (target, source, ...sources) => { const to = toObject(target); @@ -592,7 +931,9 @@ export const setPropertyValues = (target, source, ...sources) => { // values. const nextSource = i === -1 ? source : sources[i]; if (nextSource != null) { - // The current source is not nullish; handle its own properties. + // The current source is not nullish. + // + // Handle its own properties. const from = toObject(nextSource); const keys = ownKeys(from); for (let k = 0; k < keys.length; ++k) { @@ -601,8 +942,9 @@ export const setPropertyValues = (target, source, ...sources) => { const nextKey = keys[k]; const desc = reflectGetOwnPropertyDescriptor(from, nextKey); if (desc !== UNDEFINED && desc.enumerable) { - // The current key is present and enumerable; set it to its - // corresponding value. + // The current key is present and enumerable. + // + // Set it to its corresponding value. const propValue = from[nextKey]; to[nextKey] = propValue; } else { @@ -622,21 +964,24 @@ export const setPropertyValues = (target, source, ...sources) => { * Sets the prototype of the provided object to the provided value and * returns the object. * - * ※ This is effectively an alias for `Object.setPrototypeOf`, but it - * won’t throw when setting the prototype of a primitive to its current + * ※ This is effectively an alias for `Object.setPrototypeOf´, but it + * won¦t throw when setting the prototype of a primitive to its current * value. */ export const setPrototype = (O, proto) => { const obj = toObject(O); if (O === obj) { - // The provided value is an object; set its prototype normally. + // 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. + // 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 + // ☡ This will throw if the given prototype does not match the // existing one on the coerced object. setPrototypeOf(objectPreventExtensions(obj), proto); return O; @@ -654,19 +999,12 @@ export const toObject = ($) => { if ($ == null) { // The provided value is nullish; this is an error. throw new TypeError( - `Piscēs: Cannot convert ${$} into an object.`, + `${PISCĒS}: Cannot convert ${$} into an object.`, ); } else { - // The provided value is not nullish; coerce it to an object. + // The provided value is not nullish. + // + // Coerce it to an object. return object($); } }; - -/** - * 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}`; -};