@layerzerolabs/base-definitions 0.0.1 → 0.0.5

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.
Files changed (66) hide show
  1. package/.turbo/turbo-build.log +54 -37
  2. package/.turbo/turbo-lint.log +4 -0
  3. package/.turbo/turbo-test.log +14 -0
  4. package/dist/2W6KYHJN.cjs +38 -0
  5. package/dist/2W6KYHJN.cjs.map +1 -0
  6. package/dist/67HCA6YT.cjs +64 -0
  7. package/dist/67HCA6YT.cjs.map +1 -0
  8. package/dist/B2JM5RKU.cjs +17 -0
  9. package/dist/B2JM5RKU.cjs.map +1 -0
  10. package/dist/ISLTTWBQ.js +15 -0
  11. package/dist/ISLTTWBQ.js.map +1 -0
  12. package/dist/O4SGLGEI.js +62 -0
  13. package/dist/O4SGLGEI.js.map +1 -0
  14. package/dist/PLNCBQCW.js +34 -0
  15. package/dist/PLNCBQCW.js.map +1 -0
  16. package/dist/S2FOVFOI.js +134 -0
  17. package/dist/S2FOVFOI.js.map +1 -0
  18. package/dist/VO33UEHJ.cjs +136 -0
  19. package/dist/VO33UEHJ.cjs.map +1 -0
  20. package/dist/VUOMXK5T.js +6 -0
  21. package/dist/VUOMXK5T.js.map +1 -0
  22. package/dist/YJF4D23A.cjs +8 -0
  23. package/dist/YJF4D23A.cjs.map +1 -0
  24. package/dist/definitions.cjs +8 -4
  25. package/dist/definitions.d.ts +80 -39
  26. package/dist/definitions.d.ts.map +1 -1
  27. package/dist/definitions.js +2 -2
  28. package/dist/index.cjs +21 -7
  29. package/dist/index.d.ts +2 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +5 -3
  32. package/dist/lzyringe.cjs +13 -0
  33. package/dist/lzyringe.cjs.map +1 -0
  34. package/dist/lzyringe.d.ts +24 -0
  35. package/dist/lzyringe.d.ts.map +1 -0
  36. package/dist/lzyringe.js +4 -0
  37. package/dist/lzyringe.js.map +1 -0
  38. package/dist/registrarBuilder.cjs +3 -3
  39. package/dist/registrarBuilder.d.ts +35 -3
  40. package/dist/registrarBuilder.d.ts.map +1 -1
  41. package/dist/registrarBuilder.js +2 -2
  42. package/dist/utils.cjs +14 -0
  43. package/dist/utils.cjs.map +1 -0
  44. package/dist/utils.d.ts +4 -0
  45. package/dist/utils.d.ts.map +1 -0
  46. package/dist/utils.js +5 -0
  47. package/dist/utils.js.map +1 -0
  48. package/package.json +10 -10
  49. package/src/definitions.ts +134 -55
  50. package/src/index.ts +2 -0
  51. package/src/lzyringe.ts +63 -0
  52. package/src/registrarBuilder.ts +101 -6
  53. package/src/utils.ts +24 -0
  54. package/test/registrarBuilder.test.ts +122 -0
  55. package/tsconfig.json +5 -16
  56. package/tsup.config.ts +0 -2
  57. package/.eslintrc.cjs +0 -5
  58. package/dist/chunk-3HJUWVUI.js +0 -79
  59. package/dist/chunk-3HJUWVUI.js.map +0 -1
  60. package/dist/chunk-H2WIRLVA.cjs +0 -81
  61. package/dist/chunk-H2WIRLVA.cjs.map +0 -1
  62. package/dist/chunk-JALW6HEL.js +0 -29
  63. package/dist/chunk-JALW6HEL.js.map +0 -1
  64. package/dist/chunk-OIOBHV2Q.cjs +0 -32
  65. package/dist/chunk-OIOBHV2Q.cjs.map +0 -1
  66. package/tsconfig.tsbuildinfo +0 -1
