@rsdk/common 6.0.0-next.0 → 6.0.0-next.10
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/functions/obj-normalization.d.ts +3 -0
- package/dist/functions/obj-normalization.js +12 -1
- package/dist/functions/obj-normalization.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/validation/index.d.ts +1 -0
- package/dist/{observable → validation}/index.js +1 -1
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/typebox.validator.d.ts +26 -0
- package/dist/validation/typebox.validator.js +38 -0
- package/dist/validation/typebox.validator.js.map +1 -0
- package/package.json +9 -4
- package/src/functions/obj-normalization.spec.ts +102 -0
- package/src/functions/obj-normalization.ts +14 -1
- package/src/index.ts +1 -1
- package/src/validation/index.ts +1 -0
- package/src/validation/typebox.validator.ts +38 -0
- package/dist/observable/index.d.ts +0 -1
- package/dist/observable/index.js.map +0 -1
- package/dist/observable/observable-to-async-iterable.d.ts +0 -7
- package/dist/observable/observable-to-async-iterable.js +0 -107
- package/dist/observable/observable-to-async-iterable.js.map +0 -1
- package/src/observable/index.ts +0 -1
- package/src/observable/observable-to-async-iterable.ts +0 -115
|
@@ -6,6 +6,7 @@ export interface NormalizeOptions {
|
|
|
6
6
|
filterKeys?: string[];
|
|
7
7
|
sortKeys?: SortKeys;
|
|
8
8
|
maxDepth?: number;
|
|
9
|
+
keepOriginPrototype?: boolean;
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
11
12
|
* Creates a function that prepares objects for JSON.stringify().
|
|
@@ -24,6 +25,7 @@ export interface NormalizeOptions {
|
|
|
24
25
|
* - Map -> '[Map size]'
|
|
25
26
|
* - Set -> '[Set size]'
|
|
26
27
|
* - Limits object nesting depth (default: 10)
|
|
28
|
+
* - Keeps origin prototype (default: false)
|
|
27
29
|
* - Protects against large objects (>16M keys)
|
|
28
30
|
*
|
|
29
31
|
* @example
|
|
@@ -43,6 +45,7 @@ export interface NormalizeOptions {
|
|
|
43
45
|
* - filterKeys: Array of keys to exclude
|
|
44
46
|
* - sortKeys: Custom key sorting configuration
|
|
45
47
|
* - maxDepth: Maximum nesting depth (default: 10)
|
|
48
|
+
* - keepOriginPrototype: Whether to keep the original prototype (default: false)
|
|
46
49
|
* @param depth - Current recursion depth (internal use)
|
|
47
50
|
*/
|
|
48
51
|
export declare const normalizer: () => ((x: unknown, options?: NormalizeOptions, depth?: number) => unknown);
|
|
@@ -20,6 +20,7 @@ const DEFAULT_MAX_DEPTH = 10;
|
|
|
20
20
|
* - Map -> '[Map size]'
|
|
21
21
|
* - Set -> '[Set size]'
|
|
22
22
|
* - Limits object nesting depth (default: 10)
|
|
23
|
+
* - Keeps origin prototype (default: false)
|
|
23
24
|
* - Protects against large objects (>16M keys)
|
|
24
25
|
*
|
|
25
26
|
* @example
|
|
@@ -39,6 +40,7 @@ const DEFAULT_MAX_DEPTH = 10;
|
|
|
39
40
|
* - filterKeys: Array of keys to exclude
|
|
40
41
|
* - sortKeys: Custom key sorting configuration
|
|
41
42
|
* - maxDepth: Maximum nesting depth (default: 10)
|
|
43
|
+
* - keepOriginPrototype: Whether to keep the original prototype (default: false)
|
|
42
44
|
* @param depth - Current recursion depth (internal use)
|
|
43
45
|
*/
|
|
44
46
|
const normalizer = () => {
|
|
@@ -94,13 +96,22 @@ const normalizer = () => {
|
|
|
94
96
|
if (options?.sortKeys?.match(xObject)) {
|
|
95
97
|
keys.sort(options.sortKeys.sortFn);
|
|
96
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* There is several cases, when we have to keep the origin prototype.
|
|
101
|
+
* For example, if normalizer is executing implicitly
|
|
102
|
+
* and normalized object will be used in `instanceof` condition
|
|
103
|
+
* next to execution context
|
|
104
|
+
*/
|
|
105
|
+
const normalized = options?.keepOriginPrototype
|
|
106
|
+
? Object.setPrototypeOf({}, Object.getPrototypeOf(xObject))
|
|
107
|
+
: {};
|
|
97
108
|
return keys.reduce((acc, key) => {
|
|
98
109
|
if (options?.filterKeys?.includes(key)) {
|
|
99
110
|
return acc;
|
|
100
111
|
}
|
|
101
112
|
acc[key] = normalize(xObject[key], options, newDepth);
|
|
102
113
|
return acc;
|
|
103
|
-
},
|
|
114
|
+
}, normalized);
|
|
104
115
|
}
|
|
105
116
|
catch (error) {
|
|
106
117
|
return `[Can not get keys from object. ${error}]`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obj-normalization.js","sourceRoot":"","sources":["../../src/functions/obj-normalization.ts"],"names":[],"mappings":";;;AAAA,2DAAqD;
|
|
1
|
+
{"version":3,"file":"obj-normalization.js","sourceRoot":"","sources":["../../src/functions/obj-normalization.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -21,6 +21,6 @@ __exportStar(require("./time"), exports);
|
|
|
21
21
|
__exportStar(require("./functions"), exports);
|
|
22
22
|
__exportStar(require("./size"), exports);
|
|
23
23
|
__exportStar(require("./strings"), exports);
|
|
24
|
-
__exportStar(require("./observable"), exports);
|
|
25
24
|
__exportStar(require("./parsers"), exports);
|
|
25
|
+
__exportStar(require("./validation"), exports);
|
|
26
26
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,0CAAwB;AACxB,4CAA0B;AAC1B,yCAAuB;AACvB,8CAA4B;AAC5B,yCAAuB;AACvB,4CAA0B;AAC1B,+CAA6B
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,0CAAwB;AACxB,4CAA0B;AAC1B,yCAAuB;AACvB,8CAA4B;AAC5B,yCAAuB;AACvB,4CAA0B;AAC1B,4CAA0B;AAC1B,+CAA6B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './typebox.validator';
|
|
@@ -14,5 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./
|
|
17
|
+
__exportStar(require("./typebox.validator"), exports);
|
|
18
18
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/validation/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sDAAoC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { TSchema } from '@sinclair/typebox';
|
|
2
|
+
import type { ValueError } from '@sinclair/typebox/compiler';
|
|
3
|
+
/**
|
|
4
|
+
* Wrapper around Typebox's type validation.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* const validator = new Validator(t.Object({ name: t.String() }));
|
|
9
|
+
* const { isValid, errors } = validator.run({ name: 'John' });
|
|
10
|
+
* ...
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare class TypeBoxValidator<T extends TSchema> {
|
|
14
|
+
private readonly validator;
|
|
15
|
+
constructor(schema: T);
|
|
16
|
+
/**
|
|
17
|
+
* Run the validator on the given data.
|
|
18
|
+
*
|
|
19
|
+
* @param data - The data to validate.
|
|
20
|
+
* @returns The validation result.
|
|
21
|
+
*/
|
|
22
|
+
check(data: unknown): {
|
|
23
|
+
isValid: boolean;
|
|
24
|
+
errors: ValueError[];
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TypeBoxValidator = void 0;
|
|
4
|
+
const compiler_1 = require("@sinclair/typebox/compiler");
|
|
5
|
+
/**
|
|
6
|
+
* Wrapper around Typebox's type validation.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const validator = new Validator(t.Object({ name: t.String() }));
|
|
11
|
+
* const { isValid, errors } = validator.run({ name: 'John' });
|
|
12
|
+
* ...
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
class TypeBoxValidator {
|
|
16
|
+
validator;
|
|
17
|
+
constructor(schema) {
|
|
18
|
+
this.validator = compiler_1.TypeCompiler.Compile(schema);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Run the validator on the given data.
|
|
22
|
+
*
|
|
23
|
+
* @param data - The data to validate.
|
|
24
|
+
* @returns The validation result.
|
|
25
|
+
*/
|
|
26
|
+
check(data) {
|
|
27
|
+
/**
|
|
28
|
+
* TODO: При случае, придумать, как нормально распечатывать ошибки для union'ов.
|
|
29
|
+
* Сейчас они ужасно неинформативные.
|
|
30
|
+
*/
|
|
31
|
+
return {
|
|
32
|
+
isValid: this.validator.Check(data),
|
|
33
|
+
errors: [...this.validator.Errors(data)],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.TypeBoxValidator = TypeBoxValidator;
|
|
38
|
+
//# sourceMappingURL=typebox.validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typebox.validator.js","sourceRoot":"","sources":["../../src/validation/typebox.validator.ts"],"names":[],"mappings":";;;AAEA,yDAA0D;AAE1D;;;;;;;;;GASG;AACH,MAAa,gBAAgB;IACV,SAAS,CAAe;IAEzC,YAAY,MAAS;QACnB,IAAI,CAAC,SAAS,GAAG,uBAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,IAAa;QACjB;;;WAGG;QACH,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC;YACnC,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;SACzC,CAAC;IACJ,CAAC;CACF;AAvBD,4CAuBC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rsdk/common",
|
|
3
|
-
"version": "6.0.0-next.
|
|
3
|
+
"version": "6.0.0-next.10",
|
|
4
4
|
"description": "Useful common classes, functions and types",
|
|
5
5
|
"license": "Apache License 2.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -13,8 +13,13 @@
|
|
|
13
13
|
"scripts": {
|
|
14
14
|
"prepublishOnly": "npm run build"
|
|
15
15
|
},
|
|
16
|
-
"
|
|
17
|
-
"
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"@sinclair/typebox": "^0.34.9"
|
|
18
18
|
},
|
|
19
|
-
"
|
|
19
|
+
"peerDependenciesMeta": {
|
|
20
|
+
"@sinclair/typebox": {
|
|
21
|
+
"optional": true
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"gitHead": "26c1a04480e6209098be6636afbde7fd357da61a"
|
|
20
25
|
}
|
|
@@ -207,3 +207,105 @@ describe('max depth', () => {
|
|
|
207
207
|
);
|
|
208
208
|
});
|
|
209
209
|
});
|
|
210
|
+
|
|
211
|
+
describe('keep origin prototype', () => {
|
|
212
|
+
class TestObject {
|
|
213
|
+
a = 1;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const objectCases: {
|
|
217
|
+
input: any;
|
|
218
|
+
output: any;
|
|
219
|
+
options?: NormalizeOptions;
|
|
220
|
+
title: string;
|
|
221
|
+
}[] = [
|
|
222
|
+
{
|
|
223
|
+
input: new TestObject(),
|
|
224
|
+
output: Object,
|
|
225
|
+
title: `should have the Object prototype if input is an instance of a class without keepOriginPrototype option`,
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
input: new TestObject(),
|
|
229
|
+
output: Object,
|
|
230
|
+
options: { keepOriginPrototype: false },
|
|
231
|
+
title: `should not have the same prototype if keepOriginPrototype is false`,
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
input: new TestObject(),
|
|
235
|
+
output: Object,
|
|
236
|
+
options: { keepOriginPrototype: true },
|
|
237
|
+
title: `should have the same prototype if keepOriginPrototype is true`,
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
input: {},
|
|
241
|
+
output: Object,
|
|
242
|
+
title: `should have the object prototype if input is an object by default without keepOriginPrototype option`,
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
input: {},
|
|
246
|
+
options: { keepOriginPrototype: false },
|
|
247
|
+
output: Object,
|
|
248
|
+
title: `should have the same prototype if input is an object and keepOriginPrototype is false`,
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
input: {},
|
|
252
|
+
options: { keepOriginPrototype: true },
|
|
253
|
+
output: Object,
|
|
254
|
+
title: `should have the same prototype if input is an object and keepOriginPrototype is true`,
|
|
255
|
+
},
|
|
256
|
+
] as const;
|
|
257
|
+
|
|
258
|
+
it.each(objectCases)('$title', ({ input, output, options }) => {
|
|
259
|
+
const result = normalizer()(input, options);
|
|
260
|
+
|
|
261
|
+
expect(result).toBeInstanceOf(output);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
const primitiveCases: {
|
|
265
|
+
input: any;
|
|
266
|
+
output: any;
|
|
267
|
+
options?: NormalizeOptions;
|
|
268
|
+
title: string;
|
|
269
|
+
}[] = [
|
|
270
|
+
{
|
|
271
|
+
input: 1,
|
|
272
|
+
output: 'number',
|
|
273
|
+
title: `should not affect number primitive if options is not set`,
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
input: 1,
|
|
277
|
+
options: { keepOriginPrototype: false },
|
|
278
|
+
output: 'number',
|
|
279
|
+
title: `should not affect number primitive if keepOriginPrototype is false`,
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
input: 1,
|
|
283
|
+
options: { keepOriginPrototype: true },
|
|
284
|
+
output: 'number',
|
|
285
|
+
title: `should not affect number primitive if keepOriginPrototype is true`,
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
input: '1',
|
|
289
|
+
output: 'string',
|
|
290
|
+
title: `should not affect string primitive if options is not set`,
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
input: '1',
|
|
294
|
+
options: { keepOriginPrototype: false },
|
|
295
|
+
output: 'string',
|
|
296
|
+
title: `should not affect string primitive if keepOriginPrototype is false`,
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
input: '1',
|
|
300
|
+
options: { keepOriginPrototype: true },
|
|
301
|
+
output: 'string',
|
|
302
|
+
title: `should not affect string primitive if keepOriginPrototype is true`,
|
|
303
|
+
},
|
|
304
|
+
];
|
|
305
|
+
|
|
306
|
+
it.each(primitiveCases)('$title', ({ input, output, options }) => {
|
|
307
|
+
const result = normalizer()(input, options);
|
|
308
|
+
|
|
309
|
+
expect(typeof result).toBe(output);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
@@ -9,6 +9,7 @@ export interface NormalizeOptions {
|
|
|
9
9
|
filterKeys?: string[];
|
|
10
10
|
sortKeys?: SortKeys;
|
|
11
11
|
maxDepth?: number;
|
|
12
|
+
keepOriginPrototype?: boolean;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
const DEFAULT_MAX_DEPTH = 10;
|
|
@@ -30,6 +31,7 @@ const DEFAULT_MAX_DEPTH = 10;
|
|
|
30
31
|
* - Map -> '[Map size]'
|
|
31
32
|
* - Set -> '[Set size]'
|
|
32
33
|
* - Limits object nesting depth (default: 10)
|
|
34
|
+
* - Keeps origin prototype (default: false)
|
|
33
35
|
* - Protects against large objects (>16M keys)
|
|
34
36
|
*
|
|
35
37
|
* @example
|
|
@@ -49,6 +51,7 @@ const DEFAULT_MAX_DEPTH = 10;
|
|
|
49
51
|
* - filterKeys: Array of keys to exclude
|
|
50
52
|
* - sortKeys: Custom key sorting configuration
|
|
51
53
|
* - maxDepth: Maximum nesting depth (default: 10)
|
|
54
|
+
* - keepOriginPrototype: Whether to keep the original prototype (default: false)
|
|
52
55
|
* @param depth - Current recursion depth (internal use)
|
|
53
56
|
*/
|
|
54
57
|
export const normalizer = (): ((
|
|
@@ -128,6 +131,16 @@ export const normalizer = (): ((
|
|
|
128
131
|
keys.sort(options.sortKeys.sortFn);
|
|
129
132
|
}
|
|
130
133
|
|
|
134
|
+
/**
|
|
135
|
+
* There is several cases, when we have to keep the origin prototype.
|
|
136
|
+
* For example, if normalizer is executing implicitly
|
|
137
|
+
* and normalized object will be used in `instanceof` condition
|
|
138
|
+
* next to execution context
|
|
139
|
+
*/
|
|
140
|
+
const normalized = options?.keepOriginPrototype
|
|
141
|
+
? Object.setPrototypeOf({}, Object.getPrototypeOf(xObject))
|
|
142
|
+
: {};
|
|
143
|
+
|
|
131
144
|
return keys.reduce((acc: Record<string, unknown>, key) => {
|
|
132
145
|
if (options?.filterKeys?.includes(key)) {
|
|
133
146
|
return acc;
|
|
@@ -136,7 +149,7 @@ export const normalizer = (): ((
|
|
|
136
149
|
acc[key] = normalize((xObject as any)[key], options, newDepth);
|
|
137
150
|
|
|
138
151
|
return acc;
|
|
139
|
-
},
|
|
152
|
+
}, normalized);
|
|
140
153
|
} catch (error) {
|
|
141
154
|
return `[Can not get keys from object. ${error}]`;
|
|
142
155
|
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './typebox.validator';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { TSchema } from '@sinclair/typebox';
|
|
2
|
+
import type { TypeCheck, ValueError } from '@sinclair/typebox/compiler';
|
|
3
|
+
import { TypeCompiler } from '@sinclair/typebox/compiler';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Wrapper around Typebox's type validation.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const validator = new Validator(t.Object({ name: t.String() }));
|
|
11
|
+
* const { isValid, errors } = validator.run({ name: 'John' });
|
|
12
|
+
* ...
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export class TypeBoxValidator<T extends TSchema> {
|
|
16
|
+
private readonly validator: TypeCheck<T>;
|
|
17
|
+
|
|
18
|
+
constructor(schema: T) {
|
|
19
|
+
this.validator = TypeCompiler.Compile(schema);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Run the validator on the given data.
|
|
24
|
+
*
|
|
25
|
+
* @param data - The data to validate.
|
|
26
|
+
* @returns The validation result.
|
|
27
|
+
*/
|
|
28
|
+
check(data: unknown): { isValid: boolean; errors: ValueError[] } {
|
|
29
|
+
/**
|
|
30
|
+
* TODO: При случае, придумать, как нормально распечатывать ошибки для union'ов.
|
|
31
|
+
* Сейчас они ужасно неинформативные.
|
|
32
|
+
*/
|
|
33
|
+
return {
|
|
34
|
+
isValid: this.validator.Check(data),
|
|
35
|
+
errors: [...this.validator.Errors(data)],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './observable-to-async-iterable';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/observable/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iEAA+C"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Observable } from 'rxjs';
|
|
2
|
-
export type Callback = (value?: any) => any;
|
|
3
|
-
/**
|
|
4
|
-
* Утилита для создания асинк итератора из обзервабл
|
|
5
|
-
* поиском "observableToAsyncIterable" можно найти тесты в которых есть пример использования
|
|
6
|
-
*/
|
|
7
|
-
export declare function observableToAsyncIterable<T>(observable: Observable<T>): AsyncIterableIterator<T>;
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.observableToAsyncIterable = observableToAsyncIterable;
|
|
4
|
-
/**
|
|
5
|
-
* Утилита для создания асинк итератора из обзервабл
|
|
6
|
-
* поиском "observableToAsyncIterable" можно найти тесты в которых есть пример использования
|
|
7
|
-
*/
|
|
8
|
-
function observableToAsyncIterable(observable) {
|
|
9
|
-
const pullQueue = [];
|
|
10
|
-
const pushQueue = [];
|
|
11
|
-
let listening = true;
|
|
12
|
-
const pushValue = (value) => {
|
|
13
|
-
if (pullQueue.length > 0) {
|
|
14
|
-
// It is safe to use the ! operator here as we check the length.
|
|
15
|
-
pullQueue.shift()({
|
|
16
|
-
value,
|
|
17
|
-
done: false,
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
pushQueue.push({
|
|
22
|
-
value,
|
|
23
|
-
done: false,
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
const pushError = (error) => {
|
|
28
|
-
if (pullQueue.length > 0) {
|
|
29
|
-
// It is safe to use the ! operator here as we check the length.
|
|
30
|
-
pullQueue.shift()({
|
|
31
|
-
value: { errors: [error] },
|
|
32
|
-
done: false,
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
pushQueue.push({
|
|
37
|
-
value: { errors: [error] },
|
|
38
|
-
done: false,
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
const pushDone = () => {
|
|
43
|
-
if (pullQueue.length > 0) {
|
|
44
|
-
// It is safe to use the ! operator here as we check the length.
|
|
45
|
-
pullQueue.shift()({ done: true });
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
pushQueue.push({ done: true });
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
const pullValue = () => new Promise((resolve) => {
|
|
52
|
-
if (pushQueue.length > 0) {
|
|
53
|
-
const element = pushQueue.shift();
|
|
54
|
-
// either {value: {errors: [...]}} or {value: ...}
|
|
55
|
-
resolve(element);
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
pullQueue.push(resolve);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
const subscription = observable.subscribe({
|
|
62
|
-
next(value) {
|
|
63
|
-
pushValue(value);
|
|
64
|
-
},
|
|
65
|
-
error(err) {
|
|
66
|
-
pushError(err);
|
|
67
|
-
},
|
|
68
|
-
complete() {
|
|
69
|
-
pushDone();
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
const emptyQueue = () => {
|
|
73
|
-
if (listening) {
|
|
74
|
-
listening = false;
|
|
75
|
-
subscription.unsubscribe();
|
|
76
|
-
for (const resolve of pullQueue) {
|
|
77
|
-
resolve({
|
|
78
|
-
value: undefined,
|
|
79
|
-
done: true,
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
pullQueue.length = 0;
|
|
83
|
-
pushQueue.length = 0;
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
return {
|
|
87
|
-
next() {
|
|
88
|
-
// return is a defined method, so it is safe to call it.
|
|
89
|
-
return listening ? pullValue() : this.return();
|
|
90
|
-
},
|
|
91
|
-
return() {
|
|
92
|
-
emptyQueue();
|
|
93
|
-
return Promise.resolve({
|
|
94
|
-
value: undefined,
|
|
95
|
-
done: true,
|
|
96
|
-
});
|
|
97
|
-
},
|
|
98
|
-
throw(error) {
|
|
99
|
-
emptyQueue();
|
|
100
|
-
return Promise.reject(error);
|
|
101
|
-
},
|
|
102
|
-
[Symbol.asyncIterator]() {
|
|
103
|
-
return this;
|
|
104
|
-
},
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
//# sourceMappingURL=observable-to-async-iterable.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"observable-to-async-iterable.js","sourceRoot":"","sources":["../../src/observable/observable-to-async-iterable.ts"],"names":[],"mappings":"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"}
|
package/src/observable/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './observable-to-async-iterable';
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import type { Observable } from 'rxjs';
|
|
2
|
-
|
|
3
|
-
export type Callback = (value?: any) => any;
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Утилита для создания асинк итератора из обзервабл
|
|
7
|
-
* поиском "observableToAsyncIterable" можно найти тесты в которых есть пример использования
|
|
8
|
-
*/
|
|
9
|
-
export function observableToAsyncIterable<T>(
|
|
10
|
-
observable: Observable<T>,
|
|
11
|
-
): AsyncIterableIterator<T> {
|
|
12
|
-
const pullQueue: Array<Callback> = [];
|
|
13
|
-
const pushQueue: Array<any> = [];
|
|
14
|
-
|
|
15
|
-
let listening = true;
|
|
16
|
-
|
|
17
|
-
const pushValue = (value: any): void => {
|
|
18
|
-
if (pullQueue.length > 0) {
|
|
19
|
-
// It is safe to use the ! operator here as we check the length.
|
|
20
|
-
pullQueue.shift()!({
|
|
21
|
-
value,
|
|
22
|
-
done: false,
|
|
23
|
-
});
|
|
24
|
-
} else {
|
|
25
|
-
pushQueue.push({
|
|
26
|
-
value,
|
|
27
|
-
done: false,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const pushError = (error: any): void => {
|
|
33
|
-
if (pullQueue.length > 0) {
|
|
34
|
-
// It is safe to use the ! operator here as we check the length.
|
|
35
|
-
pullQueue.shift()!({
|
|
36
|
-
value: { errors: [error] },
|
|
37
|
-
done: false,
|
|
38
|
-
});
|
|
39
|
-
} else {
|
|
40
|
-
pushQueue.push({
|
|
41
|
-
value: { errors: [error] },
|
|
42
|
-
done: false,
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const pushDone = (): void => {
|
|
48
|
-
if (pullQueue.length > 0) {
|
|
49
|
-
// It is safe to use the ! operator here as we check the length.
|
|
50
|
-
pullQueue.shift()!({ done: true });
|
|
51
|
-
} else {
|
|
52
|
-
pushQueue.push({ done: true });
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const pullValue = (): Promise<IteratorResult<T>> =>
|
|
57
|
-
new Promise<IteratorResult<T>>((resolve) => {
|
|
58
|
-
if (pushQueue.length > 0) {
|
|
59
|
-
const element = pushQueue.shift();
|
|
60
|
-
|
|
61
|
-
// either {value: {errors: [...]}} or {value: ...}
|
|
62
|
-
resolve(element);
|
|
63
|
-
} else {
|
|
64
|
-
pullQueue.push(resolve);
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const subscription = observable.subscribe({
|
|
69
|
-
next(value: any) {
|
|
70
|
-
pushValue(value);
|
|
71
|
-
},
|
|
72
|
-
error(err: Error) {
|
|
73
|
-
pushError(err);
|
|
74
|
-
},
|
|
75
|
-
complete() {
|
|
76
|
-
pushDone();
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
const emptyQueue = (): void => {
|
|
81
|
-
if (listening) {
|
|
82
|
-
listening = false;
|
|
83
|
-
subscription.unsubscribe();
|
|
84
|
-
for (const resolve of pullQueue) {
|
|
85
|
-
resolve({
|
|
86
|
-
value: undefined,
|
|
87
|
-
done: true,
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
pullQueue.length = 0;
|
|
91
|
-
pushQueue.length = 0;
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
return {
|
|
96
|
-
next(): Promise<IteratorResult<T>> {
|
|
97
|
-
// return is a defined method, so it is safe to call it.
|
|
98
|
-
return listening ? pullValue() : this.return!();
|
|
99
|
-
},
|
|
100
|
-
return(): Promise<IteratorResult<T>> {
|
|
101
|
-
emptyQueue();
|
|
102
|
-
return Promise.resolve({
|
|
103
|
-
value: undefined,
|
|
104
|
-
done: true,
|
|
105
|
-
});
|
|
106
|
-
},
|
|
107
|
-
throw(error): Promise<IteratorResult<T>> {
|
|
108
|
-
emptyQueue();
|
|
109
|
-
return Promise.reject(error);
|
|
110
|
-
},
|
|
111
|
-
[Symbol.asyncIterator](): AsyncIterableIterator<T> {
|
|
112
|
-
return this;
|
|
113
|
-
},
|
|
114
|
-
};
|
|
115
|
-
}
|