@andrew_l/context 0.3.22 → 0.4.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/dist/index.d.mts +28 -33
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +101 -164
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -8
- package/dist/index.cjs +0 -205
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -151
- package/dist/index.d.ts +0 -151
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { AnyFunction } from
|
|
2
|
-
|
|
1
|
+
import { AnyFunction } from "@andrew_l/toolkit";
|
|
3
2
|
/**
|
|
4
3
|
* Wrapper around `provide/inject` function to simple usage.
|
|
5
4
|
*
|
|
@@ -27,7 +26,6 @@ import { AnyFunction } from '@andrew_l/toolkit';
|
|
|
27
26
|
* @group Main
|
|
28
27
|
*/
|
|
29
28
|
declare function createContext<ContextValue>(providerName: string | string[], contextName?: string): readonly [<T extends ContextValue | null | undefined = ContextValue>(fallback?: T | (() => T)) => T extends null ? ContextValue | null : ContextValue, (contextValue: ContextValue) => ContextValue];
|
|
30
|
-
|
|
31
29
|
/**
|
|
32
30
|
* The callback will be invoked when the associated context completes.
|
|
33
31
|
*
|
|
@@ -51,7 +49,6 @@ declare function createContext<ContextValue>(providerName: string | string[], co
|
|
|
51
49
|
* @group Main
|
|
52
50
|
*/
|
|
53
51
|
declare function onScopeDispose(fn: () => void): void;
|
|
54
|
-
|
|
55
52
|
type ProvideKey = symbol | string | number | object;
|
|
56
53
|
type ProvideValue<T = unknown> = T | undefined;
|
|
57
54
|
type InjectionKey = symbol | string | number | object;
|
|
@@ -71,39 +68,37 @@ declare function inject<T = any>(key: ProvideKey, defaultValue?: T | (() => T)):
|
|
|
71
68
|
* @group Main
|
|
72
69
|
*/
|
|
73
70
|
declare function hasInjectionContext(): boolean;
|
|
74
|
-
|
|
75
71
|
declare class Scope {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
72
|
+
detached: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* @internal
|
|
75
|
+
*/
|
|
76
|
+
id: number;
|
|
77
|
+
/**
|
|
78
|
+
* @internal
|
|
79
|
+
*/
|
|
80
|
+
providers: Map<any, any>;
|
|
81
|
+
/**
|
|
82
|
+
* @internal
|
|
83
|
+
*/
|
|
84
|
+
parent: Scope | null;
|
|
85
|
+
/**
|
|
86
|
+
* @internal
|
|
87
|
+
*/
|
|
88
|
+
cleanups: (() => void)[];
|
|
89
|
+
/**
|
|
90
|
+
* @internal
|
|
91
|
+
*/
|
|
92
|
+
private _activeRuns;
|
|
93
|
+
constructor(detached?: boolean);
|
|
94
|
+
run<T>(fn: () => T): T;
|
|
95
|
+
stop(): void;
|
|
96
|
+
get active(): boolean;
|
|
101
97
|
}
|
|
102
98
|
/**
|
|
103
99
|
* @group Main
|
|
104
100
|
*/
|
|
105
101
|
declare function getCurrentScope(): Scope | null;
|
|
106
|
-
|
|
107
102
|
/**
|
|
108
103
|
* Creates a function within the injection context and returns its result. Providers/injections are only accessible within the callback function.
|
|
109
104
|
* @param isolated Do not inject parent providers into this context (Default: `false`)
|
|
@@ -147,5 +142,5 @@ declare function runWithContext<T = any>(fn: () => T, isolated?: boolean): T;
|
|
|
147
142
|
* @group Main
|
|
148
143
|
*/
|
|
149
144
|
declare function bindContext<T>(fn: () => T): () => T;
|
|
150
|
-
|
|
151
|
-
|
|
145
|
+
export { InjectionKey, ProvideKey, ProvideValue, bindContext, createContext, getCurrentScope, hasInjectionContext, inject, onScopeDispose, provide, runWithContext, withContext };
|
|
146
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":["ContextValue","providerName","contextName","T","fallback","contextValue","fn","T","ProvideKey","key","value","enterWith","defaultValue","ProvideValue","detached","id","providers","Map","parent","Scope","cleanups","_activeRuns","constructor","run","T","fn","stop","active","scope","T","AnyFunction","fn","detached","isolated"],"sources":["../src/hooks/createContext.d.ts","../src/hooks/onScopeDispose.d.ts","../src/hooks/provide.d.ts","../src/scope.d.ts","../src/index.d.ts"],"mappings":";;;AA0BA;;;;;;;;;;;;;;;;;;;;;;;;iBAAwB,aAAA,eAA4BC,YAAAA,qBAAiCC,WAAAA,iCAA4C,YAAA,sBAAkC,YAAA,EAAcE,QAAAA,GAAW,CAAA,UAAW,CAAA,MAAO,CAAA,gBAAiB,YAAA,UAAsB,YAAA,GAAeC,YAAAA,EAAc,YAAA,KAAiB,YAAA;;;AAAnS;;;;;;;;;;;;;;;;;;;;iBCJwB,cAAA,CAAeC,EAAc;AAAA,KCtBzC,UAAA;AAAA,KACA,YAAA,gBAA4B,CAAC;AAAA,KAC7B,YAAA;;;;;;iBAMY,OAAA,CAAQG,GAAAA,EAAK,UAAU,EAAEC,KAAAA,OAAYC,SAAAA;;;;;iBAKrC,MAAA,UAAgBF,GAAAA,EAAK,UAAA,EAAYG,YAAAA,GAAe,CAAA,UAAW,CAAA,IAAK,YAAA,CAAa,CAAA;;;;;iBAK7E,mBAAA;AAAA,cClBH,KAAA;EACjBE,QAAAA;EHyBoB;;;EGrBpBC,EAAAA;EHqB+J;;;EGjB/JC,SAAAA,EAAW,GAAA;EHiBgN;;;EGb3NE,MAAAA,EAAQ,KAAA;EHamS;;;EGT3SE,QAAAA;EHSiFlB;;;EAAAA,QGLzEmB,WAAAA;EACRC,WAAAA,CAAYR,QAAAA;EACZS,GAAAA,IAAOE,EAAAA,QAAU,CAAA,GAAI,CAAA;EACrBC,IAAAA;EAAAA,IACIC,MAAAA;AAAAA;;AHCuS;;iBGQvR,eAAA,IAAmB,KAAK;;;;;;;;;;;;;;;;;;;;iBCVxB,WAAA,WAAsB,WAAA,EAAaI,EAAAA,EAAI,CAAA,EAAGC,QAAAA,aAAqB,CAAA;;;;;;iBAM/D,cAAA,UAAwBD,EAAAA,QAAU,CAAA,EAAGE,QAAAA,aAAqB,CAAC;;AJJ4N;;ACJ/S;;;;AAAqD;;ACtBrD;;;;AAAsB;AACtB;;iBE8CwB,WAAA,IAAeF,EAAAA,QAAU,CAAA,SAAU,CAAC"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,195 +1,132 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { assert, captureStackTrace, catchError, isFunction, isPromise, noop } from "@andrew_l/toolkit";
|
|
3
2
|
let idSec = 0;
|
|
4
3
|
let ALS;
|
|
5
4
|
let currentScope = null;
|
|
6
|
-
import(
|
|
7
|
-
|
|
5
|
+
import("node:async_hooks").then((r) => {
|
|
6
|
+
ALS = new r.AsyncLocalStorage();
|
|
8
7
|
}).catch(noop);
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (this._activeRuns === 0) {
|
|
42
|
-
this.stop();
|
|
43
|
-
}
|
|
44
|
-
if (err) {
|
|
45
|
-
throw err;
|
|
46
|
-
}
|
|
47
|
-
return result;
|
|
48
|
-
};
|
|
49
|
-
const r = runInScope(this, fn);
|
|
50
|
-
if (isPromise(r)) {
|
|
51
|
-
return r.then(onComplete);
|
|
52
|
-
}
|
|
53
|
-
return onComplete(r);
|
|
54
|
-
}
|
|
55
|
-
stop() {
|
|
56
|
-
for (let i = 0, l = this.cleanups.length; i < l; i++) {
|
|
57
|
-
this.cleanups[i]();
|
|
58
|
-
}
|
|
59
|
-
this.cleanups.length = 0;
|
|
60
|
-
}
|
|
61
|
-
get active() {
|
|
62
|
-
return this._activeRuns > 0;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
8
|
+
var Scope = class {
|
|
9
|
+
detached;
|
|
10
|
+
id;
|
|
11
|
+
providers = /* @__PURE__ */ new Map();
|
|
12
|
+
parent = null;
|
|
13
|
+
cleanups = [];
|
|
14
|
+
_activeRuns = 0;
|
|
15
|
+
constructor(detached = false) {
|
|
16
|
+
this.detached = detached;
|
|
17
|
+
this.id = ++idSec;
|
|
18
|
+
if (!detached) this.parent = getCurrentScope();
|
|
19
|
+
}
|
|
20
|
+
run(fn) {
|
|
21
|
+
this._activeRuns++;
|
|
22
|
+
const onComplete = ([err, result]) => {
|
|
23
|
+
this._activeRuns--;
|
|
24
|
+
if (this._activeRuns === 0) this.stop();
|
|
25
|
+
if (err) throw err;
|
|
26
|
+
return result;
|
|
27
|
+
};
|
|
28
|
+
const r = runInScope(this, fn);
|
|
29
|
+
if (isPromise(r)) return r.then(onComplete);
|
|
30
|
+
return onComplete(r);
|
|
31
|
+
}
|
|
32
|
+
stop() {
|
|
33
|
+
for (let i = 0, l = this.cleanups.length; i < l; i++) this.cleanups[i]();
|
|
34
|
+
this.cleanups.length = 0;
|
|
35
|
+
}
|
|
36
|
+
get active() {
|
|
37
|
+
return this._activeRuns > 0;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
65
40
|
function createScope(detached) {
|
|
66
|
-
|
|
41
|
+
return new Scope(detached);
|
|
67
42
|
}
|
|
68
43
|
function getCurrentScope() {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
return currentScope;
|
|
44
|
+
if (ALS) return ALS.getStore() ?? null;
|
|
45
|
+
return currentScope;
|
|
73
46
|
}
|
|
74
47
|
function setCurrentScope(scope) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
} else {
|
|
78
|
-
currentScope = scope;
|
|
79
|
-
}
|
|
48
|
+
if (ALS) ALS.enterWith(scope);
|
|
49
|
+
else currentScope = scope;
|
|
80
50
|
}
|
|
81
51
|
function runInScope(scope, fn) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return [err, result2];
|
|
93
|
-
};
|
|
94
|
-
const result = catchError(fn);
|
|
95
|
-
if (isPromise(result)) {
|
|
96
|
-
return result.then(onComplete);
|
|
97
|
-
}
|
|
98
|
-
return onComplete(result);
|
|
52
|
+
if (ALS) return catchError(() => ALS.run(scope, fn));
|
|
53
|
+
const prevScope = getCurrentScope();
|
|
54
|
+
const onComplete = ([err, result]) => {
|
|
55
|
+
if (prevScope) setCurrentScope(prevScope);
|
|
56
|
+
else unsetCurrentScope();
|
|
57
|
+
return [err, result];
|
|
58
|
+
};
|
|
59
|
+
const result = catchError(fn);
|
|
60
|
+
if (isPromise(result)) return result.then(onComplete);
|
|
61
|
+
return onComplete(result);
|
|
99
62
|
}
|
|
100
63
|
const unsetCurrentScope = () => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
} else {
|
|
104
|
-
currentScope = null;
|
|
105
|
-
}
|
|
64
|
+
if (ALS) ALS.enterWith(null);
|
|
65
|
+
else currentScope = null;
|
|
106
66
|
};
|
|
107
|
-
|
|
108
67
|
function provide(key, value, enterWith) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
);
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
currentScope.providers.set(key, value);
|
|
68
|
+
let currentScope = getCurrentScope();
|
|
69
|
+
if (!currentScope) if (enterWith) {
|
|
70
|
+
currentScope = new Scope();
|
|
71
|
+
setCurrentScope(currentScope);
|
|
72
|
+
} else {
|
|
73
|
+
console.warn(`provide() is called when there is no active scope to be associated with.\n` + captureStackTrace(provide));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
currentScope.providers.set(key, value);
|
|
123
77
|
}
|
|
124
78
|
function inject(key, defaultValue) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
} while (currentScope && value === void 0 && !handled.has(currentScope));
|
|
140
|
-
if (value === void 0 && defaultValue !== void 0) {
|
|
141
|
-
value = isFunction(defaultValue) ? defaultValue() : defaultValue;
|
|
142
|
-
}
|
|
143
|
-
return value;
|
|
79
|
+
let currentScope = getCurrentScope();
|
|
80
|
+
if (!currentScope) {
|
|
81
|
+
console.warn(`inject() is called when there is no active scope to be associated with.\n` + captureStackTrace(inject));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const handled = /* @__PURE__ */ new WeakSet();
|
|
85
|
+
let value;
|
|
86
|
+
do {
|
|
87
|
+
value = currentScope.providers.get(key);
|
|
88
|
+
handled.add(currentScope);
|
|
89
|
+
currentScope = currentScope.parent;
|
|
90
|
+
} while (currentScope && value === void 0 && !handled.has(currentScope));
|
|
91
|
+
if (value === void 0 && defaultValue !== void 0) value = isFunction(defaultValue) ? defaultValue() : defaultValue;
|
|
92
|
+
return value;
|
|
144
93
|
}
|
|
145
94
|
function hasInjectionContext() {
|
|
146
|
-
|
|
95
|
+
return !!getCurrentScope();
|
|
147
96
|
}
|
|
148
|
-
|
|
149
97
|
function createContext(providerName, contextName) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
};
|
|
164
|
-
return [injectContext, provideContext];
|
|
98
|
+
const symbolDescription = typeof providerName === "string" && !contextName ? `${providerName}Context` : contextName;
|
|
99
|
+
const injectionKey = Symbol(symbolDescription);
|
|
100
|
+
const injectContext = (fallback) => {
|
|
101
|
+
const context = inject(injectionKey, fallback);
|
|
102
|
+
if (context) return context;
|
|
103
|
+
if (context === null) return context;
|
|
104
|
+
throw new Error(`Injection \`${injectionKey.toString()}\` not found. Must be used within ${Array.isArray(providerName) ? `one of the following providers: ${providerName.join(", ")}` : `\`${providerName}\``}`);
|
|
105
|
+
};
|
|
106
|
+
const provideContext = (contextValue) => {
|
|
107
|
+
provide(injectionKey, contextValue);
|
|
108
|
+
return contextValue;
|
|
109
|
+
};
|
|
110
|
+
return [injectContext, provideContext];
|
|
165
111
|
}
|
|
166
|
-
|
|
167
112
|
function onScopeDispose(fn) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
"onScopeDispose() is called when there is no active scope to be associated with." + captureStackTrace(onScopeDispose)
|
|
172
|
-
);
|
|
173
|
-
activeScope.cleanups.push(fn);
|
|
113
|
+
const activeScope = getCurrentScope();
|
|
114
|
+
assert.ok(activeScope, "onScopeDispose() is called when there is no active scope to be associated with." + captureStackTrace(onScopeDispose));
|
|
115
|
+
activeScope.cleanups.push(fn);
|
|
174
116
|
}
|
|
175
|
-
|
|
176
117
|
function withContext(fn, detached = false) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
};
|
|
118
|
+
return function(...args) {
|
|
119
|
+
return createScope(detached).run(fn.bind(this, ...args));
|
|
120
|
+
};
|
|
181
121
|
}
|
|
182
122
|
function runWithContext(fn, isolated = false) {
|
|
183
|
-
|
|
123
|
+
return withContext(fn, isolated)();
|
|
184
124
|
}
|
|
185
125
|
function bindContext(fn) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
"bindContext() is called when there is no active scope to be associated with."
|
|
190
|
-
);
|
|
191
|
-
return () => activeScope.run(fn);
|
|
126
|
+
const activeScope = getCurrentScope();
|
|
127
|
+
assert.ok(activeScope, "bindContext() is called when there is no active scope to be associated with.");
|
|
128
|
+
return () => activeScope.run(fn);
|
|
192
129
|
}
|
|
193
|
-
|
|
194
130
|
export { bindContext, createContext, getCurrentScope, hasInjectionContext, inject, onScopeDispose, provide, runWithContext, withContext };
|
|
195
|
-
|
|
131
|
+
|
|
132
|
+
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/scope.ts","../src/hooks/provide.ts","../src/hooks/createContext.ts","../src/hooks/onScopeDispose.ts","../src/index.ts"],"sourcesContent":["import { type Awaitable, catchError, isPromise, noop } from '@andrew_l/toolkit';\nimport type { AsyncLocalStorage } from 'node:async_hooks';\n\nlet idSec = 0;\nlet ALS: AsyncLocalStorage<Scope | null> | undefined;\nlet currentScope: Scope | null = null;\n\nimport('node:async_hooks')\n .then(r => {\n ALS = new r.AsyncLocalStorage<Scope | null>();\n })\n .catch(noop);\n\nexport class Scope {\n /**\n * @internal\n */\n id: number;\n\n /**\n * @internal\n */\n providers = new Map<any, any>();\n\n /**\n * @internal\n */\n parent: Scope | null = null;\n\n /**\n * @internal\n */\n cleanups: (() => void)[] = [];\n\n /**\n * @internal\n */\n private _activeRuns: number = 0;\n\n constructor(public detached = false) {\n this.id = ++idSec;\n\n if (!detached) {\n this.parent = getCurrentScope();\n }\n }\n\n run<T>(fn: () => T): T {\n this._activeRuns++;\n\n const onComplete = ([err, result]: [Error | undefined, any]): T => {\n this._activeRuns--;\n\n if (this._activeRuns === 0) {\n this.stop();\n }\n\n if (err) {\n throw err;\n }\n\n return result;\n };\n\n const r = runInScope(this, fn);\n\n if (isPromise<any>(r)) {\n return r.then(onComplete) as T;\n }\n\n return onComplete(r);\n }\n\n stop() {\n for (let i = 0, l = this.cleanups.length; i < l; i++) {\n this.cleanups[i]();\n }\n\n this.cleanups.length = 0;\n }\n\n get active(): boolean {\n return this._activeRuns > 0;\n }\n}\n\n/**\n * @param detached - Can be used to create a \"detached\" scope.\n */\nexport function createScope(detached?: boolean): Scope {\n return new Scope(detached);\n}\n\n/**\n * @group Main\n */\nexport function getCurrentScope(): Scope | null {\n if (ALS) {\n return ALS.getStore() ?? null;\n }\n\n return currentScope;\n}\n\nexport function setCurrentScope(scope: Scope) {\n if (ALS) {\n ALS.enterWith(scope);\n } else {\n currentScope = scope;\n }\n}\n\nfunction runInScope<T>(\n scope: Scope,\n fn: () => T,\n): Awaitable<[Error | undefined, any]> {\n if (ALS) {\n return catchError(() => ALS!.run(scope, fn));\n }\n\n const prevScope = getCurrentScope();\n\n const onComplete = ([err, result]: [Error | undefined, any]): [\n Error | undefined,\n any,\n ] => {\n if (prevScope) {\n setCurrentScope(prevScope);\n } else {\n unsetCurrentScope();\n }\n\n return [err, result];\n };\n\n const result = catchError(fn);\n\n if (isPromise<any>(result)) {\n return result.then(onComplete);\n }\n\n return onComplete(result);\n}\n\nconst unsetCurrentScope = (): void => {\n if (ALS) {\n ALS.enterWith(null);\n } else {\n currentScope = null;\n }\n};\n","import { captureStackTrace, isFunction } from '@andrew_l/toolkit';\nimport { Scope, getCurrentScope, setCurrentScope } from '../scope';\n\nexport type ProvideKey = symbol | string | number | object;\nexport type ProvideValue<T = unknown> = T | undefined;\nexport type InjectionKey = symbol | string | number | object;\n\n/**\n * To provide data to a descendants\n * @param enterWith Enter into injection context (Experimental)\n * @group Main\n */\nexport function provide(key: ProvideKey, value: any, enterWith?: boolean) {\n let currentScope = getCurrentScope();\n\n if (!currentScope) {\n if (enterWith) {\n currentScope = new Scope();\n setCurrentScope(currentScope);\n } else {\n console.warn(\n `provide() is called when there is no active scope to be associated with.\\n` +\n captureStackTrace(provide),\n );\n return;\n }\n }\n\n currentScope.providers.set(key, value);\n}\n\n/**\n * Inject previously provided data\n * @group Main\n */\nexport function inject<T = any>(\n key: ProvideKey,\n defaultValue?: T | (() => T),\n): ProvideValue<T> {\n let currentScope = getCurrentScope();\n\n if (!currentScope) {\n console.warn(\n `inject() is called when there is no active scope to be associated with.\\n` +\n captureStackTrace(inject),\n );\n return;\n }\n\n const handled = new WeakSet();\n\n let value;\n\n do {\n value = currentScope!.providers.get(key);\n handled.add(currentScope!);\n currentScope = currentScope!.parent;\n } while (currentScope && value === undefined && !handled.has(currentScope));\n\n if (value === undefined && defaultValue !== undefined) {\n value = isFunction(defaultValue) ? defaultValue() : defaultValue;\n }\n\n return value;\n}\n\n/**\n * Returns true if `inject()` can be used without warning about being called in the wrong place.\n * @group Main\n */\nexport function hasInjectionContext() {\n return !!getCurrentScope();\n}\n","import { type InjectionKey, inject, provide } from './provide';\n\n/**\n * Wrapper around `provide/inject` function to simple usage.\n *\n * @param providerName - The name(s) of the providing the context.\n *\n * There are situations where context can come from multiple scopes. In such cases, you might need to give an array of names to provide your context, instead of just a single string.\n *\n * @param contextName The description for injection key symbol.\n *\n * @example\n * const [injectTraceId, provideTraceId] = createContext<string>('withContext');\n *\n * // this function will returns the same trace if for execution context\n * export const useTraceId = () => {\n * let traceId = injectTraceId(null);\n *\n * if (!traceId) {\n * traceId = uuidv4();\n * provideTraceId(traceId);\n * }\n *\n * return traceId;\n * };\n *\n * @group Main\n */\nexport function createContext<ContextValue>(\n providerName: string | string[],\n contextName?: string,\n) {\n const symbolDescription =\n typeof providerName === 'string' && !contextName\n ? `${providerName}Context`\n : contextName;\n\n const injectionKey: InjectionKey = Symbol(symbolDescription);\n\n /**\n * @param fallback The context value to return if the injection fails.\n *\n * @throws When context injection failed and no fallback is specified.\n * This happens when the scope injecting the context is not a child of the root scope providing the context.\n */\n const injectContext = <\n T extends ContextValue | null | undefined = ContextValue,\n >(\n fallback?: T | (() => T),\n ): T extends null ? ContextValue | null : ContextValue => {\n const context = inject(injectionKey, fallback);\n if (context) return context;\n\n if (context === null) return context as any;\n\n throw new Error(\n `Injection \\`${injectionKey.toString()}\\` not found. Must be used within ${\n Array.isArray(providerName)\n ? `one of the following providers: ${providerName.join(', ')}`\n : `\\`${providerName}\\``\n }`,\n );\n };\n\n const provideContext = (contextValue: ContextValue) => {\n provide(injectionKey, contextValue);\n return contextValue;\n };\n\n return [injectContext, provideContext] as const;\n}\n","import { assert, captureStackTrace } from '@andrew_l/toolkit';\nimport { getCurrentScope } from '../scope';\n\n/**\n * The callback will be invoked when the associated context completes.\n *\n * @example\n * const fn = withContext(() => {\n * onScopeDispose(() => {\n * console.log(2);\n * });\n *\n * console.log(1);\n * });\n *\n * fn();\n *\n * console.log(3);\n *\n * // 1\n * // 2\n * // 3\n *\n * @group Main\n */\nexport function onScopeDispose(fn: () => void) {\n const activeScope = getCurrentScope();\n\n assert.ok(\n activeScope,\n 'onScopeDispose() is called when there is no active scope to be associated with.' +\n captureStackTrace(onScopeDispose),\n );\n\n activeScope.cleanups.push(fn);\n}\n","import { type AnyFunction, assert } from '@andrew_l/toolkit';\nimport { createScope, getCurrentScope } from './scope';\n\nexport * from './hooks/createContext';\nexport * from './hooks/onScopeDispose';\nexport * from './hooks/provide';\nexport { getCurrentScope } from './scope';\n\n/**\n * Creates a function within the injection context and returns its result. Providers/injections are only accessible within the callback function.\n * @param isolated Do not inject parent providers into this context (Default: `false`)\n *\n * @example\n * const main = withContext(() => {\n * provide('user', { id: 1, name: 'Andrew' });\n * doCoolStaff();\n * });\n *\n * const doCoolStaff = () => {\n * const user = inject('user');\n * console.log(user); // { id: 1, name: 'Andrew' }\n * };\n *\n * main();\n *\n * @group Main\n */\nexport function withContext<T extends AnyFunction>(fn: T, detached = false): T {\n return function (this: any, ...args: any[]) {\n const scope = createScope(detached);\n return scope.run(fn.bind(this, ...args));\n } as T;\n}\n\n/**\n * Runs a function within the injection context and returns its result. Providers/injections are only accessible inside the callback function.\n * @param isolated Do not inject parent providers into this context (Default: `false`)\n * @group Main\n */\nexport function runWithContext<T = any>(fn: () => T, isolated = false): T {\n return withContext(fn, isolated)();\n}\n\n/**\n * Binds the current context to the provided function. Useful for creating callbacks with the current context, such as `setTimeout` or `EventEmitter` handlers.\n * @example\n * const main = withContext(() => {\n * provide(\"user\", { id: 1, name: \"Andrew\" });\n *\n * setInterval(bindContext(() => {\n * const user = inject(\"user\");\n * console.log(user); // { id: 1, name: 'Andrew' }\n * }));\n * });\n *\n * main();\n *\n * @group Main\n */\nexport function bindContext<T>(fn: () => T): () => T {\n const activeScope = getCurrentScope();\n\n assert.ok(\n activeScope,\n 'bindContext() is called when there is no active scope to be associated with.',\n );\n\n return () => activeScope.run(fn);\n}\n"],"names":["result"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/scope.ts","../src/hooks/provide.ts","../src/hooks/createContext.ts","../src/hooks/onScopeDispose.ts","../src/index.ts"],"sourcesContent":["import { type Awaitable, catchError, isPromise, noop } from '@andrew_l/toolkit';\nimport type { AsyncLocalStorage } from 'node:async_hooks';\n\nlet idSec = 0;\nlet ALS: AsyncLocalStorage<Scope | null> | undefined;\nlet currentScope: Scope | null = null;\n\nimport('node:async_hooks')\n .then(r => {\n ALS = new r.AsyncLocalStorage<Scope | null>();\n })\n .catch(noop);\n\nexport class Scope {\n /**\n * @internal\n */\n id: number;\n\n /**\n * @internal\n */\n providers = new Map<any, any>();\n\n /**\n * @internal\n */\n parent: Scope | null = null;\n\n /**\n * @internal\n */\n cleanups: (() => void)[] = [];\n\n /**\n * @internal\n */\n private _activeRuns: number = 0;\n\n constructor(public detached = false) {\n this.id = ++idSec;\n\n if (!detached) {\n this.parent = getCurrentScope();\n }\n }\n\n run<T>(fn: () => T): T {\n this._activeRuns++;\n\n const onComplete = ([err, result]: [Error | undefined, any]): T => {\n this._activeRuns--;\n\n if (this._activeRuns === 0) {\n this.stop();\n }\n\n if (err) {\n throw err;\n }\n\n return result;\n };\n\n const r = runInScope(this, fn);\n\n if (isPromise<any>(r)) {\n return r.then(onComplete) as T;\n }\n\n return onComplete(r);\n }\n\n stop() {\n for (let i = 0, l = this.cleanups.length; i < l; i++) {\n this.cleanups[i]();\n }\n\n this.cleanups.length = 0;\n }\n\n get active(): boolean {\n return this._activeRuns > 0;\n }\n}\n\n/**\n * @param detached - Can be used to create a \"detached\" scope.\n */\nexport function createScope(detached?: boolean): Scope {\n return new Scope(detached);\n}\n\n/**\n * @group Main\n */\nexport function getCurrentScope(): Scope | null {\n if (ALS) {\n return ALS.getStore() ?? null;\n }\n\n return currentScope;\n}\n\nexport function setCurrentScope(scope: Scope) {\n if (ALS) {\n ALS.enterWith(scope);\n } else {\n currentScope = scope;\n }\n}\n\nfunction runInScope<T>(\n scope: Scope,\n fn: () => T,\n): Awaitable<[Error | undefined, any]> {\n if (ALS) {\n return catchError(() => ALS!.run(scope, fn));\n }\n\n const prevScope = getCurrentScope();\n\n const onComplete = ([err, result]: [Error | undefined, any]): [\n Error | undefined,\n any,\n ] => {\n if (prevScope) {\n setCurrentScope(prevScope);\n } else {\n unsetCurrentScope();\n }\n\n return [err, result];\n };\n\n const result = catchError(fn);\n\n if (isPromise<any>(result)) {\n return result.then(onComplete);\n }\n\n return onComplete(result);\n}\n\nconst unsetCurrentScope = (): void => {\n if (ALS) {\n ALS.enterWith(null);\n } else {\n currentScope = null;\n }\n};\n","import { captureStackTrace, isFunction } from '@andrew_l/toolkit';\nimport { Scope, getCurrentScope, setCurrentScope } from '../scope';\n\nexport type ProvideKey = symbol | string | number | object;\nexport type ProvideValue<T = unknown> = T | undefined;\nexport type InjectionKey = symbol | string | number | object;\n\n/**\n * To provide data to a descendants\n * @param enterWith Enter into injection context (Experimental)\n * @group Main\n */\nexport function provide(key: ProvideKey, value: any, enterWith?: boolean) {\n let currentScope = getCurrentScope();\n\n if (!currentScope) {\n if (enterWith) {\n currentScope = new Scope();\n setCurrentScope(currentScope);\n } else {\n console.warn(\n `provide() is called when there is no active scope to be associated with.\\n` +\n captureStackTrace(provide),\n );\n return;\n }\n }\n\n currentScope.providers.set(key, value);\n}\n\n/**\n * Inject previously provided data\n * @group Main\n */\nexport function inject<T = any>(\n key: ProvideKey,\n defaultValue?: T | (() => T),\n): ProvideValue<T> {\n let currentScope = getCurrentScope();\n\n if (!currentScope) {\n console.warn(\n `inject() is called when there is no active scope to be associated with.\\n` +\n captureStackTrace(inject),\n );\n return;\n }\n\n const handled = new WeakSet();\n\n let value;\n\n do {\n value = currentScope!.providers.get(key);\n handled.add(currentScope!);\n currentScope = currentScope!.parent;\n } while (currentScope && value === undefined && !handled.has(currentScope));\n\n if (value === undefined && defaultValue !== undefined) {\n value = isFunction(defaultValue) ? defaultValue() : defaultValue;\n }\n\n return value;\n}\n\n/**\n * Returns true if `inject()` can be used without warning about being called in the wrong place.\n * @group Main\n */\nexport function hasInjectionContext() {\n return !!getCurrentScope();\n}\n","import { type InjectionKey, inject, provide } from './provide';\n\n/**\n * Wrapper around `provide/inject` function to simple usage.\n *\n * @param providerName - The name(s) of the providing the context.\n *\n * There are situations where context can come from multiple scopes. In such cases, you might need to give an array of names to provide your context, instead of just a single string.\n *\n * @param contextName The description for injection key symbol.\n *\n * @example\n * const [injectTraceId, provideTraceId] = createContext<string>('withContext');\n *\n * // this function will returns the same trace if for execution context\n * export const useTraceId = () => {\n * let traceId = injectTraceId(null);\n *\n * if (!traceId) {\n * traceId = uuidv4();\n * provideTraceId(traceId);\n * }\n *\n * return traceId;\n * };\n *\n * @group Main\n */\nexport function createContext<ContextValue>(\n providerName: string | string[],\n contextName?: string,\n) {\n const symbolDescription =\n typeof providerName === 'string' && !contextName\n ? `${providerName}Context`\n : contextName;\n\n const injectionKey: InjectionKey = Symbol(symbolDescription);\n\n /**\n * @param fallback The context value to return if the injection fails.\n *\n * @throws When context injection failed and no fallback is specified.\n * This happens when the scope injecting the context is not a child of the root scope providing the context.\n */\n const injectContext = <\n T extends ContextValue | null | undefined = ContextValue,\n >(\n fallback?: T | (() => T),\n ): T extends null ? ContextValue | null : ContextValue => {\n const context = inject(injectionKey, fallback);\n if (context) return context;\n\n if (context === null) return context as any;\n\n throw new Error(\n `Injection \\`${injectionKey.toString()}\\` not found. Must be used within ${\n Array.isArray(providerName)\n ? `one of the following providers: ${providerName.join(', ')}`\n : `\\`${providerName}\\``\n }`,\n );\n };\n\n const provideContext = (contextValue: ContextValue) => {\n provide(injectionKey, contextValue);\n return contextValue;\n };\n\n return [injectContext, provideContext] as const;\n}\n","import { assert, captureStackTrace } from '@andrew_l/toolkit';\nimport { getCurrentScope } from '../scope';\n\n/**\n * The callback will be invoked when the associated context completes.\n *\n * @example\n * const fn = withContext(() => {\n * onScopeDispose(() => {\n * console.log(2);\n * });\n *\n * console.log(1);\n * });\n *\n * fn();\n *\n * console.log(3);\n *\n * // 1\n * // 2\n * // 3\n *\n * @group Main\n */\nexport function onScopeDispose(fn: () => void) {\n const activeScope = getCurrentScope();\n\n assert.ok(\n activeScope,\n 'onScopeDispose() is called when there is no active scope to be associated with.' +\n captureStackTrace(onScopeDispose),\n );\n\n activeScope.cleanups.push(fn);\n}\n","import { type AnyFunction, assert } from '@andrew_l/toolkit';\nimport { createScope, getCurrentScope } from './scope';\n\nexport * from './hooks/createContext';\nexport * from './hooks/onScopeDispose';\nexport * from './hooks/provide';\nexport { getCurrentScope } from './scope';\n\n/**\n * Creates a function within the injection context and returns its result. Providers/injections are only accessible within the callback function.\n * @param isolated Do not inject parent providers into this context (Default: `false`)\n *\n * @example\n * const main = withContext(() => {\n * provide('user', { id: 1, name: 'Andrew' });\n * doCoolStaff();\n * });\n *\n * const doCoolStaff = () => {\n * const user = inject('user');\n * console.log(user); // { id: 1, name: 'Andrew' }\n * };\n *\n * main();\n *\n * @group Main\n */\nexport function withContext<T extends AnyFunction>(fn: T, detached = false): T {\n return function (this: any, ...args: any[]) {\n const scope = createScope(detached);\n return scope.run(fn.bind(this, ...args));\n } as T;\n}\n\n/**\n * Runs a function within the injection context and returns its result. Providers/injections are only accessible inside the callback function.\n * @param isolated Do not inject parent providers into this context (Default: `false`)\n * @group Main\n */\nexport function runWithContext<T = any>(fn: () => T, isolated = false): T {\n return withContext(fn, isolated)();\n}\n\n/**\n * Binds the current context to the provided function. Useful for creating callbacks with the current context, such as `setTimeout` or `EventEmitter` handlers.\n * @example\n * const main = withContext(() => {\n * provide(\"user\", { id: 1, name: \"Andrew\" });\n *\n * setInterval(bindContext(() => {\n * const user = inject(\"user\");\n * console.log(user); // { id: 1, name: 'Andrew' }\n * }));\n * });\n *\n * main();\n *\n * @group Main\n */\nexport function bindContext<T>(fn: () => T): () => T {\n const activeScope = getCurrentScope();\n\n assert.ok(\n activeScope,\n 'bindContext() is called when there is no active scope to be associated with.',\n );\n\n return () => activeScope.run(fn);\n}\n"],"mappings":";AAGA,IAAI,QAAQ;AACZ,IAAI;AACJ,IAAI,eAA6B;AAEjC,OAAO,mBAAmB,CACvB,MAAK,MAAK;CACT,MAAM,IAAI,EAAE,kBAAgC;AAC9C,CAAC,CAAC,CACD,MAAM,IAAI;AAEb,IAAa,QAAb,MAAmB;CA0BE;;CAtBnB,4BAAA,IAAA,IAAA;;CAKA,WAAA,CAAA;;;EAKA,KAAA,WAAuB;;;;CAKvB,IAAA,IAAA;;;;GAKQ,IAAA,KAAA,gBAAsB,GAAA,KAAA,KAAA;GAE9B,IAAA,KAAA,MAAmB;GAAA,OAAA;EACjB;EAEA,MAAK,IAAA,WACE,MAAA,EAAS;EAElB,IAAA,UAAA,CAAA,GAAA,OAAA,EAAA,KAAA,UAAA;EAEA,OAAuB,WAAA,CAAA;;QAGf;OACJ,IAAK,IAAA,GAAA,IAAA,KAAA,SAAA,QAAA,IAAA,GAAA,KAAA,KAAA,SAAA,EAAA,CAAA;OAED,SAAK,SAAA;;KAQT,SAAO;EACT,OAAA,KAAA,cAAA;;;SASF,YAAA,UAAA;CAEA,OAAO,IAAA,MAAA,QAAA;;SAMP,kBAAA;CAEA,IAAI,KAAA,OAAkB,IAAA,SAAA,KAAA;QACpB;;AAEJ,SAAA,gBAAA,OAAA;;;;AAKA,SAAgB,WAAA,OAAY,IAA2B;CACrD,IAAA,KAAO,OAAI,iBAAc,IAAA,IAAA,OAAA,EAAA,CAAA;CAC3B,MAAA,YAAA,gBAAA;;;;EAKA,OAAgB,CAAA,KAAA,MAAA;CACd;CAIA,MAAA,SAAO,WAAA,EAAA;CACT,IAAA,UAAA,MAAA,GAAA,OAAA,OAAA,KAAA,UAAA;CAEA,OAAA,WAAgB,MAAgB;;MAI5B,0BAAe;CAEnB,IAAA,KAAA,IAAA,UAAA,IAAA;MAEA,eACE;;SAaM,QACF,KAAA,OAAA,WAAgB;oBAEhB,gBAAkB;KAGpB,CAAA,cAAa,IAAM,WAAA;EACrB,eAAA,IAAA,MAAA;EAEA,gBAAe,YAAa;CAE5B,OAAI;EAIJ,QAAO,KAAA,+EAAiB,kBAAA,OAAA,CAAA;EAC1B;CAEA;CACE,aACM,UAAU,IAAI,KAAA,KAAA;;;;;;;;CCtItB,MAAA,0BAAqD,IAAA,QAAqB;CACxE,IAAI;CAEJ,GAAA;EAEI,QAAA,aAAmB,UAAM,IAAA,GAAA;EACzB,QAAA,IAAA,YAAgB;EAClB,eAAO,aAAA;UACG,gBACN,UAAA,KAAA,KAAA,CAAA,QAAA,IAAA,YAAA;KAGF,UAAA,KAAA,KAAA,iBAAA,KAAA,GAAA,QAAA,WAAA,YAAA,IAAA,aAAA,IAAA;CACF,OAAA;;;;;SAcE,cAAe,cAAgB,aAAA;CAEnC,MAAK,oBAAc,OAAA,iBAAA,YAAA,CAAA,cAAA,GAAA,aAAA,WAAA;OACjB,eACE,OAAA,iBAAA;CAIJ,MAAA,iBAAA,aAAA;EAEA,MAAM,UAAA,OAAA,cAAc,QAAQ;EAE5B,IAAI,SAAA,OAAA;EAEJ,IAAG,YAAA,MAAA,OAAA;EACD,MAAA,IAAQ,MAAA,eAAwB,aAAO,SAAA,EAAA,oCAAA,MAAA,QAAA,YAAA,IAAA,mCAAA,aAAA,KAAA,IAAA,MAAA,KAAA,aAAA,KAAA;;OAEvC,kBAAe,iBAAc;EAC/B,QAAS,cAAA,YAA0B;EAEnC,OAAI;CAIJ;CACF,OAAA,CAAA,eAAA,cAAA;;;CAMA,MAAA,cAAgB,gBAAsB;CACpC,OAAO,GAAE,aAAA,oFAAgB,kBAAA,cAAA,CAAA;CAC3B,YAAA,SAAA,KAAA,EAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andrew_l/context",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Like composition api but for Node.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -21,26 +21,27 @@
|
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|
|
23
23
|
"import": "./dist/index.mjs",
|
|
24
|
-
"require": "./dist/index.
|
|
24
|
+
"require": "./dist/index.mjs",
|
|
25
|
+
"types": "./dist/index.d.mts"
|
|
25
26
|
}
|
|
26
27
|
},
|
|
27
|
-
"main": "./dist/index.
|
|
28
|
-
"types": "./dist/index.d.
|
|
28
|
+
"main": "./dist/index.mjs",
|
|
29
|
+
"types": "./dist/index.d.mts",
|
|
29
30
|
"files": [
|
|
30
31
|
"dist"
|
|
31
32
|
],
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"@types/node": "22.10.5",
|
|
34
|
-
"
|
|
35
|
-
"
|
|
35
|
+
"obuild": "^0.4.37",
|
|
36
|
+
"typescript": "6.0.3",
|
|
36
37
|
"vitest": "^3.2.4"
|
|
37
38
|
},
|
|
38
39
|
"dependencies": {
|
|
39
|
-
"@andrew_l/toolkit": "0.
|
|
40
|
+
"@andrew_l/toolkit": "0.4.0"
|
|
40
41
|
},
|
|
41
42
|
"scripts": {
|
|
42
43
|
"check-types": "tsc --noEmit",
|
|
43
|
-
"build": "
|
|
44
|
+
"build": "obuild",
|
|
44
45
|
"test": "vitest run --typecheck",
|
|
45
46
|
"test:watch": "vitest watch --typecheck"
|
|
46
47
|
}
|
package/dist/index.cjs
DELETED
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const toolkit = require('@andrew_l/toolkit');
|
|
4
|
-
|
|
5
|
-
let idSec = 0;
|
|
6
|
-
let ALS;
|
|
7
|
-
let currentScope = null;
|
|
8
|
-
import('node:async_hooks').then((r) => {
|
|
9
|
-
ALS = new r.AsyncLocalStorage();
|
|
10
|
-
}).catch(toolkit.noop);
|
|
11
|
-
class Scope {
|
|
12
|
-
constructor(detached = false) {
|
|
13
|
-
this.detached = detached;
|
|
14
|
-
this.id = ++idSec;
|
|
15
|
-
if (!detached) {
|
|
16
|
-
this.parent = getCurrentScope();
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* @internal
|
|
21
|
-
*/
|
|
22
|
-
id;
|
|
23
|
-
/**
|
|
24
|
-
* @internal
|
|
25
|
-
*/
|
|
26
|
-
providers = /* @__PURE__ */ new Map();
|
|
27
|
-
/**
|
|
28
|
-
* @internal
|
|
29
|
-
*/
|
|
30
|
-
parent = null;
|
|
31
|
-
/**
|
|
32
|
-
* @internal
|
|
33
|
-
*/
|
|
34
|
-
cleanups = [];
|
|
35
|
-
/**
|
|
36
|
-
* @internal
|
|
37
|
-
*/
|
|
38
|
-
_activeRuns = 0;
|
|
39
|
-
run(fn) {
|
|
40
|
-
this._activeRuns++;
|
|
41
|
-
const onComplete = ([err, result]) => {
|
|
42
|
-
this._activeRuns--;
|
|
43
|
-
if (this._activeRuns === 0) {
|
|
44
|
-
this.stop();
|
|
45
|
-
}
|
|
46
|
-
if (err) {
|
|
47
|
-
throw err;
|
|
48
|
-
}
|
|
49
|
-
return result;
|
|
50
|
-
};
|
|
51
|
-
const r = runInScope(this, fn);
|
|
52
|
-
if (toolkit.isPromise(r)) {
|
|
53
|
-
return r.then(onComplete);
|
|
54
|
-
}
|
|
55
|
-
return onComplete(r);
|
|
56
|
-
}
|
|
57
|
-
stop() {
|
|
58
|
-
for (let i = 0, l = this.cleanups.length; i < l; i++) {
|
|
59
|
-
this.cleanups[i]();
|
|
60
|
-
}
|
|
61
|
-
this.cleanups.length = 0;
|
|
62
|
-
}
|
|
63
|
-
get active() {
|
|
64
|
-
return this._activeRuns > 0;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function createScope(detached) {
|
|
68
|
-
return new Scope(detached);
|
|
69
|
-
}
|
|
70
|
-
function getCurrentScope() {
|
|
71
|
-
if (ALS) {
|
|
72
|
-
return ALS.getStore() ?? null;
|
|
73
|
-
}
|
|
74
|
-
return currentScope;
|
|
75
|
-
}
|
|
76
|
-
function setCurrentScope(scope) {
|
|
77
|
-
if (ALS) {
|
|
78
|
-
ALS.enterWith(scope);
|
|
79
|
-
} else {
|
|
80
|
-
currentScope = scope;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function runInScope(scope, fn) {
|
|
84
|
-
if (ALS) {
|
|
85
|
-
return toolkit.catchError(() => ALS.run(scope, fn));
|
|
86
|
-
}
|
|
87
|
-
const prevScope = getCurrentScope();
|
|
88
|
-
const onComplete = ([err, result2]) => {
|
|
89
|
-
if (prevScope) {
|
|
90
|
-
setCurrentScope(prevScope);
|
|
91
|
-
} else {
|
|
92
|
-
unsetCurrentScope();
|
|
93
|
-
}
|
|
94
|
-
return [err, result2];
|
|
95
|
-
};
|
|
96
|
-
const result = toolkit.catchError(fn);
|
|
97
|
-
if (toolkit.isPromise(result)) {
|
|
98
|
-
return result.then(onComplete);
|
|
99
|
-
}
|
|
100
|
-
return onComplete(result);
|
|
101
|
-
}
|
|
102
|
-
const unsetCurrentScope = () => {
|
|
103
|
-
if (ALS) {
|
|
104
|
-
ALS.enterWith(null);
|
|
105
|
-
} else {
|
|
106
|
-
currentScope = null;
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
function provide(key, value, enterWith) {
|
|
111
|
-
let currentScope = getCurrentScope();
|
|
112
|
-
if (!currentScope) {
|
|
113
|
-
if (enterWith) {
|
|
114
|
-
currentScope = new Scope();
|
|
115
|
-
setCurrentScope(currentScope);
|
|
116
|
-
} else {
|
|
117
|
-
console.warn(
|
|
118
|
-
`provide() is called when there is no active scope to be associated with.
|
|
119
|
-
` + toolkit.captureStackTrace(provide)
|
|
120
|
-
);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
currentScope.providers.set(key, value);
|
|
125
|
-
}
|
|
126
|
-
function inject(key, defaultValue) {
|
|
127
|
-
let currentScope = getCurrentScope();
|
|
128
|
-
if (!currentScope) {
|
|
129
|
-
console.warn(
|
|
130
|
-
`inject() is called when there is no active scope to be associated with.
|
|
131
|
-
` + toolkit.captureStackTrace(inject)
|
|
132
|
-
);
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
const handled = /* @__PURE__ */ new WeakSet();
|
|
136
|
-
let value;
|
|
137
|
-
do {
|
|
138
|
-
value = currentScope.providers.get(key);
|
|
139
|
-
handled.add(currentScope);
|
|
140
|
-
currentScope = currentScope.parent;
|
|
141
|
-
} while (currentScope && value === void 0 && !handled.has(currentScope));
|
|
142
|
-
if (value === void 0 && defaultValue !== void 0) {
|
|
143
|
-
value = toolkit.isFunction(defaultValue) ? defaultValue() : defaultValue;
|
|
144
|
-
}
|
|
145
|
-
return value;
|
|
146
|
-
}
|
|
147
|
-
function hasInjectionContext() {
|
|
148
|
-
return !!getCurrentScope();
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function createContext(providerName, contextName) {
|
|
152
|
-
const symbolDescription = typeof providerName === "string" && !contextName ? `${providerName}Context` : contextName;
|
|
153
|
-
const injectionKey = Symbol(symbolDescription);
|
|
154
|
-
const injectContext = (fallback) => {
|
|
155
|
-
const context = inject(injectionKey, fallback);
|
|
156
|
-
if (context) return context;
|
|
157
|
-
if (context === null) return context;
|
|
158
|
-
throw new Error(
|
|
159
|
-
`Injection \`${injectionKey.toString()}\` not found. Must be used within ${Array.isArray(providerName) ? `one of the following providers: ${providerName.join(", ")}` : `\`${providerName}\``}`
|
|
160
|
-
);
|
|
161
|
-
};
|
|
162
|
-
const provideContext = (contextValue) => {
|
|
163
|
-
provide(injectionKey, contextValue);
|
|
164
|
-
return contextValue;
|
|
165
|
-
};
|
|
166
|
-
return [injectContext, provideContext];
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function onScopeDispose(fn) {
|
|
170
|
-
const activeScope = getCurrentScope();
|
|
171
|
-
toolkit.assert.ok(
|
|
172
|
-
activeScope,
|
|
173
|
-
"onScopeDispose() is called when there is no active scope to be associated with." + toolkit.captureStackTrace(onScopeDispose)
|
|
174
|
-
);
|
|
175
|
-
activeScope.cleanups.push(fn);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function withContext(fn, detached = false) {
|
|
179
|
-
return function(...args) {
|
|
180
|
-
const scope = createScope(detached);
|
|
181
|
-
return scope.run(fn.bind(this, ...args));
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
function runWithContext(fn, isolated = false) {
|
|
185
|
-
return withContext(fn, isolated)();
|
|
186
|
-
}
|
|
187
|
-
function bindContext(fn) {
|
|
188
|
-
const activeScope = getCurrentScope();
|
|
189
|
-
toolkit.assert.ok(
|
|
190
|
-
activeScope,
|
|
191
|
-
"bindContext() is called when there is no active scope to be associated with."
|
|
192
|
-
);
|
|
193
|
-
return () => activeScope.run(fn);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
exports.bindContext = bindContext;
|
|
197
|
-
exports.createContext = createContext;
|
|
198
|
-
exports.getCurrentScope = getCurrentScope;
|
|
199
|
-
exports.hasInjectionContext = hasInjectionContext;
|
|
200
|
-
exports.inject = inject;
|
|
201
|
-
exports.onScopeDispose = onScopeDispose;
|
|
202
|
-
exports.provide = provide;
|
|
203
|
-
exports.runWithContext = runWithContext;
|
|
204
|
-
exports.withContext = withContext;
|
|
205
|
-
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/scope.ts","../src/hooks/provide.ts","../src/hooks/createContext.ts","../src/hooks/onScopeDispose.ts","../src/index.ts"],"sourcesContent":["import { type Awaitable, catchError, isPromise, noop } from '@andrew_l/toolkit';\nimport type { AsyncLocalStorage } from 'node:async_hooks';\n\nlet idSec = 0;\nlet ALS: AsyncLocalStorage<Scope | null> | undefined;\nlet currentScope: Scope | null = null;\n\nimport('node:async_hooks')\n .then(r => {\n ALS = new r.AsyncLocalStorage<Scope | null>();\n })\n .catch(noop);\n\nexport class Scope {\n /**\n * @internal\n */\n id: number;\n\n /**\n * @internal\n */\n providers = new Map<any, any>();\n\n /**\n * @internal\n */\n parent: Scope | null = null;\n\n /**\n * @internal\n */\n cleanups: (() => void)[] = [];\n\n /**\n * @internal\n */\n private _activeRuns: number = 0;\n\n constructor(public detached = false) {\n this.id = ++idSec;\n\n if (!detached) {\n this.parent = getCurrentScope();\n }\n }\n\n run<T>(fn: () => T): T {\n this._activeRuns++;\n\n const onComplete = ([err, result]: [Error | undefined, any]): T => {\n this._activeRuns--;\n\n if (this._activeRuns === 0) {\n this.stop();\n }\n\n if (err) {\n throw err;\n }\n\n return result;\n };\n\n const r = runInScope(this, fn);\n\n if (isPromise<any>(r)) {\n return r.then(onComplete) as T;\n }\n\n return onComplete(r);\n }\n\n stop() {\n for (let i = 0, l = this.cleanups.length; i < l; i++) {\n this.cleanups[i]();\n }\n\n this.cleanups.length = 0;\n }\n\n get active(): boolean {\n return this._activeRuns > 0;\n }\n}\n\n/**\n * @param detached - Can be used to create a \"detached\" scope.\n */\nexport function createScope(detached?: boolean): Scope {\n return new Scope(detached);\n}\n\n/**\n * @group Main\n */\nexport function getCurrentScope(): Scope | null {\n if (ALS) {\n return ALS.getStore() ?? null;\n }\n\n return currentScope;\n}\n\nexport function setCurrentScope(scope: Scope) {\n if (ALS) {\n ALS.enterWith(scope);\n } else {\n currentScope = scope;\n }\n}\n\nfunction runInScope<T>(\n scope: Scope,\n fn: () => T,\n): Awaitable<[Error | undefined, any]> {\n if (ALS) {\n return catchError(() => ALS!.run(scope, fn));\n }\n\n const prevScope = getCurrentScope();\n\n const onComplete = ([err, result]: [Error | undefined, any]): [\n Error | undefined,\n any,\n ] => {\n if (prevScope) {\n setCurrentScope(prevScope);\n } else {\n unsetCurrentScope();\n }\n\n return [err, result];\n };\n\n const result = catchError(fn);\n\n if (isPromise<any>(result)) {\n return result.then(onComplete);\n }\n\n return onComplete(result);\n}\n\nconst unsetCurrentScope = (): void => {\n if (ALS) {\n ALS.enterWith(null);\n } else {\n currentScope = null;\n }\n};\n","import { captureStackTrace, isFunction } from '@andrew_l/toolkit';\nimport { Scope, getCurrentScope, setCurrentScope } from '../scope';\n\nexport type ProvideKey = symbol | string | number | object;\nexport type ProvideValue<T = unknown> = T | undefined;\nexport type InjectionKey = symbol | string | number | object;\n\n/**\n * To provide data to a descendants\n * @param enterWith Enter into injection context (Experimental)\n * @group Main\n */\nexport function provide(key: ProvideKey, value: any, enterWith?: boolean) {\n let currentScope = getCurrentScope();\n\n if (!currentScope) {\n if (enterWith) {\n currentScope = new Scope();\n setCurrentScope(currentScope);\n } else {\n console.warn(\n `provide() is called when there is no active scope to be associated with.\\n` +\n captureStackTrace(provide),\n );\n return;\n }\n }\n\n currentScope.providers.set(key, value);\n}\n\n/**\n * Inject previously provided data\n * @group Main\n */\nexport function inject<T = any>(\n key: ProvideKey,\n defaultValue?: T | (() => T),\n): ProvideValue<T> {\n let currentScope = getCurrentScope();\n\n if (!currentScope) {\n console.warn(\n `inject() is called when there is no active scope to be associated with.\\n` +\n captureStackTrace(inject),\n );\n return;\n }\n\n const handled = new WeakSet();\n\n let value;\n\n do {\n value = currentScope!.providers.get(key);\n handled.add(currentScope!);\n currentScope = currentScope!.parent;\n } while (currentScope && value === undefined && !handled.has(currentScope));\n\n if (value === undefined && defaultValue !== undefined) {\n value = isFunction(defaultValue) ? defaultValue() : defaultValue;\n }\n\n return value;\n}\n\n/**\n * Returns true if `inject()` can be used without warning about being called in the wrong place.\n * @group Main\n */\nexport function hasInjectionContext() {\n return !!getCurrentScope();\n}\n","import { type InjectionKey, inject, provide } from './provide';\n\n/**\n * Wrapper around `provide/inject` function to simple usage.\n *\n * @param providerName - The name(s) of the providing the context.\n *\n * There are situations where context can come from multiple scopes. In such cases, you might need to give an array of names to provide your context, instead of just a single string.\n *\n * @param contextName The description for injection key symbol.\n *\n * @example\n * const [injectTraceId, provideTraceId] = createContext<string>('withContext');\n *\n * // this function will returns the same trace if for execution context\n * export const useTraceId = () => {\n * let traceId = injectTraceId(null);\n *\n * if (!traceId) {\n * traceId = uuidv4();\n * provideTraceId(traceId);\n * }\n *\n * return traceId;\n * };\n *\n * @group Main\n */\nexport function createContext<ContextValue>(\n providerName: string | string[],\n contextName?: string,\n) {\n const symbolDescription =\n typeof providerName === 'string' && !contextName\n ? `${providerName}Context`\n : contextName;\n\n const injectionKey: InjectionKey = Symbol(symbolDescription);\n\n /**\n * @param fallback The context value to return if the injection fails.\n *\n * @throws When context injection failed and no fallback is specified.\n * This happens when the scope injecting the context is not a child of the root scope providing the context.\n */\n const injectContext = <\n T extends ContextValue | null | undefined = ContextValue,\n >(\n fallback?: T | (() => T),\n ): T extends null ? ContextValue | null : ContextValue => {\n const context = inject(injectionKey, fallback);\n if (context) return context;\n\n if (context === null) return context as any;\n\n throw new Error(\n `Injection \\`${injectionKey.toString()}\\` not found. Must be used within ${\n Array.isArray(providerName)\n ? `one of the following providers: ${providerName.join(', ')}`\n : `\\`${providerName}\\``\n }`,\n );\n };\n\n const provideContext = (contextValue: ContextValue) => {\n provide(injectionKey, contextValue);\n return contextValue;\n };\n\n return [injectContext, provideContext] as const;\n}\n","import { assert, captureStackTrace } from '@andrew_l/toolkit';\nimport { getCurrentScope } from '../scope';\n\n/**\n * The callback will be invoked when the associated context completes.\n *\n * @example\n * const fn = withContext(() => {\n * onScopeDispose(() => {\n * console.log(2);\n * });\n *\n * console.log(1);\n * });\n *\n * fn();\n *\n * console.log(3);\n *\n * // 1\n * // 2\n * // 3\n *\n * @group Main\n */\nexport function onScopeDispose(fn: () => void) {\n const activeScope = getCurrentScope();\n\n assert.ok(\n activeScope,\n 'onScopeDispose() is called when there is no active scope to be associated with.' +\n captureStackTrace(onScopeDispose),\n );\n\n activeScope.cleanups.push(fn);\n}\n","import { type AnyFunction, assert } from '@andrew_l/toolkit';\nimport { createScope, getCurrentScope } from './scope';\n\nexport * from './hooks/createContext';\nexport * from './hooks/onScopeDispose';\nexport * from './hooks/provide';\nexport { getCurrentScope } from './scope';\n\n/**\n * Creates a function within the injection context and returns its result. Providers/injections are only accessible within the callback function.\n * @param isolated Do not inject parent providers into this context (Default: `false`)\n *\n * @example\n * const main = withContext(() => {\n * provide('user', { id: 1, name: 'Andrew' });\n * doCoolStaff();\n * });\n *\n * const doCoolStaff = () => {\n * const user = inject('user');\n * console.log(user); // { id: 1, name: 'Andrew' }\n * };\n *\n * main();\n *\n * @group Main\n */\nexport function withContext<T extends AnyFunction>(fn: T, detached = false): T {\n return function (this: any, ...args: any[]) {\n const scope = createScope(detached);\n return scope.run(fn.bind(this, ...args));\n } as T;\n}\n\n/**\n * Runs a function within the injection context and returns its result. Providers/injections are only accessible inside the callback function.\n * @param isolated Do not inject parent providers into this context (Default: `false`)\n * @group Main\n */\nexport function runWithContext<T = any>(fn: () => T, isolated = false): T {\n return withContext(fn, isolated)();\n}\n\n/**\n * Binds the current context to the provided function. Useful for creating callbacks with the current context, such as `setTimeout` or `EventEmitter` handlers.\n * @example\n * const main = withContext(() => {\n * provide(\"user\", { id: 1, name: \"Andrew\" });\n *\n * setInterval(bindContext(() => {\n * const user = inject(\"user\");\n * console.log(user); // { id: 1, name: 'Andrew' }\n * }));\n * });\n *\n * main();\n *\n * @group Main\n */\nexport function bindContext<T>(fn: () => T): () => T {\n const activeScope = getCurrentScope();\n\n assert.ok(\n activeScope,\n 'bindContext() is called when there is no active scope to be associated with.',\n );\n\n return () => activeScope.run(fn);\n}\n"],"names":["noop","isPromise","catchError","result","captureStackTrace","isFunction","assert"],"mappings":"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"}
|
package/dist/index.d.cts
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import { AnyFunction } from '@andrew_l/toolkit';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Wrapper around `provide/inject` function to simple usage.
|
|
5
|
-
*
|
|
6
|
-
* @param providerName - The name(s) of the providing the context.
|
|
7
|
-
*
|
|
8
|
-
* There are situations where context can come from multiple scopes. In such cases, you might need to give an array of names to provide your context, instead of just a single string.
|
|
9
|
-
*
|
|
10
|
-
* @param contextName The description for injection key symbol.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* const [injectTraceId, provideTraceId] = createContext<string>('withContext');
|
|
14
|
-
*
|
|
15
|
-
* // this function will returns the same trace if for execution context
|
|
16
|
-
* export const useTraceId = () => {
|
|
17
|
-
* let traceId = injectTraceId(null);
|
|
18
|
-
*
|
|
19
|
-
* if (!traceId) {
|
|
20
|
-
* traceId = uuidv4();
|
|
21
|
-
* provideTraceId(traceId);
|
|
22
|
-
* }
|
|
23
|
-
*
|
|
24
|
-
* return traceId;
|
|
25
|
-
* };
|
|
26
|
-
*
|
|
27
|
-
* @group Main
|
|
28
|
-
*/
|
|
29
|
-
declare function createContext<ContextValue>(providerName: string | string[], contextName?: string): readonly [<T extends ContextValue | null | undefined = ContextValue>(fallback?: T | (() => T)) => T extends null ? ContextValue | null : ContextValue, (contextValue: ContextValue) => ContextValue];
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* The callback will be invoked when the associated context completes.
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* const fn = withContext(() => {
|
|
36
|
-
* onScopeDispose(() => {
|
|
37
|
-
* console.log(2);
|
|
38
|
-
* });
|
|
39
|
-
*
|
|
40
|
-
* console.log(1);
|
|
41
|
-
* });
|
|
42
|
-
*
|
|
43
|
-
* fn();
|
|
44
|
-
*
|
|
45
|
-
* console.log(3);
|
|
46
|
-
*
|
|
47
|
-
* // 1
|
|
48
|
-
* // 2
|
|
49
|
-
* // 3
|
|
50
|
-
*
|
|
51
|
-
* @group Main
|
|
52
|
-
*/
|
|
53
|
-
declare function onScopeDispose(fn: () => void): void;
|
|
54
|
-
|
|
55
|
-
type ProvideKey = symbol | string | number | object;
|
|
56
|
-
type ProvideValue<T = unknown> = T | undefined;
|
|
57
|
-
type InjectionKey = symbol | string | number | object;
|
|
58
|
-
/**
|
|
59
|
-
* To provide data to a descendants
|
|
60
|
-
* @param enterWith Enter into injection context (Experimental)
|
|
61
|
-
* @group Main
|
|
62
|
-
*/
|
|
63
|
-
declare function provide(key: ProvideKey, value: any, enterWith?: boolean): void;
|
|
64
|
-
/**
|
|
65
|
-
* Inject previously provided data
|
|
66
|
-
* @group Main
|
|
67
|
-
*/
|
|
68
|
-
declare function inject<T = any>(key: ProvideKey, defaultValue?: T | (() => T)): ProvideValue<T>;
|
|
69
|
-
/**
|
|
70
|
-
* Returns true if `inject()` can be used without warning about being called in the wrong place.
|
|
71
|
-
* @group Main
|
|
72
|
-
*/
|
|
73
|
-
declare function hasInjectionContext(): boolean;
|
|
74
|
-
|
|
75
|
-
declare class Scope {
|
|
76
|
-
detached: boolean;
|
|
77
|
-
/**
|
|
78
|
-
* @internal
|
|
79
|
-
*/
|
|
80
|
-
id: number;
|
|
81
|
-
/**
|
|
82
|
-
* @internal
|
|
83
|
-
*/
|
|
84
|
-
providers: Map<any, any>;
|
|
85
|
-
/**
|
|
86
|
-
* @internal
|
|
87
|
-
*/
|
|
88
|
-
parent: Scope | null;
|
|
89
|
-
/**
|
|
90
|
-
* @internal
|
|
91
|
-
*/
|
|
92
|
-
cleanups: (() => void)[];
|
|
93
|
-
/**
|
|
94
|
-
* @internal
|
|
95
|
-
*/
|
|
96
|
-
private _activeRuns;
|
|
97
|
-
constructor(detached?: boolean);
|
|
98
|
-
run<T>(fn: () => T): T;
|
|
99
|
-
stop(): void;
|
|
100
|
-
get active(): boolean;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* @group Main
|
|
104
|
-
*/
|
|
105
|
-
declare function getCurrentScope(): Scope | null;
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Creates a function within the injection context and returns its result. Providers/injections are only accessible within the callback function.
|
|
109
|
-
* @param isolated Do not inject parent providers into this context (Default: `false`)
|
|
110
|
-
*
|
|
111
|
-
* @example
|
|
112
|
-
* const main = withContext(() => {
|
|
113
|
-
* provide('user', { id: 1, name: 'Andrew' });
|
|
114
|
-
* doCoolStaff();
|
|
115
|
-
* });
|
|
116
|
-
*
|
|
117
|
-
* const doCoolStaff = () => {
|
|
118
|
-
* const user = inject('user');
|
|
119
|
-
* console.log(user); // { id: 1, name: 'Andrew' }
|
|
120
|
-
* };
|
|
121
|
-
*
|
|
122
|
-
* main();
|
|
123
|
-
*
|
|
124
|
-
* @group Main
|
|
125
|
-
*/
|
|
126
|
-
declare function withContext<T extends AnyFunction>(fn: T, detached?: boolean): T;
|
|
127
|
-
/**
|
|
128
|
-
* Runs a function within the injection context and returns its result. Providers/injections are only accessible inside the callback function.
|
|
129
|
-
* @param isolated Do not inject parent providers into this context (Default: `false`)
|
|
130
|
-
* @group Main
|
|
131
|
-
*/
|
|
132
|
-
declare function runWithContext<T = any>(fn: () => T, isolated?: boolean): T;
|
|
133
|
-
/**
|
|
134
|
-
* Binds the current context to the provided function. Useful for creating callbacks with the current context, such as `setTimeout` or `EventEmitter` handlers.
|
|
135
|
-
* @example
|
|
136
|
-
* const main = withContext(() => {
|
|
137
|
-
* provide("user", { id: 1, name: "Andrew" });
|
|
138
|
-
*
|
|
139
|
-
* setInterval(bindContext(() => {
|
|
140
|
-
* const user = inject("user");
|
|
141
|
-
* console.log(user); // { id: 1, name: 'Andrew' }
|
|
142
|
-
* }));
|
|
143
|
-
* });
|
|
144
|
-
*
|
|
145
|
-
* main();
|
|
146
|
-
*
|
|
147
|
-
* @group Main
|
|
148
|
-
*/
|
|
149
|
-
declare function bindContext<T>(fn: () => T): () => T;
|
|
150
|
-
|
|
151
|
-
export { type InjectionKey, type ProvideKey, type ProvideValue, bindContext, createContext, getCurrentScope, hasInjectionContext, inject, onScopeDispose, provide, runWithContext, withContext };
|
package/dist/index.d.ts
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import { AnyFunction } from '@andrew_l/toolkit';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Wrapper around `provide/inject` function to simple usage.
|
|
5
|
-
*
|
|
6
|
-
* @param providerName - The name(s) of the providing the context.
|
|
7
|
-
*
|
|
8
|
-
* There are situations where context can come from multiple scopes. In such cases, you might need to give an array of names to provide your context, instead of just a single string.
|
|
9
|
-
*
|
|
10
|
-
* @param contextName The description for injection key symbol.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* const [injectTraceId, provideTraceId] = createContext<string>('withContext');
|
|
14
|
-
*
|
|
15
|
-
* // this function will returns the same trace if for execution context
|
|
16
|
-
* export const useTraceId = () => {
|
|
17
|
-
* let traceId = injectTraceId(null);
|
|
18
|
-
*
|
|
19
|
-
* if (!traceId) {
|
|
20
|
-
* traceId = uuidv4();
|
|
21
|
-
* provideTraceId(traceId);
|
|
22
|
-
* }
|
|
23
|
-
*
|
|
24
|
-
* return traceId;
|
|
25
|
-
* };
|
|
26
|
-
*
|
|
27
|
-
* @group Main
|
|
28
|
-
*/
|
|
29
|
-
declare function createContext<ContextValue>(providerName: string | string[], contextName?: string): readonly [<T extends ContextValue | null | undefined = ContextValue>(fallback?: T | (() => T)) => T extends null ? ContextValue | null : ContextValue, (contextValue: ContextValue) => ContextValue];
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* The callback will be invoked when the associated context completes.
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* const fn = withContext(() => {
|
|
36
|
-
* onScopeDispose(() => {
|
|
37
|
-
* console.log(2);
|
|
38
|
-
* });
|
|
39
|
-
*
|
|
40
|
-
* console.log(1);
|
|
41
|
-
* });
|
|
42
|
-
*
|
|
43
|
-
* fn();
|
|
44
|
-
*
|
|
45
|
-
* console.log(3);
|
|
46
|
-
*
|
|
47
|
-
* // 1
|
|
48
|
-
* // 2
|
|
49
|
-
* // 3
|
|
50
|
-
*
|
|
51
|
-
* @group Main
|
|
52
|
-
*/
|
|
53
|
-
declare function onScopeDispose(fn: () => void): void;
|
|
54
|
-
|
|
55
|
-
type ProvideKey = symbol | string | number | object;
|
|
56
|
-
type ProvideValue<T = unknown> = T | undefined;
|
|
57
|
-
type InjectionKey = symbol | string | number | object;
|
|
58
|
-
/**
|
|
59
|
-
* To provide data to a descendants
|
|
60
|
-
* @param enterWith Enter into injection context (Experimental)
|
|
61
|
-
* @group Main
|
|
62
|
-
*/
|
|
63
|
-
declare function provide(key: ProvideKey, value: any, enterWith?: boolean): void;
|
|
64
|
-
/**
|
|
65
|
-
* Inject previously provided data
|
|
66
|
-
* @group Main
|
|
67
|
-
*/
|
|
68
|
-
declare function inject<T = any>(key: ProvideKey, defaultValue?: T | (() => T)): ProvideValue<T>;
|
|
69
|
-
/**
|
|
70
|
-
* Returns true if `inject()` can be used without warning about being called in the wrong place.
|
|
71
|
-
* @group Main
|
|
72
|
-
*/
|
|
73
|
-
declare function hasInjectionContext(): boolean;
|
|
74
|
-
|
|
75
|
-
declare class Scope {
|
|
76
|
-
detached: boolean;
|
|
77
|
-
/**
|
|
78
|
-
* @internal
|
|
79
|
-
*/
|
|
80
|
-
id: number;
|
|
81
|
-
/**
|
|
82
|
-
* @internal
|
|
83
|
-
*/
|
|
84
|
-
providers: Map<any, any>;
|
|
85
|
-
/**
|
|
86
|
-
* @internal
|
|
87
|
-
*/
|
|
88
|
-
parent: Scope | null;
|
|
89
|
-
/**
|
|
90
|
-
* @internal
|
|
91
|
-
*/
|
|
92
|
-
cleanups: (() => void)[];
|
|
93
|
-
/**
|
|
94
|
-
* @internal
|
|
95
|
-
*/
|
|
96
|
-
private _activeRuns;
|
|
97
|
-
constructor(detached?: boolean);
|
|
98
|
-
run<T>(fn: () => T): T;
|
|
99
|
-
stop(): void;
|
|
100
|
-
get active(): boolean;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* @group Main
|
|
104
|
-
*/
|
|
105
|
-
declare function getCurrentScope(): Scope | null;
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Creates a function within the injection context and returns its result. Providers/injections are only accessible within the callback function.
|
|
109
|
-
* @param isolated Do not inject parent providers into this context (Default: `false`)
|
|
110
|
-
*
|
|
111
|
-
* @example
|
|
112
|
-
* const main = withContext(() => {
|
|
113
|
-
* provide('user', { id: 1, name: 'Andrew' });
|
|
114
|
-
* doCoolStaff();
|
|
115
|
-
* });
|
|
116
|
-
*
|
|
117
|
-
* const doCoolStaff = () => {
|
|
118
|
-
* const user = inject('user');
|
|
119
|
-
* console.log(user); // { id: 1, name: 'Andrew' }
|
|
120
|
-
* };
|
|
121
|
-
*
|
|
122
|
-
* main();
|
|
123
|
-
*
|
|
124
|
-
* @group Main
|
|
125
|
-
*/
|
|
126
|
-
declare function withContext<T extends AnyFunction>(fn: T, detached?: boolean): T;
|
|
127
|
-
/**
|
|
128
|
-
* Runs a function within the injection context and returns its result. Providers/injections are only accessible inside the callback function.
|
|
129
|
-
* @param isolated Do not inject parent providers into this context (Default: `false`)
|
|
130
|
-
* @group Main
|
|
131
|
-
*/
|
|
132
|
-
declare function runWithContext<T = any>(fn: () => T, isolated?: boolean): T;
|
|
133
|
-
/**
|
|
134
|
-
* Binds the current context to the provided function. Useful for creating callbacks with the current context, such as `setTimeout` or `EventEmitter` handlers.
|
|
135
|
-
* @example
|
|
136
|
-
* const main = withContext(() => {
|
|
137
|
-
* provide("user", { id: 1, name: "Andrew" });
|
|
138
|
-
*
|
|
139
|
-
* setInterval(bindContext(() => {
|
|
140
|
-
* const user = inject("user");
|
|
141
|
-
* console.log(user); // { id: 1, name: 'Andrew' }
|
|
142
|
-
* }));
|
|
143
|
-
* });
|
|
144
|
-
*
|
|
145
|
-
* main();
|
|
146
|
-
*
|
|
147
|
-
* @group Main
|
|
148
|
-
*/
|
|
149
|
-
declare function bindContext<T>(fn: () => T): () => T;
|
|
150
|
-
|
|
151
|
-
export { type InjectionKey, type ProvideKey, type ProvideValue, bindContext, createContext, getCurrentScope, hasInjectionContext, inject, onScopeDispose, provide, runWithContext, withContext };
|