@timesplinter/pimple 1.1.1 → 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.
@@ -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
- - uses: actions/checkout@v1
12
- - name: Run Jest
13
- uses: stefanoeb/jest-action@1.0.3
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
- ```js
12
+ ```ts
13
13
  import Pimple from '@timesplinter/pimple';
14
14
 
15
- const container: Container = new Pimple({env: 'dev'});
15
+ type ServiceMap = {
16
+ 'foo': string,
17
+ 'bar': string,
18
+ };
16
19
 
17
- container.set('foo', (container: Pimple) => {
18
- return `bar (${container.get('env')})`;
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;
@@ -1,4 +1,5 @@
1
- export default interface Container {
2
- get(service: string): any;
3
- has(service: string): boolean;
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
  }
@@ -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
- declare type ServiceDeclaration = Function | Object;
5
- declare type ProviderDeclaration = Function | ServiceProvider;
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: string, service: ServiceDeclaration): Pimple;
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: string, callback: Function): Pimple;
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: string): any;
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(service: string): boolean;
53
+ has<K extends ServiceKey<T>>(name: K): boolean;
49
54
  /**
50
55
  * Register a protected function
51
56
  */
52
- protect(service: Function): Function;
57
+ protect<T extends Function>(func: T): () => T;
53
58
  /**
54
59
  * Extend a service
55
60
  */
56
- extend(serviceName: string, service: Function): Function;
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: string): Function;
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
- this.set(service, services[service]);
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(service) {
92
- return service in this._definitions;
92
+ has(name) {
93
+ return name in this._definitions;
93
94
  }
94
95
  /**
95
96
  * Register a protected function
96
97
  */
97
- protect(service) {
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
- var def = this._definitions[serviceName];
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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pimple.js","sourceRoot":"","sources":["../../src/pimple.ts"],"names":[],"mappings":"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"}
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
  }
@@ -1,4 +1,5 @@
1
- export default interface Container {
2
- get(service: string): any;
3
- has(service: string): boolean;
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
  }
@@ -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
- declare type ServiceDeclaration = Function | Object;
5
- declare type ProviderDeclaration = Function | ServiceProvider;
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: string, service: ServiceDeclaration): Pimple;
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: string, callback: Function): Pimple;
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: string): any;
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(service: string): boolean;
53
+ has<K extends ServiceKey<T>>(name: K): boolean;
49
54
  /**
50
55
  * Register a protected function
51
56
  */
52
- protect(service: Function): Function;
57
+ protect<T extends Function>(func: T): () => T;
53
58
  /**
54
59
  * Extend a service
55
60
  */
56
- extend(serviceName: string, service: Function): Function;
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: string): Function;
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
- this.set(service, services[service]);
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(service) {
91
- return service in this._definitions;
91
+ has(name) {
92
+ return name in this._definitions;
92
93
  }
93
94
  /**
94
95
  * Register a protected function
95
96
  */
96
- protect(service) {
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
- var def = this._definitions[serviceName];
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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pimple.js","sourceRoot":"","sources":["../../src/pimple.ts"],"names":[],"mappings":"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"}
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": "1.1.1",
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
- "coverage": "jest --collect-coverage",
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.14.3",
18
- "@babel/preset-env": "^7.14.4",
19
- "@babel/preset-typescript": "^7.13.0",
20
- "@types/jest": "^26.0.23",
21
- "babel-jest": "^27.0.2",
22
- "jest": "^27.0.4",
23
- "typescript": "^4.3.2"
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
- import ServiceProvider from './serviceProvider';
1
+ export type ServiceKey<T> = keyof T;
2
2
 
3
- export default interface Container
3
+ export default interface Container<T>
4
4
  {
5
- get(service: string): any;
5
+ get<K extends ServiceKey<T>>(key: K): T[K];
6
6
 
7
- has(service: string): boolean;
7
+ has<K extends ServiceKey<T>>(key: K): boolean;
8
8
  }
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 ServiceDeclaration = Function|Object;
8
- type ProviderDeclaration = Function|ServiceProvider;
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: { [key: string]: any; } = {};
44
+ private _definitions: Partial<ServiceMap<T>> = {};
40
45
 
41
46
  /**
42
47
  * @type {{}}
43
48
  * @private
44
49
  */
45
- private _raw: { [key: string]: any; } = {};
50
+ private _raw: Partial<ServiceMap<T>> = {};
46
51
 
47
- constructor(services: { [key: string]: any; } = {}) {
52
+ constructor(services: Partial<ServiceMap<T>> = {}) {
48
53
  Object.keys(services).forEach((service) => {
49
- this.set(service, services[service]);
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: string, service: ServiceDeclaration): Pimple
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: string, callback: Function): Pimple {
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: string): any {
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(service: string): boolean {
114
- return service in this._definitions;
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(service: Function): Function {
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: string, service: Function): Function {
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
- var def = this._definitions[serviceName];
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: string): Function {
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
- return this;
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
  }
@@ -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
  }
@@ -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 verison', async () => {
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
- const container = new Pimple({baz: 42});
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
- const container = new Pimple();
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
- const container = new Pimple();
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
- const container = new Pimple();
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
- const container = new Pimple();
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
- const container = new Pimple();
55
-
56
- const protectedFunciton = () => {
57
- return 'baz';
77
+ type ServiceMap = {
78
+ foo: () => string,
79
+ baz: () => string,
80
+ untyped: Function,
58
81
  };
59
82
 
60
- container.set('foo', container.protect(protectedFunciton));
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(protectedFunciton);
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
- const container = new Pimple();
98
+ type ServiceMap = {
99
+ foo: string,
100
+ };
101
+
102
+ const container = new Pimple<ServiceMap>();
67
103
 
68
- const protectedFunciton = () => {
104
+ const protectedFunction = () => {
69
105
  return 'baz';
70
106
  };
71
107
 
72
- container.set('foo', protectedFunciton);
108
+ container.set('foo', protectedFunction);
73
109
 
74
- expect(container.raw('foo')).toBe(protectedFunciton);
110
+ expect(container.raw('foo')).toBe(protectedFunction);
75
111
  });
76
112
 
77
113
  it('registers services defined in service provider', async () => {
78
- const container = new Pimple();
114
+ type ServiceMap = {
115
+ 'foo': string,
116
+ }
79
117
 
80
- const serviceProviderMock = {
81
- register: (container: Pimple) => {
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
- const container = new Pimple();
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
- const container = new Pimple();
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
- const container = new Pimple();
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
- const container = new Pimple({
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
 
package/jest.config.json DELETED
@@ -1,11 +0,0 @@
1
- {
2
- "coverageDirectory": "./build/coverage",
3
- "coverageThreshold": {
4
- "global": {
5
- "branches": 80,
6
- "functions": 88,
7
- "lines": 93,
8
- "statements": 93
9
- }
10
- }
11
- }