@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,12 @@
1
+ <component name="ProjectRunConfigurationManager">
2
+ <configuration default="false" name="build-dev" type="js.build_tools.npm" nameIsGenerated="true">
3
+ <package-json value="$PROJECT_DIR$/package.json" />
4
+ <command value="run" />
5
+ <scripts>
6
+ <script value="build-dev" />
7
+ </scripts>
8
+ <node-interpreter value="project" />
9
+ <envs />
10
+ <method v="2" />
11
+ </configuration>
12
+ </component>
package/eslint.config.js CHANGED
@@ -1,15 +1,13 @@
1
1
  import tseslint from "typescript-eslint";
2
- import js from "@eslint/js";
3
2
  import stylistic from "@stylistic/eslint-plugin";
4
3
  import jsdoc from "eslint-plugin-jsdoc";
5
4
  import esLintConfigLove from "eslint-config-love";
6
5
  import { esLintConfigAIDCToolkit } from "@aidc-toolkit/dev";
7
6
 
8
7
  export default tseslint.config(
9
- js.configs.recommended,
10
8
  ...tseslint.configs.strictTypeChecked,
11
9
  stylistic.configs["recommended-flat"],
12
10
  jsdoc.configs["flat/recommended-typescript"],
13
11
  esLintConfigLove,
14
- esLintConfigAIDCToolkit
12
+ ...esLintConfigAIDCToolkit
15
13
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aidc-toolkit/utility",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "Foundational utilities for AIDC Toolkit",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -20,23 +20,23 @@
20
20
  },
21
21
  "scripts": {
22
22
  "eslint": "eslint .",
23
- "build": "tsup src/index.ts --format cjs,esm --dts",
23
+ "build": "tsup src/index.ts --clean --format cjs,esm --dts",
24
+ "build-dev": "npm run build && tsc src/index.ts --outDir dist --target esnext --moduleResolution nodenext --module nodenext --emitDeclarationOnly --declaration --declarationMap",
24
25
  "test": "vitest run"
25
26
  },
26
27
  "devDependencies": {
27
- "@aidc-toolkit/dev": "^0.9.0",
28
- "@eslint/js": "^9.10.0",
29
- "@stylistic/eslint-plugin": "^2.7.2",
30
- "eslint-config-love": "^64.0.0",
31
- "eslint-plugin-jsdoc": "^50.2.2",
28
+ "@aidc-toolkit/dev": "^0.9.2",
29
+ "@stylistic/eslint-plugin": "^2.10.1",
30
+ "eslint-config-love": "^98.0.2",
31
+ "eslint-plugin-jsdoc": "^50.5.0",
32
32
  "ts-node": "^10.9.2",
33
- "tsup": "^8.2.4",
34
- "typescript": "^5.5.4",
35
- "typescript-eslint": "^8.4.0",
36
- "vitest": "^2.0.5"
33
+ "tsup": "^8.3.5",
34
+ "typescript": "^5.6.3",
35
+ "typescript-eslint": "^8.14.0",
36
+ "vitest": "^2.1.4"
37
37
  },
38
38
  "dependencies": {
39
- "@aidc-toolkit/core": "^0.9.0",
40
- "i18next": "^23.14.0"
39
+ "@aidc-toolkit/core": "^0.9.2",
40
+ "i18next": "^23.16.5"
41
41
  }
42
42
  }
@@ -1,8 +1,7 @@
1
- import { IterationHelper, type IterationSource } from "./iteration.js";
2
1
  import i18next, { utilityNS } from "./locale/i18n.js";
3
2
  import { RegExpValidator } from "./reg_exp.js";
4
3
  import type { StringValidation, StringValidator } from "./string.js";
5
- import { type TransformationCallback, Transformer } from "./transformer.js";
4
+ import { Transformer } from "./transformer.js";
6
5
 
7
6
  /**
8
7
  * Exclusion options for validating and creating strings based on character sets.
@@ -29,29 +28,29 @@ export enum Exclusion {
29
28
  */
