@aidc-toolkit/utility 0.9.0 → 0.9.2

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,13 +6,12 @@ import {
6
6
  CharacterSetCreator,
7
7
  Exclusion,
8
8
  HEXADECIMAL_CREATOR,
9
- IterationHelper,
10
- NUMERIC_CREATOR
9
+ NUMERIC_CREATOR,
10
+ Sequencer
11
11
  } from "../src/index.js";
12
12
 
13
13
  await i18nInit(I18NEnvironment.CLI, true);
14
14
 
15
- // eslint-disable-next-line jsdoc/require-jsdoc
16
15
  function testCharacterSetCreator(name: string, characterSetCreator: CharacterSetCreator, characterSetSize: number, length: number, excludeFirstZero: boolean, excludeAllNumeric: boolean): void {
17
16
  describe(name, () => {
18
17
  test("Character set", () => {
@@ -46,7 +45,6 @@ function testCharacterSetCreator(name: string, characterSetCreator: CharacterSet
46
45
  expect(characterSetCreator.exclusionSupport.includes(Exclusion.AllNumeric)).toBe(excludeAllNumeric);
47
46
  });
48
47
 
49
- // eslint-disable-next-line jsdoc/require-jsdoc
50
48
  function testCreate(exclusion: Exclusion): void {
51
49
  let domain: number;
52
50
 
@@ -66,7 +64,7 @@ function testCharacterSetCreator(name: string, characterSetCreator: CharacterSet
66
64
  break;
67
65
  }
68
66
 
69
- const sequence = IterationHelper.from(characterSetCreator.createSequence(length, 0n, domain, exclusion));
67
+ const sequence = Iterator.from(characterSetCreator.create(length, new Sequencer(0n, domain), exclusion));
70
68
 
71
69
  let previousS = "";
72
70
 
@@ -78,26 +76,26 @@ function testCharacterSetCreator(name: string, characterSetCreator: CharacterSet
78
76
 
79
77
  expect(s.length).toBe(length);
80
78
 
81
- expect(characterSetCreator.value(s, exclusion)).toBe(BigInt(index));
79
+ expect(characterSetCreator.valueFor(s, exclusion)).toBe(BigInt(index));
82
80
 
83
81
  sequenceCount++;
84
82
  });
85
83
 
86
84
  expect(sequenceCount).toBe(domain);
87
85
 
88
- expect(() => characterSetCreator.create(length, domain, exclusion)).toThrow(RangeError);
86
+ expect(() => characterSetCreator.create(length, domain, exclusion)).toThrow(`Value ${domain} must be less than ${domain}`);
89
87
 
90
- const sparseSequence = IterationHelper.from(characterSetCreator.createSequence(length, 0n, domain, exclusion, 123456n));
88
+ const sparseSequence = Iterator.from(characterSetCreator.create(length, new Sequencer(domain - 1, -domain), exclusion, 123456n));
91
89
 
92
90
  let sequential = true;
93
- previousS = "";
91
+ previousS = "~";
94
92
 
95
93
  const sequenceSet = new Set<string>();
96
94
 
97
95
  sequenceCount = 0;
98
96
 
99
97
  sparseSequence.forEach((s, index) => {
100
- sequential = sequential && s > previousS;
98
+ sequential = sequential && s < previousS;
101
99
  previousS = s;
102
100
 
103
101
  expect(s.length).toBe(length);
@@ -105,7 +103,7 @@ function testCharacterSetCreator(name: string, characterSetCreator: CharacterSet
105
103
  expect(sequenceSet.has(s)).toBe(false);
106
104
  sequenceSet.add(s);
107
105
 
108
- expect(characterSetCreator.value(s, exclusion, 123456n)).toBe(BigInt(index));
106
+ expect(characterSetCreator.valueFor(s, exclusion, 123456n)).toBe(BigInt(domain - index - 1));
109
107
 
110
108
  sequenceCount++;
111
109
  });
@@ -125,12 +123,19 @@ function testCharacterSetCreator(name: string, characterSetCreator: CharacterSet
125
123
  sparseRandomValues.push(characterSetCreator.create(length, randomValue, exclusion, 123456n));
126
124
  }
127
125
 
128
- expect(Array.from(characterSetCreator.createMultiple(length, randomValues, exclusion))).toStrictEqual(straightRandomValues);
129
- expect(Array.from(characterSetCreator.createMultiple(length, randomValues, exclusion, 123456n))).toStrictEqual(sparseRandomValues);
126
+ expect(Array.from(characterSetCreator.create(length, randomValues, exclusion))).toStrictEqual(straightRandomValues);
127
+ expect(Array.from(characterSetCreator.create(length, randomValues, exclusion, 123456n))).toStrictEqual(sparseRandomValues);
130
128
 
131
- expect(() => characterSetCreator.create(length, exclusion, domain, 123456n)).toThrow(RangeError);
129
+ expect(() => characterSetCreator.create(length, domain, exclusion, 123456n)).toThrow(`Value ${domain} must be less than ${domain}`);
132
130
  }
133
131
 
132
+ test("Length", () => {
133
+ expect(() => characterSetCreator.create(0, 0)).not.toThrow(RangeError);
134
+ expect(() => characterSetCreator.create(-1, 0)).toThrow("Length -1 must be greater than or equal to 0");
135
+ expect(() => characterSetCreator.create(40, 0)).not.toThrow(RangeError);
136
+ expect(() => characterSetCreator.create(41, 0)).toThrow("Length 41 must be less than or equal to 40");
137
+ });
138
+
134
139
  test("Create sequence", () => {
135
140
  testCreate(Exclusion.None);
136
141
  });
@@ -139,8 +144,8 @@ function testCharacterSetCreator(name: string, characterSetCreator: CharacterSet
139
144
  test("Create sequence, exclude first zero", () => {
140
145
  testCreate(Exclusion.FirstZero);
141
146
 
142
- expect(() => characterSetCreator.value("0000", Exclusion.FirstZero)).toThrow(RangeError);
143
- expect(() => characterSetCreator.value("1000", Exclusion.FirstZero)).not.toThrow(RangeError);
147
+ expect(() => characterSetCreator.valueFor("0000", Exclusion.FirstZero)).toThrow("Invalid character '0' at position 1");
148
+ expect(() => characterSetCreator.valueFor("1000", Exclusion.FirstZero)).not.toThrow(RangeError);
144
149
  });
145
150
  }
146
151
 
@@ -148,17 +153,41 @@ function testCharacterSetCreator(name: string, characterSetCreator: CharacterSet
148
153
  test("Create sequence, exclude all numeric", () => {
149
154
  testCreate(Exclusion.AllNumeric);
150
155
 
151
- expect(() => characterSetCreator.value("0000", Exclusion.AllNumeric)).toThrow(RangeError);
152
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
153
- expect(() => characterSetCreator.value("000" + characterSetCreator.character(characterSetCreator.characterIndex("9")! + 1), Exclusion.AllNumeric)).not.toThrow(RangeError);
154
- expect(() => characterSetCreator.value("9999", Exclusion.AllNumeric)).toThrow(RangeError);
155
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
156
- expect(() => characterSetCreator.value("999" + characterSetCreator.character(characterSetCreator.characterIndex("9")! + 1), Exclusion.AllNumeric)).not.toThrow(RangeError);
156
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Nine is known to be present in the character set.
157
+ const afterNine = characterSetCreator.character(characterSetCreator.characterIndex("9")! + 1);
158
+
159
+ expect(() => characterSetCreator.valueFor("0000", Exclusion.AllNumeric)).toThrow("String must not be all numeric");
160
+ expect(() => characterSetCreator.valueFor(`000${afterNine}`, Exclusion.AllNumeric)).not.toThrow(RangeError);
161
+ expect(() => characterSetCreator.valueFor("9999", Exclusion.AllNumeric)).toThrow("String must not be all numeric");
162
+ expect(() => characterSetCreator.valueFor(`999${afterNine}`, Exclusion.AllNumeric)).not.toThrow(RangeError);
157
163
  });
158
164
  }
159
165
  });
160
166
  }
161
167
 
168
+ describe("Exclusion", () => {
169
+ test("First zero", () => {
170
+ expect(() => new CharacterSetCreator([
171
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
172
+ ], Exclusion.FirstZero)).not.toThrow(RangeError);
173
+ expect(() => new CharacterSetCreator([
174
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"
175
+ ], Exclusion.FirstZero)).toThrow("Character set must support zero as first character");
176
+ });
177
+
178
+ test("All numeric", () => {
179
+ expect(() => new CharacterSetCreator([
180
+ "!", "#", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D"
181
+ ], Exclusion.AllNumeric)).not.toThrow(RangeError);
182
+ expect(() => new CharacterSetCreator([
183
+ "!", "#", "/", "0", "1", "2", "3", "A", "B", "C", "D"
184
+ ], Exclusion.AllNumeric)).toThrow("Character set must support all numeric characters in sequence");
185
+ expect(() => new CharacterSetCreator([
186
+ "!", "#", "/", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "A", "B", "C", "D"
187
+ ], Exclusion.AllNumeric)).toThrow("Character set must support all numeric characters in sequence");
188
+ });
189
+ });
190
+
162
191
  testCharacterSetCreator("Numeric", NUMERIC_CREATOR, 10, 4, true, false);
163
192
  testCharacterSetCreator("Hexadecimal", HEXADECIMAL_CREATOR, 16, 4, true, true);
164
193
  testCharacterSetCreator("Alphabetic", ALPHABETIC_CREATOR, 26, 3, false, false);
@@ -1,6 +1,6 @@
1
- import {I18NEnvironment, i18nInit} from "@aidc-toolkit/core";
2
- import {describe, expect, test} from "vitest";
3
- import {RecordValidator} from "../src/index.js";
1
+ import { I18NEnvironment, i18nInit } from "@aidc-toolkit/core";
2
+ import { describe, expect, test } from "vitest";
3
+ import { RecordValidator } from "../src/index.js";
4
4
 
5
5
  await i18nInit(I18NEnvironment.CLI, true);
6
6
 
@@ -1,6 +1,6 @@
1
- import {I18NEnvironment, i18nInit} from "@aidc-toolkit/core";
2
- import {describe, expect, test} from "vitest";
3
- import {RegExpValidator} from "../src/index.js";
1
+ import { I18NEnvironment, i18nInit } from "@aidc-toolkit/core";
2
+ import { describe, expect, test } from "vitest";
3
+ import { RegExpValidator } from "../src/index.js";
4
4
 
5
5
  await i18nInit(I18NEnvironment.CLI, true);
6
6
 
@@ -0,0 +1,72 @@
1
+ import { I18NEnvironment, i18nInit } from "@aidc-toolkit/core";
2
+ import { describe, expect, test } from "vitest";
3
+ import { Sequencer } from "../src/index.js";
4
+
5
+ await i18nInit(I18NEnvironment.CLI, true);
6
+
7
+ describe("Sequence", () => {
8
+ const sequencer1 = new Sequencer(10, 20);
9
+ const sequencer2 = new Sequencer(29, -20);
10
+
11
+ test("Structure", () => {
12
+ expect(sequencer1.startValue).toBe(10n);
13
+ expect(sequencer1.endValue).toBe(30n);
14
+ expect(sequencer1.count).toBe(20);
15
+ expect(sequencer1.minValue).toBe(10n);
16
+ expect(sequencer1.maxValue).toBe(29n);
17
+
18
+ expect(sequencer2.startValue).toBe(29n);
19
+ expect(sequencer2.endValue).toBe(9n);
20
+ expect(sequencer2.count).toBe(-20);
21
+ expect(sequencer2.minValue).toBe(10n);
22
+ expect(sequencer2.maxValue).toBe(29n);
23
+ });
24
+
25
+ test("Iteration", () => {
26
+ let expectedValue: bigint;
27
+ let count: number;
28
+
29
+ expectedValue = 10n;
30
+ count = 0;
31
+
32
+ for (const value of Iterator.from(sequencer1)) {
33
+ expect(value).toBe(expectedValue);
34
+
35
+ expectedValue++;
36
+ count++;
37
+ }
38
+
39
+ expect(count).toBe(20);
40
+
41
+ expectedValue = 29n;
42
+ count = 0;
43
+
44
+ for (const value of Iterator.from(sequencer2)) {
45
+ expect(value).toBe(expectedValue);
46
+
47
+ expectedValue--;
48
+ count++;
49
+ }
50
+
51
+ expect(count).toBe(20);
52
+ });
53
+
54
+ test("Reset", () => {
55
+ let expectedValue: bigint;
56
+ let count: number;
57
+
58
+ expectedValue = 10n;
59
+ count = 0;
60
+
61
+ sequencer1.reset();
62
+
63
+ for (const value of Iterator.from(sequencer1)) {
64
+ expect(value).toBe(expectedValue);
65
+
66
+ expectedValue++;
67
+ count++;
68
+ }
69
+
70
+ expect(count).toBe(20);
71
+ });
72
+ });
@@ -1,6 +1,6 @@
1
- import {I18NEnvironment, i18nInit} from "@aidc-toolkit/core";
2
- import {describe, expect, test} from "vitest";
3
- import { EncryptionTransformer, IdentityTransformer, IterationHelper, Transformer } from "../src/index.js";
1
+ import { I18NEnvironment, i18nInit } from "@aidc-toolkit/core";
2
+ import { describe, expect, test } from "vitest";
3
+ import { Sequencer, EncryptionTransformer, IdentityTransformer, Transformer } from "../src/index.js";
4
4
 
5
5
  await i18nInit(I18NEnvironment.CLI, true);
6
6
 
@@ -11,7 +11,7 @@ function testTransformer(domain: number, tweak?: number, callback?: (value: bigi
11
11
 
12
12
  const transformedValuesSet = new Set<bigint>();
13
13
 
14
- IterationHelper.from(transformer.forwardSequence(0n, domain)).forEach((transformedValue, index) => {
14
+ Iterator.from(transformer.forward(new Sequencer(0n, domain))).forEach((transformedValue, index) => {
15
15
  const indexN = BigInt(index);
16
16
 
17
17
  if (sequential && transformedValue !== indexN) {
@@ -40,12 +40,14 @@ function testTransformer(domain: number, tweak?: number, callback?: (value: bigi
40
40
  transformedRandomValues.push(transformer.forward(randomValue));
41
41
  }
42
42
 
43
- expect(Array.from(transformer.forwardMultiple(randomValues))).toStrictEqual(transformedRandomValues);
43
+ expect(Array.from(transformer.forward(randomValues))).toStrictEqual(transformedRandomValues);
44
44
 
45
- expect(() => transformer.forward(BigInt(domain))).toThrow(`Value ${domain} must be less than ${domain}`);
46
- expect(() => transformer.forwardSequence(BigInt(domain), 0)).not.toThrow(RangeError);
47
- expect(() => transformer.forwardSequence(BigInt(domain) - 1n, 1)).not.toThrow(RangeError);
48
- expect(() => transformer.forwardSequence(BigInt(domain), 1)).toThrow(`End value (start value + count - 1) ${domain} must be less than ${domain}`);
45
+ expect(() => transformer.forward(domain)).toThrow(`Value ${domain} must be less than ${domain}`);
46
+ expect(() => transformer.forward(new Sequencer(domain, 0))).not.toThrow(RangeError);
47
+ expect(() => transformer.forward(new Sequencer(domain - 1, 1))).not.toThrow(RangeError);
48
+ expect(() => transformer.forward(new Sequencer(domain, 1))).toThrow(`Maximum value ${domain} must be less than ${domain}`);
49
+ expect(() => transformer.forward(new Sequencer(0, -1))).not.toThrow(RangeError);
50
+ expect(() => transformer.forward(new Sequencer(-1, -1))).toThrow("Minimum value -1 must be greater than or equal to 0");
49
51
  }
50
52
 
51
53
  describe("Identity", () => {
@@ -117,13 +119,9 @@ describe("Encryption", () => {
117
119
  });
118
120
 
119
121
  test("Byte boundary", () => {
120
- // eslint-disable-next-line @typescript-eslint/dot-notation
121
122
  expect((Transformer.get(256n, 1n) as EncryptionTransformer)["_domainBytes"]).toBe(1);
122
- // eslint-disable-next-line @typescript-eslint/dot-notation
123
123
  expect((Transformer.get(257n, 1n) as EncryptionTransformer)["_domainBytes"]).toBe(2);
124
- // eslint-disable-next-line @typescript-eslint/dot-notation
125
124
  expect((Transformer.get(65536n, 1n) as EncryptionTransformer)["_domainBytes"]).toBe(2);
126
- // eslint-disable-next-line @typescript-eslint/dot-notation
127
125
  expect((Transformer.get(65537n, 1n) as EncryptionTransformer)["_domainBytes"]).toBe(3);
128
126
 
129
127
  testTransformer(256, 1);
@@ -131,7 +129,7 @@ describe("Encryption", () => {
131
129
  });
132
130
 
133
131
  test("Tweak variation", () => {
134
- expect(Array.from(Transformer.get(1000, 1235).forwardSequence(0n, 1000))).not.toStrictEqual(Array.from(Transformer.get(1000, 1234).forwardSequence(0n, 1000)));
132
+ expect(Array.from(Transformer.get(1000, 1235).forward(new Sequencer(0n, 1000)))).not.toStrictEqual(Array.from(Transformer.get(1000, 1234).forward(new Sequencer(0n, 1000))));
135
133
  });
136
134
 
137
135
  test("Consistency", () => {
package/typedoc.json CHANGED
@@ -6,5 +6,6 @@
6
6
  "name": "Utility",
7
7
  "entryPoints": [
8
8
  "src/index.ts"
9
- ]
9
+ ],
10
+ "gitRevision": "main"
10
11
  }
@@ -1,12 +0,0 @@
1
- <component name="ProjectRunConfigurationManager">
2
- <configuration default="false" name="Test iteration" type="JavaScriptTestRunnerVitest">
3
- <node-interpreter value="project" />
4
- <vitest-package value="$PROJECT_DIR$/node_modules/vitest" />
5
- <working-dir value="$PROJECT_DIR$" />
6
- <vitest-options value="--run" />
7
- <envs />
8
- <scope-kind value="TEST_FILE" />
9
- <test-file value="$PROJECT_DIR$/test/iteration.test.ts" />
10
- <method v="2" />
11
- </configuration>
12
- </component>
package/src/iteration.ts DELETED
@@ -1,343 +0,0 @@
1
- /**
2
- * Iteration source type. The underlying source is an iterable or iterator or a callback to an iterable or iterator.
3
- */
4
- export type IterationSource<T> = Iterable<T> | Iterator<T> | (() => (Iterable<T> | Iterator<T>));
5
-
6
- /**
7
- * Iteration proxy class for applying a callback for mapping or filtering.
8
- */
9
- class IterationProxy<T, U, V> implements IterableIterator<V> {
10
- /**
11
- * Proxied iterable iterator.
12
- */
13
- private readonly _proxiedIterableIterator: IterableIterator<T>;
14
-
15
- /**
16
- * Callback for map or filter.
17
- */
18
- private readonly _callback: (element: T, index: number) => U;
19
-
20
- /**
21
- * If true, callback is a predicate for a filter.
22
- */
23
- private readonly _isPredicate: boolean;
24
-
25
- /**
26
- * Index into proxied iterable iterator.
27
- */
28
- private _index: number;
29
-
30
- /**
31
- * Constructor.
32
- *
33
- * @param proxiedIterableIterator
34
- * Proxied iterable iterator.
35
- *
36
- * @param callback
37
- * Callback for map or filter.
38
- *
39
- * @param isPredicate
40
- * If true, callback is a predicate for a filter.
41
- */
42
- constructor(proxiedIterableIterator: IterableIterator<T>, callback: (element: T, index: number) => U, isPredicate: boolean) {
43
- this._proxiedIterableIterator = proxiedIterableIterator;
44
- this._callback = callback;
45
- this._isPredicate = isPredicate;
46
-
47
- this._index = 0;
48
- }
49
-
50
- /**
51
- * {@link Iterable} interface implementation.
52
- *
53
- * @returns
54
- * Iterable iterator.
55
- */
56
- [Symbol.iterator](): IterableIterator<V> {
57
- return this;
58
- }
59
-
60
- /**
61
- * {@link Iterator} interface implementation.
62
- *
63
- * @param args
64
- * Arguments.
65
- *
66
- * @returns
67
- * Next element or number or total number of elements if none.
68
- */
69
- next(...args: [] | [undefined]): IteratorResult<V, number> {
70
- let done = false;
71
- let value: V | undefined;
72
-
73
- let callbackDone: boolean;
74
-
75
- do {
76
- const proxiedNext = this._proxiedIterableIterator.next(...args);
77
-
78
- if (!(proxiedNext.done ?? false)) {
79
- const proxiedValue = proxiedNext.value;
80
- const callbackValue = this._callback(proxiedValue, this._index++);
81
-
82
- if (!this._isPredicate) {
83
- // Types U and V are known to be identical.
84
- value = callbackValue as unknown as V;
85
-
86
- callbackDone = true;
87
- } else {
88
- callbackDone = callbackValue as boolean;
89
-
90
- if (callbackDone) {
91
- // Types T and V are known to be identical.
92
- value = proxiedValue as unknown as V;
93
- }
94
- }
95
- } else {
96
- done = true;
97
- callbackDone = true;
98
- }
99
- } while (!callbackDone);
100
-
101
- return done ?
102
- {
103
- done: true,
104
- value: this._index
105
- } :
106
- {
107
- done: false,
108
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
109
- value: value!
110
- };
111
- }
112
- }
113
-
114
- /**
115
- * Iteration helper. Adds array-like functionality through {@link forEach}, {@link map}, {@link filter}, and
116
- * {@link reduce} methods. Likely to be refactored as {@link
117
- * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator#iterator_helpers | iterator
118
- * helpers} are more widely deployed.
119
- */
120
- export class IterationHelper<T> implements IterableIterator<T> {
121
- /**
122
- * Iteration source.
123
- */
124
- private readonly _iterationSource: IterationSource<T>;
125
-
126
- /**
127
- * Iterable extracted from iteration source.
128
- */
129
- private _iterable?: Iterable<T>;
130
-
131
- /**
132
- * Iterator extracted from iteration source.
133
- */
134
- private _iterator?: Iterator<T>;
135
-
136
- /**
137
- * Constructor.
138
- *
139
- * @param iterationSource
140
- * Iteration source.
141
- */
142
- private constructor(iterationSource: IterationSource<T>) {
143
- this._iterationSource = iterationSource;
144
- }
145
-
146
- /**
147
- * Get an iteration helper from an iteration source. If the iteration source is itself an iteration helper, it is
148
- * returned verbatim, otherwise a new iteration helper is constructed.
149
- *
150
- * @param iterationSource
151
- * Iteration source.
152
- *
153
- * @returns
154
- * Iteration helper.
155
- */
156
- static from<T>(iterationSource: IterationSource<T>): IterationHelper<T> {
157
- return iterationSource instanceof IterationHelper ? iterationSource as IterationHelper<T> : new IterationHelper(iterationSource);
158
- }
159
-
160
- /**
161
- * Get the iteration source.
162
- */
163
- get iterationSource(): IterationSource<T> {
164
- return this._iterationSource;
165
- }
166
-
167
- /**
168
- * Get the iteration source as an iterable.
169
- *
170
- * @returns
171
- * Iterable.
172
- */
173
- asIterable(): Iterable<T> {
174
- if (this._iterable === undefined) {
175
- const resolvedIterationSource = typeof this.iterationSource === "function" ? this.iterationSource() : this.iterationSource;
176
-
177
- this._iterable = Symbol.iterator in resolvedIterationSource ?
178
- resolvedIterationSource :
179
- {
180
- [Symbol.iterator](): Iterator<T> {
181
- return resolvedIterationSource;
182
- }
183
- };
184
- }
185
-
186
- return this._iterable;
187
- }
188
-
189
- /**
190
- * Get the iteration source as an array.
191
- *
192
- * @returns
193
- * Array.
194
- */
195
- asArray(): readonly T[] {
196
- const iterable = this.asIterable();
197
-
198
- // Return iterable as array.
199
- return Array.isArray(iterable) ? iterable as readonly T[] : Array.from(iterable);
200
- }
201
-
202
- /**
203
- * Get the iteration source as an iterator.
204
- *
205
- * @returns
206
- * Iterator.
207
- */
208
- asIterator(): Iterator<T> {
209
- if (this._iterator === undefined) {
210
- this._iterator = this.asIterable()[Symbol.iterator]();
211
- }
212
-
213
- return this._iterator;
214
- }
215
-
216
- /**
217
- * Get the iteration source as a callback.
218
- *
219
- * @returns
220
- * Callback.
221
- */
222
- asCallback(): () => IterationSource<T> {
223
- return typeof this._iterationSource === "function" ? this._iterationSource : () => this._iterationSource;
224
- }
225
-
226
- /**
227
- * {@link Iterable} interface implementation.
228
- *
229
- * @returns
230
- * Iterable iterator.
231
- */
232
- [Symbol.iterator](): IterableIterator<T> {
233
- return this;
234
- }
235
-
236
- /**
237
- * {@link Iterator} interface implementation.
238
- *
239
- * @param args
240
- * Arguments.
241
- *
242
- * @returns
243
- * Next element.
244
- */
245
- next(...args: [] | [undefined]): IteratorResult<T, unknown> {
246
- return this.asIterator().next(...args);
247
- }
248
-
249
- /**
250
- * Perform an action for each element in the iteration helper.
251
- *
252
- * @param callback
253
- * Callback that processes the element and its index in the iteration sequence.
254
- */
255
- forEach(callback: (element: T, index: number) => void): void {
256
- let index = 0;
257
-
258
- for (const element of this) {
259
- callback(element, index++);
260
- }
261
- }
262
-
263
- /**
264
- * Map the iteration helper to another iteration helper by performing an action for each element in the iteration
265
- * helper along the way.
266
- *
267
- * @param callback
268
- * Callback that processes the element and its index in the iteration sequence.
269
- *
270
- * @returns
271
- * Iterable iterator over callback results.
272
- */
273
- map<U>(callback: (element: T, index: number) => U): IterableIterator<U> {
274
- return new IterationProxy(this, callback, false);
275
- }
276
-
277
- /**
278
- * Filter the iteration helper based on the condition specified in a predicate. Each call to `.next()` will iterate
279
- * as far as necessary until it reaches an element that satisfies the predicate. Care should be taken when working
280
- * with large iterators and infrequently truthy predicates.
281
- *
282
- * @param predicate
283
- * Predicate that processes the element and its index in the iteration sequence.
284
- *
285
- * @returns
286
- * Iterator iterable over elements that satisfy the predicate.
287
- */
288
- filter(predicate: (element: T, index: number) => boolean): IterableIterator<T> {
289
- return new IterationProxy(this, predicate, true);
290
- }
291
-
292
- /**
293
- * Reduce the iterator to a single value by applying a callback.
294
- *
295
- * @param callback
296
- * Callback that processes the previous return value of the callback, the current value of the iterator, and the
297
- * current index. The initial value is considered to be the first element in the iteration helper.
298
- *
299
- * @returns
300
- * Reduced value.
301
- */
302
- reduce(callback: (previousValue: T, currentValue: T, currentIndex: number) => T): T;
303
-
304
- /**
305
- * Reduce the iterator to a single value by applying a callback.
306
- *
307
- * @param callback
308
- * Callback that processes the previous return value of the callback, the current value of the iterator, and the
309
- * current index.
310
- *
311
- * @param initialValue
312
- * Initial value, passed as the first previous return value of the callback.
313
- *
314
- * @returns
315
- * Reduced value.
316
- */
317
- reduce(callback: (previousValue: T, currentValue: T, currentIndex: number) => T, initialValue: T): T;
318
-
319
- reduce<U>(callback: (previousValue: U, currentValue: T, currentIndex: number) => U, initialValue?: U): U {
320
- let index = 0;
321
- let result = initialValue;
322
-
323
- for (const value of this) {
324
- if (index === 0 && initialValue === undefined) {
325
- result = value as unknown as U;
326
- } else {
327
- // Iteration has occurred at least once so result is of the expected type.
328
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
329
- result = callback(result!, value, index);
330
- }
331
-
332
- index++;
333
- }
334
-
335
- if (index === 0 && initialValue === undefined) {
336
- throw new Error("reduce() of empty iterator with no initial value");
337
- }
338
-
339
- // Iteration has occurred at least once so result is of the expected type.
340
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
341
- return result!;
342
- }
343
- }