@aidc-toolkit/utility 0.9.7-beta → 0.9.9-beta

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.
@@ -1,7 +1,86 @@
1
- import { IteratorProxy } from "./iterator_proxy.js";
2
- import i18next, { utilityNS } from "./locale/i18n.js";
3
- import { Sequencer } from "./sequencer.js";
4
- import type { TransformerCallback, TransformerInput, TransformerOutput } from "./types.js";
1
+ import { i18nextUtility } from "./locale/i18n.js";
2
+ import { Sequence } from "./sequence.js";
3
+
4
+ /**
5
+ * Transformer primitive type.
6
+ */
7
+ export type TransformerPrimitive = string | number | bigint | boolean;
8
+
9
+ /**
10
+ * Transformer input type, one of:
11
+ *
12
+ * - TInput (primitive type)
13
+ * - Iterable<TInput>
14
+ *
15
+ * @template TInput
16
+ * Transformer input primitive type.
17
+ */
18
+ export type TransformerInput<TInput extends TransformerPrimitive> = TInput | Iterable<TInput>;
19
+
20
+ /**
21
+ * Transformer callback, used to convert transformed value to its final value.
22
+ *
23
+ * @template TInput
24
+ * Transformer input primitive type.
25
+ *
26
+ * @template TOutput
27
+ * Transformer output type.
28
+ *
29
+ * @param input
30
+ * Input value.
31
+ *
32
+ * @param index
33
+ * Index in sequence (0 for single transformation).
34
+ *
35
+ * @returns
36
+ * Output value.
37
+ */
38
+ export type TransformerCallback<TInput extends TransformerPrimitive, TOutput> = (input: TInput, index: number) => TOutput;
39
+
40
+ /**
41
+ * Transformer output, based on transformer input:
42
+ *
43
+ * - If type TTransformerInput is primitive, result is type TOutput.
44
+ * - If type TTransformerInput is Iterable, result is type Iterable<TOutput>.
45
+ *
46
+ * @template TTransformerInput
47
+ * Transformer input type.
48
+ *
49
+ * @template TOutput
50
+ * Output base type.
51
+ */
52
+ export type TransformerOutput<TTransformerInput extends TransformerInput<TransformerPrimitive>, TOutput> =
53
+ TTransformerInput extends (TTransformerInput extends TransformerInput<infer TInput> ? TInput : never) ? TOutput : Iterable<TOutput>;
54
+
55
+ /**
56
+ * Transform an input iterable to an output iterable that applies a transformer callback to each value in the input.
57
+ *
58
+ * @param values
59
+ * Input values iterable.
60
+ *
61
+ * @param transformerCallback
62
+ * Callback to transform input value to output value.
63
+ *
64
+ * @returns
65
+ * Output values iterable.
66
+ */
67
+ export function transformIterable<TInput extends TransformerPrimitive, TOutput>(values: Iterable<TInput>, transformerCallback: TransformerCallback<TInput, TOutput>): Iterable<TOutput> {
68
+ return {
69
+ /**
70
+ * Iterable implementation.
71
+ *
72
+ * @yields
73
+ * Next output value.
74
+ */
75
+ * [Symbol.iterator](): Generator<TOutput> {
76
+ let index = 0;
77
+
78
+ for (const value of values) {
79
+ yield transformerCallback(value, index++);
80
+ }
81
+ }
82
+ };
83
+ }
5
84
 
6
85
  /**
7
86
  * Transformer that transforms values in a numeric domain to values in a range equal to the domain or to another range
@@ -41,8 +120,7 @@ export abstract class Transformer {
41
120
  this._domain = BigInt(domain);
42
121
 
43
122
  if (this._domain <= 0n) {
44
- throw new RangeError(i18next.t("Transformer.domainMustBeGreaterThanZero", {
45
- ns: utilityNS,
123
+ throw new RangeError(i18nextUtility.t("Transformer.domainMustBeGreaterThanZero", {
46
124
  domain
47
125
  }));
48
126
  }
@@ -100,15 +178,13 @@ export abstract class Transformer {
100
178
  */
