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;
/**
- * Returns −0 if the provided argument is "-0"; returns a number
- * representing the index if the provided argument is a canonical
- * numeric index string; otherwise, returns undefined.
+ * Completes the provided property descriptor by setting missing values
+ * to their defaults.
*
- * There is no clamping of the numeric index, but note that numbers
- * above 2^53 − 1 are not safe nor valid integer indices.
+ * ※ This method modifies the provided object and returns undefined.
*/
-export const canonicalNumericIndexString = ($) => {
- if (typeof $ !== "string") {
- return undefined;
- } else if ($ === "-0") {
- return -0;
+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 {
- const n = +$;
- return $ === `${n}` ? n : undefined;
+ // `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);
+
/**
- * Returns the length of the provided arraylike value.
- *
- * This can produce larger lengths than can actually be stored in
- * arrays, because no such restrictions exist on arraylike methods.
- *
- * ☡ This function throws if the provided value is not arraylike.
+ * Gets whether the provided value is a fully‐populated property
+ * descriptor.
*/
-export const lengthOfArraylike = ({ length }) => toLength(length);
+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 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 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.
+ */
+ toPropertyDescriptor,
+} = (() => {
+ const {
+ assign: setPropertyValues,
+ create: objectCreate,
+ defineProperty: defineOwnProperty,
+ } = Object;
+ const {
+ apply: call,
+ defineProperty: reflectDefineProperty,
+ setPrototypeOf: reflectSetPrototypeOf,
+ } = Reflect;
+ 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") {
+ throw new TypeError(
+ "Piscēs: Getters must be callable.",
+ );
+ } else {
+ return V;
+ }
+ case "set":
+ if (V !== undefined && typeof V !== "function") {
+ throw new TypeError(
+ "Piscēs: Setters must be callable.",
+ );
+ } else {
+ return V;
+ }
+ default:
+ return V;
+ }
+ };
+ const propertyDescriptorProxyHandler = Object.freeze(
+ Object.assign(
+ Object.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 = setPropertyValues(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.
+ 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, [$]),
+ toPropertyDescriptor: (Obj) => {
+ if (type(Obj) !== "object") {
+ // The provided value is not an object.
+ throw new TypeError(
+ `Piscēs: Cannot convert primitive to property descriptor: ${O}.`,
+ );
+ } else {
+ // The provided value is an object.
+ const desc = objectCreate(null);
+ if ("enumerable" in Obj) {
+ // An enumerable property is specified.
+ defineOwnProperty(desc, "enumerable", {
+ configurable: true,
+ enumerable: true,
+ value: !!Obj.enumerable,
+ writable: true,
+ });
+ } else {
+ // An enumerable property is not specified.
+ /* do nothing */
+ }
+ if ("configurable" in Obj) {
+ // A configurable property is specified.
+ defineOwnProperty(desc, "configurable", {
+ configurable: true,
+ enumerable: true,
+ value: !!Obj.configurable,
+ writable: true,
+ });
+ } else {
+ // A configurable property is not specified.
+ /* do nothing */
+ }
+ if ("value" in Obj) {
+ // A value property is specified.
+ defineOwnProperty(desc, "value", {
+ configurable: true,
+ enumerable: true,
+ value: Obj.value,
+ writable: true,
+ });
+ } else {
+ // A value property is not specified.
+ /* do nothing */
+ }
+ if ("writable" in Obj) {
+ // A writable property is specified.
+ defineOwnProperty(desc, "writable", {
+ configurable: true,
+ enumerable: true,
+ value: !!Obj.writable,
+ writable: true,
+ });
+ } 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.
+ throw new TypeError("Piscēs: Getters must be callable.");
+ } else {
+ // The getter is callable.
+ defineOwnProperty(desc, "get", {
+ configurable: true,
+ enumerable: true,
+ value: getter,
+ writable: true,
+ });
+ }
+ } 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.
+ throw new TypeError("Piscēs: Setters must be callable.");
+ } else {
+ // The setter is callable.
+ defineOwnProperty(desc, "set", {
+ configurable: true,
+ enumerable: true,
+ value: setter,
+ writable: true,
+ });
+ }
+ } 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.
+ 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;
+ }
+ }
+ },
+ };
+})();
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.
toPrimitive,
} = (() => {
const { apply: call } = Reflect;
+ const getSymbolDescription = Object.getOwnPropertyDescriptor(
+ Symbol.prototype,
+ "description",
+ ).get;
return {
ordinaryToPrimitive: (O, hint) => {
"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 (
})();
export const {
- /** Returns whether the provided value is an integer index string. */
- isIntegerIndexString,
-
/**
* Returns whether the provided values are the same value.
*
toLength,
} = (() => {
const { floor, max, min } = Math;
- const {
- MAX_SAFE_INTEGER: MAXIMUM_SAFE_INTEGRAL_NUMBER,
- isInteger: isIntegralNumber,
- isNaN: isNan,
- } = Number;
+ const { isNaN: isNan } = Number;
const { is } = Object;
return {
- isIntegerIndexString: ($) => {
- const value = canonicalNumericIndexString($);
- if (value !== undefined && isIntegralNumber(value)) {
- // The provided value is an integral canonical numeric index
- // string.
- return sameValue(value, 0) ||
- value > 0 && value <= MAXIMUM_SAFE_INTEGRAL_NUMBER &&
- value === toLength(value);
- } else {
- // The provided value is not an integral canonical numeric
- // index string.
- return false;
- }
- },
sameValue: (a, b) => is(a, b),
sameValueZero: ($1, $2) => {
const type1 = type($1);