parent
67db1eaf28
commit
7716e49e1a
@ -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]; |
@ -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>; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue