X-Git-Url: https://git.ladys.computer/Pisces/blobdiff_plain/70b032d26faece9d6573e6f0b2375f071bbcc866..refs/heads/current:/value.js diff --git a/value.js b/value.js index 83c1e18..cf858ad 100644 --- a/value.js +++ b/value.js @@ -173,6 +173,93 @@ export const POSITIVE_ZERO = 0; /** The undefined primitive. */ export const UNDEFINED = undefined; +/** + * Completes the provided property descriptor by setting missing values + * to their defaults. + * + * ※ This method modifies the provided object and returns undefined. + */ +export const completePropertyDescriptor = (Desc) => { + if (Desc === UNDEFINED) { + throw new TypeError( + "Piscēs: Cannot complete undefined property descriptor.", + ); + } else if (!("get" in Desc || "set" in Desc)) { + // This is a generic or data descriptor. + if (!("value" in Desc)) { + // `value` is not defined on this. + Desc.value = UNDEFINED; + } else { + // `value` is already defined on this. + /* do nothing */ + } + if (!("writable" in Desc)) { + // `writable` is not defined on this. + Desc.writable = false; + } else { + // `writable` is already defined on this. + /* do nothing */ + } + } else { + // This is not a generic or data descriptor. + if (!("get" in Desc)) { + // `get` is not defined on this. + Desc.get = UNDEFINED; + } else { + // `get` is already defined on this. + /* do nothing */ + } + if (!("set" in Desc)) { + // `set` is not defined on this. + Desc.set = UNDEFINED; + } else { + // `set` is already defined on this. + /* do nothing */ + } + } + if (!("enumerable" in Desc)) { + // `enumerable` is not defined on this. + Desc.enumerable = false; + } else { + // `enumerable` is already defined on this. + /* do nothing */ + } + if (!("configurable" in Desc)) { + // `configurable` is not defined on this. + Desc.configurable = false; + } else { + // `configurable` is already defined on this. + /* do nothing */ + } +}; + +/** Gets whether the provided value is an accessor descrtiptor. */ +export const isAccessorDescriptor = (Desc) => + Desc !== UNDEFINED && ("get" in Desc || "set" in Desc); + +/** Gets whether the provided value is a data descrtiptor. */ +export const isDataDescriptor = (Desc) => + Desc !== UNDEFINED && ("value" in Desc || "writable" in Desc); + +/** + * Gets whether the provided value is a fully‐populated property + * descriptor. + */ +export const isFullyPopulatedDescriptor = (Desc) => + Desc !== UNDEFINED && + ("value" in Desc && "writable" in Desc || + "get" in Desc && "set" in Desc) && + "enumerable" in Desc && "configurable" in Desc; + +/** + * Gets whether the provided value is a generic (not accessor or data) + * descrtiptor. + */ +export const isGenericDescriptor = (Desc) => + Desc !== UNDEFINED && + !("get" in Desc || "set" in Desc || "value" in Desc || + "writable" in Desc); + export const { /** * Returns the primitive value of the provided object per its @@ -186,6 +273,12 @@ export const { */ ordinaryToPrimitive, + /** + * Returns a string function name generated from the provided value + * and optional prefix. + */ + toFunctionName, + /** * Returns the provided value converted to a primitive, or throws if * no such conversion is possible. @@ -199,6 +292,10 @@ export const { toPrimitive, } = (() => { const { apply: call } = Reflect; + const getSymbolDescription = Object.getOwnPropertyDescriptor( + Symbol.prototype, + "description", + ).get; return { ordinaryToPrimitive: (O, hint) => { @@ -226,6 +323,21 @@ export const { "Piscēs: Unable to convert object to primitive", ); }, + toFunctionName: ($, prefix = UNDEFINED) => { + const key = toPrimitive($, "string"); + const name = (() => { + if (typeof key === "symbol") { + // The provided value is a symbol; format its description. + const description = call(getSymbolDescription, key, []); + return description === UNDEFINED ? "" : `[${description}]`; + } else { + // The provided value not a symbol; convert it to a string + // property key. + return `${key}`; + } + })(); + return prefix !== UNDEFINED ? `${prefix} ${name}` : name; + }, toPrimitive: ($, preferredType = "default") => { const hint = `${preferredType}`; if ( @@ -238,8 +350,8 @@ export const { ); } else if (type($) === "object") { // The provided value is an object. - const exoticToPrim = $[TO_PRIMITIVE] ?? undefined; - if (exoticToPrim !== undefined) { + const exoticToPrim = $[TO_PRIMITIVE] ?? UNDEFINED; + if (exoticToPrim !== UNDEFINED) { // The provided value has an exotic primitive conversion // method. if (typeof exoticToPrim !== "function") { @@ -336,6 +448,15 @@ export const { }; })(); +/** + * 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}`; +}; + /** * Returns a lowercase string identifying the type of the provided * value.