1 // SPDX-FileCopyrightText: 2022, 2023, 2025 Lady <https://www.ladys.computer/about/#lady>
2 // SPDX-License-Identifier: MPL-2.0
4 * ⁌ ♓🧩 Piscēs ∷ value.js
6 * Copyright © 2022–2023, 2025 Lady [@ Ladys Computer].
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
13 const PISC
ĒS
= "♓🧩 Piscēs";
16 /** The welknown `@@asyncIterator´ symbol. */
17 asyncIterator: ASYNC_ITERATOR
,
19 /** The welknown `@@hasInstance´ symbol. */
20 hasInstance: HAS_INSTANCE
,
22 /** The welknown `@@isConcatSpreadable´ symbol. */
23 isConcatSpreadable: IS_CONCAT_SPREADABLE
,
25 /** The welknown `@@iterator´ symbol. */
28 /** The welknown `@@match´ symbol. */
31 /** The welknown `@@matchAll´ symbol. */
34 /** The welknown `@@replace´ symbol. */
37 /** The welknown `@@species´ symbol. */
40 /** The welknown `@@split´ symbol. */
43 /** The welknown `@@toPrimitive´ symbol. */
44 toPrimitive: TO_PRIMITIVE
,
46 /** The welknown `@@toStringTag´ symbol. */
47 toStringTag: TO_STRING_TAG
,
49 /** The welknown `@@unscopables´ symbol. */
50 unscopables: UNSCOPABLES
,
57 * ※ This is an alias for `Math.LN10´.
64 * ※ This is an alias for `Math.LN2´.
71 * ※ This is an alias for `Math.LOG10E´.
78 * ※ This is an alias for `Math.LOG2E´.
85 * ※ This is an alias for `Math.SQRT1_2´.
87 SQRT1_2: RECIPROCAL_SQRT_2
,
92 * ※ This is an alias for `Math.SQRT2´.
97 * The mathematical constant 𝑒.
99 * ※ This is an alias for `Math.E´.
104 * The mathematical constant 𝜋.
106 * ※ This is an alias for `Math.PI´.
113 * The largest number value less than infinity.
115 * ※ This is an alias for `Number.MAX_VALUE´.
117 MAX_VALUE: MAXIMUM_NUMBER
,
122 * ※ This is an alias for `Number.MAX_SAFE_INTEGER´.
124 MAX_SAFE_INTEGER: MAXIMUM_SAFE_INTEGRAL_NUMBER
,
127 * The smallest number value greater than negative infinity.
129 * ※ This is an alias for `Number.MIN_VALUE´.
131 MIN_VALUE: MINIMUM_NUMBER
,
136 * ※ This is an alias for `Number.MIN_SAFE_INTEGER´.
138 MIN_SAFE_INTEGER: MINIMUM_SAFE_INTEGRAL_NUMBER
,
143 * ※ This is an alias for `Number.NEGATIVE_INFINITY´.
150 * ※ This is an alias for `Number.NaN´.
157 * ※ This is an alias for `Number.POSITIVE_INFINITY´.
162 * The difference between 1 and the smallest number greater than 1.
164 * ※ This is an alias for `Number.EPSILON´.
169 /** Negative zero. */
170 export const NEGATIVE_ZERO
= -0;
172 /** The null primitive. */
173 export const NULL
= null;
175 /** Positive zero. */
176 export const POSITIVE_ZERO
= 0;
178 /** The undefined primitive. */
179 export const UNDEFINED
= undefined;
182 * Completes the provided property descriptor by setting missing values
185 * ※ This method modifies the provided object and returns undefined.
187 export const completePropertyDescriptor
= (Desc
) => {
188 if (Desc
=== UNDEFINED
) {
189 // A description was not provided; this is an error.
191 `${PISCĒS}: Cannot complete undefined property descriptor.`,
193 } else if (!("get" in Desc
|| "set" in Desc
)) {
194 // This is a generic or data descriptor.
195 if (!("value" in Desc
)) {
196 // `value´ is not defined on this.
197 Desc
.value
= UNDEFINED
;
199 // `value´ is already defined on this.
202 if (!("writable" in Desc
)) {
203 // `writable´ is not defined on this.
204 Desc
.writable
= false;
206 // `writable´ is already defined on this.
210 // This is not a generic or data descriptor.
211 if (!("get" in Desc
)) {
212 // `get´ is not defined on this.
213 Desc
.get = UNDEFINED
;
215 // `get´ is already defined on this.
218 if (!("set" in Desc
)) {
219 // `set´ is not defined on this.
220 Desc
.set = UNDEFINED
;
222 // `set´ is already defined on this.
226 if (!("enumerable" in Desc
)) {
227 // `enumerable´ is not defined on this.
228 Desc
.enumerable
= false;
230 // `enumerable´ is already defined on this.
233 if (!("configurable" in Desc
)) {
234 // `configurable´ is not defined on this.
235 Desc
.configurable
= false;
237 // `configurable´ is already defined on this.
242 /** Gets whether the provided value is an accessor descrtiptor. */
243 export const isAccessorDescriptor
= (Desc
) =>
244 Desc
!== UNDEFINED
&& ("get" in Desc
|| "set" in Desc
);
246 /** Gets whether the provided value is a data descrtiptor. */
247 export const isDataDescriptor
= (Desc
) =>
248 Desc
!== UNDEFINED
&& ("value" in Desc
|| "writable" in Desc
);
251 * Gets whether the provided value is a fully‐populated property
254 export const isFullyPopulatedDescriptor
= (Desc
) =>
256 && ("value" in Desc
&& "writable" in Desc
257 || "get" in Desc
&& "set" in Desc
)
258 && "enumerable" in Desc
&& "configurable" in Desc
;
261 * Gets whether the provided value is a generic (not accessor or data)
264 export const isGenericDescriptor
= (Desc
) =>
266 && !("get" in Desc
|| "set" in Desc
|| "value" in Desc
267 || "writable" in Desc
);
271 * Returns the primitive value of the provided object per its
272 * `.toString´ and `.valueOf´ methods.
274 * If the provided hint is "string", then `.toString´ takes
275 * precedence; otherwise, `.valueOf´ does.
277 * Throws an error if both of these methods are not callable or do
278 * not return a primitive.
283 * Returns a string function name generated from the provided value
284 * and optional prefix.
289 * Returns the provided value converted to a primitive, or throws if
290 * no such conversion is possible.
292 * The provided preferred type, if specified, should be "string",
293 * "number", or "default". If the provided input has a
294 * `.[Symbol.toPrimitive]´ method, this function will throw rather
295 * than calling that method with a preferred type other than one of
300 const { apply: call
} = Reflect
;
301 const getSymbolDescription
= Object
.getOwnPropertyDescriptor(
307 ordinaryToPrimitive: (O
, hint
) => {
308 const methodNames
= hint
== "string"
309 ? ["toString", "valueOf"]
310 : ["valueOf", "toString"];
311 for (let index
= 0; index
< methodNames
.length
; ++index
) {
312 // Test the methods in the order determined above (based on the
313 // hint) and return the result if the method returns a
316 // ☡ If this loop exits with·out returning, it is an error.
317 const method
= O
[methodNames
[index
]];
318 if (typeof method
=== "function") {
319 // Method is callable.
320 const result
= call(method
, O
, []);
321 if (type(result
) !== "object") {
322 // Method returns a primitive.
325 // Method returns an object.
329 // Method is not callable.
334 `${PISCĒS}: Unable to convert object to primitive.`,
337 toFunctionName: ($, prefix
= UNDEFINED
) => {
338 const key
= toPrimitive($, "string");
339 const name
= (() => {
340 if (typeof key
=== "symbol") {
341 // The provided value is a symbol.
343 // Format its description.
344 const description
= call(getSymbolDescription
, key
, []);
345 return description
=== UNDEFINED
? "" : `[${description}]`;
347 // The provided value not a symbol.
349 // Convert it to a string property key.
353 return prefix
!== UNDEFINED
? `${prefix} ${name}` : name
;
355 toPrimitive: ($, preferredType
= "default") => {
356 const hint
= `${preferredType}`;
358 "default" !== hint
&& "string" !== hint
361 // An invalid preferred type was specified.
363 `${PISCĒS}: Invalid preferred type: ${preferredType}.`,
365 } else if (type($) === "object") {
366 // The provided value is an object.
367 const exoticToPrim
= $[TO_PRIMITIVE
] ?? UNDEFINED
;
368 if (exoticToPrim
!== UNDEFINED
) {
369 // The provided value has an exotic primitive conversion
371 if (typeof exoticToPrim
!== "function") {
372 // The method is not callable.
374 `${PISCĒS}: .[Symbol.toPrimitive] was neither nullish nor callable.`,
377 // The method is callable.
378 return call(exoticToPrim
, $, [hint
]);
381 // Use the ordinary primitive conversion function.
382 return ordinaryToPrimitive($, hint
);
385 // The provided value is already a primitive.
394 * Returns whether the provided values are the same value.
396 * ※ This differs from `===´ in the cases of nan and zero.
401 * Returns whether the provided values are either the same value or
402 * both zero (either positive or negative).
404 * ※ This differs from `===´ in the case of nan.
409 * Returns the result of converting the provided value to an index,
410 * or throws an error if it is out of range.
415 * Returns the result of converting the provided value to a length.
419 const { floor
, max
, min
} = Math
;
420 const { isNaN: isNan
} = Number
;
421 const { is
} = Object
;
423 sameValue: (a
, b
) => is(a
, b
),
424 sameValueZero: ($1, $2) => {
425 const type1
= type($1);
426 const type2
= type($2);
427 if (type1
!== type2
) {
428 // The provided values are not of the same type.
430 } else if (type1
=== "number") {
431 // The provided values are numbers.
433 // Check if they are nan and use strict equality otherwise.
434 return isNan($1) && isNan($2) || $1 === $2;
436 // The provided values are not numbers.
438 // Use strict equality.
443 const integer
= floor($);
444 if (isNan(integer
) || integer
== 0) {
445 // The value is zero·like.
447 // Return positive zero.
450 // The value is not zero·like.
451 const clamped
= toLength(integer
);
452 if (clamped
!== integer
) {
453 // Clamping the value changes it; this is an error.
454 throw new RangeError(`${PISCĒS}: Index out of range: ${$}.`);
456 // The value is within appropriate bounds.
464 const len
= floor($);
465 return isNan(len
) || len
== 0
467 : max(min(len
, MAXIMUM_SAFE_INTEGRAL_NUMBER
), 0);
473 * Returns the property key (symbol or string) corresponding to the
476 export const toPropertyKey
= ($) => {
477 const key
= toPrimitive($, "string");
478 return typeof key
=== "symbol" ? key : `${key}`;
482 * Returns a lowercase string identifying the type of the provided
485 * This differs from the value of the `typeof´ operator only in the
486 * cases of callable objects and null.
488 export const type
= ($) => {
490 // The provided value is null.
493 // The provided value is not null.
494 const type
·of = typeof $;
495 return type
·of === "function" ? "object" : type
·of;