From 3316818633146b6ea294263d0f7cdfcf945cd9c9 Mon Sep 17 00:00:00 2001 From: Jackson Morgan Date: Wed, 18 Dec 2024 00:35:56 -0500 Subject: [PATCH] Refactor Visitor and Transformer to include an instance graph --- packages/type-traverser/README.md | 10 +- packages/type-traverser/src/Visitors.ts | 126 ------------- packages/type-traverser/src/index.ts | 4 +- .../src/instanceGraph/InstanceGraph.ts | 2 +- .../ReverseRelationshipTypes.ts | 2 +- .../src/instanceGraph/nodes/InstanceNode.ts | 2 +- .../src/transformer/Transformer.ts | 47 +++-- .../src/transformer/Transformers.ts | 88 +++++++-- .../TransformerInterfaceSubTraverser.ts | 22 ++- .../TransformerParentSubTraverser.ts | 6 +- .../TransformerPrimitiveSubTraverser.ts | 24 ++- .../TransformerUnionSubTraverser.ts | 14 +- .../util/CircularDependencyAwaiter.ts | 2 +- .../transformerSubTraversers/util/MultiMap.ts | 0 .../transformerSubTraversers/util/MultiSet.ts | 0 .../util/SuperPromise.ts | 0 .../transformerSubTraversers/util/timeout.ts | 0 .../util/transformerSubTraverserTypes.ts | 4 +- .../src/{ => visitor}/Visitor.ts | 48 +++-- .../type-traverser/src/visitor/Visitors.ts | 157 ++++++++++++++++ .../VisitorInterfaceSubTraverser.ts | 24 ++- .../VisitorParentSubTraverser.ts | 2 +- .../VisitorPrimitiveSubTraverser.ts | 18 +- .../VisitorUnionSubTraverser.ts | 19 +- .../util/visitorSubTraverserTypes.ts | 6 +- .../test/integration/InstanceGraph.test.ts | 156 ++++++++++++++++ .../AvatarBrokenTransformer.ts | 0 .../AvatarErroringTransformer.ts | 0 .../AvatarTraverserDefinition.ts | 4 +- .../AvatarTraverserTypes.ts | 0 .../test/integration/avatar/avatar.test.ts | 170 ++---------------- .../{avatar_old => avatar}/sampleData.ts | 0 .../test/integration/avatar_old/avatar.old.ts | 19 -- 33 files changed, 587 insertions(+), 389 deletions(-) delete mode 100644 packages/type-traverser/src/Visitors.ts rename packages/type-traverser/src/{ => instanceGraph}/ReverseRelationshipTypes.ts (98%) rename packages/type-traverser/src/{ => transformer}/transformerSubTraversers/TransformerInterfaceSubTraverser.ts (84%) rename packages/type-traverser/src/{ => transformer}/transformerSubTraversers/TransformerParentSubTraverser.ts (95%) rename packages/type-traverser/src/{ => transformer}/transformerSubTraversers/TransformerPrimitiveSubTraverser.ts (58%) rename packages/type-traverser/src/{ => transformer}/transformerSubTraversers/TransformerUnionSubTraverser.ts (81%) rename packages/type-traverser/src/{ => transformer}/transformerSubTraversers/util/CircularDependencyAwaiter.ts (97%) rename packages/type-traverser/src/{ => transformer}/transformerSubTraversers/util/MultiMap.ts (100%) rename packages/type-traverser/src/{ => transformer}/transformerSubTraversers/util/MultiSet.ts (100%) rename packages/type-traverser/src/{ => transformer}/transformerSubTraversers/util/SuperPromise.ts (100%) rename packages/type-traverser/src/{ => transformer}/transformerSubTraversers/util/timeout.ts (100%) rename packages/type-traverser/src/{ => transformer}/transformerSubTraversers/util/transformerSubTraverserTypes.ts (91%) rename packages/type-traverser/src/{ => visitor}/Visitor.ts (71%) create mode 100644 packages/type-traverser/src/visitor/Visitors.ts rename packages/type-traverser/src/{ => visitor}/visitorSubTraversers/VisitorInterfaceSubTraverser.ts (71%) rename packages/type-traverser/src/{ => visitor}/visitorSubTraversers/VisitorParentSubTraverser.ts (95%) rename packages/type-traverser/src/{ => visitor}/visitorSubTraversers/VisitorPrimitiveSubTraverser.ts (52%) rename packages/type-traverser/src/{ => visitor}/visitorSubTraversers/VisitorUnionSubTraverser.ts (60%) rename packages/type-traverser/src/{ => visitor}/visitorSubTraversers/util/visitorSubTraverserTypes.ts (75%) create mode 100644 packages/type-traverser/test/integration/InstanceGraph.test.ts rename packages/type-traverser/test/integration/{avatar_old => avatar}/AvatarBrokenTransformer.ts (100%) rename packages/type-traverser/test/integration/{avatar_old => avatar}/AvatarErroringTransformer.ts (100%) rename packages/type-traverser/test/integration/{avatar_old => avatar}/AvatarTraverserDefinition.ts (78%) rename packages/type-traverser/test/integration/{avatar_old => avatar}/AvatarTraverserTypes.ts (100%) rename packages/type-traverser/test/integration/{avatar_old => avatar}/sampleData.ts (100%) delete mode 100644 packages/type-traverser/test/integration/avatar_old/avatar.old.ts diff --git a/packages/type-traverser/README.md b/packages/type-traverser/README.md index d8652c9..46fe38d 100644 --- a/packages/type-traverser/README.md +++ b/packages/type-traverser/README.md @@ -159,14 +159,14 @@ There are two fields for the primitive sub-traverser: - `type`: The typescript type corresponding to this primitive. ### 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`, 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`, 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) -In our example, the TraverserDefinition looks like: +In our example, the TraverserDefinitions looks like: ```typescript -const avatarTraverserDefinition: TraverserDefinition = { +const avatarTraverserDefinitions: TraverserDefinitions = { Element: { kind: "primitive", }, @@ -193,7 +193,7 @@ const avatarTraverserDefinition: TraverserDefinition = { ``` #### 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. @@ -204,7 +204,7 @@ In our example, this is how we instantiate the traverser ```typescript const avatarTraverser = new Traverser( - avatarTraverserDefinition + avatarTraverserDefinitions ); ``` diff --git a/packages/type-traverser/src/Visitors.ts b/packages/type-traverser/src/Visitors.ts deleted file mode 100644 index 086d903..0000000 --- a/packages/type-traverser/src/Visitors.ts +++ /dev/null @@ -1,126 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import type { - InterfaceType, - PrimitiveType, - TraverserTypes, - UnionType, -} from "."; - -export type InterfaceVisitorFunction< - Types extends TraverserTypes, - Type extends InterfaceType, - Context, -> = (originalData: Type["type"], context: Context) => Promise; - -export type InterfaceVisitorPropertyFunction< - Types extends TraverserTypes, - Type extends InterfaceType, - PropertyName extends keyof Type["properties"], - Context, -> = ( - originalData: Types[Type["properties"][PropertyName]]["type"], - context: Context, -) => Promise; - -export type InterfaceVisitorDefinition< - Types extends TraverserTypes, - Type extends InterfaceType, - Context, -> = { - visitor: InterfaceVisitorFunction; - properties: { - [PropertyName in keyof Type["properties"]]: InterfaceVisitorPropertyFunction< - Types, - Type, - PropertyName, - Context - >; - }; -}; - -export type UnionVisitorFunction< - Types extends TraverserTypes, - Type extends UnionType, - Context, -> = (originalData: Type["type"], context: Context) => Promise; - -export type UnionVisitorDefinition< - Types extends TraverserTypes, - Type extends UnionType, - Context, -> = UnionVisitorFunction; - -export type PrimitiveVisitorFunction = ( - originalData: Type["type"], - context: Context, -) => Promise; - -export type PrimitiveVisitorDefinition< - Type extends PrimitiveType, - Context, -> = PrimitiveVisitorFunction; - -export type VisitorDefinition< - Types extends TraverserTypes, - TypeName extends keyof Types, - Context, -> = Types[TypeName] extends InterfaceType - ? InterfaceVisitorDefinition - : Types[TypeName] extends UnionType - ? UnionVisitorDefinition - : Types[TypeName] extends PrimitiveType - ? PrimitiveVisitorDefinition - : never; - -export type Visitors, Context> = { - [TypeName in keyof Types]: VisitorDefinition; -}; - -/** - * Input - */ -export type InterfaceVisitorInputDefinition< - Types extends TraverserTypes, - Type extends InterfaceType, - Context, -> = { - visitor: InterfaceVisitorFunction; - properties?: Partial<{ - [PropertyName in keyof Type["properties"]]: InterfaceVisitorPropertyFunction< - Types, - Type, - PropertyName, - Context - >; - }>; -}; - -export type UnionVisitorInputDefinition< - Types extends TraverserTypes, - Type extends UnionType, - Context, -> = UnionVisitorFunction; - -export type PrimitiveVisitorInputDefinition< - Type extends PrimitiveType, - Context, -> = PrimitiveVisitorFunction; - -export type VisitorInputDefinition< - Types extends TraverserTypes, - TypeName extends keyof Types, - Context, -> = Types[TypeName] extends InterfaceType - ? InterfaceVisitorInputDefinition - : Types[TypeName] extends UnionType - ? UnionVisitorInputDefinition - : Types[TypeName] extends PrimitiveType - ? PrimitiveVisitorInputDefinition - : never; - -export type VisitorsInput< - Types extends TraverserTypes, - Context, -> = Partial<{ - [TypeName in keyof Types]: VisitorInputDefinition; -}>; diff --git a/packages/type-traverser/src/index.ts b/packages/type-traverser/src/index.ts index ba02e66..7204010 100644 --- a/packages/type-traverser/src/index.ts +++ b/packages/type-traverser/src/index.ts @@ -5,5 +5,5 @@ export * from "./transformer/TransformerReturnTypes"; export * from "./transformer/TransformerReturnTypesDefaults"; export * from "./traverser/Traverser"; export * from "./transformer/Transformer"; -export * from "./Visitor"; -export * from "./Visitors"; +export * from "./visitor/Visitor"; +export * from "./visitor/Visitors"; diff --git a/packages/type-traverser/src/instanceGraph/InstanceGraph.ts b/packages/type-traverser/src/instanceGraph/InstanceGraph.ts index 2fb3922..a0068d3 100644 --- a/packages/type-traverser/src/instanceGraph/InstanceGraph.ts +++ b/packages/type-traverser/src/instanceGraph/InstanceGraph.ts @@ -1,5 +1,5 @@ /* 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 { createInstanceNodeFor, diff --git a/packages/type-traverser/src/ReverseRelationshipTypes.ts b/packages/type-traverser/src/instanceGraph/ReverseRelationshipTypes.ts similarity index 98% rename from packages/type-traverser/src/ReverseRelationshipTypes.ts rename to packages/type-traverser/src/instanceGraph/ReverseRelationshipTypes.ts index 7e16861..5e34940 100644 --- a/packages/type-traverser/src/ReverseRelationshipTypes.ts +++ b/packages/type-traverser/src/instanceGraph/ReverseRelationshipTypes.ts @@ -4,7 +4,7 @@ import type { PrimitiveType, TraverserTypes, UnionType, -} from "./traverser/TraverserTypes"; +} from "../traverser/TraverserTypes"; export type InterfaceReverseRelationshipIndentifier< Types extends TraverserTypes, diff --git a/packages/type-traverser/src/instanceGraph/nodes/InstanceNode.ts b/packages/type-traverser/src/instanceGraph/nodes/InstanceNode.ts index 85f5bf2..7656670 100644 --- a/packages/type-traverser/src/instanceGraph/nodes/InstanceNode.ts +++ b/packages/type-traverser/src/instanceGraph/nodes/InstanceNode.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import type { TraverserDefinition } from "../.."; -import type { ParentIdentifiers } from "../../reverseRelationshipTypes"; +import type { ParentIdentifiers } from "../../instanceGraph/ReverseRelationshipTypes"; import type { TraverserTypes } from "../../traverser/TraverserTypes"; import type { InstanceGraph } from "../instanceGraph"; import type { InstanceNodeFor } from "./createInstanceNodeFor"; diff --git a/packages/type-traverser/src/transformer/Transformer.ts b/packages/type-traverser/src/transformer/Transformer.ts index a0ba5a8..cd2b0aa 100644 --- a/packages/type-traverser/src/transformer/Transformer.ts +++ b/packages/type-traverser/src/transformer/Transformer.ts @@ -13,10 +13,10 @@ import type { UnionReturnType, UnionType, } from ".."; -import { transformerParentSubTraverser } from "../transformerSubTraversers/TransformerParentSubTraverser"; -import { CircularDepenedencyAwaiter } from "../transformerSubTraversers/util/CircularDependencyAwaiter"; -import { MultiMap } from "../transformerSubTraversers/util/MultiMap"; -import { SuperPromise } from "../transformerSubTraversers/util/SuperPromise"; +import { transformerParentSubTraverser } from "./transformerSubTraversers/TransformerParentSubTraverser"; +import { CircularDepenedencyAwaiter } from "./transformerSubTraversers/util/CircularDependencyAwaiter"; +import { MultiMap } from "./transformerSubTraversers/util/MultiMap"; +import { SuperPromise } from "./transformerSubTraversers/util/SuperPromise"; import type { GetTransformedChildrenFunction, InterfaceTransformerDefinition, @@ -28,6 +28,7 @@ import type { UnionTransformerDefinition, UnionTransformerInputDefinition, } from "./Transformers"; +import { InstanceGraph } from "../instanceGraph/instanceGraph"; // 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. @@ -54,12 +55,14 @@ export class Transformer< } private applyDefaultInterfaceTransformerProperties< - Type extends InterfaceType, + TypeName extends keyof Types, + Type extends InterfaceType & Types[TypeName], ReturnType extends InterfaceReturnType, >( typeName: keyof Types, typePropertiesInput: InterfaceTransformerInputDefinition< Types, + TypeName, Type, ApplyTransformerReturnTypesDefaults, ReturnType, @@ -67,6 +70,7 @@ export class Transformer< >["properties"], ): InterfaceTransformerDefinition< Types, + TypeName, Type, ApplyTransformerReturnTypesDefaults, ReturnType, @@ -89,6 +93,7 @@ export class Transformer< return agg; }, {}) as InterfaceTransformerDefinition< Types, + TypeName, Type, ApplyTransformerReturnTypesDefaults, ReturnType, @@ -97,12 +102,14 @@ export class Transformer< } private applyDefaultInterfaceTransformer< - Type extends InterfaceType, + TypeName extends keyof Types, + Type extends InterfaceType & Types[TypeName], ReturnType extends InterfaceReturnType, >( typeName: keyof Types, typeInput?: InterfaceTransformerInputDefinition< Types, + TypeName, Type, ApplyTransformerReturnTypesDefaults, ReturnType, @@ -110,6 +117,7 @@ export class Transformer< >, ): InterfaceTransformerDefinition< Types, + TypeName, Type, ApplyTransformerReturnTypesDefaults, ReturnType, @@ -139,11 +147,13 @@ export class Transformer< } private applyDefaultUnionTransformer< - Type extends UnionType, + TypeName extends keyof Types, + Type extends UnionType & Types[TypeName], ReturnType extends UnionReturnType, >( typeInput?: UnionTransformerInputDefinition< Types, + TypeName, Type, ApplyTransformerReturnTypesDefaults, ReturnType, @@ -151,6 +161,7 @@ export class Transformer< >, ): UnionTransformerDefinition< Types, + TypeName, Type, ApplyTransformerReturnTypesDefaults, ReturnType, @@ -168,11 +179,24 @@ export class Transformer< } private applyDefaultPrimitiveTransformer< - Type extends PrimitiveType, + TypeName extends keyof Types, + Type extends PrimitiveType & Types[TypeName], ReturnType extends PrimitiveReturnType, >( - typeInput?: PrimitiveTransformerInputDefinition, - ): PrimitiveTransformerDefinition { + typeInput?: PrimitiveTransformerInputDefinition< + Types, + TypeName, + Type, + ReturnType, + Context + >, + ): PrimitiveTransformerDefinition< + Types, + TypeName, + Type, + ReturnType, + Context + > { if (!typeInput) { return async (originalData) => { return originalData; @@ -229,12 +253,15 @@ export class Transformer< >[TypeName]["return"] > { const superPromise = new SuperPromise(); + const instanceGraph = new InstanceGraph(this.traverserDefinition); + instanceGraph.getNodeFor(item, itemTypeName); const toReturn = await transformerParentSubTraverser(item, itemTypeName, { traverserDefinition: this.traverserDefinition, transformers: this.transformers, executingPromises: new MultiMap(), circularDependencyAwaiter: new CircularDepenedencyAwaiter(), superPromise, + instanceGraph, context, }); await superPromise.wait(); diff --git a/packages/type-traverser/src/transformer/Transformers.ts b/packages/type-traverser/src/transformer/Transformers.ts index 2378dc9..677680f 100644 --- a/packages/type-traverser/src/transformer/Transformers.ts +++ b/packages/type-traverser/src/transformer/Transformers.ts @@ -12,6 +12,8 @@ import type { 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 GetTransformedChildrenFunction = () => Promise; @@ -22,7 +24,8 @@ export type SetReturnPointerFunction = ( export type InterfaceTransformerFunction< Types extends TraverserTypes, - Type extends InterfaceType, + TypeName extends keyof Types, + Type extends InterfaceType & Types[TypeName], ReturnType extends InterfaceReturnType, Context, > = ( @@ -31,13 +34,14 @@ export type InterfaceTransformerFunction< [PropertyName in keyof ReturnType["properties"]]: ReturnType["properties"][PropertyName]; }>, setReturnPointer: SetReturnPointerFunction, - node: InterfaceInstanceNode, + node: InterfaceInstanceNode, context: Context, ) => Promise; export type InterfaceTransformerPropertyFunction< Types extends TraverserTypes, - Type extends InterfaceType, + TypeName extends keyof Types, + Type extends InterfaceType & Types[TypeName], ReturnTypes extends TransformerReturnTypes, ReturnType extends InterfaceReturnType, PropertyName extends keyof Type["properties"], @@ -47,20 +51,29 @@ export type InterfaceTransformerPropertyFunction< getTransfromedChildren: GetTransformedChildrenFunction< ReturnTypes[Type["properties"][PropertyName]]["return"] >, + node: InterfaceInstanceNode, context: Context, ) => Promise; export type InterfaceTransformerDefinition< Types extends TraverserTypes, - Type extends InterfaceType, + TypeName extends keyof Types, + Type extends InterfaceType & Types[TypeName], ReturnTypes extends TransformerReturnTypes, ReturnType extends InterfaceReturnType, Context, > = { - transformer: InterfaceTransformerFunction; + transformer: InterfaceTransformerFunction< + Types, + TypeName, + Type, + ReturnType, + Context + >; properties: { [PropertyName in keyof Type["properties"]]: InterfaceTransformerPropertyFunction< Types, + TypeName, Type, ReturnTypes, ReturnType, @@ -72,7 +85,8 @@ export type InterfaceTransformerDefinition< export type UnionTransformerFunction< Types extends TraverserTypes, - Type extends UnionType, + TypeName extends keyof Types, + Type extends UnionType & Types[TypeName], ReturnTypes extends TransformerReturnTypes, ReturnType extends UnionReturnType, Context, @@ -82,31 +96,45 @@ export type UnionTransformerFunction< ReturnTypes[Type["typeNames"]]["return"] >, setReturnPointer: SetReturnPointerFunction, + node: UnionInstanceNode, context: Context, ) => Promise; export type UnionTransformerDefinition< Types extends TraverserTypes, - Type extends UnionType, + TypeName extends keyof Types, + Type extends UnionType & Types[TypeName], ReturnTypes extends TransformerReturnTypes, ReturnType extends UnionReturnType, Context, -> = UnionTransformerFunction; +> = UnionTransformerFunction< + Types, + TypeName, + Type, + ReturnTypes, + ReturnType, + Context +>; export type PrimitiveTransformerFunction< - Type extends PrimitiveType, + Types extends TraverserTypes, + TypeName extends keyof Types, + Type extends PrimitiveType & Types[TypeName], ReturnType extends PrimitiveReturnType, Context, > = ( originalData: Type["type"], + node: PrimitiveInstanceNode, context: Context, ) => Promise; export type PrimitiveTransformerDefinition< - Type extends PrimitiveType, + Types extends TraverserTypes, + TypeName extends keyof Types, + Type extends PrimitiveType & Types[TypeName], ReturnType extends PrimitiveReturnType, Context, -> = PrimitiveTransformerFunction; +> = PrimitiveTransformerFunction; export type TransformerDefinition< Types extends TraverserTypes, @@ -117,6 +145,7 @@ export type TransformerDefinition< ? ReturnTypes[TypeName] extends InterfaceReturnType ? InterfaceTransformerDefinition< Types, + TypeName, Types[TypeName], ReturnTypes, ReturnTypes[TypeName], @@ -127,6 +156,7 @@ export type TransformerDefinition< ? ReturnTypes[TypeName] extends UnionReturnType ? UnionTransformerDefinition< Types, + TypeName, Types[TypeName], ReturnTypes, ReturnTypes[TypeName], @@ -136,6 +166,8 @@ export type TransformerDefinition< : Types[TypeName] extends PrimitiveType ? ReturnTypes[TypeName] extends PrimitiveReturnType ? PrimitiveTransformerDefinition< + Types, + TypeName, Types[TypeName], ReturnTypes[TypeName], Context @@ -161,15 +193,23 @@ export type Transformers< */ export type InterfaceTransformerInputDefinition< Types extends TraverserTypes, - Type extends InterfaceType, + TypeName extends keyof Types, + Type extends InterfaceType & Types[TypeName], ReturnTypes extends TransformerReturnTypes, ReturnType extends InterfaceReturnType, Context, > = { - transformer: InterfaceTransformerFunction; + transformer: InterfaceTransformerFunction< + Types, + TypeName, + Type, + ReturnType, + Context + >; properties?: Partial<{ [PropertyName in keyof Type["properties"]]: InterfaceTransformerPropertyFunction< Types, + TypeName, Type, ReturnTypes, ReturnType, @@ -181,17 +221,27 @@ export type InterfaceTransformerInputDefinition< export type UnionTransformerInputDefinition< Types extends TraverserTypes, - Type extends UnionType, + TypeName extends keyof Types, + Type extends UnionType & Types[TypeName], ReturnTypes extends TransformerReturnTypes, ReturnType extends UnionReturnType, Context, -> = UnionTransformerFunction; +> = UnionTransformerFunction< + Types, + TypeName, + Type, + ReturnTypes, + ReturnType, + Context +>; export type PrimitiveTransformerInputDefinition< - Type extends PrimitiveType, + Types extends TraverserTypes, + TypeName extends keyof Types, + Type extends PrimitiveType & Types[TypeName], ReturnType extends PrimitiveReturnType, Context, -> = PrimitiveTransformerFunction; +> = PrimitiveTransformerFunction; export type TransformerInputDefinition< Types extends TraverserTypes, @@ -202,6 +252,7 @@ export type TransformerInputDefinition< ? ReturnTypes[TypeName] extends InterfaceReturnType ? InterfaceTransformerInputDefinition< Types, + TypeName, Types[TypeName], ReturnTypes, ReturnTypes[TypeName], @@ -212,6 +263,7 @@ export type TransformerInputDefinition< ? ReturnTypes[TypeName] extends UnionReturnType ? UnionTransformerInputDefinition< Types, + TypeName, Types[TypeName], ReturnTypes, ReturnTypes[TypeName], @@ -221,6 +273,8 @@ export type TransformerInputDefinition< : Types[TypeName] extends PrimitiveType ? ReturnTypes[TypeName] extends PrimitiveReturnType ? PrimitiveTransformerInputDefinition< + Types, + TypeName, Types[TypeName], ReturnTypes[TypeName], Context diff --git a/packages/type-traverser/src/transformerSubTraversers/TransformerInterfaceSubTraverser.ts b/packages/type-traverser/src/transformer/transformerSubTraversers/TransformerInterfaceSubTraverser.ts similarity index 84% rename from packages/type-traverser/src/transformerSubTraversers/TransformerInterfaceSubTraverser.ts rename to packages/type-traverser/src/transformer/transformerSubTraversers/TransformerInterfaceSubTraverser.ts index a0ce693..eb2eb21 100644 --- a/packages/type-traverser/src/transformerSubTraversers/TransformerInterfaceSubTraverser.ts +++ b/packages/type-traverser/src/transformer/transformerSubTraversers/TransformerInterfaceSubTraverser.ts @@ -1,20 +1,21 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { TraverserTypes } from ".."; +import type { TraverserTypes } from "../../"; import type { InterfaceReturnType, TransformerReturnTypes, } from "../TransformerReturnTypes"; import type { InterfaceTransformerDefinition } from "../Transformers"; -import type { InterfaceTraverserDefinition } from "../traverser/TraverserDefinition"; -import type { InterfaceType } from "../traverser/TraverserTypes"; +import type { InterfaceTraverserDefinition } from "../../traverser/TraverserDefinition"; +import type { InterfaceType } from "../../traverser/TraverserTypes"; import { transformerParentSubTraverser } from "./TransformerParentSubTraverser"; import type { TransformerSubTraverserGlobals } from "./util/transformerSubTraverserTypes"; +import type { InterfaceInstanceNode } from "../../instanceGraph/nodes/InterfaceInstanceNode"; export async function transformerInterfaceSubTraverser< Types extends TraverserTypes, TypeName extends keyof Types, ReturnTypes extends TransformerReturnTypes, - Type extends InterfaceType, + Type extends InterfaceType & Types[TypeName], ReturnType extends InterfaceReturnType, Context, >( @@ -40,6 +41,7 @@ export async function transformerInterfaceSubTraverser< itemTypeName ] as unknown as InterfaceTransformerDefinition< Types, + TypeName, Type, ReturnTypes, ReturnType, @@ -99,6 +101,14 @@ export async function transformerInterfaceSubTraverser< return toReturn; } }, + globals.instanceGraph.getNodeFor( + item, + itemTypeName, + ) as unknown as InterfaceInstanceNode< + Types, + TypeName, + Type + >, globals.context, ); return [propertyName, transformedProperty]; @@ -111,6 +121,10 @@ export async function transformerInterfaceSubTraverser< (input) => { resolve(input); }, + globals.instanceGraph.getNodeFor( + item, + itemTypeName, + ) as unknown as InterfaceInstanceNode, globals.context, ); resolve(transformedObject); diff --git a/packages/type-traverser/src/transformerSubTraversers/TransformerParentSubTraverser.ts b/packages/type-traverser/src/transformer/transformerSubTraversers/TransformerParentSubTraverser.ts similarity index 95% rename from packages/type-traverser/src/transformerSubTraversers/TransformerParentSubTraverser.ts rename to packages/type-traverser/src/transformer/transformerSubTraversers/TransformerParentSubTraverser.ts index 6267e71..8a251d2 100644 --- a/packages/type-traverser/src/transformerSubTraversers/TransformerParentSubTraverser.ts +++ b/packages/type-traverser/src/transformer/transformerSubTraversers/TransformerParentSubTraverser.ts @@ -1,5 +1,9 @@ /* 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 { transformerInterfaceSubTraverser } from "./TransformerInterfaceSubTraverser"; import { transformerPrimitiveSubTraverser } from "./TransformerPrimitiveSubTraverser"; diff --git a/packages/type-traverser/src/transformerSubTraversers/TransformerPrimitiveSubTraverser.ts b/packages/type-traverser/src/transformer/transformerSubTraversers/TransformerPrimitiveSubTraverser.ts similarity index 58% rename from packages/type-traverser/src/transformerSubTraversers/TransformerPrimitiveSubTraverser.ts rename to packages/type-traverser/src/transformer/transformerSubTraversers/TransformerPrimitiveSubTraverser.ts index adcf17a..672e084 100644 --- a/packages/type-traverser/src/transformerSubTraversers/TransformerPrimitiveSubTraverser.ts +++ b/packages/type-traverser/src/transformer/transformerSubTraversers/TransformerPrimitiveSubTraverser.ts @@ -1,18 +1,19 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { TraverserTypes } from ".."; +import type { TraverserTypes } from "../../"; +import type { PrimitiveInstanceNode } from "../../instanceGraph/nodes/PrimitiveInstanceNode"; import type { PrimitiveReturnType, TransformerReturnTypes, } from "../TransformerReturnTypes"; import type { PrimitiveTransformerDefinition } from "../Transformers"; -import type { PrimitiveType } from "../traverser/TraverserTypes"; +import type { PrimitiveType } from "../../traverser/TraverserTypes"; import type { TransformerSubTraverserGlobals } from "./util/transformerSubTraverserTypes"; export async function transformerPrimitiveSubTraverser< Types extends TraverserTypes, TypeName extends keyof Types, ReturnTypes extends TransformerReturnTypes, - Type extends PrimitiveType, + Type extends PrimitiveType & Types[TypeName], ReturnType extends PrimitiveReturnType, Context, >( @@ -23,6 +24,19 @@ export async function transformerPrimitiveSubTraverser< const { transformers } = globals; const transformer = transformers[ itemTypeName - ] as unknown as PrimitiveTransformerDefinition; - return transformer(item, globals.context); + ] as unknown as PrimitiveTransformerDefinition< + Types, + TypeName, + Type, + ReturnType, + Context + >; + return transformer( + item, + globals.instanceGraph.getNodeFor( + item, + itemTypeName, + ) as unknown as PrimitiveInstanceNode, + globals.context, + ); } diff --git a/packages/type-traverser/src/transformerSubTraversers/TransformerUnionSubTraverser.ts b/packages/type-traverser/src/transformer/transformerSubTraversers/TransformerUnionSubTraverser.ts similarity index 81% rename from packages/type-traverser/src/transformerSubTraversers/TransformerUnionSubTraverser.ts rename to packages/type-traverser/src/transformer/transformerSubTraversers/TransformerUnionSubTraverser.ts index 39a342c..e74d0c5 100644 --- a/packages/type-traverser/src/transformerSubTraversers/TransformerUnionSubTraverser.ts +++ b/packages/type-traverser/src/transformer/transformerSubTraversers/TransformerUnionSubTraverser.ts @@ -1,12 +1,13 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { TraverserTypes } from ".."; +import type { TraverserTypes } from "../../"; +import type { UnionInstanceNode } from "../../instanceGraph/nodes/UnionInstanceNode"; import type { TransformerReturnTypes, UnionReturnType, } from "../TransformerReturnTypes"; import type { UnionTransformerDefinition } from "../Transformers"; -import type { UnionTraverserDefinition } from "../traverser/TraverserDefinition"; -import type { UnionType } from "../traverser/TraverserTypes"; +import type { UnionTraverserDefinition } from "../../traverser/TraverserDefinition"; +import type { UnionType } from "../../traverser/TraverserTypes"; import { transformerParentSubTraverser } from "./TransformerParentSubTraverser"; import type { TransformerSubTraverserGlobals } from "./util/transformerSubTraverserTypes"; @@ -14,7 +15,7 @@ export async function transformerUnionSubTraverser< Types extends TraverserTypes, TypeName extends keyof Types, ReturnTypes extends TransformerReturnTypes, - Type extends UnionType, + Type extends UnionType & Types[TypeName], ReturnType extends UnionReturnType, Context, >( @@ -39,6 +40,7 @@ export async function transformerUnionSubTraverser< itemTypeName ] as unknown as UnionTransformerDefinition< Types, + TypeName, Type, ReturnTypes, ReturnType, @@ -66,6 +68,10 @@ export async function transformerUnionSubTraverser< (input) => { resolve(input); }, + globals.instanceGraph.getNodeFor( + item, + itemTypeName, + ) as unknown as UnionInstanceNode, globals.context, ); resolve(transformedObject); diff --git a/packages/type-traverser/src/transformerSubTraversers/util/CircularDependencyAwaiter.ts b/packages/type-traverser/src/transformer/transformerSubTraversers/util/CircularDependencyAwaiter.ts similarity index 97% rename from packages/type-traverser/src/transformerSubTraversers/util/CircularDependencyAwaiter.ts rename to packages/type-traverser/src/transformer/transformerSubTraversers/util/CircularDependencyAwaiter.ts index 6a0c5e5..e63b323 100644 --- a/packages/type-traverser/src/transformerSubTraversers/util/CircularDependencyAwaiter.ts +++ b/packages/type-traverser/src/transformer/transformerSubTraversers/util/CircularDependencyAwaiter.ts @@ -1,4 +1,4 @@ -import type { KeyTypes } from "../.."; +import type { KeyTypes } from "../../../"; import { MultiMap } from "./MultiMap"; import { MultiSet } from "./MultiSet"; import type { TransformerSubTraverserExecutingPromises } from "./transformerSubTraverserTypes"; diff --git a/packages/type-traverser/src/transformerSubTraversers/util/MultiMap.ts b/packages/type-traverser/src/transformer/transformerSubTraversers/util/MultiMap.ts similarity index 100% rename from packages/type-traverser/src/transformerSubTraversers/util/MultiMap.ts rename to packages/type-traverser/src/transformer/transformerSubTraversers/util/MultiMap.ts diff --git a/packages/type-traverser/src/transformerSubTraversers/util/MultiSet.ts b/packages/type-traverser/src/transformer/transformerSubTraversers/util/MultiSet.ts similarity index 100% rename from packages/type-traverser/src/transformerSubTraversers/util/MultiSet.ts rename to packages/type-traverser/src/transformer/transformerSubTraversers/util/MultiSet.ts diff --git a/packages/type-traverser/src/transformerSubTraversers/util/SuperPromise.ts b/packages/type-traverser/src/transformer/transformerSubTraversers/util/SuperPromise.ts similarity index 100% rename from packages/type-traverser/src/transformerSubTraversers/util/SuperPromise.ts rename to packages/type-traverser/src/transformer/transformerSubTraversers/util/SuperPromise.ts diff --git a/packages/type-traverser/src/transformerSubTraversers/util/timeout.ts b/packages/type-traverser/src/transformer/transformerSubTraversers/util/timeout.ts similarity index 100% rename from packages/type-traverser/src/transformerSubTraversers/util/timeout.ts rename to packages/type-traverser/src/transformer/transformerSubTraversers/util/timeout.ts diff --git a/packages/type-traverser/src/transformerSubTraversers/util/transformerSubTraverserTypes.ts b/packages/type-traverser/src/transformer/transformerSubTraversers/util/transformerSubTraverserTypes.ts similarity index 91% rename from packages/type-traverser/src/transformerSubTraversers/util/transformerSubTraverserTypes.ts rename to packages/type-traverser/src/transformer/transformerSubTraversers/util/transformerSubTraverserTypes.ts index cd5c9a7..2126158 100644 --- a/packages/type-traverser/src/transformerSubTraversers/util/transformerSubTraverserTypes.ts +++ b/packages/type-traverser/src/transformer/transformerSubTraversers/util/transformerSubTraverserTypes.ts @@ -6,7 +6,8 @@ import type { TransformerReturnTypes, TraverserDefinitions, TraverserTypes, -} from "../.."; +} from "../../../"; +import type { InstanceGraph } from "../../../instanceGraph/instanceGraph"; import type { Transformers } from "../../Transformers"; import type { CircularDepenedencyAwaiter } from "./CircularDependencyAwaiter"; import type { MultiMap } from "./MultiMap"; @@ -35,6 +36,7 @@ export interface TransformerSubTraverserGlobals< executingPromises: TransformerSubTraverserExecutingPromises; circularDependencyAwaiter: CircularDepenedencyAwaiter; superPromise: SuperPromise; + instanceGraph: InstanceGraph; context: Context; } diff --git a/packages/type-traverser/src/Visitor.ts b/packages/type-traverser/src/visitor/Visitor.ts similarity index 71% rename from packages/type-traverser/src/Visitor.ts rename to packages/type-traverser/src/visitor/Visitor.ts index 781e38b..1676157 100644 --- a/packages/type-traverser/src/Visitor.ts +++ b/packages/type-traverser/src/visitor/Visitor.ts @@ -15,8 +15,9 @@ import type { UnionVisitorInputDefinition, Visitors, VisitorsInput, -} from "."; -import { MultiSet } from "./transformerSubTraversers/util/MultiSet"; +} from "../"; +import { InstanceGraph } from "../instanceGraph/instanceGraph"; +import { MultiSet } from "../transformer/transformerSubTraversers/util/MultiSet"; import { visitorParentSubTraverser } from "./visitorSubTraversers/VisitorParentSubTraverser"; // TODO: Lots of "any" in this file. I'm just done with fancy typescript, @@ -39,15 +40,17 @@ export class Visitor< } private applyDefaultInterfaceVisitorProperties< - Type extends InterfaceType, + TypeName extends keyof Types, + Type extends InterfaceType & Types[TypeName], >( typeName: keyof Types, typePropertiesInput: InterfaceVisitorInputDefinition< Types, + TypeName, Type, Context >["properties"], - ): InterfaceVisitorDefinition["properties"] { + ): InterfaceVisitorDefinition["properties"] { return Object.keys( (this.traverserDefinition[typeName] as InterfaceTraverserDefinition) .properties, @@ -60,13 +63,21 @@ export class Visitor< }; } return agg; - }, {}) as InterfaceVisitorDefinition["properties"]; + }, {}) as InterfaceVisitorDefinition< + Types, + TypeName, + Type, + Context + >["properties"]; } - private applyDefaultInterfaceVisitor>( + private applyDefaultInterfaceVisitor< + TypeName extends keyof Types, + Type extends InterfaceType & Types[TypeName], + >( typeName: keyof Types, - typeInput?: InterfaceVisitorInputDefinition, - ): InterfaceVisitorDefinition { + typeInput?: InterfaceVisitorInputDefinition, + ): InterfaceVisitorDefinition { if (!typeInput) { return { visitor: async () => { @@ -84,9 +95,12 @@ export class Visitor< }; } - private applyDefaultUnionVisitor>( - typeInput?: UnionVisitorInputDefinition, - ): UnionVisitorDefinition { + private applyDefaultUnionVisitor< + TypeName extends keyof Types, + Type extends UnionType & Types[TypeName], + >( + typeInput?: UnionVisitorInputDefinition, + ): UnionVisitorDefinition { if (!typeInput) { return async () => { return; @@ -95,9 +109,12 @@ export class Visitor< return typeInput; } - private applyDefaultPrimitiveVisitor( - typeInput?: PrimitiveVisitorInputDefinition, - ): PrimitiveVisitorDefinition { + private applyDefaultPrimitiveVisitor< + TypeName extends keyof Types, + Type extends PrimitiveType & Types[TypeName], + >( + typeInput?: PrimitiveVisitorInputDefinition, + ): PrimitiveVisitorDefinition { if (!typeInput) { return async () => { return; @@ -134,10 +151,13 @@ export class Visitor< itemTypeName: TypeName, context: Context, ): Promise { + const instanceGraph = new InstanceGraph(this.traverserDefinition); + instanceGraph.getNodeFor(item, itemTypeName); const toReturn = await visitorParentSubTraverser(item, itemTypeName, { traverserDefinition: this.traverserDefinition, visitors: this.visitors, visitedObjects: new MultiSet(), + instanceGraph, context, }); return toReturn; diff --git a/packages/type-traverser/src/visitor/Visitors.ts b/packages/type-traverser/src/visitor/Visitors.ts new file mode 100644 index 0000000..751676e --- /dev/null +++ b/packages/type-traverser/src/visitor/Visitors.ts @@ -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, + TypeName extends keyof Types, + Type extends InterfaceType & Types[TypeName], + Context, +> = ( + originalData: Type["type"], + node: InterfaceInstanceNode, + context: Context, +) => Promise; + +export type InterfaceVisitorPropertyFunction< + Types extends TraverserTypes, + TypeName extends keyof Types, + Type extends InterfaceType & Types[TypeName], + PropertyName extends keyof Type["properties"], + Context, +> = ( + originalData: Types[Type["properties"][PropertyName]]["type"], + node: InterfaceInstanceNode, + context: Context, +) => Promise; + +export type InterfaceVisitorDefinition< + Types extends TraverserTypes, + TypeName extends keyof Types, + Type extends InterfaceType & Types[TypeName], + Context, +> = { + visitor: InterfaceVisitorFunction; + properties: { + [PropertyName in keyof Type["properties"]]: InterfaceVisitorPropertyFunction< + Types, + TypeName, + Type, + PropertyName, + Context + >; + }; +}; + +export type UnionVisitorFunction< + Types extends TraverserTypes, + TypeName extends keyof Types, + Type extends UnionType & Types[TypeName], + Context, +> = ( + originalData: Type["type"], + node: UnionInstanceNode, + context: Context, +) => Promise; + +export type UnionVisitorDefinition< + Types extends TraverserTypes, + TypeName extends keyof Types, + Type extends UnionType & Types[TypeName], + Context, +> = UnionVisitorFunction; + +export type PrimitiveVisitorFunction< + Types extends TraverserTypes, + TypeName extends keyof Types, + Type extends PrimitiveType & Types[TypeName], + Context, +> = ( + originalData: Type["type"], + node: PrimitiveInstanceNode, + context: Context, +) => Promise; + +export type PrimitiveVisitorDefinition< + Types extends TraverserTypes, + TypeName extends keyof Types, + Type extends PrimitiveType & Types[TypeName], + Context, +> = PrimitiveVisitorFunction; + +export type VisitorDefinition< + Types extends TraverserTypes, + TypeName extends keyof Types, + Context, +> = Types[TypeName] extends InterfaceType + ? InterfaceVisitorDefinition + : Types[TypeName] extends UnionType + ? UnionVisitorDefinition + : Types[TypeName] extends PrimitiveType + ? PrimitiveVisitorDefinition + : never; + +export type Visitors, Context> = { + [TypeName in keyof Types]: VisitorDefinition; +}; + +/** + * Input + */ +export type InterfaceVisitorInputDefinition< + Types extends TraverserTypes, + TypeName extends keyof Types, + Type extends InterfaceType & Types[TypeName], + Context, +> = { + visitor: InterfaceVisitorFunction; + properties?: Partial<{ + [PropertyName in keyof Type["properties"]]: InterfaceVisitorPropertyFunction< + Types, + TypeName, + Type, + PropertyName, + Context + >; + }>; +}; + +export type UnionVisitorInputDefinition< + Types extends TraverserTypes, + TypeName extends keyof Types, + Type extends UnionType & Types[TypeName], + Context, +> = UnionVisitorFunction; + +export type PrimitiveVisitorInputDefinition< + Types extends TraverserTypes, + TypeName extends keyof Types, + Type extends PrimitiveType & Types[TypeName], + Context, +> = PrimitiveVisitorFunction; + +export type VisitorInputDefinition< + Types extends TraverserTypes, + TypeName extends keyof Types, + Context, +> = Types[TypeName] extends InterfaceType + ? InterfaceVisitorInputDefinition + : Types[TypeName] extends UnionType + ? UnionVisitorInputDefinition + : Types[TypeName] extends PrimitiveType + ? PrimitiveVisitorInputDefinition + : never; + +export type VisitorsInput< + Types extends TraverserTypes, + Context, +> = Partial<{ + [TypeName in keyof Types]: VisitorInputDefinition; +}>; diff --git a/packages/type-traverser/src/visitorSubTraversers/VisitorInterfaceSubTraverser.ts b/packages/type-traverser/src/visitor/visitorSubTraversers/VisitorInterfaceSubTraverser.ts similarity index 71% rename from packages/type-traverser/src/visitorSubTraversers/VisitorInterfaceSubTraverser.ts rename to packages/type-traverser/src/visitor/visitorSubTraversers/VisitorInterfaceSubTraverser.ts index f93e01b..7f6ae16 100644 --- a/packages/type-traverser/src/visitorSubTraversers/VisitorInterfaceSubTraverser.ts +++ b/packages/type-traverser/src/visitor/visitorSubTraversers/VisitorInterfaceSubTraverser.ts @@ -1,14 +1,15 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { InterfaceVisitorDefinition, TraverserTypes } from ".."; -import type { InterfaceTraverserDefinition } from "../traverser/TraverserDefinition"; -import type { InterfaceType } from "../traverser/TraverserTypes"; +import type { InterfaceVisitorDefinition, TraverserTypes } from "../../"; +import type { InterfaceInstanceNode } from "../../instanceGraph/nodes/InterfaceInstanceNode"; +import type { InterfaceTraverserDefinition } from "../../traverser/TraverserDefinition"; +import type { InterfaceType } from "../../traverser/TraverserTypes"; import type { VisitorSubTraverserGlobals } from "./util/visitorSubTraverserTypes"; import { visitorParentSubTraverser } from "./VisitorParentSubTraverser"; export async function visitorInterfaceSubTraverser< Types extends TraverserTypes, TypeName extends keyof Types, - Type extends InterfaceType, + Type extends InterfaceType & Types[TypeName], Context, >( item: Type["type"], @@ -22,16 +23,27 @@ export async function visitorInterfaceSubTraverser< ] as InterfaceTraverserDefinition; const visitor = visitors[ itemTypeName - ] as unknown as InterfaceVisitorDefinition; + ] as unknown as InterfaceVisitorDefinition; await Promise.all([ - visitor.visitor(item, globals.context), + visitor.visitor( + item, + globals.instanceGraph.getNodeFor( + item, + itemTypeName, + ) as unknown as InterfaceInstanceNode, + globals.context, + ), Promise.all( Object.entries(definition.properties).map(async ([propertyName]) => { const originalObject = item[propertyName]; const originalPropertyDefinition = definition.properties[propertyName]; const propertyVisitorPromise = visitor.properties[propertyName]( originalObject, + globals.instanceGraph.getNodeFor( + item, + itemTypeName, + ) as unknown as InterfaceInstanceNode, globals.context, ); let propertyTraverserPromise: Promise; diff --git a/packages/type-traverser/src/visitorSubTraversers/VisitorParentSubTraverser.ts b/packages/type-traverser/src/visitor/visitorSubTraversers/VisitorParentSubTraverser.ts similarity index 95% rename from packages/type-traverser/src/visitorSubTraversers/VisitorParentSubTraverser.ts rename to packages/type-traverser/src/visitor/visitorSubTraversers/VisitorParentSubTraverser.ts index 56553eb..ada6f88 100644 --- a/packages/type-traverser/src/visitorSubTraversers/VisitorParentSubTraverser.ts +++ b/packages/type-traverser/src/visitor/visitorSubTraversers/VisitorParentSubTraverser.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { BaseTraverserTypes, TraverserTypes } from ".."; +import type { BaseTraverserTypes, TraverserTypes } from "../../"; import type { VisitorSubTraverser, VisitorSubTraverserGlobals, diff --git a/packages/type-traverser/src/visitorSubTraversers/VisitorPrimitiveSubTraverser.ts b/packages/type-traverser/src/visitor/visitorSubTraversers/VisitorPrimitiveSubTraverser.ts similarity index 52% rename from packages/type-traverser/src/visitorSubTraversers/VisitorPrimitiveSubTraverser.ts rename to packages/type-traverser/src/visitor/visitorSubTraversers/VisitorPrimitiveSubTraverser.ts index 35593b1..7ee49b0 100644 --- a/packages/type-traverser/src/visitorSubTraversers/VisitorPrimitiveSubTraverser.ts +++ b/packages/type-traverser/src/visitor/visitorSubTraversers/VisitorPrimitiveSubTraverser.ts @@ -1,12 +1,13 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { PrimitiveVisitorDefinition, TraverserTypes } from ".."; -import type { PrimitiveType } from "../traverser/TraverserTypes"; +import type { PrimitiveVisitorDefinition, TraverserTypes } from "../../"; +import type { PrimitiveInstanceNode } from "../../instanceGraph/nodes/PrimitiveInstanceNode"; +import type { PrimitiveType } from "../../traverser/TraverserTypes"; import type { VisitorSubTraverserGlobals } from "./util/visitorSubTraverserTypes"; export async function visitorPrimitiveSubTraverser< Types extends TraverserTypes, TypeName extends keyof Types, - Type extends PrimitiveType, + Type extends PrimitiveType & Types[TypeName], Context, >( item: Type["type"], @@ -16,6 +17,13 @@ export async function visitorPrimitiveSubTraverser< const { visitors } = globals; const visitor = visitors[ itemTypeName - ] as unknown as PrimitiveVisitorDefinition; - return visitor(item, globals.context); + ] as unknown as PrimitiveVisitorDefinition; + return visitor( + item, + globals.instanceGraph.getNodeFor( + item, + itemTypeName, + ) as unknown as PrimitiveInstanceNode, + globals.context, + ); } diff --git a/packages/type-traverser/src/visitorSubTraversers/VisitorUnionSubTraverser.ts b/packages/type-traverser/src/visitor/visitorSubTraversers/VisitorUnionSubTraverser.ts similarity index 60% rename from packages/type-traverser/src/visitorSubTraversers/VisitorUnionSubTraverser.ts rename to packages/type-traverser/src/visitor/visitorSubTraversers/VisitorUnionSubTraverser.ts index 8a75bcf..45ae27a 100644 --- a/packages/type-traverser/src/visitorSubTraversers/VisitorUnionSubTraverser.ts +++ b/packages/type-traverser/src/visitor/visitorSubTraversers/VisitorUnionSubTraverser.ts @@ -1,14 +1,15 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { TraverserTypes, UnionVisitorDefinition } from ".."; -import type { UnionTraverserDefinition } from "../traverser/TraverserDefinition"; -import type { UnionType } from "../traverser/TraverserTypes"; +import type { TraverserTypes, UnionVisitorDefinition } from "../../"; +import type { UnionInstanceNode } from "../../instanceGraph/nodes/UnionInstanceNode"; +import type { UnionTraverserDefinition } from "../../traverser/TraverserDefinition"; +import type { UnionType } from "../../traverser/TraverserTypes"; import type { VisitorSubTraverserGlobals } from "./util/visitorSubTraverserTypes"; import { visitorParentSubTraverser } from "./VisitorParentSubTraverser"; export async function visitorUnionSubTraverser< Types extends TraverserTypes, TypeName extends keyof Types, - Type extends UnionType, + Type extends UnionType & Types[TypeName], Context, >( item: Type["type"], @@ -21,12 +22,20 @@ export async function visitorUnionSubTraverser< ] as UnionTraverserDefinition; const visitor = visitors[itemTypeName] as unknown as UnionVisitorDefinition< Types, + TypeName, Type, Context >; const itemSpecificTypeName = definition.selector(item); await Promise.all([ - visitor(item, globals.context), + visitor( + item, + globals.instanceGraph.getNodeFor( + item, + itemTypeName, + ) as unknown as UnionInstanceNode, + globals.context, + ), visitorParentSubTraverser(item, itemSpecificTypeName, globals), ]); } diff --git a/packages/type-traverser/src/visitorSubTraversers/util/visitorSubTraverserTypes.ts b/packages/type-traverser/src/visitor/visitorSubTraversers/util/visitorSubTraverserTypes.ts similarity index 75% rename from packages/type-traverser/src/visitorSubTraversers/util/visitorSubTraverserTypes.ts rename to packages/type-traverser/src/visitor/visitorSubTraversers/util/visitorSubTraverserTypes.ts index 82ccfc3..e3841f2 100644 --- a/packages/type-traverser/src/visitorSubTraversers/util/visitorSubTraverserTypes.ts +++ b/packages/type-traverser/src/visitor/visitorSubTraversers/util/visitorSubTraverserTypes.ts @@ -4,8 +4,9 @@ import type { TraverserDefinitions, TraverserTypes, Visitors, -} from "../.."; -import type { MultiSet } from "../../transformerSubTraversers/util/MultiSet"; +} from "../../../"; +import type { InstanceGraph } from "../../../instanceGraph/instanceGraph"; +import type { MultiSet } from "../../../transformer/transformerSubTraversers/util/MultiSet"; export type VisitorSubTraverser< Types extends TraverserTypes, @@ -25,5 +26,6 @@ export interface VisitorSubTraverserGlobals< traverserDefinition: TraverserDefinitions; visitors: Visitors; visitedObjects: MultiSet; + instanceGraph: InstanceGraph; context: Context; } diff --git a/packages/type-traverser/test/integration/InstanceGraph.test.ts b/packages/type-traverser/test/integration/InstanceGraph.test.ts new file mode 100644 index 0000000..6645a7e --- /dev/null +++ b/packages/type-traverser/test/integration/InstanceGraph.test.ts @@ -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 = + { + 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", () => {}); + }); +}); diff --git a/packages/type-traverser/test/integration/avatar_old/AvatarBrokenTransformer.ts b/packages/type-traverser/test/integration/avatar/AvatarBrokenTransformer.ts similarity index 100% rename from packages/type-traverser/test/integration/avatar_old/AvatarBrokenTransformer.ts rename to packages/type-traverser/test/integration/avatar/AvatarBrokenTransformer.ts diff --git a/packages/type-traverser/test/integration/avatar_old/AvatarErroringTransformer.ts b/packages/type-traverser/test/integration/avatar/AvatarErroringTransformer.ts similarity index 100% rename from packages/type-traverser/test/integration/avatar_old/AvatarErroringTransformer.ts rename to packages/type-traverser/test/integration/avatar/AvatarErroringTransformer.ts diff --git a/packages/type-traverser/test/integration/avatar_old/AvatarTraverserDefinition.ts b/packages/type-traverser/test/integration/avatar/AvatarTraverserDefinition.ts similarity index 78% rename from packages/type-traverser/test/integration/avatar_old/AvatarTraverserDefinition.ts rename to packages/type-traverser/test/integration/avatar/AvatarTraverserDefinition.ts index 2984080..cda24ba 100644 --- a/packages/type-traverser/test/integration/avatar_old/AvatarTraverserDefinition.ts +++ b/packages/type-traverser/test/integration/avatar/AvatarTraverserDefinition.ts @@ -1,7 +1,7 @@ -import type { TraverserDefinition } from "../../../src"; +import type { TraverserDefinitions } from "../../../src"; import type { AvatarTraverserTypes, Bender } from "./AvatarTraverserTypes"; -export const avatarTraverserDefinition: TraverserDefinition = +export const avatarTraverserDefinition: TraverserDefinitions = { Element: { kind: "primitive", diff --git a/packages/type-traverser/test/integration/avatar_old/AvatarTraverserTypes.ts b/packages/type-traverser/test/integration/avatar/AvatarTraverserTypes.ts similarity index 100% rename from packages/type-traverser/test/integration/avatar_old/AvatarTraverserTypes.ts rename to packages/type-traverser/test/integration/avatar/AvatarTraverserTypes.ts diff --git a/packages/type-traverser/test/integration/avatar/avatar.test.ts b/packages/type-traverser/test/integration/avatar/avatar.test.ts index 6d3d16f..6748fc6 100644 --- a/packages/type-traverser/test/integration/avatar/avatar.test.ts +++ b/packages/type-traverser/test/integration/avatar/avatar.test.ts @@ -1,161 +1,19 @@ -import type { - TraverserDefinitions, - ValidateTraverserTypes, -} from "../../../src"; -import { InstanceGraph } from "../../../src/instanceGraph/instanceGraph"; +import { BrokenAvatarTransformer } from "./AvatarBrokenTransformer"; +import { AvatarErroringTransformer } from "./AvatarErroringTransformer"; +import { aang } from "./sampleData"; -describe("AvatarExample", () => { - /** - * 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 = - { - 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("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`, + ); }); - describe("Transformer", () => { - it("transforms", () => { - - }) + it("Bubbles errors", async () => { + await expect( + AvatarErroringTransformer.transform(aang, "Bender", undefined), + ).rejects.toThrow("No Non Benders Allowed"); }); }); diff --git a/packages/type-traverser/test/integration/avatar_old/sampleData.ts b/packages/type-traverser/test/integration/avatar/sampleData.ts similarity index 100% rename from packages/type-traverser/test/integration/avatar_old/sampleData.ts rename to packages/type-traverser/test/integration/avatar/sampleData.ts diff --git a/packages/type-traverser/test/integration/avatar_old/avatar.old.ts b/packages/type-traverser/test/integration/avatar_old/avatar.old.ts deleted file mode 100644 index 6748fc6..0000000 --- a/packages/type-traverser/test/integration/avatar_old/avatar.old.ts +++ /dev/null @@ -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"); - }); -});