UNPKG

@k8ts/instruments

Version:

A collection of utilities and core components for k8ts.

151 lines (138 loc) 5.38 kB
import { Map, type Set } from "immutable" import { Kind } from "../api-kind" import { InstrumentsError } from "../error" import { RefKey } from "../ref-key" const separator = "/" export type LookupKey = NodeEntry[keyof NodeEntry] interface NodeEntry { kind: string class: Function ident: Kind.Identifier } export class KindMap { constructor( private _entryMap: Map<LookupKey, NodeEntry> = Map([]) as any, private _parent: KindMap | undefined = undefined ) {} refKey<Kind extends string, Name extends string>( kind: Kind | Kind.Identifier<Kind>, name: Name ): RefKey<Kind, Name> { const trueKind = this.getKind(kind) return new RefKey.RefKey(trueKind, name) as any } private _bindEntry(entry: NodeEntry) { for (const key of [entry.kind, entry.class, entry.ident]) { this._entryMap = this._entryMap.set(key, entry) } } add(kind: Kind.Identifier, klass: Function) { this._bindEntry({ kind: kind.name, class: klass, ident: kind }) } parse(ref: string | RefKey) { const result = this.tryParse(ref) if (!result) { throw new InstrumentsError(`Could not parse reference key: ${ref}`) } return result } tryParse(ref: unknown): RefKey.RefKey | undefined { if (typeof ref !== "string" && typeof ref !== "object") { return undefined } if (ref == null) { return undefined } if (ref instanceof RefKey.RefKey) { return ref } if (typeof ref === "object") { return undefined } const [kind, name] = ref.split(separator).map(s => s.trim()) if (!kind || !name) { return undefined } return this.refKey(kind, name) } get kinds(): Set<string> { return this._entryMap .keySeq() .filter(k => typeof k === "string") .toSet() } private _unknownNameError(kind: string) { return new InstrumentsError(`The shorthand name ${kind} is not registered`) } private _unknownIdentError(ident: Kind.Identifier) { return new InstrumentsError(`The kind identifier ${ident} is not registered`) } private _unknownClassError(klass: Function) { return new InstrumentsError(`The class ${klass.name} is not registered`) } private _convert(something: LookupKey | RefKey.RefKey) { if (typeof something === "string") { if (something.includes("/")) { return this.parse(something).kind } return something } else if (typeof something === "function" || something instanceof Kind.Identifier) { return something } else if (something instanceof RefKey.RefKey) { return something.kind } throw new InstrumentsError(`Invalid argument ${something}`) } private _getEntry(key: LookupKey | RefKey.RefKey) { const converted = this._convert(key) const entry = this._tryGetEntry(key) if (!entry) { if (typeof converted === "string") { throw this._unknownNameError(converted) } else if (converted instanceof Kind.Identifier) { throw this._unknownIdentError(converted) } else if (typeof converted === "function") { throw this._unknownClassError(converted) } } return entry! } private _tryGetEntry(key: LookupKey | RefKey.RefKey): NodeEntry | undefined { const converted = this._convert(key) return this._entryMap.get(converted) ?? this._parent?._tryGetEntry(converted) ?? undefined } tryGetKind<Name extends string>(refKey: RefKey.RefKey<Name>): Kind.Identifier<Name> | undefined tryGetKind<F extends Kind.Identifier>(klass: F): F tryGetKind<Name extends string>(kind: Name): Kind.Identifier<Name> | undefined tryGetKind(key: LookupKey): Kind.Identifier | undefined tryGetKind(kindOrIdent: LookupKey | RefKey.RefKey): Kind.Identifier | undefined { return this._tryGetEntry(kindOrIdent)?.ident } getKind<K extends Kind.Identifier>(kind: K): K getKind<Name extends string>(kind: Name): Kind.Identifier<Name> getKind(kindOrClass: LookupKey): Kind.Identifier getKind(kindOrClass: string | Function): Kind.Identifier { return this._getEntry(kindOrClass).ident } tryGetClass(refKey: RefKey.RefKey): Function | undefined tryGetClass<F extends Function>(klass: F): F tryGetClass(kind: string): Function | undefined tryGetClass(ident: Kind.Identifier): Function | undefined tryGetClass(kindOrIdent: LookupKey | RefKey.RefKey): Function | undefined { return this._tryGetEntry(kindOrIdent)?.class } getClass(refKey: RefKey.RefKey): Function getClass<F extends Function>(klass: F): F getClass(kind: string): Function getClass<T extends Function | string>(kindOrClass: T): T extends Function ? string : Function getClass(kindOrClass: string | Function | RefKey.RefKey): Function | string { return this._getEntry(kindOrClass).class } has(kindOrClass: LookupKey): boolean { return this._entryMap.has(kindOrClass as any) } }