@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.
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Sequencer. Defines an ascending or descending sequence of big integers implemented as an iterable iterator.
3
+ */
4
+ export class Sequencer implements Iterable<bigint>, IterableIterator<bigint> {
5
+ /**
6
+ * Start value (inclusive).
7
+ */
8
+ private readonly _startValue: bigint;
9
+
10
+ /**
11
+ * End value (exclusive).
12
+ */
13
+ private readonly _endValue: bigint;
14
+
15
+ /**
16
+ * Count of values.
17
+ */
18
+ private readonly _count: number;
19
+
20
+ /**
21
+ * Delta to the next value; equal to the sign of the count.
22
+ */
23
+ private readonly _nextDelta: 1n | -1n;
24
+
25
+ /**
26
+ * Minimum value (inclusive).
27
+ */
28
+ private readonly _minValue: bigint;
29
+
30
+ /**
31
+ * Maximum value (inclusive).
32
+ */
33
+ private readonly _maxValue: bigint;
34
+
35
+ /**
36
+ * Next value.
37
+ */
38
+ private _nextValue: bigint;
39
+
40
+ /**
41
+ * Constructor.
42
+ *
43
+ * @param startValue
44
+ * Start value.
45
+ *
46
+ * @param count
47
+ * Count of values. If count is zero or positive, iteration ascends from start value, otherwise it descends from
48
+ * start value.
49
+ */
50
+ constructor(startValue: number | bigint, count: number) {
51
+ this._startValue = BigInt(startValue);
52
+ this._endValue = this._startValue + BigInt(count);
53
+ this._count = count;
54
+
55
+ const ascending = count >= 0;
56
+
57
+ if (ascending) {
58
+ this._nextDelta = 1n;
59
+ this._minValue = this._startValue;
60
+ this._maxValue = this._endValue - 1n;
61
+ } else {
62
+ this._nextDelta = -1n;
63
+ this._minValue = this._endValue + 1n;
64
+ this._maxValue = this._startValue;
65
+ }
66
+
67
+ this._nextValue = this._startValue;
68
+ }
69
+
70
+ /**
71
+ * Get the start value (inclusive).
72
+ */
73
+ get startValue(): bigint {
74
+ return this._startValue;
75
+ }
76
+
77
+ /**
78
+ * Get the end value (exclusive).
79
+ */
80
+ get endValue(): bigint {
81
+ return this._endValue;
82
+ }
83
+
84
+ /**
85
+ * Get the count of values.
86
+ */
87
+ get count(): number {
88
+ return this._count;
89
+ }
90
+
91
+ /**
92
+ * Get the minimum value (inclusive).
93
+ */
94
+ get minValue(): bigint {
95
+ return this._minValue;
96
+ }
97
+
98
+ /**
99
+ * Get the maximum value (inclusive).
100
+ */
101
+ get maxValue(): bigint {
102
+ return this._maxValue;
103
+ }
104
+
105
+ /**
106
+ * Iterable implementation.
107
+ *
108
+ * @returns
109
+ * this
110
+ */
111
+ [Symbol.iterator](): this {
112
+ return this;
113
+ }
114
+
115
+ /**
116
+ * Iterator implementation.
117
+ *
118
+ * @returns
119
+ * Iterator result. If iterator is exhausted, the value is absolute value of the count.
120
+ */
121
+ next(): IteratorResult<bigint, number> {
122
+ const done = this._nextValue === this._endValue;
123
+
124
+ let result: IteratorResult<bigint, number>;
125
+
126
+ if (!done) {
127
+ result = {
128
+ value: this._nextValue
129
+ };
130
+
131
+ this._nextValue += this._nextDelta;
132
+ } else {
133
+ result = {
134
+ done: true,
135
+ value: Math.abs(this._count)
136
+ };
137
+ }
138
+
139
+ return result;
140
+ }
141
+
142
+ /**
143
+ * Reset the iterator.
144
+ */
145
+ reset(): void {
146
+ // Reset simply returns to the start.
147
+ this._nextValue = this._startValue;
148
+ }
149
+ }
package/src/string.ts CHANGED
@@ -8,9 +8,9 @@ export interface StringValidation {
8
8
  /**
9
9
  * String validator interface.
10
10
  */
11
- export interface StringValidator {
11
+ export interface StringValidator<V extends StringValidation = StringValidation> {
12
12
  /**
13
- * Validate a string and throw an exception if validation fails.
13
+ * Validate a string and throw an error if validation fails.
14
14
  *
15
15
  * @param s
16
16
  * String.
@@ -18,5 +18,5 @@ export interface StringValidator {
18
18
  * @param validation
19
19
  * String validation parameters.
20
20
  */
21
- validate: (s: string, validation?: StringValidation) => void;
21
+ validate: (s: string, validation?: V) => void;
22
22
  }
@@ -1,5 +1,5 @@
1
- import { IterationHelper, type IterationSource } from "./iteration.js";
2
1
  import i18next, { utilityNS } from "./locale/i18n.js";
2
+ import { Sequencer } from "./sequencer.js";
3
3
 
4
4
  /**
5
5
  * Transformation callback, used to convert transformed value to its final value.
@@ -52,15 +52,15 @@ export abstract class Transformer {
52
52
  * @param domain
53
53
  * Domain.
54
54
  */
55
- constructor(domain: bigint) {
56
- if (domain <= 0n) {
55
+ constructor(domain: number | bigint) {
56
+ this._domain = BigInt(domain);
57
+
58
+ if (this._domain <= 0n) {
57
59
  throw new RangeError(i18next.t("Transformer.domainMustBeGreaterThanZero", {
58
60
  ns: utilityNS,
59
61
  domain
60
62
  }));
61
63
  }
62
-
63
- this._domain = BigInt(domain);
64
64
  }
65
65
 
66
66
  /**
@@ -108,30 +108,23 @@ export abstract class Transformer {
108
108
  }
109
109
 
110
110
  /**
111
- * Validate that a start value and count are within the domain.
111
+ * Validate that a value is within the domain.
112
112
  *
113
- * @param startValue
114
- * Start value of range to validate.
115
- *
116
- * @param count
117
- * Number of entries in the range to validate or 1 if undefined.
118
- *
119
- * @throws RangeError
113
+ * @param value
114
+ * Value.
120
115
  */
121
- private validate(startValue: bigint, count?: number): void {
122
- if (startValue < 0n) {
123
- throw new RangeError(i18next.t(count === undefined ? "Transformer.valueMustBeGreaterThanOrEqualToZero" : "Transformer.startValueMustBeGreaterThanOrEqualToZero", {
116
+ private validate(value: bigint): void {
117
+ if (value < 0n) {
118
+ throw new RangeError(i18next.t("Transformer.valueMustBeGreaterThanOrEqualToZero", {
124
119
  ns: utilityNS,
125
- startValue
120
+ value
126
121
  }));
127
122
  }
128
123
 
129
- const endValue = count === undefined ? startValue : startValue + BigInt(count - 1);
130
-
131
- if (endValue >= this.domain) {
132
- throw new RangeError(i18next.t(count === undefined ? "Transformer.valueMustBeLessThan" : "Transformer.endValueMustBeLessThan", {
124
+ if (value >= this.domain) {
125
+ throw new RangeError(i18next.t("Transformer.valueMustBeLessThan", {
133
126
  ns: utilityNS,
134
- endValue,
127
+ value,
135
128
  domain: this.domain
136
129
  }));
137
130
  }
@@ -157,13 +150,13 @@ export abstract class Transformer {
157
150
  * @returns
158
151
  * Transformed value.
159
152
  */
160
- forward(value: bigint): bigint;
153
+ forward(value: number | bigint): bigint;
161
154
 
162
155
  /**
163
156
  * Transform a value forward.
164
157
  *
165
158
  * @template T
166
- * Type returned by transformation callback or bigint if none.
159
+ * Type returned by transformation callback.
167
160
  *
168
161
  * @param value
169
162
  * Value.
@@ -174,118 +167,126 @@ export abstract class Transformer {
174
167
  * @returns
175
168
  * Value transformed into object.
176
169
  */
177
- forward<T>(value: bigint, transformationCallback: TransformationCallback<T>): T;
178
-
179
- forward<T>(value: bigint, transformationCallback?: TransformationCallback<T>): bigint | T {
180
- this.validate(value);
170
+ forward<T>(value: number | bigint, transformationCallback: TransformationCallback<T>): T;
181
171
 
182
- const transformedValue = this.doForward(value);
183
-
184
- return transformationCallback === undefined ? transformedValue : transformationCallback(transformedValue, 0);
185
- }
172
+ /**
173
+ * Transform values forward.
174
+ *
175
+ * @param values
176
+ * Values. If this is an instance of {@link Sequencer}, the minimum and maximum values are validated prior to
177
+ * transformation. Otherwise, the individual values are validated at the time of transformation.
178
+ *
179
+ * @returns
180
+ * Transformed values.
181
+ */
182
+ forward(values: Iterable<number | bigint>): IterableIterator<bigint>;
186
183
 
187
184
  /**
188
- * Do the work for the forward sequence method. Parameters are as defined in the public methods.
185
+ * Transform values forward.
189
186
  *
190
187
  * @template T
191
- * See public methods.
188
+ * Type returned by transformation callback.
192
189
  *
193
- * @param startValue
194
- * See public methods.
195
- *
196
- * @param count
197
- * See public methods.
190
+ * @param values
191
+ * Values. If this is an instance of {@link Sequencer}, the minimum and maximum values are validated prior to
192
+ * transformation. Otherwise, the individual values are validated at the time of transformation.
198
193
  *
199
194
  * @param transformationCallback
200
- * See public methods.
195
+ * Called after each value is transformed to convert it to its final value.
201
196
  *
202
- * @yields
203
- * Transformed value optionally defined by transformation callback.
197
+ * @returns
198
+ * Values transformed into objects.
204
199
  */
205
- private * doForwardSequence<T>(startValue: bigint, count: number, transformationCallback?: TransformationCallback<T>): Generator<bigint | T> {
206
- for (let index = 0, value = startValue; index < count; index++, value++) {
207
- const transformedValue = this.doForward(value);
208
-
209
- yield transformationCallback !== undefined ? transformationCallback(transformedValue, index) : transformedValue;
210
- }
211
- }
200
+ forward<T>(values: Iterable<number | bigint>, transformationCallback: TransformationCallback<T>): IterableIterator<T>;
212
201
 
213
202
  /**
214
- * Transform a sequence of values forward.
203
+ * Transform a value or values forward. This signature exists to allow similar overloaded methods in other classes
204
+ * to call this method correctly.
215
205
  *
216
- * @param startValue
217
- * Numerical value of the first object. Objects are created from `startValue` to `startValue + count - 1`.
206
+ * @param valueOrValues
218
207
  *
219
- * @param count
220
- * Number of objects to create.
221
- *
222
- * @yields
223
- * Transformed value.
208
+ * @returns
224
209
  */
225
- forwardSequence(startValue: bigint, count: number): IterableIterator<bigint>;
210
+ forward(valueOrValues: number | bigint | Iterable<number | bigint>): bigint | IterableIterator<bigint>;
226
211
 
227
212
  /**
228
- * Transform a sequence of values forward.
213
+ * Transform a value or values forward. This signature exists to allow similar overloaded methods in other classes
214
+ * to call this method correctly.
229
215
  *
230
216
  * @template T
231
- * Type returned by transformation callback or bigint if none.
232
- *
233
- * @param startValue
234
- * Numerical value of the first object. Objects are created from `startValue` to `startValue + count - 1`.
235
217
  *
236
- * @param count
237
- * Number of objects to create.
218
+ * @param valueOrValues
238
219
  *
239
220
  * @param transformationCallback
240
- * Transformation callback called after the value is transformed to convert it to its final value.
241
221
  *
242
222
  * @returns
243
- * Iterable iterator over transformed values as defined by transformation callback.
244
223
  */
245
- forwardSequence<T>(startValue: bigint, count: number, transformationCallback: TransformationCallback<T>): IterableIterator<T>;
246
-
247
- forwardSequence<T>(startValue: bigint, count: number, transformationCallback?: TransformationCallback<T>): IterableIterator<bigint | T> {
248
- this.validate(startValue, count);
249
-
250
- return this.doForwardSequence(startValue, count, transformationCallback);
251
- }
224
+ forward<T>(valueOrValues: number | bigint | Iterable<number | bigint>, transformationCallback: TransformationCallback<T>): T | IterableIterator<T>;
252
225
 
253
226
  /**
254
- * Transform multiple values forward.
255
- *
256
- * @param valuesSource
257
- * Source of values.
258
- *
259
- * @returns
260
- * Iterable iterator over transformed values.
261
- */
262
- forwardMultiple(valuesSource: IterationSource<bigint>): IterableIterator<bigint>;
263
-
264
- /**
265
- * Transform multiple values forward.
227
+ * Transform a value or values forward.
266
228
  *
267
229
  * @template T
268
- * Type returned by transformation callback or bigint if none.
230
+ * Type returned by transformation callback.
269
231
  *
270
- * @param valuesSource
271
- * Source of values.
232
+ * @param valueOrValues
233
+ * Value(s).
272
234
  *
273
235
  * @param transformationCallback
274
- * Transformation callback called after the value is transformed to convert it to its final value.
236
+ * Called after value(s) is/are transformed to convert it/them to its/their final value(s).
275
237
  *
276
238
  * @returns
277
- * Iterable iterator over transformed values as defined by transformation callback.
239
+ * Value(s) transformed into object(s).
278
240
  */
279
- forwardMultiple<T>(valuesSource: IterationSource<bigint>, transformationCallback: TransformationCallback<T>): IterableIterator<T>;
241
+ forward<T>(valueOrValues: number | bigint | Iterable<number | bigint>, transformationCallback?: TransformationCallback<T>): bigint | T | IterableIterator<bigint> | IterableIterator<T> {
242
+ let result: bigint | T | IterableIterator<bigint> | IterableIterator<T>;
280
243
 
281
- forwardMultiple<T>(valuesSource: IterationSource<bigint>, transformationCallback?: TransformationCallback<T>): IterableIterator<bigint | T> {
282
- return IterationHelper.from(valuesSource).map((value, index) => {
283
- this.validate(value);
244
+ if (typeof valueOrValues !== "object") {
245
+ const valueN = BigInt(valueOrValues);
284
246
 
285
- const transformedValue = this.doForward(value);
247
+ this.validate(valueN);
286
248
 
287
- return transformationCallback !== undefined ? transformationCallback(transformedValue, index) : transformedValue;
288
- });
249
+ const transformedValue = this.doForward(valueN);
250
+
251
+ result = transformationCallback === undefined ? transformedValue : transformationCallback(transformedValue, 0);
252
+ } else if (valueOrValues instanceof Sequencer) {
253
+ if (valueOrValues.minValue < 0n) {
254
+ throw new RangeError(i18next.t("Transformer.minValueMustBeGreaterThanOrEqualToZero", {
255
+ ns: utilityNS,
256
+ minValue: valueOrValues.minValue
257
+ }));
258
+ }
259
+
260
+ if (valueOrValues.maxValue >= this.domain) {
261
+ throw new RangeError(i18next.t("Transformer.maxValueMustBeLessThan", {
262
+ ns: utilityNS,
263
+ maxValue: valueOrValues.maxValue,
264
+ domain: this.domain
265
+ }));
266
+ }
267
+
268
+ result = transformationCallback === undefined ?
269
+ Iterator.from(valueOrValues).map(value => this.doForward(value)) :
270
+ Iterator.from(valueOrValues).map((value, index) => transformationCallback(this.doForward(value), index));
271
+ } else {
272
+ result = transformationCallback === undefined ?
273
+ Iterator.from(valueOrValues).map((value) => {
274
+ const valueN = BigInt(value);
275
+
276
+ this.validate(valueN);
277
+
278
+ return this.doForward(valueN);
279
+ }) :
280
+ Iterator.from(valueOrValues).map((value, index) => {
281
+ const valueN = BigInt(value);
282
+
283
+ this.validate(valueN);
284
+
285
+ return transformationCallback(this.doForward(valueN), index);
286
+ });
287
+ }
288
+
289
+ return result;
289
290
  }
290
291
 
291
292
  /**
@@ -308,10 +309,12 @@ export abstract class Transformer {
308
309
  * @returns
309
310
  * Value.
310
311
  */
311
- reverse(transformedValue: bigint): bigint {
312
- this.validate(transformedValue);
312
+ reverse(transformedValue: number | bigint): bigint {
313
+ const transformedValueN = BigInt(transformedValue);
314
+
315
+ this.validate(transformedValueN);
313
316
 
314
- return this.doReverse(transformedValue);
317
+ return this.doReverse(transformedValueN);
315
318
  }
316
319
  }
317
320
 
@@ -319,10 +322,16 @@ export abstract class Transformer {
319
322
  * Identity transformer. Values are transformed to themselves.
320
323
  */
321
324
  export class IdentityTransformer extends Transformer {
325
+ /**
326
+ * @inheritDoc
327
+ */
322
328
  protected doForward(value: bigint): bigint {
323
329
  return value;
324
330
  }
325
331
 
332
+ /**
333
+ * @inheritDoc
334
+ */
326
335
  protected doReverse(transformedValue: bigint): bigint {
327
336
  return transformedValue;
328
337
  }
@@ -402,7 +411,7 @@ export class EncryptionTransformer extends Transformer {
402
411
  * @param tweak
403
412
  * Tweak.
404
413
  */
405
- constructor(domain: bigint, tweak: bigint) {
414
+ constructor(domain: number | bigint, tweak: number | bigint) {
406
415
  super(domain);
407
416
 
408
417
  if (tweak < 0n) {
@@ -415,19 +424,19 @@ export class EncryptionTransformer extends Transformer {
415
424
  let domainBytes = 0;
416
425
 
417
426
  // The number of bytes in the domain determines the size of the shuffle and xor operations.
418
- for (let reducedDomainMinusOne = domain - 1n; reducedDomainMinusOne !== 0n; reducedDomainMinusOne = reducedDomainMinusOne >> 8n) {
427
+ for (let reducedDomainMinusOne = this.domain - 1n; reducedDomainMinusOne !== 0n; reducedDomainMinusOne = reducedDomainMinusOne >> 8n) {
419
428
  domainBytes++;
420
429
  }
421
430
 
422
431
  this._domainBytes = domainBytes;
423
- this._tweak = tweak;
432
+ this._tweak = BigInt(tweak);
424
433
 
425
434
  const xorBytes = new Array<number>();
426
435
  const bits = new Array<number>();
427
436
  const inverseBits = new Array<number>();
428
437
 
429
438
  // Key is the product of domain, tweak, and an 8-digit prime to force at least four rounds.
430
- for (let reducedKey = domain * tweak * 603868999n; reducedKey !== 0n; reducedKey = reducedKey >> 8n) {
439
+ for (let reducedKey = this.domain * this.tweak * 603868999n; reducedKey !== 0n; reducedKey = reducedKey >> 8n) {
431
440
  // Extract least-significant byte.
432
441
  const keyByte = Number(reducedKey & 0xFFn);
433
442
 
@@ -504,9 +513,7 @@ export class EncryptionTransformer extends Transformer {
504
513
  * Value.
505
514
  */
506
515
  private static bytesToValue(bytes: Uint8Array): bigint {
507
- return bytes.reduce((accumulator, byte) => {
508
- return accumulator << 8n | BigInt(byte);
509
- }, 0n);
516
+ return bytes.reduce((accumulator, byte) => accumulator << 8n | BigInt(byte), 0n);
510
517
  }
511
518
 
512
519
  /**
@@ -618,6 +625,9 @@ export class EncryptionTransformer extends Transformer {
618
625
  });
619
626
  }
620
627
 
628
+ /**
629
+ * @inheritDoc
630
+ */
621
631
  protected doForward(value: bigint): bigint {
622
632
  let bytes = this.valueToBytes(value);
623
633
  let transformedValue: bigint;
@@ -635,6 +645,9 @@ export class EncryptionTransformer extends Transformer {
635
645
  return transformedValue;
636
646
  }
637
647
 
648
+ /**
649
+ * @inheritDoc
650
+ */
638
651
  protected doReverse(transformedValue: bigint): bigint {
639
652
  let bytes = this.valueToBytes(transformedValue);
640
653
  let value: bigint;