@joist/di 4.0.0-next.5 → 4.0.0-next.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -38
- package/package.json +4 -7
- package/src/lib/context/injector.ts +5 -0
- package/src/lib/context/protocol.ts +78 -0
- package/src/lib/dom-injector.test.ts +53 -17
- package/src/lib/dom-injector.ts +48 -5
- package/src/lib/inject.test.ts +36 -22
- package/src/lib/inject.ts +6 -7
- package/src/lib/injectable-el.test.ts +29 -29
- package/src/lib/injectable-el.ts +53 -47
- package/src/lib/injectable.test.ts +47 -9
- package/src/lib/injectable.ts +45 -16
- package/src/lib/injector.test.ts +78 -64
- package/src/lib/injector.ts +54 -58
- package/src/lib/lifecycle.test.ts +70 -35
- package/src/lib/lifecycle.ts +33 -10
- package/src/lib/metadata.ts +17 -0
- package/src/lib/provider.ts +19 -11
- package/src/lib.ts +11 -6
- package/target/lib/context/injector.d.ts +3 -0
- package/target/lib/context/injector.js +3 -0
- package/target/lib/context/injector.js.map +1 -0
- package/target/lib/context/protocol.d.ts +18 -0
- package/target/lib/context/protocol.js +15 -0
- package/target/lib/context/protocol.js.map +1 -0
- package/target/lib/dom-injector.d.ts +5 -3
- package/target/lib/dom-injector.js +30 -5
- package/target/lib/dom-injector.js.map +1 -1
- package/target/lib/dom-injector.test.js +41 -17
- package/target/lib/dom-injector.test.js.map +1 -1
- package/target/lib/inject.d.ts +1 -1
- package/target/lib/inject.js +2 -3
- package/target/lib/inject.js.map +1 -1
- package/target/lib/inject.test.js +33 -22
- package/target/lib/inject.test.js.map +1 -1
- package/target/lib/injectable-el.d.ts +2 -334
- package/target/lib/injectable-el.js +39 -31
- package/target/lib/injectable-el.js.map +1 -1
- package/target/lib/injectable-el.test.js +29 -29
- package/target/lib/injectable-el.test.js.map +1 -1
- package/target/lib/injectable.d.ts +5 -7
- package/target/lib/injectable.js +26 -12
- package/target/lib/injectable.js.map +1 -1
- package/target/lib/injectable.test.js +82 -8
- package/target/lib/injectable.test.js.map +1 -1
- package/target/lib/injector.d.ts +10 -5
- package/target/lib/injector.js +26 -42
- package/target/lib/injector.js.map +1 -1
- package/target/lib/injector.test.js +75 -60
- package/target/lib/injector.test.js.map +1 -1
- package/target/lib/lifecycle.d.ts +5 -13
- package/target/lib/lifecycle.js +22 -6
- package/target/lib/lifecycle.js.map +1 -1
- package/target/lib/lifecycle.test.js +101 -38
- package/target/lib/lifecycle.test.js.map +1 -1
- package/target/lib/metadata.d.ts +8 -0
- package/target/lib/metadata.js +5 -0
- package/target/lib/metadata.js.map +1 -0
- package/target/lib/provider.d.ts +11 -8
- package/target/lib/provider.js +1 -0
- package/target/lib/provider.js.map +1 -1
- package/target/lib.d.ts +6 -6
- package/target/lib.js +6 -6
- package/target/lib.js.map +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { assert } from
|
|
1
|
+
import { assert } from "chai";
|
|
2
2
|
|
|
3
|
-
import { inject } from
|
|
4
|
-
import { injectable } from
|
|
3
|
+
import { inject } from "./inject.js";
|
|
4
|
+
import { injectable } from "./injectable.js";
|
|
5
5
|
|
|
6
|
-
it(
|
|
6
|
+
it("should allow services to be injected into custom element", () => {
|
|
7
7
|
class Foo {}
|
|
8
8
|
|
|
9
9
|
@injectable()
|
|
@@ -11,14 +11,14 @@ it('should allow services to be injected into custom element', () => {
|
|
|
11
11
|
foo = inject(Foo);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
customElements.define(
|
|
14
|
+
customElements.define("injectable-1", MyElement);
|
|
15
15
|
|
|
16
16
|
const el = new MyElement();
|
|
17
17
|
|
|
18
18
|
assert.instanceOf(el.foo(), Foo);
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
it(
|
|
21
|
+
it("should allow services to be injected into custom elements that has been extended", () => {
|
|
22
22
|
class Foo {}
|
|
23
23
|
|
|
24
24
|
class MyBaseElement extends HTMLElement {}
|
|
@@ -28,14 +28,14 @@ it('should allow services to be injected into custom elements that has been exte
|
|
|
28
28
|
foo = inject(Foo);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
customElements.define(
|
|
31
|
+
customElements.define("injectable-2", MyElement);
|
|
32
32
|
|
|
33
33
|
const el = new MyElement();
|
|
34
34
|
|
|
35
35
|
assert.instanceOf(el.foo(), Foo);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
it(
|
|
38
|
+
it("should handle parent HTML Injectors", async () => {
|
|
39
39
|
@injectable()
|
|
40
40
|
class A {}
|
|
41
41
|
|
|
@@ -48,9 +48,9 @@ it('should handle parent HTML Injectors', async () => {
|
|
|
48
48
|
|
|
49
49
|
@injectable({
|
|
50
50
|
providers: [
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
]
|
|
51
|
+
[B, { use: B }],
|
|
52
|
+
[A, { use: AltA }],
|
|
53
|
+
],
|
|
54
54
|
})
|
|
55
55
|
class Parent extends HTMLElement {}
|
|
56
56
|
|
|
@@ -59,10 +59,10 @@ it('should handle parent HTML Injectors', async () => {
|
|
|
59
59
|
b = inject(B);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
customElements.define(
|
|
63
|
-
customElements.define(
|
|
62
|
+
customElements.define("injectable-parent-1", Parent);
|
|
63
|
+
customElements.define("injectable-child-1", Child);
|
|
64
64
|
|
|
65
|
-
const el = document.createElement(
|
|
65
|
+
const el = document.createElement("div");
|
|
66
66
|
el.innerHTML = /*html*/ `
|
|
67
67
|
<injectable-parent-1>
|
|
68
68
|
<injectable-child-1></injectable-child-1>
|
|
@@ -71,24 +71,24 @@ it('should handle parent HTML Injectors', async () => {
|
|
|
71
71
|
|
|
72
72
|
document.body.append(el);
|
|
73
73
|
|
|
74
|
-
const child = el.querySelector<Child>(
|
|
74
|
+
const child = el.querySelector<Child>("injectable-child-1");
|
|
75
75
|
|
|
76
|
-
assert.instanceOf(child
|
|
76
|
+
assert.instanceOf(child?.b().a(), AltA);
|
|
77
77
|
|
|
78
78
|
el.remove();
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
it(
|
|
81
|
+
it("should handle changing contexts", async () => {
|
|
82
82
|
class A {}
|
|
83
83
|
class AltA implements A {}
|
|
84
84
|
|
|
85
85
|
@injectable({
|
|
86
|
-
providers: [
|
|
86
|
+
providers: [[A, { use: A }]],
|
|
87
87
|
})
|
|
88
88
|
class Ctx1 extends HTMLElement {}
|
|
89
89
|
|
|
90
90
|
@injectable({
|
|
91
|
-
providers: [
|
|
91
|
+
providers: [[A, { use: AltA }]],
|
|
92
92
|
})
|
|
93
93
|
class Ctx2 extends HTMLElement {}
|
|
94
94
|
|
|
@@ -97,11 +97,11 @@ it('should handle changing contexts', async () => {
|
|
|
97
97
|
a = inject(A);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
customElements.define(
|
|
101
|
-
customElements.define(
|
|
102
|
-
customElements.define(
|
|
100
|
+
customElements.define("ctx-1", Ctx1);
|
|
101
|
+
customElements.define("ctx-2", Ctx2);
|
|
102
|
+
customElements.define("ctx-child", Child);
|
|
103
103
|
|
|
104
|
-
const el = document.createElement(
|
|
104
|
+
const el = document.createElement("div");
|
|
105
105
|
el.innerHTML = /*html*/ `
|
|
106
106
|
<div>
|
|
107
107
|
<ctx-1>
|
|
@@ -114,17 +114,17 @@ it('should handle changing contexts', async () => {
|
|
|
114
114
|
|
|
115
115
|
document.body.append(el);
|
|
116
116
|
|
|
117
|
-
const ctx2 = el.querySelector(
|
|
117
|
+
const ctx2 = el.querySelector("ctx-2");
|
|
118
118
|
|
|
119
|
-
let child = el.querySelector<Child>(
|
|
119
|
+
let child = el.querySelector<Child>("ctx-child");
|
|
120
120
|
|
|
121
|
-
assert.instanceOf(child
|
|
121
|
+
assert.instanceOf(child?.a(), A);
|
|
122
122
|
|
|
123
123
|
child.remove();
|
|
124
124
|
|
|
125
|
-
ctx2
|
|
125
|
+
ctx2?.append(child);
|
|
126
126
|
|
|
127
|
-
child = el.querySelector<Child>(
|
|
127
|
+
child = el.querySelector<Child>("ctx-child");
|
|
128
128
|
|
|
129
|
-
assert.instanceOf(child
|
|
129
|
+
assert.instanceOf(child?.a(), AltA);
|
|
130
130
|
});
|
package/src/lib/injectable-el.ts
CHANGED
|
@@ -1,63 +1,69 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
(Symbol as any).metadata ??= Symbol("Symbol.metadata");
|
|
2
|
+
|
|
3
|
+
import { INJECTOR_CTX } from "./context/injector.js";
|
|
4
|
+
import { ContextRequestEvent } from "./context/protocol.js";
|
|
5
|
+
import { injectables } from "./injector.js";
|
|
6
|
+
import { callLifecycle } from "./lifecycle.js";
|
|
7
|
+
import type { InjectableMetadata } from "./metadata.js";
|
|
8
|
+
import type { ConstructableToken } from "./provider.js";
|
|
3
9
|
|
|
4
10
|
export function injectableEl<T extends ConstructableToken<HTMLElement>>(
|
|
5
11
|
Base: T,
|
|
6
|
-
|
|
7
|
-
) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
ctx: ClassDecoratorContext,
|
|
13
|
+
): T {
|
|
14
|
+
const metadata: InjectableMetadata = ctx.metadata;
|
|
15
|
+
|
|
16
|
+
const def = {
|
|
17
|
+
[Base.name]: class extends Base {
|
|
18
|
+
constructor(..._: any[]) {
|
|
19
|
+
super();
|
|
20
|
+
|
|
21
|
+
const injector = injectables.get(this);
|
|
22
|
+
|
|
23
|
+
if (injector) {
|
|
24
|
+
this.addEventListener("context-request", (e) => {
|
|
25
|
+
if (e.target !== this && e.context === INJECTOR_CTX) {
|
|
26
|
+
e.stopPropagation();
|
|
27
|
+
|
|
28
|
+
e.callback(injector);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
callLifecycle(this, injector, metadata?.onCreated);
|
|
23
33
|
}
|
|
24
|
-
}
|
|
25
|
-
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
connectedCallback() {
|
|
37
|
+
const injector = injectables.get(this);
|
|
38
|
+
|
|
39
|
+
if (injector) {
|
|
40
|
+
this.dispatchEvent(
|
|
41
|
+
new ContextRequestEvent(INJECTOR_CTX, (ctx) => {
|
|
42
|
+
injector.parent = ctx;
|
|
43
|
+
}),
|
|
44
|
+
);
|
|
26
45
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
this.dispatchEvent(new Event('finddiroot', { bubbles: true }));
|
|
46
|
+
callLifecycle(this, injector, metadata?.onInjected);
|
|
47
|
+
}
|
|
30
48
|
|
|
31
49
|
if (super.connectedCallback) {
|
|
32
50
|
super.connectedCallback();
|
|
33
51
|
}
|
|
34
52
|
}
|
|
35
|
-
}
|
|
36
53
|
|
|
37
|
-
|
|
38
|
-
|
|
54
|
+
disconnectedCallback() {
|
|
55
|
+
const injector = injectables.get(this);
|
|
56
|
+
|
|
57
|
+
if (injector) {
|
|
58
|
+
injector.parent = undefined;
|
|
59
|
+
}
|
|
39
60
|
|
|
40
|
-
|
|
41
|
-
|
|
61
|
+
if (super.disconnectedCallback) {
|
|
62
|
+
super.disconnectedCallback();
|
|
63
|
+
}
|
|
42
64
|
}
|
|
43
|
-
}
|
|
65
|
+
},
|
|
44
66
|
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function findInjectorRoot(e: Event): Injector | null {
|
|
48
|
-
const path = e.composedPath();
|
|
49
|
-
|
|
50
|
-
// find firt parent
|
|
51
|
-
// skips the first item which is the target
|
|
52
|
-
for (let i = 1; i < path.length; i++) {
|
|
53
|
-
const part = path[i];
|
|
54
|
-
|
|
55
|
-
const injector = injectables.get(part);
|
|
56
|
-
|
|
57
|
-
if (injector) {
|
|
58
|
-
return injector;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
67
|
|
|
62
|
-
return
|
|
68
|
+
return def[Base.name];
|
|
63
69
|
}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { assert } from
|
|
1
|
+
import { assert } from "chai";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { injectables } from
|
|
3
|
+
import { inject } from "./inject.js";
|
|
4
|
+
import { injectable } from "./injectable.js";
|
|
5
|
+
import { Injector, injectables } from "./injector.js";
|
|
6
|
+
import { StaticToken } from "./provider.js";
|
|
6
7
|
|
|
7
|
-
it(
|
|
8
|
+
it("should locally override a provider", () => {
|
|
8
9
|
class Foo {}
|
|
9
10
|
|
|
10
11
|
class Bar extends Foo {}
|
|
11
12
|
|
|
12
13
|
@injectable({
|
|
13
|
-
providers: [
|
|
14
|
+
providers: [[Foo, { use: Bar }]],
|
|
14
15
|
})
|
|
15
16
|
class MyService {
|
|
16
17
|
foo = inject(Foo);
|
|
@@ -21,11 +22,48 @@ it('should locally override a provider', () => {
|
|
|
21
22
|
assert.instanceOf(el.foo(), Bar);
|
|
22
23
|
});
|
|
23
24
|
|
|
24
|
-
it(
|
|
25
|
+
it("should define an injector for a service instance", () => {
|
|
25
26
|
@injectable()
|
|
26
|
-
class MyService {
|
|
27
|
+
class MyService {
|
|
28
|
+
constructor(public arg = "a") {}
|
|
29
|
+
}
|
|
27
30
|
|
|
28
|
-
const instance = new MyService();
|
|
31
|
+
const instance = new MyService("b");
|
|
29
32
|
|
|
30
33
|
assert.ok(injectables.has(instance));
|
|
34
|
+
assert.ok(instance.arg === "b");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should inject the current service injectable instance", () => {
|
|
38
|
+
@injectable()
|
|
39
|
+
class MyService {
|
|
40
|
+
injector = inject(Injector);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const app = new Injector();
|
|
44
|
+
const service = app.inject(MyService);
|
|
45
|
+
|
|
46
|
+
assert.equal(service.injector(), injectables.get(service));
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("should not override the name of the original class", () => {
|
|
50
|
+
@injectable()
|
|
51
|
+
class MyService {}
|
|
52
|
+
|
|
53
|
+
assert.equal(MyService.name, "MyService");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should provide itself for spefified tokens", () => {
|
|
57
|
+
const TOKEN = new StaticToken("MY_TOKEN");
|
|
58
|
+
|
|
59
|
+
@injectable({
|
|
60
|
+
provideSelfAs: [TOKEN],
|
|
61
|
+
})
|
|
62
|
+
class MyService {
|
|
63
|
+
value = inject(TOKEN);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const service = new MyService();
|
|
67
|
+
|
|
68
|
+
assert.equal(service.value(), service);
|
|
31
69
|
});
|
package/src/lib/injectable.ts
CHANGED
|
@@ -1,31 +1,60 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { injectableEl } from
|
|
1
|
+
(Symbol as any).metadata ??= Symbol("Symbol.metadata");
|
|
2
|
+
|
|
3
|
+
import { injectableEl } from "./injectable-el.js";
|
|
4
|
+
import { Injector, injectables } from "./injector.js";
|
|
5
|
+
import type {
|
|
6
|
+
ConstructableToken,
|
|
7
|
+
InjectionToken,
|
|
8
|
+
Provider,
|
|
9
|
+
} from "./provider.js";
|
|
4
10
|
|
|
5
11
|
export interface InjectableOpts {
|
|
6
|
-
|
|
12
|
+
name?: string;
|
|
13
|
+
providers?: Iterable<Provider<any>>;
|
|
14
|
+
provideSelfAs?: InjectionToken<any>[];
|
|
7
15
|
}
|
|
8
16
|
|
|
9
17
|
export function injectable(opts?: InjectableOpts) {
|
|
10
18
|
return function injectableDecorator<T extends ConstructableToken<any>>(
|
|
11
19
|
Base: T,
|
|
12
|
-
ctx: ClassDecoratorContext
|
|
13
|
-
) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
ctx: ClassDecoratorContext,
|
|
21
|
+
): T {
|
|
22
|
+
const def = {
|
|
23
|
+
[Base.name]: class extends Base {
|
|
24
|
+
constructor(...args: any[]) {
|
|
25
|
+
super(...args);
|
|
17
26
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
27
|
+
const injector = new Injector(opts);
|
|
28
|
+
|
|
29
|
+
injector.providers.set(Injector, {
|
|
30
|
+
factory: () => injector,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (opts?.provideSelfAs) {
|
|
34
|
+
for (const token of opts.provideSelfAs) {
|
|
35
|
+
injector.providers.set(token, {
|
|
36
|
+
factory: () => this,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
injectables.set(this, injector);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
};
|
|
21
45
|
|
|
22
46
|
// Only apply custom element bootstrap logic if the decorated class is an HTMLElement
|
|
23
|
-
if (
|
|
24
|
-
if (
|
|
25
|
-
|
|
47
|
+
if ("HTMLElement" in globalThis) {
|
|
48
|
+
if (
|
|
49
|
+
Object.prototype.isPrototypeOf.call(
|
|
50
|
+
HTMLElement.prototype,
|
|
51
|
+
Base.prototype,
|
|
52
|
+
)
|
|
53
|
+
) {
|
|
54
|
+
return injectableEl(def[Base.name], ctx);
|
|
26
55
|
}
|
|
27
56
|
}
|
|
28
57
|
|
|
29
|
-
return
|
|
58
|
+
return def[Base.name];
|
|
30
59
|
};
|
|
31
60
|
}
|
package/src/lib/injector.test.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { assert } from
|
|
1
|
+
import { assert } from "chai";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { inject } from "./inject.js";
|
|
4
|
+
import { injectable } from "./injectable.js";
|
|
5
|
+
import { Injector } from "./injector.js";
|
|
6
|
+
import { StaticToken } from "./provider.js";
|
|
7
7
|
|
|
8
|
-
it(
|
|
8
|
+
it("should create a new instance of a single provider", () => {
|
|
9
9
|
class A {}
|
|
10
10
|
|
|
11
11
|
const app = new Injector();
|
|
@@ -15,7 +15,7 @@ it('should create a new instance of a single provider', () => {
|
|
|
15
15
|
assert.equal(app.inject(A), app.inject(A));
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
it(
|
|
18
|
+
it("should inject providers in the correct order", () => {
|
|
19
19
|
class A {}
|
|
20
20
|
class B {}
|
|
21
21
|
|
|
@@ -32,7 +32,7 @@ it('should inject providers in the correct order', () => {
|
|
|
32
32
|
assert(instance.b() instanceof B);
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
it(
|
|
35
|
+
it("should create a new instance of a provider that has a full dep tree", () => {
|
|
36
36
|
class A {}
|
|
37
37
|
|
|
38
38
|
@injectable()
|
|
@@ -61,7 +61,7 @@ it('should create a new instance of a provider that has a full dep tree', () =>
|
|
|
61
61
|
assert(instance.d().c().b().a() instanceof A);
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
it(
|
|
64
|
+
it("should override a provider if explicitly instructed", () => {
|
|
65
65
|
class A {}
|
|
66
66
|
|
|
67
67
|
@injectable()
|
|
@@ -70,117 +70,131 @@ it('should override a provider if explicitly instructed', () => {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
class AltA extends A {}
|
|
73
|
-
const app = new Injector(
|
|
73
|
+
const app = new Injector({
|
|
74
|
+
providers: [[A, { use: AltA }]],
|
|
75
|
+
});
|
|
74
76
|
|
|
75
77
|
assert(app.inject(B).a() instanceof AltA);
|
|
76
78
|
});
|
|
77
79
|
|
|
78
|
-
it(
|
|
80
|
+
it("should return an existing instance from a parent injector", () => {
|
|
79
81
|
class A {}
|
|
80
82
|
|
|
81
83
|
const parent = new Injector();
|
|
82
84
|
|
|
83
|
-
const app = new Injector(
|
|
85
|
+
const app = new Injector({
|
|
86
|
+
parent,
|
|
87
|
+
});
|
|
84
88
|
|
|
85
89
|
assert.equal(parent.inject(A), app.inject(A));
|
|
86
90
|
});
|
|
87
91
|
|
|
88
|
-
it(
|
|
92
|
+
it("should use a factory if provided", () => {
|
|
89
93
|
class Service {
|
|
90
94
|
hello() {
|
|
91
|
-
return
|
|
95
|
+
return "world";
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
98
|
|
|
95
|
-
const injector = new Injector(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
99
|
+
const injector = new Injector({
|
|
100
|
+
providers: [
|
|
101
|
+
[
|
|
102
|
+
Service,
|
|
103
|
+
{
|
|
104
|
+
factory() {
|
|
105
|
+
return {
|
|
106
|
+
hello() {
|
|
107
|
+
return "world";
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
],
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
assert.equal(injector.inject(Service).hello(), "world");
|
|
109
117
|
});
|
|
110
118
|
|
|
111
|
-
it(
|
|
119
|
+
it("should throw an error if provider is missing both factory and use", () => {
|
|
112
120
|
class Service {
|
|
113
121
|
hello() {
|
|
114
|
-
return
|
|
122
|
+
return "world";
|
|
115
123
|
}
|
|
116
124
|
}
|
|
117
125
|
|
|
118
|
-
const injector = new Injector(
|
|
119
|
-
{
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
]);
|
|
126
|
+
const injector = new Injector({
|
|
127
|
+
providers: [[Service, {} as any]],
|
|
128
|
+
});
|
|
123
129
|
|
|
124
130
|
assert.throws(
|
|
125
131
|
() => injector.inject(Service),
|
|
126
|
-
"Provider for Service found but is missing either 'use' or 'factory'"
|
|
132
|
+
"Provider for Service found but is missing either 'use' or 'factory'",
|
|
127
133
|
);
|
|
128
134
|
});
|
|
129
135
|
|
|
130
|
-
it(
|
|
136
|
+
it("should pass factories and instance of the injector", async () => {
|
|
131
137
|
class Service {
|
|
132
138
|
hello() {
|
|
133
|
-
return
|
|
139
|
+
return "world";
|
|
134
140
|
}
|
|
135
141
|
}
|
|
136
142
|
|
|
137
143
|
let factoryInjector: Injector | null = null;
|
|
138
144
|
|
|
139
|
-
const injector = new Injector(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
const injector = new Injector({
|
|
146
|
+
providers: [
|
|
147
|
+
[
|
|
148
|
+
Service,
|
|
149
|
+
{
|
|
150
|
+
factory(i) {
|
|
151
|
+
factoryInjector = i;
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
],
|
|
156
|
+
});
|
|
147
157
|
|
|
148
158
|
injector.inject(Service);
|
|
149
159
|
|
|
150
160
|
assert.equal(factoryInjector, injector);
|
|
151
161
|
});
|
|
152
162
|
|
|
153
|
-
it(
|
|
154
|
-
const TOKEN = new StaticToken(
|
|
163
|
+
it("should create an instance from a StaticToken factory", () => {
|
|
164
|
+
const TOKEN = new StaticToken("test", () => "Hello World");
|
|
155
165
|
const injector = new Injector();
|
|
156
166
|
|
|
157
167
|
const res = injector.inject(TOKEN);
|
|
158
168
|
|
|
159
|
-
assert.equal(res,
|
|
169
|
+
assert.equal(res, "Hello World");
|
|
160
170
|
});
|
|
161
171
|
|
|
162
|
-
it(
|
|
163
|
-
const TOKEN = new StaticToken(
|
|
172
|
+
it("should create an instance from an async StaticToken factory", async () => {
|
|
173
|
+
const TOKEN = new StaticToken("test", async () => "Hello World");
|
|
164
174
|
const injector = new Injector();
|
|
165
175
|
|
|
166
176
|
const res = await injector.inject(TOKEN);
|
|
167
177
|
|
|
168
|
-
assert.equal(res,
|
|
178
|
+
assert.equal(res, "Hello World");
|
|
169
179
|
});
|
|
170
180
|
|
|
171
|
-
it(
|
|
172
|
-
const TOKEN = new StaticToken<string>(
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
181
|
+
it("should allow static token to be overridden", () => {
|
|
182
|
+
const TOKEN = new StaticToken<string>("test");
|
|
183
|
+
|
|
184
|
+
const injector = new Injector({
|
|
185
|
+
providers: [
|
|
186
|
+
[
|
|
187
|
+
TOKEN,
|
|
188
|
+
{
|
|
189
|
+
factory() {
|
|
190
|
+
return "Hello World";
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
],
|
|
195
|
+
});
|
|
182
196
|
|
|
183
197
|
const res = injector.inject(TOKEN);
|
|
184
198
|
|
|
185
|
-
assert.equal(res,
|
|
199
|
+
assert.equal(res, "Hello World");
|
|
186
200
|
});
|