/* A Dispatcher is a collection of operations that do run-time * dispatch on the types of their arguments. Thus, every individual * method is like a typed-function (from the library by that name), * but they can depend on one another and on ona another's implementations * for specific types (including their own). */ type TypeName = string type Parameter = TypeName type Signature = Parameter[] export class Specifications {} export type typeOfDependency = {typeOf: (x: unknown) => TypeName} //dummy implementation for now export function joinTypes(a: TypeName, b: TypeName) { if (a === b) return a return 'any' } // Will need to build this up. Need to start with looping through the keys of // values of keys, and filtering ones that start with Name, then add in // checking the types. // Some relevant stuff that worked in the playground: // type KeysMatching = {[K in keyof T]-?: T[K] extends V ? K extends `${string}${N}${string}` ? K : never : never}[keyof T]; // type ValuesMatching = {[K in keyof T]: T[K] extends V ? T[K] : never}[keyof T] // type SubKeysMatching = {[K in keyof T]: KeysMatching}[keyof T] // type SubValuesMatching = {[K in keyof T]: ValuesMatching}[keyof T] // let trial: SubKeysMatching = 'strange' // let valtrial: SubValuesMatching = 3 // type MyFunc = (...args: [string, number]) => any // Selecting the proper key for arguments [string, number] is working // let key: KeysMatching = 'bar' // OK, and 'baz' here does fail, as desired // The above should have all of the ingredients. type DependenciesType = Record type FinalShape = FuncType extends (arg: DependenciesType) => Function ? ReturnType : FuncType type BeginsWith = `${Name}${string}` type ImmediateDependency = {[K in keyof Ob]: K extends BeginsWith ? FinalShape extends (...args: ParamTuple) => any ? FinalShape : never : never}[keyof Ob] type SpecType = typeof Specifications export type ImplementationDependency = {[S in keyof SpecType]: ImmediateDependency}[keyof SpecType] type TypeSpecification = { before?: TypeName[], test: ((x: unknown) => boolean) | ((d: DependenciesType) => (x: unknown) => boolean), from: Record, infer?: (d: DependenciesType) => (z: unknown) => TypeName } type SpecObject = Record export type SpecifcationsGroup = Record export class Dispatcher { installSpecification( name: string, signature: Signature, returns: Type, dependencies: Record, behavior: Function // possible todo: constrain this type based // on the signature, return type, and dependencies. Not sure if // that's really possible, though. ) { console.log('Pretending to install', name, signature, '=>', returns) //TODO: implement me } installType(name: TypeName, typespec: TypeSpecification) { console.log('Pretending to install type', name, typespec) //TODO: implement me } constructor(collection: SpecificationsGroup) { for (key in collection) { console.log('Working on', key) for (identifier in collection[key]) { console.log('Handling', key, ':', identifier) const parts = identifier.split('_') if (parts[parts.length - 1] === 'type') { parts.pop() const name = parts.join('_') installType(name, collection[key][identifier]) } else { const name = parts[0] installSpecification( name, ['dunno'], 'unsure', {}, collection[key][identifier]) } } } } }