ActivationContext.ts
138 lines
| 3.4 KiB
| video/mp2t
|
TypeScriptLexer
|
|
r49 | import { TraceSource } from "../log/TraceSource"; | ||
|
|
r120 | import { argumentNotNull, argumentNotEmptyString } from "../safe"; | ||
| import { Descriptor, ContainerProvided, ContainerServiceMap, ContainerKeys, ContainerResolve } from "./interfaces"; | ||||
|
|
r49 | import { Container } from "./Container"; | ||
|
|
r114 | import { MapOf } from "../interfaces"; | ||
|
|
r49 | |||
| const trace = TraceSource.get("@implab/core/di/ActivationContext"); | ||||
|
|
r120 | export interface ActivationContextInfo<S extends object> { | ||
|
|
r49 | name: string; | ||
| service: string; | ||||
|
|
r120 | scope: ContainerServiceMap<S>; | ||
|
|
r49 | } | ||
|
|
r120 | export class ActivationContext<S extends object> { | ||
|
|
r114 | _cache: MapOf<any>; | ||
|
|
r49 | |||
|
|
r120 | _services: ContainerServiceMap<S>; | ||
|
|
r49 | |||
|
|
r114 | _stack: ActivationContextInfo<S>[]; | ||
|
|
r49 | |||
|
|
r114 | _visited: MapOf<any>; | ||
|
|
r49 | |||
| _name: string; | ||||
|
|
r114 | _localized: boolean = false; | ||
|
|
r49 | |||
|
|
r114 | container: Container<S>; | ||
|
|
r49 | |||
|
|
r120 | constructor(container: Container<S>, services: ContainerServiceMap<S>, name?: string, cache?: object, visited?: MapOf<any>) { | ||
|
|
r49 | argumentNotNull(container, "container"); | ||
| argumentNotNull(services, "services"); | ||||
|
|
r114 | this._name = name || "<unnamed>"; | ||
|
|
r49 | this._visited = visited || {}; | ||
| this._stack = []; | ||||
| this._cache = cache || {}; | ||||
| this._services = services; | ||||
| this.container = container; | ||||
| } | ||||
| getName() { | ||||
| return this._name; | ||||
| } | ||||
|
|
r120 | resolve<K extends ContainerKeys<S>>(name: K, def?: ContainerResolve<S, K>) { | ||
|
|
r49 | const d = this._services[name]; | ||
|
|
r114 | if (d !== undefined) { | ||
|
|
r120 | return this.activate(d, name.toString()); | ||
|
|
r114 | } else { | ||
| if (def !== undefined && def !== null) | ||||
|
|
r49 | return def; | ||
| else | ||||
| throw new Error(`Service ${name} not found`); | ||||
|
|
r114 | } | ||
|
|
r49 | } | ||
| /** | ||||
| * registers services local to the the activation context | ||||
| * | ||||
| * @name{string} the name of the service | ||||
| * @service{string} the service descriptor to register | ||||
| */ | ||||
|
|
r115 | register<K extends keyof S>(name: K, service: Descriptor<S, S[K]>) { | ||
|
|
r49 | argumentNotEmptyString(name, "name"); | ||
|
|
r120 | this._services[name] = service as any; | ||
|
|
r49 | } | ||
| clone() { | ||||
|
|
r115 | return new ActivationContext<S>( | ||
|
|
r49 | this.container, | ||
| this._services, | ||||
| this._name, | ||||
| this._cache, | ||||
| this._visited | ||||
| ); | ||||
| } | ||||
| has(id: string) { | ||||
| return id in this._cache; | ||||
| } | ||||
|
|
r114 | get<T>(id: string) { | ||
|
|
r49 | return this._cache[id]; | ||
| } | ||||
|
|
r114 | store(id: string, value: any) { | ||
|
|
r49 | return (this._cache[id] = value); | ||
| } | ||||
|
|
r115 | activate<T>(d: Descriptor<S, T>, name: string) { | ||
|
|
r49 | if (trace.isLogEnabled()) | ||
| trace.log(`enter ${name} ${d}`); | ||||
| this.enter(name, d.toString()); | ||||
|
|
r115 | const v = d.activate(this); | ||
|
|
r49 | this.leave(); | ||
| if (trace.isLogEnabled()) | ||||
| trace.log(`leave ${name}`); | ||||
| return v; | ||||
| } | ||||
| visit(id: string) { | ||||
| const count = this._visited[id] || 0; | ||||
| this._visited[id] = count + 1; | ||||
| return count; | ||||
| } | ||||
| getStack() { | ||||
| return this._stack.slice().reverse(); | ||||
| } | ||||
| private enter(name: string, service: string) { | ||||
| this._stack.push({ | ||||
| name, | ||||
| service, | ||||
| scope: this._services | ||||
| }); | ||||
| this._name = name; | ||||
| this._services = Object.create(this._services); | ||||
| } | ||||
| private leave() { | ||||
| const ctx = this._stack.pop(); | ||||
|
|
r114 | if (ctx) { | ||
| this._services = ctx.scope; | ||||
| this._name = ctx.name; | ||||
| } else { | ||||
| trace.error("Trying to leave the last activation scope"); | ||||
| } | ||||
|
|
r49 | } | ||
| } | ||||