package/dist/utils.cjs ADDED
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ var B2JM5RKU_cjs = require('./B2JM5RKU.cjs');
4
+ require('./2W6KYHJN.cjs');
5
+ require('./YJF4D23A.cjs');
6
+
7
+
8
+
9
+ Object.defineProperty(exports, "extractSchemaFromFactory", {
10
+ enumerable: true,
11
+ get: function () { return B2JM5RKU_cjs.extractSchemaFromFactory; }
12
+ });
13
+ //# sourceMappingURL=utils.cjs.map
14
+ //# sourceMappingURL=utils.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"utils.cjs"}
@@ -0,0 +1,4 @@
1
+ import type z from 'zod/v4';
2
+ import { type FactoryDefinition } from './definitions';
3
+ export declare const extractSchemaFromFactory: <Dim extends z.ZodObject>(factoryDefinition: FactoryDefinition<any, Dim, any, any>, dimension: z.infer<Dim>) => z.ZodObject;
4
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAI5B,OAAO,EAAE,KAAK,iBAAiB,EAAuB,MAAM,eAAe,CAAC;AAE5E,eAAO,MAAM,wBAAwB,GAAI,GAAG,SAAS,CAAC,CAAC,SAAS,EAC5D,mBAAmB,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EACxD,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KACxB,CAAC,CAAC,SAcJ,CAAC"}
package/dist/utils.js ADDED
@@ -0,0 +1,5 @@
1
+ export { extractSchemaFromFactory } from './ISLTTWBQ.js';
2
+ import './PLNCBQCW.js';
3
+ import './VUOMXK5T.js';
4
+ //# sourceMappingURL=utils.js.map
5
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"utils.js"}
package/package.json CHANGED
@@ -1,25 +1,25 @@
1
1
  {
2
2
  "name": "@layerzerolabs/base-definitions",
3
- "version": "0.0.1",
3
+ "version": "0.0.5",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.cjs",
6
6
  "types": "./dist/index.d.ts",
7
7
  "dependencies": {
8
- "reflect-metadata": "^0.2.2",
9
- "tsup": "^8.4.0",
10
8
  "zod": "^3.23.8",
11
- "@layerzerolabs/dependency-graph": "0.0.1",
12
- "@layerzerolabs/dfs": "0.0.1"
9
+ "@layerzerolabs/dfs": "0.0.5",
10
+ "@layerzerolabs/dependency-graph": "0.0.5",
11
+ "@layerzerolabs/common-utils": "0.0.5"
13
12
  },
14
13
  "publishConfig": {
15
14
  "access": "restricted",
16
15
  "registry": "https://registry.npmjs.org/"
17
16
  },
18
17
  "devDependencies": {
19
- "@layerzerolabs/tsup-configuration": "0.0.1",
20
- "@layerzerolabs/eslint-configuration": "0.0.0",
21
- "@layerzerolabs/typescript-configuration": "0.0.0",
22
- "@layerzerolabs/typescript-utils": "0.0.0"
18
+ "tsup": "^8.4.0",
19
+ "vitest": "^3.2.3",
20
+ "@layerzerolabs/typescript-configuration": "0.0.5",
21
+ "@layerzerolabs/tsup-configuration": "0.0.5",
22
+ "@layerzerolabs/typescript-utils": "0.0.5"
23
23
  },
24
24
  "module": "./dist/index.js",
25
25
  "exports": {
@@ -35,7 +35,7 @@
35
35
  "build": "tsup",
36
36
  "lint": "eslint . --max-warnings 0",
37
37
  "lint:fix": "eslint . --fix --max-warnings 0",
38
- "typecheck": "tsc --noEmit",
38
+ "test": "vitest --run --pass-with-no-tests",
39
39
  "dev": "tsup --watch"
40
40
  }
41
41
  }
