Graph creation works

main
Jackson Morgan 9 months ago
parent 637a517b4b
commit 665511f2f0
  1. 408
      packages/type-traverser/example/example.ts
  2. 7
      packages/type-traverser/src/ReverseRelationshipTypes.ts
  3. 25
      packages/type-traverser/src/TraverserDefinition.ts
  4. 20
      packages/type-traverser/src/instanceGraph/InstanceGraph.ts
  5. 17
      packages/type-traverser/src/instanceGraph/nodes/InstanceNode.ts
  6. 28
      packages/type-traverser/src/instanceGraph/nodes/InterfaceInstanceNode.ts
  7. 2
      packages/type-traverser/src/instanceGraph/nodes/PrimitiveInstanceNode.ts
  8. 13
      packages/type-traverser/src/instanceGraph/nodes/UnionInstanceNode.ts
  9. 161
      packages/type-traverser/test/integration/avatar/avatar.test.ts
  10. 0
      packages/type-traverser/test/integration/avatar_old/AvatarBrokenTransformer.ts
  11. 0
      packages/type-traverser/test/integration/avatar_old/AvatarErroringTransformer.ts
  12. 0
      packages/type-traverser/test/integration/avatar_old/AvatarTraverserDefinition.ts
  13. 0
      packages/type-traverser/test/integration/avatar_old/AvatarTraverserTypes.ts
  14. 19
      packages/type-traverser/test/integration/avatar_old/avatar.old.ts
  15. 0
      packages/type-traverser/test/integration/avatar_old/sampleData.ts
  16. 2
      packages/type-traverser/tsconfig.build.json
  17. 1
      tsconfig.base.json