101
179
  private validate(value: bigint): void {
102
180
  if (value < 0n) {
103
- throw new RangeError(i18next.t("Transformer.valueMustBeGreaterThanOrEqualToZero", {
104
- ns: utilityNS,
181
+ throw new RangeError(i18nextUtility.t("Transformer.valueMustBeGreaterThanOrEqualToZero", {
105
182
  value
106
183
  }));
107
184
  }
108
185
 
109
186
  if (value >= this.domain) {
110
- throw new RangeError(i18next.t("Transformer.valueMustBeLessThan", {
111
- ns: utilityNS,
187
+ throw new RangeError(i18nextUtility.t("Transformer.valueMustBeLessThan", {
112
188
  value,
113
189
  domain: this.domain
114
190
  }));
@@ -126,32 +202,68 @@ export abstract class Transformer {
126
202
  */
127
203
  protected abstract doForward(value: bigint): bigint;
128
204
 
205
+ /**
206
+ * Validate that a value is within the domain and do the work of transforming it forward.
207
+ *
208
+ * @param value
209
+ * Value.
210
+ *
211
+ * @returns
212
+ * Transformed value.
213
+ */
214
+ private validateDoForward(value: number | bigint): bigint {
215
+ const valueN = BigInt(value);
216
+
217
+ this.validate(valueN);
218
+
219
+ return this.doForward(valueN);
220
+ }
221
+
222
+ /**
223
+ * Validate that a value is within the domain, do the work of transforming it forward, and apply a callback.
224
+ *
225
+ * @param transformerCallback
226
+ * Called after each value is transformed to convert it to its final value.
227
+ *
228
+ * @param value
229
+ * Value.
230
+ *
231
+ * @param index
232
+ * Index in sequence (0 for single transformation).
233
+ *
234
+ * @returns
235
+ * Transformed value.
236
+ */
237
+ private validateDoForwardCallback<TOutput>(transformerCallback: TransformerCallback<bigint, TOutput>, value: number | bigint, index: number): TOutput {
238
+ return transformerCallback(this.validateDoForward(value), index);
239
+ };
240
+
129
241
  /**
130
242
  * Transform value(s) forward.
131
243
  *
132
- * @template T
244
+ * @template TTransformerInput
133
245
  * Value(s) input type.
134
246
  *
135
247
  * @param valueOrValues
136
- * Value(s). If this is an instance of {@link Sequencer}, the minimum and maximum values are validated prior to
248
+ * Value(s). If this is an instance of {@link Sequence}, the minimum and maximum values are validated prior to
137
249
  * transformation. Otherwise, the individual value(s) is/are validated at the time of transformation.
138
250
  *
139
251
  * @returns
140
252
  * Transformed value(s).
141
253
  */
142
- forward<T extends TransformerInput<number | bigint>>(valueOrValues: T): TransformerOutput<T, bigint>;
254
+ forward<TTransformerInput extends TransformerInput<number | bigint>>(valueOrValues: TTransformerInput): TransformerOutput<TTransformerInput, bigint>;
143
255
 
144
256
  /**
145
257
  * Transform value(s) forward, optionally applying a transformation.
146
258
  *
147
- * @template T
259
+ * @template TTransformerInput
148
260
  * Value(s) input type.
149
261
  *
150
- * @template U
262
+ * @template TOutput
151
263
  * Transformation callback output type.
152
264
  *
153
265
  * @param valueOrValues
154
- * Value(s). If this is an instance of {@link Sequencer}, the minimum and maximum values are validated prior to
266
+ * Value(s). If this is an instance of {@link Sequence}, the minimum and maximum values are validated prior to
155
267
  * transformation. Otherwise, the individual value(s) is/are validated at the time of transformation.
156
268
  *
157
269
  * @param transformerCallback
@@ -160,60 +272,36 @@ export abstract class Transformer {
160
272
  * @returns
161
273
  * Transformed value(s).
162
274
  */
163
- forward<T extends TransformerInput<number | bigint>, U>(valueOrValues: T, transformerCallback: TransformerCallback<bigint, U>): TransformerOutput<T, U>;
275
+ forward<TTransformerInput extends TransformerInput<number | bigint>, TOutput>(valueOrValues: TTransformerInput, transformerCallback: TransformerCallback<bigint, TOutput>): TransformerOutput<TTransformerInput, TOutput>;
164
276
 
165
277
  // eslint-disable-next-line jsdoc/require-jsdoc -- Implementation of overloaded signatures.
166
- forward<T extends TransformerInput<number | bigint>, U>(valueOrValues: T, transformerCallback?: TransformerCallback<bigint, U>): TransformerOutput<T, U> {
278
+ forward<TTransformerInput extends TransformerInput<number | bigint>, TOutput>(valueOrValues: TTransformerInput, transformerCallback?: TransformerCallback<bigint, TOutput>): TransformerOutput<TTransformerInput, TOutput> {
167
279
  // TODO Refactor type when https://github.com/microsoft/TypeScript/pull/56941 released.
168
- let result: bigint | U | IterableIterator<bigint> | IterableIterator<U>;
280
+ let result: bigint | TOutput | Iterable<bigint> | Iterable<TOutput>;
169
281
 
170
282
  if (typeof valueOrValues !== "object") {
171
- const valueN = BigInt(valueOrValues);
172
-
173
- this.validate(valueN);
174
-
175
- const transformedValue = this.doForward(valueN);
176
-
177
- result = transformerCallback === undefined ? transformedValue : transformerCallback(transformedValue, 0);
178
- } else if (valueOrValues instanceof Sequencer) {
179
- if (valueOrValues.minValue < 0n) {
180
- throw new RangeError(i18next.t("Transformer.minValueMustBeGreaterThanOrEqualToZero", {
181
- ns: utilityNS,
182
- minValue: valueOrValues.minValue
283
+ result = transformerCallback === undefined ? this.validateDoForward(valueOrValues) : this.validateDoForwardCallback(transformerCallback, valueOrValues, 0);
284
+ } else if (valueOrValues instanceof Sequence) {
285
+ if (valueOrValues.minimumValue < 0n) {
286
+ throw new RangeError(i18nextUtility.t("Transformer.minimumValueMustBeGreaterThanOrEqualToZero", {
287
+ minimumValue: valueOrValues.minimumValue
183
288
  }));
184
289
  }
185
290
 
186
- if (valueOrValues.maxValue >= this.domain) {
187
- throw new RangeError(i18next.t("Transformer.maxValueMustBeLessThan", {
188
- ns: utilityNS,
189
- maxValue: valueOrValues.maxValue,
291
+ if (valueOrValues.maximumValue >= this.domain) {
292
+ throw new RangeError(i18nextUtility.t("Transformer.maximumValueMustBeLessThan", {
293
+ maximumValue: valueOrValues.maximumValue,
190
294
  domain: this.domain
191
295
  }));
192
296
  }
193
297
 
194
- result = transformerCallback === undefined ?
195
- IteratorProxy.from(valueOrValues).map(value => this.doForward(value)) :
196
- IteratorProxy.from(valueOrValues).map((value, index) => transformerCallback(this.doForward(value), index));
298
+ result = transformerCallback === undefined ? transformIterable(valueOrValues, value => this.doForward(value)) : transformIterable(valueOrValues, (value, index) => transformerCallback(this.doForward(value), index));
197
299
  } else {
198
- result = transformerCallback === undefined ?
199
- IteratorProxy.from(valueOrValues).map((value) => {
200
- const valueN = BigInt(value);
201
-
202
- this.validate(valueN);
203
-
204
- return this.doForward(valueN);
205
- }) :
206
- IteratorProxy.from(valueOrValues).map((value, index) => {
207
- const valueN = BigInt(value);
208
-
209
- this.validate(valueN);
210
-
211
- return transformerCallback(this.doForward(valueN), index);
212
- });
300
+ result = transformerCallback === undefined ? transformIterable(valueOrValues, value => this.validateDoForward(value)) : transformIterable(valueOrValues, (value, index) => this.validateDoForwardCallback(transformerCallback, value, index));
213
301
  }
214
302
 
215
303
  // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Type determination is handled above.
216
- return result as TransformerOutput<T, U>;
304
+ return result as TransformerOutput<TTransformerInput, TOutput>;
217
305
  }
218
306
 
219
307
  /**
@@ -265,10 +353,11 @@ export class IdentityTransformer extends Transformer {
265
353
  }
266
354
 
267
355
  /**
268
- * Encryption transformer. Values are transformed using repeated shuffle and xor operations. The underlying operations
269
- * are similar to those found in many cryptography algorithms, particularly AES. While sufficient for obfuscation of
270
- * numeric sequences (e.g., serial number generation, below), if true format-preserving encryption is required, a more
271
- * robust algorithm such as {@link https://doi.org/10.6028/NIST.SP.800-38Gr1-draft | FF1} is recommended.
356
+ * Encryption transformer. Values are transformed using repeated shuffle and xor operations, similar to those found in
357
+ * many cryptography algorithms, particularly AES. While sufficient for obfuscation of numeric sequences (e.g., serial
358
+ * number generation, below), if true format-preserving encryption is required, a more robust algorithm such as
359
+ * {@link https://doi.org/10.6028/NIST.SP.800-38Gr1-draft | FF1} is recommended. Furthermore, no work has been done to
360
+ * mitigate {@link https://timing.attacks.cr.yp.to/index.html | timing attacks} for key detection.
272
361
  *
273
362
  * The purpose of the encryption transformer is to generate pseudo-random values in a deterministic manner to obscure
274
363
  * the sequence of values generated over time. A typical example is for serial number generation, where knowledge of the
@@ -304,11 +393,6 @@ export class EncryptionTransformer extends Transformer {
304
393
  */
305
394
  private readonly _domainBytes: number;
306
395
 
307
- /**
308
- * Tweak.
309
- */
310
- private readonly _tweak: bigint;
311
-
312
396
  /**
313
397
  * Xor bytes array generated from the domain and tweak.
314
398
  */
@@ -342,8 +426,7 @@ export class EncryptionTransformer extends Transformer {
342
426
  super(domain);
343
427
 
344
428
  if (tweak < 0n) {
345
- throw new RangeError(i18next.t("Transformer.tweakMustBeGreaterThanOrEqualToZero", {
346
- ns: utilityNS,
429
+ throw new RangeError(i18nextUtility.t("Transformer.tweakMustBeGreaterThanOrEqualToZero", {
347
430
  tweak
348
431
  }));
349
432
  }
@@ -351,26 +434,23 @@ export class EncryptionTransformer extends Transformer {
351
434
  let domainBytes = 0;
352
435
 
353
436
  // The number of bytes in the domain determines the size of the shuffle and xor operations.
354
- for (let reducedDomainMinusOne = this.domain - 1n; reducedDomainMinusOne !== 0n; reducedDomainMinusOne = reducedDomainMinusOne >> 8n) {
437
+ for (let reducedDomainMinusOne = this.domain - 1n; reducedDomainMinusOne !== 0n; reducedDomainMinusOne >>= 8n) {
355
438
  domainBytes++;
356
439
  }
357
440
 
358
441
  this._domainBytes = domainBytes;
359
- this._tweak = BigInt(tweak);
360
442
 
361
443
  const xorBytes = new Array<number>();
362
444
  const bits = new Array<number>();
363
445
  const inverseBits = new Array<number>();
364
446
 
365
447
  // Key is the product of domain, tweak, and an 8-digit prime to force at least four rounds.
366
- for (let reducedKey = this.domain * this.tweak * 603868999n; reducedKey !== 0n; reducedKey = reducedKey >> 8n) {
367
- // Extract least-significant byte.
368
- const keyByte = Number(reducedKey & 0xFFn);
369
-
370
- xorBytes.unshift(keyByte);
448
+ for (let reducedKey = this.domain * BigInt(tweak) * 603868999n; reducedKey !== 0n; reducedKey >>= 8n) {
449
+ // Extract the least significant byte.
450
+ xorBytes.unshift(Number(BigInt.asUintN(8, reducedKey)));
371
451
 
372
- // Bit number is the key byte mod 8.
373
- const bitNumber = keyByte & 0x07;
452
+ // Bit number is the reduced key mod 8.
453
+ const bitNumber = Number(BigInt.asUintN(3, reducedKey));
374
454
 
375
455
  // Bits are applied in reverse order so that they don't correlate directly with the key bytes at the same index.
376
456
  bits.push(EncryptionTransformer.BITS[bitNumber]);
@@ -399,13 +479,6 @@ export class EncryptionTransformer extends Transformer {
399
479
  }
400
480
  }
401
481
 
402
- /**
403
- * Get the tweak.
404
- */
405
- get tweak(): bigint {
406
- return this._tweak;
407
- }
408
-
409
482
  /**
410
483
  * Convert a value to a byte array big enough to handle the entire domain.
411
484
  *
@@ -418,13 +491,9 @@ export class EncryptionTransformer extends Transformer {
418
491
  private valueToBytes(value: bigint): Uint8Array {
419
492
  const bytes = new Uint8Array(this._domainBytes);
420
493
 
421
- let reducedValue = value;
422
-
423
494
  // Build byte array in reverse order to get as big-endian.
424
- for (let index = this._domainBytes - 1; index >= 0; index--) {
425
- bytes[index] = Number(reducedValue & 0xFFn);
426
-
427
- reducedValue = reducedValue >> 8n;
495
+ for (let index = this._domainBytes - 1, reducedValue = value; index >= 0 && reducedValue !== 0n; index--, reducedValue >>= 8n) {
496
+ bytes[index] = Number(BigInt.asUintN(8, reducedValue));
428
497
  }
429
498
 
430
499
  return bytes;
@@ -1,4 +1,4 @@
1
- import { I18NEnvironment, i18nInit } from "@aidc-toolkit/core";
1
+ import { I18NEnvironment } from "@aidc-toolkit/core";
2
2
  import { describe, expect, test } from "vitest";
3
3
  import {
4
4
  ALPHABETIC_CREATOR,
@@ -6,11 +6,12 @@ import {
6
6
  CharacterSetCreator,
7
7
  Exclusion,
8
8
  HEXADECIMAL_CREATOR,
9
+ i18nUtilityInit,
9
10
  NUMERIC_CREATOR,
10
- Sequencer
11
+ Sequence
11
12
  } from "../src/index.js";
12
13
 
13
- await i18nInit(I18NEnvironment.CLI);
14
+ await i18nUtilityInit(I18NEnvironment.CLI);
14
15
 
15
16
  function testCharacterSetCreator(name: string, characterSetCreator: CharacterSetCreator, characterSetSize: number, length: number, excludeFirstZero: boolean, excludeAllNumeric: boolean): void {
16
17
  describe(name, () => {
@@ -64,7 +65,7 @@ function testCharacterSetCreator(name: string, characterSetCreator: CharacterSet
64
65
  break;
65
66
  }
66
67
 
67
- const sequence = Iterator.from(characterSetCreator.create(length, new Sequencer(0n, domain), exclusion));
68
+ const sequence = Iterator.from(characterSetCreator.create(length, new Sequence(0n, domain), exclusion));
68
69
 
69
70
  let previousS = "";
70
71
 
@@ -85,7 +86,7 @@ function testCharacterSetCreator(name: string, characterSetCreator: CharacterSet
85
86
 
86
87
  expect(() => characterSetCreator.create(length, domain, exclusion)).toThrow(`Value ${domain} must be less than ${domain}`);
87
88
 
88
- const sparseSequence = Iterator.from(characterSetCreator.create(length, new Sequencer(domain - 1, -domain), exclusion, 123456n));
89
+ const sparseSequence = Iterator.from(characterSetCreator.create(length, new Sequence(domain - 1, -domain), exclusion, 123456n));
89
90
 
90
91
  let sequential = true;
91
92
  previousS = "~";
@@ -95,7 +96,7 @@ function testCharacterSetCreator(name: string, characterSetCreator: CharacterSet
95
96
  sequenceCount = 0;
96
97
 
97
98
  sparseSequence.forEach((s, index) => {
98
- sequential = sequential && s < previousS;
99
+ sequential &&= s < previousS;
99
100
  previousS = s;
100
101
 
101
102
  expect(s.length).toBe(length);
@@ -1,8 +1,8 @@
1
- import { I18NEnvironment, i18nInit } from "@aidc-toolkit/core";
1
+ import { I18NEnvironment } from "@aidc-toolkit/core";
2
2
  import { describe, expect, test } from "vitest";
3
- import { RecordValidator } from "../src/index.js";
3
+ import { i18nUtilityInit, RecordValidator } from "../src/index.js";
4
4
 
5
- await i18nInit(I18NEnvironment.CLI);
5
+ await i18nUtilityInit(I18NEnvironment.CLI);
6
6
 
7
7
  describe("Record validator", () => {
8
8
  enum StringEnum {
@@ -1,8 +1,8 @@
1
- import { I18NEnvironment, i18nInit } from "@aidc-toolkit/core";
1
+ import { I18NEnvironment } from "@aidc-toolkit/core";
2
2
  import { describe, expect, test } from "vitest";
3
- import { RegExpValidator } from "../src/index.js";
3
+ import { i18nUtilityInit, RegExpValidator } from "../src/index.js";
4
4
 
5
- await i18nInit(I18NEnvironment.CLI);
5
+ await i18nUtilityInit(I18NEnvironment.CLI);
6
6
 
7
7
  describe("Regular expression validator", () => {
8
8
  test("Validation", () => {
@@ -0,0 +1,61 @@
1
+ import { I18NEnvironment } from "@aidc-toolkit/core";
2
+ import { describe, expect, test } from "vitest";
3
+ import { i18nUtilityInit, Sequence } from "../src/index.js";
4
+
5
+ await i18nUtilityInit(I18NEnvironment.CLI);
6
+
7
+ describe("Sequence", () => {
8
+ const sequence1 = new Sequence(10, 20);
9
+ const sequence2 = new Sequence(29, -20);
10
+
11
+ test("Structure", () => {
12
+ expect(sequence1.startValue).toBe(10n);
13
+ expect(sequence1.endValue).toBe(30n);
14
+ expect(sequence1.count).toBe(20);
15
+ expect(sequence1.minimumValue).toBe(10n);
16
+ expect(sequence1.maximumValue).toBe(29n);
17
+
18
+ expect(sequence2.startValue).toBe(29n);
19
+ expect(sequence2.endValue).toBe(9n);
20
+ expect(sequence2.count).toBe(-20);
21
+ expect(sequence2.minimumValue).toBe(10n);
22
+ expect(sequence2.maximumValue).toBe(29n);
23
+ });
24
+
25
+ function iterate(): void {
26
+ let expectedValue: bigint;
27
+ let count: number;
28
+
29
+ expectedValue = 10n;
30
+ count = 0;
31
+
32
+ for (const value of Iterator.from(sequence1)) {
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(sequence2)) {
45
+ expect(value).toBe(expectedValue);
46
+
47
+ expectedValue--;
48
+ count++;
49
+ }
50
+
51
+ expect(count).toBe(20);
52
+ }
53
+
54
+ test("Iteration", () => {
55
+ iterate();
56
+ });
57
+
58
+ test("Repeat", () => {
59
+ iterate();
60
+ });
61
+ });
@@ -1,8 +1,8 @@
1
- import { I18NEnvironment, i18nInit } from "@aidc-toolkit/core";
1
+ import { I18NEnvironment } from "@aidc-toolkit/core";
2
2
  import { describe, expect, test } from "vitest";
3
- import { EncryptionTransformer, IdentityTransformer, Sequencer, Transformer } from "../src/index.js";
3
+ import { EncryptionTransformer, i18nUtilityInit, IdentityTransformer, Sequence, Transformer } from "../src/index.js";
4
4
 
5
- await i18nInit(I18NEnvironment.CLI);
5
+ await i18nUtilityInit(I18NEnvironment.CLI);
6
6
 
7
7
  function testTransformer(domain: number, tweak?: number, callback?: (value: bigint, forwardValue: bigint) => void): void {
8
8
  const transformer = Transformer.get(domain, tweak);
@@ -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
- Iterator.from(transformer.forward(new Sequencer(0n, domain))).forEach((transformedValue, index) => {
14
+ Iterator.from(transformer.forward(new Sequence(0n, domain))).forEach((transformedValue, index) => {
15
15
  const indexN = BigInt(index);
16
16
 
17
17
  if (sequential && transformedValue !== indexN) {
@@ -43,11 +43,11 @@ function testTransformer(domain: number, tweak?: number, callback?: (value: bigi
43
43
  expect(Array.from(transformer.forward(randomValues))).toStrictEqual(transformedRandomValues);
44
44
 
45
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");
46
+ expect(() => transformer.forward(new Sequence(domain, 0))).not.toThrow(RangeError);
47
+ expect(() => transformer.forward(new Sequence(domain - 1, 1))).not.toThrow(RangeError);
48
+ expect(() => transformer.forward(new Sequence(domain, 1))).toThrow(`Maximum value ${domain} must be less than ${domain}`);
49
+ expect(() => transformer.forward(new Sequence(0, -1))).not.toThrow(RangeError);
50
+ expect(() => transformer.forward(new Sequence(-1, -1))).toThrow("Minimum value -1 must be greater than or equal to 0");
51
51
  }
52
52
 
53
53
  describe("Identity", () => {
@@ -83,7 +83,6 @@ describe("Encryption", () => {
83
83
  expect(Transformer.get(1000n, 1234n)).toBe(transformer);
84
84
 
85
85
  expect(transformer.domain).toBe(BigInt(1000n));
86
- expect((transformer as EncryptionTransformer).tweak).toBe(BigInt(1234n));
87
86
 
88
87
  const transformer0 = Transformer.get(1000, 0);
89
88
 
@@ -129,7 +128,7 @@ describe("Encryption", () => {
129
128
  });
130
129
 
131
130
  test("Tweak variation", () => {
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))));
131
+ expect(Array.from(Transformer.get(1000, 1235).forward(new Sequence(0n, 1000)))).not.toStrictEqual(Array.from(Transformer.get(1000, 1234).forward(new Sequence(0n, 1000))));
133
132
  });
134
133
 
135
134
  test("Consistency", () => {
@@ -139,3 +138,31 @@ describe("Encryption", () => {
139
138
  expect(Transformer.get(1000000n, 1234567n).forward(987654n)).toBe(639402n);
140
139
  });
141
140
  });
141
+
142
+ describe("Non-sequence", () => {
143
+ function testIterables(sequence: Sequence): void {
144
+ const nonSequence = Array.from(sequence);
145
+
146
+ const transformer = Transformer.get(1000n, 1234n);
147
+
148
+ const sequenceForward = transformer.forward(sequence);
149
+ const nonSequenceForward = transformer.forward(nonSequence);
150
+
151
+ const nonSequenceIterator = nonSequenceForward[Symbol.iterator]();
152
+
153
+ for (const sequenceValue of sequenceForward) {
154
+ const nonSequenceNext = nonSequenceIterator.next();
155
+
156
+ expect(nonSequenceNext.done).not.toBe(true);
157
+ expect(nonSequenceNext.value).toBe(sequenceValue);
158
+ }
159
+ }
160
+
161
+ test("Ascending", () => {
162
+ testIterables(new Sequence(0, 10));
163
+ });
164
+
165
+ test("Descending", () => {
166
+ testIterables(new Sequence(9, -10));
167
+ });
168
+ });