di-sacala 0.1.2 → 0.1.4
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 +55 -3
- package/dist/di-sacala.d.ts.map +1 -1
- package/dist/index.js +11 -39
- package/dist/index.umd.cjs +1 -1
- package/package.json +32 -4
package/README.md
CHANGED
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
# di-sacala
|
|
2
2
|
|
|
3
3
|
[](https://github.com/monkin/di-sacala/actions/workflows/test.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/di-sacala)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://bundlephobia.com/package/di-sacala)
|
|
4
7
|
|
|
5
8
|
`di-sacala` is a lightweight, type-safe dependency injection container for TypeScript. It leverages TypeScript's advanced type system to provide a fluent API for service registration and resolution with full type safety and autocompletion.
|
|
6
9
|
|
|
10
|
+
## Table of Contents
|
|
11
|
+
|
|
12
|
+
- [Features](#features)
|
|
13
|
+
- [Motivation](#motivation)
|
|
14
|
+
- [Installation](#installation)
|
|
15
|
+
- [Usage](#usage)
|
|
16
|
+
- [1. Defining a Service](#1-defining-a-service)
|
|
17
|
+
- [2. Basic Injection](#2-basic-injection)
|
|
18
|
+
- [3. Services with Dependencies](#3-services-with-dependencies)
|
|
19
|
+
- [4. Merging Containers](#4-merging-containers)
|
|
20
|
+
- [5. Lazy & Singleton](#5-lazy--singleton)
|
|
21
|
+
- [6. Duplicate Service Name Protection](#6-duplicate-service-name-protection)
|
|
22
|
+
- [7. Reserved Field Names](#7-reserved-field-names)
|
|
23
|
+
- [API Reference](#api-reference)
|
|
24
|
+
- [Development](#development)
|
|
25
|
+
- [License](#license)
|
|
26
|
+
|
|
7
27
|
## Features
|
|
8
28
|
|
|
9
29
|
- **Full Type Safety**: Get autocompletion and type checks for all your injected services.
|
|
30
|
+
- **No Decorators**: No need for `reflect-metadata` or experimental decorators. Pure TypeScript.
|
|
10
31
|
- **Fluent API**: Chainable service registration makes it easy to compose your container.
|
|
11
32
|
- **Container Composition**: Merge multiple containers together to share dependencies across different parts of your application.
|
|
12
33
|
- **Lazy & Singleton**: Services are instantiated only on demand (when first accessed) and reused for subsequent accesses.
|
|
@@ -60,23 +81,29 @@ To inject dependencies into a service, define its constructor to accept the cont
|
|
|
60
81
|
```typescript
|
|
61
82
|
import { Di, DiService } from 'di-sacala';
|
|
62
83
|
import { LoggerService } from './LoggerService';
|
|
84
|
+
import { ConfigService } from './ConfigService';
|
|
63
85
|
|
|
64
86
|
export class UserService implements DiService<"user"> {
|
|
65
87
|
getServiceName() {
|
|
66
88
|
return "user" as const;
|
|
67
89
|
}
|
|
68
90
|
|
|
69
|
-
//
|
|
70
|
-
constructor(private di: Di<LoggerService>) {}
|
|
91
|
+
// Single dependency:
|
|
92
|
+
// constructor(private di: Di<LoggerService>) {}
|
|
93
|
+
|
|
94
|
+
// Multiple dependencies using a tuple:
|
|
95
|
+
constructor(private di: Di<[LoggerService, ConfigService]>) {}
|
|
71
96
|
|
|
72
97
|
getUser(id: string) {
|
|
73
|
-
this.di.
|
|
98
|
+
const prefix = this.di.config.get("userPrefix");
|
|
99
|
+
this.di.logger.log(`Fetching user: ${prefix}${id}`);
|
|
74
100
|
return { id, name: "User " + id };
|
|
75
101
|
}
|
|
76
102
|
}
|
|
77
103
|
|
|
78
104
|
const container = new DiContainer()
|
|
79
105
|
.inject(LoggerService)
|
|
106
|
+
.inject(ConfigService)
|
|
80
107
|
.inject(UserService);
|
|
81
108
|
|
|
82
109
|
container.user.getUser("42");
|
|
@@ -149,6 +176,31 @@ const container = new DiContainer();
|
|
|
149
176
|
container.inject(InjectService);
|
|
150
177
|
```
|
|
151
178
|
|
|
179
|
+
## API Reference
|
|
180
|
+
|
|
181
|
+
### `DiContainer`
|
|
182
|
+
|
|
183
|
+
The main class for managing services.
|
|
184
|
+
|
|
185
|
+
- `inject(ServiceClass: new (di: this) => S): DiContainer & Di<S>`
|
|
186
|
+
Registers a service class. Returns the container instance, typed with the newly added service.
|
|
187
|
+
- `injectContainer(other: DiContainer): DiContainer & ...`
|
|
188
|
+
Copies all services from another container into this one.
|
|
189
|
+
|
|
190
|
+
### `DiService<Name>`
|
|
191
|
+
|
|
192
|
+
An interface that your service classes must implement.
|
|
193
|
+
|
|
194
|
+
- `getServiceName(this: null): Name`
|
|
195
|
+
Must return the unique name of the service as a string literal type.
|
|
196
|
+
|
|
197
|
+
### `Di<S>`
|
|
198
|
+
|
|
199
|
+
A utility type to help define dependencies in your service constructors.
|
|
200
|
+
|
|
201
|
+
- `Di<ServiceClass>`: Resolves to an object with the service name as the key and the service instance as the value.
|
|
202
|
+
- `Di<[Service1, Service2]>`: Resolves to a merged object containing all specified services.
|
|
203
|
+
|
|
152
204
|
## Development
|
|
153
205
|
|
|
154
206
|
### Installation
|
package/dist/di-sacala.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"di-sacala.d.ts","sourceRoot":"","sources":["../src/di-sacala.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,SAAS,CAAC,IAAI,SAAS,MAAM;IAC1C;;;;;OAKG;IACH,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;CACpC;AAED;;;;;;GAMG;AACH,MAAM,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,GAAG,MAAM,IAAI,CAAC,GACjD,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GACjB,CAAC,SAAS,EAAE,GACV,OAAO,GACP,CAAC,SAAS,SAAS,CAAC,MAAM,IAAI,CAAC,GAC7B;KAAG,GAAG,IAAI,IAAI,GAAG,CAAC;CAAE,GACpB,KAAK,CAAC;AAIhB,KAAK,kBAAkB,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,SAAS,MAAM,WAAW,GAC3D,wBAAwB,IAAI,EAAE,GAC9B,CAAC,CAAC;AAER,KAAK,MAAM,CAAC,SAAS,EAAE,OAAO,SAAS,SAAS,CAAC,MAAM,CAAC,IACpD,OAAO,SAAS,SAAS,CAAC,MAAM,IAAI,CAAC,GAC/B,kBAAkB,CACd,IAAI,EACJ,SAAS,SAAS;KAAG,GAAG,IAAI,IAAI,GAAG,OAAO;CAAE,GACtC,2BAA2B,IAAI,EAAE,GACjC,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC,CAChC,GACD,KAAK,CAAC;AAEhB,KAAK,KAAK,CAAC,GAAG,EAAE,GAAG,IAAI,OAAO,CAAC,MAAM,GAAG,EAAE,QAAQ,GAAG,iBAAiB,CAAC,GACnE,OAAO,CAAC,MAAM,GAAG,EAAE,QAAQ,GAAG,iBAAiB,CAAC,SAAS,KAAK,GAC5D,GAAG,GAAG,GAAG,GACT,oCAAoC,CAAC,OAAO,CACxC,MAAM,GAAG,EACT,QAAQ,GAAG,iBAAiB,CAC/B,GACG,OAAO,CAAC,MAAM,GAAG,EAAE,QAAQ,GAAG,iBAAiB,CAAC,CAAC,GACjD,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"di-sacala.d.ts","sourceRoot":"","sources":["../src/di-sacala.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,SAAS,CAAC,IAAI,SAAS,MAAM;IAC1C;;;;;OAKG;IACH,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;CACpC;AAED;;;;;;GAMG;AACH,MAAM,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,GAAG,MAAM,IAAI,CAAC,GACjD,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GACjB,CAAC,SAAS,EAAE,GACV,OAAO,GACP,CAAC,SAAS,SAAS,CAAC,MAAM,IAAI,CAAC,GAC7B;KAAG,GAAG,IAAI,IAAI,GAAG,CAAC;CAAE,GACpB,KAAK,CAAC;AAIhB,KAAK,kBAAkB,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,SAAS,MAAM,WAAW,GAC3D,wBAAwB,IAAI,EAAE,GAC9B,CAAC,CAAC;AAER,KAAK,MAAM,CAAC,SAAS,EAAE,OAAO,SAAS,SAAS,CAAC,MAAM,CAAC,IACpD,OAAO,SAAS,SAAS,CAAC,MAAM,IAAI,CAAC,GAC/B,kBAAkB,CACd,IAAI,EACJ,SAAS,SAAS;KAAG,GAAG,IAAI,IAAI,GAAG,OAAO;CAAE,GACtC,2BAA2B,IAAI,EAAE,GACjC,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC,CAChC,GACD,KAAK,CAAC;AAEhB,KAAK,KAAK,CAAC,GAAG,EAAE,GAAG,IAAI,OAAO,CAAC,MAAM,GAAG,EAAE,QAAQ,GAAG,iBAAiB,CAAC,GACnE,OAAO,CAAC,MAAM,GAAG,EAAE,QAAQ,GAAG,iBAAiB,CAAC,SAAS,KAAK,GAC5D,GAAG,GAAG,GAAG,GACT,oCAAoC,CAAC,OAAO,CACxC,MAAM,GAAG,EACT,QAAQ,GAAG,iBAAiB,CAC/B,GACG,OAAO,CAAC,MAAM,GAAG,EAAE,QAAQ,GAAG,iBAAiB,CAAC,CAAC,GACjD,MAAM,EAAE,CAAC;AAYnB;;;;GAIG;AACH,qBAAa,WAAW;;IAGpB;;;;;;;;OAQG;IACH,MAAM,CAAC,CAAC,SAAS,SAAS,CAAC,MAAM,CAAC,EAC9B,UAAU,EAAE,KAAK,YAAY,EAAE,IAAI,KAAK,CAAC,GAC1C,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAwBlB;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,SAAS,WAAW,EAAE,KAAK,EAAE,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;CAetE"}
|
package/dist/index.js
CHANGED
|
@@ -1,49 +1,21 @@
|
|
|
1
|
-
const
|
|
1
|
+
const a = new Set(["inject", "injectContainer"]), c = (r, t) => Object.prototype.hasOwnProperty.call(r, t), s = (r, t) => Object.keys(r).forEach(t), n = (r) => {
|
|
2
|
+
throw new Error(r);
|
|
3
|
+
};
|
|
2
4
|
class o {
|
|
3
5
|
constructor() {
|
|
4
6
|
}
|
|
5
|
-
/**
|
|
6
|
-
* Registers a new service by instantiating it with the current container instance.
|
|
7
|
-
* The service is then attached to the container using its `name` property.
|
|
8
|
-
*
|
|
9
|
-
* @template S - The type of service being injected.
|
|
10
|
-
* @param dependency - A constructor for the service, which receives the container as its only argument.
|
|
11
|
-
* @returns The container instance, typed with the newly added service.
|
|
12
|
-
* @throws {Error} If a service with the same name is already registered.
|
|
13
|
-
*/
|
|
14
7
|
inject(t) {
|
|
15
|
-
const e = t.prototype.getServiceName();
|
|
16
|
-
|
|
17
|
-
throw new Error(`Reserved field name: ${e}`);
|
|
18
|
-
if (r(this, e))
|
|
19
|
-
throw new Error(`Duplicate service name: ${e}`);
|
|
8
|
+
const e = t.prototype.getServiceName.call(null);
|
|
9
|
+
a.has(e) && n(`Reserved field name: ${e}`), c(this, e) && n(`Duplicate service name: ${e}`);
|
|
20
10
|
let i;
|
|
21
|
-
return Object.defineProperty(this, e, {
|
|
22
|
-
enumerable: !0,
|
|
23
|
-
configurable: !1,
|
|
24
|
-
get: () => i ?? (i = new t(this))
|
|
25
|
-
}), this;
|
|
11
|
+
return Object.defineProperty(this, e, { enumerable: !0, get: () => i ?? (i = new t(this)) }), this;
|
|
26
12
|
}
|
|
27
|
-
/**
|
|
28
|
-
* Copies all service properties from another container into this one.
|
|
29
|
-
* Useful for composing containers or providing shared dependencies.
|
|
30
|
-
*
|
|
31
|
-
* @template DC - The type of the other DiContainer.
|
|
32
|
-
* @param other - The source container to copy services from.
|
|
33
|
-
* @returns The current container instance, typed with the merged services.
|
|
34
|
-
* @throws {Error} If any service name from the other container already exists in this container.
|
|
35
|
-
*/
|
|
36
13
|
injectContainer(t) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
enumerable: !0,
|
|
43
|
-
configurable: !1,
|
|
44
|
-
get: () => t[e]
|
|
45
|
-
});
|
|
46
|
-
return this;
|
|
14
|
+
return s(t, (e) => {
|
|
15
|
+
c(this, e) && n(`Containers have duplicated keys: ${String(e)}`);
|
|
16
|
+
}), s(t, (e) => {
|
|
17
|
+
Object.defineProperty(this, e, { enumerable: !0, get: () => t[e] });
|
|
18
|
+
}), this;
|
|
47
19
|
}
|
|
48
20
|
}
|
|
49
21
|
export {
|
package/dist/index.umd.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(i,o){typeof exports=="object"&&typeof module<"u"?o(exports):typeof define=="function"&&define.amd?define(["exports"],o):(i=typeof globalThis<"u"?globalThis:i||self,o(i.DiSacala={}))})(this,(function(i){"use strict";const o=new Set(["inject","injectContainer"]),s=(n,t)=>Object.prototype.hasOwnProperty.call(n,t),c=(n,t)=>Object.keys(n).forEach(t),r=n=>{throw new Error(n)};class l{constructor(){}inject(t){const e=t.prototype.getServiceName.call(null);o.has(e)&&r(`Reserved field name: ${e}`),s(this,e)&&r(`Duplicate service name: ${e}`);let a;return Object.defineProperty(this,e,{enumerable:!0,get:()=>a??(a=new t(this))}),this}injectContainer(t){return c(t,e=>{s(this,e)&&r(`Containers have duplicated keys: ${String(e)}`)}),c(t,e=>{Object.defineProperty(this,e,{enumerable:!0,get:()=>t[e]})}),this}}i.DiContainer=l,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"})}));
|
package/package.json
CHANGED
|
@@ -1,27 +1,55 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "di-sacala",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Small type-safe dependency injection lib",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
|
-
"types": "./dist/
|
|
7
|
+
"types": "./dist/di-sacala.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/di-sacala.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.umd.cjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
8
15
|
"files": [
|
|
9
16
|
"dist"
|
|
10
17
|
],
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=18.0.0"
|
|
21
|
+
},
|
|
11
22
|
"scripts": {
|
|
12
23
|
"build": "vite build",
|
|
13
24
|
"test": "vitest run",
|
|
14
25
|
"test:watch": "vitest",
|
|
15
26
|
"lint": "eslint src --ext .ts",
|
|
16
27
|
"format": "prettier --write \"src/**/*.ts\"",
|
|
17
|
-
"format:check": "prettier --check \"src/**/*.ts\""
|
|
28
|
+
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
29
|
+
"prepublishOnly": "npm run lint && npm run test && npm run build"
|
|
18
30
|
},
|
|
19
|
-
"keywords": [
|
|
31
|
+
"keywords": [
|
|
32
|
+
"dependency-injection",
|
|
33
|
+
"di",
|
|
34
|
+
"typescript",
|
|
35
|
+
"type-safe",
|
|
36
|
+
"container",
|
|
37
|
+
"ioc",
|
|
38
|
+
"lightweight"
|
|
39
|
+
],
|
|
20
40
|
"author": {
|
|
21
41
|
"name": "Andrei Monkin",
|
|
22
42
|
"email": "monkin.andrey@gmail.com",
|
|
23
43
|
"url": "https://github.com/monkin"
|
|
24
44
|
},
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "git+https://github.com/monkin/di-sacala.git"
|
|
48
|
+
},
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/monkin/di-sacala/issues"
|
|
51
|
+
},
|
|
52
|
+
"homepage": "https://github.com/monkin/di-sacala#readme",
|
|
25
53
|
"license": "MIT",
|
|
26
54
|
"devDependencies": {
|
|
27
55
|
"@eslint/js": "^9.39.2",
|