before touching traverserDefinition

main
Jackson Morgan 9 months ago
parent 67db1eaf28
commit 7716e49e1a
  1. 66
      packages/type-traverser/example/example.ts
  2. 77
      packages/type-traverser/src/ReverseRelationshipTypes.ts
  3. 6
      packages/type-traverser/src/Transformer.ts
  4. 6
      packages/type-traverser/src/Traverser.ts
  5. 23
      packages/type-traverser/src/TraverserDefinition.ts
  6. 6
      packages/type-traverser/src/Visitor.ts
  7. 39
      packages/type-traverser/src/instanceGraph/InstanceGraph.ts
  8. 80
      packages/type-traverser/src/instanceGraph/nodes/InstanceNode.ts
  9. 67
      packages/type-traverser/src/instanceGraph/nodes/InterfaceInstanceNode.ts
  10. 22
      packages/type-traverser/src/instanceGraph/nodes/PrimitiveInstanceNode.ts
  11. 27
      packages/type-traverser/src/instanceGraph/nodes/UnionInstanceNode.ts
  12. 52
      packages/type-traverser/src/instanceGraph/nodes/createInstanceNodeFor.ts
  13. 4
      packages/type-traverser/src/transformerSubTraversers/util/MultiMap.ts
  14. 4
      packages/type-traverser/src/transformerSubTraversers/util/MultiSet.ts
  15. 4
      packages/type-traverser/src/transformerSubTraversers/util/transformerSubTraverserTypes.ts
  16. 4
      packages/type-traverser/src/visitorSubTraversers/util/visitorSubTraverserTypes.ts

