@timesplinter/pimple 1.1.1 → 2.1.0
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 +13 -4
- package/lib/cjs/container.d.ts +4 -3
- package/lib/cjs/pimple.d.ts +28 -27
- package/lib/cjs/pimple.js +56 -28
- package/lib/cjs/pimple.js.map +1 -1
- package/lib/cjs/serviceProvider.d.ts +2 -2
- package/lib/esm/container.d.ts +4 -3
- package/lib/esm/pimple.d.ts +28 -27
- package/lib/esm/pimple.js +56 -28
- package/lib/esm/pimple.js.map +1 -1
- package/lib/esm/serviceProvider.d.ts +2 -2
- package/package.json +19 -10
- package/.babelrc +0 -6
- package/.github/workflows/test.yml +0 -13
- package/jest.config.json +0 -11
- package/src/container.ts +0 -8
- package/src/index.ts +0 -8
- package/src/pimple.ts +0 -171
- package/src/serviceProvider.ts +0 -9
- package/tests/pimple.spec.ts +0 -138
- package/tsconfig-cjs.json +0 -8
- package/tsconfig.json +0 -19
package/README.md
CHANGED
|
@@ -9,13 +9,22 @@ and the original PHP Pimple container by Fabien Potencier.
|
|
|
9
9
|
|
|
10
10
|
## Usage
|
|
11
11
|
|
|
12
|
-
```
|
|
12
|
+
```ts
|
|
13
13
|
import Pimple from '@timesplinter/pimple';
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
type ServiceMap = {
|
|
16
|
+
'foo': string,
|
|
17
|
+
'bar': string,
|
|
18
|
+
};
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
const container: Container = new Pimple<ServiceMap>({env: 'dev'});
|
|
21
|
+
|
|
22
|
+
container.set('foo', () => {
|
|
23
|
+
return `baz (${container.get('env')})`;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
container.set('bar', (container: Pimple<ServiceMap>) => {
|
|
27
|
+
return `bar: ${container.get('foo')}`;
|
|
19
28
|
});
|
|
20
29
|
|
|
21
30
|
console.log(container.get('foo')); // 'bar (dev)';
|
package/lib/cjs/container.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export type ServiceKey<T> = keyof T;
|
|
2
|
+
export default interface Container<T> {
|
|
3
|
+
get<K extends ServiceKey<T>>(key: K): T[K];
|
|
4
|
+
has<K extends ServiceKey<T>>(key: K): boolean;
|
|
4
5
|
}
|
package/lib/cjs/pimple.d.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import Container from "./container";
|
|
1
|
+
import Container, { ServiceKey } from "./container";
|
|
2
2
|
import ServiceProvider from "./serviceProvider";
|
|
3
3
|
/** Declaration types */
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
type ServiceProviderFunction<T> = (container: Pimple<T>) => void;
|
|
5
|
+
type ProviderDeclaration<T> = ServiceProviderFunction<T> | ServiceProvider<T>;
|
|
6
|
+
type LazyServiceDefinition<T, S> = (container: Pimple<T>) => S;
|
|
7
|
+
type ProtectedServiceDefinition<T, S> = () => LazyServiceDefinition<T, S>;
|
|
8
|
+
type PlainServiceDefinition<S> = S extends Function ? () => S : S;
|
|
9
|
+
type ServiceDefinition<T, S> = PlainServiceDefinition<S> | LazyServiceDefinition<T, S> | ProtectedServiceDefinition<T, S>;
|
|
10
|
+
type ServiceMap<T> = {
|
|
11
|
+
[key in ServiceKey<T>]: ServiceDefinition<T, T[ServiceKey<T>]>;
|
|
12
|
+
};
|
|
6
13
|
/**
|
|
7
14
|
* Pimple dependency injection container
|
|
8
15
|
*
|
|
@@ -10,58 +17,52 @@ declare type ProviderDeclaration = Function | ServiceProvider;
|
|
|
10
17
|
* @copyright 2016 SerafimArts <nesk@xakep.ru>
|
|
11
18
|
* @copyright 2021 TiMESPLiNTER <dev@timesplinter.ch>
|
|
12
19
|
* @license LGPL
|
|
13
|
-
* @version
|
|
20
|
+
* @version 2.1.0
|
|
14
21
|
*/
|
|
15
|
-
export default class Pimple implements Container {
|
|
16
|
-
/**
|
|
17
|
-
* @type {string}
|
|
18
|
-
*/
|
|
22
|
+
export default class Pimple<T> implements Container<T> {
|
|
19
23
|
static get VERSION(): string;
|
|
20
|
-
/**
|
|
21
|
-
* @type {{}}
|
|
22
|
-
* @private
|
|
23
|
-
*/
|
|
24
24
|
private _definitions;
|
|
25
|
+
private _raw;
|
|
26
|
+
private _resolved;
|
|
27
|
+
private _resolving;
|
|
28
|
+
constructor(services?: Partial<ServiceMap<T>>);
|
|
25
29
|
/**
|
|
26
|
-
*
|
|
27
|
-
* @private
|
|
30
|
+
* Define a service (first-time registration only)
|
|
28
31
|
*/
|
|
29
|
-
|
|
30
|
-
constructor(services?: {
|
|
31
|
-
[key: string]: any;
|
|
32
|
-
});
|
|
32
|
+
set<K extends ServiceKey<T>>(name: K, service: ServiceDefinition<T, T[K]>): Pimple<T>;
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
34
|
+
* Replace an existing service definition before it has been resolved
|
|
35
35
|
*/
|
|
36
|
-
|
|
36
|
+
replace<K extends ServiceKey<T>>(name: K, service: ServiceDefinition<T, T[K]>): Pimple<T>;
|
|
37
|
+
private define;
|
|
37
38
|
/**
|
|
38
39
|
* Register a factory
|
|
39
40
|
*/
|
|
40
|
-
factory(name:
|
|
41
|
+
factory<K extends ServiceKey<T>>(name: K, callback: ServiceDefinition<T, T[K]>): Pimple<T>;
|
|
41
42
|
/**
|
|
42
43
|
* Get a service instance
|
|
43
44
|
*/
|
|
44
|
-
get(name:
|
|
45
|
+
get<K extends ServiceKey<T>>(name: K): T[K];
|
|
45
46
|
/**
|
|
46
47
|
* Checks whether a service is registered or not
|
|
47
48
|
*/
|
|
48
|
-
has(
|
|
49
|
+
has<K extends ServiceKey<T>>(name: K): boolean;
|
|
49
50
|
/**
|
|
50
51
|
* Register a protected function
|
|
51
52
|
*/
|
|
52
|
-
protect(
|
|
53
|
+
protect<T extends Function>(func: T): () => T;
|
|
53
54
|
/**
|
|
54
55
|
* Extend a service
|
|
55
56
|
*/
|
|
56
|
-
extend(serviceName:
|
|
57
|
+
extend<K extends ServiceKey<T>>(serviceName: K, service: Function): Function;
|
|
57
58
|
/**
|
|
58
59
|
* Get a service raw definition
|
|
59
60
|
*/
|
|
60
|
-
raw(name:
|
|
61
|
+
raw<K extends ServiceKey<T>>(name: K): ServiceDefinition<T, T[K]>;
|
|
61
62
|
/**
|
|
62
63
|
* Register a service provider
|
|
63
64
|
*/
|
|
64
|
-
register(provider: ProviderDeclaration): Pimple
|
|
65
|
+
register(provider: ProviderDeclaration<T>): Pimple<T>;
|
|
65
66
|
private instanceOfServiceProvider;
|
|
66
67
|
}
|
|
67
68
|
export {};
|
package/lib/cjs/pimple.js
CHANGED
|
@@ -15,32 +15,49 @@ const reservedProperties = [
|
|
|
15
15
|
* @copyright 2016 SerafimArts <nesk@xakep.ru>
|
|
16
16
|
* @copyright 2021 TiMESPLiNTER <dev@timesplinter.ch>
|
|
17
17
|
* @license LGPL
|
|
18
|
-
* @version
|
|
18
|
+
* @version 2.1.0
|
|
19
19
|
*/
|
|
20
20
|
class Pimple {
|
|
21
|
+
static get VERSION() { return '2.1.0'; }
|
|
21
22
|
constructor(services = {}) {
|
|
22
|
-
/**
|
|
23
|
-
* @type {{}}
|
|
24
|
-
* @private
|
|
25
|
-
*/
|
|
26
23
|
this._definitions = {};
|
|
27
|
-
/**
|
|
28
|
-
* @type {{}}
|
|
29
|
-
* @private
|
|
30
|
-
*/
|
|
31
24
|
this._raw = {};
|
|
25
|
+
this._resolved = new Map();
|
|
26
|
+
this._resolving = [];
|
|
32
27
|
Object.keys(services).forEach((service) => {
|
|
33
|
-
|
|
28
|
+
const serviceKey = service;
|
|
29
|
+
this.set(serviceKey, services[serviceKey]);
|
|
34
30
|
}, this);
|
|
35
31
|
}
|
|
36
32
|
/**
|
|
37
|
-
*
|
|
33
|
+
* Define a service (first-time registration only)
|
|
38
34
|
*/
|
|
39
|
-
|
|
35
|
+
set(name, service) {
|
|
36
|
+
if (this.has(name)) {
|
|
37
|
+
throw new Error(`Service "${name.toString()}" is already defined. Use replace() to overwrite it.`);
|
|
38
|
+
}
|
|
39
|
+
return this.define(name, service);
|
|
40
|
+
}
|
|
40
41
|
/**
|
|
41
|
-
*
|
|
42
|
+
* Replace an existing service definition before it has been resolved
|
|
42
43
|
*/
|
|
43
|
-
|
|
44
|
+
replace(name, service) {
|
|
45
|
+
var _a;
|
|
46
|
+
if (!this.has(name)) {
|
|
47
|
+
throw new RangeError(`Service "${name.toString()}" is not defined in the container.`);
|
|
48
|
+
}
|
|
49
|
+
if (this._resolved.has(name)) {
|
|
50
|
+
const trace = [];
|
|
51
|
+
let current = name;
|
|
52
|
+
while (current !== null) {
|
|
53
|
+
trace.unshift(current.toString());
|
|
54
|
+
current = (_a = this._resolved.get(current)) !== null && _a !== void 0 ? _a : null;
|
|
55
|
+
}
|
|
56
|
+
throw new Error(`Service "${name.toString()}" has already been resolved and cannot be replaced. Resolution trace: ${trace.join(' → ')}`);
|
|
57
|
+
}
|
|
58
|
+
return this.define(name, service);
|
|
59
|
+
}
|
|
60
|
+
define(name, service) {
|
|
44
61
|
this._raw[name] = service;
|
|
45
62
|
this._definitions[name] = service instanceof Function ?
|
|
46
63
|
(function () {
|
|
@@ -52,8 +69,9 @@ class Pimple {
|
|
|
52
69
|
return cached;
|
|
53
70
|
};
|
|
54
71
|
}()) : service;
|
|
55
|
-
if (reservedProperties.indexOf(name) === -1) {
|
|
72
|
+
if (reservedProperties.indexOf(name.toString()) === -1) {
|
|
56
73
|
Object.defineProperty(this, name, {
|
|
74
|
+
configurable: true,
|
|
57
75
|
get: () => {
|
|
58
76
|
return this.get(name);
|
|
59
77
|
}
|
|
@@ -67,8 +85,9 @@ class Pimple {
|
|
|
67
85
|
factory(name, callback) {
|
|
68
86
|
this._raw[name] = callback;
|
|
69
87
|
this._definitions[name] = callback;
|
|
70
|
-
if (reservedProperties.indexOf(name) === -1) {
|
|
88
|
+
if (reservedProperties.indexOf(name.toString()) === -1) {
|
|
71
89
|
Object.defineProperty(this, name, {
|
|
90
|
+
configurable: true,
|
|
72
91
|
get: () => {
|
|
73
92
|
return this.get(name);
|
|
74
93
|
}
|
|
@@ -81,32 +100,43 @@ class Pimple {
|
|
|
81
100
|
*/
|
|
82
101
|
get(name) {
|
|
83
102
|
if (this._definitions[name] instanceof Function) {
|
|
84
|
-
|
|
103
|
+
const firstResolution = !this._resolved.has(name);
|
|
104
|
+
if (firstResolution) {
|
|
105
|
+
const parent = this._resolving.length > 0 ? this._resolving[this._resolving.length - 1] : null;
|
|
106
|
+
this._resolved.set(name, parent);
|
|
107
|
+
this._resolving.push(name);
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
return this._definitions[name](this);
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
if (firstResolution) {
|
|
114
|
+
this._resolving.pop();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
85
117
|
}
|
|
86
118
|
return this._definitions[name];
|
|
87
119
|
}
|
|
88
120
|
/**
|
|
89
121
|
* Checks whether a service is registered or not
|
|
90
122
|
*/
|
|
91
|
-
has(
|
|
92
|
-
return
|
|
123
|
+
has(name) {
|
|
124
|
+
return name in this._definitions;
|
|
93
125
|
}
|
|
94
126
|
/**
|
|
95
127
|
* Register a protected function
|
|
96
128
|
*/
|
|
97
|
-
protect(
|
|
98
|
-
return () =>
|
|
99
|
-
return service;
|
|
100
|
-
};
|
|
129
|
+
protect(func) {
|
|
130
|
+
return () => func;
|
|
101
131
|
}
|
|
102
132
|
/**
|
|
103
133
|
* Extend a service
|
|
104
134
|
*/
|
|
105
135
|
extend(serviceName, service) {
|
|
106
136
|
if (!this._definitions[serviceName]) {
|
|
107
|
-
throw new RangeError(`Definition with "${serviceName}" not defined in container.`);
|
|
137
|
+
throw new RangeError(`Definition with "${serviceName.toString()}" not defined in container.`);
|
|
108
138
|
}
|
|
109
|
-
|
|
139
|
+
let def = this._definitions[serviceName];
|
|
110
140
|
return this._definitions[serviceName] = (container) => {
|
|
111
141
|
if (def instanceof Function) {
|
|
112
142
|
def = def(container);
|
|
@@ -126,11 +156,9 @@ class Pimple {
|
|
|
126
156
|
register(provider) {
|
|
127
157
|
if (this.instanceOfServiceProvider(provider) && provider.register instanceof Function) {
|
|
128
158
|
provider.register(this);
|
|
129
|
-
return this;
|
|
130
159
|
}
|
|
131
|
-
if (provider instanceof Function) {
|
|
160
|
+
else if (provider instanceof Function) {
|
|
132
161
|
provider(this);
|
|
133
|
-
return this;
|
|
134
162
|
}
|
|
135
163
|
return this;
|
|
136
164
|
}
|
package/lib/cjs/pimple.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pimple.js","sourceRoot":"","sources":["../../src/pimple.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;
|
|
1
|
+
{"version":3,"file":"pimple.js","sourceRoot":"","sources":["../../src/pimple.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,6 @@ import Pimple from "./pimple";
|
|
|
2
2
|
/**
|
|
3
3
|
* Service provider class for service injecting in Pimple container
|
|
4
4
|
*/
|
|
5
|
-
export default interface ServiceProvider {
|
|
6
|
-
register(container: Pimple): void;
|
|
5
|
+
export default interface ServiceProvider<T> {
|
|
6
|
+
register(container: Pimple<T>): void;
|
|
7
7
|
}
|
package/lib/esm/container.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export type ServiceKey<T> = keyof T;
|
|
2
|
+
export default interface Container<T> {
|
|
3
|
+
get<K extends ServiceKey<T>>(key: K): T[K];
|
|
4
|
+
has<K extends ServiceKey<T>>(key: K): boolean;
|
|
4
5
|
}
|
package/lib/esm/pimple.d.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import Container from "./container";
|
|
1
|
+
import Container, { ServiceKey } from "./container";
|
|
2
2
|
import ServiceProvider from "./serviceProvider";
|
|
3
3
|
/** Declaration types */
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
type ServiceProviderFunction<T> = (container: Pimple<T>) => void;
|
|
5
|
+
type ProviderDeclaration<T> = ServiceProviderFunction<T> | ServiceProvider<T>;
|
|
6
|
+
type LazyServiceDefinition<T, S> = (container: Pimple<T>) => S;
|
|
7
|
+
type ProtectedServiceDefinition<T, S> = () => LazyServiceDefinition<T, S>;
|
|
8
|
+
type PlainServiceDefinition<S> = S extends Function ? () => S : S;
|
|
9
|
+
type ServiceDefinition<T, S> = PlainServiceDefinition<S> | LazyServiceDefinition<T, S> | ProtectedServiceDefinition<T, S>;
|
|
10
|
+
type ServiceMap<T> = {
|
|
11
|
+
[key in ServiceKey<T>]: ServiceDefinition<T, T[ServiceKey<T>]>;
|
|
12
|
+
};
|
|
6
13
|
/**
|
|
7
14
|
* Pimple dependency injection container
|
|
8
15
|
*
|
|
@@ -10,58 +17,52 @@ declare type ProviderDeclaration = Function | ServiceProvider;
|
|
|
10
17
|
* @copyright 2016 SerafimArts <nesk@xakep.ru>
|
|
11
18
|
* @copyright 2021 TiMESPLiNTER <dev@timesplinter.ch>
|
|
12
19
|
* @license LGPL
|
|
13
|
-
* @version
|
|
20
|
+
* @version 2.1.0
|
|
14
21
|
*/
|
|
15
|
-
export default class Pimple implements Container {
|
|
16
|
-
/**
|
|
17
|
-
* @type {string}
|
|
18
|
-
*/
|
|
22
|
+
export default class Pimple<T> implements Container<T> {
|
|
19
23
|
static get VERSION(): string;
|
|
20
|
-
/**
|
|
21
|
-
* @type {{}}
|
|
22
|
-
* @private
|
|
23
|
-
*/
|
|
24
24
|
private _definitions;
|
|
25
|
+
private _raw;
|
|
26
|
+
private _resolved;
|
|
27
|
+
private _resolving;
|
|
28
|
+
constructor(services?: Partial<ServiceMap<T>>);
|
|
25
29
|
/**
|
|
26
|
-
*
|
|
27
|
-
* @private
|
|
30
|
+
* Define a service (first-time registration only)
|
|
28
31
|
*/
|
|
29
|
-
|
|
30
|
-
constructor(services?: {
|
|
31
|
-
[key: string]: any;
|
|
32
|
-
});
|
|
32
|
+
set<K extends ServiceKey<T>>(name: K, service: ServiceDefinition<T, T[K]>): Pimple<T>;
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
34
|
+
* Replace an existing service definition before it has been resolved
|
|
35
35
|
*/
|
|
36
|
-
|
|
36
|
+
replace<K extends ServiceKey<T>>(name: K, service: ServiceDefinition<T, T[K]>): Pimple<T>;
|
|
37
|
+
private define;
|
|
37
38
|
/**
|
|
38
39
|
* Register a factory
|
|
39
40
|
*/
|
|
40
|
-
factory(name:
|
|
41
|
+
factory<K extends ServiceKey<T>>(name: K, callback: ServiceDefinition<T, T[K]>): Pimple<T>;
|
|
41
42
|
/**
|
|
42
43
|
* Get a service instance
|
|
43
44
|
*/
|
|
44
|
-
get(name:
|
|
45
|
+
get<K extends ServiceKey<T>>(name: K): T[K];
|
|
45
46
|
/**
|
|
46
47
|
* Checks whether a service is registered or not
|
|
47
48
|
*/
|
|
48
|
-
has(
|
|
49
|
+
has<K extends ServiceKey<T>>(name: K): boolean;
|
|
49
50
|
/**
|
|
50
51
|
* Register a protected function
|
|
51
52
|
*/
|
|
52
|
-
protect(
|
|
53
|
+
protect<T extends Function>(func: T): () => T;
|
|
53
54
|
/**
|
|
54
55
|
* Extend a service
|
|
55
56
|
*/
|
|
56
|
-
extend(serviceName:
|
|
57
|
+
extend<K extends ServiceKey<T>>(serviceName: K, service: Function): Function;
|
|
57
58
|
/**
|
|
58
59
|
* Get a service raw definition
|
|
59
60
|
*/
|
|
60
|
-
raw(name:
|
|
61
|
+
raw<K extends ServiceKey<T>>(name: K): ServiceDefinition<T, T[K]>;
|
|
61
62
|
/**
|
|
62
63
|
* Register a service provider
|
|
63
64
|
*/
|
|
64
|
-
register(provider: ProviderDeclaration): Pimple
|
|
65
|
+
register(provider: ProviderDeclaration<T>): Pimple<T>;
|
|
65
66
|
private instanceOfServiceProvider;
|
|
66
67
|
}
|
|
67
68
|
export {};
|
package/lib/esm/pimple.js
CHANGED
|
@@ -14,32 +14,49 @@ const reservedProperties = [
|
|
|
14
14
|
* @copyright 2016 SerafimArts <nesk@xakep.ru>
|
|
15
15
|
* @copyright 2021 TiMESPLiNTER <dev@timesplinter.ch>
|
|
16
16
|
* @license LGPL
|
|
17
|
-
* @version
|
|
17
|
+
* @version 2.1.0
|
|
18
18
|
*/
|
|
19
19
|
export default class Pimple {
|
|
20
|
+
static get VERSION() { return '2.1.0'; }
|
|
20
21
|
constructor(services = {}) {
|
|
21
|
-
/**
|
|
22
|
-
* @type {{}}
|
|
23
|
-
* @private
|
|
24
|
-
*/
|
|
25
22
|
this._definitions = {};
|
|
26
|
-
/**
|
|
27
|
-
* @type {{}}
|
|
28
|
-
* @private
|
|
29
|
-
*/
|
|
30
23
|
this._raw = {};
|
|
24
|
+
this._resolved = new Map();
|
|
25
|
+
this._resolving = [];
|
|
31
26
|
Object.keys(services).forEach((service) => {
|
|
32
|
-
|
|
27
|
+
const serviceKey = service;
|
|
28
|
+
this.set(serviceKey, services[serviceKey]);
|
|
33
29
|
}, this);
|
|
34
30
|
}
|
|
35
31
|
/**
|
|
36
|
-
*
|
|
32
|
+
* Define a service (first-time registration only)
|
|
37
33
|
*/
|
|
38
|
-
|
|
34
|
+
set(name, service) {
|
|
35
|
+
if (this.has(name)) {
|
|
36
|
+
throw new Error(`Service "${name.toString()}" is already defined. Use replace() to overwrite it.`);
|
|
37
|
+
}
|
|
38
|
+
return this.define(name, service);
|
|
39
|
+
}
|
|
39
40
|
/**
|
|
40
|
-
*
|
|
41
|
+
* Replace an existing service definition before it has been resolved
|
|
41
42
|
*/
|
|
42
|
-
|
|
43
|
+
replace(name, service) {
|
|
44
|
+
var _a;
|
|
45
|
+
if (!this.has(name)) {
|
|
46
|
+
throw new RangeError(`Service "${name.toString()}" is not defined in the container.`);
|
|
47
|
+
}
|
|
48
|
+
if (this._resolved.has(name)) {
|
|
49
|
+
const trace = [];
|
|
50
|
+
let current = name;
|
|
51
|
+
while (current !== null) {
|
|
52
|
+
trace.unshift(current.toString());
|
|
53
|
+
current = (_a = this._resolved.get(current)) !== null && _a !== void 0 ? _a : null;
|
|
54
|
+
}
|
|
55
|
+
throw new Error(`Service "${name.toString()}" has already been resolved and cannot be replaced. Resolution trace: ${trace.join(' → ')}`);
|
|
56
|
+
}
|
|
57
|
+
return this.define(name, service);
|
|
58
|
+
}
|
|
59
|
+
define(name, service) {
|
|
43
60
|
this._raw[name] = service;
|
|
44
61
|
this._definitions[name] = service instanceof Function ?
|
|
45
62
|
(function () {
|
|
@@ -51,8 +68,9 @@ export default class Pimple {
|
|
|
51
68
|
return cached;
|
|
52
69
|
};
|
|
53
70
|
}()) : service;
|
|
54
|
-
if (reservedProperties.indexOf(name) === -1) {
|
|
71
|
+
if (reservedProperties.indexOf(name.toString()) === -1) {
|
|
55
72
|
Object.defineProperty(this, name, {
|
|
73
|
+
configurable: true,
|
|
56
74
|
get: () => {
|
|
57
75
|
return this.get(name);
|
|
58
76
|
}
|
|
@@ -66,8 +84,9 @@ export default class Pimple {
|
|
|
66
84
|
factory(name, callback) {
|
|
67
85
|
this._raw[name] = callback;
|
|
68
86
|
this._definitions[name] = callback;
|
|
69
|
-
if (reservedProperties.indexOf(name) === -1) {
|
|
87
|
+
if (reservedProperties.indexOf(name.toString()) === -1) {
|
|
70
88
|
Object.defineProperty(this, name, {
|
|
89
|
+
configurable: true,
|
|
71
90
|
get: () => {
|
|
72
91
|
return this.get(name);
|
|
73
92
|
}
|
|
@@ -80,32 +99,43 @@ export default class Pimple {
|
|
|
80
99
|
*/
|
|
81
100
|
get(name) {
|
|
82
101
|
if (this._definitions[name] instanceof Function) {
|
|
83
|
-
|
|
102
|
+
const firstResolution = !this._resolved.has(name);
|
|
103
|
+
if (firstResolution) {
|
|
104
|
+
const parent = this._resolving.length > 0 ? this._resolving[this._resolving.length - 1] : null;
|
|
105
|
+
this._resolved.set(name, parent);
|
|
106
|
+
this._resolving.push(name);
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
return this._definitions[name](this);
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
if (firstResolution) {
|
|
113
|
+
this._resolving.pop();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
84
116
|
}
|
|
85
117
|
return this._definitions[name];
|
|
86
118
|
}
|
|
87
119
|
/**
|
|
88
120
|
* Checks whether a service is registered or not
|
|
89
121
|
*/
|
|
90
|
-
has(
|
|
91
|
-
return
|
|
122
|
+
has(name) {
|
|
123
|
+
return name in this._definitions;
|
|
92
124
|
}
|
|
93
125
|
/**
|
|
94
126
|
* Register a protected function
|
|
95
127
|
*/
|
|
96
|
-
protect(
|
|
97
|
-
return () =>
|
|
98
|
-
return service;
|
|
99
|
-
};
|
|
128
|
+
protect(func) {
|
|
129
|
+
return () => func;
|
|
100
130
|
}
|
|
101
131
|
/**
|
|
102
132
|
* Extend a service
|
|
103
133
|
*/
|
|
104
134
|
extend(serviceName, service) {
|
|
105
135
|
if (!this._definitions[serviceName]) {
|
|
106
|
-
throw new RangeError(`Definition with "${serviceName}" not defined in container.`);
|
|
136
|
+
throw new RangeError(`Definition with "${serviceName.toString()}" not defined in container.`);
|
|
107
137
|
}
|
|
108
|
-
|
|
138
|
+
let def = this._definitions[serviceName];
|
|
109
139
|
return this._definitions[serviceName] = (container) => {
|
|
110
140
|
if (def instanceof Function) {
|
|
111
141
|
def = def(container);
|
|
@@ -125,11 +155,9 @@ export default class Pimple {
|
|
|
125
155
|
register(provider) {
|
|
126
156
|
if (this.instanceOfServiceProvider(provider) && provider.register instanceof Function) {
|
|
127
157
|
provider.register(this);
|
|
128
|
-
return this;
|
|
129
158
|
}
|
|
130
|
-
if (provider instanceof Function) {
|
|
159
|
+
else if (provider instanceof Function) {
|
|
131
160
|
provider(this);
|
|
132
|
-
return this;
|
|
133
161
|
}
|
|
134
162
|
return this;
|
|
135
163
|
}
|
package/lib/esm/pimple.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pimple.js","sourceRoot":"","sources":["../../src/pimple.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"pimple.js","sourceRoot":"","sources":["../../src/pimple.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,6 @@ import Pimple from "./pimple";
|
|
|
2
2
|
/**
|
|
3
3
|
* Service provider class for service injecting in Pimple container
|
|
4
4
|
*/
|
|
5
|
-
export default interface ServiceProvider {
|
|
6
|
-
register(container: Pimple): void;
|
|
5
|
+
export default interface ServiceProvider<T> {
|
|
6
|
+
register(container: Pimple<T>): void;
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timesplinter/pimple",
|
|
3
3
|
"license": "LGPL-3.0-or-later",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "2.1.0",
|
|
5
5
|
"module": "./lib/esm/index.js",
|
|
6
6
|
"main": "./lib/cjs/index.js",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/TiMESPLiNTER/pimple-js.git"
|
|
10
|
+
},
|
|
7
11
|
"scripts": {
|
|
8
12
|
"test": "jest",
|
|
9
|
-
"
|
|
13
|
+
"test:cov": "jest --collect-coverage",
|
|
14
|
+
"typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig-cjs.json",
|
|
10
15
|
"transpile": "tsc -p tsconfig.json && tsc -p tsconfig-cjs.json",
|
|
11
|
-
"
|
|
16
|
+
"prepublishOnly": "npm run transpile"
|
|
12
17
|
},
|
|
18
|
+
"files": [
|
|
19
|
+
"lib/"
|
|
20
|
+
],
|
|
13
21
|
"keywords": [],
|
|
14
22
|
"author": "Pascal Münst <dev@timesplinter.ch>",
|
|
15
23
|
"description": "A simple dependency-injection container written in TypeScript based on PHP's Pimple",
|
|
16
24
|
"devDependencies": {
|
|
17
|
-
"@babel/core": "^7.
|
|
18
|
-
"@babel/preset-env": "^7.
|
|
19
|
-
"@babel/preset-typescript": "^7.
|
|
20
|
-
"@types/jest": "^
|
|
21
|
-
"babel-jest": "^
|
|
22
|
-
"jest": "^
|
|
23
|
-
"
|
|
25
|
+
"@babel/core": "^7.23.9",
|
|
26
|
+
"@babel/preset-env": "^7.23.9",
|
|
27
|
+
"@babel/preset-typescript": "^7.23.3",
|
|
28
|
+
"@types/jest": "^29.5.14",
|
|
29
|
+
"babel-jest": "^29.7.0",
|
|
30
|
+
"jest": "^29.7.0",
|
|
31
|
+
"ts-node": "^10.9.2",
|
|
32
|
+
"typescript": "^4.9.5"
|
|
24
33
|
}
|
|
25
34
|
}
|
package/.babelrc
DELETED
package/jest.config.json
DELETED
package/src/container.ts
DELETED
package/src/index.ts
DELETED
package/src/pimple.ts
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import Container from "./container";
|
|
4
|
-
import ServiceProvider from "./serviceProvider";
|
|
5
|
-
|
|
6
|
-
/** Declaration types */
|
|
7
|
-
type ServiceDeclaration = Function|Object;
|
|
8
|
-
type ProviderDeclaration = Function|ServiceProvider;
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Reserved names of properties
|
|
12
|
-
*/
|
|
13
|
-
const reservedProperties: string[] = [
|
|
14
|
-
'get', 'set', 'factory', 'raw',
|
|
15
|
-
'protect', 'share', 'toString', 'constructor',
|
|
16
|
-
'prototype'
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Pimple dependency injection container
|
|
21
|
-
*
|
|
22
|
-
* @copyright 2011 M.PARAISO <mparaiso@online.fr>
|
|
23
|
-
* @copyright 2016 SerafimArts <nesk@xakep.ru>
|
|
24
|
-
* @copyright 2021 TiMESPLiNTER <dev@timesplinter.ch>
|
|
25
|
-
* @license LGPL
|
|
26
|
-
* @version 3.0.0
|
|
27
|
-
*/
|
|
28
|
-
export default class Pimple implements Container
|
|
29
|
-
{
|
|
30
|
-
/**
|
|
31
|
-
* @type {string}
|
|
32
|
-
*/
|
|
33
|
-
static get VERSION() { return '3.0.0'; }
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* @type {{}}
|
|
37
|
-
* @private
|
|
38
|
-
*/
|
|
39
|
-
private _definitions: { [key: string]: any; } = {};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* @type {{}}
|
|
43
|
-
* @private
|
|
44
|
-
*/
|
|
45
|
-
private _raw: { [key: string]: any; } = {};
|
|
46
|
-
|
|
47
|
-
constructor(services: { [key: string]: any; } = {}) {
|
|
48
|
-
Object.keys(services).forEach((service) => {
|
|
49
|
-
this.set(service, services[service]);
|
|
50
|
-
}, this);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Define a service
|
|
55
|
-
*/
|
|
56
|
-
public set(name: string, service: ServiceDeclaration): Pimple
|
|
57
|
-
{
|
|
58
|
-
this._raw[name] = service;
|
|
59
|
-
|
|
60
|
-
this._definitions[name] = service instanceof Function ?
|
|
61
|
-
(function () {
|
|
62
|
-
let cached: any;
|
|
63
|
-
return (pimple: Pimple) => {
|
|
64
|
-
if (cached === undefined) {
|
|
65
|
-
cached = service(pimple);
|
|
66
|
-
}
|
|
67
|
-
return cached;
|
|
68
|
-
};
|
|
69
|
-
}()) : service;
|
|
70
|
-
|
|
71
|
-
if (reservedProperties.indexOf(name) === -1) {
|
|
72
|
-
Object.defineProperty(this, name, {
|
|
73
|
-
get: () => {
|
|
74
|
-
return this.get(name);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return this;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Register a factory
|
|
84
|
-
*/
|
|
85
|
-
public factory(name: string, callback: Function): Pimple {
|
|
86
|
-
this._raw[name] = callback;
|
|
87
|
-
this._definitions[name] = callback;
|
|
88
|
-
|
|
89
|
-
if (reservedProperties.indexOf(name) === -1) {
|
|
90
|
-
Object.defineProperty(this, name, {
|
|
91
|
-
get: () => {
|
|
92
|
-
return this.get(name);
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return this;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Get a service instance
|
|
102
|
-
*/
|
|
103
|
-
public get(name: string): any {
|
|
104
|
-
if (this._definitions[name] instanceof Function) {
|
|
105
|
-
return this._definitions[name](this);
|
|
106
|
-
}
|
|
107
|
-
return this._definitions[name];
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Checks whether a service is registered or not
|
|
112
|
-
*/
|
|
113
|
-
public has(service: string): boolean {
|
|
114
|
-
return service in this._definitions;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Register a protected function
|
|
119
|
-
*/
|
|
120
|
-
public protect(service: Function): Function {
|
|
121
|
-
return () => {
|
|
122
|
-
return service;
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Extend a service
|
|
128
|
-
*/
|
|
129
|
-
public extend(serviceName: string, service: Function): Function {
|
|
130
|
-
if (!this._definitions[serviceName]) {
|
|
131
|
-
throw new RangeError(`Definition with "${serviceName}" not defined in container.`);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
var def = this._definitions[serviceName];
|
|
135
|
-
|
|
136
|
-
return this._definitions[serviceName] = (container: Pimple) => {
|
|
137
|
-
if (def instanceof Function) {
|
|
138
|
-
def = def(container);
|
|
139
|
-
}
|
|
140
|
-
return service(def, container);
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Get a service raw definition
|
|
146
|
-
*/
|
|
147
|
-
public raw(name: string): Function {
|
|
148
|
-
return this._raw[name];
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Register a service provider
|
|
153
|
-
*/
|
|
154
|
-
public register(provider: ProviderDeclaration): Pimple {
|
|
155
|
-
if (this.instanceOfServiceProvider(provider) && provider.register instanceof Function) {
|
|
156
|
-
provider.register(this);
|
|
157
|
-
return this;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (provider instanceof Function) {
|
|
161
|
-
provider(this);
|
|
162
|
-
return this;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return this;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
private instanceOfServiceProvider(object: any): object is ServiceProvider {
|
|
169
|
-
return 'register' in object;
|
|
170
|
-
}
|
|
171
|
-
}
|
package/src/serviceProvider.ts
DELETED
package/tests/pimple.spec.ts
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import Pimple from '../src/pimple';
|
|
2
|
-
|
|
3
|
-
describe('pimple container', () => {
|
|
4
|
-
it('returns container verison', async () => {
|
|
5
|
-
expect(Pimple.VERSION).toBe('3.0.0');
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
it('stores values', async () => {
|
|
9
|
-
const container = new Pimple({baz: 42});
|
|
10
|
-
|
|
11
|
-
container.set('foo', 'bar');
|
|
12
|
-
|
|
13
|
-
expect(container.get('foo')).toBe('bar');
|
|
14
|
-
expect(container.get('baz')).toBe(42);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('resolves function', async () => {
|
|
18
|
-
const container = new Pimple();
|
|
19
|
-
|
|
20
|
-
container.set('foo', () => {
|
|
21
|
-
return 'baz';
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
expect(container.get('foo')).toBe('baz');
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('resolves function only once', async () => {
|
|
28
|
-
const container = new Pimple();
|
|
29
|
-
|
|
30
|
-
container.set('foo', () => {
|
|
31
|
-
return Math.random();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
expect(container.get('foo')).toBe(container.get('foo'));
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('returns true if service exists', async () => {
|
|
38
|
-
const container = new Pimple();
|
|
39
|
-
|
|
40
|
-
container.set('foo', () => {
|
|
41
|
-
return 42;
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
expect(container.has('foo')).toBe(true);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('returns true if service exists', async () => {
|
|
48
|
-
const container = new Pimple();
|
|
49
|
-
|
|
50
|
-
expect(container.has('foo')).toBe(false);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('protects function', async () => {
|
|
54
|
-
const container = new Pimple();
|
|
55
|
-
|
|
56
|
-
const protectedFunciton = () => {
|
|
57
|
-
return 'baz';
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
container.set('foo', container.protect(protectedFunciton));
|
|
61
|
-
|
|
62
|
-
expect(container.get('foo')).toBe(protectedFunciton);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('returns original function', async () => {
|
|
66
|
-
const container = new Pimple();
|
|
67
|
-
|
|
68
|
-
const protectedFunciton = () => {
|
|
69
|
-
return 'baz';
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
container.set('foo', protectedFunciton);
|
|
73
|
-
|
|
74
|
-
expect(container.raw('foo')).toBe(protectedFunciton);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('registers services defined in service provider', async () => {
|
|
78
|
-
const container = new Pimple();
|
|
79
|
-
|
|
80
|
-
const serviceProviderMock = {
|
|
81
|
-
register: (container: Pimple) => {
|
|
82
|
-
container.set('foo', () => {
|
|
83
|
-
return 'baz'
|
|
84
|
-
});
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
container.register(serviceProviderMock);
|
|
89
|
-
|
|
90
|
-
expect(container.get('foo')).toBe('baz');
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('registers services defined in function', async () => {
|
|
94
|
-
const container = new Pimple();
|
|
95
|
-
|
|
96
|
-
const serviceProviderMock = (container: Pimple) => {
|
|
97
|
-
container.set('foo', () => {
|
|
98
|
-
return 'baz'
|
|
99
|
-
});
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
container.register(serviceProviderMock);
|
|
103
|
-
|
|
104
|
-
expect(container.get('foo')).toBe('baz');
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('returns new instance from factory', async () => {
|
|
108
|
-
const container = new Pimple();
|
|
109
|
-
|
|
110
|
-
container.factory('foo', () => {
|
|
111
|
-
return Math.random();
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
expect(container.get('foo')).not.toBe(container.get('foo'));
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('throws exception on extending an undefined service', () => {
|
|
118
|
-
const container = new Pimple();
|
|
119
|
-
|
|
120
|
-
expect(() => {
|
|
121
|
-
container.extend('foo', () => {});
|
|
122
|
-
}).toThrow('Definition with "foo" not defined in container.');
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('extends service', () => {
|
|
126
|
-
const container = new Pimple({
|
|
127
|
-
foo: () => {
|
|
128
|
-
return 'baz';
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
container.extend('foo', (initialService: string, container: Pimple) => {
|
|
133
|
-
return initialService + 'bar';
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
expect(container.get('foo')).toBe('bazbar');
|
|
137
|
-
});
|
|
138
|
-
});
|
package/tsconfig-cjs.json
DELETED
package/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2015",
|
|
4
|
-
"module": "ES2020",
|
|
5
|
-
"strict": true,
|
|
6
|
-
"esModuleInterop": true,
|
|
7
|
-
"noImplicitAny": true,
|
|
8
|
-
"declaration": true,
|
|
9
|
-
"sourceMap": true,
|
|
10
|
-
"experimentalDecorators": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"moduleResolution": "node",
|
|
13
|
-
"outDir": "./lib/esm",
|
|
14
|
-
"baseUrl": "."
|
|
15
|
-
},
|
|
16
|
-
"include": [
|
|
17
|
-
"src/"
|
|
18
|
-
]
|
|
19
|
-
}
|