Refactor Visitor and Transformer to include an instance graph

main
Jackson Morgan 9 months ago
parent 2a0c2b0629
commit 3316818633
  1. 10
      packages/type-traverser/README.md
  2. 126
      packages/type-traverser/src/Visitors.ts
  3. 4
      packages/type-traverser/src/index.ts
  4. 2
      packages/type-traverser/src/instanceGraph/InstanceGraph.ts
  5. 2
      packages/type-traverser/src/instanceGraph/ReverseRelationshipTypes.ts
  6. 2
      packages/type-traverser/src/instanceGraph/nodes/InstanceNode.ts
  7. 47
      packages/type-traverser/src/transformer/Transformer.ts
  8. 88
      packages/type-traverser/src/transformer/Transformers.ts
  9. 22
      packages/type-traverser/src/transformer/transformerSubTraversers/TransformerInterfaceSubTraverser.ts
  10. 6
      packages/type-traverser/src/transformer/transformerSubTraversers/TransformerParentSubTraverser.ts
  11. 24
      packages/type-traverser/src/transformer/transformerSubTraversers/TransformerPrimitiveSubTraverser.ts
  12. 14
      packages/type-traverser/src/transformer/transformerSubTraversers/TransformerUnionSubTraverser.ts
  13. 2
      packages/type-traverser/src/transformer/transformerSubTraversers/util/CircularDependencyAwaiter.ts
  14. 0
      packages/type-traverser/src/transformer/transformerSubTraversers/util/MultiMap.ts
  15. 0
      packages/type-traverser/src/transformer/transformerSubTraversers/util/MultiSet.ts
  16. 0
      packages/type-traverser/src/transformer/transformerSubTraversers/util/SuperPromise.ts
  17. 0
      packages/type-traverser/src/transformer/transformerSubTraversers/util/timeout.ts
  18. 4
      packages/type-traverser/src/transformer/transformerSubTraversers/util/transformerSubTraverserTypes.ts
  19. 48
      packages/type-traverser/src/visitor/Visitor.ts
  20. 157
      packages/type-traverser/src/visitor/Visitors.ts
  21. 24
      packages/type-traverser/src/visitor/visitorSubTraversers/VisitorInterfaceSubTraverser.ts
  22. 2
      packages/type-traverser/src/visitor/visitorSubTraversers/VisitorParentSubTraverser.ts
  23. 18
      packages/type-traverser/src/visitor/visitorSubTraversers/VisitorPrimitiveSubTraverser.ts
  24. 19
      packages/type-traverser/src/visitor/visitorSubTraversers/VisitorUnionSubTraverser.ts
  25. 6
      packages/type-traverser/src/visitor/visitorSubTraversers/util/visitorSubTraverserTypes.ts
  26. 156
      packages/type-traverser/test/integration/InstanceGraph.test.ts
  27. 0
      packages/type-traverser/test/integration/avatar/AvatarBrokenTransformer.ts
  28. 0
      packages/type-traverser/test/integration/avatar/AvatarErroringTransformer.ts
  29. 4
      packages/type-traverser/test/integration/avatar/AvatarTraverserDefinition.ts
  30. 0
      packages/type-traverser/test/integration/avatar/AvatarTraverserTypes.ts
  31. 170
      packages/type-traverser/test/integration/avatar/avatar.test.ts
  32. 0
      packages/type-traverser/test/integration/avatar/sampleData.ts
  33. 19
      packages/type-traverser/test/integration/avatar_old/avatar.old.ts

