@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 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)';
@@ -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>;
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 3.0.0
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
- * @type {{}}
27
- * @private
30
+ * Define a service (first-time registration only)
28
31
  */
29
- private _raw;
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
- * Define a service
34
+ * Replace an existing service definition before it has been resolved
35
35
  */
36
- set(name: string, service: ServiceDeclaration): Pimple;
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: string, callback: Function): Pimple;
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: string): any;
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(service: string): boolean;
49
+ has<K extends ServiceKey<T>>(name: K): boolean;
49
50
  /**
50
51
  * Register a protected function
51
52
  */
52
- protect(service: Function): Function;
53
+ protect<T extends Function>(func: T): () => T;
53
54
  /**
54
55
  * Extend a service
55
56
  */
56
- extend(serviceName: string, service: Function): Function;
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: string): Function;
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 3.0.0
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
- this.set(service, services[service]);
28
+ const serviceKey = service;
29
+ this.set(serviceKey, services[serviceKey]);
34
30
  }, this);
35
31
  }
36
32
  /**
37
- * @type {string}
33
+ * Define a service (first-time registration only)
38
34
  */
39
- static get VERSION() { return '3.0.0'; }
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
- * Define a service
42
+ * Replace an existing service definition before it has been resolved
42
43
  */
43
- set(name, service) {
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
- return this._definitions[name](this);
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(service) {
92
- return service in this._definitions;
123
+ has(name) {
124
+ return name in this._definitions;
93
125
  }
94
126
  /**
95
127
  * Register a protected function
96
128
  */
97
- protect(service) {
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
- var def = this._definitions[serviceName];
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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pimple.js","sourceRoot":"","sources":["../../src/pimple.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AASb;;GAEG;AACH,MAAM,kBAAkB,GAAa;IACjC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK;IAC9B,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa;IAC7C,WAAW;CACd,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAqB,MAAM;IAmBvB,YAAY,WAAoC,EAAE;QAZlD;;;WAGG;QACK,iBAAY,GAA4B,EAAE,CAAC;QAEnD;;;WAGG;QACK,SAAI,GAA4B,EAAE,CAAC;QAGvC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YACtC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QACzC,CAAC,EAAE,IAAI,CAAC,CAAC;IACb,CAAC;IArBD;;OAEG;IACH,MAAM,KAAK,OAAO,KAAK,OAAO,OAAO,CAAC,CAAC,CAAC;IAoBxC;;OAEG;IACI,GAAG,CAAC,IAAY,EAAE,OAA2B;QAEhD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;QAE1B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,OAAO,YAAY,QAAQ,CAAC,CAAC;YACnD,CAAC;gBACG,IAAI,MAAW,CAAC;gBAChB,OAAO,CAAC,MAAc,EAAE,EAAE;oBACtB,IAAI,MAAM,KAAK,SAAS,EAAE;wBACtB,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;qBAC5B;oBACD,OAAO,MAAM,CAAC;gBAClB,CAAC,CAAC;YACN,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAEnB,IAAI,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE;YACzC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE;gBAC9B,GAAG,EAAE,GAAG,EAAE;oBACN,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC1B,CAAC;aACJ,CAAC,CAAC;SACN;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;OAEG;IACI,OAAO,CAAC,IAAY,EAAE,QAAkB;QAC3C,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAW,QAAQ,CAAC;QACnC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;QAEnC,IAAI,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE;YACzC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE;gBAC9B,GAAG,EAAE,GAAG,EAAE;oBACN,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC1B,CAAC;aACJ,CAAC,CAAC;SACN;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;OAEG;IACI,GAAG,CAAC,IAAY;QACnB,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,QAAQ,EAAE;YAC7C,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;SACxC;QACD,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED;;OAEG;IACI,GAAG,CAAC,OAAe;QACtB,OAAO,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC;IACxC,CAAC;IAED;;OAEG;IACI,OAAO,CAAC,OAAiB;QAC5B,OAAO,GAAG,EAAE;YACR,OAAO,OAAO,CAAC;QACnB,CAAC,CAAC;IACN,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,WAAmB,EAAE,OAAiB;QAChD,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE;YACjC,MAAM,IAAI,UAAU,CAAC,oBAAoB,WAAW,6BAA6B,CAAC,CAAC;SACtF;QAED,IAAI,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;QAEzC,OAAO,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC,SAAiB,EAAE,EAAE;YAC1D,IAAI,GAAG,YAAY,QAAQ,EAAE;gBACzB,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;aACxB;YACD,OAAO,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACnC,CAAC,CAAC;IACN,CAAC;IAED;;OAEG;IACI,GAAG,CAAC,IAAY;QACnB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED;;OAEG;IACI,QAAQ,CAAC,QAA6B;QACzC,IAAI,IAAI,CAAC,yBAAyB,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,QAAQ,YAAY,QAAQ,EAAE;YACnF,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACxB,OAAO,IAAI,CAAC;SACf;QAED,IAAI,QAAQ,YAAY,QAAQ,EAAE;YAC9B,QAAQ,CAAC,IAAI,CAAC,CAAC;YACf,OAAO,IAAI,CAAC;SACf;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;IAEO,yBAAyB,CAAC,MAAW;QACzC,OAAO,UAAU,IAAI,MAAM,CAAC;IAChC,CAAC;CACJ;AA/ID,yBA+IC"}
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>;
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 3.0.0
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
- * @type {{}}
27
- * @private
30
+ * Define a service (first-time registration only)
28
31
  */
29
- private _raw;
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
- * Define a service
34
+ * Replace an existing service definition before it has been resolved
35
35
  */
36
- set(name: string, service: ServiceDeclaration): Pimple;
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: string, callback: Function): Pimple;
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: string): any;
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(service: string): boolean;
49
+ has<K extends ServiceKey<T>>(name: K): boolean;
49
50
  /**
50
51
  * Register a protected function
51
52
  */
52
- protect(service: Function): Function;
53
+ protect<T extends Function>(func: T): () => T;
53
54
  /**
54
55
  * Extend a service
55
56
  */
56
- extend(serviceName: string, service: Function): Function;
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: string): Function;
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 3.0.0
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
- this.set(service, services[service]);
27
+ const serviceKey = service;
28
+ this.set(serviceKey, services[serviceKey]);
33
29
  }, this);
