@slimlib/injector 1.0.6 → 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/README.md +91 -24
- package/package.json +10 -15
- package/src/index.js +58 -0
- package/types/index.d.ts +15 -0
- package/types/index.d.ts.map +17 -0
- package/dist/index.cjs +0 -15
- package/dist/index.d.ts +0 -3
- package/dist/index.mjs +0 -13
package/README.md
CHANGED
|
@@ -2,79 +2,146 @@
|
|
|
2
2
|
|
|
3
3
|
Parameter names based dependency injector for nodejs.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[Changelog](./CHANGELOG.md)
|
|
6
|
+
|
|
7
|
+
## API
|
|
8
|
+
|
|
9
|
+
### createInject()
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
11
|
+
Returns a new instance of an injector function to work with.
|
|
12
|
+
|
|
13
|
+
_Limitations_
|
|
14
|
+
|
|
15
|
+
- minification of code is not supported (use `createInjectAnnotated` instead)
|
|
9
16
|
- not typesafe
|
|
10
|
-
- classes not supported
|
|
11
17
|
- slower than a normal function call
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
### createInjectAnnotated()
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
Returns a new instance of an injector function that uses AngularJS-style array annotation for minification safety.
|
|
16
22
|
|
|
17
|
-
|
|
23
|
+
Instead of parsing parameter names, it expects dependencies to be specified as strings in an array before the function:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
inject(["dep1", "dep2", (dep1, dep2) => { ... }]);
|
|
27
|
+
```
|
|
18
28
|
|
|
19
|
-
|
|
29
|
+
This allows code to be minified since the dependency names are preserved as strings.
|
|
30
|
+
|
|
31
|
+
> **Note:** The input array is mutated during injection (the function is removed via `pop()`). Always use inline array literals or create a fresh array for each call if you need to reuse the dependency list.
|
|
20
32
|
|
|
21
33
|
### injector(function, scope)
|
|
22
34
|
|
|
23
|
-
|
|
35
|
+
Injects arguments into function and invokes it.
|
|
24
36
|
|
|
25
|
-
`function` -
|
|
26
|
-
`scope` -
|
|
37
|
+
`function` - _required_, function to inject parameters and call (or annotated array for `createInjectAnnotated`)
|
|
38
|
+
`scope` - _optional_, _default_ = `{}`, this argument for the function
|
|
27
39
|
|
|
28
40
|
### $provide(key, value)
|
|
29
41
|
|
|
30
|
-
|
|
42
|
+
Predefined injectable function.
|
|
31
43
|
|
|
32
44
|
`key` - string, required
|
|
33
45
|
`value` - unknown
|
|
34
46
|
|
|
35
|
-
|
|
47
|
+
To get it, inject it into the function:
|
|
36
48
|
|
|
37
49
|
```typescript
|
|
38
50
|
inject(($provide: Provider) => {
|
|
39
|
-
|
|
51
|
+
$provide("service", service);
|
|
40
52
|
});
|
|
41
53
|
```
|
|
42
54
|
|
|
43
|
-
##
|
|
55
|
+
## Examples
|
|
56
|
+
|
|
57
|
+
### Using createInject (development / non-minified)
|
|
44
58
|
|
|
45
59
|
```typescript
|
|
46
|
-
import createInject from
|
|
60
|
+
import { createInject } from "@slimlib/injector";
|
|
47
61
|
|
|
48
62
|
const inject = createInject();
|
|
49
63
|
|
|
50
64
|
inject(($provide: Provider) => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
65
|
+
$provide("config", {
|
|
66
|
+
url: "http://example.com/json",
|
|
67
|
+
format: "json",
|
|
68
|
+
});
|
|
55
69
|
});
|
|
56
70
|
|
|
57
71
|
inject(async (config: Json) => {
|
|
72
|
+
const data = await fetch(config.url);
|
|
73
|
+
const result = config.json ? await data.json() : data;
|
|
74
|
+
// and so on
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Using createInjectAnnotated (minification-safe)
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { createInjectAnnotated } from "@slimlib/injector";
|
|
82
|
+
|
|
83
|
+
const inject = createInjectAnnotated();
|
|
84
|
+
|
|
85
|
+
inject([
|
|
86
|
+
"$provide",
|
|
87
|
+
($provide: Provider) => {
|
|
88
|
+
$provide("config", {
|
|
89
|
+
url: "http://example.com/json",
|
|
90
|
+
format: "json",
|
|
91
|
+
});
|
|
92
|
+
},
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
inject([
|
|
96
|
+
"config",
|
|
97
|
+
async (config: Json) => {
|
|
58
98
|
const data = await fetch(config.url);
|
|
59
99
|
const result = config.json ? await data.json() : data;
|
|
60
100
|
// and so on
|
|
101
|
+
},
|
|
102
|
+
]);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
This style is similar to AngularJS's dependency injection annotation:
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
// Before minification
|
|
109
|
+
angular.module("App", []).controller("MyController", function ($scope) {
|
|
110
|
+
$scope.value = "test";
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// After minification (broken)
|
|
114
|
+
angular.module("App", []).controller("MyController", function (a) {
|
|
115
|
+
a.value = "test";
|
|
61
116
|
});
|
|
117
|
+
|
|
118
|
+
// With array annotation (works after minification)
|
|
119
|
+
angular.module("App", []).controller("MyController", [
|
|
120
|
+
"$scope",
|
|
121
|
+
function (a) {
|
|
122
|
+
a.value = "test";
|
|
123
|
+
},
|
|
124
|
+
]);
|
|
62
125
|
```
|
|
63
126
|
|
|
127
|
+
## Build-time Swapping
|
|
128
|
+
|
|
129
|
+
You can use `createInject` during development and swap to `createInjectAnnotated` at build time for production. This can be done with build tools like Rollup, Webpack, or esbuild by aliasing the import.
|
|
130
|
+
|
|
64
131
|
# FAQ
|
|
65
132
|
|
|
66
133
|
1. Is it a good solution to mock something in unit tests?
|
|
67
134
|
|
|
68
|
-
-
|
|
135
|
+
- No, please use [jest](https://jestjs.io/), [vitest](https://vitest.dev/), [proxyquire](https://www.npmjs.com/package/proxyquire), [proxyrequire](https://www.npmjs.com/package/proxyrequire) and other similar approaches to mock modules.
|
|
69
136
|
|
|
70
137
|
2. Is it a good solution to use in frontend code?
|
|
71
138
|
|
|
72
|
-
-
|
|
139
|
+
- `createInject` will not work after minification, but `createInjectAnnotated` is designed to work with minified code.
|
|
73
140
|
|
|
74
141
|
3. Is it good for nodejs applications?
|
|
75
142
|
|
|
76
|
-
-
|
|
143
|
+
- Only in some edge cases, please use singletons/factories/something else if possible.
|
|
77
144
|
|
|
78
145
|
# License
|
|
79
146
|
|
|
80
|
-
[MIT](https://github.com/kshutkin/slimlib/blob/main/LICENSE)
|
|
147
|
+
[MIT](https://github.com/kshutkin/slimlib/blob/main/LICENSE)
|
package/package.json
CHANGED
|
@@ -1,27 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"name": "@slimlib/injector",
|
|
5
5
|
"description": "Parameter names based dependency injector for nodejs",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Konstantin Shutkin",
|
|
8
|
-
"main": "./
|
|
9
|
-
"module": "./
|
|
8
|
+
"main": "./src/index.js",
|
|
9
|
+
"module": "./src/index.js",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
|
-
"types": "./
|
|
13
|
-
"
|
|
14
|
-
"require": "./dist/index.cjs",
|
|
15
|
-
"default": "./dist/index.mjs"
|
|
12
|
+
"types": "./types/index.d.ts",
|
|
13
|
+
"default": "./src/index.js"
|
|
16
14
|
},
|
|
17
15
|
"./package.json": "./package.json"
|
|
18
16
|
},
|
|
19
|
-
"types": "./
|
|
17
|
+
"types": "./types/index.d.ts",
|
|
20
18
|
"files": [
|
|
21
|
-
"
|
|
19
|
+
"types"
|
|
22
20
|
],
|
|
23
|
-
"
|
|
24
|
-
"
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@slimlib/get-parameter-names": "^1.0.0"
|
|
25
23
|
},
|
|
26
24
|
"repository": {
|
|
27
25
|
"type": "git",
|
|
@@ -36,8 +34,5 @@
|
|
|
36
34
|
"injector",
|
|
37
35
|
"dependency injection",
|
|
38
36
|
"nodejs"
|
|
39
|
-
]
|
|
40
|
-
"dependencies": {
|
|
41
|
-
"get-parameter-names": "0.3.0"
|
|
42
|
-
}
|
|
37
|
+
]
|
|
43
38
|
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { getParameterNames } from '@slimlib/get-parameter-names';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {(key: string, value: unknown) => void} Provider
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {[...string[], (...args: any[]) => any]} AnnotatedFunction
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @returns {<F extends (...args: any[]) => any>(func: F, scope?: object) => ReturnType<F>}
|
|
13
|
+
*/
|
|
14
|
+
export function createInject() {
|
|
15
|
+
/** @type {Record<string, unknown>} */
|
|
16
|
+
const dependencies = Object.create(null);
|
|
17
|
+
|
|
18
|
+
dependencies.$provide = /** @type {Provider} */ (
|
|
19
|
+
(key, value) => {
|
|
20
|
+
dependencies[key] = value;
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return (func, scope = {}) =>
|
|
25
|
+
func.apply(
|
|
26
|
+
scope,
|
|
27
|
+
getParameterNames(func).map((/** @type {string} */ key) => dependencies[key])
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Creates an injector that uses AngularJS-style array annotation for minification safety.
|
|
33
|
+
* Instead of parsing parameter names, it expects dependencies to be specified as strings
|
|
34
|
+
* in an array before the function: ['dep1', 'dep2', function(dep1, dep2) { ... }]
|
|
35
|
+
* @returns {<F extends (...args: any[]) => any>(funcOrArray: F | [...string[], F], scope?: object) => ReturnType<F>}
|
|
36
|
+
*/
|
|
37
|
+
export function createInjectAnnotated() {
|
|
38
|
+
/** @type {Record<string, unknown>} */
|
|
39
|
+
const dependencies = Object.create(null);
|
|
40
|
+
|
|
41
|
+
dependencies.$provide = /** @type {Provider} */ (
|
|
42
|
+
(key, value) => {
|
|
43
|
+
dependencies[key] = value;
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
return (funcOrArray, scope = {}) => {
|
|
48
|
+
if (Array.isArray(funcOrArray)) {
|
|
49
|
+
const func = /** @type {(...args: any[]) => any} */ (funcOrArray.pop());
|
|
50
|
+
return func.apply(
|
|
51
|
+
scope,
|
|
52
|
+
/** @type {string[]} */ (funcOrArray).map(key => dependencies[key])
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
// If not an array, just call the function with no dependencies
|
|
56
|
+
return funcOrArray.apply(scope, []);
|
|
57
|
+
};
|
|
58
|
+
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
declare module '@slimlib/injector' {
|
|
2
|
+
export function createInject(): <F extends (...args: any[]) => any>(func: F, scope?: object) => ReturnType<F>;
|
|
3
|
+
/**
|
|
4
|
+
* Creates an injector that uses AngularJS-style array annotation for minification safety.
|
|
5
|
+
* Instead of parsing parameter names, it expects dependencies to be specified as strings
|
|
6
|
+
* in an array before the function: ['dep1', 'dep2', function(dep1, dep2) { ... }]
|
|
7
|
+
* */
|
|
8
|
+
export function createInjectAnnotated(): <F extends (...args: any[]) => any>(funcOrArray: F | [...string[], F], scope?: object) => ReturnType<F>;
|
|
9
|
+
export type Provider = (key: string, value: unknown) => void;
|
|
10
|
+
export type AnnotatedFunction = [...string[], (...args: any[]) => any];
|
|
11
|
+
|
|
12
|
+
export {};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"file": "index.d.ts",
|
|
4
|
+
"names": [
|
|
5
|
+
"createInject",
|
|
6
|
+
"createInjectAnnotated",
|
|
7
|
+
"Provider",
|
|
8
|
+
"AnnotatedFunction"
|
|
9
|
+
],
|
|
10
|
+
"sources": [
|
|
11
|
+
"../src/index.js"
|
|
12
|
+
],
|
|
13
|
+
"sourcesContent": [
|
|
14
|
+
null
|
|
15
|
+
],
|
|
16
|
+
"mappings": ";iBAagBA,YAAYA;;;;;;iBAuBZC,qBAAqBA;aAjCeC,QAAQA;aAIPC,iBAAiBA"
|
|
17
|
+
}
|
package/dist/index.cjs
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var getParameterNames = require('get-parameter-names');
|
|
4
|
-
|
|
5
|
-
var index = () => {
|
|
6
|
-
const dependencies = Object.create(null);
|
|
7
|
-
dependencies['$provide'] = (key, value) => {
|
|
8
|
-
dependencies[key] = value;
|
|
9
|
-
};
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
-
return (func, scope = {}) => func.apply(scope, getParameterNames(func)
|
|
12
|
-
.map((key) => dependencies[key]));
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
module.exports = index;
|
package/dist/index.d.ts
DELETED
package/dist/index.mjs
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import getParameterNames from 'get-parameter-names';
|
|
2
|
-
|
|
3
|
-
var index = () => {
|
|
4
|
-
const dependencies = Object.create(null);
|
|
5
|
-
dependencies['$provide'] = (key, value) => {
|
|
6
|
-
dependencies[key] = value;
|
|
7
|
-
};
|
|
8
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
-
return (func, scope = {}) => func.apply(scope, getParameterNames(func)
|
|
10
|
-
.map((key) => dependencies[key]));
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export { index as default };
|