@timesplinter/pimple 1.1.0 → 2.0.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/.github/workflows/publish.yml +18 -0
- package/.github/workflows/test.yml +5 -5
- package/README.md +13 -4
- package/jest.config.ts +19 -0
- package/lib/cjs/container.d.ts +4 -3
- package/lib/cjs/index.d.ts +2 -1
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/pimple.d.ts +20 -15
- package/lib/cjs/pimple.js +15 -18
- 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/index.d.ts +2 -1
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/pimple.d.ts +20 -15
- package/lib/esm/pimple.js +15 -18
- package/lib/esm/pimple.js.map +1 -1
- package/lib/esm/serviceProvider.d.ts +2 -2
- package/package.json +10 -9
- package/src/container.ts +4 -4
- package/src/index.ts +2 -0
- package/src/pimple.ts +35 -35
- package/src/serviceProvider.ts +2 -2
- package/tests/pimple.spec.ts +81 -25
- package/jest.config.json +0 -11
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name: Publish Package to npmjs
|
|
2
|
+
on:
|
|
3
|
+
release:
|
|
4
|
+
types: [published]
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
steps:
|
|
9
|
+
- uses: actions/checkout@v4
|
|
10
|
+
# Setup .npmrc file to publish to npm
|
|
11
|
+
- uses: actions/setup-node@v3
|
|
12
|
+
with:
|
|
13
|
+
node-version: '20.x'
|
|
14
|
+
registry-url: 'https://registry.npmjs.org'
|
|
15
|
+
- run: npm ci
|
|
16
|
+
- run: npm publish --access public
|
|
17
|
+
env:
|
|
18
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -4,10 +4,10 @@ on: [push]
|
|
|
4
4
|
|
|
5
5
|
jobs:
|
|
6
6
|
build:
|
|
7
|
-
|
|
8
7
|
runs-on: ubuntu-latest
|
|
9
|
-
|
|
10
8
|
steps:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
- uses: actions/checkout@v2
|
|
10
|
+
- name: Install modules
|
|
11
|
+
run: npm install
|
|
12
|
+
- name: Run coverage
|
|
13
|
+
run: npm run test:cov
|
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/jest.config.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type {Config} from 'jest';
|
|
2
|
+
|
|
3
|
+
const config: Config = {
|
|
4
|
+
coverageDirectory: "./build/coverage",
|
|
5
|
+
coverageReporters: ['text', 'html', 'lcov'],
|
|
6
|
+
coverageThreshold: {
|
|
7
|
+
global: {
|
|
8
|
+
branches: 80,
|
|
9
|
+
functions: 88,
|
|
10
|
+
lines: 93,
|
|
11
|
+
statements: 93
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
collectCoverageFrom: [
|
|
15
|
+
"src/**/*"
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default config;
|
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/index.d.ts
CHANGED
package/lib/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;AACA,sDAA6B;AAI3B,iBAJK,gBAAM,CAIL"}
|
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> | (S extends Function ? () => S : 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
|
*
|
|
@@ -12,7 +19,7 @@ declare type ProviderDeclaration = Function | ServiceProvider;
|
|
|
12
19
|
* @license LGPL
|
|
13
20
|
* @version 3.0.0
|
|
14
21
|
*/
|
|
15
|
-
export default class Pimple implements Container {
|
|
22
|
+
export default class Pimple<T> implements Container<T> {
|
|
16
23
|
/**
|
|
17
24
|
* @type {string}
|
|
18
25
|
*/
|
|
@@ -27,41 +34,39 @@ export default class Pimple implements Container {
|
|
|
27
34
|
* @private
|
|
28
35
|
*/
|
|
29
36
|
private _raw;
|
|
30
|
-
constructor(services?:
|
|
31
|
-
[key: string]: any;
|
|
32
|
-
});
|
|
37
|
+
constructor(services?: Partial<ServiceMap<T>>);
|
|
33
38
|
/**
|
|
34
39
|
* Define a service
|
|
35
40
|
*/
|
|
36
|
-
set(name:
|
|
41
|
+
set<K extends ServiceKey<T>>(name: K, service: ServiceDefinition<T, T[K]>): Pimple<T>;
|
|
37
42
|
/**
|
|
38
43
|
* Register a factory
|
|
39
44
|
*/
|
|
40
|
-
factory(name:
|
|
45
|
+
factory<K extends ServiceKey<T>>(name: K, callback: ServiceDefinition<T, T[K]>): Pimple<T>;
|
|
41
46
|
/**
|
|
42
47
|
* Get a service instance
|
|
43
48
|
*/
|
|
44
|
-
get(name:
|
|
49
|
+
get<K extends ServiceKey<T>>(name: K): T[K];
|
|
45
50
|
/**
|
|
46
51
|
* Checks whether a service is registered or not
|
|
47
52
|
*/
|
|
48
|
-
has(
|
|
53
|
+
has<K extends ServiceKey<T>>(name: K): boolean;
|
|
49
54
|
/**
|
|
50
55
|
* Register a protected function
|
|
51
56
|
*/
|
|
52
|
-
protect(
|
|
57
|
+
protect<T extends Function>(func: T): () => T;
|
|
53
58
|
/**
|
|
54
59
|
* Extend a service
|
|
55
60
|
*/
|
|
56
|
-
extend(serviceName:
|
|
61
|
+
extend<K extends ServiceKey<T>>(serviceName: K, service: Function): Function;
|
|
57
62
|
/**
|
|
58
63
|
* Get a service raw definition
|
|
59
64
|
*/
|
|
60
|
-
raw(name:
|
|
65
|
+
raw<K extends ServiceKey<T>>(name: K): ServiceDefinition<T, T[K]>;
|
|
61
66
|
/**
|
|
62
67
|
* Register a service provider
|
|
63
68
|
*/
|
|
64
|
-
register(provider: ProviderDeclaration): Pimple
|
|
69
|
+
register(provider: ProviderDeclaration<T>): Pimple<T>;
|
|
65
70
|
private instanceOfServiceProvider;
|
|
66
71
|
}
|
|
67
72
|
export {};
|
package/lib/cjs/pimple.js
CHANGED
|
@@ -18,6 +18,10 @@ const reservedProperties = [
|
|
|
18
18
|
* @version 3.0.0
|
|
19
19
|
*/
|
|
20
20
|
class Pimple {
|
|
21
|
+
/**
|
|
22
|
+
* @type {string}
|
|
23
|
+
*/
|
|
24
|
+
static get VERSION() { return '3.0.0'; }
|
|
21
25
|
constructor(services = {}) {
|
|
22
26
|
/**
|
|
23
27
|
* @type {{}}
|
|
@@ -30,13 +34,10 @@ class Pimple {
|
|
|
30
34
|
*/
|
|
31
35
|
this._raw = {};
|
|
32
36
|
Object.keys(services).forEach((service) => {
|
|
33
|
-
|
|
37
|
+
const serviceKey = service;
|
|
38
|
+
this.set(serviceKey, services[serviceKey]);
|
|
34
39
|
}, this);
|
|
35
40
|
}
|
|
36
|
-
/**
|
|
37
|
-
* @type {string}
|
|
38
|
-
*/
|
|
39
|
-
static get VERSION() { return '3.0.0'; }
|
|
40
41
|
/**
|
|
41
42
|
* Define a service
|
|
42
43
|
*/
|
|
@@ -52,7 +53,7 @@ class Pimple {
|
|
|
52
53
|
return cached;
|
|
53
54
|
};
|
|
54
55
|
}()) : service;
|
|
55
|
-
if (reservedProperties.indexOf(name) === -1) {
|
|
56
|
+
if (reservedProperties.indexOf(name.toString()) === -1) {
|
|
56
57
|
Object.defineProperty(this, name, {
|
|
57
58
|
get: () => {
|
|
58
59
|
return this.get(name);
|
|
@@ -67,7 +68,7 @@ class Pimple {
|
|
|
67
68
|
factory(name, callback) {
|
|
68
69
|
this._raw[name] = callback;
|
|
69
70
|
this._definitions[name] = callback;
|
|
70
|
-
if (reservedProperties.indexOf(name) === -1) {
|
|
71
|
+
if (reservedProperties.indexOf(name.toString()) === -1) {
|
|
71
72
|
Object.defineProperty(this, name, {
|
|
72
73
|
get: () => {
|
|
73
74
|
return this.get(name);
|
|
@@ -88,25 +89,23 @@ class Pimple {
|
|
|
88
89
|
/**
|
|
89
90
|
* Checks whether a service is registered or not
|
|
90
91
|
*/
|
|
91
|
-
has(
|
|
92
|
-
return
|
|
92
|
+
has(name) {
|
|
93
|
+
return name in this._definitions;
|
|
93
94
|
}
|
|
94
95
|
/**
|
|
95
96
|
* Register a protected function
|
|
96
97
|
*/
|
|
97
|
-
protect(
|
|
98
|
-
return () =>
|
|
99
|
-
return service;
|
|
100
|
-
};
|
|
98
|
+
protect(func) {
|
|
99
|
+
return () => func;
|
|
101
100
|
}
|
|
102
101
|
/**
|
|
103
102
|
* Extend a service
|
|
104
103
|
*/
|
|
105
104
|
extend(serviceName, service) {
|
|
106
105
|
if (!this._definitions[serviceName]) {
|
|
107
|
-
throw new RangeError(`Definition with "${serviceName}" not defined in container.`);
|
|
106
|
+
throw new RangeError(`Definition with "${serviceName.toString()}" not defined in container.`);
|
|
108
107
|
}
|
|
109
|
-
|
|
108
|
+
let def = this._definitions[serviceName];
|
|
110
109
|
return this._definitions[serviceName] = (container) => {
|
|
111
110
|
if (def instanceof Function) {
|
|
112
111
|
def = def(container);
|
|
@@ -126,11 +125,9 @@ class Pimple {
|
|
|
126
125
|
register(provider) {
|
|
127
126
|
if (this.instanceOfServiceProvider(provider) && provider.register instanceof Function) {
|
|
128
127
|
provider.register(this);
|
|
129
|
-
return this;
|
|
130
128
|
}
|
|
131
|
-
if (provider instanceof Function) {
|
|
129
|
+
else if (provider instanceof Function) {
|
|
132
130
|
provider(this);
|
|
133
|
-
return this;
|
|
134
131
|
}
|
|
135
132
|
return this;
|
|
136
133
|
}
|
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/index.d.ts
CHANGED
package/lib/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,UAAU,CAAA;AAE7B,OAAO,EAEL,MAAM,EAEP,CAAA"}
|
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> | (S extends Function ? () => S : 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
|
*
|
|
@@ -12,7 +19,7 @@ declare type ProviderDeclaration = Function | ServiceProvider;
|
|
|
12
19
|
* @license LGPL
|
|
13
20
|
* @version 3.0.0
|
|
14
21
|
*/
|
|
15
|
-
export default class Pimple implements Container {
|
|
22
|
+
export default class Pimple<T> implements Container<T> {
|
|
16
23
|
/**
|
|
17
24
|
* @type {string}
|
|
18
25
|
*/
|
|
@@ -27,41 +34,39 @@ export default class Pimple implements Container {
|
|
|
27
34
|
* @private
|
|
28
35
|
*/
|
|
29
36
|
private _raw;
|
|
30
|
-
constructor(services?:
|
|
31
|
-
[key: string]: any;
|
|
32
|
-
});
|
|
37
|
+
constructor(services?: Partial<ServiceMap<T>>);
|
|
33
38
|
/**
|
|
34
39
|
* Define a service
|
|
35
40
|
*/
|
|
36
|
-
set(name:
|
|
41
|
+
set<K extends ServiceKey<T>>(name: K, service: ServiceDefinition<T, T[K]>): Pimple<T>;
|
|
37
42
|
/**
|
|
38
43
|
* Register a factory
|
|
39
44
|
*/
|
|
40
|
-
factory(name:
|
|
45
|
+
factory<K extends ServiceKey<T>>(name: K, callback: ServiceDefinition<T, T[K]>): Pimple<T>;
|
|
41
46
|
/**
|
|
42
47
|
* Get a service instance
|
|
43
48
|
*/
|
|
44
|
-
get(name:
|
|
49
|
+
get<K extends ServiceKey<T>>(name: K): T[K];
|
|
45
50
|
/**
|
|
46
51
|
* Checks whether a service is registered or not
|
|
47
52
|
*/
|
|
48
|
-
has(
|
|
53
|
+
has<K extends ServiceKey<T>>(name: K): boolean;
|
|
49
54
|
/**
|
|
50
55
|
* Register a protected function
|
|
51
56
|
*/
|
|
52
|
-
protect(
|
|
57
|
+
protect<T extends Function>(func: T): () => T;
|
|
53
58
|
/**
|
|
54
59
|
* Extend a service
|
|
55
60
|
*/
|
|
56
|
-
extend(serviceName:
|
|
61
|
+
extend<K extends ServiceKey<T>>(serviceName: K, service: Function): Function;
|
|
57
62
|
/**
|
|
58
63
|
* Get a service raw definition
|
|
59
64
|
*/
|
|
60
|
-
raw(name:
|
|
65
|
+
raw<K extends ServiceKey<T>>(name: K): ServiceDefinition<T, T[K]>;
|
|
61
66
|
/**
|
|
62
67
|
* Register a service provider
|
|
63
68
|
*/
|
|
64
|
-
register(provider: ProviderDeclaration): Pimple
|
|
69
|
+
register(provider: ProviderDeclaration<T>): Pimple<T>;
|
|
65
70
|
private instanceOfServiceProvider;
|
|
66
71
|
}
|
|
67
72
|
export {};
|
package/lib/esm/pimple.js
CHANGED
|
@@ -17,6 +17,10 @@ const reservedProperties = [
|
|
|
17
17
|
* @version 3.0.0
|
|
18
18
|
*/
|
|
19
19
|
export default class Pimple {
|
|
20
|
+
/**
|
|
21
|
+
* @type {string}
|
|
22
|
+
*/
|
|
23
|
+
static get VERSION() { return '3.0.0'; }
|
|
20
24
|
constructor(services = {}) {
|
|
21
25
|
/**
|
|
22
26
|
* @type {{}}
|
|
@@ -29,13 +33,10 @@ export default class Pimple {
|
|
|
29
33
|
*/
|
|
30
34
|
this._raw = {};
|
|
31
35
|
Object.keys(services).forEach((service) => {
|
|
32
|
-
|
|
36
|
+
const serviceKey = service;
|
|
37
|
+
this.set(serviceKey, services[serviceKey]);
|
|
33
38
|
}, this);
|
|
34
39
|
}
|
|
35
|
-
/**
|
|
36
|
-
* @type {string}
|
|
37
|
-
*/
|
|
38
|
-
static get VERSION() { return '3.0.0'; }
|
|
39
40
|
/**
|
|
40
41
|
* Define a service
|
|
41
42
|
*/
|
|
@@ -51,7 +52,7 @@ export default class Pimple {
|
|
|
51
52
|
return cached;
|
|
52
53
|
};
|
|
53
54
|
}()) : service;
|
|
54
|
-
if (reservedProperties.indexOf(name) === -1) {
|
|
55
|
+
if (reservedProperties.indexOf(name.toString()) === -1) {
|
|
55
56
|
Object.defineProperty(this, name, {
|
|
56
57
|
get: () => {
|
|
57
58
|
return this.get(name);
|
|
@@ -66,7 +67,7 @@ export default class Pimple {
|
|
|
66
67
|
factory(name, callback) {
|
|
67
68
|
this._raw[name] = callback;
|
|
68
69
|
this._definitions[name] = callback;
|
|
69
|
-
if (reservedProperties.indexOf(name) === -1) {
|
|
70
|
+
if (reservedProperties.indexOf(name.toString()) === -1) {
|
|
70
71
|
Object.defineProperty(this, name, {
|
|
71
72
|
get: () => {
|
|
72
73
|
return this.get(name);
|
|
@@ -87,25 +88,23 @@ export default class Pimple {
|
|
|
87
88
|
/**
|
|
88
89
|
* Checks whether a service is registered or not
|
|
89
90
|
*/
|
|
90
|
-
has(
|
|
91
|
-
return
|
|
91
|
+
has(name) {
|
|
92
|
+
return name in this._definitions;
|
|
92
93
|
}
|
|
93
94
|
/**
|
|
94
95
|
* Register a protected function
|
|
95
96
|
*/
|
|
96
|
-
protect(
|
|
97
|
-
return () =>
|
|
98
|
-
return service;
|
|
99
|
-
};
|
|
97
|
+
protect(func) {
|
|
98
|
+
return () => func;
|
|
100
99
|
}
|
|
101
100
|
/**
|
|
102
101
|
* Extend a service
|
|
103
102
|
*/
|
|
104
103
|
extend(serviceName, service) {
|
|
105
104
|
if (!this._definitions[serviceName]) {
|
|
106
|
-
throw new RangeError(`Definition with "${serviceName}" not defined in container.`);
|
|
105
|
+
throw new RangeError(`Definition with "${serviceName.toString()}" not defined in container.`);
|
|
107
106
|
}
|
|
108
|
-
|
|
107
|
+
let def = this._definitions[serviceName];
|
|
109
108
|
return this._definitions[serviceName] = (container) => {
|
|
110
109
|
if (def instanceof Function) {
|
|
111
110
|
def = def(container);
|
|
@@ -125,11 +124,9 @@ export default class Pimple {
|
|
|
125
124
|
register(provider) {
|
|
126
125
|
if (this.instanceOfServiceProvider(provider) && provider.register instanceof Function) {
|
|
127
126
|
provider.register(this);
|
|
128
|
-
return this;
|
|
129
127
|
}
|
|
130
|
-
if (provider instanceof Function) {
|
|
128
|
+
else if (provider instanceof Function) {
|
|
131
129
|
provider(this);
|
|
132
|
-
return this;
|
|
133
130
|
}
|
|
134
131
|
return this;
|
|
135
132
|
}
|
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,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timesplinter/pimple",
|
|
3
3
|
"license": "LGPL-3.0-or-later",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "2.0.0",
|
|
5
5
|
"module": "./lib/esm/index.js",
|
|
6
6
|
"main": "./lib/cjs/index.js",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"test": "jest",
|
|
9
|
-
"
|
|
9
|
+
"test:cov": "jest --collect-coverage",
|
|
10
10
|
"transpile": "tsc -p tsconfig.json && tsc -p tsconfig-cjs.json",
|
|
11
11
|
"prepublish": "npm run transpile"
|
|
12
12
|
},
|
|
@@ -14,12 +14,13 @@
|
|
|
14
14
|
"author": "Pascal Münst <dev@timesplinter.ch>",
|
|
15
15
|
"description": "A simple dependency-injection container written in TypeScript based on PHP's Pimple",
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@babel/core": "^7.
|
|
18
|
-
"@babel/preset-env": "^7.
|
|
19
|
-
"@babel/preset-typescript": "^7.
|
|
20
|
-
"@types/jest": "^
|
|
21
|
-
"babel-jest": "^
|
|
22
|
-
"jest": "^
|
|
23
|
-
"typescript": "^4.
|
|
17
|
+
"@babel/core": "^7.23.9",
|
|
18
|
+
"@babel/preset-env": "^7.23.9",
|
|
19
|
+
"@babel/preset-typescript": "^7.23.3",
|
|
20
|
+
"@types/jest": "^29.5.11",
|
|
21
|
+
"babel-jest": "^29.7.0",
|
|
22
|
+
"jest": "^29.7.0",
|
|
23
|
+
"typescript": "^4.9.5",
|
|
24
|
+
"ts-node": "^10.9.2"
|
|
24
25
|
}
|
|
25
26
|
}
|
package/src/container.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
export type ServiceKey<T> = keyof T;
|
|
2
2
|
|
|
3
|
-
export default interface Container
|
|
3
|
+
export default interface Container<T>
|
|
4
4
|
{
|
|
5
|
-
get(
|
|
5
|
+
get<K extends ServiceKey<T>>(key: K): T[K];
|
|
6
6
|
|
|
7
|
-
has(
|
|
7
|
+
has<K extends ServiceKey<T>>(key: K): boolean;
|
|
8
8
|
}
|
package/src/index.ts
CHANGED
package/src/pimple.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import Container from "./container";
|
|
3
|
+
import Container, {ServiceKey} from "./container";
|
|
4
4
|
import ServiceProvider from "./serviceProvider";
|
|
5
5
|
|
|
6
6
|
/** Declaration types */
|
|
7
|
-
type
|
|
8
|
-
type ProviderDeclaration =
|
|
7
|
+
type ServiceProviderFunction<T> = (container: Pimple<T>) => void;
|
|
8
|
+
type ProviderDeclaration<T> = ServiceProviderFunction<T>|ServiceProvider<T>;
|
|
9
|
+
type LazyServiceDefinition<T, S> = (container: Pimple<T>) => S;
|
|
10
|
+
type ProtectedServiceDefinition<T, S> = () => LazyServiceDefinition<T, S>;
|
|
11
|
+
type PlainServiceDefinition<S> = S extends Function ? () => S : S; // If a function, it needs to be wrapped/protected
|
|
12
|
+
type ServiceDefinition<T, S> = PlainServiceDefinition<S>|LazyServiceDefinition<T, S>|ProtectedServiceDefinition<T, S>|(S extends Function ? () => S : S);
|
|
13
|
+
type ServiceMap<T> = { [key in ServiceKey<T>]: ServiceDefinition<T, T[ServiceKey<T>]> };
|
|
9
14
|
|
|
10
15
|
/**
|
|
11
16
|
* Reserved names of properties
|
|
@@ -25,7 +30,7 @@ const reservedProperties: string[] = [
|
|
|
25
30
|
* @license LGPL
|
|
26
31
|
* @version 3.0.0
|
|
27
32
|
*/
|
|
28
|
-
export default class Pimple implements Container
|
|
33
|
+
export default class Pimple<T> implements Container<T>
|
|
29
34
|
{
|
|
30
35
|
/**
|
|
31
36
|
* @type {string}
|
|
@@ -36,31 +41,32 @@ export default class Pimple implements Container
|
|
|
36
41
|
* @type {{}}
|
|
37
42
|
* @private
|
|
38
43
|
*/
|
|
39
|
-
private _definitions:
|
|
44
|
+
private _definitions: Partial<ServiceMap<T>> = {};
|
|
40
45
|
|
|
41
46
|
/**
|
|
42
47
|
* @type {{}}
|
|
43
48
|
* @private
|
|
44
49
|
*/
|
|
45
|
-
private _raw:
|
|
50
|
+
private _raw: Partial<ServiceMap<T>> = {};
|
|
46
51
|
|
|
47
|
-
constructor(services:
|
|
52
|
+
constructor(services: Partial<ServiceMap<T>> = {}) {
|
|
48
53
|
Object.keys(services).forEach((service) => {
|
|
49
|
-
|
|
54
|
+
const serviceKey = service as ServiceKey<T>;
|
|
55
|
+
this.set(serviceKey, services[serviceKey] as ServiceDefinition<T, T[ServiceKey<T>]>);
|
|
50
56
|
}, this);
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
/**
|
|
54
60
|
* Define a service
|
|
55
61
|
*/
|
|
56
|
-
public set(name:
|
|
62
|
+
public set<K extends ServiceKey<T>>(name: K, service: ServiceDefinition<T,T[K]>): Pimple<T>
|
|
57
63
|
{
|
|
58
64
|
this._raw[name] = service;
|
|
59
65
|
|
|
60
66
|
this._definitions[name] = service instanceof Function ?
|
|
61
67
|
(function () {
|
|
62
68
|
let cached: any;
|
|
63
|
-
return (pimple: Pimple) => {
|
|
69
|
+
return (pimple: Pimple<T>) => {
|
|
64
70
|
if (cached === undefined) {
|
|
65
71
|
cached = service(pimple);
|
|
66
72
|
}
|
|
@@ -68,7 +74,7 @@ export default class Pimple implements Container
|
|
|
68
74
|
};
|
|
69
75
|
}()) : service;
|
|
70
76
|
|
|
71
|
-
if (reservedProperties.indexOf(name) === -1) {
|
|
77
|
+
if (reservedProperties.indexOf(name.toString()) === -1) {
|
|
72
78
|
Object.defineProperty(this, name, {
|
|
73
79
|
get: () => {
|
|
74
80
|
return this.get(name);
|
|
@@ -82,11 +88,11 @@ export default class Pimple implements Container
|
|
|
82
88
|
/**
|
|
83
89
|
* Register a factory
|
|
84
90
|
*/
|
|
85
|
-
public factory(name:
|
|
91
|
+
public factory<K extends ServiceKey<T>>(name: K, callback: ServiceDefinition<T,T[K]>): Pimple<T> {
|
|
86
92
|
this._raw[name] = callback;
|
|
87
93
|
this._definitions[name] = callback;
|
|
88
94
|
|
|
89
|
-
if (reservedProperties.indexOf(name) === -1) {
|
|
95
|
+
if (reservedProperties.indexOf(name.toString()) === -1) {
|
|
90
96
|
Object.defineProperty(this, name, {
|
|
91
97
|
get: () => {
|
|
92
98
|
return this.get(name);
|
|
@@ -100,40 +106,38 @@ export default class Pimple implements Container
|
|
|
100
106
|
/**
|
|
101
107
|
* Get a service instance
|
|
102
108
|
*/
|
|
103
|
-
public get(name:
|
|
109
|
+
public get<K extends ServiceKey<T>>(name: K): T[K] {
|
|
104
110
|
if (this._definitions[name] instanceof Function) {
|
|
105
|
-
return this._definitions[name](this);
|
|
111
|
+
return (this._definitions[name] as LazyServiceDefinition<T, T[K]>)(this);
|
|
106
112
|
}
|
|
107
|
-
return this._definitions[name];
|
|
113
|
+
return this._definitions[name] as T[K];
|
|
108
114
|
}
|
|
109
115
|
|
|
110
116
|
/**
|
|
111
117
|
* Checks whether a service is registered or not
|
|
112
118
|
*/
|
|
113
|
-
public has(
|
|
114
|
-
return
|
|
119
|
+
public has<K extends ServiceKey<T>>(name: K): boolean {
|
|
120
|
+
return name in this._definitions;
|
|
115
121
|
}
|
|
116
122
|
|
|
117
123
|
/**
|
|
118
124
|
* Register a protected function
|
|
119
125
|
*/
|
|
120
|
-
public protect(
|
|
121
|
-
return () =>
|
|
122
|
-
return service;
|
|
123
|
-
};
|
|
126
|
+
public protect<T extends Function>(func: T): () => T {
|
|
127
|
+
return () => func;
|
|
124
128
|
}
|
|
125
129
|
|
|
126
130
|
/**
|
|
127
131
|
* Extend a service
|
|
128
132
|
*/
|
|
129
|
-
public extend(serviceName:
|
|
133
|
+
public extend<K extends ServiceKey<T>>(serviceName: K, service: Function): Function {
|
|
130
134
|
if (!this._definitions[serviceName]) {
|
|
131
|
-
throw new RangeError(`Definition with "${serviceName}" not defined in container.`);
|
|
135
|
+
throw new RangeError(`Definition with "${serviceName.toString()}" not defined in container.`);
|
|
132
136
|
}
|
|
133
137
|
|
|
134
|
-
|
|
138
|
+
let def = this._definitions[serviceName];
|
|
135
139
|
|
|
136
|
-
return this._definitions[serviceName] = (container: Pimple) => {
|
|
140
|
+
return this._definitions[serviceName] = (container: Pimple<T>) => {
|
|
137
141
|
if (def instanceof Function) {
|
|
138
142
|
def = def(container);
|
|
139
143
|
}
|
|
@@ -144,28 +148,24 @@ export default class Pimple implements Container
|
|
|
144
148
|
/**
|
|
145
149
|
* Get a service raw definition
|
|
146
150
|
*/
|
|
147
|
-
public raw(name:
|
|
148
|
-
return this._raw[name]
|
|
151
|
+
public raw<K extends ServiceKey<T>>(name: K): ServiceDefinition<T, T[K]> {
|
|
152
|
+
return this._raw[name] as ServiceDefinition<T, T[K]>;
|
|
149
153
|
}
|
|
150
154
|
|
|
151
155
|
/**
|
|
152
156
|
* Register a service provider
|
|
153
157
|
*/
|
|
154
|
-
public register(provider: ProviderDeclaration): Pimple {
|
|
158
|
+
public register(provider: ProviderDeclaration<T>): Pimple<T> {
|
|
155
159
|
if (this.instanceOfServiceProvider(provider) && provider.register instanceof Function) {
|
|
156
160
|
provider.register(this);
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (provider instanceof Function) {
|
|
161
|
+
} else if (provider instanceof Function) {
|
|
161
162
|
provider(this);
|
|
162
|
-
return this;
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
return this;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
private instanceOfServiceProvider(object: any): object is ServiceProvider {
|
|
168
|
+
private instanceOfServiceProvider(object: any): object is ServiceProvider<T> {
|
|
169
169
|
return 'register' in object;
|
|
170
170
|
}
|
|
171
171
|
}
|
package/src/serviceProvider.ts
CHANGED
|
@@ -3,7 +3,7 @@ import Pimple from "./pimple";
|
|
|
3
3
|
/**
|
|
4
4
|
* Service provider class for service injecting in Pimple container
|
|
5
5
|
*/
|
|
6
|
-
export default interface ServiceProvider
|
|
6
|
+
export default interface ServiceProvider<T>
|
|
7
7
|
{
|
|
8
|
-
register(container: Pimple): void;
|
|
8
|
+
register(container: Pimple<T>): void;
|
|
9
9
|
}
|
package/tests/pimple.spec.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import Pimple from '../src/pimple';
|
|
2
|
+
import {ServiceProvider} from "../src/index.js";
|
|
2
3
|
|
|
3
4
|
describe('pimple container', () => {
|
|
4
|
-
it('returns container
|
|
5
|
+
it('returns container version', async () => {
|
|
5
6
|
expect(Pimple.VERSION).toBe('3.0.0');
|
|
6
7
|
});
|
|
7
8
|
|
|
8
9
|
it('stores values', async () => {
|
|
9
|
-
|
|
10
|
+
type ServiceMap = {
|
|
11
|
+
'baz': number,
|
|
12
|
+
'foo': string,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const container = new Pimple<ServiceMap>({baz: 42});
|
|
10
16
|
|
|
11
17
|
container.set('foo', 'bar');
|
|
12
18
|
|
|
@@ -15,7 +21,12 @@ describe('pimple container', () => {
|
|
|
15
21
|
});
|
|
16
22
|
|
|
17
23
|
it('resolves function', async () => {
|
|
18
|
-
|
|
24
|
+
type ServiceMap = {
|
|
25
|
+
'baz': number,
|
|
26
|
+
'foo': string,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const container = new Pimple<ServiceMap>();
|
|
19
30
|
|
|
20
31
|
container.set('foo', () => {
|
|
21
32
|
return 'baz';
|
|
@@ -25,7 +36,11 @@ describe('pimple container', () => {
|
|
|
25
36
|
});
|
|
26
37
|
|
|
27
38
|
it('resolves function only once', async () => {
|
|
28
|
-
|
|
39
|
+
type ServiceMap = {
|
|
40
|
+
'foo': number,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const container = new Pimple<ServiceMap>();
|
|
29
44
|
|
|
30
45
|
container.set('foo', () => {
|
|
31
46
|
return Math.random();
|
|
@@ -35,7 +50,11 @@ describe('pimple container', () => {
|
|
|
35
50
|
});
|
|
36
51
|
|
|
37
52
|
it('returns true if service exists', async () => {
|
|
38
|
-
|
|
53
|
+
type ServiceMap = {
|
|
54
|
+
'foo': number,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const container = new Pimple<ServiceMap>();
|
|
39
58
|
|
|
40
59
|
container.set('foo', () => {
|
|
41
60
|
return 42;
|
|
@@ -45,40 +64,61 @@ describe('pimple container', () => {
|
|
|
45
64
|
});
|
|
46
65
|
|
|
47
66
|
it('returns true if service exists', async () => {
|
|
48
|
-
|
|
67
|
+
type ServiceMap = {
|
|
68
|
+
'foo': number,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const container = new Pimple<ServiceMap>();
|
|
49
72
|
|
|
50
73
|
expect(container.has('foo')).toBe(false);
|
|
51
74
|
});
|
|
52
75
|
|
|
53
76
|
it('protects function', async () => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
77
|
+
type ServiceMap = {
|
|
78
|
+
foo: () => string,
|
|
79
|
+
baz: () => string,
|
|
80
|
+
untyped: Function,
|
|
58
81
|
};
|
|
59
82
|
|
|
60
|
-
container
|
|
83
|
+
const container = new Pimple<ServiceMap>();
|
|
84
|
+
|
|
85
|
+
const typeProtectedFunction = () => 'baz';
|
|
86
|
+
const untypedProtectedFunction = () => 42;
|
|
87
|
+
|
|
88
|
+
container.set('foo', container.protect(typeProtectedFunction));
|
|
89
|
+
container.set('baz', () => typeProtectedFunction);
|
|
90
|
+
container.set('untyped', container.protect(untypedProtectedFunction));
|
|
61
91
|
|
|
62
|
-
expect(container.get('foo')).toBe(
|
|
92
|
+
expect(container.get('foo')).toBe(typeProtectedFunction);
|
|
93
|
+
expect(container.get('baz')).toBe(typeProtectedFunction);
|
|
94
|
+
expect(container.get('untyped')).toBe(untypedProtectedFunction);
|
|
63
95
|
});
|
|
64
96
|
|
|
65
97
|
it('returns original function', async () => {
|
|
66
|
-
|
|
98
|
+
type ServiceMap = {
|
|
99
|
+
foo: string,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const container = new Pimple<ServiceMap>();
|
|
67
103
|
|
|
68
|
-
const
|
|
104
|
+
const protectedFunction = () => {
|
|
69
105
|
return 'baz';
|
|
70
106
|
};
|
|
71
107
|
|
|
72
|
-
container.set('foo',
|
|
108
|
+
container.set('foo', protectedFunction);
|
|
73
109
|
|
|
74
|
-
expect(container.raw('foo')).toBe(
|
|
110
|
+
expect(container.raw('foo')).toBe(protectedFunction);
|
|
75
111
|
});
|
|
76
112
|
|
|
77
113
|
it('registers services defined in service provider', async () => {
|
|
78
|
-
|
|
114
|
+
type ServiceMap = {
|
|
115
|
+
'foo': string,
|
|
116
|
+
}
|
|
79
117
|
|
|
80
|
-
const
|
|
81
|
-
|
|
118
|
+
const container = new Pimple<ServiceMap>();
|
|
119
|
+
|
|
120
|
+
const serviceProviderMock: ServiceProvider<ServiceMap> = {
|
|
121
|
+
register: (container: Pimple<ServiceMap>) => {
|
|
82
122
|
container.set('foo', () => {
|
|
83
123
|
return 'baz'
|
|
84
124
|
});
|
|
@@ -91,9 +131,13 @@ describe('pimple container', () => {
|
|
|
91
131
|
});
|
|
92
132
|
|
|
93
133
|
it('registers services defined in function', async () => {
|
|
94
|
-
|
|
134
|
+
type ServiceMap = {
|
|
135
|
+
foo: string,
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const container = new Pimple<ServiceMap>();
|
|
95
139
|
|
|
96
|
-
const serviceProviderMock = (container: Pimple) => {
|
|
140
|
+
const serviceProviderMock = (container: Pimple<ServiceMap>) => {
|
|
97
141
|
container.set('foo', () => {
|
|
98
142
|
return 'baz'
|
|
99
143
|
});
|
|
@@ -105,7 +149,11 @@ describe('pimple container', () => {
|
|
|
105
149
|
});
|
|
106
150
|
|
|
107
151
|
it('returns new instance from factory', async () => {
|
|
108
|
-
|
|
152
|
+
type ServiceMap = {
|
|
153
|
+
foo: number,
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const container = new Pimple<ServiceMap>();
|
|
109
157
|
|
|
110
158
|
container.factory('foo', () => {
|
|
111
159
|
return Math.random();
|
|
@@ -115,7 +163,11 @@ describe('pimple container', () => {
|
|
|
115
163
|
});
|
|
116
164
|
|
|
117
165
|
it('throws exception on extending an undefined service', () => {
|
|
118
|
-
|
|
166
|
+
type ServiceMap = {
|
|
167
|
+
foo: string,
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const container = new Pimple<ServiceMap>();
|
|
119
171
|
|
|
120
172
|
expect(() => {
|
|
121
173
|
container.extend('foo', () => {});
|
|
@@ -123,13 +175,17 @@ describe('pimple container', () => {
|
|
|
123
175
|
});
|
|
124
176
|
|
|
125
177
|
it('extends service', () => {
|
|
126
|
-
|
|
178
|
+
type ServiceMap = {
|
|
179
|
+
foo: string,
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const container = new Pimple<ServiceMap>({
|
|
127
183
|
foo: () => {
|
|
128
184
|
return 'baz';
|
|
129
185
|
}
|
|
130
186
|
});
|
|
131
187
|
|
|
132
|
-
container.extend('foo', (initialService: string, container: Pimple) => {
|
|
188
|
+
container.extend('foo', (initialService: string, container: Pimple<ServiceMap>) => {
|
|
133
189
|
return initialService + 'bar';
|
|
134
190
|
});
|
|
135
191
|
|