From: Lady <redacted>
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?ds=sidebyside

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 <https://mozilla.org/MPL/2.0/>.
 
 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 = {