@@ -1,66 +1,109 @@
1
- import type { z } from 'zod';
1
+ import type { z } from 'zod/v4';
2
2
 
3
+ import type { FunctionPointer } from '@layerzerolabs/common-utils';
3
4
  import type { Dependencies } from '@layerzerolabs/dependency-graph';
4
5
  import { DependencyNode } from '@layerzerolabs/dependency-graph';
5
- import type { IntersectionValueOf, RemoveNever } from '@layerzerolabs/typescript-utils';
6
+ import type {
7
+ AdvancedRecord,
8
+ AdvancedRecordLookup,
9
+ Merge,
10
+ MethodOf,
11
+ RemoveNever,
12
+ UnionToIntersection,
13
+ } from '@layerzerolabs/typescript-utils';
14
+
15
+ export type DimensionToSchemaMap<DimConstraint extends object = object> = {
16
+ byDimension?: AdvancedRecord<DimConstraint, z.ZodType>;
17
+ base: z.ZodType;
18
+ };
19
+
20
+ export type GetModelFromSchema<DMap extends DimensionToSchemaMap, Dim> =
21
+ AdvancedRecordLookup<DMap['byDimension'], Dim> extends never
22
+ ? z.infer<DMap['base']>
23
+ : Merge<z.infer<DMap['base']>, z.infer<AdvancedRecordLookup<DMap['byDimension'], Dim>>>;
24
+
25
+ type GetImplFunctionWithConditionalOptionalDim<Dim, Return> = {} extends Dim
26
+ ? (dim?: Dim) => Return
27
+ : (dim: Dim) => Return;
28
+
29
+ type GetImplOverloads<
30
+ Dim extends z.ZodObject<any>,
31
+ DMap extends DimensionToSchemaMap<z.infer<Dim>>,
32
+ > = UnionToIntersection<
33
+ | {
34
+ [I in keyof DMap['byDimension']]: DMap['byDimension'][I] extends readonly [infer K, any]
35
+ ? {
36
+ getImpl: GetImplFunctionWithConditionalOptionalDim<
37
+ K,
38
+ GetModelFromSchema<DMap, K>
39
+ >;
40
+ }
41
+ : never;
42
+ }[keyof DMap['byDimension']]
43
+ | { getImpl: GetImplFunctionWithConditionalOptionalDim<z.infer<Dim>, z.infer<DMap['base']>> }
44
+ >;
6
45
 
7
46
  export type Factory<
8
47
  _Dependencies extends Dependencies,
9
48
  Dim extends z.ZodObject<any>,
10
- GetImplMetadata extends {
11
- getModel: (dim: z.infer<Dim>) => any;
12
- },
13
- > = { getImpl: (dim: z.infer<Dim>) => ReturnType<GetImplMetadata['getModel']> }
49
+ DMap extends DimensionToSchemaMap<z.infer<Dim>>,
50
+ > = { implKeys: string[] } & GetImplOverloads<Dim, DMap>;
14
51
 
15
52
  export type GetFactory<
16
53
  _Dependencies extends Dependencies,
17
54
  Dim extends z.ZodObject<any>,
18
- GetImplMetadata extends { getModel: (dim: z.infer<Dim>) => any },
19
- > = () =>
20
- | Factory<_Dependencies, Dim, GetImplMetadata>
21
- | Promise<Factory<_Dependencies, Dim, GetImplMetadata>>;
22
-
23
- export type GetFactoryForDefinition<Definition> = GetFactory<
24
- Definition extends FactoryDefinition<any, any, any, infer D> ? D : never,
25
- Definition extends FactoryDefinition<any, infer D, any, any> ? D : never,
26
- Definition extends FactoryDefinition<any, any, infer G, any> ? G : never
27
- >;
55
+ DMap extends DimensionToSchemaMap<z.infer<Dim>>,
56
+ > = () => Factory<_Dependencies, Dim, DMap> | Promise<Factory<_Dependencies, Dim, DMap>>;
28
57
 
