ActivationContext.ts
134 lines
| 3.3 KiB
| video/mp2t
|
TypeScriptLexer
|
|
r33 | import { TraceSource } from "../log/TraceSource"; | ||
| import { argumentNotNull, argumentNotEmptyString, isPrimitive, each, isNull } from "../safe"; | ||||
|
|
r34 | import { Descriptor, ServiceMap, isDescriptor } from "./interfaces"; | ||
| import { Container } from "./Container"; | ||||
|
|
r33 | |||
|
|
r39 | const trace = TraceSource.get("@implab/core/di/ActivationContext"); | ||
|
|
r33 | |||
|
|
r39 | export interface ActivationContextInfo { | ||
| name: string; | ||||
|
|
r34 | |||
|
|
r39 | service: Descriptor; | ||
|
|
r34 | |||
|
|
r39 | scope: ServiceMap; | ||
|
|
r34 | } | ||
|
|
r39 | export class ActivationContext { | ||
| _cache: object; | ||||
|
|
r33 | |||
|
|
r39 | _services: ServiceMap; | ||
|
|
r33 | |||
|
|
r39 | _stack: ActivationContextInfo[]; | ||
|
|
r33 | |||
|
|
r39 | _visited: object; | ||
|
|
r33 | |||
|
|
r39 | container: Container; | ||
|
|
r33 | |||
| constructor(container: Container, services: ServiceMap, cache?: object, visited?) { | ||||
| argumentNotNull(container, "container"); | ||||
| argumentNotNull(services, "services"); | ||||
| this._visited = visited || {}; | ||||
| this._stack = []; | ||||
| this._cache = cache || {}; | ||||
| this._services = services; | ||||
| this.container = container; | ||||
| } | ||||
| getService(name, def?): any { | ||||
|
|
r39 | const d = this._services[name]; | ||
|
|
r33 | |||
| if (!d) | ||||
| if (arguments.length > 1) | ||||
| return def; | ||||
| else | ||||
|
|
r39 | throw new Error(`Service ${name} not found`); | ||
|
|
r33 | |||
|
|
r40 | return isDescriptor(d) ? d.activate(this, name) : d; | ||
|
|
r33 | } | ||
| /** | ||||
| * registers services local to the the activation context | ||||
|
|
r39 | * | ||
|
|
r33 | * @name{string} the name of the service | ||
| * @service{string} the service descriptor to register | ||||
| */ | ||||
| register(name: string, service: Descriptor) { | ||||
| argumentNotEmptyString(name, "name"); | ||||
| this._services[name] = service; | ||||
| } | ||||
| clone() { | ||||
| return new ActivationContext( | ||||
| this.container, | ||||
| Object.create(this._services), | ||||
| this._cache, | ||||
| this._visited | ||||
| ); | ||||
| } | ||||
|
|
r39 | has(id: string) { | ||
|
|
r33 | return id in this._cache; | ||
| } | ||||
|
|
r39 | get(id: string) { | ||
|
|
r33 | return this._cache[id]; | ||
| } | ||||
|
|
r39 | store(id: string, value) { | ||
|
|
r33 | return (this._cache[id] = value); | ||
| } | ||||
|
|
r40 | parse(data, name: string) { | ||
|
|
r33 | if (isPrimitive(data)) | ||
| return data; | ||||
| if (isDescriptor(data)) { | ||||
| return data.activate(this, name); | ||||
| } else if (data instanceof Array) { | ||||
|
|
r39 | this.enter(name); | ||
| const v = data.map( (x, i) => this.parse(x, `[${i}]`)); | ||||
| this.leave(); | ||||
|
|
r33 | return v; | ||
| } else { | ||||
|
|
r39 | this.enter(name); | ||
| const result = {}; | ||||
| for (const p in data) | ||||
| result[p] = this.parse(data[p], "." + p); | ||||
| this.leave(); | ||||
|
|
r33 | return result; | ||
| } | ||||
| } | ||||
|
|
r39 | visit(id: string) { | ||
| const count = this._visited[id] || 0; | ||||
|
|
r33 | this._visited[id] = count + 1; | ||
| return count; | ||||
| } | ||||
| getStack() { | ||||
| return this._stack.slice().reverse(); | ||||
| } | ||||
|
|
r39 | enter(name: string, d?: Descriptor, localize?: boolean) { | ||
|
|
r33 | if (trace.isLogEnabled()) | ||
| trace.log("enter " + name + " " + (d || "") + | ||||
| (localize ? " localize" : "")); | ||||
| this._stack.push({ | ||||
|
|
r39 | name, | ||
|
|
r33 | service: d, | ||
| scope: this._services | ||||
| }); | ||||
| if (localize) | ||||
| this._services = Object.create(this._services); | ||||
| } | ||||
| leave() { | ||||
|
|
r39 | const ctx = this._stack.pop(); | ||
|
|
r33 | this._services = ctx.scope; | ||
| if (trace.isLogEnabled()) | ||||
| trace.log("leave " + ctx.name + " " + (ctx.service || "")); | ||||
| } | ||||
|
|
r39 | } | ||
