From: Lady Date: Sun, 19 Nov 2023 16:04:12 +0000 (-0500) Subject: Move arraylike functions into object.js X-Git-Url: https://git.ladys.computer/Pisces/commitdiff_plain/e272aec320bec47125cd7922e1d1ed5f65e37e1f Move arraylike functions into object.js Arraylikes are treated as objects, even when they aren’t literally objects (e·g strings). `isArraylikeObject` notably checks for both. --- diff --git a/collection.js b/collection.js index 69c0bee..03326a6 100644 --- a/collection.js +++ b/collection.js @@ -8,7 +8,7 @@ // file, You can obtain one at . import { call, createCallableFunction } from "./function.js"; -import { lengthOfArraylike, toIndex, type } from "./value.js"; +import { toIndex, type } from "./value.js"; const { prototype: arrayPrototype } = Array; @@ -193,19 +193,6 @@ export const indices = createCallableFunction( "indices", ); -/** Returns whether the provided value is arraylike. */ -export const isArraylikeObject = ($) => { - if (type($) !== "object") { - return false; - } else { - try { - lengthOfArraylike($); // throws if not arraylike - return true; - } catch { - return false; - } - } -}; /** * Returns whether the provided object is a collection. diff --git a/collection.test.js b/collection.test.js index acd90d2..779b4ca 100644 --- a/collection.test.js +++ b/collection.test.js @@ -18,7 +18,6 @@ import { } from "./dev-deps.js"; import { findIndexedEntry, - isArraylikeObject, isCollection, isConcatSpreadable, } from "./collection.js"; @@ -79,39 +78,6 @@ describe("findIndexedEntry", () => { }); }); -describe("isArraylikeObject", () => { - it("[[Call]] returns false for primitives", () => { - assertStrictEquals(isArraylikeObject("failure"), false); - }); - - it("[[Call]] returns false if length throws", () => { - assertStrictEquals( - isArraylikeObject({ - get length() { - throw void {}; - }, - }), - false, - ); - }); - - it("[[Call]] returns false if length is not a number and cannot be converted to one", () => { - assertStrictEquals(isArraylikeObject({ length: 1n }), false); - }); - - it("[[Call]] returns true if length is convertable to a number", () => { - assertStrictEquals(isArraylikeObject({ length: -0 }), true); - assertStrictEquals(isArraylikeObject({ length: 1 }), true); - assertStrictEquals(isArraylikeObject({ length: -1.25 }), true); - assertStrictEquals( - isArraylikeObject({ length: 9007199254740992 }), - true, - ); - assertStrictEquals(isArraylikeObject({ length: Infinity }), true); - assertStrictEquals(isArraylikeObject({ length: "success" }), true); - }); -}); - describe("isCollection", () => { it("[[Call]] returns false for primitives", () => { assertStrictEquals(isCollection("failure"), false); diff --git a/object.js b/object.js index 83519fd..3052f15 100644 --- a/object.js +++ b/object.js @@ -13,7 +13,13 @@ import { createArrowFunction, toFunctionName, } from "./function.js"; -import { ITERATOR, SPECIES, toPrimitive, type } from "./value.js"; +import { + ITERATOR, + SPECIES, + toLength, + toPrimitive, + type, +} from "./value.js"; /** * An object whose properties are lazy‐loaded from the methods on the @@ -804,6 +810,20 @@ export const hasOwnProperty = createArrowFunction(Object.hasOwn, { name: "hasOwnProperty", }); +/** Returns whether the provided value is an arraylike object. */ +export const isArraylikeObject = ($) => { + if (type($) !== "object") { + return false; + } else { + try { + lengthOfArraylike($); // throws if not arraylike + return true; + } catch { + return false; + } + } +}; + /** * Returns whether the provided object is extensible. * @@ -816,6 +836,16 @@ export const isExtensibleObject = createArrowFunction( { name: "isExtensibleObject" }, ); +/** + * 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); + /** * Returns an array of key~value pairs for the enumerable, * string‐valued property keys on the provided object. diff --git a/object.test.js b/object.test.js index d5a60bb..fc62be3 100644 --- a/object.test.js +++ b/object.test.js @@ -34,10 +34,12 @@ import { getPrototype, hasOwnProperty, hasProperty, + isArraylikeObject, isExtensibleObject, isUnfrozenObject, isUnsealedObject, LazyLoader, + lengthOfArraylike, namedEntries, namedKeys, namedValues, @@ -1534,6 +1536,58 @@ describe("hasOwnProperty", () => { }); }); +describe("isArraylikeObject", () => { + it("[[Call]] returns false for primitives", () => { + assertStrictEquals(isArraylikeObject("failure"), false); + }); + + it("[[Call]] returns false if length throws", () => { + assertStrictEquals( + isArraylikeObject({ + get length() { + throw void {}; + }, + }), + false, + ); + }); + + it("[[Call]] returns false if length is not a number and cannot be converted to one", () => { + assertStrictEquals(isArraylikeObject({ length: 1n }), false); + }); + + it("[[Call]] returns true if length is convertable to a number", () => { + assertStrictEquals(isArraylikeObject({ length: -0 }), true); + assertStrictEquals(isArraylikeObject({ length: 1 }), true); + assertStrictEquals(isArraylikeObject({ length: -1.25 }), true); + assertStrictEquals( + isArraylikeObject({ length: 9007199254740992 }), + true, + ); + assertStrictEquals(isArraylikeObject({ length: Infinity }), true); + assertStrictEquals(isArraylikeObject({ length: "success" }), true); + }); + + it("[[Construct]] throws an error", () => { + assertThrows(() => new isArraylikeObject({})); + }); + + describe(".length", () => { + it("[[Get]] returns the correct length", () => { + assertStrictEquals(isArraylikeObject.length, 1); + }); + }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals( + isArraylikeObject.name, + "isArraylikeObject", + ); + }); + }); +}); + describe("isExtensibleObject", () => { it("[[Call]] returns true for extensible objects", () => { assertStrictEquals(isExtensibleObject({}), true); @@ -1648,6 +1702,63 @@ describe("isUnsealedObject", () => { }); }); +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("namedEntries", () => { it("[[Call]] gets named entries", () => { assertEquals(namedEntries({ success: true }), [["success", true]]); diff --git a/value.js b/value.js index 4e46f63..d552fdc 100644 --- a/value.js +++ b/value.js @@ -51,16 +51,6 @@ export const NULL = null; /** The undefined primitive. */ export const UNDEFINED = 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 diff --git a/value.test.js b/value.test.js index d68ff65..88d727b 100644 --- a/value.test.js +++ b/value.test.js @@ -18,7 +18,6 @@ import { HAS_INSTANCE, IS_CONCAT_SPREADABLE, ITERATOR, - lengthOfArraylike, MATCH, MATCH_ALL, NULL, @@ -125,63 +124,6 @@ describe("UNSCOPABLES", () => { }); }); -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 = {