]> Lady’s Gitweb - Pisces/blobdiff - object.js
Add toIntegralNumber to numeric.js
[Pisces] / object.js
index 578f84f5201f9d46907cc77ba36a30d1c984ddcb..f68909e659c54aad765e93abc816ac2a480154f0 100644 (file)
--- a/object.js
+++ b/object.js
 import { bind, call } from "./function.js";
 import { toPrimitive, type } from "./value.js";
 
+/**
+ * An object whose properties are lazy‐loaded from the methods on the
+ * own properties of the provided object.
+ *
+ * This is useful when you are looking to reference properties on
+ * objects which, due to module dependency graphs, cannot be guaranteed
+ * to have been initialized yet.
+ *
+ * The resulting properties will have the same attributes (regarding
+ * configurability, enumerability, and writability) as the
+ * corresponding properties on the methods object. If a property is
+ * marked as writable, the method will never be called if it is set
+ * before it is gotten. By necessity, the resulting properties are all
+ * configurable before they are accessed for the first time.
+ *
+ * Methods will be called with the resulting object as their this
+ * value.
+ *
+ * LazyLoader objects have the same prototype as the passed methods
+ * object.
+ */
+export class LazyLoader extends null {
+  /** Constructs a new LazyLoader object. */
+  constructor(loadMethods) {
+    const result = objectCreate(getPrototype(loadMethods));
+    const methodKeys = getOwnPropertyKeys(loadMethods);
+    for (let index = 0; index < methodKeys.length; ++index) {
+      const methodKey = methodKeys[index];
+      const { configurable, enumerable, writable } =
+        getOwnPropertyDescriptor(loadMethods, methodKey);
+      defineOwnProperty(result, methodKey, {
+        configurable: true,
+        enumerable,
+        get: () => {
+          const value = call(loadMethods[methodKey], result, []);
+          defineOwnProperty(result, methodKey, {
+            configurable,
+            enumerable,
+            value,
+            writable,
+          });
+          return value;
+        },
+        set: writable
+          ? ($) =>
+            defineOwnProperty(result, methodKey, {
+              configurable,
+              enumerable,
+              value: $,
+              writable,
+            })
+          : void {},
+      });
+    }
+    return result;
+  }
+}
+
 /**
  * A property descriptor object.
  *
@@ -515,26 +573,62 @@ export const {
    * Removes the provided property key from the provided object and
    * returns the object.
    *
-   *  This function differs from Reflect.deleteProperty and the
+   *  This function differs from Reflect.deleteProperty and the
    * `delete` operator in that it throws if the deletion is
    * unsuccessful.
+   *
+   * ※ This function throws if the first argument is not an object.
    */
   deleteOwnProperty,
 
+  /**
+   * Returns an array of property keys on the provided object.
+   *
+   * ※ This is effectively an alias for Reflect.ownKeys, except that
+   * it does not require that the argument be an object.
+   */
+  getOwnPropertyKeys,
+
+  /**
+   * Returns the value of the provided property key on the provided
+   * object.
+   *
+   * ※ This is effectively an alias for Reflect.get, except that it
+   * does not require that the argument be an object.
+   */
+  getPropertyValue,
+
+  /**
+   * Returns whether the provided property key exists on the provided
+   * object.
+   *
+   * ※ This is effectively an alias for Reflect.has, except that it
+   * does not require that the argument be an object.
+   *
+   * ※ This includes properties present on the prototype chain.
+   */
+  hasProperty,
+
   /**
    * Sets the provided property key to the provided value on the
    * provided object and returns the object.
    *
    * ※ This function differs from Reflect.set in that it throws if the
    * setting is unsuccessful.
+   *
+   * ※ This function throws if the first argument is not an object.
    */
   setPropertyValue,
 } = (() => {
-  const { deleteProperty, set } = Reflect;
+  const { deleteProperty, get, has, ownKeys, set } = Reflect;
 
   return {
     deleteOwnProperty: (O, P) => {
-      if (!deleteProperty(O, P)) {
+      if (type(O) !== "object") {
+        throw new TypeError(
+          `Piscēs: Tried to set property but provided value was not an object: ${V}`,
+        );
+      } else if (!deleteProperty(O, P)) {
         throw new TypeError(
           `Piscēs: Tried to delete property from object but [[Delete]] returned false: ${P}`,
         );
@@ -542,8 +636,16 @@ export const {
         return O;
       }
     },
+    getOwnPropertyKeys: (O) => ownKeys(toObject(O)),
+    getPropertyValue: (O, P, Receiver = O) =>
+      get(toObject(O), P, Receiver),
+    hasProperty: (O, P) => has(toObject(O), P),
     setPropertyValue: (O, P, V, Receiver = O) => {
-      if (!set(O, P, V, Receiver)) {
+      if (type(O) !== "object") {
+        throw new TypeError(
+          `Piscēs: Tried to set property but provided value was not an object: ${V}`,
+        );
+      } else if (!set(O, P, V, Receiver)) {
         throw new TypeError(
           `Piscēs: Tried to set property on object but [[Set]] returned false: ${P}`,
         );
@@ -656,46 +758,38 @@ export const {
   };
 })();
 
-export const {
-  /**
-   * Returns an array of property keys on the provided object.
-   *
-   * ※ This is an alias for Reflect.ownKeys.
-   */
-  ownKeys: getOwnPropertyKeys,
-
-  /**
-   * Returns the value of the provided property key on the provided
-   * object.
-   *
-   * ※ This is an alias for Reflect.get.
-   */
-  get: getPropertyValue,
-
-  /**
-   * Returns whether the provided property key exists on the provided
-   * object.
-   *
-   * ※ This is an alias for Reflect.has.
-   *
-   * ※ This includes properties present on the prototype chain.
-   */
-  has: hasProperty,
-} = Reflect;
+export const getMethod = (V, P) => {
+  const func = getPropertyValue(V, P);
+  if (func == null) {
+    return undefined;
+  } else if (typeof func !== "function") {
+    throw new TypeError(`Piscēs: Method not callable: ${P}`);
+  } else {
+    return func;
+  }
+};
 
 /**
  * Returns the provided value converted to an object.
  *
- * Null and undefined are converted to a new, empty object. Other
- * primitives are wrapped. Existing objects are returned with no
- * modification.
+ * Existing objects are returned with no modification.
  *
- * ※ This is effectively a nonconstructible version of the Object
- * constructor.
+ * ☡ This function throws a TypeError if its argument is null or
+ * undefined.
  */
 export const { toObject } = (() => {
   const makeObject = Object;
-  return { toObject: ($) => makeObject($) };
+  return {
+    toObject: ($) => {
+      if ($ == null) {
+        throw new TypeError(
+          `Piscēs: Cannot convert ${$} into an object.`,
+        );
+      } else {
+        return makeObject($);
+      }
+    },
+  };
 })();
 
 /**
This page took 0.023367 seconds and 4 git commands to generate.