@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.
@@ -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":"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"}
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
@@ -5,5 +5,5 @@ export * from './time';
5
5
  export * from './functions';
6
6
  export * from './size';
7
7
  export * from './strings';
8
- export * from './observable';
9
8
  export * from './parsers';
9
+ export * from './validation';
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;AAC7B,4CAA0B"}
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("./observable-to-async-iterable"), exports);
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.0",
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
- "dependencies": {
17
- "rxjs": "^7.8.1"
16
+ "peerDependencies": {
17
+ "@sinclair/typebox": "^0.34.9"
18
18
  },
19
- "gitHead": "215cccea23d95118dd8b6af3ce11c6a35ce19c30"
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
@@ -5,5 +5,5 @@ export * from './time';
5
5
  export * from './functions';
6
6
  export * from './size';
7
7
  export * from './strings';
8
- export * from './observable';
9
8
  export * from './parsers';
9
+ export * from './validation';
@@ -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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"}
@@ -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
- }