vendor(cordis): document the full plugin-author surface (@param/@returns everywhere)

Comment-only enrichment across cordis/src/*.ts — Context, EventsService (+ the
ctx merges), Fiber, RegistryService, ReflectService, Service, logger — so the
website API generator can render a complete reference and hard-error on any
future undocumented member (vendor sync included). Logged as local
modification 6 in vendor/README.md; retire it when upstreamed to the fork.
INHERITED_SERVICES/EVENTS source pointers refreshed for the shifted lines;
cordis catalogs regenerated.
This commit is contained in:
lintianle
2026-07-16 18:12:36 +08:00
parent 6ce9f16030
commit 83cb48441e
11 changed files with 587 additions and 55 deletions

View File

@@ -5,14 +5,66 @@ import { Fiber, FiberState } from './fiber.ts'
declare module './context.ts' {
interface Context {
/**
* Read a service from the store without the inject requirement.
*
* @param name — the service name.
* @param strict — when `true` (default), only return implementations
* whose providing fiber is currently active.
* @returns the service value, or `undefined` when not (yet) provided.
*/
get<K extends string & keyof this>(name: K, strict?: boolean): undefined | this[K]
/** Same as above for service names outside the typed `Context` surface. */
get(name: string, strict?: boolean): any
/**
* Overwrite a provided service's value.
*
* Only the fiber that provided the service may set it; setting an
* unprovided name throws.
*
* @param name — the service name.
* @param value — the new service value.
*/
set<K extends string & keyof this>(name: K, value: undefined | this[K]): void
/** Same as above for service names outside the typed `Context` surface. */
set(name: string, value: any): void
/**
* Register a service implementation owned by the current fiber.
*
* The service becomes visible to dependents in the same isolation scope
* once the fiber is active; it is unregistered (waking dependents) when
* the returned disposer runs or the fiber unloads. Throws if the name is
* already provided in this scope or declared as an accessor.
*
* @param name — the service name.
* @param value — the service value.
* @returns a disposer that unregisters the service.
*/
provide<K extends string & keyof this>(name: K, value: undefined | this[K]): () => void
/** Same as above for service names outside the typed `Context` surface. */
provide(name: string, value?: any): () => void
/**
* Define a computed context property backed by get/set hooks.
*
* The accessor is removed when the current fiber unloads. Throws if the
* name is already declared.
*
* @param name — the context property name.
* @param options — the `get` hook and optional `set` hook.
*/
accessor(name: string, options: Omit<Property.Accessor, 'type'>): void
/**
* Expose selected members of a service directly on `ctx`.
*
* Each mixed-in key becomes an accessor that forwards to the service
* (binding methods to it), so e.g. `ctx.on` forwards to `ctx.events.on`.
* Mixins are removed when the current fiber unloads.
*
* @param name — the context property holding the source service.
* @param mixins — keys to forward, or a source-key → ctx-key map.
*/
mixin<K extends string & keyof this>(name: K, mixins: (keyof this & keyof this[K])[] | Dict<string>): void
/** Same as above with a source object instead of a context property name. */
mixin<T extends {}>(source: T, mixins: (keyof this & keyof T)[] | Dict<string>): void
}
}
@@ -44,22 +96,30 @@ export type Property = Property.Service | Property.Accessor
export namespace Property {
/** Service property backed by a provided implementation. */
export interface Service {
/** Discriminator. */
type: 'service'
}
/** Computed context property backed by custom get/set hooks. */
export interface Accessor {
/** Discriminator. */
type: 'accessor'
/** Compute the property value; `error` carries the caller stack for diagnostics. */
get: (this: Context, receiver: any, error: Error) => any
/** Optional setter; return `false` to reject the write. */
set?: (this: Context, value: any, receiver: any, error: Error) => boolean
}
}
/** Concrete service implementation record stored in the root reflect service. */
export interface Impl {
/** The service name. */
name: string
/** The fiber that provided the service (owns its lifetime). */
fiber: Fiber
/** The current service value. */
value?: any
/** Optional availability predicate consulted before dependents may load. */
check?: () => boolean
}
@@ -70,6 +130,7 @@ export interface Impl {
* the mixins that expose core service methods directly on `ctx`.
*/
export class ReflectService {
/** Proxy traps implementing service resolution for every context object. */
static handler: ProxyHandler<Context> = {
get: (target, prop, ctx: Context) => {
if (isSpecialProperty(prop)) {
@@ -143,7 +204,9 @@ export class ReflectService {
},
}
/** Service implementations, keyed by isolation label. */
public store: Dict<Impl, symbol> = Object.create(null)
/** Declared context properties (services and accessors), by name. */
public props: Dict<Property> = Object.create(null)
constructor(public ctx: Context) {
@@ -158,6 +221,14 @@ export class ReflectService {
this.mixin('events', ['on', 'once', 'parallel', 'emit', 'serial', 'bail', 'waterfall'])
}
/**
* Read a service from the store without the inject requirement.
*
* @param name — the service name.
* @param strict — when `true`, only return implementations whose providing
* fiber is currently active.
* @returns the service value, or `undefined` when not (yet) provided.
*/
get(name: string, strict = true) {
return getTraceable(this.ctx, this._getImpl(name, strict)?.value)
}
@@ -170,6 +241,15 @@ export class ReflectService {
return impl
}
/**
* Overwrite a provided service's value.
*
* @param name — the service name.
* @param value — the new service value.
* @param error — carrier for the caller stack in diagnostics.
* @returns `true` on success.
* @throws when `name` was never provided, or was provided by another fiber.
*/
set(name: string, value: any, error?: Error) {
const key = this.ctx[symbols.isolate][name]
const impl = this.store[key]
@@ -183,6 +263,16 @@ export class ReflectService {
return true
}
/**
* Register a service implementation owned by the current fiber.
*
* See the `ctx.provide()` overload above for the full contract.
*
* @param name — the service name.
* @param value — the service value.
* @param check — optional availability predicate for dependents.
* @returns a disposer that unregisters the service.
*/
provide(name: string, value?: any, check?: () => boolean) {
return this.ctx.fiber.effect(() => {
if (!this.props[name]) {
@@ -213,6 +303,13 @@ export class ReflectService {
}, `ctx.provide(${JSON.stringify(name)})`)
}
/**
* Re-evaluate every fiber that requires one of the given services.
*
* @param names — the service names that changed.
* @param filter — restricts notification to matching isolation scopes.
* @returns the fibers whose dependency state was refreshed.
*/
notify(names: string[], filter = (ctx: Context, name: string) => ctx[symbols.isolate][name] === this.ctx[symbols.isolate][name]) {
const fibers: Fiber[] = []
for (const runtime of this.ctx.registry.values()) {
@@ -232,6 +329,13 @@ export class ReflectService {
return fibers
}
/**
* Define a computed context property backed by get/set hooks.
*
* @param name — the context property name.
* @param options — the `get` hook and optional `set` hook.
* @returns a disposer that removes the accessor.
*/
accessor(name: string, options: Omit<Property.Accessor, 'type'>) {
return this.ctx.fiber.effect(() => {
if (name in this.props) {
@@ -242,6 +346,15 @@ export class ReflectService {
}, `ctx.accessor(${JSON.stringify(name)})`)
}
/**
* Expose selected members of a service directly on `ctx`.
*
* See the `ctx.mixin()` overload above for the full contract.
*
* @param source — a context property name or a source object.
* @param mixins — keys to forward, or a source-key → ctx-key map.
* @returns a disposer that removes all created accessors.
*/
mixin(source: any, mixins: string[] | Dict<string>) {
const self = this
return this.ctx.fiber.effect(function* () {
@@ -270,10 +383,22 @@ export class ReflectService {
}, `ctx.mixin(${JSON.stringify(source)})`)
}
/**
* Attach this context's tracing wrapper to a value.
*
* @param value — the value to wrap.
* @returns the traceable wrapper (or the value itself when not applicable).
*/
trace<T>(value: T) {
return getTraceable(this.ctx, value)
}
/**
* Wrap a callback so calls trace `this` and arguments to this context.
*
* @param callback — the function to wrap.
* @returns a proxy delegating to `callback` with traced values.
*/
bind<T extends Function>(callback: T) {
return new Proxy(callback, {
apply: (target, thisArg, args) => {