@k8ts/instruments
Version:
A collection of utilities and core components for k8ts.
152 lines (141 loc) • 5.26 kB
text/typescript
import chalk from "chalk"
import { Embedder } from "../_embedder"
export type KnownFormats = "local" | "global" | undefined
export namespace Displayers {
export interface Out {
default: (format?: string) => string
simple: (format?: KnownFormats | string) => string
pretty: (format?: KnownFormats | string) => string
prefix?: () => string
}
export type In<Target extends object = object> = {
simple?: (this: Out, self: Target, format?: string) => string | object
pretty?: (this: Out, self: Target, format?: string) => string | object
prefix?: (this: Out, self: Target) => string
}
export type Modes = keyof In
}
const chalkNoColor = new chalk.Instance({
level: 0
})
class DisplayerDecorator {
private _system = new Embedder<object, Displayers.In>("displayers")
private _lastMode: Displayers.Modes = "simple"
private _withLastMode(mode: Displayers.Modes, fn: (...args: any[]) => string) {
return (...args: any[]) => {
const oldMode = this._lastMode
this._lastMode = mode
const result = fn(...args)
this._lastMode = oldMode
return result
}
}
implement(ctor: typeof PrivateCtorExemplar, input: Displayers.In) {
this._system.set(ctor.prototype, input)
const decorator = this
Object.defineProperties(ctor.prototype, {
[Symbol.toStringTag]: {
get() {
const a = decorator.get(this)
return a.default()
}
},
toString: {
value() {
return this[Symbol.toStringTag]
}
}
})
}
wrapRecursiveFallback(out: Displayers.Out) {
const oAny = out as any
const self = this
for (const k in out) {
const orig = oAny[k]
if (typeof orig === "function") {
oAny[k] = function (...args: any[]) {
const oldMode = self._lastMode
if (k === "simple" || k === "pretty") {
self._lastMode = k
}
try {
let result = orig.call(oAny, ...args)
if (!Array.isArray(result)) {
result = [result]
}
const terms = result.map((x: any) => {
const sndDisplayers = Displayers.tryGet(x) as any
if (sndDisplayers) {
return sndDisplayers[k].call(sndDisplayers, x, ...args)
}
return x
})
return terms.join(" ")
} finally {
this._lastMode = oldMode
}
}
}
}
return out
}
tryGet(target: any): Displayers.Out | undefined {
if (typeof target !== "object") {
return undefined
}
const input = this._system.get(target)
if (!input) {
return undefined
}
const o: Displayers.Out = {
default: (format?: string) => {
const lastMode = this._lastMode
const result = o[lastMode]?.call(o, format) ?? o.simple(format)
return result
},
simple: format => {
const result = input.simple?.call(o, target, format)
if (!result) {
const pretty = input.pretty?.call(o, target, format)
if (typeof pretty === "string") {
return chalkNoColor(pretty)
}
return "?!!?"
}
return result as any
},
prefix: input.prefix && (() => input.prefix!.call(o, target)),
pretty: format => {
return (input.pretty?.call(o, target, format) ??
input.simple?.call(o, target, format) ??
"?!?") as any
}
}
return this.wrapRecursiveFallback(o)
}
get(target: object): Displayers.Out {
this._system.get(target) // error if not there
return this.tryGet(target)!
}
get decorator() {
return <Target extends AnyCtor<any>, Impl extends Displayers.In<InstanceTypeOf<Target>>>(
input: Impl
) => {
return (ctor: Target) => {
this.implement(ctor, input as any)
}
}
}
}
export type PrivateCtor<T extends object> = typeof PrivateCtorExemplar & {
prototype: T
}
export type PublicCtor<T extends object> = abstract new (...args: any[]) => T
export type AnyCtor<T extends object> = PrivateCtor<T> | PublicCtor<T>
export type InstanceTypeOf<T extends AnyCtor<any>> =
T extends PrivateCtor<infer U> ? U : T extends PublicCtor<infer U> ? U : never
abstract class PrivateCtorExemplar {
protected constructor(...args: any[]) {}
}
export const Displayers = new DisplayerDecorator()
export const displayers = Displayers.decorator