@ -1,5 +1,13 @@
import type { TraverserDefinition, ValidateTraverserTypes } from "../src";
import type {
TraverserDefinition,
ValidateTraverserTypes,
AssertExtends,
InterfaceType,
PrimitiveType,
UnionType,
} from "../src";
import { Traverser } from "../src";
import type { ReverseRelationshipIndentifiers } from "../src/reverseRelationshipTypes";
async function run() {
/**
@ -68,6 +76,62 @@ 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<
AvatarTraverserTypes,
{ kind: "interface" }
>;
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"
/**
* Create the traverser definition
*/

@ -0,0 +1,77 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type {
InterfaceType,
PrimitiveType,
TraverserTypes,
UnionType,
} from "./TraverserTypes";
export type InterfaceReverseRelationshipIndentifier<
Types extends TraverserTypes<any>,
ChildName extends keyof Types,
PotentialParentName extends keyof Types,
PotentialParentType extends InterfaceType<keyof Types>,
> = {
[PropertyField in keyof PotentialParentType["properties"]]: ChildName extends PotentialParentType["properties"][PropertyField]
? [PotentialParentName, PropertyField]
: never;
}[keyof PotentialParentType["properties"]];
export type UnionReverseRelationshipIndentifier<
Types extends TraverserTypes<any>,
ChildName extends keyof Types,
PotentialParentName extends keyof Types,
PotentialParentType extends UnionType<keyof Types>,
> = ChildName extends PotentialParentType["typeNames"]
? [PotentialParentName]
: never;
export type PrimitiveReverseRelationshipIndentifier<
Types extends TraverserTypes<any>,
_ChildName extends keyof Types,
_PotentialParentName extends keyof Types,
_PotentialParentType extends PrimitiveType,
> = never;
export type BaseReverseRelationshipIndentifier<
Types extends TraverserTypes<any>,
ChildName extends keyof Types,
PotentialParentName extends keyof Types,
> = Types[PotentialParentName] extends InterfaceType<keyof Types>
? InterfaceReverseRelationshipIndentifier<
Types,
ChildName,
PotentialParentName,
Types[PotentialParentName]
>
: Types[PotentialParentName] extends UnionType<keyof Types>
? UnionReverseRelationshipIndentifier<
Types,
ChildName,
PotentialParentName,
Types[PotentialParentName]
>
: Types[PotentialParentName] extends PrimitiveType
? PrimitiveReverseRelationshipIndentifier<
Types,
ChildName,
PotentialParentName,
Types[PotentialParentName]
>
: never;
export type BaseReverseRelationshipIndentifiers<
Types extends TraverserTypes<any>,
ChildName extends keyof Types,
> = {
[ParentName in keyof Types]: BaseReverseRelationshipIndentifier<
Types,
ChildName,
ParentName
>;
};
export type ParentIdentifiers<
Types extends TraverserTypes<any>,
ChildName extends keyof Types,
> = BaseReverseRelationshipIndentifiers<Types, ChildName>[keyof Types];

@ -8,7 +8,7 @@ import type {
PrimitiveReturnType,
PrimitiveType,
TransformerInputReturnTypes,
TraverserDefinition,
TraverserDefinitions,
TraverserTypes,
UnionReturnType,
UnionType,
@ -38,7 +38,7 @@ export class Transformer<
InputReturnTypes extends TransformerInputReturnTypes<Types>,
Context = undefined,
> {
private traverserDefinition: TraverserDefinition<Types>;
private traverserDefinition: TraverserDefinitions<Types>;
private transformers: Transformers<
Types,
ApplyTransformerReturnTypesDefaults<Types, InputReturnTypes>,
@ -46,7 +46,7 @@ export class Transformer<
>;
constructor(
traverserDefinition: TraverserDefinition<Types>,
traverserDefinition: TraverserDefinitions<Types>,
transformers: TransformersInput<Types, InputReturnTypes, Context>,
) {
this.traverserDefinition = traverserDefinition;

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type {
TransformerInputReturnTypes,
TraverserDefinition,
TraverserDefinitions,
TraverserTypes,
VisitorsInput,
} from ".";
@ -12,9 +12,9 @@ export class Traverser<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Types extends TraverserTypes<any>,
> {
private traverserDefinition: TraverserDefinition<Types>;
private traverserDefinition: TraverserDefinitions<Types>;
constructor(traverserDefinition: TraverserDefinition<Types>) {
constructor(traverserDefinition: TraverserDefinitions<Types>) {
this.traverserDefinition = traverserDefinition;
}

@ -22,14 +22,17 @@ export type PrimitiveTraverserDefinition = {
kind: "primitive";
};
export type TraverserDefinition<Types extends TraverserTypes<any>> = {
[TypeField in 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;
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;
export type TraverserDefinitions<Types extends TraverserTypes<any>> = {
[TypeField in keyof Types]: TraverserDefinition<Types, TypeField>;
};

@ -8,7 +8,7 @@ import type {
PrimitiveType,
PrimitiveVisitorDefinition,
PrimitiveVisitorInputDefinition,
TraverserDefinition,
TraverserDefinitions,
TraverserTypes,
UnionType,
UnionVisitorDefinition,
@ -27,11 +27,11 @@ export class Visitor<
Types extends TraverserTypes<any>,
Context = undefined,
> {
private traverserDefinition: TraverserDefinition<Types>;
private traverserDefinition: TraverserDefinitions<Types>;
private visitors: Visitors<Types, Context>;
constructor(
traverserDefinition: TraverserDefinition<Types>,
traverserDefinition: TraverserDefinitions<Types>,
visitors: VisitorsInput<Types, Context>,
) {
this.traverserDefinition = traverserDefinition;

@ -0,0 +1,39 @@
/* 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,
} from "./nodes/createInstanceNodeFor";
import type { TraverserDefinitions } from "../TraverserDefinition";
export class InstanceGraph<Types extends TraverserTypes<any>> {
protected objectMap: MultiMap<
object,
keyof Types,
InstanceNode<Types, keyof Types, Types[keyof Types]>
> = new MultiMap();
public readonly traverserDefinitions: TraverserDefinitions<Types>;
constructor(traverserDefinitions: TraverserDefinitions<Types>) {
this.traverserDefinitions = traverserDefinitions;
}
getNodeFor<TypeName extends keyof Types>(
instance: unknown,
typeName: TypeName,
): InstanceNodeFor<Types, TypeName> {
let potentialNode;
// Skip the cache for Primitive Nodes
if (
this.traverserDefinitions[typeName].kind !== "primitive" &&
typeof instance === "object" &&
instance != null
) {
potentialNode = this.objectMap.get(instance, typeName);
}
if (potentialNode) return potentialNode as InstanceNodeFor<Types, TypeName>;
return createInstanceNodeFor(instance, typeName, this);
}
}

@ -0,0 +1,80 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { TraverserDefinition } from "../..";
import type { ParentIdentifiers } from "../../reverseRelationshipTypes";
import type { TraverserTypes } from "../../TraverserTypes";
import type { InstanceGraph } from "../instanceGraph";
import type { InstanceNodeFor } from "./createInstanceNodeFor";
export abstract class InstanceNode<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
_Type extends Types[TypeName],
> {
readonly graph: InstanceGraph<Types>;
readonly instance: Types[TypeName]["type"];
readonly typeName: TypeName;
protected readonly parents: Record<
string,
Set<InstanceNodeFor<Types, Types[ParentIdentifiers<Types, TypeName>[0]]>>
>;
constructor(
graph: InstanceGraph<Types>,
instance: Types[TypeName]["type"],
typeName: TypeName,
) {
this.graph = graph;
this.instance = instance;
this.typeName = typeName;
this._recursivelyBuildChildren();
}
private getParentKey(
identifiers: ParentIdentifiers<Types, TypeName>,
): string {
return identifiers.join("|");
}
public _setParent<Identifiers extends ParentIdentifiers<Types, TypeName>>(
identifiers: Identifiers,
parentNode: InstanceNodeFor<Types, Types[Identifiers[0]]>,
) {
const parentKey = this.getParentKey(identifiers);
if (!this.parents[parentKey]) this.parents[parentKey] = new Set();
this.parents[parentKey].add(parentNode);
}
public parent<Identifiers extends ParentIdentifiers<Types, TypeName>>(
...identifiers: Identifiers
): InstanceNodeFor<Types, Identifiers[0]>[] {
return Array.from(this.parents[this.getParentKey(identifiers)] ?? []);
}
public allParents(): InstanceNodeFor<
Types,
ParentIdentifiers<Types, TypeName>[0]
>[] {
return Object.values(this.parents)
.map((parentSet) => Array.from(parentSet))
.flat();
}
public abstract _setChild(...props: any[]): void;
public abstract child(...props: any[]): any;
/**
* Returns all nodes that are children of this node reguardless of their edge
*/
public abstract allChildren(): InstanceNode<
Types,
keyof Types,
Types[keyof Types]
>[];
protected abstract _recursivelyBuildChildren(): void;
public get traverserDefinition(): TraverserDefinition<Types, TypeName> {
return this.graph.traverserDefinitions[this.typeName];
}
}

@ -0,0 +1,67 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { InterfaceType, TraverserTypes } from "../../TraverserTypes";
import type { InstanceNodeFor } from "./createInstanceNodeFor";
import { InstanceNode } from "./InstanceNode";
type InterfacePropertyNode<
Types extends TraverserTypes<any>,
Type extends InterfaceType<keyof Types>,
PropertyName extends keyof Type["properties"],
> = Type["type"][PropertyName] extends Array<any>
? InstanceNodeFor<Types, Type["properties"][PropertyName]>[]
: InstanceNodeFor<Types, Type["properties"][PropertyName]>;
export class InterfaceInstanceNode<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends InterfaceType<keyof Types> & Types[TypeName],
> extends InstanceNode<Types, TypeName, Type> {
private children: {
[PropertyName in keyof Type["properties"]]: InterfacePropertyNode<
Types,
Type,
PropertyName
>;
};
public _setChild<PropertyName extends keyof Type["properties"]>(
propertyName: PropertyName,
child: InterfacePropertyNode<Types, Type, PropertyName>,
): void {
this.children[propertyName] = child;
}
public child<PropertyName extends keyof Type["properties"]>(
propertyName: PropertyName,
): InterfacePropertyNode<Types, Type, PropertyName> {
return this.children[propertyName];
}
public allChildren(): InstanceNodeFor<
Types,
Types[Type["properties"][keyof Type["properties"]]]
>[] {
return Object.values(this.children).flat();
}
public _recursivelyBuildChildren() {
Object.entries(this.instance).forEach(
([propertyName, value]: [keyof Type["properties"], unknown]) => {
const initChildNode = (val: unknown) => {
const node = this.graph.getNodeFor(val, this.typeName);
// I know it's bad, I just can't figure out what's wrong with this type
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
node._setParent([this.typeName, propertyName], this);
return node;
};
const childNode = (
Array.isArray(value)
? value.map((val) => initChildNode(val))
: initChildNode(value)
) as InterfacePropertyNode<Types, Type, keyof Type["properties"]>;
this._setChild(propertyName, childNode);
},
);
}
}

@ -0,0 +1,22 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { PrimitiveType, TraverserTypes } from "../../TraverserTypes";
import { InstanceNode } from "./InstanceNode";
export class PrimitiveInstanceNode<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends PrimitiveType & Types[TypeName],
> extends InstanceNode<Types, TypeName, Type> {
public _setChild(): void {
return;
}
public child() {
return undefined;
}
public allChildren(): [] {
return [];
}
protected _recursivelyBuildChildren() {
return;
}
}

@ -0,0 +1,27 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { TraverserTypes, UnionType } from "../../TraverserTypes";
import type { InstanceNodeFor } from "./createInstanceNodeFor";
import { InstanceNode } from "./InstanceNode";
export class UnionInstanceNode<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
Type extends UnionType<keyof Types> & Types[TypeName],
> extends InstanceNode<Types, TypeName, Type> {
private childNode: InstanceNodeFor<Types, Type["typeNames"]> | undefined;
public _setChild(child: InstanceNodeFor<Types, Type["typeNames"]>): void {
this.childNode = child;
}
public child(): InstanceNodeFor<Types, Type["typeNames"]> | undefined {
return this.childNode;
}
public allChildren(): InstanceNode<Types, keyof Types, Types[keyof Types]>[] {
return this.childNode ? [this.childNode] : [];
}
protected _recursivelyBuildChildren() {
// TODO
}
}

@ -0,0 +1,52 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type {
InterfaceType,
PrimitiveType,
TraverserTypes,
UnionType,
} from "../../TraverserTypes";
import type { InstanceGraph } from "../instanceGraph";
import { InterfaceInstanceNode } from "./InterfaceInstanceNode";
import { PrimitiveInstanceNode } from "./PrimitiveInstanceNode";
import { UnionInstanceNode } from "./UnionInstanceNode";
export type InstanceNodeFor<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
> = Types[TypeName] extends InterfaceType<keyof Types>
? InterfaceInstanceNode<Types, TypeName, Types[TypeName]>
: Types[TypeName] extends UnionType<keyof Types>
? UnionInstanceNode<Types, TypeName, Types[TypeName]>
: Types[TypeName] extends PrimitiveType
? PrimitiveInstanceNode<Types, TypeName, Types[TypeName]>
: never;
export function createInstanceNodeFor<
Types extends TraverserTypes<any>,
TypeName extends keyof Types,
>(
instance: unknown,
typeName: TypeName,
graph: InstanceGraph<Types>,
): InstanceNodeFor<Types, TypeName> {
switch (graph.traverserDefinitions[typeName].kind) {
case "interface":
return new InterfaceInstanceNode(
graph,
instance,
typeName,
) as InstanceNodeFor<Types, TypeName>;
case "union":
return new UnionInstanceNode(
graph,
instance,
typeName,
) as InstanceNodeFor<Types, TypeName>;
case "primitive":
return new PrimitiveInstanceNode(
graph,
instance,
typeName,
) as InstanceNodeFor<Types, TypeName>;
}
}

@ -1,3 +1,7 @@
/**
* A Multi-Map is a map between the tuple of two items and a value
*/
/* eslint-disable @typescript-eslint/no-explicit-any */
export class MultiMap<Key1, Key2, Value> {
private map: Map<Key1, Map<Key2, Value>> = new Map();

@ -1,3 +1,7 @@
/**
* A Multi-Set is a set where two items occupy a unique spot
*/
export class MultiSet<Key1, Key2> {
private map: Map<Key1, Set<Key2>> = new Map();
// eslint-disable-next-line @typescript-eslint/no-inferrable-types

@ -4,7 +4,7 @@ import type {
BaseTraverserTypes,
KeyTypes,
TransformerReturnTypes,
TraverserDefinition,
TraverserDefinitions,
TraverserTypes,
} from "../..";
import type { Transformers } from "../../Transformers";
@ -30,7 +30,7 @@ export interface TransformerSubTraverserGlobals<
ReturnTypes extends TransformerReturnTypes<Types>,
Context,
> {
traverserDefinition: TraverserDefinition<Types>;
traverserDefinition: TraverserDefinitions<Types>;
transformers: Transformers<Types, ReturnTypes, Context>;
executingPromises: TransformerSubTraverserExecutingPromises<keyof Types>;
circularDependencyAwaiter: CircularDepenedencyAwaiter;

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type {
BaseTraverserTypes,
TraverserDefinition,
TraverserDefinitions,
TraverserTypes,
Visitors,
} from "../..";
@ -22,7 +22,7 @@ export interface VisitorSubTraverserGlobals<
Types extends TraverserTypes<any>,
Context,
> {
traverserDefinition: TraverserDefinition<Types>;
traverserDefinition: TraverserDefinitions<Types>;
visitors: Visitors<Types, Context>;
visitedObjects: MultiSet<object, keyof Types>;
context: Context;

Loading…
Cancel
Save