@ -1,13 +1,10 @@
import type {
TraverserDefinition,
ValidateTraverserTypes,
AssertExtends,
InterfaceType,
PrimitiveType,
UnionType,
ItemNamed,
TraverserDefinitions,
} from "../src";
import { Traverser } from "../src";
import type { ReverseRelationshipIndentifiers } from "../src/reverseRelationshipTypes";
import { InstanceGraph } from "../src/instanceGraph/instanceGraph";
import type { ParentIdentifiers } from "../src/ReverseRelationshipTypes";
async function run() {
/**
@ -64,7 +61,7 @@ async function run() {
};
NonBender: {
kind: "interface";
type: Bender;
type: NonBender;
properties: {
friends: "Person";
};
@ -76,236 +73,205 @@ async function run() {
};
}>;
type AvatarReverseRelationshipIdentifiers =
ReverseRelationshipIndentifiers<AvatarTraverserTypes>;
const sample: AvatarReverseRelationshipIdentifiers = {
Element: ["Bender", "element"],
Bender: ["Person"],
}
type KeysMatchingCondition<T, Condition> = {
[K in keyof T]: T[K] extends Condition ? K : never;
}[keyof T];
// Condition: objects with `{ kind: "interface" }`
type InterfaceKeys = KeysMatchingCondition<
type PersonParentIdentifiers = ParentIdentifiers<
AvatarTraverserTypes,
{ kind: "interface" }
"Person"
>;
type something = AvatarTraverserTypes[keyof AvatarTraverserTypes];
type something2 = something extends PrimitiveType ? "cool" : never;
type SomeInterface = {
a: { type: "1" };
b: { type: "2" };
c: { type: "3" };
};
// type TestUnionType = AvatarTraverserTypes[keyof AvatarTraverserTypes];
// type MapUnion<T> = T extends InterfaceType<keyof AvatarTraverserTypes>
// ? "interface"
// : T extends UnionType<keyof AvatarTraverserTypes>
// ? "union"
// : T extends PrimitiveType
// ? "primitive"
// : never;
// // Example usage:
// type MappedUnion = MapUnion<TestUnionType>; // "a_mapped" | "b_mapped" | "c_mapped"
interface;
type UnionType = "a" | "b" | "c";
type MapUnion<T> = T extends "a"
? "a_mapped"
: T extends "b"
? "b_mapped"
: T extends "c"
? "c_mapped"
: never;
// Example usage:
type MappedUnion = MapUnion<UnionType>; // "a_mapped" | "b_mapped" | "c_mapped"
const sample: PersonParentIdentifiers = ["Bender", "friends"];
console.log(sample);
/**
* Create the traverser definition
*/
const avatarTraverserDefinition: TraverserDefinition<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";
const avatarTraverserDefinition: TraverserDefinitions<AvatarTraverserTypes> =
{
Element: {
kind: "primitive",
},
},
};
/**
* Instantiate the Traverser
*/
const avatarTraverser = new Traverser<AvatarTraverserTypes>(
avatarTraverserDefinition,
);
/**
* Create a visitor
*/
const avatarVisitor = avatarTraverser.createVisitor<undefined>({
Element: async (item) => {
console.log(`Element: ${item}`);
},
Bender: {
visitor: async (item) => {
console.log(`Bender: ${item.name}`);
Bender: {
kind: "interface",
properties: {
element: "Element",
friends: "Person",
},
},
properties: {
element: async (item) => {
console.log(`Bender.element: ${item}`);
NonBender: {
kind: "interface",
properties: {
friends: "Person",
},
},
},
NonBender: {
visitor: async (item) => {
console.log(`NonBender: ${item.name}`);
Person: {
kind: "union",
selector: (item) => {
return (item as Bender).element ? "Bender" : "NonBender";
},
},
},
Person: async (item) => {
console.log(`Person: ${item.name}`);
},
});
};
/**
* Run the visitor on data
*/
console.log(
"############################## Visitor Logs ##############################",
);
await avatarVisitor.visit(aang, "Bender", undefined);
console.log(avatarTraverserDefinition);
/**
* Create a visitor that uses context
*/
interface AvatarCountingVisitorContext {
numberOfBenders: number;
}
const avatarCountingVisitor =
avatarTraverser.createVisitor<AvatarCountingVisitorContext>({
Bender: {
visitor: async (item, context) => {
context.numberOfBenders++;
},
},
});
const graph = new InstanceGraph(avatarTraverserDefinition);
const aangNode = graph.getNodeFor(aang, "Bender");
const aangeChild = aangNode.child("friends");
/**
* Run the counting visitor
*/
console.log(
"############################## Found Number of Benders Using Visitor ##############################",
);
const countContext: AvatarCountingVisitorContext = { numberOfBenders: 0 };
await avatarCountingVisitor.visit(aang, "Bender", countContext);
console.log(countContext.numberOfBenders);
const parent = aangNode.parent("Person");
/**
* Set up a transformer
*/
interface ActionablePerson {
doAction(): void;
friends: ActionablePerson[];
}
const avatarTransformer = avatarTraverser.createTransformer<
{
Element: {
return: string;
};
Bender: {
return: ActionablePerson;
properties: {
element: string;
};
};
NonBender: {
return: ActionablePerson;
};
},
undefined
>({
Element: async (item) => {
return item.toUpperCase();
},
Bender: {
transformer: async (item, getTransformedChildren) => {
const transformedChildren = await getTransformedChildren();
return {
doAction: () => {
console.log(`I can bend ${transformedChildren.element}`);
},
friends: transformedChildren.friends,
};
},
properties: {
element: async (item, getTransformedChildren) => {
const transformedChildren = await getTransformedChildren();
return `the element of ${transformedChildren}`;
},
},
},
NonBender: {
transformer: async (item, getTransformedChildren) => {
const transformedChildren = await getTransformedChildren();
return {
doAction: () => {
console.log(`I can't bend.`);
},
friends: transformedChildren.friends,
};
},
},
Person: async (
item,
getTransformedChildren,
setReturnPointer,
_context,
) => {
const personToReturn: ActionablePerson = {} as ActionablePerson;
setReturnPointer(personToReturn);
const transformedChildren = await getTransformedChildren();
personToReturn.doAction = transformedChildren.doAction;
personToReturn.friends = transformedChildren.friends;
return personToReturn;
},
const aangChildren = aangNode.allChildren();
aangChildren.forEach((child) => {
child.typeName === "Element";
});
/**
* Run the Transformer
*/
console.log(
"############################## AvatarTraverser DoAction ##############################",
);
const result = await avatarTransformer.transform(aang, "Bender", undefined);
result.doAction();
result.friends[0].doAction();
result.friends[1].doAction();
const aangParents = aangNode.allParents();
// /**
// * Instantiate the Traverser
// */
// const avatarTraverser = new Traverser<AvatarTraverserTypes>(
// avatarTraverserDefinition,
// );
// /**
// * Create a visitor
// */
// const avatarVisitor = avatarTraverser.createVisitor<undefined>({
// Element: async (item) => {
// console.log(`Element: ${item}`);
// },
// Bender: {
// visitor: async (item) => {
// console.log(`Bender: ${item.name}`);
// },
// properties: {
// element: async (item) => {
// console.log(`Bender.element: ${item}`);
// },
// },
// },
// NonBender: {
// visitor: async (item) => {
// console.log(`NonBender: ${item.name}`);
// },
// },
// Person: async (item) => {
// console.log(`Person: ${item.name}`);
// },
// });
// /**
// * Run the visitor on data
// */
// console.log(
// "############################## Visitor Logs ##############################",
// );
// await avatarVisitor.visit(aang, "Bender", undefined);
// /**
// * Create a visitor that uses context
// */
// interface AvatarCountingVisitorContext {
// numberOfBenders: number;
// }
// const avatarCountingVisitor =
// avatarTraverser.createVisitor<AvatarCountingVisitorContext>({
// Bender: {
// visitor: async (item, context) => {
// context.numberOfBenders++;
// },
// },
// });
// /**
// * Run the counting visitor
// */
// console.log(
// "############################## Found Number of Benders Using Visitor ##############################",
// );
// const countContext: AvatarCountingVisitorContext = { numberOfBenders: 0 };
// await avatarCountingVisitor.visit(aang, "Bender", countContext);
// console.log(countContext.numberOfBenders);
// /**
// * Set up a transformer
// */
// interface ActionablePerson {
// doAction(): void;
// friends: ActionablePerson[];
// }
// const avatarTransformer = avatarTraverser.createTransformer<
// {
// Element: {
// return: string;
// };
// Bender: {
// return: ActionablePerson;
// properties: {
// element: string;
// };
// };
// NonBender: {
// return: ActionablePerson;
// };
// },
// undefined
// >({
// Element: async (item) => {
// return item.toUpperCase();
// },
// Bender: {
// transformer: async (item, getTransformedChildren) => {
// const transformedChildren = await getTransformedChildren();
// return {
// doAction: () => {
// console.log(`I can bend ${transformedChildren.element}`);
// },
// friends: transformedChildren.friends,
// };
// },
// properties: {
// element: async (item, getTransformedChildren) => {
// const transformedChildren = await getTransformedChildren();
// return `the element of ${transformedChildren}`;
// },
// },
// },
// NonBender: {
// transformer: async (item, getTransformedChildren) => {
// const transformedChildren = await getTransformedChildren();
// return {
// doAction: () => {
// console.log(`I can't bend.`);
// },
// friends: transformedChildren.friends,
// };
// },
// },
// Person: async (
// item,
// getTransformedChildren,
// setReturnPointer,
// _context,
// ) => {
// const personToReturn: ActionablePerson = {} as ActionablePerson;
// setReturnPointer(personToReturn);
// const transformedChildren = await getTransformedChildren();
// personToReturn.doAction = transformedChildren.doAction;
// personToReturn.friends = transformedChildren.friends;
// return personToReturn;
// },
// });
// /**
// * Run the Transformer
// */
// console.log(
// "############################## AvatarTraverser DoAction ##############################",
// );
// const result = await avatarTransformer.transform(aang, "Bender", undefined);
// result.doAction();
// result.friends[0].doAction();
// result.friends[1].doAction();
}
run();

@ -74,4 +74,9 @@ export type BaseReverseRelationshipIndentifiers<
export type ParentIdentifiers<
Types extends TraverserTypes<any>,
ChildName extends keyof Types,
> = BaseReverseRelationshipIndentifiers<Types, ChildName>[keyof Types];
> = {
[CN in ChildName]: BaseReverseRelationshipIndentifiers<
Types,
CN
>[keyof Types];
}[ChildName];

@ -24,15 +24,22 @@ export type PrimitiveTraverserDefinition = {
export type TraverserDefinition<
Types extends TraverserTypes<any>,
TypeField extends keyof Types,
> = Types[TypeField] extends InterfaceType<keyof Types>
? InterfaceTraverserDefinition<Types[TypeField]>
: Types[TypeField] extends UnionType<keyof Types>
? UnionTraverserDefinition<Types[TypeField]>
: Types[TypeField] extends PrimitiveType
? PrimitiveTraverserDefinition
: never;
TypeName extends keyof Types,
Type extends Types[TypeName],
> = {
[TN in TypeName]: Type extends InterfaceType<keyof Types>
? InterfaceTraverserDefinition<Type>
: Type extends UnionType<keyof Types>
? UnionTraverserDefinition<Type>
: Type extends PrimitiveType
? PrimitiveTraverserDefinition
: never;
}[TypeName];
export type TraverserDefinitions<Types extends TraverserTypes<any>> = {
[TypeField in keyof Types]: TraverserDefinition<Types, TypeField>;
[TypeName in keyof Types]: TraverserDefinition<
Types,
TypeName,
Types[TypeName]
>;
};

@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { MultiMap } from "../transformerSubTraversers/util/MultiMap";
import type { TraverserTypes } from "../TraverserTypes";
import type { InstanceNode } from "./nodes/InstanceNode";
import {
createInstanceNodeFor,
type InstanceNodeFor,
@ -12,7 +11,7 @@ export class InstanceGraph<Types extends TraverserTypes<any>> {
protected objectMap: MultiMap<
object,
keyof Types,
InstanceNode<Types, keyof Types, Types[keyof Types]>
InstanceNodeFor<Types, keyof Types>
> = new MultiMap();
public readonly traverserDefinitions: TraverserDefinitions<Types>;
@ -26,14 +25,23 @@ export class InstanceGraph<Types extends TraverserTypes<any>> {
): InstanceNodeFor<Types, TypeName> {
let potentialNode;
// Skip the cache for Primitive Nodes
if (
const isCachable =
this.traverserDefinitions[typeName].kind !== "primitive" &&
typeof instance === "object" &&
instance != null
) {
instance != null;
if (isCachable) {
potentialNode = this.objectMap.get(instance, typeName);
}
if (potentialNode) return potentialNode as InstanceNodeFor<Types, TypeName>;
return createInstanceNodeFor(instance, typeName, this);
const newNode = createInstanceNodeFor(instance, typeName, this);
if (isCachable) {
// TODO: Figure out why this is a ts error
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
this.objectMap.set(instance, typeName, newNode);
}
newNode._recursivelyBuildChildren();
return newNode;
}
}

@ -8,7 +8,7 @@ import type { InstanceNodeFor } from "./createInstanceNodeFor";
export abstract class InstanceNode<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
_Type extends Types[TypeName],
Type extends Types[TypeName],
> {
readonly graph: InstanceGraph<Types>;
readonly instance: Types[TypeName]["type"];
@ -16,17 +16,16 @@ export abstract class InstanceNode<
protected readonly parents: Record<
string,
Set<InstanceNodeFor<Types, ParentIdentifiers<Types, TypeName>[0]>>
>;
> = {};
constructor(
graph: InstanceGraph<Types>,
instance: Types[TypeName]["type"],
instance: Type["type"],
typeName: TypeName,
) {
this.graph = graph;
this.instance = instance;
this.typeName = typeName;
this._recursivelyBuildChildren();
}
private getParentKey(
@ -68,9 +67,11 @@ export abstract class InstanceNode<
*/
public abstract allChildren(): InstanceNodeFor<Types, any>[];
protected abstract _recursivelyBuildChildren(): void;
public get traverserDefinition(): TraverserDefinition<Types, TypeName> {
return this.graph.traverserDefinitions[this.typeName];
public get traverserDefinition(): TraverserDefinition<Types, TypeName, Type> {
return this.graph.traverserDefinitions[
this.typeName
] as unknown as TraverserDefinition<Types, TypeName, Type>;
}
public abstract _recursivelyBuildChildren(): void;
}

@ -1,8 +1,12 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { InterfaceType, TraverserTypes } from "../../TraverserTypes";
import type { InstanceGraph } from "../instanceGraph";
import type { InstanceNodeFor } from "./createInstanceNodeFor";
import { InstanceNode } from "./InstanceNode";
/**
* Helper Function
*/
type InterfacePropertyNode<
Types extends TraverserTypes<any>,
Type extends InterfaceType<keyof Types>,
@ -11,6 +15,9 @@ type InterfacePropertyNode<
? InstanceNodeFor<Types, Type["properties"][PropertyName]>[]
: InstanceNodeFor<Types, Type["properties"][PropertyName]>;
/**
* Class
*/
export class InterfaceInstanceNode<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
@ -24,6 +31,18 @@ export class InterfaceInstanceNode<
>;
};
constructor(
graph: InstanceGraph<Types>,
instance: Type["type"],
typeName: TypeName,
) {
super(graph, instance, typeName);
// This will eventually be filled out by the recursivelyBuildChildren method
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
this.children = {};
}
public _setChild<PropertyName extends keyof Type["properties"]>(
propertyName: PropertyName,
child: InterfacePropertyNode<Types, Type, PropertyName>,
@ -47,8 +66,15 @@ export class InterfaceInstanceNode<
public _recursivelyBuildChildren() {
Object.entries(this.instance).forEach(
([propertyName, value]: [keyof Type["properties"], unknown]) => {
const propertyTypeName =
// Fancy typescript doesn't work until you actually give it a type
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
this.traverserDefinition.properties[propertyName];
if (!propertyTypeName) return;
const initChildNode = (val: unknown) => {
const node = this.graph.getNodeFor(val, this.typeName);
const node = this.graph.getNodeFor(val, propertyTypeName);
// Fancy typescript doesn't work until you actually give it a type
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore

@ -16,7 +16,7 @@ export class PrimitiveInstanceNode<
public allChildren(): [] {
return [];
}
protected _recursivelyBuildChildren() {
public _recursivelyBuildChildren(): void {
return;
}
}

@ -14,14 +14,21 @@ export class UnionInstanceNode<
this.childNode = child;
}
public child(): InstanceNodeFor<Types, Type["typeNames"]> | undefined {
public child(): InstanceNodeFor<Types, Type["typeNames"]> {
if (!this.childNode) throw new Error("Child node not yet set");
return this.childNode;
}
public allChildren(): InstanceNodeFor<Types, Type["typeNames"]>[] {
return this.childNode ? [this.childNode] : [];
}
protected _recursivelyBuildChildren() {
// TODO
public _recursivelyBuildChildren(): void {
const childType = this.traverserDefinition.selector(this.instance);
const childNode = this.graph.getNodeFor(this.instance, childType);
this._setChild(childNode);
// Fancy typescript only works once the type is provided
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
childNode._setParent([this.typeName], this);
}
}

@ -1,19 +1,152 @@
import { BrokenAvatarTransformer } from "./AvatarBrokenTransformer";
import { AvatarErroringTransformer } from "./AvatarErroringTransformer";
import { aang } from "./sampleData";
import type {
TraverserDefinitions,
ValidateTraverserTypes,
} from "../../../src";
import { InstanceGraph } from "../../../src/instanceGraph/instanceGraph";
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("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<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";
},
},
};
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("Bubbles errors", async () => {
await expect(
AvatarErroringTransformer.transform(aang, "Bender", undefined),
).rejects.toThrow("No Non Benders Allowed");
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");
});
});

@ -0,0 +1,19 @@
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");
});
});

@ -1,7 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist"
"outDir": "./dist",
},
"include": ["./src"]
}

@ -13,6 +13,7 @@
"target": "ES2021",
"sourceMap": true,
"jsx": "react-jsx",
"noErrorTruncation": true
},
"exclude": [
"node_modules",

Loading…
Cancel
Save