@arkstack/common 0.12.16 → 0.12.18

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-Y1a3rhA3.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,13 +134,40 @@ 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 TraitMethodHelpers = {
138
+ getTraitMethods: <T extends TraitMethod = TraitMethod>(name: PropertyKey) => T[];
139
+ callTraitMethods: <T = any>(name: PropertyKey, ...args: any[]) => T[];
140
+ };
141
+ type DeriveTraitsWithMethodHelpers<T extends ((Trait | TypeFactory<Trait>)[] | [...(Trait | TypeFactory<Trait>)[], DirectBase])> = DeriveTraits<T> extends (new (...args: infer Args) => infer Instance) ? (new (...args: Args) => Instance & TraitMethodHelpers) & Omit<DeriveTraits<T>, 'prototype'> & TraitMethodHelpers : never;
142
+ type TraitMethod = (...args: any[]) => any;
143
+ /**
144
+ * Return every trait implementation for a method, bound to the supplied
145
+ * instance or class. Methods are ordered from the base implementation to the
146
+ * currently active trait implementation.
147
+ *
148
+ * @param target
149
+ * @param name
150
+ * @returns
151
+ */
152
+ declare const getTraitMethods: <T extends TraitMethod = TraitMethod>(target: object | Cons, name: PropertyKey) => T[];
153
+ /**
154
+ * Invoke every trait implementation for a method in registration order.
155
+ *
156
+ * @param target
157
+ * @param name
158
+ * @param args
159
+ * @returns
160
+ */
161
+ declare const callTraitMethods: <T = any>(target: object | Cons, name: PropertyKey, ...args: any[]) => T[];
162
+ type UsableTraits = ([Trait | TypeFactory<Trait>, ...(Trait | TypeFactory<Trait>)[]] | [...(Trait | TypeFactory<Trait>)[], DirectBase]);
137
163
  /**
138
164
  * API: derive a class from one or more traits or trait type factories
139
165
  *
140
166
  * @param traits
141
167
  * @returns
142
168
  */
143
- declare function use<T extends ([Trait | TypeFactory<Trait>, ...(Trait | TypeFactory<Trait>)[]] | [...(Trait | TypeFactory<Trait>)[], DirectBase])>(...traits: T): DeriveTraits<T>;
169
+ declare function use<T extends UsableTraits>(withMethodHelpers: true, ...traits: T): DeriveTraitsWithMethodHelpers<T>;
170
+ declare function use<T extends UsableTraits>(...traits: T): DeriveTraits<T>;
144
171
  /**
145
172
  * internal type: implements trait type
146
173
  */
@@ -158,4 +185,4 @@ type Derived<T extends (Trait | TypeFactory<Trait> | Cons)> = T extends TypeFact
158
185
  */
159
186
  declare function uses<T extends (Trait | TypeFactory<Trait> | Cons)>(instance: unknown, trait: T): instance is Derived<T>;
160
187
  //#endregion
161
- export { AbstractModelConstructor, Derived, Encryption, Hash, ModelConstructor, ModelRegistry, Trait, abort, abortIf, assertFound, crc32, getModel, initializeGlobalContext, isClass, perPage, trait, use, uses };
188
+ 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-Y1a3rhA3.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
@@ -452,30 +523,40 @@ const deriveTrait = (trait$, baseClz, derived) => {
452
523
  * @returns
453
524
  */
454
525
  const reverseTraitList = (traits) => traits.slice().reverse();
455
- /**
456
- * API: derive a class from one or more traits or trait type factories
457
- *
458
- * @param traits
459
- * @returns
460
- */
461
- function use(...traits) {
526
+ function use(...args) {
527
+ const withMethodHelpers = args[0] === true;
528
+ const traits = withMethodHelpers ? args.slice(1) : args;
462
529
  if (traits.length === 0) throw new Error("invalid number of parameters (expected one or more traits)");
463
- let clz;
530
+ let classInstance;
464
531
  let lot;
465
532
  const last = traits[traits.length - 1];
466
533
  if (isCons(last) && !isTypeFactory(last)) {
467
- clz = last;
534
+ classInstance = last;
468
535
  lot = traits.slice(0, -1);
469
536
  } else if (isArkormModelInstance(last)) {
470
- clz = last.constructor;
537
+ classInstance = last.constructor;
471
538
  lot = traits.slice(0, -1);
472
539
  } else {
473
- clz = class ROOT {};
540
+ classInstance = class ROOT {};
474
541
  lot = traits;
475
542
  }
476
543
  const derived = /* @__PURE__ */ new Map();
477
- for (const trait of reverseTraitList(lot)) clz = deriveTrait(trait, clz, derived);
478
- return clz;
544
+ for (const trait of reverseTraitList(lot)) classInstance = deriveTrait(trait, classInstance, derived);
545
+ if (withMethodHelpers) classInstance = class TraitMethodEnabled extends classInstance {
546
+ getTraitMethods(name) {
547
+ return getTraitMethods(this, name);
548
+ }
549
+ callTraitMethods(name, ...args) {
550
+ return callTraitMethods(this, name, ...args);
551
+ }
552
+ static getTraitMethods(name) {
553
+ return getTraitMethods(this, name);
554
+ }
555
+ static callTraitMethods(name, ...args) {
556
+ return callTraitMethods(this, name, ...args);
557
+ }
558
+ };
559
+ return classInstance;
479
560
  }
480
561
  /**
481
562
  * API: type guard for checking whether class instance is derived from a trait
@@ -498,4 +579,4 @@ function uses(instance, trait) {
498
579
  return false;
499
580
  }
500
581
  //#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 };
582
+ 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.16",
3
+ "version": "0.12.18",
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.5.0",
45
- "@arkstack/foundry": "^0.12.16",
46
- "@arkstack/contract": "^0.12.16"
44
+ "arkormx": "^2.5.2",
45
+ "@arkstack/foundry": "^0.12.18",
46
+ "@arkstack/contract": "^0.12.18"
47
47
  },
48
48
  "scripts": {
49
49
  "build": "tsdown --config-loader unrun",