X-Git-Url: https://git.ladys.computer/Pisces/blobdiff_plain/58d78d7c0602b17a9599e28232cc8a2ff1d8fc65..refs/heads/current:/value.js?ds=sidebyside diff --git a/value.js b/value.js index 3f0c6fa..cf858ad 100644 --- a/value.js +++ b/value.js @@ -45,12 +45,221 @@ export const { unscopables: UNSCOPABLES, } = Symbol; +export const { + /** + * ln(10). + * + * ※ This is an alias for `Math.LN10`. + */ + LN10, + + /** + * ln(2). + * + * ※ This is an alias for `Math.LN2`. + */ + LN2, + + /** + * log10(ℇ). + * + * ※ This is an alias for `Math.LOG10E`. + */ + LOG10E: LOG10ℇ, + + /** + * log2(ℇ). + * + * ※ This is an alias for `Math.LOG2E`. + */ + LOG2E: LOG2ℇ, + + /** + * sqrt(½). + * + * ※ This is an alias for `Math.SQRT1_2`. + */ + SQRT1_2: RECIPROCAL_SQRT2, + + /** + * sqrt(2). + * + * ※ This is an alias for `Math.SQRT2`. + */ + SQRT2, + + /** + * The mathematical constant π. + * + * ※ This is an alias for `Math.PI`. + */ + PI: Π, + + /** + * The Euler number. + * + * ※ This is an alias for `Math.E`. + */ + E: ℇ, +} = Math; + +export const { + /** + * The largest number value less than infinity. + * + * ※ This is an alias for `Number.MAX_VALUE`. + */ + MAX_VALUE: MAXIMUM_NUMBER, + + /** + * 2**53 - 1. + * + * ※ This is an alias for `Number.MAX_SAFE_INTEGER`. + */ + MAX_SAFE_INTEGER: MAXIMUM_SAFE_INTEGRAL_NUMBER, + + /** + * The smallest number value greater than negative infinity. + * + * ※ This is an alias for `Number.MIN_VALUE`. + */ + MIN_VALUE: MINIMUM_NUMBER, + + /** + * -(2**53 - 1). + * + * ※ This is an alias for `Number.MIN_SAFE_INTEGER`. + */ + MIN_SAFE_INTEGER: MINIMUM_SAFE_INTEGRAL_NUMBER, + + /** + * Negative infinity. + * + * ※ This is an alias for `Number.NEGATIVE_INFINITY`. + */ + NEGATIVE_INFINITY, + + /** + * Nan. + * + * ※ This is an alias for `Number.NaN`. + */ + NaN: NAN, + + /** + * Positive infinity. + * + * ※ This is an alias for `Number.POSITIVE_INFINITY`. + */ + POSITIVE_INFINITY, + + /** + * The difference between 1 and the smallest number greater than 1. + * + * ※ This is an alias for `Number.EPSILON`. + */ + EPSILON: Ε, +} = Number; + +/** Negative zero. */ +export const NEGATIVE_ZERO = -0; + /** The null primitive. */ export const NULL = null; +/** Positive zero. */ +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 @@ -64,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. @@ -77,6 +292,10 @@ export const { toPrimitive, } = (() => { const { apply: call } = Reflect; + const getSymbolDescription = Object.getOwnPropertyDescriptor( + Symbol.prototype, + "description", + ).get; return { ordinaryToPrimitive: (O, hint) => { @@ -104,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 ( @@ -116,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") { @@ -141,14 +375,14 @@ export const { }; })(); -/** - * Returns whether the provided values are the same value. - * - * ※ This differs from `===` in the cases of nan and zero. - */ -export const sameValue = Object.is; - export const { + /** + * Returns whether the provided values are the same value. + * + * ※ This differs from `===` in the cases of nan and zero. + */ + sameValue, + /** * Returns whether the provided values are either the same value or * both zero (either positive or negative). @@ -156,9 +390,23 @@ export const { * ※ This differs from `===` in the case of nan. */ sameValueZero, + + /** + * Returns the result of converting the provided value to an index, + * or throws an error if it is out of range. + */ + toIndex, + + /** + * Returns the result of converting the provided value to a length. + */ + toLength, } = (() => { + const { floor, max, min } = Math; const { isNaN: isNan } = Number; + const { is } = Object; return { + sameValue: (a, b) => is(a, b), sameValueZero: ($1, $2) => { const type1 = type($1); const type2 = type($2); @@ -174,9 +422,41 @@ export const { return $1 === $2; } }, + toIndex: ($) => { + const integer = floor($); + if (isNan(integer) || integer == 0) { + // The value is zero·like. + return 0; + } else { + // The value is not zero·like. + const clamped = toLength(integer); + if (clamped !== integer) { + // Clamping the value changes it. + throw new RangeError(`Piscēs: Index out of range: ${$}.`); + } else { + // The value is within appropriate bounds. + return integer; + } + } + }, + toLength: ($) => { + const len = floor($); + return isNan(len) || len == 0 + ? 0 + : max(min(len, MAXIMUM_SAFE_INTEGRAL_NUMBER), 0); + }, }; })(); +/** + * 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.