import { call, createCallableFunction } from "./function.js";
import {
- floor,
isIntegralNumber,
- isNan,
- max,
MAXIMUM_SAFE_INTEGRAL_NUMBER,
- min,
} from "./numeric.js";
-import { sameValue, type } from "./value.js";
+import {
+ canonicalNumericIndexString,
+ lengthOfArraylike,
+ sameValue,
+ toIndex,
+ toLength,
+ type,
+} from "./value.js";
const { prototype: arrayPrototype } = Array;
from: toArray,
} = Array;
-/**
- * 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.
- *
- * There is no clamping of the numeric index, but note that numbers
- * above 2^53 − 1 are not safe nor valid integer indices.
- */
-export const canonicalNumericIndexString = ($) => {
- if (typeof $ !== "string") {
- return undefined;
- } else if ($ === "-0") {
- return -0;
- } else {
- const n = +$;
- return $ === `${n}` ? n : undefined;
- }
-};
-
/**
* Returns the result of catenating the provided arraylikes into a new
* collection according to the algorithm of `Array::concat`.
"items",
);
-/**
- * Returns the length of the provided arraylike object.
- *
- * Will throw if the provided object is not arraylike.
- *
- * This can produce larger lengths than can actually be stored in
- * arrays, because no such restrictions exist on arraylike methods.
- */
-export const lengthOfArraylike = ({ length }) => toLength(length);
-
/**
* Returns the result of mapping the provided value with the provided
* callback according to the algorithm of `Array::map`.
*/
export const splice = createCallableFunction(arrayPrototype.splice);
-/**
- * Returns the result of converting the provided value to an array
- * index, or throws an error if it is out of range.
- */
-export const 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;
- }
- }
-};
-
-/** Returns the result of converting the provided value to a length. */
-export const toLength = ($) => {
- const len = floor($);
- return isNan(len) || len == 0
- ? 0
- : max(min(len, MAXIMUM_SAFE_INTEGRAL_NUMBER), 0);
-};
-
/**
* Unshifts the provided value according to the algorithm of
* `Array::unshift`.
assertSpyCall,
assertSpyCalls,
assertStrictEquals,
- assertThrows,
describe,
it,
spy,
} from "./dev-deps.js";
import {
- canonicalNumericIndexString,
findIndexedEntry,
isArrayIndexString,
isArraylikeObject,
isCollection,
isConcatSpreadable,
isIntegerIndexString,
- lengthOfArraylike,
- toIndex,
- toLength,
} from "./collection.js";
-describe("canonicalNumericIndexString", () => {
- it("[[Call]] returns undefined for nonstrings", () => {
- assertStrictEquals(canonicalNumericIndexString(1), void {});
- });
-
- it("[[Call]] returns undefined for noncanonical strings", () => {
- assertStrictEquals(canonicalNumericIndexString(""), void {});
- assertStrictEquals(canonicalNumericIndexString("01"), void {});
- assertStrictEquals(
- canonicalNumericIndexString("9007199254740993"),
- void {},
- );
- });
-
- it('[[Call]] returns -0 for "-0"', () => {
- assertStrictEquals(canonicalNumericIndexString("-0"), -0);
- });
-
- it("[[Call]] returns the corresponding number for canonical strings", () => {
- assertStrictEquals(canonicalNumericIndexString("0"), 0);
- assertStrictEquals(canonicalNumericIndexString("-0.25"), -0.25);
- assertStrictEquals(
- canonicalNumericIndexString("9007199254740992"),
- 9007199254740992,
- );
- assertStrictEquals(canonicalNumericIndexString("NaN"), 0 / 0);
- assertStrictEquals(canonicalNumericIndexString("Infinity"), 1 / 0);
- assertStrictEquals(
- canonicalNumericIndexString("-Infinity"),
- -1 / 0,
- );
- });
-});
-
describe("findIndexedEntry", () => {
it("[[Call]] returns undefined if no matching entry exists", () => {
assertStrictEquals(findIndexedEntry([], () => true), void {});
assertStrictEquals(isIntegerIndexString("9007199254740991"), true);
});
});
-
-describe("lengthOfArraylike", () => {
- it("[[Call]] returns the length", () => {
- assertStrictEquals(
- lengthOfArraylike({ length: 9007199254740991 }),
- 9007199254740991,
- );
- });
-
- it("[[Call]] returns a non·nan result", () => {
- assertStrictEquals(lengthOfArraylike({ length: NaN }), 0);
- assertStrictEquals(lengthOfArraylike({ length: "failure" }), 0);
- });
-
- it("[[Call]] returns an integral result", () => {
- assertStrictEquals(lengthOfArraylike({ length: 0.25 }), 0);
- assertStrictEquals(lengthOfArraylike({ length: 1.1 }), 1);
- });
-
- it("[[Call]] returns a result greater than or equal to zero", () => {
- assertStrictEquals(lengthOfArraylike({ length: -0 }), 0);
- assertStrictEquals(lengthOfArraylike({ length: -1 }), 0);
- assertStrictEquals(lengthOfArraylike({ length: -Infinity }), 0);
- });
-
- it("[[Call]] returns a result less than 2 ** 53", () => {
- assertStrictEquals(
- lengthOfArraylike({ length: 9007199254740992 }),
- 9007199254740991,
- );
- assertStrictEquals(
- lengthOfArraylike({ length: Infinity }),
- 9007199254740991,
- );
- });
-});
-
-describe("toIndex", () => {
- it("[[Call]] returns an index", () => {
- assertStrictEquals(toIndex(9007199254740991), 9007199254740991);
- });
-
- it("[[Call]] returns zero for a zerolike result", () => {
- assertStrictEquals(toIndex(NaN), 0);
- assertStrictEquals(toIndex("failure"), 0);
- assertStrictEquals(toIndex(-0), 0);
- });
-
- it("[[Call]] rounds down to the nearest integer", () => {
- assertStrictEquals(toIndex(0.25), 0);
- assertStrictEquals(toIndex(1.1), 1);
- });
-
- it("[[Call]] throws when provided a negative number", () => {
- assertThrows(() => toIndex(-1));
- assertThrows(() => toIndex(-Infinity));
- });
-
- it("[[Call]] throws when provided a number greater than or equal to 2 ** 53", () => {
- assertThrows(() => toIndex(9007199254740992));
- assertThrows(() => toIndex(Infinity));
- });
-});
-
-describe("toLength", () => {
- it("[[Call]] returns a length", () => {
- assertStrictEquals(toLength(9007199254740991), 9007199254740991);
- });
-
- it("[[Call]] returns a non·nan result", () => {
- assertStrictEquals(toLength(NaN), 0);
- assertStrictEquals(toLength("failure"), 0);
- });
-
- it("[[Call]] returns an integral result", () => {
- assertStrictEquals(toLength(0.25), 0);
- assertStrictEquals(toLength(1.1), 1);
- });
-
- it("[[Call]] returns a result greater than or equal to zero", () => {
- assertStrictEquals(toLength(-0), 0);
- assertStrictEquals(toLength(-1), 0);
- assertStrictEquals(toLength(-Infinity), 0);
- });
-
- it("[[Call]] returns a result less than 2 ** 53", () => {
- assertStrictEquals(toLength(9007199254740992), 9007199254740991);
- assertStrictEquals(toLength(Infinity), 9007199254740991);
- });
-});
/** 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.
+ *
+ * There is no clamping of the numeric index, but note that numbers
+ * above 2^53 − 1 are not safe nor valid integer indices.
+ */
+export const canonicalNumericIndexString = ($) => {
+ if (typeof $ !== "string") {
+ return undefined;
+ } else if ($ === "-0") {
+ return -0;
+ } else {
+ const n = +$;
+ return $ === `${n}` ? n : undefined;
+ }
+};
+
+/**
+ * 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.
+ */
+export const lengthOfArraylike = ({ length }) => toLength(length);
+
export const {
/**
* Returns the primitive value of the provided object per its
* ※ 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 { isNaN: isNan } = Number;
+ const { floor, max, min } = Math;
+ const {
+ MAX_SAFE_INTEGER: MAXIMUM_SAFE_INTEGRAL_NUMBER,
+ isNaN: isNan,
+ } = Number;
const { is } = Object;
return {
sameValue: (a, b) => is(a, b),
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);
+ },
};
})();
} from "./dev-deps.js";
import {
ASYNC_ITERATOR,
+ canonicalNumericIndexString,
HAS_INSTANCE,
IS_CONCAT_SPREADABLE,
ITERATOR,
+ lengthOfArraylike,
MATCH,
MATCH_ALL,
NULL,
SPLIT,
TO_PRIMITIVE,
TO_STRING_TAG,
+ toIndex,
+ toLength,
toPrimitive,
type,
UNDEFINED,
});
});
+describe("canonicalNumericIndexString", () => {
+ it("[[Call]] returns undefined for nonstrings", () => {
+ assertStrictEquals(canonicalNumericIndexString(1), void {});
+ });
+
+ it("[[Call]] returns undefined for noncanonical strings", () => {
+ assertStrictEquals(canonicalNumericIndexString(""), void {});
+ assertStrictEquals(canonicalNumericIndexString("01"), void {});
+ assertStrictEquals(
+ canonicalNumericIndexString("9007199254740993"),
+ void {},
+ );
+ });
+
+ it('[[Call]] returns -0 for "-0"', () => {
+ assertStrictEquals(canonicalNumericIndexString("-0"), -0);
+ });
+
+ it("[[Call]] returns the corresponding number for canonical strings", () => {
+ assertStrictEquals(canonicalNumericIndexString("0"), 0);
+ assertStrictEquals(canonicalNumericIndexString("-0.25"), -0.25);
+ assertStrictEquals(
+ canonicalNumericIndexString("9007199254740992"),
+ 9007199254740992,
+ );
+ assertStrictEquals(canonicalNumericIndexString("NaN"), 0 / 0);
+ assertStrictEquals(canonicalNumericIndexString("Infinity"), 1 / 0);
+ assertStrictEquals(
+ canonicalNumericIndexString("-Infinity"),
+ -1 / 0,
+ );
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new canonicalNumericIndexString(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(canonicalNumericIndexString.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(
+ canonicalNumericIndexString.name,
+ "canonicalNumericIndexString",
+ );
+ });
+ });
+});
+
+describe("lengthOfArraylike", () => {
+ it("[[Call]] returns the length", () => {
+ assertStrictEquals(
+ lengthOfArraylike({ length: 9007199254740991 }),
+ 9007199254740991,
+ );
+ });
+
+ it("[[Call]] returns a non·nan result", () => {
+ assertStrictEquals(lengthOfArraylike({ length: NaN }), 0);
+ assertStrictEquals(lengthOfArraylike({ length: "failure" }), 0);
+ });
+
+ it("[[Call]] returns an integral result", () => {
+ assertStrictEquals(lengthOfArraylike({ length: 0.25 }), 0);
+ assertStrictEquals(lengthOfArraylike({ length: 1.1 }), 1);
+ });
+
+ it("[[Call]] returns a result greater than or equal to zero", () => {
+ assertStrictEquals(lengthOfArraylike({ length: -0 }), 0);
+ assertStrictEquals(lengthOfArraylike({ length: -1 }), 0);
+ assertStrictEquals(lengthOfArraylike({ length: -Infinity }), 0);
+ });
+
+ it("[[Call]] returns a result less than 2 ** 53", () => {
+ assertStrictEquals(
+ lengthOfArraylike({ length: 9007199254740992 }),
+ 9007199254740991,
+ );
+ assertStrictEquals(
+ lengthOfArraylike({ length: Infinity }),
+ 9007199254740991,
+ );
+ });
+
+ it("[[Call]] does not require an object argument", () => {
+ assertStrictEquals(lengthOfArraylike("string"), 6);
+ assertStrictEquals(lengthOfArraylike(Symbol()), 0);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new lengthOfArraylike(""));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(lengthOfArraylike.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(lengthOfArraylike.name, "lengthOfArraylike");
+ });
+ });
+});
+
describe("ordinaryToPrimitive", () => {
it("[[Call]] prefers `valueOf` by default", () => {
const obj = {
});
});
+describe("toIndex", () => {
+ it("[[Call]] returns an index", () => {
+ assertStrictEquals(toIndex(9007199254740991), 9007199254740991);
+ });
+
+ it("[[Call]] returns zero for a zerolike argument", () => {
+ assertStrictEquals(toIndex(NaN), 0);
+ assertStrictEquals(toIndex("failure"), 0);
+ assertStrictEquals(toIndex(-0), 0);
+ });
+
+ it("[[Call]] rounds down to the nearest integer", () => {
+ assertStrictEquals(toIndex(0.25), 0);
+ assertStrictEquals(toIndex(1.1), 1);
+ });
+
+ it("[[Call]] throws when provided a negative number", () => {
+ assertThrows(() => toIndex(-1));
+ assertThrows(() => toIndex(-Infinity));
+ });
+
+ it("[[Call]] throws when provided a number greater than or equal to 2 ** 53", () => {
+ assertThrows(() => toIndex(9007199254740992));
+ assertThrows(() => toIndex(Infinity));
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new toIndex(0));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(toIndex.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(toIndex.name, "toIndex");
+ });
+ });
+});
+
+describe("toLength", () => {
+ it("[[Call]] returns a length", () => {
+ assertStrictEquals(toLength(9007199254740991), 9007199254740991);
+ });
+
+ it("[[Call]] returns zero for a nan argument", () => {
+ assertStrictEquals(toLength(NaN), 0);
+ assertStrictEquals(toLength("failure"), 0);
+ });
+
+ it("[[Call]] rounds down to the nearest integer", () => {
+ assertStrictEquals(toLength(0.25), 0);
+ assertStrictEquals(toLength(1.1), 1);
+ });
+
+ it("[[Call]] returns a result greater than or equal to zero", () => {
+ assertStrictEquals(toLength(-0), 0);
+ assertStrictEquals(toLength(-1), 0);
+ assertStrictEquals(toLength(-Infinity), 0);
+ });
+
+ it("[[Call]] returns a result less than 2 ** 53", () => {
+ assertStrictEquals(toLength(9007199254740992), 9007199254740991);
+ assertStrictEquals(toLength(Infinity), 9007199254740991);
+ });
+
+ it("[[Construct]] throws an error", () => {
+ assertThrows(() => new toLength(0));
+ });
+
+ describe(".length", () => {
+ it("[[Get]] returns the correct length", () => {
+ assertStrictEquals(toLength.length, 1);
+ });
+ });
+
+ describe(".name", () => {
+ it("[[Get]] returns the correct name", () => {
+ assertStrictEquals(toLength.name, "toLength");
+ });
+ });
+});
+
describe("toPrimitive", () => {
it("[[Call]] returns the argument when passed a primitive", () => {
const value = Symbol();