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