@unional/async-context 2.0.0 → 3.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 +64 -28
- package/cjs/AsyncContext.d.ts +11 -9
- package/cjs/AsyncContext.d.ts.map +1 -1
- package/cjs/AsyncContext.js +45 -111
- package/cjs/AsyncContext.js.map +1 -1
- package/cjs/errors.js +5 -22
- package/cjs/errors.js.map +1 -1
- package/esm/AsyncContext.d.ts +11 -9
- package/esm/AsyncContext.d.ts.map +1 -1
- package/esm/AsyncContext.js +38 -26
- package/esm/AsyncContext.js.map +1 -1
- package/package.json +2 -2
- package/ts/AsyncContext.ts +42 -36
package/README.md
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@unional/async-context`
|
|
2
2
|
|
|
3
3
|
[![NPM version][npm-image]][npm-url]
|
|
4
4
|
[![NPM downloads][downloads-image]][downloads-url]
|
|
5
5
|
[![Bundle size][bundlephobia-image]][bundlephobia-url]
|
|
6
6
|
|
|
7
7
|
[![Codecov][codecov-image]][codecov-url]
|
|
8
|
-
[![Codacy Grade Badge][codacy-grade]][codacy-grade-url]
|
|
9
|
-
[![Codacy Coverage Badge][codacy-coverage]][codacy-coverage-url]
|
|
10
8
|
|
|
11
9
|
Secure, type safe, asynchronous context for functional programming.
|
|
12
10
|
|
|
13
11
|
In functional programming,
|
|
14
12
|
it is common to pass in a context object containing dependencies used by the function.
|
|
15
13
|
|
|
16
|
-
`AsyncContext`
|
|
14
|
+
`AsyncContext` allows these dependencies to be loaded asynchronously.
|
|
17
15
|
|
|
18
16
|
This is useful in many cases. For example,
|
|
19
17
|
|
|
@@ -24,52 +22,69 @@ This is useful in many cases. For example,
|
|
|
24
22
|
|
|
25
23
|
## Installation
|
|
26
24
|
|
|
25
|
+
This is part of [`async-fp`](../async-fp/README.md).
|
|
26
|
+
|
|
27
|
+
Typically, you will install that instead of installing `@unional/async-context` directly.
|
|
28
|
+
|
|
29
|
+
But if you want, you can:
|
|
30
|
+
|
|
27
31
|
```sh
|
|
32
|
+
# npm
|
|
28
33
|
npm install @unional/async-context
|
|
29
|
-
|
|
34
|
+
|
|
35
|
+
# yarn
|
|
30
36
|
yarn add @unional/async-context
|
|
37
|
+
|
|
38
|
+
# pnpm
|
|
39
|
+
pnpm install @unional/async-context
|
|
40
|
+
|
|
41
|
+
#rush
|
|
42
|
+
rush add -p @unional/async-context
|
|
31
43
|
```
|
|
32
44
|
|
|
33
45
|
## Usage
|
|
34
46
|
|
|
47
|
+
You can provide the initial context when calling the constructor.
|
|
48
|
+
The context value must be an object (`Record`).
|
|
49
|
+
You can extend and augment the context with the [`extend()`](#extend) later.
|
|
50
|
+
|
|
51
|
+
You can supply the context value in 4 different ways:
|
|
52
|
+
|
|
35
53
|
```ts
|
|
36
54
|
import { AsyncContext } from '@unional/async-context'
|
|
37
55
|
|
|
38
|
-
const context = new AsyncContext({ key: 'secret key' })
|
|
39
|
-
const context = new AsyncContext(Promise.resolve({ key: 'secret key' }))
|
|
40
|
-
const context = new AsyncContext(() => ({ key: 'secret key' }))
|
|
56
|
+
const context = new AsyncContext({ key: 'secret key' }) // or
|
|
57
|
+
const context = new AsyncContext(Promise.resolve({ key: 'secret key' })) // or
|
|
58
|
+
const context = new AsyncContext(() => ({ key: 'secret key' })) // or
|
|
41
59
|
const context = new AsyncContext(async () => ({ key: 'secret key' }))
|
|
42
60
|
|
|
43
61
|
await context.get() // => { key: 'secret key' }
|
|
44
62
|
```
|
|
45
63
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
If you provide a handler,
|
|
50
|
-
it will not be executed until the first `context.get()` is called.
|
|
51
|
-
It allows you to wait for user input and change the value/dependency loaded.
|
|
64
|
+
If you provide an initialize function,
|
|
65
|
+
it will not be executed until the `context.get()` is called.
|
|
66
|
+
It allows you to wait for user input and change the values/dependencies loaded.
|
|
52
67
|
|
|
53
68
|
If you want to start loading the dependencies immediately,
|
|
54
|
-
starts the loading and pass in
|
|
69
|
+
starts the loading and pass in the resulting `Promise`.
|
|
55
70
|
|
|
56
71
|
### Initialize
|
|
57
72
|
|
|
58
|
-
You can create
|
|
73
|
+
You can create a `AsyncContext` and initialize it later.
|
|
59
74
|
This allows you to create a context in one part of your system,
|
|
60
|
-
and initialize it in another
|
|
75
|
+
and initialize it in another.
|
|
61
76
|
|
|
62
77
|
```ts
|
|
63
78
|
import { AsyncContext } from '@unional/async-context'
|
|
64
79
|
|
|
65
|
-
export const context = new AsyncContext<{ key: string }>()
|
|
80
|
+
export const context = new AsyncContext<{ key: string }>() // optionally specify the init context type
|
|
66
81
|
|
|
67
82
|
// in another file
|
|
68
83
|
import { context } from './context'
|
|
69
84
|
|
|
70
|
-
context.initialize({ key: 'secret key' })
|
|
71
|
-
context.initialize(Promise.resolve({ key: 'secret key' }))
|
|
72
|
-
context.initialize(() => ({ key: 'secret key' }))
|
|
85
|
+
context.initialize({ key: 'secret key' }) // or
|
|
86
|
+
context.initialize(Promise.resolve({ key: 'secret key' })) // or
|
|
87
|
+
context.initialize(() => ({ key: 'secret key' })) // or
|
|
73
88
|
context.initialize(() => Promise.resolve({ key: 'secret key' }))
|
|
74
89
|
```
|
|
75
90
|
|
|
@@ -83,7 +98,7 @@ you can use [`Object.freeze()`](https://developer.mozilla.org/en-US/docs/Web/Jav
|
|
|
83
98
|
|
|
84
99
|
### Extend
|
|
85
100
|
|
|
86
|
-
You can
|
|
101
|
+
You can extend or augment the context by calling `extend()`.
|
|
87
102
|
|
|
88
103
|
```ts
|
|
89
104
|
import { AsyncContext } from '@unional/async-context'
|
|
@@ -98,6 +113,33 @@ const newCtx = ctx.extend(async () => ({ b: 2, c: 3 }))
|
|
|
98
113
|
await newCtx.get() // => { a: 1, b: 2, c: 3 }
|
|
99
114
|
```
|
|
100
115
|
|
|
116
|
+
The `extend()` updates the `AsyncContext` in place,
|
|
117
|
+
i.e. the `newCtx` and `ctx` above is the same instance.
|
|
118
|
+
|
|
119
|
+
The difference is that `newCtx` will have the context type updated while `ctx` doesn't.
|
|
120
|
+
|
|
121
|
+
If you want to use the `ctx` directly, you can use `get<T>()` to assert the context type.
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
const ctx = new AsyncContext({ a: 1, b: 'b' })
|
|
125
|
+
|
|
126
|
+
ctx.extend({ b: 2, c: 3 })
|
|
127
|
+
await ctx.get<{ a: number, b: number, c: number }>()
|
|
128
|
+
|
|
129
|
+
// it is really the same as this, but less verbose
|
|
130
|
+
(await ctx.get() as { a: number, b: number, c: number })
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Chaining
|
|
134
|
+
|
|
135
|
+
As you can guess, the `initialize()` and `extend()` functions can be chained:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
const ctx = new AsyncContext()
|
|
139
|
+
|
|
140
|
+
ctx.initialize({ a: 1 }).extend({ b: 2 }).extend({ c: 3 })
|
|
141
|
+
```
|
|
142
|
+
|
|
101
143
|
## Use Cases
|
|
102
144
|
|
|
103
145
|
### Just-in-time Dependency Loading
|
|
@@ -166,15 +208,9 @@ configure({ ... })
|
|
|
166
208
|
|
|
167
209
|
[bundlephobia-image]: https://img.shields.io/bundlephobia/minzip/@unional/async-context.svg
|
|
168
210
|
[bundlephobia-url]: https://bundlephobia.com/result?p=@unional/async-context
|
|
169
|
-
[codacy-grade]: https://api.codacy.com/project/badge/Grade/707f89609508442486050d207ec5bd78
|
|
170
|
-
[codacy-grade-url]: https://www.codacy.com/app/homawong/async-fp?utm_source=github.com&utm_medium=referral&utm_content=unional/async-fp&utm_campaign=Badge_Grade
|
|
171
|
-
[codacy-coverage]: https://api.codacy.com/project/badge/Coverage/707f89609508442486050d207ec5bd78
|
|
172
|
-
[codacy-coverage-url]: https://www.codacy.com/manual/homawong/async-fp?utm_source=github.com&utm_medium=referral&utm_content=unional/async-fp&utm_campaign=Badge_Coverage
|
|
173
211
|
[codecov-image]: https://codecov.io/gh/unional/async-fp/branch/master/graph/badge.svg
|
|
174
212
|
[codecov-url]: https://codecov.io/gh/unional/async-fp
|
|
175
213
|
[downloads-image]: https://img.shields.io/npm/dm/@unional/async-context.svg?style=flat
|
|
176
214
|
[downloads-url]: https://npmjs.org/package/@unional/async-context
|
|
177
|
-
[github-nodejs]: https://github.com/unional/async-fp/workflows/Node%20CI/badge.svg
|
|
178
|
-
[github-action-url]: https://github.com/unional/async-fp/actions
|
|
179
215
|
[npm-image]: https://img.shields.io/npm/v/@unional/async-context.svg?style=flat
|
|
180
216
|
[npm-url]: https://npmjs.org/package/@unional/async-context
|
package/cjs/AsyncContext.d.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { LeftJoin } from 'type-plus';
|
|
2
|
-
export declare class AsyncContext<
|
|
3
|
-
private
|
|
4
|
-
private
|
|
2
|
+
export declare class AsyncContext<Init extends Record<string | symbol, any>, Context extends Record<string | symbol, any> = Init> {
|
|
3
|
+
#private;
|
|
4
|
+
private init?;
|
|
5
|
+
private transformers;
|
|
5
6
|
private resolving;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
initialize(
|
|
9
|
-
extend<R extends Record<string | symbol, any>>(context: R | Promise<R> | AsyncContext.Transformer<
|
|
7
|
+
private resolve;
|
|
8
|
+
constructor(init?: Init | Promise<Init> | AsyncContext.Initializer<Init> | undefined);
|
|
9
|
+
initialize<I extends Init = Init>(init: I | Promise<I> | AsyncContext.Initializer<I>): AsyncContext<I>;
|
|
10
|
+
extend<R extends Record<string | symbol, any>>(context: R | Promise<R> | AsyncContext.Transformer<Context, R>): AsyncContext<Init, LeftJoin<Context, R>>;
|
|
11
|
+
get<C = Context>(): Promise<C>;
|
|
10
12
|
}
|
|
11
13
|
export declare namespace AsyncContext {
|
|
12
|
-
type Initializer<
|
|
13
|
-
type Transformer<
|
|
14
|
+
type Initializer<Init> = () => Init | Promise<Init>;
|
|
15
|
+
type Transformer<CurrentContext, AdditionalContext> = (context: CurrentContext) => AdditionalContext | Promise<AdditionalContext>;
|
|
14
16
|
}
|
|
15
17
|
//# sourceMappingURL=AsyncContext.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AsyncContext.d.ts","sourceRoot":"","sources":["../ts/AsyncContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAGpC,qBAAa,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC
|
|
1
|
+
{"version":3,"file":"AsyncContext.d.ts","sourceRoot":"","sources":["../ts/AsyncContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAGpC,qBAAa,YAAY,CACvB,IAAI,SAAS,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,EACzC,OAAO,SAAS,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;;IAKvC,OAAO,CAAC,IAAI,CAAC;IAHzB,OAAO,CAAC,YAAY,CAAgD;IACpE,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,OAAO,CAA6D;gBACxD,IAAI,CAAC,mEAAuD;IAChF,UAAU,CAAC,CAAC,SAAS,IAAI,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;IAOtG,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,EAC3C,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,GAC7D,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAIrC,GAAG,CAAC,CAAC,GAAG,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC;CAUrC;AACD,yBAAiB,YAAY,CAAC;IAC5B,KAAY,WAAW,CAAC,IAAI,IAAI,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1D,KAAY,WAAW,CACrB,cAAc,EACd,iBAAiB,IACb,CAAC,OAAO,EAAE,cAAc,KAAK,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;CAClF"}
|
package/cjs/AsyncContext.js
CHANGED
|
@@ -1,67 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
-
t[p] = s[p];
|
|
8
|
-
}
|
|
9
|
-
return t;
|
|
10
|
-
};
|
|
11
|
-
return __assign.apply(this, arguments);
|
|
12
|
-
};
|
|
13
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
-
});
|
|
21
|
-
};
|
|
22
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
24
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
-
function step(op) {
|
|
27
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
-
while (_) try {
|
|
29
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
-
switch (op[0]) {
|
|
32
|
-
case 0: case 1: t = op; break;
|
|
33
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
-
default:
|
|
37
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
-
if (t[2]) _.ops.pop();
|
|
42
|
-
_.trys.pop(); continue;
|
|
43
|
-
}
|
|
44
|
-
op = body.call(thisArg, _);
|
|
45
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
-
}
|
|
2
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
5
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
48
6
|
};
|
|
7
|
+
var _AsyncContext_instances, _AsyncContext_buildContext;
|
|
49
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
9
|
exports.AsyncContext = void 0;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
10
|
+
const errors_1 = require("./errors");
|
|
11
|
+
class AsyncContext {
|
|
12
|
+
constructor(init) {
|
|
13
|
+
_AsyncContext_instances.add(this);
|
|
14
|
+
Object.defineProperty(this, "init", {
|
|
55
15
|
enumerable: true,
|
|
56
16
|
configurable: true,
|
|
57
17
|
writable: true,
|
|
58
|
-
value:
|
|
18
|
+
value: init
|
|
59
19
|
});
|
|
60
|
-
Object.defineProperty(this, "
|
|
20
|
+
Object.defineProperty(this, "transformers", {
|
|
61
21
|
enumerable: true,
|
|
62
22
|
configurable: true,
|
|
63
23
|
writable: true,
|
|
64
|
-
value:
|
|
24
|
+
value: []
|
|
65
25
|
});
|
|
66
26
|
Object.defineProperty(this, "resolving", {
|
|
67
27
|
enumerable: true,
|
|
@@ -69,66 +29,40 @@ var AsyncContext = /** @class */ (function () {
|
|
|
69
29
|
writable: true,
|
|
70
30
|
value: void 0
|
|
71
31
|
});
|
|
32
|
+
Object.defineProperty(this, "resolve", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
value: undefined
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
initialize(init) {
|
|
40
|
+
if (this.init)
|
|
41
|
+
throw new errors_1.ContextAlreadyInitialized();
|
|
42
|
+
this.init = init;
|
|
43
|
+
if (this.resolve)
|
|
44
|
+
this.resolve(__classPrivateFieldGet(this, _AsyncContext_instances, "m", _AsyncContext_buildContext).call(this));
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
extend(context) {
|
|
48
|
+
this.transformers.push(isTransformer(context) ? context : () => context);
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
async get() {
|
|
52
|
+
if (this.resolving)
|
|
53
|
+
return this.resolving;
|
|
54
|
+
return this.resolving = this.init ? __classPrivateFieldGet(this, _AsyncContext_instances, "m", _AsyncContext_buildContext).call(this) : new Promise(a => this.resolve = a);
|
|
72
55
|
}
|
|
73
|
-
Object.defineProperty(AsyncContext.prototype, "get", {
|
|
74
|
-
enumerable: false,
|
|
75
|
-
configurable: true,
|
|
76
|
-
writable: true,
|
|
77
|
-
value: function () {
|
|
78
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
79
|
-
var _this = this;
|
|
80
|
-
return __generator(this, function (_a) {
|
|
81
|
-
if (this.resolving)
|
|
82
|
-
return [2 /*return*/, this.resolving];
|
|
83
|
-
return [2 /*return*/, this.resolving = this.context
|
|
84
|
-
? Promise.resolve(initContext(this.context))
|
|
85
|
-
: new Promise(function (a) { return _this.resolve = a; })];
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
Object.defineProperty(AsyncContext.prototype, "initialize", {
|
|
91
|
-
enumerable: false,
|
|
92
|
-
configurable: true,
|
|
93
|
-
writable: true,
|
|
94
|
-
value: function (context) {
|
|
95
|
-
if (this.context)
|
|
96
|
-
throw new errors_1.ContextAlreadyInitialized();
|
|
97
|
-
this.context = context;
|
|
98
|
-
if (this.resolve)
|
|
99
|
-
this.resolve(initContext(context));
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
Object.defineProperty(AsyncContext.prototype, "extend", {
|
|
103
|
-
enumerable: false,
|
|
104
|
-
configurable: true,
|
|
105
|
-
writable: true,
|
|
106
|
-
value: function (context) {
|
|
107
|
-
var _this = this;
|
|
108
|
-
return new AsyncContext(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
109
|
-
var current, next;
|
|
110
|
-
return __generator(this, function (_a) {
|
|
111
|
-
switch (_a.label) {
|
|
112
|
-
case 0: return [4 /*yield*/, this.get()];
|
|
113
|
-
case 1:
|
|
114
|
-
current = _a.sent();
|
|
115
|
-
return [4 /*yield*/, transformContext(context, this)];
|
|
116
|
-
case 2:
|
|
117
|
-
next = _a.sent();
|
|
118
|
-
return [2 /*return*/, __assign(__assign({}, current), next)];
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
}); });
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
return AsyncContext;
|
|
125
|
-
}());
|
|
126
|
-
exports.AsyncContext = AsyncContext;
|
|
127
|
-
function initContext(context) {
|
|
128
|
-
return isInitializer(context) ? context() : context;
|
|
129
56
|
}
|
|
130
|
-
|
|
131
|
-
|
|
57
|
+
exports.AsyncContext = AsyncContext;
|
|
58
|
+
_AsyncContext_instances = new WeakSet(), _AsyncContext_buildContext = async function _AsyncContext_buildContext() {
|
|
59
|
+
return this.transformers.reduce(async (p, t) => {
|
|
60
|
+
const c = await p;
|
|
61
|
+
return { ...c, ...await t(c) };
|
|
62
|
+
}, resolveInit(this.init));
|
|
63
|
+
};
|
|
64
|
+
async function resolveInit(init) {
|
|
65
|
+
return isInitializer(init) ? init() : init;
|
|
132
66
|
}
|
|
133
67
|
function isTransformer(context) {
|
|
134
68
|
return typeof context === 'function';
|
package/cjs/AsyncContext.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AsyncContext.js","sourceRoot":"","sources":["../ts/AsyncContext.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AsyncContext.js","sourceRoot":"","sources":["../ts/AsyncContext.ts"],"names":[],"mappings":";;;;;;;;;AACA,qCAAoD;AAEpD,MAAa,YAAY;IAOvB,YAAoB,IAA4D;;;;;;mBAA5D;;QAHpB;;;;mBAAkE,EAAE;WAAA;QACpE;;;;;WAA2C;QAC3C;;;;mBAAmE,SAAS;WAAA;IACQ,CAAC;IACrF,UAAU,CAAwB,IAAkD;QAClF,IAAI,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,kCAAyB,EAAE,CAAA;QACpD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAEhB,IAAI,IAAI,CAAC,OAAO;YAAE,IAAI,CAAC,OAAO,CAAC,uBAAA,IAAI,2DAAc,MAAlB,IAAI,CAAgB,CAAC,CAAA;QACpD,OAAO,IAAuB,CAAA;IAChC,CAAC;IACD,MAAM,CACJ,OAA8D;QAE9D,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAA;QACxE,OAAO,IAAgD,CAAA;IACzD,CAAC;IACD,KAAK,CAAC,GAAG;QACP,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC,SAAS,CAAA;QACzC,OAAO,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,uBAAA,IAAI,2DAAc,MAAlB,IAAI,CAAgB,CAAC,CAAC,CAAC,IAAI,OAAO,CAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAA;IACpG,CAAC;CAOF;AA/BD,oCA+BC;sEANC,KAAK;IACH,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;QAC7C,MAAM,CAAC,GAAG,MAAM,CAAC,CAAA;QACjB,OAAO,EAAE,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAQ,EAAE,CAAA;IACvC,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,IAAK,CAAC,CAAqB,CAAA;AACjD,CAAC;AAUH,KAAK,UAAU,WAAW,CAEtB,IAA2D;IAC7D,OAAO,aAAa,CAAO,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AAClD,CAAC;AAED,SAAS,aAAa,CAGpB,OAAgB;IAChB,OAAO,OAAO,OAAO,KAAK,UAAU,CAAA;AACtC,CAAC;AAED,SAAS,aAAa,CAAI,OAAgB;IACxC,OAAO,OAAO,OAAO,KAAK,UAAU,CAAA;AACtC,CAAC","sourcesContent":["import { LeftJoin } from 'type-plus'\nimport { ContextAlreadyInitialized } from './errors'\n\nexport class AsyncContext<\n Init extends Record<string | symbol, any>,\n Context extends Record<string | symbol, any> = Init\n > {\n private transformers: Array<AsyncContext.Transformer<any, any>> = []\n private resolving: Promise<any> | undefined\n private resolve: ((value: Promise<Context>) => void) | undefined = undefined\n constructor(private init?: Init | Promise<Init> | AsyncContext.Initializer<Init>) { }\n initialize<I extends Init = Init>(init: I | Promise<I> | AsyncContext.Initializer<I>): AsyncContext<I> {\n if (this.init) throw new ContextAlreadyInitialized()\n this.init = init\n\n if (this.resolve) this.resolve(this.#buildContext())\n return this as AsyncContext<I>\n }\n extend<R extends Record<string | symbol, any>>(\n context: R | Promise<R> | AsyncContext.Transformer<Context, R>\n ): AsyncContext<Init, LeftJoin<Context, R>> {\n this.transformers.push(isTransformer(context) ? context : () => context)\n return this as AsyncContext<Init, LeftJoin<Context, R>>\n }\n async get<C = Context>(): Promise<C> {\n if (this.resolving) return this.resolving\n return this.resolving = this.init ? this.#buildContext() : new Promise<any>(a => this.resolve = a)\n }\n async #buildContext(): Promise<Context> {\n return this.transformers.reduce(async (p, t) => {\n const c = await p\n return { ...c, ...await t(c) as any }\n }, resolveInit(this.init!)) as Promise<Context>\n }\n}\nexport namespace AsyncContext {\n export type Initializer<Init> = () => Init | Promise<Init>\n export type Transformer<\n CurrentContext,\n AdditionalContext\n > = (context: CurrentContext) => AdditionalContext | Promise<AdditionalContext>\n}\n\nasync function resolveInit<\n Init extends Record<string | symbol, any>,\n >(init: Init | Promise<Init> | AsyncContext.Initializer<Init>): Promise<Init> {\n return isInitializer<Init>(init) ? init() : init\n}\n\nfunction isTransformer<\n CurrentContext,\n AdditionalContext\n>(context: unknown): context is AsyncContext.Transformer<CurrentContext, AdditionalContext> {\n return typeof context === 'function'\n}\n\nfunction isInitializer<T>(context: unknown): context is AsyncContext.Initializer<T> {\n return typeof context === 'function'\n}\n"]}
|
package/cjs/errors.js
CHANGED
|
@@ -1,28 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __extends = (this && this.__extends) || (function () {
|
|
3
|
-
var extendStatics = function (d, b) {
|
|
4
|
-
extendStatics = Object.setPrototypeOf ||
|
|
5
|
-
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
-
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
7
|
-
return extendStatics(d, b);
|
|
8
|
-
};
|
|
9
|
-
return function (d, b) {
|
|
10
|
-
if (typeof b !== "function" && b !== null)
|
|
11
|
-
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
12
|
-
extendStatics(d, b);
|
|
13
|
-
function __() { this.constructor = d; }
|
|
14
|
-
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
15
|
-
};
|
|
16
|
-
})();
|
|
17
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
3
|
exports.ContextAlreadyInitialized = void 0;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return _super.call(this, '@unional/async-context', 'context can only be initialized once.', options) || this;
|
|
4
|
+
const iso_error_1 = require("iso-error");
|
|
5
|
+
class ContextAlreadyInitialized extends iso_error_1.ModuleError {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
super('@unional/async-context', 'context can only be initialized once.', options);
|
|
24
8
|
}
|
|
25
|
-
|
|
26
|
-
}(iso_error_1.ModuleError));
|
|
9
|
+
}
|
|
27
10
|
exports.ContextAlreadyInitialized = ContextAlreadyInitialized;
|
|
28
11
|
//# sourceMappingURL=errors.js.map
|
package/cjs/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../ts/errors.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../ts/errors.ts"],"names":[],"mappings":";;;AAAA,yCAAiD;AAEjD,MAAa,yBAA0B,SAAQ,uBAAW;IACxD,YAAY,OAA0B;QACpC,KAAK,CAAC,wBAAwB,EAAE,uCAAuC,EAAE,OAAO,CAAC,CAAA;IACnF,CAAC;CACF;AAJD,8DAIC","sourcesContent":["import { IsoError, ModuleError } from 'iso-error'\n\nexport class ContextAlreadyInitialized extends ModuleError {\n constructor(options?: IsoError.Options) {\n super('@unional/async-context', 'context can only be initialized once.', options)\n }\n}\n"]}
|
package/esm/AsyncContext.d.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { LeftJoin } from 'type-plus';
|
|
2
|
-
export declare class AsyncContext<
|
|
3
|
-
private
|
|
4
|
-
private
|
|
2
|
+
export declare class AsyncContext<Init extends Record<string | symbol, any>, Context extends Record<string | symbol, any> = Init> {
|
|
3
|
+
#private;
|
|
4
|
+
private init?;
|
|
5
|
+
private transformers;
|
|
5
6
|
private resolving;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
initialize(
|
|
9
|
-
extend<R extends Record<string | symbol, any>>(context: R | Promise<R> | AsyncContext.Transformer<
|
|
7
|
+
private resolve;
|
|
8
|
+
constructor(init?: Init | Promise<Init> | AsyncContext.Initializer<Init> | undefined);
|
|
9
|
+
initialize<I extends Init = Init>(init: I | Promise<I> | AsyncContext.Initializer<I>): AsyncContext<I>;
|
|
10
|
+
extend<R extends Record<string | symbol, any>>(context: R | Promise<R> | AsyncContext.Transformer<Context, R>): AsyncContext<Init, LeftJoin<Context, R>>;
|
|
11
|
+
get<C = Context>(): Promise<C>;
|
|
10
12
|
}
|
|
11
13
|
export declare namespace AsyncContext {
|
|
12
|
-
type Initializer<
|
|
13
|
-
type Transformer<
|
|
14
|
+
type Initializer<Init> = () => Init | Promise<Init>;
|
|
15
|
+
type Transformer<CurrentContext, AdditionalContext> = (context: CurrentContext) => AdditionalContext | Promise<AdditionalContext>;
|
|
14
16
|
}
|
|
15
17
|
//# sourceMappingURL=AsyncContext.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AsyncContext.d.ts","sourceRoot":"","sources":["../ts/AsyncContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAGpC,qBAAa,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC
|
|
1
|
+
{"version":3,"file":"AsyncContext.d.ts","sourceRoot":"","sources":["../ts/AsyncContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAGpC,qBAAa,YAAY,CACvB,IAAI,SAAS,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,EACzC,OAAO,SAAS,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;;IAKvC,OAAO,CAAC,IAAI,CAAC;IAHzB,OAAO,CAAC,YAAY,CAAgD;IACpE,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,OAAO,CAA6D;gBACxD,IAAI,CAAC,mEAAuD;IAChF,UAAU,CAAC,CAAC,SAAS,IAAI,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;IAOtG,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,EAC3C,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,GAC7D,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAIrC,GAAG,CAAC,CAAC,GAAG,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC;CAUrC;AACD,yBAAiB,YAAY,CAAC;IAC5B,KAAY,WAAW,CAAC,IAAI,IAAI,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1D,KAAY,WAAW,CACrB,cAAc,EACd,iBAAiB,IACb,CAAC,OAAO,EAAE,cAAc,KAAK,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;CAClF"}
|
package/esm/AsyncContext.js
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
+
};
|
|
6
|
+
var _AsyncContext_instances, _AsyncContext_buildContext;
|
|
1
7
|
import { ContextAlreadyInitialized } from './errors';
|
|
2
8
|
export class AsyncContext {
|
|
3
|
-
constructor(
|
|
4
|
-
|
|
9
|
+
constructor(init) {
|
|
10
|
+
_AsyncContext_instances.add(this);
|
|
11
|
+
Object.defineProperty(this, "init", {
|
|
5
12
|
enumerable: true,
|
|
6
13
|
configurable: true,
|
|
7
14
|
writable: true,
|
|
8
|
-
value:
|
|
15
|
+
value: init
|
|
9
16
|
});
|
|
10
|
-
Object.defineProperty(this, "
|
|
17
|
+
Object.defineProperty(this, "transformers", {
|
|
11
18
|
enumerable: true,
|
|
12
19
|
configurable: true,
|
|
13
20
|
writable: true,
|
|
14
|
-
value:
|
|
21
|
+
value: []
|
|
15
22
|
});
|
|
16
23
|
Object.defineProperty(this, "resolving", {
|
|
17
24
|
enumerable: true,
|
|
@@ -19,34 +26,39 @@ export class AsyncContext {
|
|
|
19
26
|
writable: true,
|
|
20
27
|
value: void 0
|
|
21
28
|
});
|
|
29
|
+
Object.defineProperty(this, "resolve", {
|
|
30
|
+
enumerable: true,
|
|
31
|
+
configurable: true,
|
|
32
|
+
writable: true,
|
|
33
|
+
value: undefined
|
|
34
|
+
});
|
|
22
35
|
}
|
|
23
|
-
|
|
24
|
-
if (this.
|
|
25
|
-
return this.resolving;
|
|
26
|
-
return this.resolving = this.context
|
|
27
|
-
? Promise.resolve(initContext(this.context))
|
|
28
|
-
: new Promise(a => this.resolve = a);
|
|
29
|
-
}
|
|
30
|
-
initialize(context) {
|
|
31
|
-
if (this.context)
|
|
36
|
+
initialize(init) {
|
|
37
|
+
if (this.init)
|
|
32
38
|
throw new ContextAlreadyInitialized();
|
|
33
|
-
this.
|
|
39
|
+
this.init = init;
|
|
34
40
|
if (this.resolve)
|
|
35
|
-
this.resolve(
|
|
41
|
+
this.resolve(__classPrivateFieldGet(this, _AsyncContext_instances, "m", _AsyncContext_buildContext).call(this));
|
|
42
|
+
return this;
|
|
36
43
|
}
|
|
37
44
|
extend(context) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
this.transformers.push(isTransformer(context) ? context : () => context);
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
async get() {
|
|
49
|
+
if (this.resolving)
|
|
50
|
+
return this.resolving;
|
|
51
|
+
return this.resolving = this.init ? __classPrivateFieldGet(this, _AsyncContext_instances, "m", _AsyncContext_buildContext).call(this) : new Promise(a => this.resolve = a);
|
|
43
52
|
}
|
|
44
53
|
}
|
|
45
|
-
function
|
|
46
|
-
return
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
_AsyncContext_instances = new WeakSet(), _AsyncContext_buildContext = async function _AsyncContext_buildContext() {
|
|
55
|
+
return this.transformers.reduce(async (p, t) => {
|
|
56
|
+
const c = await p;
|
|
57
|
+
return { ...c, ...await t(c) };
|
|
58
|
+
}, resolveInit(this.init));
|
|
59
|
+
};
|
|
60
|
+
async function resolveInit(init) {
|
|
61
|
+
return isInitializer(init) ? init() : init;
|
|
50
62
|
}
|
|
51
63
|
function isTransformer(context) {
|
|
52
64
|
return typeof context === 'function';
|
package/esm/AsyncContext.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AsyncContext.js","sourceRoot":"","sources":["../ts/AsyncContext.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAA;AAEpD,MAAM,OAAO,YAAY;
|
|
1
|
+
{"version":3,"file":"AsyncContext.js","sourceRoot":"","sources":["../ts/AsyncContext.ts"],"names":[],"mappings":";;;;;;AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAA;AAEpD,MAAM,OAAO,YAAY;IAOvB,YAAoB,IAA4D;;;;;;mBAA5D;;QAHpB;;;;mBAAkE,EAAE;WAAA;QACpE;;;;;WAA2C;QAC3C;;;;mBAAmE,SAAS;WAAA;IACQ,CAAC;IACrF,UAAU,CAAwB,IAAkD;QAClF,IAAI,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,yBAAyB,EAAE,CAAA;QACpD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAEhB,IAAI,IAAI,CAAC,OAAO;YAAE,IAAI,CAAC,OAAO,CAAC,uBAAA,IAAI,2DAAc,MAAlB,IAAI,CAAgB,CAAC,CAAA;QACpD,OAAO,IAAuB,CAAA;IAChC,CAAC;IACD,MAAM,CACJ,OAA8D;QAE9D,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAA;QACxE,OAAO,IAAgD,CAAA;IACzD,CAAC;IACD,KAAK,CAAC,GAAG;QACP,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC,SAAS,CAAA;QACzC,OAAO,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,uBAAA,IAAI,2DAAc,MAAlB,IAAI,CAAgB,CAAC,CAAC,CAAC,IAAI,OAAO,CAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAA;IACpG,CAAC;CAOF;sEANC,KAAK;IACH,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;QAC7C,MAAM,CAAC,GAAG,MAAM,CAAC,CAAA;QACjB,OAAO,EAAE,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAQ,EAAE,CAAA;IACvC,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,IAAK,CAAC,CAAqB,CAAA;AACjD,CAAC;AAUH,KAAK,UAAU,WAAW,CAEtB,IAA2D;IAC7D,OAAO,aAAa,CAAO,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AAClD,CAAC;AAED,SAAS,aAAa,CAGpB,OAAgB;IAChB,OAAO,OAAO,OAAO,KAAK,UAAU,CAAA;AACtC,CAAC;AAED,SAAS,aAAa,CAAI,OAAgB;IACxC,OAAO,OAAO,OAAO,KAAK,UAAU,CAAA;AACtC,CAAC","sourcesContent":["import { LeftJoin } from 'type-plus'\nimport { ContextAlreadyInitialized } from './errors'\n\nexport class AsyncContext<\n Init extends Record<string | symbol, any>,\n Context extends Record<string | symbol, any> = Init\n > {\n private transformers: Array<AsyncContext.Transformer<any, any>> = []\n private resolving: Promise<any> | undefined\n private resolve: ((value: Promise<Context>) => void) | undefined = undefined\n constructor(private init?: Init | Promise<Init> | AsyncContext.Initializer<Init>) { }\n initialize<I extends Init = Init>(init: I | Promise<I> | AsyncContext.Initializer<I>): AsyncContext<I> {\n if (this.init) throw new ContextAlreadyInitialized()\n this.init = init\n\n if (this.resolve) this.resolve(this.#buildContext())\n return this as AsyncContext<I>\n }\n extend<R extends Record<string | symbol, any>>(\n context: R | Promise<R> | AsyncContext.Transformer<Context, R>\n ): AsyncContext<Init, LeftJoin<Context, R>> {\n this.transformers.push(isTransformer(context) ? context : () => context)\n return this as AsyncContext<Init, LeftJoin<Context, R>>\n }\n async get<C = Context>(): Promise<C> {\n if (this.resolving) return this.resolving\n return this.resolving = this.init ? this.#buildContext() : new Promise<any>(a => this.resolve = a)\n }\n async #buildContext(): Promise<Context> {\n return this.transformers.reduce(async (p, t) => {\n const c = await p\n return { ...c, ...await t(c) as any }\n }, resolveInit(this.init!)) as Promise<Context>\n }\n}\nexport namespace AsyncContext {\n export type Initializer<Init> = () => Init | Promise<Init>\n export type Transformer<\n CurrentContext,\n AdditionalContext\n > = (context: CurrentContext) => AdditionalContext | Promise<AdditionalContext>\n}\n\nasync function resolveInit<\n Init extends Record<string | symbol, any>,\n >(init: Init | Promise<Init> | AsyncContext.Initializer<Init>): Promise<Init> {\n return isInitializer<Init>(init) ? init() : init\n}\n\nfunction isTransformer<\n CurrentContext,\n AdditionalContext\n>(context: unknown): context is AsyncContext.Transformer<CurrentContext, AdditionalContext> {\n return typeof context === 'function'\n}\n\nfunction isInitializer<T>(context: unknown): context is AsyncContext.Initializer<T> {\n return typeof context === 'function'\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unional/async-context",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Asynchronous context for functional style programming",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"async",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@size-limit/preset-small-lib": "^8.0.1",
|
|
42
|
-
"@types/node": "^
|
|
42
|
+
"@types/node": "^16.0.0",
|
|
43
43
|
"@typescript-eslint/eslint-plugin": "^5.33.0",
|
|
44
44
|
"@typescript-eslint/parser": "^5.33.0",
|
|
45
45
|
"assertron": "^10.0.0",
|
package/ts/AsyncContext.ts
CHANGED
|
@@ -1,53 +1,59 @@
|
|
|
1
1
|
import { LeftJoin } from 'type-plus'
|
|
2
2
|
import { ContextAlreadyInitialized } from './errors'
|
|
3
3
|
|
|
4
|
-
export class AsyncContext<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
export class AsyncContext<
|
|
5
|
+
Init extends Record<string | symbol, any>,
|
|
6
|
+
Context extends Record<string | symbol, any> = Init
|
|
7
|
+
> {
|
|
8
|
+
private transformers: Array<AsyncContext.Transformer<any, any>> = []
|
|
9
|
+
private resolving: Promise<any> | undefined
|
|
10
|
+
private resolve: ((value: Promise<Context>) => void) | undefined = undefined
|
|
11
|
+
constructor(private init?: Init | Promise<Init> | AsyncContext.Initializer<Init>) { }
|
|
12
|
+
initialize<I extends Init = Init>(init: I | Promise<I> | AsyncContext.Initializer<I>): AsyncContext<I> {
|
|
13
|
+
if (this.init) throw new ContextAlreadyInitialized()
|
|
14
|
+
this.init = init
|
|
15
|
+
|
|
16
|
+
if (this.resolve) this.resolve(this.#buildContext())
|
|
17
|
+
return this as AsyncContext<I>
|
|
13
18
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
extend<R extends Record<string | symbol, any>>(
|
|
20
|
+
context: R | Promise<R> | AsyncContext.Transformer<Context, R>
|
|
21
|
+
): AsyncContext<Init, LeftJoin<Context, R>> {
|
|
22
|
+
this.transformers.push(isTransformer(context) ? context : () => context)
|
|
23
|
+
return this as AsyncContext<Init, LeftJoin<Context, R>>
|
|
18
24
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
async get<C = Context>(): Promise<C> {
|
|
26
|
+
if (this.resolving) return this.resolving
|
|
27
|
+
return this.resolving = this.init ? this.#buildContext() : new Promise<any>(a => this.resolve = a)
|
|
28
|
+
}
|
|
29
|
+
async #buildContext(): Promise<Context> {
|
|
30
|
+
return this.transformers.reduce(async (p, t) => {
|
|
31
|
+
const c = await p
|
|
32
|
+
return { ...c, ...await t(c) as any }
|
|
33
|
+
}, resolveInit(this.init!)) as Promise<Context>
|
|
26
34
|
}
|
|
27
35
|
}
|
|
28
|
-
|
|
29
36
|
export namespace AsyncContext {
|
|
30
|
-
export type Initializer<
|
|
31
|
-
export type Transformer<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
T extends Record<string | symbol, any>,
|
|
36
|
-
>(context: T | Promise<T> | AsyncContext.Initializer<T>): T | Promise<T> {
|
|
37
|
-
return isInitializer<T>(context) ? context() : context
|
|
37
|
+
export type Initializer<Init> = () => Init | Promise<Init>
|
|
38
|
+
export type Transformer<
|
|
39
|
+
CurrentContext,
|
|
40
|
+
AdditionalContext
|
|
41
|
+
> = (context: CurrentContext) => AdditionalContext | Promise<AdditionalContext>
|
|
38
42
|
}
|
|
39
43
|
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return isTransformer<T, R>(context) ? context(currentContext) : context
|
|
44
|
+
async function resolveInit<
|
|
45
|
+
Init extends Record<string | symbol, any>,
|
|
46
|
+
>(init: Init | Promise<Init> | AsyncContext.Initializer<Init>): Promise<Init> {
|
|
47
|
+
return isInitializer<Init>(init) ? init() : init
|
|
45
48
|
}
|
|
46
49
|
|
|
47
|
-
function isTransformer<
|
|
50
|
+
function isTransformer<
|
|
51
|
+
CurrentContext,
|
|
52
|
+
AdditionalContext
|
|
53
|
+
>(context: unknown): context is AsyncContext.Transformer<CurrentContext, AdditionalContext> {
|
|
48
54
|
return typeof context === 'function'
|
|
49
55
|
}
|
|
50
56
|
|
|
51
|
-
function isInitializer<T>(context:
|
|
57
|
+
function isInitializer<T>(context: unknown): context is AsyncContext.Initializer<T> {
|
|
52
58
|
return typeof context === 'function'
|
|
53
59
|
}
|