34
30
  }
35
31
  /**
36
- * @type {string}
32
+ * Define a service (first-time registration only)
37
33
  */
38
- static get VERSION() { return '3.0.0'; }
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
- * Define a service
41
+ * Replace an existing service definition before it has been resolved
41
42
  */
42
- set(name, service) {
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
- return this._definitions[name](this);
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(service) {
91
- return service in this._definitions;
122
+ has(name) {
123
+ return name in this._definitions;
92
124
  }
93
125
  /**
94
126
  * Register a protected function
95
127
  */
96
- protect(service) {
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
- var def = this._definitions[serviceName];
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
  }
@@ -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":"AAAA,YAAY,CAAC;AAcb;;GAEG;AACH,MAAM,kBAAkB,GAAa;IACjC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK;IAC9B,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa;IAC7C,WAAW;CACd,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,OAAO,OAAO,MAAM;IAEvB,MAAM,KAAK,OAAO,KAAK,OAAO,OAAO,CAAC,CAAC,CAAC;IAUxC,YAAY,WAAmC,EAAE;QARzC,iBAAY,GAA2B,EAAE,CAAC;QAE1C,SAAI,GAA2B,EAAE,CAAC;QAElC,cAAS,GAAmE,IAAI,GAAG,EAAE,CAAC;QAEtF,eAAU,GAAiC,EAAE,CAAC;QAGlD,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YACtC,MAAM,UAAU,GAAG,OAAwB,CAAC;YAC5C,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,UAAU,CAA2C,CAAC,CAAC;QACzF,CAAC,EAAE,IAAI,CAAC,CAAC;IACb,CAAC;IAED;;OAEG;IACI,GAAG,CAA0B,IAAO,EAAE,OAAkC;QAE3E,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YAChB,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,CAAC,QAAQ,EAAE,sDAAsD,CAAC,CAAC;SACtG;QAED,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC;IAED;;OAEG;IACI,OAAO,CAA0B,IAAO,EAAE,OAAkC;;QAE/E,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YACjB,MAAM,IAAI,UAAU,CAAC,YAAY,IAAI,CAAC,QAAQ,EAAE,oCAAoC,CAAC,CAAC;SACzF;QACD,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YAC1B,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,IAAI,OAAO,GAAoC,IAAI,CAAC;YACpD,OAAO,OAAO,KAAK,IAAI,EAAE;gBACrB,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAClC,OAAO,GAAG,MAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,mCAAI,IAAI,CAAC;aACjD;YACD,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,CAAC,QAAQ,EAAE,yEAAyE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;SAC5I;QAED,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC;IAEO,MAAM,CAA0B,IAAO,EAAE,OAAkC;QAE/E,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;QAE1B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,OAAO,YAAY,QAAQ,CAAC,CAAC;YACnD,CAAC;gBACG,IAAI,MAAW,CAAC;gBAChB,OAAO,CAAC,MAAiB,EAAE,EAAE;oBACzB,IAAI,MAAM,KAAK,SAAS,EAAE;wBACtB,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;qBAC5B;oBACD,OAAO,MAAM,CAAC;gBAClB,CAAC,CAAC;YACN,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAEnB,IAAI,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE;YACpD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE;gBAC9B,YAAY,EAAE,IAAI;gBAClB,GAAG,EAAE,GAAG,EAAE;oBACN,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC1B,CAAC;aACJ,CAAC,CAAC;SACN;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;OAEG;IACI,OAAO,CAA0B,IAAO,EAAE,QAAmC;QAChF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAW,QAAQ,CAAC;QACnC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;QAEnC,IAAI,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE;YACpD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE;gBAC9B,YAAY,EAAE,IAAI;gBAClB,GAAG,EAAE,GAAG,EAAE;oBACN,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC1B,CAAC;aACJ,CAAC,CAAC;SACN;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;OAEG;IACI,GAAG,CAA0B,IAAO;QACvC,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,QAAQ,EAAE;YAC7C,MAAM,eAAe,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,eAAe,EAAE;gBACjB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gBAC/F,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBACjC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;aAC9B;YACD,IAAI;gBACA,OAAQ,IAAI,CAAC,YAAY,CAAC,IAAI,CAAoC,CAAC,IAAI,CAAC,CAAC;aAC5E;oBAAS;gBACN,IAAI,eAAe,EAAE;oBACjB,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;iBACzB;aACJ;SACJ;QACD,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAS,CAAC;IAC3C,CAAC;IAED;;OAEG;IACI,GAAG,CAA0B,IAAO;QACvC,OAAO,IAAI,IAAI,IAAI,CAAC,YAAY,CAAC;IACrC,CAAC;IAED;;OAEG;IACI,OAAO,CAAqB,IAAO;QACtC,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC;IACtB,CAAC;IAED;;OAEG;IACI,MAAM,CAA0B,WAAc,EAAE,OAAiB;QACpE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE;YACjC,MAAM,IAAI,UAAU,CAAC,oBAAoB,WAAW,CAAC,QAAQ,EAAE,6BAA6B,CAAC,CAAC;SACjG;QAED,IAAI,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;QAEzC,OAAO,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC,SAAoB,EAAE,EAAE;YAC7D,IAAI,GAAG,YAAY,QAAQ,EAAE;gBACzB,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;aACxB;YACD,OAAO,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACnC,CAAC,CAAC;IACN,CAAC;IAED;;OAEG;IACI,GAAG,CAA0B,IAAO;QACvC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAA+B,CAAC;IACzD,CAAC;IAED;;OAEG;IACI,QAAQ,CAAC,QAAgC;QAC5C,IAAI,IAAI,CAAC,yBAAyB,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,QAAQ,YAAY,QAAQ,EAAE;YACnF,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;SAC3B;aAAM,IAAI,QAAQ,YAAY,QAAQ,EAAE;YACrC,QAAQ,CAAC,IAAI,CAAC,CAAC;SAClB;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;IAEO,yBAAyB,CAAC,MAAW;QACzC,OAAO,UAAU,IAAI,MAAM,CAAC;IAChC,CAAC;CACJ"}
@@ -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": "1.1.1",
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
- "coverage": "jest --collect-coverage",
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
- "prepublish": "npm run transpile"
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.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"
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
@@ -1,6 +0,0 @@
1
- {
2
- "presets": [
3
- ["@babel/preset-env", {"targets": {"node": "current"}}],
4
- "@babel/preset-typescript"
5
- ]
6
- }
@@ -1,13 +0,0 @@
1
- name: Tests
2
-
3
- on: [push]
4
-
5
- jobs:
6
- build:
7
-
8
- runs-on: ubuntu-latest
9
-
10
- steps:
11
- - uses: actions/checkout@v1
12
- - name: Run Jest
13
- uses: stefanoeb/jest-action@1.0.3
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
- }
package/src/container.ts DELETED
@@ -1,8 +0,0 @@
1
- import ServiceProvider from './serviceProvider';
2
-
3
- export default interface Container
4
- {
5
- get(service: string): any;
6
-
7
- has(service: string): boolean;
8
- }
package/src/index.ts DELETED
@@ -1,8 +0,0 @@
1
- import Container from './container'
2
- import Pimple from './pimple'
3
- import ServiceProvider from './serviceProvider'
4
- export {
5
- Container,
6
- Pimple,
7
- ServiceProvider
8
- }
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
- }
@@ -1,9 +0,0 @@
1
- import Pimple from "./pimple";
2
-
3
- /**
4
- * Service provider class for service injecting in Pimple container
5
- */
6
- export default interface ServiceProvider
7
- {
8
- register(container: Pimple): void;
9
- }
@@ -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
@@ -1,8 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "compilerOptions": {
4
- "module": "CommonJS",
5
- "outDir": "./lib/cjs"
6
- },
7
- }
8
-
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
- }