UNPKG

@cordisjs/core

Version:

Meta-Framework for Modern JavaScript Applications

395 lines (394 loc) 17.2 kB
import { Awaitable, Dict, Promisify } from 'cosmokit'; export abstract class Service<T = unknown, C extends Context = Context> { static readonly setup: unique symbol; static readonly invoke: unique symbol; static readonly extend: unique symbol; static readonly tracker: unique symbol; static readonly provide: unique symbol; static readonly immediate: unique symbol; protected start(): Awaitable<void>; protected stop(): Awaitable<void>; protected fork?(ctx: C, config: any): void; protected ctx: C; name: string; config: T; constructor(...args: Spread<T>); constructor(ctx: C, ...args: Spread<T>); constructor(ctx: C, name: string, immediate?: boolean); protected [symbols.filter](ctx: Context): boolean; protected [symbols.setup](): void; protected [symbols.extend](props?: any): any; static [Symbol.hasInstance](instance: any): boolean; } export interface Tracker { associate?: string; property?: string; } export const symbols: { shadow: symbol; receiver: symbol; original: symbol; store: typeof Context.store; events: typeof Context.events; static: typeof Context.static; filter: typeof Context.filter; expose: typeof Context.expose; isolate: typeof Context.isolate; internal: typeof Context.internal; intercept: typeof Context.intercept; setup: typeof Service.setup; invoke: typeof Service.invoke; extend: typeof Service.extend; tracker: typeof Service.tracker; provide: typeof Service.provide; immediate: typeof Service.immediate; }; export function isConstructor(func: any): func is new (...args: any) => any; export function resolveConfig(plugin: any, config: any): any; export function isUnproxyable(value: any): boolean; export function joinPrototype(proto1: {}, proto2: {}): any; export function isObject(value: any): value is {}; export function getTraceable<T>(ctx: Context, value: T, noTrap?: boolean): T; export function withProps(target: any, props?: {}): any; export function createCallable(name: string, proto: {}, tracker: Tracker): any; export type Inject = string[] | Dict<Inject.Meta>; export function Inject(inject: Inject): (value: any, ctx: ClassDecoratorContext<any> | ClassMethodDecoratorContext<any>) => void; export namespace Inject { interface Meta { required: boolean; } function resolve(inject: Inject | null | undefined): { [k: string]: { required: boolean; }; }; } export type Plugin<C extends Context = Context, T = any> = Plugin.Function<C, T> | Plugin.Constructor<C, T> | Plugin.Object<C, T>; export namespace Plugin { interface Base<T = any> { name?: string; reactive?: boolean; reusable?: boolean; Config?: (config: any) => T; inject?: Inject; intercept?: Dict<boolean>; } interface Transform<S, T> { schema?: true; Config: (config: S) => T; } interface Function<C extends Context = Context, T = any> extends Base<T> { (ctx: C, config: T): void; } interface Constructor<C extends Context = Context, T = any> extends Base<T> { new (ctx: C, config: T): void; } interface Object<C extends Context = Context, T = any> extends Base<T> { apply: (ctx: C, config: T) => void; } } export type Spread<T> = undefined extends T ? [config?: T] : [config: T]; export interface Context { /** @deprecated use `ctx.inject()` instead */ using(deps: Inject, callback: Plugin.Function<this, void>): ForkScope<this>; inject(deps: Inject, callback: Plugin.Function<this, void>): ForkScope<this>; plugin<T = undefined, S = T>(plugin: Plugin.Function<this, T> & Plugin.Transform<S, T>, ...args: Spread<S>): ForkScope<this>; plugin<T = undefined, S = T>(plugin: Plugin.Constructor<this, T> & Plugin.Transform<S, T>, ...args: Spread<S>): ForkScope<this>; plugin<T = undefined, S = T>(plugin: Plugin.Object<this, T> & Plugin.Transform<S, T>, ...args: Spread<S>): ForkScope<this>; plugin<T = undefined>(plugin: Plugin.Function<this, T>, ...args: Spread<T>): ForkScope<this>; plugin<T = undefined>(plugin: Plugin.Constructor<this, T>, ...args: Spread<T>): ForkScope<this>; plugin<T = undefined>(plugin: Plugin.Object<this, T>, ...args: Spread<T>): ForkScope<this>; } declare class Registry<C extends Context = Context> { ctx: C; private _counter; private _internal; protected context: Context; constructor(ctx: C, config: any); get counter(): number; get size(): number; resolve(plugin: Plugin, assert?: boolean): Function | undefined; get(plugin: Plugin): MainScope<C> | undefined; has(plugin: Plugin): boolean; set(plugin: Plugin, state: MainScope<C>): void; delete(plugin: Plugin): MainScope<C> | undefined; keys(): IterableIterator<Function>; values(): IterableIterator<MainScope<C>>; entries(): IterableIterator<[Function, MainScope<C>]>; forEach(callback: (value: MainScope<C>, key: Function, map: Map<Plugin, MainScope<C>>) => void): void; using(inject: Inject, callback: Plugin.Function<C, void>): ForkScope<C>; inject(inject: Inject, callback: Plugin.Function<C, void>): ForkScope<C>; plugin(plugin: Plugin<C>, config?: any, error?: any): ForkScope<C>; } export interface Context { scope: EffectScope<this>; runtime: MainScope<this>; effect<T extends DisposableLike>(callback: Callable<T, [ctx: this]>): T; effect<T extends DisposableLike, R>(callback: Callable<T, [ctx: this, config: R]>, config: R): T; /** @deprecated use `ctx.effect()` instead */ collect(label: string, callback: () => void): () => void; accept(callback?: (config: this['config']) => void | boolean, options?: AcceptOptions): () => boolean; accept(keys: (keyof this['config'])[], callback?: (config: this['config']) => void | boolean, options?: AcceptOptions): () => boolean; decline(keys: (keyof this['config'])[]): () => boolean; } export type Disposable = () => void; export type DisposableLike = Disposable | { dispose: Disposable; }; export type Callable<T, R extends unknown[]> = ((...args: R) => T) | (new (...args: R) => T); export interface AcceptOptions { passive?: boolean; immediate?: boolean; } export interface Acceptor extends AcceptOptions { keys?: string[]; callback?: (config: any) => void | boolean; } export const enum ScopeStatus { PENDING = 0, LOADING = 1, ACTIVE = 2, FAILED = 3, DISPOSED = 4 } export class CordisError extends Error { code: CordisError.Code; constructor(code: CordisError.Code, message?: string); } export namespace CordisError { type Code = keyof typeof Code; const Code: { readonly INACTIVE_EFFECT: "cannot create effect on inactive context"; }; } export abstract class EffectScope<C extends Context = Context> { parent: C; config: C['config']; uid: number | null; ctx: C; disposables: Disposable[]; error: any; status: ScopeStatus; isActive: boolean; protected context: Context; protected proxy: any; protected acceptors: Acceptor[]; protected tasks: Set<Promise<void>>; protected hasError: boolean; abstract runtime: MainScope<C>; abstract dispose(): boolean; abstract update(config: C['config'], forced?: boolean): void; constructor(parent: C, config: C['config']); protected get _config(): any; assertActive(): void; effect(callback: Callable<DisposableLike, [ctx: C, config: any]>, config?: any): { dispose: Disposable; } | (() => void); collect(label: string, callback: () => any): () => any; restart(): void; protected _getStatus(): ScopeStatus; updateStatus(callback?: () => void): void; ensure(callback: () => Promise<void>): void; cancel(reason?: any): void; get ready(): boolean; reset(): void; protected init(error?: any): void; start(): true | undefined; accept(callback?: (config: C['config']) => void | boolean, options?: AcceptOptions): () => boolean; accept(keys: string[], callback?: (config: C['config']) => void | boolean, options?: AcceptOptions): () => boolean; decline(keys: string[]): () => boolean; checkUpdate(resolved: any, forced?: boolean): boolean[]; } export class ForkScope<C extends Context = Context> extends EffectScope<C> { runtime: MainScope<C>; dispose: () => boolean; constructor(parent: Context, runtime: MainScope<C>, config: C['config'], error?: any); start(): true | undefined; update(config: any, forced?: boolean): void; } export class MainScope<C extends Context = Context> extends EffectScope<C> { plugin: Plugin; value: any; runtime: this; schema: any; name?: string; inject: Dict<Inject.Meta>; forkables: Function[]; children: ForkScope<C>[]; isReusable?: boolean; isReactive?: boolean; constructor(ctx: C, plugin: Plugin, config: any, error?: any); get isForkable(): boolean; fork(parent: Context, config: any, error?: any): ForkScope<C>; dispose(): boolean; private setup; private apply; reset(): void; start(): true | undefined; update(config: C['config'], forced?: boolean): void; } export interface Context { get<K extends string & keyof this>(name: K): undefined | this[K]; get(name: string): any; set<K extends string & keyof this>(name: K, value: undefined | this[K]): () => void; set(name: string, value: any): () => void; /** @deprecated use `ctx.set()` instead */ provide(name: string, value?: any, builtin?: boolean): void; accessor(name: string, options: Omit<Context.Internal.Accessor, 'type'>): void; alias(name: string, aliases: string[]): void; mixin<K extends string & keyof this>(name: K, mixins: (keyof this & keyof this[K])[] | Dict<string>): void; mixin<T extends {}>(source: T, mixins: (keyof this & keyof T)[] | Dict<string>): void; } declare class ReflectService { ctx: Context; static resolveInject(ctx: Context, name: string): readonly [string, Context.Internal.Service | Context.Internal.Accessor]; static checkInject(ctx: Context, name: string, error: Error): void; static handler: ProxyHandler<Context>; constructor(ctx: Context); get(name: string): any; set(name: string, value: any): () => void; provide(name: string, value?: any, builtin?: boolean): void; _accessor(name: string, options: Omit<Context.Internal.Accessor, 'type'>): () => void; accessor(name: string, options: Omit<Context.Internal.Accessor, 'type'>): void; alias(name: string, aliases: string[]): void; _mixin(source: any, mixins: string[] | Dict<string>): () => void; mixin(source: any, mixins: string[] | Dict<string>): void; trace<T>(value: T): T; bind<T extends Function>(callback: T): T; } export function isBailed(value: any): boolean; export type Parameters<F> = F extends (...args: infer P) => any ? P : never; export type ReturnType<F> = F extends (...args: any) => infer R ? R : never; export type ThisType<F> = F extends (this: infer T, ...args: any) => any ? T : never; export type GetEvents<C extends Context> = C[typeof Context.events]; export interface Context { [Context.events]: Events<this>; parallel<K extends keyof GetEvents<this>>(name: K, ...args: Parameters<GetEvents<this>[K]>): Promise<void>; parallel<K extends keyof GetEvents<this>>(thisArg: ThisType<GetEvents<this>[K]>, name: K, ...args: Parameters<GetEvents<this>[K]>): Promise<void>; emit<K extends keyof GetEvents<this>>(name: K, ...args: Parameters<GetEvents<this>[K]>): void; emit<K extends keyof GetEvents<this>>(thisArg: ThisType<GetEvents<this>[K]>, name: K, ...args: Parameters<GetEvents<this>[K]>): void; serial<K extends keyof GetEvents<this>>(name: K, ...args: Parameters<GetEvents<this>[K]>): Promisify<ReturnType<GetEvents<this>[K]>>; serial<K extends keyof GetEvents<this>>(thisArg: ThisType<GetEvents<this>[K]>, name: K, ...args: Parameters<GetEvents<this>[K]>): Promisify<ReturnType<GetEvents<this>[K]>>; bail<K extends keyof GetEvents<this>>(name: K, ...args: Parameters<GetEvents<this>[K]>): ReturnType<GetEvents<this>[K]>; bail<K extends keyof GetEvents<this>>(thisArg: ThisType<GetEvents<this>[K]>, name: K, ...args: Parameters<GetEvents<this>[K]>): ReturnType<GetEvents<this>[K]>; on<K extends keyof GetEvents<this>>(name: K, listener: GetEvents<this>[K], options?: boolean | EventOptions): () => boolean; once<K extends keyof GetEvents<this>>(name: K, listener: GetEvents<this>[K], options?: boolean | EventOptions): () => boolean; off<K extends keyof GetEvents<this>>(name: K, listener: GetEvents<this>[K]): boolean; start(): Promise<void>; stop(): Promise<void>; } export interface EventOptions { prepend?: boolean; global?: boolean; } export interface Hook extends EventOptions { ctx: Context; callback: (...args: any[]) => any; } declare class Lifecycle { private ctx; isActive: boolean; _tasks: Set<Promise<void>>; _hooks: Record<keyof any, Hook[]>; constructor(ctx: Context); flush(): Promise<void>; filterHooks(hooks: Hook[], thisArg?: object): Hook[]; dispatch(type: string, args: any[]): Generator<any, void, unknown>; parallel(...args: any[]): Promise<void>; emit(...args: any[]): void; serial(...args: any[]): Promise<any>; bail(...args: any[]): any; register(label: string, hooks: Hook[], callback: any, options: EventOptions): () => any; unregister(hooks: Hook[], callback: any): true | undefined; on(name: string, listener: (...args: any) => any, options?: boolean | EventOptions): any; once(name: string, listener: (...args: any) => any, options?: boolean | EventOptions): any; start(): Promise<void>; stop(): Promise<void>; } export interface Events<in C extends Context = Context> { 'fork'(ctx: C, config: C['config']): void; 'ready'(): Awaitable<void>; 'dispose'(): Awaitable<void>; 'internal/fork'(fork: ForkScope<C>): void; 'internal/runtime'(runtime: MainScope<C>): void; 'internal/status'(scope: EffectScope<C>, oldValue: ScopeStatus): void; 'internal/info'(this: C, format: any, ...param: any[]): void; 'internal/error'(this: C, format: any, ...param: any[]): void; 'internal/warning'(this: C, format: any, ...param: any[]): void; 'internal/before-service'(this: C, name: string, value: any): void; 'internal/service'(this: C, name: string, value: any): void; 'internal/before-update'(fork: ForkScope<C>, config: any): void; 'internal/update'(fork: ForkScope<C>, oldConfig: any): void; 'internal/inject'(this: C, name: string): boolean | undefined; 'internal/listener'(this: C, name: string, listener: any, prepend: boolean): void; 'internal/event'(type: 'emit' | 'parallel' | 'serial' | 'bail', name: string, args: any[], thisArg: any): void; } export { Lifecycle, ReflectService, Registry }; export namespace Context { type Parameterized<C, T = any> = C & { config: T; }; /** @deprecated use `string[]` instead */ interface MixinOptions { methods?: string[]; accessors?: string[]; prototype?: {}; } interface Item<C extends Context> { value?: any; source: C; } type Internal = Internal.Service | Internal.Accessor | Internal.Alias; namespace Internal { interface Service { type: 'service'; builtin?: boolean; prototype?: {}; } interface Accessor { type: 'accessor'; get: (this: Context, receiver: any) => any; set?: (this: Context, value: any, receiver: any) => boolean; } interface Alias { type: 'alias'; name: string; } } } export interface Intercept<C extends Context = Context> { } export interface Context { [Context.store]: Dict<Context.Item<this>, symbol>; [Context.isolate]: Dict<symbol>; [Context.intercept]: Intercept<this>; [Context.internal]: Dict<Context.Internal>; root: this; lifecycle: Lifecycle; reflect: ReflectService; registry: Registry<this>; config: any; } export class Context { static readonly store: unique symbol; static readonly events: unique symbol; static readonly static: unique symbol; static readonly filter: unique symbol; static readonly expose: unique symbol; static readonly isolate: unique symbol; static readonly internal: unique symbol; static readonly intercept: unique symbol; static readonly origin = "ctx"; static readonly current = "ctx"; static is<C extends Context>(value: any): value is C; /** @deprecated use `Service.traceable` instead */ static associate<T extends {}>(object: T, name: string): T; constructor(config?: any); get name(): string; get events(): Lifecycle; /** @deprecated */ get state(): EffectScope<this>; extend(meta?: {}): this; isolate(name: string, label?: symbol): this; intercept<K extends keyof Intercept>(name: K, config: Intercept[K]): this; }