30
29
  export interface CharacterSetValidation extends StringValidation {
31
30
  /**
32
- * Minimum length. If defined and the string is less than this length, an exception is thrown.
31
+ * Minimum length. If defined and the string is less than this length, an error is thrown.
33
32
  */
34
33
  minimumLength?: number | undefined;
35
34
 
36
35
  /**
37
- * Maximum length. If defined and the string is greater than this length, an exception is thrown.
36
+ * Maximum length. If defined and the string is greater than this length, an error is thrown.
38
37
  */
39
38
  maximumLength?: number | undefined;
40
39
 
41
40
  /**
42
- * Exclusion from the string. If defined and the string is within the exclusion range, an exception is thrown.
41
+ * Exclusion from the string. If defined and the string is within the exclusion range, an error is thrown.
43
42
  */
44
43
  exclusion?: Exclusion | undefined;
45
44
 
46
45
  /**
47
46
  * Position offset within a larger string. Strings are sometimes composed of multiple substrings; this parameter
48
- * ensures that the exception notes the proper position in the string.
47
+ * ensures that the error notes the proper position in the string.
49
48
  */
50
49
  positionOffset?: number | undefined;
51
50
 
52
51
  /**
53
52
  * Name of component, typically but not exclusively within a larger string. This parameter ensure that the
54
- * exception notes the component that triggered it. Value may be a string or a callback that returns a string, the
53
+ * error notes the component that triggered it. Value may be a string or a callback that returns a string, the
55
54
  * latter allowing for localization changes.
56
55
  */
57
56
  component?: string | (() => string) | undefined;
@@ -60,8 +59,17 @@ export interface CharacterSetValidation extends StringValidation {
60
59
  /**
61
60
  * Character set validator. Validates a string against a specified character set.
62
61
  */
63
- export class CharacterSetValidator implements StringValidator {
62
+ export class CharacterSetValidator implements StringValidator<CharacterSetValidation> {
64
63
  private static readonly NOT_ALL_NUMERIC_VALIDATOR = new class extends RegExpValidator {
64
+ /**
65
+ * Create an error message for an all-numeric string.
66
+ *
67
+ * @param _s
68
+ * String.
69
+ *
70
+ * @returns
71
+ * Error message.
72
+ */
65
73
  protected override createErrorMessage(_s: string): string {
66
74
  return i18next.t("CharacterSetValidator.stringMustNotBeAllNumeric", {
67
75
  ns: utilityNS
@@ -78,7 +86,7 @@ export class CharacterSetValidator implements StringValidator {
78
86
  * Character set map, mapping each character in the character set to its index such that
79
87
  * `_characterSetMap.get(_characterSet[index]) === index`.
80
88
  */
81
- private readonly _characterSetMap: Map<string, number>;
89
+ private readonly _characterSetMap: ReadonlyMap<string, number>;
82
90
 
83
91
  /**
84
92
  * Exclusions supported by the character set.
@@ -98,7 +106,13 @@ export class CharacterSetValidator implements StringValidator {
98
106
  constructor(characterSet: readonly string[], ...exclusionSupport: readonly Exclusion[]) {
99
107
  this._characterSet = characterSet;
100
108
 
101
- this._characterSetMap = new Map(characterSet.map((c, index) => [c, index]));
109
+ const characterSetMap = new Map<string, number>();
110
+
111
+ characterSet.forEach((c, index) => {
112
+ characterSetMap.set(c, index);
113
+ });
114
+
115
+ this._characterSetMap = characterSetMap;
102
116
 
103
117
  this._exclusionSupport = exclusionSupport;
104
118
  }
@@ -174,16 +188,14 @@ export class CharacterSetValidator implements StringValidator {
174
188
  * Component as a string or undefined.
175
189
  */
176
190
  private static componentToString(component: string | (() => string) | undefined): string | undefined {
177
- return component === undefined || typeof component === "string" ? component : component();
191
+ return typeof component === "function" ? component() : component;
178
192
  }
179
193
 
180
194
  /**
181
- * Validate that an exclusion is supported. If not, an exception is thrown.
195
+ * Validate that an exclusion is supported. If not, an error is thrown.
182
196
  *
183
197
  * @param exclusion
184
198
  * Exclusion.
185
- *
186
- * @throws RangeError
187
199
  */
188
200
  protected validateExclusion(exclusion: Exclusion): void {
189
201
  if (exclusion !== Exclusion.None && !this._exclusionSupport.includes(exclusion)) {
@@ -196,15 +208,13 @@ export class CharacterSetValidator implements StringValidator {
196
208
 
197
209
  /**
198
210
  * Validate a string. If the string violates the character set or any of the character set validation parameters, an
199
- * exception is thrown.
211
+ * error is thrown.
200
212
  *
201
213
  * @param s
202
214
  * String.
203
215
  *
204
216
  * @param validation
205
217
  * Character set validation parameters.
206
- *
207
- * @throws RangeError
208
218
  */
209
219
  validate(s: string, validation?: CharacterSetValidation): void {
210
220
  const length = s.length;
@@ -259,6 +269,9 @@ export class CharacterSetValidator implements StringValidator {
259
269
  this.validateExclusion(validation.exclusion);
260
270
 
261
271
  switch (validation.exclusion) {
272
+ case Exclusion.None:
273
+ break;
274
+
262
275
  case Exclusion.FirstZero:
263
276
  if (s.startsWith("0")) {
264
277
  throw new RangeError(i18next.t(validation.component === undefined ? "CharacterSetValidator.invalidCharacterAtPosition" : "CharacterSetValidator.invalidCharacterAtPositionOfComponent", {
@@ -353,12 +366,12 @@ export class CharacterSetCreator extends CharacterSetValidator {
353
366
  /**
354
367
  * Domains for every length for every supported {@link Exclusion}.
355
368
  */
356
- private readonly _exclusionDomains: ReadonlyArray<readonly bigint[] | undefined>;
369
+ private readonly _exclusionDomains: ReadonlyArray<readonly bigint[]>;
357
370
 
358
371
  /**
359
372
  * Values that would generate all zeros in the created string.
360
373
  */
361
- private readonly _allZerosValues: readonly bigint[] | undefined;
374
+ private readonly _allZerosValues: readonly bigint[];
362
375
 
363
376
  /**
364
377
  * Constructor.
@@ -376,12 +389,20 @@ export class CharacterSetCreator extends CharacterSetValidator {
376
389
  this._characterSetSizeN = BigInt(this.characterSetSize);
377
390
  this._characterSetSizeMinusOneN = BigInt(this.characterSetSize - 1);
378
391
 
392
+ const exclusionDomains: Array<readonly bigint[]> = [];
393
+
379
394
  const exclusionNoneDomains = CharacterSetCreator.createPowersOf(this.characterSetSize);
380
395
 
381
- let exclusionFirstZeroDomains: bigint[] | undefined;
396
+ exclusionDomains[Exclusion.None] = exclusionNoneDomains;
382
397
 
383
398
  if (exclusionSupport.includes(Exclusion.FirstZero)) {
384
- exclusionFirstZeroDomains = new Array<bigint>(CharacterSetCreator.MAXIMUM_STRING_LENGTH + 1);
399
+ if (characterSet[0] !== "0") {
400
+ throw new RangeError(i18next.t("CharacterSetValidator.firstZeroFirstCharacter", {
401
+ ns: utilityNS
402
+ }));
403
+ }
404
+
405
+ const exclusionFirstZeroDomains = new Array<bigint>(CharacterSetCreator.MAXIMUM_STRING_LENGTH + 1);
385
406
 
386
407
  // Exclusion of first zero mathematically prohibits length of 0.
387
408
  exclusionFirstZeroDomains[0] = 0n;
@@ -390,16 +411,30 @@ export class CharacterSetCreator extends CharacterSetValidator {
390
411
  // Domain excludes zero as the first character and so works with previous exclusion none domain.
391
412
  exclusionFirstZeroDomains[index] = this._characterSetSizeMinusOneN * exclusionNoneDomains[index - 1];
392
413
  }
393
- }
394
414
 
395
- let exclusionAllNumericDomains: bigint[] | undefined;
415
+ exclusionDomains[Exclusion.FirstZero] = exclusionFirstZeroDomains;
416
+ }
396
417
 
397
418
  if (exclusionSupport.includes(Exclusion.AllNumeric)) {
398
- exclusionAllNumericDomains = new Array<bigint>(CharacterSetCreator.MAXIMUM_STRING_LENGTH + 1);
419
+ const exclusionAllNumericDomains = new Array<bigint>(CharacterSetCreator.MAXIMUM_STRING_LENGTH + 1);
420
+
421
+ const numberIndexes = this.characterIndexes("0123456789");
422
+
423
+ let expectedNumberIndex = numberIndexes[0];
424
+
425
+ // Make sure that all numeric characters are present and in sequence.
426
+ for (const numberIndex of numberIndexes) {
427
+ if (numberIndex === undefined || numberIndex !== expectedNumberIndex) {
428
+ throw new RangeError(i18next.t("CharacterSetValidator.allNumericAllNumericCharacters", {
429
+ ns: utilityNS
430
+ }));
431
+ }
432
+
433
+ expectedNumberIndex = numberIndex + 1;
434
+ }
399
435
 
400
436
  // Zero index is the all-zero value for a single-character string.
401
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
402
- const zeroIndex = BigInt(this.characterIndex("0")!);
437
+ const zeroIndex = BigInt((numberIndexes as number[])[0]);
403
438
 
404
439
  const allZerosValues = new Array<bigint>(CharacterSetCreator.MAXIMUM_STRING_LENGTH + 1);
405
440
  let allZerosValue = 0n;
@@ -415,13 +450,14 @@ export class CharacterSetCreator extends CharacterSetValidator {
415
450
  }
416
451
 
417
452
  this._allZerosValues = allZerosValues;
453
+
454
+ exclusionDomains[Exclusion.AllNumeric] = exclusionAllNumericDomains;
455
+ } else {
456
+ // Empty array obviates need for non-null assertion while still forcing error if indexed due to a bug.
457
+ this._allZerosValues = [];
418
458
  }
419
459
 
420
- this._exclusionDomains = [
421
- exclusionNoneDomains,
422
- exclusionFirstZeroDomains,
423
- exclusionAllNumericDomains
424
- ];
460
+ this._exclusionDomains = exclusionDomains;
425
461
  }
426
462
 
427
463
  /**
@@ -434,8 +470,7 @@ export class CharacterSetCreator extends CharacterSetValidator {
434
470
  * `characterSetSize**power`.
435
471
  */
436
472
  private powerOfSize(power: number): bigint {
437
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
438
- return this._exclusionDomains[Exclusion.None]![power];
473
+ return this._exclusionDomains[Exclusion.None][power];
439
474
  }
440
475
 
441
476
  /**
@@ -452,8 +487,6 @@ export class CharacterSetCreator extends CharacterSetValidator {
452
487
  *
453
488
  * @returns
454
489
  * Shift required to skip all all-numeric strings.
455
- *
456
- * @throws RangeError
457
490
  */
458
491
  private allNumericShift(shiftForward: boolean, length: number, value: bigint): bigint {
459
492
  let shift: bigint;
@@ -491,14 +524,20 @@ export class CharacterSetCreator extends CharacterSetValidator {
491
524
  }
492
525
 
493
526
  /**
494
- * Validate that a length is less than or equal to {@link MAXIMUM_STRING_LENGTH}. If not, an exception is thrown.
527
+ * Validate that a length is less than or equal to {@link MAXIMUM_STRING_LENGTH}. If not, an error is thrown.
495
528
  *
496
529
  * @param length
497
530
  * Length.
498
- *
499
- * @throws RangeError
500
531
  */
501
532
  private validateLength(length: number): void {
533
+ if (length < 0) {
534
+ throw new RangeError(i18next.t("CharacterSetValidator.lengthMustBeGreaterThanOrEqualTo", {
535
+ ns: utilityNS,
536
+ length,
537
+ minimumLength: 0
538
+ }));
539
+ }
540
+
502
541
  if (length > CharacterSetCreator.MAXIMUM_STRING_LENGTH) {
503
542
  throw new RangeError(i18next.t("CharacterSetValidator.lengthMustBeLessThanOrEqualTo", {
504
543
  ns: utilityNS,
@@ -508,73 +547,6 @@ export class CharacterSetCreator extends CharacterSetValidator {
508
547
  }
509
548
  }
510
549
 
511
- /**
512
- * Do the work for the creation methods. Undocumented parameters are as defined in the public methods.
513
- *
514
- * @template T
515
- * Type defined by creation callback to do the work of creation (string or string[]).
516
- *
517
- * @param length
518
- * See public methods.
519
- *
520
- * @param exclusion
521
- * See public methods.
522
- *
523
- * @param tweak
524
- * See public methods.
525
- *
526
- * @param creationCallback
527
- * See public methods.
528
- *
529
- * @param createCallback
530
- * Callback to do the work of creation, whether for a single value or a sequence. Called with the appropriate
531
- * transformer and a transformation callback method to map individual transformed values to strings.
532
- *
533
- * @returns
534
- * Created string or iterable iterator over created strings.
535
- */
536
- private doCreate<T>(length: number, exclusion: Exclusion, tweak: number | bigint | undefined, creationCallback: CreationCallback | undefined, createCallback: (transformer: Transformer, transformationCallback: TransformationCallback<string>) => T): T {
537
- this.validateLength(length);
538
- this.validateExclusion(exclusion);
539
-
540
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
541
- const allZerosValue = exclusion === Exclusion.AllNumeric ? this._allZerosValues![length] : undefined;
542
-
543
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
544
- const transformer = Transformer.get(this._exclusionDomains[exclusion]![length], tweak);
545
-
546
- return createCallback(transformer, (transformedValue, index) => {
547
- let s = "";
548
-
549
- // Empty string is valid.
550
- if (length !== 0) {
551
- let convertValue = transformedValue;
552
-
553
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
554
- if (exclusion === Exclusion.AllNumeric && convertValue >= allZerosValue!) {
555
- // Value to convert is shifted by the number of all-numeric strings that occur at or prior to it.
556
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
557
- convertValue = convertValue + this.allNumericShift(true, length, convertValue - allZerosValue!);
558
- }
559
-
560
- // Build string from right to left excluding the first character.
561
- for (let position = length - 1; position > 0; position--) {
562
- const nextConvertValue = convertValue / this._characterSetSizeN;
563
-
564
- // First step is effectively a modulus calculation.
565
- s = this.character(Number(convertValue - nextConvertValue * this._characterSetSizeN)) + s;
566
-
567
- convertValue = nextConvertValue;
568
- }
569
-
570
- // Zero is first in the character set for those that support excluding first zero.
571
- s = this.character(exclusion === Exclusion.FirstZero ? Number(convertValue % this._characterSetSizeMinusOneN) + 1 : Number(convertValue % this._characterSetSizeN)) + s;
572
- }
573
-
574
- return creationCallback !== undefined ? creationCallback(s, index) : s;
575
- });
576
- }
577
-
578
550
  /**
579
551
  * Create a string by mapping a value to the equivalent characters in the character set across the length of the
580
552
  * string.
@@ -598,68 +570,89 @@ export class CharacterSetCreator extends CharacterSetValidator {
598
570
  * @returns
599
571
  * String created from the value.
600
572
  */
601
- create(length: number, value: number | bigint, exclusion: Exclusion = Exclusion.None, tweak?: number | bigint, creationCallback?: CreationCallback): string {
602
- return this.doCreate(length, exclusion, tweak, creationCallback, (transformer, transformationCallback) => transformer.forward(BigInt(value), transformationCallback));
603
- }
573
+ create(length: number, value: number | bigint, exclusion?: Exclusion, tweak?: number | bigint, creationCallback?: CreationCallback): string;
604
574
 
605
575
  /**
606
- * Create a sequence of strings by mapping each value to the equivalent characters in the character set across the
607
- * length of the string. Equivalent to calling {@link create} for `value = startValue + n` where `n` ranges from `0`
608
- * to `count - 1`.
609
- *
610
- * The implementation uses {@link Transformer.forwardSequence}, so the values are created only as needed.
576
+ * Create multiple strings by mapping each value to the equivalent characters in the character set across the length
577
+ * of the string. Equivalent to calling this method for each individual value.
611
578
  *
612
579
  * @param length
613
- * See {@link create}.
614
- *
615
- * @param startValue
616
- * Numeric value of the first string. Strings are created from `startValue` to `startValue + count - 1`.
580
+ * Required string length.
617
581
  *
618
- * @param count
619
- * The number of strings to create.
582
+ * @param values
583
+ * Numeric values of the strings.
620
584
  *
621
585
  * @param exclusion
622
- * See {@link create}.
586
+ * Strings to be excluded from the range of outputs. See {@link Exclusion} for possible values and their meaning.
623
587
  *
624
588
  * @param tweak
625
- * See {@link create}.
589
+ * If provided, the numerical value of the strings are "tweaked" using an {@link EncryptionTransformer | encryption
590
+ * transformer}.
626
591
  *
627
592
  * @param creationCallback
628
- * See {@link create}.
593
+ * If provided, called after each string is constructed to create the final value.
629
594
  *
630
595
  * @returns
631
- * Iterable iterator over created strings.
596
+ * Iterable iterator over strings created from the values.
632
597
  */
633
- createSequence(length: number, startValue: number | bigint, count: number, exclusion: Exclusion = Exclusion.None, tweak?: number | bigint, creationCallback?: CreationCallback): IterableIterator<string> {
634
- return this.doCreate(length, exclusion, tweak, creationCallback, (transformer, transformationCallback) => transformer.forwardSequence(BigInt(startValue), count, transformationCallback));
635
- }
598
+ create(length: number, values: Iterable<number | bigint>, exclusion?: Exclusion, tweak?: number | bigint, creationCallback?: CreationCallback): IterableIterator<string>;
636
599
 
637
600
  /**
638
- * Create multiple strings by mapping each value to the equivalent characters in the character set across the length
639
- * of the string. Equivalent to calling {@link create} for each value in the values source.
640
- *
641
- * The implementation uses {@link Transformer.forwardMultiple}, so the values are created only as needed.
601
+ * Create a string or multiple strings. This signature exists to allow similar overloaded methods in other classes
602
+ * to call this method correctly.
642
603
  *
643
604
  * @param length
644
- * See {@link create}.
645
605
  *
646
- * @param valuesSource
647
- * Source of values.
606
+ * @param valueOrValues
648
607
  *
649
608
  * @param exclusion
650
- * See {@link create}.
651
609
  *
652
610
  * @param tweak
653
- * See {@link create}.
654
611
  *
655
612
  * @param creationCallback
656
- * See {@link create}.
657
613
  *
658
614
  * @returns
659
- * Iterable iterator over created strings.
660
615
  */
661
- createMultiple(length: number, valuesSource: IterationSource<number | bigint>, exclusion: Exclusion = Exclusion.None, tweak?: number | bigint, creationCallback?: CreationCallback): IterableIterator<string> {
662
- return this.doCreate(length, exclusion, tweak, creationCallback, (transformer, transformationCallback) => transformer.forwardMultiple(IterationHelper.from(valuesSource).map(value => BigInt(value)), transformationCallback));
616
+ create(length: number, valueOrValues: number | bigint | Iterable<number | bigint>, exclusion?: Exclusion, tweak?: number | bigint, creationCallback?: CreationCallback): string | IterableIterator<string>;
617
+
618
+ // eslint-disable-next-line jsdoc/require-jsdoc -- Implementation of overloaded signatures.
619
+ create(length: number, valueOrValues: number | bigint | Iterable<number | bigint>, exclusion: Exclusion = Exclusion.None, tweak?: number | bigint, creationCallback?: CreationCallback): string | IterableIterator<string> {
620
+ this.validateLength(length);
621
+ this.validateExclusion(exclusion);
622
+
623
+ // Zero value obviates need for non-null assertion.
624
+ const allZerosValue = exclusion === Exclusion.AllNumeric ? this._allZerosValues[length] : 0n;
625
+
626
+ const transformer = Transformer.get(this._exclusionDomains[exclusion][length], tweak);
627
+
628
+ return transformer.forward(valueOrValues, (transformedValue, index) => {
629
+ let s = "";
630
+
631
+ // Empty string is valid.
632
+ if (length !== 0) {
633
+ let convertValue = transformedValue;
634
+
635
+ if (exclusion === Exclusion.AllNumeric && convertValue >= allZerosValue) {
636
+ // Value to convert is shifted by the number of all-numeric strings that occur at or prior to it.
637
+ convertValue = convertValue + this.allNumericShift(true, length, convertValue - allZerosValue);
638
+ }
639
+
640
+ // Build string from right to left excluding the first character.
641
+ for (let position = length - 1; position > 0; position--) {
642
+ const nextConvertValue = convertValue / this._characterSetSizeN;
643
+
644
+ // First step is effectively a modulus calculation.
645
+ s = this.character(Number(convertValue - nextConvertValue * this._characterSetSizeN)) + s;
646
+
647
+ convertValue = nextConvertValue;
648
+ }
649
+
650
+ // Zero is first in the character set for those that support excluding first zero.
651
+ s = this.character(exclusion === Exclusion.FirstZero ? Number(convertValue % this._characterSetSizeMinusOneN) + 1 : Number(convertValue % this._characterSetSizeN)) + s;
652
+ }
653
+
654
+ return creationCallback !== undefined ? creationCallback(s, index) : s;
655
+ });
663
656
  }
664
657
 
665
658
  /**
@@ -678,7 +671,7 @@ export class CharacterSetCreator extends CharacterSetValidator {
678
671
  * @returns
679
672
  * Numeric value of the string.
680
673
  */
681
- value(s: string, exclusion: Exclusion = Exclusion.None, tweak?: number | bigint): bigint {
674
+ valueFor(s: string, exclusion: Exclusion = Exclusion.None, tweak?: number | bigint): bigint {
682
675
  const length = s.length;
683
676
 
684
677
  this.validateLength(length);
@@ -717,8 +710,7 @@ export class CharacterSetCreator extends CharacterSetValidator {
717
710
  }, 0n);
718
711
 
719
712
  if (exclusion === Exclusion.AllNumeric) {
720
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
721
- const allZerosValue = this._allZerosValues![length];
713
+ const allZerosValue = this._allZerosValues[length];
722
714
 
723
715
  if (value >= allZerosValue) {
724
716
  // Call will ensure that string is not all-numeric.
@@ -726,8 +718,7 @@ export class CharacterSetCreator extends CharacterSetValidator {
726
718
  }
727
719
  }
728
720
 
729
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
730
- return Transformer.get(this._exclusionDomains[exclusion]![length], tweak).reverse(value);
721
+ return Transformer.get(this._exclusionDomains[exclusion][length], tweak).reverse(value);
731
722
  }
732
723
  }
733
724
 
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
- export * from "./iteration.js";
1
+ export * from "./sequencer.js";
2
2
  export * from "./transformer.js";
3
- export * from "./string.js";
3
+ export type * from "./string.js";
4
4
  export * from "./reg_exp.js";
5
5
  export * from "./record.js";
6
6
  export * from "./character_set.js";
@@ -2,15 +2,17 @@ export const localeStrings = {
2
2
  Transformer: {
3
3
  domainMustBeGreaterThanZero: "Domain {{domain}} must be greater than 0",
4
4
  tweakMustBeGreaterThanOrEqualToZero: "Tweak {{tweak}} must be greater than or equal to 0",
5
- valueMustBeGreaterThanOrEqualToZero: "Value {{startValue}} must be greater than or equal to 0",
6
- startValueMustBeGreaterThanOrEqualToZero: "Start value {{startValue}} must be greater than or equal to 0",
7
- valueMustBeLessThan: "Value {{endValue}} must be less than {{domain}}",
8
- endValueMustBeLessThan: "End value (start value + count - 1) {{endValue}} must be less than {{domain}}"
5
+ valueMustBeGreaterThanOrEqualToZero: "Value {{value}} must be greater than or equal to 0",
6
+ valueMustBeLessThan: "Value {{value}} must be less than {{domain}}",
7
+ minValueMustBeGreaterThanOrEqualToZero: "Minimum value {{minValue}} must be greater than or equal to 0",
8
+ maxValueMustBeLessThan: "Maximum value {{maxValue}} must be less than {{domain}}"
9
9
  },
10
10
  RegExpValidator: {
11
11
  stringDoesNotMatchPattern: "String {{s}} does not match pattern"
12
12
  },
13
13
  CharacterSetValidator: {
14
+ firstZeroFirstCharacter: "Character set must support zero as first character",
15
+ allNumericAllNumericCharacters: "Character set must support all numeric characters in sequence",
14
16
  stringMustNotBeAllNumeric: "String must not be all numeric",
15
17
  lengthMustBeGreaterThanOrEqualTo: "Length {{length}} must be greater than or equal to {{minimumLength}}",
16
18
  lengthMustBeLessThanOrEqualTo: "Length {{length}} must be less than or equal to {{maximumLength}}",
@@ -1,6 +1,12 @@
1
1
  import type { localeStrings } from "./en/locale_strings.js";
2
2
 
3
+ /**
4
+ * Internationalization module.
5
+ */
3
6
  declare module "i18next" {
7
+ /**
8
+ * Custom type options for this package.
9
+ */
4
10
  interface CustomTypeOptions {
5
11
  resources: {
6
12
  // Extract the type from the English locale strings object.
package/src/record.ts CHANGED
@@ -2,8 +2,8 @@ import i18next, { utilityNS } from "./locale/i18n.js";
2
2
  import type { StringValidator } from "./string.js";
3
3
 
4
4
  /**
5
- * Record validator. Validation is performed against a record with a string key type and throws an exception if the key
6
- * is not found.
5
+ * Record validator. Validation is performed against a record with a string key type and throws an error if the key is
6
+ * not found.
7
7
  */
8
8
  export class RecordValidator<T> implements StringValidator {
9
9
  /**
@@ -49,8 +49,6 @@ export class RecordValidator<T> implements StringValidator {
49
49
  *
50
50
  * @param key
51
51
  * Record key.
52
- *
53
- * @throws RangeError
54
52
  */
55
53
  validate(key: string): void {
56
54
  if (this.record[key] === undefined) {
package/src/reg_exp.ts CHANGED
@@ -50,6 +50,9 @@ export class RegExpValidator implements StringValidator {
50
50
  });
51
51
  }
52
52
 
53
+ /**
54
+ * @inheritDoc
55
+ */
53
56
  validate(s: string): void {
54
57
  if (!this._regExp.test(s)) {
55
58
  throw new RangeError(this.createErrorMessage(s));