@ -159,14 +159,14 @@ There are two fields for the primitive sub-traverser:
- `type`: The typescript type corresponding to this primitive. - `type`: The typescript type corresponding to this primitive.
### Creating a traverser definition ### Creating a traverser definition
Typescript typings aren't available at runtime, so the next step is to translate the `TraverserTypes` that we made into a standard JSON object called a "TraverserDefinition". But, don't worry! This will be easy. If you define a variable as a `TraverserDefinition<TraverserType>`, your IDE's IntelliSense will be able to direct you through exactly what to fill out, as seen below. Typescript typings aren't available at runtime, so the next step is to translate the `TraverserTypes` that we made into a standard JSON object called a "TraverserDefinitions". But, don't worry! This will be easy. If you define a variable as a `TraverserDefinitions<TraverserType>`, your IDE's IntelliSense will be able to direct you through exactly what to fill out, as seen below.
![Traverse Definition IntelliSense](/tutorialImages/TraveserDefinitionIntellisense.png) ![Traverse Definition IntelliSense](/tutorialImages/TraveserDefinitionIntellisense.png)
In our example, the TraverserDefinition looks like: In our example, the TraverserDefinitions looks like:
```typescript ```typescript
const avatarTraverserDefinition: TraverserDefinition<AvatarTraverserTypes> = { const avatarTraverserDefinitions: TraverserDefinitions<AvatarTraverserTypes> = {
Element: { Element: {
kind: "primitive", kind: "primitive",
}, },
@ -193,7 +193,7 @@ const avatarTraverserDefinition: TraverserDefinition<AvatarTraverserTypes> = {
``` ```
#### Defining a Union Selector #### Defining a Union Selector
The only part of the TraverserDefinition that isn't just blindly following IntelliSense is the `selector` on a Union sub-traverser. A `selector` is given the item and should return the TypeName corresponding to the item. The only part of the TraverserDefinitions that isn't just blindly following IntelliSense is the `selector` on a Union sub-traverser. A `selector` is given the item and should return the TypeName corresponding to the item.
In the above example, `"Bender"` is returned if the given item has a `"element"` property because a `"NonBender"` does not include an `"element"` property. In the above example, `"Bender"` is returned if the given item has a `"element"` property because a `"NonBender"` does not include an `"element"` property.
@ -204,7 +204,7 @@ In our example, this is how we instantiate the traverser
```typescript ```typescript
const avatarTraverser = new Traverser<AvatarTraverserTypes>( const avatarTraverser = new Traverser<AvatarTraverserTypes>(
avatarTraverserDefinition avatarTraverserDefinitions
); );
``` ```

@ -1,126 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type {
InterfaceType,
PrimitiveType,
TraverserTypes,
UnionType,
} from ".";
export type InterfaceVisitorFunction<
Types extends TraverserTypes<any>,
Type extends InterfaceType<keyof Types>,
Context,
> = (originalData: Type["type"], context: Context) => Promise<void>;
export type InterfaceVisitorPropertyFunction<
Types extends TraverserTypes<any>,
Type extends InterfaceType<keyof Types>,
PropertyName extends keyof Type["properties"],
Context,
> = (
originalData: Types[Type["properties"][PropertyName]]["type"],
context: Context,
) => Promise<void>;
export type InterfaceVisitorDefinition<
Types extends TraverserTypes<any>,
Type extends InterfaceType<keyof Types>,
Context,
> = {
visitor: InterfaceVisitorFunction<Types, Type, Context>;
properties: {
[PropertyName in keyof Type["properties"]]: InterfaceVisitorPropertyFunction<
Types,
Type,
PropertyName,
Context
>;
};
};
export type UnionVisitorFunction<
Types extends TraverserTypes<any>,
Type extends UnionType<keyof Types>,
Context,
> = (originalData: Type["type"], context: Context) => Promise<void>;
export type UnionVisitorDefinition<
Types extends TraverserTypes<any>,
Type extends UnionType<keyof Types>,
Context,
> = UnionVisitorFunction<Types, Type, Context>;
export type PrimitiveVisitorFunction<Type extends PrimitiveType, Context> = (
originalData: Type["type"],
context: Context,
) => Promise<void>;
export type PrimitiveVisitorDefinition<
Type extends PrimitiveType,
Context,
> = PrimitiveVisitorFunction<Type, Context>;
export type VisitorDefinition<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Context,
> = Types[TypeName] extends InterfaceType<keyof Types>
? InterfaceVisitorDefinition<Types, Types[TypeName], Context>
: Types[TypeName] extends UnionType<keyof Types>
? UnionVisitorDefinition<Types, Types[TypeName], Context>
: Types[TypeName] extends PrimitiveType
? PrimitiveVisitorDefinition<Types[TypeName], Context>
: never;
export type Visitors<Types extends TraverserTypes<any>, Context> = {
[TypeName in keyof Types]: VisitorDefinition<Types, TypeName, Context>;
};
/**
* Input
*/
export type InterfaceVisitorInputDefinition<
Types extends TraverserTypes<any>,
Type extends InterfaceType<keyof Types>,
Context,
> = {
visitor: InterfaceVisitorFunction<Types, Type, Context>;
properties?: Partial<{
[PropertyName in keyof Type["properties"]]: InterfaceVisitorPropertyFunction<
Types,
Type,
PropertyName,
Context
>;
}>;
};
export type UnionVisitorInputDefinition<
Types extends TraverserTypes<any>,
Type extends UnionType<keyof Types>,
Context,
> = UnionVisitorFunction<Types, Type, Context>;
export type PrimitiveVisitorInputDefinition<
Type extends PrimitiveType,
Context,
> = PrimitiveVisitorFunction<Type, Context>;
export type VisitorInputDefinition<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Context,
> = Types[TypeName] extends InterfaceType<keyof Types>
? InterfaceVisitorInputDefinition<Types, Types[TypeName], Context>
: Types[TypeName] extends UnionType<keyof Types>
? UnionVisitorInputDefinition<Types, Types[TypeName], Context>
: Types[TypeName] extends PrimitiveType
? PrimitiveVisitorInputDefinition<Types[TypeName], Context>
: never;
export type VisitorsInput<
Types extends TraverserTypes<any>,
Context,
> = Partial<{
[TypeName in keyof Types]: VisitorInputDefinition<Types, TypeName, Context>;
}>;

@ -5,5 +5,5 @@ export * from "./transformer/TransformerReturnTypes";
export * from "./transformer/TransformerReturnTypesDefaults"; export * from "./transformer/TransformerReturnTypesDefaults";
export * from "./traverser/Traverser"; export * from "./traverser/Traverser";
export * from "./transformer/Transformer"; export * from "./transformer/Transformer";
export * from "./Visitor"; export * from "./visitor/Visitor";
export * from "./Visitors"; export * from "./visitor/Visitors";

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { MultiMap } from "../transformerSubTraversers/util/MultiMap"; import { MultiMap } from "../transformer/transformerSubTraversers/util/MultiMap";
import type { TraverserTypes } from "../traverser/TraverserTypes"; import type { TraverserTypes } from "../traverser/TraverserTypes";
import { import {
createInstanceNodeFor, createInstanceNodeFor,

@ -4,7 +4,7 @@ import type {
PrimitiveType, PrimitiveType,
TraverserTypes, TraverserTypes,
UnionType, UnionType,
} from "./traverser/TraverserTypes"; } from "../traverser/TraverserTypes";
export type InterfaceReverseRelationshipIndentifier< export type InterfaceReverseRelationshipIndentifier<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import type { TraverserDefinition } from "../.."; import type { TraverserDefinition } from "../..";
import type { ParentIdentifiers } from "../../reverseRelationshipTypes"; import type { ParentIdentifiers } from "../../instanceGraph/ReverseRelationshipTypes";
import type { TraverserTypes } from "../../traverser/TraverserTypes"; import type { TraverserTypes } from "../../traverser/TraverserTypes";
import type { InstanceGraph } from "../instanceGraph"; import type { InstanceGraph } from "../instanceGraph";
import type { InstanceNodeFor } from "./createInstanceNodeFor"; import type { InstanceNodeFor } from "./createInstanceNodeFor";

@ -13,10 +13,10 @@ import type {
UnionReturnType, UnionReturnType,
UnionType, UnionType,
} from ".."; } from "..";
import { transformerParentSubTraverser } from "../transformerSubTraversers/TransformerParentSubTraverser"; import { transformerParentSubTraverser } from "./transformerSubTraversers/TransformerParentSubTraverser";
import { CircularDepenedencyAwaiter } from "../transformerSubTraversers/util/CircularDependencyAwaiter"; import { CircularDepenedencyAwaiter } from "./transformerSubTraversers/util/CircularDependencyAwaiter";
import { MultiMap } from "../transformerSubTraversers/util/MultiMap"; import { MultiMap } from "./transformerSubTraversers/util/MultiMap";
import { SuperPromise } from "../transformerSubTraversers/util/SuperPromise"; import { SuperPromise } from "./transformerSubTraversers/util/SuperPromise";
import type { import type {
GetTransformedChildrenFunction, GetTransformedChildrenFunction,
InterfaceTransformerDefinition, InterfaceTransformerDefinition,
@ -28,6 +28,7 @@ import type {
UnionTransformerDefinition, UnionTransformerDefinition,
UnionTransformerInputDefinition, UnionTransformerInputDefinition,
} from "./Transformers"; } from "./Transformers";
import { InstanceGraph } from "../instanceGraph/instanceGraph";
// TODO: Lots of "any" in this file. I'm just done with fancy typescript, // TODO: Lots of "any" in this file. I'm just done with fancy typescript,
// but if I ever feel so inclined, I should fix this in the future. // but if I ever feel so inclined, I should fix this in the future.
@ -54,12 +55,14 @@ export class Transformer<
} }
private applyDefaultInterfaceTransformerProperties< private applyDefaultInterfaceTransformerProperties<
Type extends InterfaceType<keyof Types>, TypeName extends keyof Types,
Type extends InterfaceType<keyof Types> & Types[TypeName],
ReturnType extends InterfaceReturnType<Type>, ReturnType extends InterfaceReturnType<Type>,
>( >(
typeName: keyof Types, typeName: keyof Types,
typePropertiesInput: InterfaceTransformerInputDefinition< typePropertiesInput: InterfaceTransformerInputDefinition<
Types, Types,
TypeName,
Type, Type,
ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>, ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>,
ReturnType, ReturnType,
@ -67,6 +70,7 @@ export class Transformer<
>["properties"], >["properties"],
): InterfaceTransformerDefinition< ): InterfaceTransformerDefinition<
Types, Types,
TypeName,
Type, Type,
ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>, ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>,
ReturnType, ReturnType,
@ -89,6 +93,7 @@ export class Transformer<
return agg; return agg;
}, {}) as InterfaceTransformerDefinition< }, {}) as InterfaceTransformerDefinition<
Types, Types,
TypeName,
Type, Type,
ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>, ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>,
ReturnType, ReturnType,
@ -97,12 +102,14 @@ export class Transformer<
} }
private applyDefaultInterfaceTransformer< private applyDefaultInterfaceTransformer<
Type extends InterfaceType<keyof Types>, TypeName extends keyof Types,
Type extends InterfaceType<keyof Types> & Types[TypeName],
ReturnType extends InterfaceReturnType<Type>, ReturnType extends InterfaceReturnType<Type>,
>( >(
typeName: keyof Types, typeName: keyof Types,
typeInput?: InterfaceTransformerInputDefinition< typeInput?: InterfaceTransformerInputDefinition<
Types, Types,
TypeName,
Type, Type,
ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>, ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>,
ReturnType, ReturnType,
@ -110,6 +117,7 @@ export class Transformer<
>, >,
): InterfaceTransformerDefinition< ): InterfaceTransformerDefinition<
Types, Types,
TypeName,
Type, Type,
ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>, ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>,
ReturnType, ReturnType,
@ -139,11 +147,13 @@ export class Transformer<
} }
private applyDefaultUnionTransformer< private applyDefaultUnionTransformer<
Type extends UnionType<keyof Types>, TypeName extends keyof Types,
Type extends UnionType<keyof Types> & Types[TypeName],
ReturnType extends UnionReturnType, ReturnType extends UnionReturnType,
>( >(
typeInput?: UnionTransformerInputDefinition< typeInput?: UnionTransformerInputDefinition<
Types, Types,
TypeName,
Type, Type,
ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>, ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>,
ReturnType, ReturnType,
@ -151,6 +161,7 @@ export class Transformer<
>, >,
): UnionTransformerDefinition< ): UnionTransformerDefinition<
Types, Types,
TypeName,
Type, Type,
ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>, ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>,
ReturnType, ReturnType,
@ -168,11 +179,24 @@ export class Transformer<
} }
private applyDefaultPrimitiveTransformer< private applyDefaultPrimitiveTransformer<
Type extends PrimitiveType, TypeName extends keyof Types,
Type extends PrimitiveType & Types[TypeName],
ReturnType extends PrimitiveReturnType, ReturnType extends PrimitiveReturnType,
>( >(
typeInput?: PrimitiveTransformerInputDefinition<Type, ReturnType, Context>, typeInput?: PrimitiveTransformerInputDefinition<
): PrimitiveTransformerDefinition<Type, ReturnType, Context> { Types,
TypeName,
Type,
ReturnType,
Context
>,
): PrimitiveTransformerDefinition<
Types,
TypeName,
Type,
ReturnType,
Context
> {
if (!typeInput) { if (!typeInput) {
return async (originalData) => { return async (originalData) => {
return originalData; return originalData;
@ -229,12 +253,15 @@ export class Transformer<
>[TypeName]["return"] >[TypeName]["return"]
> { > {
const superPromise = new SuperPromise(); const superPromise = new SuperPromise();
const instanceGraph = new InstanceGraph(this.traverserDefinition);
instanceGraph.getNodeFor(item, itemTypeName);
const toReturn = await transformerParentSubTraverser(item, itemTypeName, { const toReturn = await transformerParentSubTraverser(item, itemTypeName, {
traverserDefinition: this.traverserDefinition, traverserDefinition: this.traverserDefinition,
transformers: this.transformers, transformers: this.transformers,
executingPromises: new MultiMap(), executingPromises: new MultiMap(),
circularDependencyAwaiter: new CircularDepenedencyAwaiter(), circularDependencyAwaiter: new CircularDepenedencyAwaiter(),
superPromise, superPromise,
instanceGraph,
context, context,
}); });
await superPromise.wait(); await superPromise.wait();

@ -12,6 +12,8 @@ import type {
UnionType, UnionType,
} from ".."; } from "..";
import type { InterfaceInstanceNode } from "../instanceGraph/nodes/InterfaceInstanceNode"; import type { InterfaceInstanceNode } from "../instanceGraph/nodes/InterfaceInstanceNode";
import type { PrimitiveInstanceNode } from "../instanceGraph/nodes/PrimitiveInstanceNode";
import type { UnionInstanceNode } from "../instanceGraph/nodes/UnionInstanceNode";
export type GetTransformedChildrenFunction<TransformedChildrenType> = export type GetTransformedChildrenFunction<TransformedChildrenType> =
() => Promise<TransformedChildrenType>; () => Promise<TransformedChildrenType>;
@ -22,7 +24,8 @@ export type SetReturnPointerFunction<ReturnType> = (
export type InterfaceTransformerFunction< export type InterfaceTransformerFunction<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
Type extends InterfaceType<keyof Types>, TypeName extends keyof Types,
Type extends InterfaceType<keyof Types> & Types[TypeName],
ReturnType extends InterfaceReturnType<Type>, ReturnType extends InterfaceReturnType<Type>,
Context, Context,
> = ( > = (
@ -31,13 +34,14 @@ export type InterfaceTransformerFunction<
[PropertyName in keyof ReturnType["properties"]]: ReturnType["properties"][PropertyName]; [PropertyName in keyof ReturnType["properties"]]: ReturnType["properties"][PropertyName];
}>, }>,
setReturnPointer: SetReturnPointerFunction<ReturnType["return"]>, setReturnPointer: SetReturnPointerFunction<ReturnType["return"]>,
node: InterfaceInstanceNode<Types, Type>, node: InterfaceInstanceNode<Types, TypeName, Type>,
context: Context, context: Context,
) => Promise<ReturnType["return"]>; ) => Promise<ReturnType["return"]>;
export type InterfaceTransformerPropertyFunction< export type InterfaceTransformerPropertyFunction<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
Type extends InterfaceType<keyof Types>, TypeName extends keyof Types,
Type extends InterfaceType<keyof Types> & Types[TypeName],
ReturnTypes extends TransformerReturnTypes<Types>, ReturnTypes extends TransformerReturnTypes<Types>,
ReturnType extends InterfaceReturnType<Type>, ReturnType extends InterfaceReturnType<Type>,
PropertyName extends keyof Type["properties"], PropertyName extends keyof Type["properties"],
@ -47,20 +51,29 @@ export type InterfaceTransformerPropertyFunction<
getTransfromedChildren: GetTransformedChildrenFunction< getTransfromedChildren: GetTransformedChildrenFunction<
ReturnTypes[Type["properties"][PropertyName]]["return"] ReturnTypes[Type["properties"][PropertyName]]["return"]
>, >,
node: InterfaceInstanceNode<Types, TypeName, Type>,
context: Context, context: Context,
) => Promise<ReturnType["properties"][PropertyName]>; ) => Promise<ReturnType["properties"][PropertyName]>;
export type InterfaceTransformerDefinition< export type InterfaceTransformerDefinition<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
Type extends InterfaceType<keyof Types>, TypeName extends keyof Types,
Type extends InterfaceType<keyof Types> & Types[TypeName],
ReturnTypes extends TransformerReturnTypes<Types>, ReturnTypes extends TransformerReturnTypes<Types>,
ReturnType extends InterfaceReturnType<Type>, ReturnType extends InterfaceReturnType<Type>,
Context, Context,
> = { > = {
transformer: InterfaceTransformerFunction<Types, Type, ReturnType, Context>; transformer: InterfaceTransformerFunction<
Types,
TypeName,
Type,
ReturnType,
Context
>;
properties: { properties: {
[PropertyName in keyof Type["properties"]]: InterfaceTransformerPropertyFunction< [PropertyName in keyof Type["properties"]]: InterfaceTransformerPropertyFunction<
Types, Types,
TypeName,
Type, Type,
ReturnTypes, ReturnTypes,
ReturnType, ReturnType,
@ -72,7 +85,8 @@ export type InterfaceTransformerDefinition<
export type UnionTransformerFunction< export type UnionTransformerFunction<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
Type extends UnionType<keyof Types>, TypeName extends keyof Types,
Type extends UnionType<keyof Types> & Types[TypeName],
ReturnTypes extends TransformerReturnTypes<Types>, ReturnTypes extends TransformerReturnTypes<Types>,
ReturnType extends UnionReturnType, ReturnType extends UnionReturnType,
Context, Context,
@ -82,31 +96,45 @@ export type UnionTransformerFunction<
ReturnTypes[Type["typeNames"]]["return"] ReturnTypes[Type["typeNames"]]["return"]
>, >,
setReturnPointer: SetReturnPointerFunction<ReturnType["return"]>, setReturnPointer: SetReturnPointerFunction<ReturnType["return"]>,
node: UnionInstanceNode<Types, TypeName, Type>,
context: Context, context: Context,
) => Promise<ReturnType["return"]>; ) => Promise<ReturnType["return"]>;
export type UnionTransformerDefinition< export type UnionTransformerDefinition<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
Type extends UnionType<keyof Types>, TypeName extends keyof Types,
Type extends UnionType<keyof Types> & Types[TypeName],
ReturnTypes extends TransformerReturnTypes<Types>, ReturnTypes extends TransformerReturnTypes<Types>,
ReturnType extends UnionReturnType, ReturnType extends UnionReturnType,
Context, Context,
> = UnionTransformerFunction<Types, Type, ReturnTypes, ReturnType, Context>; > = UnionTransformerFunction<
Types,
TypeName,
Type,
ReturnTypes,
ReturnType,
Context
>;
export type PrimitiveTransformerFunction< export type PrimitiveTransformerFunction<
Type extends PrimitiveType, Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends PrimitiveType & Types[TypeName],
ReturnType extends PrimitiveReturnType, ReturnType extends PrimitiveReturnType,
Context, Context,
> = ( > = (
originalData: Type["type"], originalData: Type["type"],
node: PrimitiveInstanceNode<Types, TypeName, Type>,
context: Context, context: Context,
) => Promise<ReturnType["return"]>; ) => Promise<ReturnType["return"]>;
export type PrimitiveTransformerDefinition< export type PrimitiveTransformerDefinition<
Type extends PrimitiveType, Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends PrimitiveType & Types[TypeName],
ReturnType extends PrimitiveReturnType, ReturnType extends PrimitiveReturnType,
Context, Context,
> = PrimitiveTransformerFunction<Type, ReturnType, Context>; > = PrimitiveTransformerFunction<Types, TypeName, Type, ReturnType, Context>;
export type TransformerDefinition< export type TransformerDefinition<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
@ -117,6 +145,7 @@ export type TransformerDefinition<
? ReturnTypes[TypeName] extends InterfaceReturnType<Types[TypeName]> ? ReturnTypes[TypeName] extends InterfaceReturnType<Types[TypeName]>
? InterfaceTransformerDefinition< ? InterfaceTransformerDefinition<
Types, Types,
TypeName,
Types[TypeName], Types[TypeName],
ReturnTypes, ReturnTypes,
ReturnTypes[TypeName], ReturnTypes[TypeName],
@ -127,6 +156,7 @@ export type TransformerDefinition<
? ReturnTypes[TypeName] extends UnionReturnType ? ReturnTypes[TypeName] extends UnionReturnType
? UnionTransformerDefinition< ? UnionTransformerDefinition<
Types, Types,
TypeName,
Types[TypeName], Types[TypeName],
ReturnTypes, ReturnTypes,
ReturnTypes[TypeName], ReturnTypes[TypeName],
@ -136,6 +166,8 @@ export type TransformerDefinition<
: Types[TypeName] extends PrimitiveType : Types[TypeName] extends PrimitiveType
? ReturnTypes[TypeName] extends PrimitiveReturnType ? ReturnTypes[TypeName] extends PrimitiveReturnType
? PrimitiveTransformerDefinition< ? PrimitiveTransformerDefinition<
Types,
TypeName,
Types[TypeName], Types[TypeName],
ReturnTypes[TypeName], ReturnTypes[TypeName],
Context Context
@ -161,15 +193,23 @@ export type Transformers<
*/ */
export type InterfaceTransformerInputDefinition< export type InterfaceTransformerInputDefinition<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
Type extends InterfaceType<keyof Types>, TypeName extends keyof Types,
Type extends InterfaceType<keyof Types> & Types[TypeName],
ReturnTypes extends TransformerReturnTypes<Types>, ReturnTypes extends TransformerReturnTypes<Types>,
ReturnType extends InterfaceReturnType<Type>, ReturnType extends InterfaceReturnType<Type>,
Context, Context,
> = { > = {
transformer: InterfaceTransformerFunction<Types, Type, ReturnType, Context>; transformer: InterfaceTransformerFunction<
Types,
TypeName,
Type,
ReturnType,
Context
>;
properties?: Partial<{ properties?: Partial<{
[PropertyName in keyof Type["properties"]]: InterfaceTransformerPropertyFunction< [PropertyName in keyof Type["properties"]]: InterfaceTransformerPropertyFunction<
Types, Types,
TypeName,
Type, Type,
ReturnTypes, ReturnTypes,
ReturnType, ReturnType,
@ -181,17 +221,27 @@ export type InterfaceTransformerInputDefinition<
export type UnionTransformerInputDefinition< export type UnionTransformerInputDefinition<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
Type extends UnionType<keyof Types>, TypeName extends keyof Types,
Type extends UnionType<keyof Types> & Types[TypeName],
ReturnTypes extends TransformerReturnTypes<Types>, ReturnTypes extends TransformerReturnTypes<Types>,
ReturnType extends UnionReturnType, ReturnType extends UnionReturnType,
Context, Context,
> = UnionTransformerFunction<Types, Type, ReturnTypes, ReturnType, Context>; > = UnionTransformerFunction<
Types,
TypeName,
Type,
ReturnTypes,
ReturnType,
Context
>;
export type PrimitiveTransformerInputDefinition< export type PrimitiveTransformerInputDefinition<
Type extends PrimitiveType, Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends PrimitiveType & Types[TypeName],
ReturnType extends PrimitiveReturnType, ReturnType extends PrimitiveReturnType,
Context, Context,
> = PrimitiveTransformerFunction<Type, ReturnType, Context>; > = PrimitiveTransformerFunction<Types, TypeName, Type, ReturnType, Context>;
export type TransformerInputDefinition< export type TransformerInputDefinition<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
@ -202,6 +252,7 @@ export type TransformerInputDefinition<
? ReturnTypes[TypeName] extends InterfaceReturnType<Types[TypeName]> ? ReturnTypes[TypeName] extends InterfaceReturnType<Types[TypeName]>
? InterfaceTransformerInputDefinition< ? InterfaceTransformerInputDefinition<
Types, Types,
TypeName,
Types[TypeName], Types[TypeName],
ReturnTypes, ReturnTypes,
ReturnTypes[TypeName], ReturnTypes[TypeName],
@ -212,6 +263,7 @@ export type TransformerInputDefinition<
? ReturnTypes[TypeName] extends UnionReturnType ? ReturnTypes[TypeName] extends UnionReturnType
? UnionTransformerInputDefinition< ? UnionTransformerInputDefinition<
Types, Types,
TypeName,
Types[TypeName], Types[TypeName],
ReturnTypes, ReturnTypes,
ReturnTypes[TypeName], ReturnTypes[TypeName],
@ -221,6 +273,8 @@ export type TransformerInputDefinition<
: Types[TypeName] extends PrimitiveType : Types[TypeName] extends PrimitiveType
? ReturnTypes[TypeName] extends PrimitiveReturnType ? ReturnTypes[TypeName] extends PrimitiveReturnType
? PrimitiveTransformerInputDefinition< ? PrimitiveTransformerInputDefinition<
Types,
TypeName,
Types[TypeName], Types[TypeName],
ReturnTypes[TypeName], ReturnTypes[TypeName],
Context Context

@ -1,20 +1,21 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import type { TraverserTypes } from ".."; import type { TraverserTypes } from "../../";
import type { import type {
InterfaceReturnType, InterfaceReturnType,
TransformerReturnTypes, TransformerReturnTypes,
} from "../TransformerReturnTypes"; } from "../TransformerReturnTypes";
import type { InterfaceTransformerDefinition } from "../Transformers"; import type { InterfaceTransformerDefinition } from "../Transformers";
import type { InterfaceTraverserDefinition } from "../traverser/TraverserDefinition"; import type { InterfaceTraverserDefinition } from "../../traverser/TraverserDefinition";
import type { InterfaceType } from "../traverser/TraverserTypes"; import type { InterfaceType } from "../../traverser/TraverserTypes";
import { transformerParentSubTraverser } from "./TransformerParentSubTraverser"; import { transformerParentSubTraverser } from "./TransformerParentSubTraverser";
import type { TransformerSubTraverserGlobals } from "./util/transformerSubTraverserTypes"; import type { TransformerSubTraverserGlobals } from "./util/transformerSubTraverserTypes";
import type { InterfaceInstanceNode } from "../../instanceGraph/nodes/InterfaceInstanceNode";
export async function transformerInterfaceSubTraverser< export async function transformerInterfaceSubTraverser<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
TypeName extends keyof Types, TypeName extends keyof Types,
ReturnTypes extends TransformerReturnTypes<Types>, ReturnTypes extends TransformerReturnTypes<Types>,
Type extends InterfaceType<keyof Types>, Type extends InterfaceType<keyof Types> & Types[TypeName],
ReturnType extends InterfaceReturnType<Type>, ReturnType extends InterfaceReturnType<Type>,
Context, Context,
>( >(
@ -40,6 +41,7 @@ export async function transformerInterfaceSubTraverser<
itemTypeName itemTypeName
] as unknown as InterfaceTransformerDefinition< ] as unknown as InterfaceTransformerDefinition<
Types, Types,
TypeName,
Type, Type,
ReturnTypes, ReturnTypes,
ReturnType, ReturnType,
@ -99,6 +101,14 @@ export async function transformerInterfaceSubTraverser<
return toReturn; return toReturn;
} }
}, },
globals.instanceGraph.getNodeFor(
item,
itemTypeName,
) as unknown as InterfaceInstanceNode<
Types,
TypeName,
Type
>,
globals.context, globals.context,
); );
return [propertyName, transformedProperty]; return [propertyName, transformedProperty];
@ -111,6 +121,10 @@ export async function transformerInterfaceSubTraverser<
(input) => { (input) => {
resolve(input); resolve(input);
}, },
globals.instanceGraph.getNodeFor(
item,
itemTypeName,
) as unknown as InterfaceInstanceNode<Types, TypeName, Type>,
globals.context, globals.context,
); );
resolve(transformedObject); resolve(transformedObject);

@ -1,5 +1,9 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import type { BaseReturnType, BaseTraverserTypes, TraverserTypes } from ".."; import type {
BaseReturnType,
BaseTraverserTypes,
TraverserTypes,
} from "../../";
import type { TransformerReturnTypes } from "../TransformerReturnTypes"; import type { TransformerReturnTypes } from "../TransformerReturnTypes";
import { transformerInterfaceSubTraverser } from "./TransformerInterfaceSubTraverser"; import { transformerInterfaceSubTraverser } from "./TransformerInterfaceSubTraverser";
import { transformerPrimitiveSubTraverser } from "./TransformerPrimitiveSubTraverser"; import { transformerPrimitiveSubTraverser } from "./TransformerPrimitiveSubTraverser";

@ -1,18 +1,19 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import type { TraverserTypes } from ".."; import type { TraverserTypes } from "../../";
import type { PrimitiveInstanceNode } from "../../instanceGraph/nodes/PrimitiveInstanceNode";
import type { import type {
PrimitiveReturnType, PrimitiveReturnType,
TransformerReturnTypes, TransformerReturnTypes,
} from "../TransformerReturnTypes"; } from "../TransformerReturnTypes";
import type { PrimitiveTransformerDefinition } from "../Transformers"; import type { PrimitiveTransformerDefinition } from "../Transformers";
import type { PrimitiveType } from "../traverser/TraverserTypes"; import type { PrimitiveType } from "../../traverser/TraverserTypes";
import type { TransformerSubTraverserGlobals } from "./util/transformerSubTraverserTypes"; import type { TransformerSubTraverserGlobals } from "./util/transformerSubTraverserTypes";
export async function transformerPrimitiveSubTraverser< export async function transformerPrimitiveSubTraverser<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
TypeName extends keyof Types, TypeName extends keyof Types,
ReturnTypes extends TransformerReturnTypes<Types>, ReturnTypes extends TransformerReturnTypes<Types>,
Type extends PrimitiveType, Type extends PrimitiveType & Types[TypeName],
ReturnType extends PrimitiveReturnType, ReturnType extends PrimitiveReturnType,
Context, Context,
>( >(
@ -23,6 +24,19 @@ export async function transformerPrimitiveSubTraverser<
const { transformers } = globals; const { transformers } = globals;
const transformer = transformers[ const transformer = transformers[
itemTypeName itemTypeName
] as unknown as PrimitiveTransformerDefinition<Type, ReturnType, Context>; ] as unknown as PrimitiveTransformerDefinition<
return transformer(item, globals.context); Types,
TypeName,
Type,
ReturnType,
Context
>;
return transformer(
item,
globals.instanceGraph.getNodeFor(
item,
itemTypeName,
) as unknown as PrimitiveInstanceNode<Types, TypeName, Type>,
globals.context,
);
} }

@ -1,12 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import type { TraverserTypes } from ".."; import type { TraverserTypes } from "../../";
import type { UnionInstanceNode } from "../../instanceGraph/nodes/UnionInstanceNode";
import type { import type {
TransformerReturnTypes, TransformerReturnTypes,
UnionReturnType, UnionReturnType,
} from "../TransformerReturnTypes"; } from "../TransformerReturnTypes";
import type { UnionTransformerDefinition } from "../Transformers"; import type { UnionTransformerDefinition } from "../Transformers";
import type { UnionTraverserDefinition } from "../traverser/TraverserDefinition"; import type { UnionTraverserDefinition } from "../../traverser/TraverserDefinition";
import type { UnionType } from "../traverser/TraverserTypes"; import type { UnionType } from "../../traverser/TraverserTypes";
import { transformerParentSubTraverser } from "./TransformerParentSubTraverser"; import { transformerParentSubTraverser } from "./TransformerParentSubTraverser";
import type { TransformerSubTraverserGlobals } from "./util/transformerSubTraverserTypes"; import type { TransformerSubTraverserGlobals } from "./util/transformerSubTraverserTypes";
@ -14,7 +15,7 @@ export async function transformerUnionSubTraverser<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
TypeName extends keyof Types, TypeName extends keyof Types,
ReturnTypes extends TransformerReturnTypes<Types>, ReturnTypes extends TransformerReturnTypes<Types>,
Type extends UnionType<keyof Types>, Type extends UnionType<keyof Types> & Types[TypeName],
ReturnType extends UnionReturnType, ReturnType extends UnionReturnType,
Context, Context,
>( >(
@ -39,6 +40,7 @@ export async function transformerUnionSubTraverser<
itemTypeName itemTypeName
] as unknown as UnionTransformerDefinition< ] as unknown as UnionTransformerDefinition<
Types, Types,
TypeName,
Type, Type,
ReturnTypes, ReturnTypes,
ReturnType, ReturnType,
@ -66,6 +68,10 @@ export async function transformerUnionSubTraverser<
(input) => { (input) => {
resolve(input); resolve(input);
}, },
globals.instanceGraph.getNodeFor(
item,
itemTypeName,
) as unknown as UnionInstanceNode<Types, TypeName, Type>,
globals.context, globals.context,
); );
resolve(transformedObject); resolve(transformedObject);