58
+ /**
59
+ * Factory definitions are a type of dependency node that shall be resolved to a *factory*.
60
+ * A factory is an object that provides a getImpl method which accepts some parameters *dim*,
61
+ * and returns some object getImplMetadata.getModel(dim).
62
+ * That is, a factory definition is given by the set of parameters it uses to get its implementations,
63
+ * and a function defining the schema it will return for each set of parameters.
64
+ * @param name inherited from {@link DependencyNode}
65
+ * @param dependencies inherited from {@link DependencyNode}
66
+ * @param dimensions a Zod schema for the parameters this factory operates on.
67
+ * @param dimensionToSchemaMap A map from dimension objects to the Zod schema for the implementation.
68
+ * @param getFactory a method that should return an object with a getImpl method that returns
69
+ * entities adhering to the schema for the corresponding getModel call
70
+ */
29
71
  export class FactoryDefinition<
30
72
  Name extends string,
31
73
  Dim extends z.ZodObject<any>,
32
- GetImplMetadata extends {
33
- getKey: (dim: z.infer<Dim>) => any;
34
- getModel: (dim: z.infer<Dim>) => any;
35
- revLookup: {
36
- [key: string]: {
37
- dim: z.infer<Dim>;
38
- model: any;
39
- };
40
- };
41
- },
74
+ DMap extends DimensionToSchemaMap<z.infer<Dim>>,
42
75
  _Dependencies extends Dependencies,
43
76
  > extends DependencyNode<Name, _Dependencies> {
44
77
  public readonly dimensions: Dim;
45
- public readonly getImplMetadata: GetImplMetadata;
46
- public readonly getFactory: GetFactory<_Dependencies, Dim, GetImplMetadata>;
78
+ public readonly dimensionToSchemaMap: DMap;
79
+ public readonly getFactory: GetFactory<_Dependencies, Dim, DMap>;
47
80
  constructor({
48
81
  dimensions,
49
- getImplMetadata,
82
+ dimensionToSchemaMap,
50
83
  getFactory,
51
84
  ...args
52
85
  }: {
53
86
  dimensions: Dim;
54
- getImplMetadata: GetImplMetadata;
55
- getFactory: GetFactory<_Dependencies, Dim, GetImplMetadata>;
87
+ dimensionToSchemaMap: DMap;
88
+ getFactory: GetFactory<_Dependencies, Dim, DMap>;
56
89
  } & ConstructorParameters<typeof DependencyNode<Name, _Dependencies>>[0]) {
57
90
  super(args);
58
91
  this.dimensions = dimensions;
59
- this.getImplMetadata = getImplMetadata;
92
+ this.dimensionToSchemaMap = dimensionToSchemaMap;
60
93
  this.getFactory = getFactory;
61
94
  }
62
95
  }
63
96
 
97
+ /**
98
+ * An object definition is a dependency node that refers to some entity
99
+ * matching a given schema. That is, it may be resolved to any entity
100
+ * that adheres to the {@link schema}.
101
+ * The object definition is abstract, as it cannot be meaningfully resolved without
102
+ * additional information. For an example of an object definition, see ReflexiveObjectDefinition or ContextDefinition
103
+ * @param name inherited from {@link DependencyNode}
104
+ * @param dependencies inherited from {@link DependencyNode}
105
+ * @param schema a Zod schema defining the expected resolution for this definition
106
+ */
64
107
  export abstract class ObjectDefinition<
65
108
  Name extends string,
66
109
  Schema extends z.ZodSchema,
@@ -83,36 +126,72 @@ export type Definition<Name extends string> =
83
126
  | FactoryDefinition<Name, any, any, any>
84
127
  | ObjectDefinition<Name, any, any>;
85
128
 
