@arkstack/common 0.12.15 → 0.12.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { C as nodeEnv, S as interopDefault, _ as CONFIG_KEY, a as abort, b as env, c as getModel, d as perPage, f as RequestException, g as Encryption, h as Hash, l as initializeGlobalContext, m as Exception, o as abortIf, p as AppException, s as assertFound, u as isClass, v as appUrl, w as outputDir, x as importFile, y as config } from "./utils-CMuDt6cA.js";
1
+ import { C as importFile, E as outputDir, S as env, T as nodeEnv, _ as Hash, b as appUrl, c as abortIf, d as initializeGlobalContext, f as isClass, g as Exception, h as AppException, l as assertFound, m as RequestException, p as perPage, s as abort, u as getModel, v as Encryption, w as interopDefault, x as config, y as CONFIG_KEY } from "./utils-DVFdK8BR.js";
2
2
  import { Hook as Hook$1 } from "@arkstack/foundry";
3
3
  import { str } from "@h3ravel/support";
4
4
  import { Arkstack } from "@arkstack/contract";
@@ -134,6 +134,26 @@ type DeriveTraitsStats<T extends ((Trait | TypeFactory<Trait>)[] | [...(Trait |
134
134
  * utility type: derive type from one or more traits or trait type factories
135
135
  */
136
136
  type DeriveTraits<T extends ((Trait | TypeFactory<Trait>)[] | [...(Trait | TypeFactory<Trait>)[], DirectBase])> = DeriveTraitsCons<T> & DeriveTraitsStats<T>;
137
+ type TraitMethod = (...args: any[]) => any;
138
+ /**
139
+ * Return every trait implementation for a method, bound to the supplied
140
+ * instance or class. Methods are ordered from the base implementation to the
141
+ * currently active trait implementation.
142
+ *
143
+ * @param target
144
+ * @param name
145
+ * @returns
146
+ */
147
+ declare const getTraitMethods: <T extends TraitMethod = TraitMethod>(target: object | Cons, name: PropertyKey) => T[];
148
+ /**
149
+ * Invoke every trait implementation for a method in registration order.
150
+ *
151
+ * @param target
152
+ * @param name
153
+ * @param args
154
+ * @returns
155
+ */
156
+ declare const callTraitMethods: <T = any>(target: object | Cons, name: PropertyKey, ...args: any[]) => T[];
137
157
  /**
138
158
  * API: derive a class from one or more traits or trait type factories
139
159
  *
@@ -158,4 +178,4 @@ type Derived<T extends (Trait | TypeFactory<Trait> | Cons)> = T extends TypeFact
158
178
  */
159
179
  declare function uses<T extends (Trait | TypeFactory<Trait> | Cons)>(instance: unknown, trait: T): instance is Derived<T>;
160
180
  //#endregion
161
- export { AbstractModelConstructor, Derived, Encryption, Hash, ModelConstructor, ModelRegistry, Trait, abort, abortIf, assertFound, crc32, getModel, initializeGlobalContext, isClass, perPage, trait, use, uses };
181
+ export { AbstractModelConstructor, Derived, Encryption, Hash, ModelConstructor, ModelRegistry, Trait, abort, abortIf, assertFound, callTraitMethods, crc32, getModel, getTraitMethods, initializeGlobalContext, isClass, perPage, trait, use, uses };
@@ -1,2 +1,2 @@
1
- import { a as abort, c as getModel, d as perPage, g as Encryption, h as Hash, i as uses, l as initializeGlobalContext, n as trait, o as abortIf, r as use, s as assertFound, t as crc32, u as isClass } from "../utils-CMuDt6cA.js";
2
- export { Encryption, Hash, abort, abortIf, assertFound, crc32, getModel, initializeGlobalContext, isClass, perPage, trait, use, uses };
1
+ import { _ as Hash, a as use, c as abortIf, d as initializeGlobalContext, f as isClass, i as trait, l as assertFound, n as crc32, o as uses, p as perPage, r as getTraitMethods, s as abort, t as callTraitMethods, u as getModel, v as Encryption } from "../utils-DVFdK8BR.js";
2
+ export { Encryption, Hash, abort, abortIf, assertFound, callTraitMethods, crc32, getModel, getTraitMethods, initializeGlobalContext, isClass, perPage, trait, use, uses };
@@ -418,6 +418,75 @@ const extendProperties = (cons, field, value) => Object.defineProperty(cons, fie
418
418
  enumerable: false,
419
419
  writable: false
420
420
  });
421
+ const traitMethodRegistry = Symbol("trait-method-registry");
422
+ const cloneMethodRegistry = (target) => {
423
+ const registry = target[traitMethodRegistry];
424
+ return new Map([...registry?.entries() ?? []].map(([name, methods]) => [name, [...methods]]));
425
+ };
426
+ const registerMethodScope = (target, base, ignored) => {
427
+ const registry = cloneMethodRegistry(base);
428
+ for (const name of Reflect.ownKeys(target)) {
429
+ if (ignored.has(name)) continue;
430
+ const method = Object.getOwnPropertyDescriptor(target, name)?.value;
431
+ if (typeof method !== "function") continue;
432
+ const methods = registry.get(name);
433
+ const previous = base?.[name];
434
+ if (methods) {
435
+ if (methods.at(-1) !== method) methods.push(method);
436
+ registry.set(name, methods);
437
+ } else if (typeof previous === "function" && previous !== method) registry.set(name, [previous, method]);
438
+ }
439
+ Object.defineProperty(target, traitMethodRegistry, {
440
+ configurable: false,
441
+ enumerable: false,
442
+ value: registry,
443
+ writable: false
444
+ });
445
+ };
446
+ /**
447
+ * Registers conflicting trait methods
448
+ *
449
+ * @param classInstance
450
+ * @param baseClass
451
+ */
452
+ const registerTraitMethods = (classInstance, baseClass) => {
453
+ registerMethodScope(classInstance.prototype, baseClass.prototype, new Set(["constructor"]));
454
+ registerMethodScope(classInstance, baseClass, new Set([
455
+ "length",
456
+ "name",
457
+ "prototype",
458
+ "arguments",
459
+ "caller"
460
+ ]));
461
+ };
462
+ /**
463
+ * Return every trait implementation for a method, bound to the supplied
464
+ * instance or class. Methods are ordered from the base implementation to the
465
+ * currently active trait implementation.
466
+ *
467
+ * @param target
468
+ * @param name
469
+ * @returns
470
+ */
471
+ const getTraitMethods = (target, name) => {
472
+ return (((typeof target === "function" ? target : Object.getPrototypeOf(target))?.[traitMethodRegistry])?.get(name) ?? []).map((method) => method.bind(target));
473
+ };
474
+ /**
475
+ * Invoke every trait implementation for a method in registration order.
476
+ *
477
+ * @param target
478
+ * @param name
479
+ * @param args
480
+ * @returns
481
+ */
482
+ const callTraitMethods = (target, name, ...args) => {
483
+ const methods = getTraitMethods(target, name);
484
+ if (methods.length === 0) {
485
+ console.warn(`No conflicting trait methods found for "${String(name)}".`);
486
+ return [];
487
+ }
488
+ return methods.map((method) => method(...args));
489
+ };
421
490
  /**
422
491
  * utility function: get raw trait
423
492
  *
@@ -429,21 +498,23 @@ const rawTrait = (x) => isTypeFactory(x) ? x() : x;
429
498
  * utility function: derive a trait
430
499
  *
431
500
  * @param trait$
432
- * @param baseClz
501
+ * @param baseClass
433
502
  * @param derived
434
503
  * @returns
435
504
  */
436
- const deriveTrait = (trait$, baseClz, derived) => {
505
+ const deriveTrait = (trait$, baseClass, derived) => {
437
506
  const trait = rawTrait(trait$);
438
- let clz = baseClz;
507
+ let classInstance = baseClass;
439
508
  if (!derived.has(trait.id)) {
440
509
  derived.set(trait.id, true);
441
- if (trait.superTraits !== void 0) for (const superTrait of reverseTraitList(trait.superTraits)) clz = deriveTrait(superTrait, clz, derived);
442
- clz = trait.factory(clz);
443
- extendProperties(clz, "id", crc32(trait.factory.toString()));
444
- extendProperties(clz, trait.symbol, true);
510
+ if (trait.superTraits !== void 0) for (const superTrait of reverseTraitList(trait.superTraits)) classInstance = deriveTrait(superTrait, classInstance, derived);
511
+ const base = classInstance;
512
+ classInstance = trait.factory(classInstance);
513
+ registerTraitMethods(classInstance, base);
514
+ extendProperties(classInstance, "id", crc32(trait.factory.toString()));
515
+ extendProperties(classInstance, trait.symbol, true);
445
516
  }
446
- return clz;
517
+ return classInstance;
447
518
  };
448
519
  /**
449
520
  * utility function: get reversed trait list
@@ -460,22 +531,22 @@ const reverseTraitList = (traits) => traits.slice().reverse();
460
531
  */
461
532
  function use(...traits) {
462
533
  if (traits.length === 0) throw new Error("invalid number of parameters (expected one or more traits)");
463
- let clz;
534
+ let classInstance;
464
535
  let lot;
465
536
  const last = traits[traits.length - 1];
466
537
  if (isCons(last) && !isTypeFactory(last)) {
467
- clz = last;
538
+ classInstance = last;
468
539
  lot = traits.slice(0, -1);
469
540
  } else if (isArkormModelInstance(last)) {
470
- clz = last.constructor;
541
+ classInstance = last.constructor;
471
542
  lot = traits.slice(0, -1);
472
543
  } else {
473
- clz = class ROOT {};
544
+ classInstance = class ROOT {};
474
545
  lot = traits;
475
546
  }
476
547
  const derived = /* @__PURE__ */ new Map();
477
- for (const trait of reverseTraitList(lot)) clz = deriveTrait(trait, clz, derived);
478
- return clz;
548
+ for (const trait of reverseTraitList(lot)) classInstance = deriveTrait(trait, classInstance, derived);
549
+ return classInstance;
479
550
  }
480
551
  /**
481
552
  * API: type guard for checking whether class instance is derived from a trait
@@ -498,4 +569,4 @@ function uses(instance, trait) {
498
569
  return false;
499
570
  }
500
571
  //#endregion
501
- export { nodeEnv as C, interopDefault as S, CONFIG_KEY as _, abort as a, env as b, getModel as c, perPage as d, RequestException as f, Encryption as g, Hash as h, uses as i, initializeGlobalContext as l, Exception as m, trait as n, abortIf as o, AppException as p, use as r, assertFound as s, crc32 as t, isClass as u, appUrl as v, outputDir as w, importFile as x, config as y };
572
+ export { importFile as C, outputDir as E, env as S, nodeEnv as T, Hash as _, use as a, appUrl as b, abortIf as c, initializeGlobalContext as d, isClass as f, Exception as g, AppException as h, trait as i, assertFound as l, RequestException as m, crc32 as n, uses as o, perPage as p, getTraitMethods as r, abort as s, callTraitMethods as t, getModel as u, Encryption as v, interopDefault as w, config as x, CONFIG_KEY as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkstack/common",
3
- "version": "0.12.15",
3
+ "version": "0.12.17",
4
4
  "type": "module",
5
5
  "description": "Core utilities, primitives, and shared infrastructure for the Arkstack ecosystem.",
6
6
  "homepage": "https://arkstack.toneflix.net",
@@ -41,9 +41,9 @@
41
41
  },
42
42
  "peerDependencies": {
43
43
  "@h3ravel/support": "^0.15.11",
44
- "arkormx": "^ 2.4.4",
45
- "@arkstack/foundry": "^0.12.15",
46
- "@arkstack/contract": "^0.12.15"
44
+ "arkormx": "^2.5.2",
45
+ "@arkstack/foundry": "^0.12.17",
46
+ "@arkstack/contract": "^0.12.17"
47
47
  },
48
48
  "scripts": {
49
49
  "build": "tsdown --config-loader unrun",