-export const { PropertyDescriptor } = (() => {
- class PropertyDescriptor extends null {
- /**
- * Constructs a new property descriptor object from the provided
- * object.
- *
- * The resulting object is proxied to enforce types (for example,
- * its `enumerable` property, if defined, will always be a
- * boolean).
- */
- //deno-lint-ignore constructor-super
- constructor(O) {
- if (type(O) !== "object") {
- // The provided value is not an object.
- throw new TypeError(
- "Piscēs: Cannot convert primitive to property descriptor.",
- );
- } else {
- // The provided value is an object.
- const desc = objectCreate(propertyDescriptorPrototype);
- if ("enumerable" in O) {
- // An enumerable property is specified.
- desc.enumerable = !!O.enumerable;
- } else {
- // An enumerable property is not specified.
- /* do nothing */
- }
- if ("configurable" in O) {
- // A configurable property is specified.
- desc.configurable = !!O.configurable;
- } else {
- // A configurable property is not specified.
- /* do nothing */
- }
- if ("value" in O) {
- // A value property is specified.
- desc.value = O.value;
- } else {
- // A value property is not specified.
- /* do nothing */
- }
- if ("writable" in O) {
- // A writable property is specified.
- desc.writable = !!O.writable;
- } else {
- // A writable property is not specified.
- /* do nothing */
- }
- if ("get" in O) {
- // A get property is specified.
- const getter = O.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.
- desc.get = getter;
- }
- } else {
- // A get property is not specified.
- /* do nothing */
- }
- if ("set" in O) {
- // A set property is specified.
- const setter = O.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.
- desc.set = setter;
- }
- } 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.
- return new Proxy(desc, propertyDescriptorProxyHandler);
- }
- }
- }
-
- /**
- * Completes this property descriptor by setting missing values to
- * their defaults.
- *
- * This method modifies this object and returns undefined.
- */
- complete() {
- if (this !== undefined && !("get" in this || "set" in this)) {
- // This is a generic or data descriptor.
- if (!("value" in this)) {
- // `value` is not defined on this.
- this.value = undefined;
- } else {
- // `value` is already defined on this.
- /* do nothing */
- }
- if (!("writable" in this)) {
- // `writable` is not defined on this.
- this.writable = false;
- } else {
- // `writable` is already defined on this.
- /* do nothing */
- }
- } else {
- // This is not a generic or data descriptor.
- if (!("get" in this)) {
- // `get` is not defined on this.
- this.get = undefined;
- } else {
- // `get` is already defined on this.
- /* do nothing */
- }
- if (!("set" in this)) {
- // `set` is not defined on this.
- this.set = undefined;
- } else {
- // `set` is already defined on this.
- /* do nothing */
- }
- }
- if (!("enumerable" in this)) {
- // `enumerable` is not defined on this.
- this.enumerable = false;
- } else {
- // `enumerable` is already defined on this.
- /* do nothing */
- }
- if (!("configurable" in this)) {
- // `configurable` is not defined on this.
- this.configurable = false;
- } else {
- // `configurable` is already defined on this.
- /* do nothing */
+export class LazyLoader extends null {
+ /**
+ * Constructs a new `LazyLoader` object.
+ *
+ * ☡ This function throws if the provided value is not an object.
+ */
+ constructor(loadMethods) {
+ if (type(loadMethods) !== "object") {
+ // The provided value is not an object; throw an error.
+ throw new TypeError(
+ `Piscēs: Cannot construct LazyLoader: Provided argument is not an object: ${loadMethods}.`,
+ );
+ } else {
+ // The provided value is an object; process it and build the
+ // result.
+ const result = objectCreate(getPrototype(loadMethods));
+ const methodKeys = getOwnPropertyKeys(loadMethods);
+ for (let index = 0; index < methodKeys.length; ++index) {
+ // Iterate over the property keys of the provided object and
+ // define getters and setters appropriately on the result.
+ const methodKey = methodKeys[index];
+ const { configurable, enumerable, writable } =
+ getOwnPropertyDescriptor(loadMethods, methodKey);
+ defineOwnProperty(result, methodKey, {
+ configurable: true,
+ enumerable,
+ get: defineOwnProperty(
+ () => {
+ const value = call(loadMethods[methodKey], result, []);
+ defineOwnProperty(result, methodKey, {
+ configurable,
+ enumerable,
+ value,
+ writable,
+ });
+ return value;
+ },
+ "name",
+ { value: toFunctionName(methodKey, "get") },
+ ),
+ set: writable
+ ? defineOwnProperty(
+ ($) =>
+ defineOwnProperty(result, methodKey, {
+ configurable,
+ enumerable,
+ value: $,
+ writable,
+ }),
+ "name",
+ { value: toFunctionName(methodKey, "set") },
+ )
+ : void {},
+ });