@ -1,4 +1,4 @@
import type { KeyTypes } from "../.."; import type { KeyTypes } from "../../../";
import { MultiMap } from "./MultiMap"; import { MultiMap } from "./MultiMap";
import { MultiSet } from "./MultiSet"; import { MultiSet } from "./MultiSet";
import type { TransformerSubTraverserExecutingPromises } from "./transformerSubTraverserTypes"; import type { TransformerSubTraverserExecutingPromises } from "./transformerSubTraverserTypes";

@ -6,7 +6,8 @@ import type {
TransformerReturnTypes, TransformerReturnTypes,
TraverserDefinitions, TraverserDefinitions,
TraverserTypes, TraverserTypes,
} from "../.."; } from "../../../";
import type { InstanceGraph } from "../../../instanceGraph/instanceGraph";
import type { Transformers } from "../../Transformers"; import type { Transformers } from "../../Transformers";
import type { CircularDepenedencyAwaiter } from "./CircularDependencyAwaiter"; import type { CircularDepenedencyAwaiter } from "./CircularDependencyAwaiter";
import type { MultiMap } from "./MultiMap"; import type { MultiMap } from "./MultiMap";
@ -35,6 +36,7 @@ export interface TransformerSubTraverserGlobals<
executingPromises: TransformerSubTraverserExecutingPromises<keyof Types>; executingPromises: TransformerSubTraverserExecutingPromises<keyof Types>;
circularDependencyAwaiter: CircularDepenedencyAwaiter; circularDependencyAwaiter: CircularDepenedencyAwaiter;
superPromise: SuperPromise; superPromise: SuperPromise;
instanceGraph: InstanceGraph<Types>;
context: Context; context: Context;
} }

