##// END OF EJS Templates
ActivationContext removed 'clone' method, rewritten 'enter' method
cin -
r3:8a4027b4c19f default
parent child
Show More
@@ -1,144 +1,138
1 import { Descriptor, ILifetime, RegistrationMap, LifetimeContainer, ConfigurableKeys } from "./interfaces";
1 import { Descriptor, ILifetime, RegistrationMap, LifetimeContainer, ConfigurableKeys } from "./interfaces";
2 import { argumentNotNull } from "./traits";
2 import { argumentNotNull } from "./traits";
3
3
4 export interface ActivationContextInfo {
4 export interface ActivationContextInfo {
5 name: string;
5 name: string;
6
6
7 service: string;
7 service: string;
8
8
9 }
9 }
10
10
11 let nextId = 1;
11 let nextId = 1;
12
12
13 /** This class is created once per `Container.resolve` method call and used to
13 /** This class is created once per `Container.resolve` method call and used to
14 * cache dependencies and to track created instances. The activation context
14 * cache dependencies and to track created instances. The activation context
15 * tracks services with `context` activation type.
15 * tracks services with `context` activation type.
16 */
16 */
17 export class ActivationContext<S extends object> {
17 export class ActivationContext<S extends object> {
18 private _cache: { [K: string]: unknown };
18 private readonly _cache: Record<string, unknown>;
19
19
20 private _services: Partial<RegistrationMap<S>>;
20 private readonly _services: Partial<RegistrationMap<S>>;
21
21
22 private _name: string;
22 private readonly _name: string;
23
23
24 private _service: Descriptor<S, unknown>;
24 private readonly _service: Descriptor<S, unknown>;
25
25
26 private readonly _containerLifetimeManager: LifetimeContainer;
26 private readonly _containerLifetimeManager: LifetimeContainer;
27
27
28 private _parent: ActivationContext<S> | undefined;
28 private readonly _parent: ActivationContext<S> | undefined;
29
29
30 /** Creates a new activation context with the specified parameters.
30 /** Creates a new activation context with the specified parameters.
31 * @param containerLifetimeManager the container which starts the activation process
31 * @param containerLifetimeManager the container which starts the activation process
32 * @param services the initial service registrations
32 * @param services the initial service registrations
33 * @param name the name of the service being activated, this parameter is
33 * @param name the name of the service being activated, this parameter is
34 * used for the debug purpose.
34 * used for the debug purpose.
35 * @param service the service to activate, this parameter is used for the
35 * @param service the service to activate, this parameter is used for the
36 * debug purpose.
36 * debug purpose.
37 */
37 */
38 constructor(containerLifetimeManager: LifetimeContainer, services: Partial<RegistrationMap<S>>, name: string, service: Descriptor<S, unknown>) {
38 constructor(containerLifetimeManager: LifetimeContainer, services: Partial<RegistrationMap<S>>, name: string, service: Descriptor<S, unknown>, cache = {}) {
39 this._name = name;
39 this._name = name;
40 this._service = service;
40 this._service = service;
41 this._cache = {};
41 this._cache = cache;
42 this._services = services;
42 this._services = services;
43 this._containerLifetimeManager = containerLifetimeManager;
43 this._containerLifetimeManager = containerLifetimeManager;
44 }
44 }
45
45
46 /** the name of the current resolving dependency */
46 /** the name of the current resolving dependency */
47 getName() {
47 getName() {
48 return this._name;
48 return this._name;
49 }
49 }
50
50
51 createContainerLifetime<T>() {
51 createContainerLifetime<T>() {
52 return this._containerLifetimeManager.createLifetime<T>();
52 return this._containerLifetimeManager.createLifetime<T>();
53 }
53 }
54
54
55 /** Resolves the specified dependency in the current context
55 /** Resolves the specified dependency in the current context
56 * @param name The name of the dependency being resolved
56 * @param name The name of the dependency being resolved
57 */
57 */
58 resolve<K extends keyof S>(name: K): NonNullable<S[K]>;
58 resolve<K extends keyof S>(name: K): NonNullable<S[K]>;
59 /** Resolves the specified dependency with the specified default value if
59 /** Resolves the specified dependency with the specified default value if
60 * the dependency is missing.
60 * the dependency is missing.
61 *
61 *
62 * @param name The name of the dependency being resolved
62 * @param name The name of the dependency being resolved
63 * @param def A default value to return in case of the specified dependency
63 * @param def A default value to return in case of the specified dependency
64 * is missing.
64 * is missing.
65 */
65 */
66 resolve<K extends keyof S, T>(name: K, def: T): NonNullable<S[K]> | T;
66 resolve<K extends keyof S, T>(name: K, def: T): NonNullable<S[K]> | T;
67 resolve<K extends keyof S, T>(name: K, def?: T): S[K] | T | undefined {
67 resolve<K extends keyof S, T>(name: K, def?: T): S[K] | T | undefined {
68 const d = this._services[name];
68 const d = this._services[name];
69
69
70 if (d !== undefined) {
70 if (d !== undefined) {
71 return this.activate(d, name.toString());
71 return this.activate(d, name.toString());
72 } else {
72 } else {
73 if (arguments.length > 1)
73 if (arguments.length > 1)
74 return def;
74 return def;
75 else
75 else
76 throw new Error(`Service ${String(name)} not found`);
76 throw new Error(`Service ${String(name)} not found`);
77 }
77 }
78 }
78 }
79
79
80 /**
80 /**
81 * registers services local to the the activation context
81 * registers services local to the the activation context
82 *
82 *
83 * @name{string} the name of the service
83 * @name{string} the name of the service
84 * @service{string} the service descriptor to register
84 * @service{string} the service descriptor to register
85 */
85 */
86 register<K extends ConfigurableKeys<S>>(name: K, service: RegistrationMap<S>[K]) {
86 register<K extends ConfigurableKeys<S>>(name: K, service: RegistrationMap<S>[K]) {
87 argumentNotNull(name, "name");
87 argumentNotNull(name, "name");
88
88
89 this._services[name] = service;
89 this._services[name] = service;
90 }
90 }
91
91
92 createLifetime<T>(): ILifetime<T> {
92 createLifetime<T>(): ILifetime<T> {
93 const id = nextId++;
93 const id = nextId++;
94 return {
94 return {
95 initialize() {},
95 initialize() {},
96 has: () => id in this._cache,
96 has: () => id in this._cache,
97 get: () => this._cache[id] as T,
97 get: () => this._cache[id] as T,
98 store: item => {
98 store: item => {
99 this._cache[id] = item;
99 this._cache[id] = item;
100 }
100 }
101 };
101 };
102 }
102 }
103
103
104 activate<T>(d: Descriptor<S, T>, name: string) {
104 activate<T>(d: Descriptor<S, T>, name: string) {
105 // TODO: add logging
105 // TODO: add logging
106 // if (trace.isLogEnabled())
106 // if (trace.isLogEnabled())
107 // trace.log("enter {0} {1}", name, d);
107 // trace.log("enter {0} {1}", name, d);
108
108
109 const ctx = this.enter(d, name);
109 const ctx = this.enter(d, name);
110 const v = d.activate(ctx);
110 const v = d.activate(ctx);
111
111
112 // if (trace.isLogEnabled())
112 // if (trace.isLogEnabled())
113 // trace.log(`leave ${name}`);
113 // trace.log(`leave ${name}`);
114
114
115 return v;
115 return v;
116 }
116 }
117
117
118 getStack(): ActivationContextInfo[] {
118 getStack(): ActivationContextInfo[] {
119 const stack = [{
119 const stack = [{
120 name: this._name,
120 name: this._name,
121 service: this._service.toString()
121 service: this._service.toString()
122 }];
122 }];
123
123
124 return this._parent ?
124 return this._parent ?
125 stack.concat(this._parent.getStack()) :
125 stack.concat(this._parent.getStack()) :
126 stack;
126 stack;
127 }
127 }
128
128
129 private enter(service: Descriptor<S, unknown>, name: string): this {
129 private enter(service: Descriptor<S, unknown>, name: string) {
130 const clone = Object.create(this) as this;
130 return new ActivationContext(
131 clone._name = name;
131 this._containerLifetimeManager,
132 clone._services = Object.create(this._services) as typeof this._services;
132 Object.create(this._services) as typeof this._services,
133 clone._parent = this;
133 name,
134 clone._service = service;
134 service,
135 return clone;
135 this._cache
136 }
136 );
137
138 /** Creates a clone for the current context, used to protect it from modifications */
139 clone(): this {
140 const clone = Object.create(this) as this;
141 clone._services = Object.create(this._services) as typeof this._services;
142 return clone;
143 }
137 }
144 }
138 }
General Comments 0
You need to be logged in to leave comments. Login now