86
- export type DefinitionResolution<Definition extends DependencyNode<any, any>> =
129
+ /**
130
+ * Infers the expected type of a definition once it has been resolved
131
+ */
132
+ export type ResolvedDefinition<Definition extends DependencyNode<any, any>> =
87
133
  Definition extends ObjectDefinition<any, infer Schema, any>
88
134
  ? z.infer<Schema>
89
- : Definition extends FactoryDefinition<any, any, infer GetImpl, any>
90
- ? {
91
- getImpl: GetImpl['getModel'];
92
- }
93
- : never;
94
-
95
- export type DefinitionsResolution<Deps extends Dependencies> = {
96
- [Key in keyof Deps]: DefinitionResolution<Deps[Key]>;
135
+ : Definition extends FactoryDefinition<any, infer Dim, infer DMap, any>
136
+ ? Factory<Definition['dependencies'], Dim, DMap>
137
+ : Definition extends FactoryDefinition<any, any, any, any>
138
+ ? Factory<
139
+ Definition['dependencies'],
140
+ Definition['dimensions'],
141
+ Definition['dimensionToSchemaMap']
142
+ >
143
+ : unknown;
144
+
145
+ /**
146
+ * Given a record from string to definition, maps each definition T to ResolvedDefinition<T>
147
+ */
148
+ export type ResolvedDefinitionMap<Deps extends Dependencies> = {
149
+ [Key in keyof Deps]: ResolvedDefinition<Deps[Key]>;
97
150
  };
98
151
 
99
- export type DefinitionImplsResolution<Definition extends DependencyNode<any, any>, Dim> =
100
- Definition extends FactoryDefinition<any, infer _Dim, infer GetImpl, any>
101
- ? Dim extends z.infer<_Dim>
102
- ? IntersectionValueOf<{
103
- [key in keyof GetImpl['revLookup']]: Dim extends GetImpl['revLookup'][key]['dim']
104
- ? GetImpl['revLookup'][key]['model']
105
- : never;
106
- }>
107
- : never
152
+ /**
153
+ * For some factory definition F and some dimension D s.t. D ⊇ F.dimensions, infers the expected return type of
154
+ * ResolvedDefinition<F>.getImpl(D)
155
+ */
156
+ export type ResolvedFactoryImplementation<Definition extends DependencyNode<any, any>, Dim> =
157
+ Definition extends FactoryDefinition<any, any, any, any>
158
+ ? GetModelFromSchema<Definition['dimensionToSchemaMap'], Dim>
108
159
  : never;
109
160
 
110
- export type DefinitionsImplsResolution<Deps extends Dependencies, Dim> = RemoveNever<{
111
- [Key in keyof Deps]: DefinitionImplsResolution<Deps[Key], Dim>;
161
+ /**
162
+ * Given a record from string to definition and some dimension D, maps each definition T to ResolvedFactoryImplementation<T, D>
163
+ */
164
+ export type ResolvedFactoryImplementationMap<Deps extends Dependencies, Dim> = RemoveNever<{
165
+ [Key in keyof Deps]: ResolvedFactoryImplementation<Deps[Key], Dim>;
112
166
  }>;
113
167
 
114
- export type Context<Deps extends Dependencies, Dim> = {
115
- dependencies: DefinitionsResolution<Deps>;
116
- impls: DefinitionsImplsResolution<Deps, Dim>;
168
+ type ActivityContext<_FactoryDefinition extends FactoryDefinition<any, any, any, any>, Dim> = {
169
+ getFunctionPointer: _FactoryDefinition extends FactoryDefinition<any, any, any, any>
170
+ ? <Method extends MethodOf<ResolvedFactoryImplementation<_FactoryDefinition, Dim>>>(
171
+ method: Method,
172
+ ) => FunctionPointer<Method>
173
+ : never;
174
+ };
175
+
176
+ /**
177
+ * The parameters that shall be received by a factory's implementation getter
178
+ */
179
+ export type Context<_FactoryDefinition extends FactoryDefinition<any, any, any, any>, Dim> = {
180
+ name: _FactoryDefinition extends FactoryDefinition<infer Name, any, any, any> ? Name : never;
181
+ dependencies: _FactoryDefinition extends FactoryDefinition<any, any, any, infer Deps>
182
+ ? ResolvedDefinitionMap<Deps>
183
+ : never;
117
184
  dim: Dim;
185
+ impls: _FactoryDefinition extends FactoryDefinition<any, any, any, infer Deps>
186
+ ? ResolvedFactoryImplementationMap<Deps, Dim>
187
+ : never;
188
+ } & ActivityContext<_FactoryDefinition, Dim>;
189
+
190
+ export const serializeDimensions = (dim: object = {}) => {
191
+ return Object.keys(dim).length
192
+ ? Object.entries(dim)
193
+ .sort()
194
+ .map(([dimName, dimVal]) => `${dimName}_${dimVal}`, '')
195
+ .join('&')
196
+ : '_base';
118
197
  };
package/src/index.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  export * from './definitions';
2
+ export * from './lzyringe';
2
3
  export * from './registrarBuilder';
4
+ export * from './utils';
@@ -0,0 +1,63 @@
1
+ type StoreValue = {
2
+ type: 'value';
3
+ value: any;
4
+ };
5
+ type StoreFactory = {
6
+ type: 'factory';
7
+ value: () => any;
8
+ };
9
+ type StoreAny = StoreValue | StoreFactory;
10
+
11
+ export class DependencyStore {
12
+ private store: Record<string, StoreAny | undefined> = {};
13
+
14
+ private throwIfRegistered(key: string) {
15
+ if (this.store[key] != null) {
16
+ throw new Error(`${key} is already registered`);
17
+ }
18
+ }
19
+
20
+ private throwIfUnregistered(key: string) {
21
+ if (this.store[key] == null) {
22
+ throw new Error(`${key} is not registered`);
23
+ }
24
+ }
25
+
26
+ /** Registers a value that will be resolved literally by resolve()
27
+ * @throws if already registered
28
+ */
29
+ public register(key: string, value: any) {
30
+ this.throwIfRegistered(key);
31
+ this.store[key] = { type: 'value', value };
32
+ }
33
+
34
+ /** Registers a factory function that will be called by resolve()
35
+ * @throws if already registered
36
+ */
37
+ public registerFactory(key: string, factory: () => any) {
38
+ this.throwIfRegistered(key);
39
+ this.store[key] = { type: 'factory', value: factory };
40
+ }
41
+
42
+ /** Unregisters a key
43
+ * @throws if not registered
44
+ */
45
+ public unregister(key: string) {
46
+ this.throwIfUnregistered(key);
47
+ this.store[key] = undefined;
48
+ }
49
+
50
+ /**
51
+ * Drops all registered values
52
+ */
53
+ public invalidate() {
54
+ this.store = {};
55
+ }
56
+
57
+ /** Resolves a key to a value */
58
+ public resolve(key: string) {
59
+ this.throwIfUnregistered(key);
60
+ const stored = this.store[key]!;
61
+ return stored.type === 'factory' ? stored.value() : stored.value;
62
+ }
63
+ }
@@ -3,6 +3,21 @@ import type { Registrar } from '@layerzerolabs/dfs';
3
3
  export type { Registrar };
4
4
  import { dfs } from '@layerzerolabs/dfs';
5
5
 
6
+ type NodeClass = new (...args: any[]) => DependencyNode<any, any>;
7
+ type AbstractNodeClass = abstract new (...args: any[]) => DependencyNode<any, any>;
8
+
9
+ /**
10
+ * A builder class for a {@link Registrar}.
11
+ * Builds a registrar that switches on node class--i.e., enables defining
12
+ * specific registration behaviour for specific node classes.
13
+ * Intelligently handles inheritance, always using the most specific
14
+ * handler defined for any given class.
15
+ * The registrar built shall return an object that maps from a handler ID,
16
+ * to a map from node name to the return of each handler,
17
+ * e.g., { objectNodes: { myObjectNode: 'my handler return' }}.
18
+ * This can be used to extract a specific resolved value after resolving the tree,
19
+ * given that the handlers return the resolved nodes.
20
+ */
6
21
  export class RegistrarBuilder<_ReturnTypes> {
7
22
  protected defaultHandler: (node: DependencyNode<any, any>) => Promise<any>;
8
23
  constructor() {
@@ -14,11 +29,16 @@ export class RegistrarBuilder<_ReturnTypes> {
14
29
  }
15
30
 
16
31
  protected classHandlers: {
17
- nodeClass: abstract new (...args: any[]) => DependencyNode<any, any>;
32
+ nodeClass: AbstractNodeClass;
18
33
  identifier: string;
19
34
  fn: (node: DependencyNode<any, any>) => Promise<any>;
20
35
  }[] = [];
21
36
 
37
+ protected classAliases: {
38
+ fromNodeClass: AbstractNodeClass;
39
+ getToNode: (from: DependencyNode<any, any>) => DependencyNode<any, any>;
40
+ }[] = [];
41
+
22
42
  /**
23
43
  * Add a function fn to be called on all nodes of class
24
44
  * @param nodeClass
@@ -27,9 +47,15 @@ export class RegistrarBuilder<_ReturnTypes> {
27
47
  */
28
48
  public addClassHandler<
29
49
  Identifier extends string,
30
- NodeClass extends new (...args: any[]) => DependencyNode<any, any>,
31
- Function extends (node: InstanceType<NodeClass>) => any,
32
- >(nodeClass: NodeClass, identifier: Identifier, fn: Function) {
50
+ _NodeClass extends NodeClass,
51
+ Function extends (node: InstanceType<_NodeClass>) => any,
52
+ >(nodeClass: _NodeClass, identifier: Identifier, fn: Function) {
53
+ if (this.classAliases.find(({ fromNodeClass }) => fromNodeClass === nodeClass)) {
54
+ throw new Error(
55
+ `Cannot define a handler for a class that is aliased to something else. This would be pointless`,
56
+ );
57
+ }
58
+
33
59
  let i = 0;
34
60
  for (const handler of this.classHandlers) {
35
61
  //check if we are overriding an existing handler
@@ -78,17 +104,86 @@ export class RegistrarBuilder<_ReturnTypes> {
78
104
  >;
79
105
  }
80
106
 
107
+ /**
108
+ * Alias some class *from*, such that any node of that class in the tree will be
109
+ * treated as though it were some other node *to*. The *to* node is given as a
110
+ * function returning a class instance, so that its dependencies, name, etc can be fixed.
111
+ * The registrar will ignore the dependencies of the original node, and follow the alias's
112
+ * dependencies instead.
113
+ *
114
+ * Additionally, this method does not affect the typing of the registrar. The output type
115
+ * of the build() method will not reflect the alias.
116
+ *
117
+ * @param fromNodeClass alias instances of this class
118
+ * @param getToNode method that returns the *to* part of the alias
119
+ */
120
+ public addClassAlias<FromNodeClass extends AbstractNodeClass>(
121
+ fromNodeClass: FromNodeClass,
122
+ getToNode: (fromNodeInstance: InstanceType<FromNodeClass>) => DependencyNode<any, any>,
123
+ ) {
124
+ if (this.classHandlers.find(({ nodeClass }) => nodeClass === fromNodeClass)) {
125
+ throw new Error(`Cannot define an alias for a class that already has a handler`);
126
+ }
127
+
128
+ let i = 0;
129
+ for (const alias of this.classAliases) {
130
+ //check if we are overriding an existing alias
131
+ if (alias.fromNodeClass === fromNodeClass) {
132
+ this.classAliases[i] = {
133
+ fromNodeClass,
134
+ getToNode: getToNode as unknown as (
135
+ from: DependencyNode<any, any>,
136
+ ) => DependencyNode<any, any>,
137
+ };
138
+
139
+ return this;
140
+ }
141
+ //check if the new alias has an ordering requirement against an existing alias
142
+ //(we always want to use more specific handlers if they exist)
143
+ // eslint-disable-next-line no-prototype-builtins
144
+ if (alias.fromNodeClass.prototype.isPrototypeOf(fromNodeClass.prototype)) {
145
+ this.classAliases.splice(i, 0, {
146
+ fromNodeClass,
147
+ getToNode: getToNode as unknown as (
148
+ from: DependencyNode<any, any>,
149
+ ) => DependencyNode<any, any>,
150
+ });
151
+
152
+ return this;
153
+ }
154
+ i++;
155
+ }
156
+
157
+ this.classAliases.push({
158
+ fromNodeClass,
159
+ getToNode: getToNode as unknown as (
160
+ from: DependencyNode<any, any>,
161
+ ) => DependencyNode<any, any>,
162
+ });
163
+
164
+ return this;
165
+ }
166
+
81
167
  /**
82
168
  * Add a default function fn to be used on nodes whose types do not have handlers.
83
169
  * If this is not set, the default behaviour will be to throw
84
170
  * @param fn
85
171
  */
86
- public addDefault(fn: (node: DependencyNode<any, any>) => Promise<any>) {
172
+ public addDefault(fn: (node: DependencyNode<any, any>) => any) {
87
173
  this.defaultHandler = fn;
88
174
  return this;
89
175
  }
90
176
 
91
177
  public build(): Registrar<_ReturnTypes> {
178
+ const mergedNodePrehandler = (node: DependencyNode<any, any>) => {
179
+ for (const { fromNodeClass, getToNode: toNode } of this.classAliases) {
180
+ if (node instanceof fromNodeClass) {
181
+ return toNode(node);
182
+ }
183
+ }
184
+ return node;
185
+ };
186
+
92
187
  const mergedNodeHandler = async (node: DependencyNode<any, any>) => {
93
188
  for (const { nodeClass, identifier, fn } of this.classHandlers) {
94
189
  if (node instanceof nodeClass) {
@@ -106,7 +201,7 @@ export class RegistrarBuilder<_ReturnTypes> {
106
201
  };
107
202
  return {
108
203
  traverseDependencies: async (node: DependencyNode<any, any>) =>
109
- await dfs<any, _ReturnTypes>(node, mergedNodeHandler)(),
204
+ await dfs<any, _ReturnTypes>(node, mergedNodeHandler, mergedNodePrehandler)(),
110
205
  };
111
206
  }
112
207
  }
package/src/utils.ts ADDED
@@ -0,0 +1,24 @@
1
+ import type z from 'zod/v4';
2
+
3
+ import type { AdvancedRecord } from '@layerzerolabs/typescript-utils';
4
+
5
+ import { type FactoryDefinition, serializeDimensions } from './definitions';
6
+
7
+ export const extractSchemaFromFactory = <Dim extends z.ZodObject>(
8
+ factoryDefinition: FactoryDefinition<any, Dim, any, any>,
9
+ dimension: z.infer<Dim>,
10
+ ): z.ZodObject => {
11
+ const schema =
12
+ (factoryDefinition.dimensionToSchemaMap.byDimension &&
13
+ Object.values(
14
+ factoryDefinition.dimensionToSchemaMap.byDimension as AdvancedRecord,
15
+ ).find(([dim]) => serializeDimensions(dim) === serializeDimensions(dimension))?.[1]) ??
16
+ factoryDefinition.dimensionToSchemaMap.base;
17
+ if (!schema?.shape) {
18
+ throw new Error(
19
+ `Couldn't resolve the schema of factory ${factoryDefinition.name} for dim ${JSON.stringify(dimension)}`,
20
+ );
21
+ }
22
+
23
+ return schema;
24
+ };