@ -15,8 +15,9 @@ import type {
UnionVisitorInputDefinition, UnionVisitorInputDefinition,
Visitors, Visitors,
VisitorsInput, VisitorsInput,
} from "."; } from "../";
import { MultiSet } from "./transformerSubTraversers/util/MultiSet"; import { InstanceGraph } from "../instanceGraph/instanceGraph";
import { MultiSet } from "../transformer/transformerSubTraversers/util/MultiSet";
import { visitorParentSubTraverser } from "./visitorSubTraversers/VisitorParentSubTraverser"; import { visitorParentSubTraverser } from "./visitorSubTraversers/VisitorParentSubTraverser";
// TODO: Lots of "any" in this file. I'm just done with fancy typescript, // TODO: Lots of "any" in this file. I'm just done with fancy typescript,
@ -39,15 +40,17 @@ export class Visitor<
} }
private applyDefaultInterfaceVisitorProperties< private applyDefaultInterfaceVisitorProperties<
Type extends InterfaceType<keyof Types>, TypeName extends keyof Types,
Type extends InterfaceType<keyof Types> & Types[TypeName],
>( >(
typeName: keyof Types, typeName: keyof Types,
typePropertiesInput: InterfaceVisitorInputDefinition< typePropertiesInput: InterfaceVisitorInputDefinition<
Types, Types,
TypeName,
Type, Type,
Context Context
>["properties"], >["properties"],
): InterfaceVisitorDefinition<Types, Type, Context>["properties"] { ): InterfaceVisitorDefinition<Types, TypeName, Type, Context>["properties"] {
return Object.keys( return Object.keys(
(this.traverserDefinition[typeName] as InterfaceTraverserDefinition<Type>) (this.traverserDefinition[typeName] as InterfaceTraverserDefinition<Type>)
.properties, .properties,
@ -60,13 +63,21 @@ export class Visitor<
}; };
} }
return agg; return agg;
}, {}) as InterfaceVisitorDefinition<Types, Type, Context>["properties"]; }, {}) as InterfaceVisitorDefinition<
Types,
TypeName,
Type,
Context
>["properties"];
} }
private applyDefaultInterfaceVisitor<Type extends InterfaceType<keyof Types>>( private applyDefaultInterfaceVisitor<
TypeName extends keyof Types,
Type extends InterfaceType<keyof Types> & Types[TypeName],
>(
typeName: keyof Types, typeName: keyof Types,
typeInput?: InterfaceVisitorInputDefinition<Types, Type, Context>, typeInput?: InterfaceVisitorInputDefinition<Types, TypeName, Type, Context>,
): InterfaceVisitorDefinition<Types, Type, Context> { ): InterfaceVisitorDefinition<Types, TypeName, Type, Context> {
if (!typeInput) { if (!typeInput) {
return { return {
visitor: async () => { visitor: async () => {
@ -84,9 +95,12 @@ export class Visitor<
}; };
} }
private applyDefaultUnionVisitor<Type extends UnionType<keyof Types>>( private applyDefaultUnionVisitor<
typeInput?: UnionVisitorInputDefinition<Types, Type, Context>, TypeName extends keyof Types,
): UnionVisitorDefinition<Types, Type, Context> { Type extends UnionType<keyof Types> & Types[TypeName],
>(
typeInput?: UnionVisitorInputDefinition<Types, TypeName, Type, Context>,
): UnionVisitorDefinition<Types, TypeName, Type, Context> {
if (!typeInput) { if (!typeInput) {
return async () => { return async () => {
return; return;
@ -95,9 +109,12 @@ export class Visitor<
return typeInput; return typeInput;
} }
private applyDefaultPrimitiveVisitor<Type extends PrimitiveType>( private applyDefaultPrimitiveVisitor<
typeInput?: PrimitiveVisitorInputDefinition<Type, Context>, TypeName extends keyof Types,
): PrimitiveVisitorDefinition<Type, Context> { Type extends PrimitiveType & Types[TypeName],
>(
typeInput?: PrimitiveVisitorInputDefinition<Types, TypeName, Type, Context>,
): PrimitiveVisitorDefinition<Types, TypeName, Type, Context> {
if (!typeInput) { if (!typeInput) {
return async () => { return async () => {
return; return;
@ -134,10 +151,13 @@ export class Visitor<
itemTypeName: TypeName, itemTypeName: TypeName,
context: Context, context: Context,
): Promise<void> { ): Promise<void> {
const instanceGraph = new InstanceGraph(this.traverserDefinition);
instanceGraph.getNodeFor(item, itemTypeName);
const toReturn = await visitorParentSubTraverser(item, itemTypeName, { const toReturn = await visitorParentSubTraverser(item, itemTypeName, {
traverserDefinition: this.traverserDefinition, traverserDefinition: this.traverserDefinition,
visitors: this.visitors, visitors: this.visitors,
visitedObjects: new MultiSet(), visitedObjects: new MultiSet(),
instanceGraph,
context, context,
}); });
return toReturn; return toReturn;

@ -0,0 +1,157 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type {
InterfaceType,
PrimitiveType,
TraverserTypes,
UnionType,
} from "../";
import type { InterfaceInstanceNode } from "../instanceGraph/nodes/InterfaceInstanceNode";
import type { PrimitiveInstanceNode } from "../instanceGraph/nodes/PrimitiveInstanceNode";
import type { UnionInstanceNode } from "../instanceGraph/nodes/UnionInstanceNode";
export type InterfaceVisitorFunction<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends InterfaceType<keyof Types> & Types[TypeName],
Context,
> = (
originalData: Type["type"],
node: InterfaceInstanceNode<Types, TypeName, Type>,
context: Context,
) => Promise<void>;
export type InterfaceVisitorPropertyFunction<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends InterfaceType<keyof Types> & Types[TypeName],
PropertyName extends keyof Type["properties"],
Context,
> = (
originalData: Types[Type["properties"][PropertyName]]["type"],
node: InterfaceInstanceNode<Types, TypeName, Type>,
context: Context,
) => Promise<void>;
export type InterfaceVisitorDefinition<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends InterfaceType<keyof Types> & Types[TypeName],
Context,
> = {
visitor: InterfaceVisitorFunction<Types, TypeName, Type, Context>;
properties: {
[PropertyName in keyof Type["properties"]]: InterfaceVisitorPropertyFunction<
Types,
TypeName,
Type,
PropertyName,
Context
>;
};
};
export type UnionVisitorFunction<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends UnionType<keyof Types> & Types[TypeName],
Context,
> = (
originalData: Type["type"],
node: UnionInstanceNode<Types, TypeName, Type>,
context: Context,
) => Promise<void>;
export type UnionVisitorDefinition<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends UnionType<keyof Types> & Types[TypeName],
Context,
> = UnionVisitorFunction<Types, TypeName, Type, Context>;
export type PrimitiveVisitorFunction<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends PrimitiveType & Types[TypeName],
Context,
> = (
originalData: Type["type"],
node: PrimitiveInstanceNode<Types, TypeName, Type>,
context: Context,
) => Promise<void>;
export type PrimitiveVisitorDefinition<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends PrimitiveType & Types[TypeName],
Context,
> = PrimitiveVisitorFunction<Types, TypeName, Type, Context>;
export type VisitorDefinition<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Context,
> = Types[TypeName] extends InterfaceType<keyof Types>
? InterfaceVisitorDefinition<Types, TypeName, Types[TypeName], Context>
: Types[TypeName] extends UnionType<keyof Types>
? UnionVisitorDefinition<Types, TypeName, Types[TypeName], Context>
: Types[TypeName] extends PrimitiveType
? PrimitiveVisitorDefinition<Types, TypeName, Types[TypeName], Context>
: never;
export type Visitors<Types extends TraverserTypes<any>, Context> = {
[TypeName in keyof Types]: VisitorDefinition<Types, TypeName, Context>;
};
/**
* Input
*/
export type InterfaceVisitorInputDefinition<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends InterfaceType<keyof Types> & Types[TypeName],
Context,
> = {
visitor: InterfaceVisitorFunction<Types, TypeName, Type, Context>;
properties?: Partial<{
[PropertyName in keyof Type["properties"]]: InterfaceVisitorPropertyFunction<
Types,
TypeName,
Type,
PropertyName,
Context
>;
}>;
};
export type UnionVisitorInputDefinition<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends UnionType<keyof Types> & Types[TypeName],
Context,
> = UnionVisitorFunction<Types, TypeName, Type, Context>;
export type PrimitiveVisitorInputDefinition<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends PrimitiveType & Types[TypeName],
Context,
> = PrimitiveVisitorFunction<Types, TypeName, Type, Context>;
export type VisitorInputDefinition<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Context,
> = Types[TypeName] extends InterfaceType<keyof Types>
? InterfaceVisitorInputDefinition<Types, TypeName, Types[TypeName], Context>
: Types[TypeName] extends UnionType<keyof Types>
? UnionVisitorInputDefinition<Types, TypeName, Types[TypeName], Context>
: Types[TypeName] extends PrimitiveType
? PrimitiveVisitorInputDefinition<Types, TypeName, Types[TypeName], Context>
: never;
export type VisitorsInput<
Types extends TraverserTypes<any>,
Context,
> = Partial<{
[TypeName in keyof Types]: VisitorInputDefinition<Types, TypeName, Context>;
}>;

@ -1,14 +1,15 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import type { InterfaceVisitorDefinition, TraverserTypes } from ".."; import type { InterfaceVisitorDefinition, TraverserTypes } from "../../";
import type { InterfaceTraverserDefinition } from "../traverser/TraverserDefinition"; import type { InterfaceInstanceNode } from "../../instanceGraph/nodes/InterfaceInstanceNode";
import type { InterfaceType } from "../traverser/TraverserTypes"; import type { InterfaceTraverserDefinition } from "../../traverser/TraverserDefinition";
import type { InterfaceType } from "../../traverser/TraverserTypes";
import type { VisitorSubTraverserGlobals } from "./util/visitorSubTraverserTypes"; import type { VisitorSubTraverserGlobals } from "./util/visitorSubTraverserTypes";
import { visitorParentSubTraverser } from "./VisitorParentSubTraverser"; import { visitorParentSubTraverser } from "./VisitorParentSubTraverser";
export async function visitorInterfaceSubTraverser< export async function visitorInterfaceSubTraverser<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
TypeName extends keyof Types, TypeName extends keyof Types,
Type extends InterfaceType<keyof Types>, Type extends InterfaceType<keyof Types> & Types[TypeName],
Context, Context,
>( >(
item: Type["type"], item: Type["type"],
@ -22,16 +23,27 @@ export async function visitorInterfaceSubTraverser<
] as InterfaceTraverserDefinition<Type>; ] as InterfaceTraverserDefinition<Type>;
const visitor = visitors[ const visitor = visitors[
itemTypeName itemTypeName
] as unknown as InterfaceVisitorDefinition<Types, Type, Context>; ] as unknown as InterfaceVisitorDefinition<Types, TypeName, Type, Context>;
await Promise.all([ await Promise.all([
visitor.visitor(item, globals.context), visitor.visitor(
item,
globals.instanceGraph.getNodeFor(
item,
itemTypeName,
) as unknown as InterfaceInstanceNode<Types, TypeName, Type>,
globals.context,
),
Promise.all( Promise.all(
Object.entries(definition.properties).map(async ([propertyName]) => { Object.entries(definition.properties).map(async ([propertyName]) => {
const originalObject = item[propertyName]; const originalObject = item[propertyName];
const originalPropertyDefinition = definition.properties[propertyName]; const originalPropertyDefinition = definition.properties[propertyName];
const propertyVisitorPromise = visitor.properties[propertyName]( const propertyVisitorPromise = visitor.properties[propertyName](
originalObject, originalObject,
globals.instanceGraph.getNodeFor(
item,
itemTypeName,
) as unknown as InterfaceInstanceNode<Types, TypeName, Type>,
globals.context, globals.context,
); );
let propertyTraverserPromise: Promise<void | void[]>; let propertyTraverserPromise: Promise<void | void[]>;

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import type { BaseTraverserTypes, TraverserTypes } from ".."; import type { BaseTraverserTypes, TraverserTypes } from "../../";
import type { import type {
VisitorSubTraverser, VisitorSubTraverser,
VisitorSubTraverserGlobals, VisitorSubTraverserGlobals,

@ -1,12 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import type { PrimitiveVisitorDefinition, TraverserTypes } from ".."; import type { PrimitiveVisitorDefinition, TraverserTypes } from "../../";
import type { PrimitiveType } from "../traverser/TraverserTypes"; import type { PrimitiveInstanceNode } from "../../instanceGraph/nodes/PrimitiveInstanceNode";
import type { PrimitiveType } from "../../traverser/TraverserTypes";
import type { VisitorSubTraverserGlobals } from "./util/visitorSubTraverserTypes"; import type { VisitorSubTraverserGlobals } from "./util/visitorSubTraverserTypes";
export async function visitorPrimitiveSubTraverser< export async function visitorPrimitiveSubTraverser<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
TypeName extends keyof Types, TypeName extends keyof Types,
Type extends PrimitiveType, Type extends PrimitiveType & Types[TypeName],
Context, Context,
>( >(
item: Type["type"], item: Type["type"],
@ -16,6 +17,13 @@ export async function visitorPrimitiveSubTraverser<
const { visitors } = globals; const { visitors } = globals;
const visitor = visitors[ const visitor = visitors[
itemTypeName itemTypeName
] as unknown as PrimitiveVisitorDefinition<Type, Context>; ] as unknown as PrimitiveVisitorDefinition<Types, TypeName, Type, Context>;
return visitor(item, globals.context); return visitor(
item,
globals.instanceGraph.getNodeFor(
item,
itemTypeName,
) as unknown as PrimitiveInstanceNode<Types, TypeName, Type>,
globals.context,
);
} }

@ -1,14 +1,15 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import type { TraverserTypes, UnionVisitorDefinition } from ".."; import type { TraverserTypes, UnionVisitorDefinition } from "../../";
import type { UnionTraverserDefinition } from "../traverser/TraverserDefinition"; import type { UnionInstanceNode } from "../../instanceGraph/nodes/UnionInstanceNode";
import type { UnionType } from "../traverser/TraverserTypes"; import type { UnionTraverserDefinition } from "../../traverser/TraverserDefinition";
import type { UnionType } from "../../traverser/TraverserTypes";
import type { VisitorSubTraverserGlobals } from "./util/visitorSubTraverserTypes"; import type { VisitorSubTraverserGlobals } from "./util/visitorSubTraverserTypes";
import { visitorParentSubTraverser } from "./VisitorParentSubTraverser"; import { visitorParentSubTraverser } from "./VisitorParentSubTraverser";
export async function visitorUnionSubTraverser< export async function visitorUnionSubTraverser<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
TypeName extends keyof Types, TypeName extends keyof Types,
Type extends UnionType<keyof Types>, Type extends UnionType<keyof Types> & Types[TypeName],
Context, Context,
>( >(
item: Type["type"], item: Type["type"],
@ -21,12 +22,20 @@ export async function visitorUnionSubTraverser<
] as UnionTraverserDefinition<Type>; ] as UnionTraverserDefinition<Type>;
const visitor = visitors[itemTypeName] as unknown as UnionVisitorDefinition< const visitor = visitors[itemTypeName] as unknown as UnionVisitorDefinition<
Types, Types,
TypeName,
Type, Type,
Context Context
>; >;
const itemSpecificTypeName = definition.selector(item); const itemSpecificTypeName = definition.selector(item);
await Promise.all([ await Promise.all([
visitor(item, globals.context), visitor(
item,
globals.instanceGraph.getNodeFor(
item,
itemTypeName,
) as unknown as UnionInstanceNode<Types, TypeName, Type>,
globals.context,
),
visitorParentSubTraverser(item, itemSpecificTypeName, globals), visitorParentSubTraverser(item, itemSpecificTypeName, globals),
]); ]);
} }

@ -4,8 +4,9 @@ import type {
TraverserDefinitions, TraverserDefinitions,
TraverserTypes, TraverserTypes,
Visitors, Visitors,
} from "../.."; } from "../../../";
import type { MultiSet } from "../../transformerSubTraversers/util/MultiSet"; import type { InstanceGraph } from "../../../instanceGraph/instanceGraph";
import type { MultiSet } from "../../../transformer/transformerSubTraversers/util/MultiSet";
export type VisitorSubTraverser< export type VisitorSubTraverser<
Types extends TraverserTypes<any>, Types extends TraverserTypes<any>,
@ -25,5 +26,6 @@ export interface VisitorSubTraverserGlobals<
traverserDefinition: TraverserDefinitions<Types>; traverserDefinition: TraverserDefinitions<Types>;
visitors: Visitors<Types, Context>; visitors: Visitors<Types, Context>;
visitedObjects: MultiSet<object, keyof Types>; visitedObjects: MultiSet<object, keyof Types>;
instanceGraph: InstanceGraph<Types>;
context: Context; context: Context;
} }

@ -0,0 +1,156 @@
import type { TraverserDefinitions, ValidateTraverserTypes } from "../../src";
import { InstanceGraph } from "../../src/instanceGraph/instanceGraph";
describe("InstanceGraph", () => {
/**
* Types
*/
type Element = "Water" | "Earth" | "Fire" | "Air";
interface Bender {
name: string;
element: Element;
friends: Person[];
}
interface NonBender {
name: string;
friends: Person[];
}
type Person = Bender | NonBender;
/**
* Raw Data to Traverse
*/
const aang: Bender = {
name: "Aang",
element: "Air",
friends: [],
};
const sokka: NonBender = {
name: "Sokka",
friends: [],
};
const katara: Bender = {
name: "Katara",
element: "Water",
friends: [],
};
aang.friends.push(sokka, katara);
sokka.friends.push(aang, katara);
katara.friends.push(aang, sokka);
/**
* Traverser Types
*/
type AvatarTraverserTypes = ValidateTraverserTypes<{
Element: {
kind: "primitive";
type: Element;
};
Bender: {
kind: "interface";
type: Bender;
properties: {
element: "Element";
friends: "Person";
};
};
NonBender: {
kind: "interface";
type: NonBender;
properties: {
friends: "Person";
};
};
Person: {
kind: "union";
type: Person;
typeNames: "Bender" | "NonBender";
};
}>;
/**
* Create the traverser definition
*/
const avatarTraverserDefinition: TraverserDefinitions<AvatarTraverserTypes> =
{
Element: {
kind: "primitive",
},
Bender: {
kind: "interface",
properties: {
element: "Element",
friends: "Person",
},
},
NonBender: {
kind: "interface",
properties: {
friends: "Person",
},
},
Person: {
kind: "union",
selector: (item) => {
return (item as Bender).element ? "Bender" : "NonBender";
},
},
};
describe("Build Instance Graph", () => {
it("returns child nodes when child methods are called.", () => {
const graph = new InstanceGraph(avatarTraverserDefinition);
const aangBender = graph.getNodeFor(aang, "Bender");
expect(aangBender.typeName).toBe("Bender");
expect(aangBender.instance.name).toBe("Aang");
// child
const aangElement = aangBender.child("element");
expect(aangElement.instance).toBe("Air");
expect(aangElement.typeName).toBe("Element");
const aangFriends = aangBender.child("friends");
expect(aangFriends.length).toBe(2);
const sokkaPerson = aangFriends[0];
const kataraPerson = aangFriends[1];
expect(sokkaPerson.instance.name).toBe("Sokka");
expect(kataraPerson.instance.name).toBe("Katara");
expect(sokkaPerson.typeName).toBe("Person");
expect(kataraPerson.typeName).toBe("Person");
const sokkaNonBender = sokkaPerson.child();
expect(sokkaNonBender.instance.name).toBe("Sokka");
expect(sokkaNonBender.typeName).toBe("NonBender");
if (sokkaNonBender.typeName === "NonBender") {
const aangPerson = sokkaNonBender.child("friends")[0];
const aangBender2 = aangPerson.child();
expect(aangBender2).toBe(aangBender);
}
// allChildren
const [childElemement, childSokka, childKatara] =
aangBender.allChildren();
expect(childElemement.instance).toBe("Air");
expect((childSokka.instance as NonBender).name).toBe("Sokka");
expect((childKatara.instance as Bender).name).toBe("Katara");
const childOfSokkaPerson = sokkaPerson.allChildren();
expect(childOfSokkaPerson.length).toBe(1);
expect(childOfSokkaPerson[0].instance.name).toBe("Sokka");
});
it("returns parent nodes when parent methods are called.", () => {
const graph = new InstanceGraph(avatarTraverserDefinition);
const aangBender = graph.getNodeFor(aang, "Bender");
// parent
const [aangPerson] = aangBender.parent("Person");
expect(aangPerson.instance.name).toBe("Aang");
expect(aangPerson.typeName).toBe("Person");
const [sokkaNonBender] = aangPerson.parent("NonBender", "friends");
const [kataraBender] = aangPerson.parent("Bender", "friends");
expect(sokkaNonBender.typeName).toBe("NonBender");
expect(sokkaNonBender.instance.name).toBe("Sokka");
expect(kataraBender.typeName).toBe("Bender");
expect(kataraBender.instance.name).toBe("Katara");
});
});
describe("Transformer", () => {
it("transforms", () => {});
});
});

@ -1,7 +1,7 @@
import type { TraverserDefinition } from "../../../src"; import type { TraverserDefinitions } from "../../../src";
import type { AvatarTraverserTypes, Bender } from "./AvatarTraverserTypes"; import type { AvatarTraverserTypes, Bender } from "./AvatarTraverserTypes";
export const avatarTraverserDefinition: TraverserDefinition<AvatarTraverserTypes> = export const avatarTraverserDefinition: TraverserDefinitions<AvatarTraverserTypes> =
{ {
Element: { Element: {
kind: "primitive", kind: "primitive",

@ -1,161 +1,19 @@
import type { import { BrokenAvatarTransformer } from "./AvatarBrokenTransformer";
TraverserDefinitions, import { AvatarErroringTransformer } from "./AvatarErroringTransformer";
ValidateTraverserTypes, import { aang } from "./sampleData";
} from "../../../src";
import { InstanceGraph } from "../../../src/instanceGraph/instanceGraph";
describe("AvatarExample", () => { describe("Avatar", () => {
/** it("Throws an error before entering an infinite loop", async () => {
* Types await expect(
*/ BrokenAvatarTransformer.transform(aang, "Bender", undefined),
type Element = "Water" | "Earth" | "Fire" | "Air"; ).rejects.toThrow(
interface Bender { `Circular dependency found. Use the 'setReturnPointer' function. The loop includes the 'Bender' type`,
name: string; );
element: Element;
friends: Person[];
}
interface NonBender {
name: string;
friends: Person[];
}
type Person = Bender | NonBender;
/**
* Raw Data to Traverse
*/
const aang: Bender = {
name: "Aang",
element: "Air",
friends: [],
};
const sokka: NonBender = {
name: "Sokka",
friends: [],
};
const katara: Bender = {
name: "Katara",
element: "Water",
friends: [],
};
aang.friends.push(sokka, katara);
sokka.friends.push(aang, katara);
katara.friends.push(aang, sokka);
/**
* Traverser Types
*/
type AvatarTraverserTypes = ValidateTraverserTypes<{
Element: {
kind: "primitive";
type: Element;
};
Bender: {
kind: "interface";
type: Bender;
properties: {
element: "Element";
friends: "Person";
};
};
NonBender: {
kind: "interface";
type: NonBender;
properties: {
friends: "Person";
};
};
Person: {
kind: "union";
type: Person;
typeNames: "Bender" | "NonBender";
};
}>;
/**
* Create the traverser definition
*/
const avatarTraverserDefinition: TraverserDefinitions<AvatarTraverserTypes> =
{
Element: {
kind: "primitive",
},
Bender: {
kind: "interface",
properties: {
element: "Element",
friends: "Person",
},
},
NonBender: {
kind: "interface",
properties: {
friends: "Person",
},
},
Person: {
kind: "union",
selector: (item) => {
return (item as Bender).element ? "Bender" : "NonBender";
},
},
};
describe("Build Instance Graph", () => {
it("returns child nodes when child methods are called.", () => {
const graph = new InstanceGraph(avatarTraverserDefinition);
const aangBender = graph.getNodeFor(aang, "Bender");
expect(aangBender.typeName).toBe("Bender");
expect(aangBender.instance.name).toBe("Aang");
// child
const aangElement = aangBender.child("element");
expect(aangElement.instance).toBe("Air");
expect(aangElement.typeName).toBe("Element");
const aangFriends = aangBender.child("friends");
expect(aangFriends.length).toBe(2);
const sokkaPerson = aangFriends[0];
const kataraPerson = aangFriends[1];
expect(sokkaPerson.instance.name).toBe("Sokka");
expect(kataraPerson.instance.name).toBe("Katara");
expect(sokkaPerson.typeName).toBe("Person");
expect(kataraPerson.typeName).toBe("Person");
const sokkaNonBender = sokkaPerson.child();
expect(sokkaNonBender.instance.name).toBe("Sokka");
expect(sokkaNonBender.typeName).toBe("NonBender");
if (sokkaNonBender.typeName === "NonBender") {
const aangPerson = sokkaNonBender.child("friends")[0];
const aangBender2 = aangPerson.child();
expect(aangBender2).toBe(aangBender);
}
// allChildren
const [childElemement, childSokka, childKatara] =
aangBender.allChildren();
expect(childElemement.instance).toBe("Air");
expect((childSokka.instance as NonBender).name).toBe("Sokka");
expect((childKatara.instance as Bender).name).toBe("Katara");
const childOfSokkaPerson = sokkaPerson.allChildren();
expect(childOfSokkaPerson.length).toBe(1);
expect(childOfSokkaPerson[0].instance.name).toBe("Sokka");
});
it("returns parent nodes when parent methods are called.", () => {
const graph = new InstanceGraph(avatarTraverserDefinition);
const aangBender = graph.getNodeFor(aang, "Bender");
// parent
const [aangPerson] = aangBender.parent("Person");
expect(aangPerson.instance.name).toBe("Aang");
expect(aangPerson.typeName).toBe("Person");
const [sokkaNonBender] = aangPerson.parent("NonBender", "friends");
const [kataraBender] = aangPerson.parent("Bender", "friends");
expect(sokkaNonBender.typeName).toBe("NonBender");
expect(sokkaNonBender.instance.name).toBe("Sokka");
expect(kataraBender.typeName).toBe("Bender");
expect(kataraBender.instance.name).toBe("Katara");
});
}); });
describe("Transformer", () => { it("Bubbles errors", async () => {
it("transforms", () => { await expect(
AvatarErroringTransformer.transform(aang, "Bender", undefined),
}) ).rejects.toThrow("No Non Benders Allowed");
}); });
}); });

@ -1,19 +0,0 @@
import { BrokenAvatarTransformer } from "./AvatarBrokenTransformer";
import { AvatarErroringTransformer } from "./AvatarErroringTransformer";
import { aang } from "./sampleData";
describe("Avatar", () => {
it("Throws an error before entering an infinite loop", async () => {
await expect(
BrokenAvatarTransformer.transform(aang, "Bender", undefined),
).rejects.toThrow(
`Circular dependency found. Use the 'setReturnPointer' function. The loop includes the 'Bender' type`,
);
});
it("Bubbles errors", async () => {
await expect(
AvatarErroringTransformer.transform(aang, "Bender", undefined),
).rejects.toThrow("No Non Benders Allowed");
});
});
Loading…
Cancel
Save