@aidc-toolkit/utility 0.9.1 → 0.9.3
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.
- package/eslint.config.js +1 -16
- package/package.json +9 -13
- package/src/character_set.ts +65 -39
- package/src/locale/en/locale_strings.ts +2 -0
- package/src/locale/fr/locale_strings.ts +32 -0
- package/src/locale/i18n.ts +5 -1
- package/src/record.ts +2 -2
- package/src/string.ts +1 -1
- package/src/transformer.ts +1 -3
- package/test/character_set.test.ts +31 -8
- package/test/record.test.ts +0 -1
- package/test/reg_exp.test.ts +0 -1
- package/test/transformer.test.ts +1 -6
package/eslint.config.js
CHANGED
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
import tseslint from "typescript-eslint";
|
|
2
|
-
import js from "@eslint/js";
|
|
3
|
-
import stylistic from "@stylistic/eslint-plugin";
|
|
4
|
-
import jsdoc from "eslint-plugin-jsdoc";
|
|
5
|
-
import esLintConfigLove from "eslint-config-love";
|
|
6
1
|
import { esLintConfigAIDCToolkit } from "@aidc-toolkit/dev";
|
|
7
2
|
|
|
8
|
-
export default
|
|
9
|
-
{
|
|
10
|
-
ignores: ["eslint.config.js", "dist"]
|
|
11
|
-
},
|
|
12
|
-
js.configs.recommended,
|
|
13
|
-
...tseslint.configs.strictTypeChecked,
|
|
14
|
-
stylistic.configs["recommended-flat"],
|
|
15
|
-
jsdoc.configs["flat/recommended-typescript"],
|
|
16
|
-
esLintConfigLove,
|
|
17
|
-
esLintConfigAIDCToolkit
|
|
18
|
-
);
|
|
3
|
+
export default esLintConfigAIDCToolkit;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aidc-toolkit/utility",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "Foundational utilities for AIDC Toolkit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -21,23 +21,19 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"eslint": "eslint .",
|
|
23
23
|
"build": "tsup src/index.ts --clean --format cjs,esm --dts",
|
|
24
|
-
"build-
|
|
24
|
+
"build-doc": "npm run build && tsc src/index.ts --outDir dist --target esnext --moduleResolution nodenext --module nodenext --emitDeclarationOnly --declaration --declarationMap",
|
|
25
25
|
"test": "vitest run"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@aidc-toolkit/dev": "^0.9.
|
|
29
|
-
"
|
|
30
|
-
"@stylistic/eslint-plugin": "^2.8.0",
|
|
31
|
-
"eslint-config-love": "^71.0.0",
|
|
32
|
-
"eslint-plugin-jsdoc": "^50.3.0",
|
|
28
|
+
"@aidc-toolkit/dev": "^0.9.3",
|
|
29
|
+
"eslint": "^9.14.0",
|
|
33
30
|
"ts-node": "^10.9.2",
|
|
34
|
-
"tsup": "^8.3.
|
|
35
|
-
"typescript": "^5.6.
|
|
36
|
-
"
|
|
37
|
-
"vitest": "^2.1.1"
|
|
31
|
+
"tsup": "^8.3.5",
|
|
32
|
+
"typescript": "^5.6.3",
|
|
33
|
+
"vitest": "^2.1.5"
|
|
38
34
|
},
|
|
39
35
|
"dependencies": {
|
|
40
|
-
"@aidc-toolkit/core": "^0.9.
|
|
41
|
-
"i18next": "^23.
|
|
36
|
+
"@aidc-toolkit/core": "^0.9.3",
|
|
37
|
+
"i18next": "^23.16.5"
|
|
42
38
|
}
|
|
43
39
|
}
|
package/src/character_set.ts
CHANGED
|
@@ -28,29 +28,29 @@ export enum Exclusion {
|
|
|
28
28
|
*/
|
|
29
29
|
export interface CharacterSetValidation extends StringValidation {
|
|
30
30
|
/**
|
|
31
|
-
* Minimum length. If defined and the string is less than this length, an
|
|
31
|
+
* Minimum length. If defined and the string is less than this length, an error is thrown.
|
|
32
32
|
*/
|
|
33
33
|
minimumLength?: number | undefined;
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
* Maximum length. If defined and the string is greater than this length, an
|
|
36
|
+
* Maximum length. If defined and the string is greater than this length, an error is thrown.
|
|
37
37
|
*/
|
|
38
38
|
maximumLength?: number | undefined;
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* Exclusion from the string. If defined and the string is within the exclusion range, an
|
|
41
|
+
* Exclusion from the string. If defined and the string is within the exclusion range, an error is thrown.
|
|
42
42
|
*/
|
|
43
43
|
exclusion?: Exclusion | undefined;
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* Position offset within a larger string. Strings are sometimes composed of multiple substrings; this parameter
|
|
47
|
-
* ensures that the
|
|
47
|
+
* ensures that the error notes the proper position in the string.
|
|
48
48
|
*/
|
|
49
49
|
positionOffset?: number | undefined;
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* Name of component, typically but not exclusively within a larger string. This parameter ensure that the
|
|
53
|
-
*
|
|
53
|
+
* error notes the component that triggered it. Value may be a string or a callback that returns a string, the
|
|
54
54
|
* latter allowing for localization changes.
|
|
55
55
|
*/
|
|
56
56
|
component?: string | (() => string) | undefined;
|
|
@@ -86,7 +86,7 @@ export class CharacterSetValidator implements StringValidator<CharacterSetValida
|
|
|
86
86
|
* Character set map, mapping each character in the character set to its index such that
|
|
87
87
|
* `_characterSetMap.get(_characterSet[index]) === index`.
|
|
88
88
|
*/
|
|
89
|
-
private readonly _characterSetMap:
|
|
89
|
+
private readonly _characterSetMap: ReadonlyMap<string, number>;
|
|
90
90
|
|
|
91
91
|
/**
|
|
92
92
|
* Exclusions supported by the character set.
|
|
@@ -106,7 +106,13 @@ export class CharacterSetValidator implements StringValidator<CharacterSetValida
|
|
|
106
106
|
constructor(characterSet: readonly string[], ...exclusionSupport: readonly Exclusion[]) {
|
|
107
107
|
this._characterSet = characterSet;
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
const characterSetMap = new Map<string, number>();
|
|
110
|
+
|
|
111
|
+
characterSet.forEach((c, index) => {
|
|
112
|
+
characterSetMap.set(c, index);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
this._characterSetMap = characterSetMap;
|
|
110
116
|
|
|
111
117
|
this._exclusionSupport = exclusionSupport;
|
|
112
118
|
}
|
|
@@ -186,7 +192,7 @@ export class CharacterSetValidator implements StringValidator<CharacterSetValida
|
|
|
186
192
|
}
|
|
187
193
|
|
|
188
194
|
/**
|
|
189
|
-
* Validate that an exclusion is supported. If not, an
|
|
195
|
+
* Validate that an exclusion is supported. If not, an error is thrown.
|
|
190
196
|
*
|
|
191
197
|
* @param exclusion
|
|
192
198
|
* Exclusion.
|
|
@@ -202,7 +208,7 @@ export class CharacterSetValidator implements StringValidator<CharacterSetValida
|
|
|
202
208
|
|
|
203
209
|
/**
|
|
204
210
|
* Validate a string. If the string violates the character set or any of the character set validation parameters, an
|
|
205
|
-
*
|
|
211
|
+
* error is thrown.
|
|
206
212
|
*
|
|
207
213
|
* @param s
|
|
208
214
|
* String.
|
|
@@ -263,6 +269,9 @@ export class CharacterSetValidator implements StringValidator<CharacterSetValida
|
|
|
263
269
|
this.validateExclusion(validation.exclusion);
|
|
264
270
|
|
|
265
271
|
switch (validation.exclusion) {
|
|
272
|
+
case Exclusion.None:
|
|
273
|
+
break;
|
|
274
|
+
|
|
266
275
|
case Exclusion.FirstZero:
|
|
267
276
|
if (s.startsWith("0")) {
|
|
268
277
|
throw new RangeError(i18next.t(validation.component === undefined ? "CharacterSetValidator.invalidCharacterAtPosition" : "CharacterSetValidator.invalidCharacterAtPositionOfComponent", {
|
|
@@ -357,12 +366,12 @@ export class CharacterSetCreator extends CharacterSetValidator {
|
|
|
357
366
|
/**
|
|
358
367
|
* Domains for every length for every supported {@link Exclusion}.
|
|
359
368
|
*/
|
|
360
|
-
private readonly _exclusionDomains: ReadonlyArray<readonly bigint[]
|
|
369
|
+
private readonly _exclusionDomains: ReadonlyArray<readonly bigint[]>;
|
|
361
370
|
|
|
362
371
|
/**
|
|
363
372
|
* Values that would generate all zeros in the created string.
|
|
364
373
|
*/
|
|
365
|
-
private readonly _allZerosValues: readonly bigint[]
|
|
374
|
+
private readonly _allZerosValues: readonly bigint[];
|
|
366
375
|
|
|
367
376
|
/**
|
|
368
377
|
* Constructor.
|
|
@@ -380,12 +389,20 @@ export class CharacterSetCreator extends CharacterSetValidator {
|
|
|
380
389
|
this._characterSetSizeN = BigInt(this.characterSetSize);
|
|
381
390
|
this._characterSetSizeMinusOneN = BigInt(this.characterSetSize - 1);
|
|
382
391
|
|
|
392
|
+
const exclusionDomains: Array<readonly bigint[]> = [];
|
|
393
|
+
|
|
383
394
|
const exclusionNoneDomains = CharacterSetCreator.createPowersOf(this.characterSetSize);
|
|
384
395
|
|
|
385
|
-
|
|
396
|
+
exclusionDomains[Exclusion.None] = exclusionNoneDomains;
|
|
386
397
|
|
|
387
398
|
if (exclusionSupport.includes(Exclusion.FirstZero)) {
|
|
388
|
-
|
|
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);
|
|
389
406
|
|
|
390
407
|
// Exclusion of first zero mathematically prohibits length of 0.
|
|
391
408
|
exclusionFirstZeroDomains[0] = 0n;
|
|
@@ -394,16 +411,30 @@ export class CharacterSetCreator extends CharacterSetValidator {
|
|
|
394
411
|
// Domain excludes zero as the first character and so works with previous exclusion none domain.
|
|
395
412
|
exclusionFirstZeroDomains[index] = this._characterSetSizeMinusOneN * exclusionNoneDomains[index - 1];
|
|
396
413
|
}
|
|
397
|
-
}
|
|
398
414
|
|
|
399
|
-
|
|
415
|
+
exclusionDomains[Exclusion.FirstZero] = exclusionFirstZeroDomains;
|
|
416
|
+
}
|
|
400
417
|
|
|
401
418
|
if (exclusionSupport.includes(Exclusion.AllNumeric)) {
|
|
402
|
-
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
|
+
}
|
|
403
435
|
|
|
404
436
|
// Zero index is the all-zero value for a single-character string.
|
|
405
|
-
|
|
406
|
-
const zeroIndex = BigInt(this.characterIndex("0")!);
|
|
437
|
+
const zeroIndex = BigInt((numberIndexes as number[])[0]);
|
|
407
438
|
|
|
408
439
|
const allZerosValues = new Array<bigint>(CharacterSetCreator.MAXIMUM_STRING_LENGTH + 1);
|
|
409
440
|
let allZerosValue = 0n;
|
|
@@ -419,13 +450,14 @@ export class CharacterSetCreator extends CharacterSetValidator {
|
|
|
419
450
|
}
|
|
420
451
|
|
|
421
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 = [];
|
|
422
458
|
}
|
|
423
459
|
|
|
424
|
-
this._exclusionDomains =
|
|
425
|
-
exclusionNoneDomains,
|
|
426
|
-
exclusionFirstZeroDomains,
|
|
427
|
-
exclusionAllNumericDomains
|
|
428
|
-
];
|
|
460
|
+
this._exclusionDomains = exclusionDomains;
|
|
429
461
|
}
|
|
430
462
|
|
|
431
463
|
/**
|
|
@@ -438,8 +470,7 @@ export class CharacterSetCreator extends CharacterSetValidator {
|
|
|
438
470
|
* `characterSetSize**power`.
|
|
439
471
|
*/
|
|
440
472
|
private powerOfSize(power: number): bigint {
|
|
441
|
-
|
|
442
|
-
return this._exclusionDomains[Exclusion.None]![power];
|
|
473
|
+
return this._exclusionDomains[Exclusion.None][power];
|
|
443
474
|
}
|
|
444
475
|
|
|
445
476
|
/**
|
|
@@ -493,7 +524,7 @@ export class CharacterSetCreator extends CharacterSetValidator {
|
|
|
493
524
|
}
|
|
494
525
|
|
|
495
526
|
/**
|
|
496
|
-
* Validate that a length is less than or equal to {@link MAXIMUM_STRING_LENGTH}. If not, an
|
|
527
|
+
* Validate that a length is less than or equal to {@link MAXIMUM_STRING_LENGTH}. If not, an error is thrown.
|
|
497
528
|
*
|
|
498
529
|
* @param length
|
|
499
530
|
* Length.
|
|
@@ -584,16 +615,15 @@ export class CharacterSetCreator extends CharacterSetValidator {
|
|
|
584
615
|
*/
|
|
585
616
|
create(length: number, valueOrValues: number | bigint | Iterable<number | bigint>, exclusion?: Exclusion, tweak?: number | bigint, creationCallback?: CreationCallback): string | IterableIterator<string>;
|
|
586
617
|
|
|
587
|
-
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
618
|
+
// eslint-disable-next-line jsdoc/require-jsdoc -- Implementation of overloaded signatures.
|
|
588
619
|
create(length: number, valueOrValues: number | bigint | Iterable<number | bigint>, exclusion: Exclusion = Exclusion.None, tweak?: number | bigint, creationCallback?: CreationCallback): string | IterableIterator<string> {
|
|
589
620
|
this.validateLength(length);
|
|
590
621
|
this.validateExclusion(exclusion);
|
|
591
622
|
|
|
592
|
-
//
|
|
593
|
-
const allZerosValue = exclusion === Exclusion.AllNumeric ? this._allZerosValues
|
|
623
|
+
// Zero value obviates need for non-null assertion.
|
|
624
|
+
const allZerosValue = exclusion === Exclusion.AllNumeric ? this._allZerosValues[length] : 0n;
|
|
594
625
|
|
|
595
|
-
|
|
596
|
-
const transformer = Transformer.get(this._exclusionDomains[exclusion]![length], tweak);
|
|
626
|
+
const transformer = Transformer.get(this._exclusionDomains[exclusion][length], tweak);
|
|
597
627
|
|
|
598
628
|
return transformer.forward(valueOrValues, (transformedValue, index) => {
|
|
599
629
|
let s = "";
|
|
@@ -602,11 +632,9 @@ export class CharacterSetCreator extends CharacterSetValidator {
|
|
|
602
632
|
if (length !== 0) {
|
|
603
633
|
let convertValue = transformedValue;
|
|
604
634
|
|
|
605
|
-
|
|
606
|
-
if (exclusion === Exclusion.AllNumeric && convertValue >= allZerosValue!) {
|
|
635
|
+
if (exclusion === Exclusion.AllNumeric && convertValue >= allZerosValue) {
|
|
607
636
|
// Value to convert is shifted by the number of all-numeric strings that occur at or prior to it.
|
|
608
|
-
|
|
609
|
-
convertValue = convertValue + this.allNumericShift(true, length, convertValue - allZerosValue!);
|
|
637
|
+
convertValue = convertValue + this.allNumericShift(true, length, convertValue - allZerosValue);
|
|
610
638
|
}
|
|
611
639
|
|
|
612
640
|
// Build string from right to left excluding the first character.
|
|
@@ -682,8 +710,7 @@ export class CharacterSetCreator extends CharacterSetValidator {
|
|
|
682
710
|
}, 0n);
|
|
683
711
|
|
|
684
712
|
if (exclusion === Exclusion.AllNumeric) {
|
|
685
|
-
|
|
686
|
-
const allZerosValue = this._allZerosValues![length];
|
|
713
|
+
const allZerosValue = this._allZerosValues[length];
|
|
687
714
|
|
|
688
715
|
if (value >= allZerosValue) {
|
|
689
716
|
// Call will ensure that string is not all-numeric.
|
|
@@ -691,8 +718,7 @@ export class CharacterSetCreator extends CharacterSetValidator {
|
|
|
691
718
|
}
|
|
692
719
|
}
|
|
693
720
|
|
|
694
|
-
|
|
695
|
-
return Transformer.get(this._exclusionDomains[exclusion]![length], tweak).reverse(value);
|
|
721
|
+
return Transformer.get(this._exclusionDomains[exclusion][length], tweak).reverse(value);
|
|
696
722
|
}
|
|
697
723
|
}
|
|
698
724
|
|
|
@@ -11,6 +11,8 @@ export const localeStrings = {
|
|
|
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}}",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const localeStrings = {
|
|
2
|
+
Transformer: {
|
|
3
|
+
domainMustBeGreaterThanZero: "Le domaine {{domain}} doit être supérieur à 0",
|
|
4
|
+
tweakMustBeGreaterThanOrEqualToZero: "Le réglage {{tweak}} doit être supérieur ou égal à 0",
|
|
5
|
+
valueMustBeGreaterThanOrEqualToZero: "La valeur {{value}} doit être supérieure ou égale à 0",
|
|
6
|
+
valueMustBeLessThan: "La valeur {{value}} doit être inférieure à {{domain}}",
|
|
7
|
+
minValueMustBeGreaterThanOrEqualToZero: "La valeur minimale {{minValue}} doit être supérieure ou égale à 0",
|
|
8
|
+
maxValueMustBeLessThan: "La valeur maximale {{maxValue}} doit être inférieure à {{domain}}"
|
|
9
|
+
},
|
|
10
|
+
RegExpValidator: {
|
|
11
|
+
stringDoesNotMatchPattern: "La chaîne {{s}} ne correspond pas au modèle"
|
|
12
|
+
},
|
|
13
|
+
CharacterSetValidator: {
|
|
14
|
+
firstZeroFirstCharacter: "Le jeu de caractères doit prendre en charge zéro comme premier caractère",
|
|
15
|
+
allNumericAllNumericCharacters: "Le jeu de caractères doit prendre en charge tous les caractères numériques en séquence",
|
|
16
|
+
stringMustNotBeAllNumeric: "La chaîne ne doit pas être entièrement numérique",
|
|
17
|
+
lengthMustBeGreaterThanOrEqualTo: "La longueur {{length}} doit être supérieure ou égale à {{minimumLength}}",
|
|
18
|
+
lengthMustBeLessThanOrEqualTo: "La longueur {{length}} doit être inférieure ou égale à {{maximumLength}}",
|
|
19
|
+
lengthMustBeEqualTo: "La longueur {{length}} doit être égale à {{exactLength}}",
|
|
20
|
+
lengthOfComponentMustBeGreaterThanOrEqualTo: "La longueur {{length}} de {{component}} doit être supérieure ou égale à {{minimumLength}}",
|
|
21
|
+
lengthOfComponentMustBeLessThanOrEqualTo: "La longueur {{length}} de {{component}} doit être inférieure ou égale à {{maximumLength}}",
|
|
22
|
+
lengthOfComponentMustBeEqualTo: "La longueur {{length}} de {{component}} doit être égale à {{exactLength}}",
|
|
23
|
+
invalidCharacterAtPosition: "Caractère non valide '{{c}}' à la position {{position}}",
|
|
24
|
+
invalidCharacterAtPositionOfComponent: "Caractère non valide '{{c}}' à la position {{position}} de {{component}}",
|
|
25
|
+
exclusionNotSupported: "La valeur d'exclusion de {{exclusion}} n'est pas prise en charge",
|
|
26
|
+
invalidTweakWithAllNumericExclusion: "Le réglage ne doit pas être utilisé avec une exclusion entièrement numérique",
|
|
27
|
+
endSequenceValueMustBeLessThanOrEqualTo: "La valeur de la séquence de fin (valeur de la séquence de début + nombre - 1) doit être inférieure à {{domaine}}"
|
|
28
|
+
},
|
|
29
|
+
RecordValidator: {
|
|
30
|
+
typeNameKeyNotFound: "{{typeName}} \"{{key}}\" introuvable"
|
|
31
|
+
}
|
|
32
|
+
} as const;
|
package/src/locale/i18n.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { i18nAddResourceBundle, i18next } from "@aidc-toolkit/core";
|
|
1
|
+
import { i18nAddResourceBundle, i18nAssertValidResources, i18next } from "@aidc-toolkit/core";
|
|
2
2
|
import { localeStrings as enLocaleStrings } from "./en/locale_strings.js";
|
|
3
|
+
import { localeStrings as frLocaleStrings } from "./fr/locale_strings.js";
|
|
3
4
|
|
|
4
5
|
export const utilityNS = "aidct_utility";
|
|
5
6
|
|
|
7
|
+
i18nAssertValidResources(enLocaleStrings, "fr", frLocaleStrings);
|
|
8
|
+
|
|
6
9
|
i18nAddResourceBundle("en", utilityNS, enLocaleStrings);
|
|
10
|
+
i18nAddResourceBundle("fr", utilityNS, frLocaleStrings);
|
|
7
11
|
|
|
8
12
|
export default i18next;
|
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
|
|
6
|
-
*
|
|
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
|
/**
|
package/src/string.ts
CHANGED
|
@@ -10,7 +10,7 @@ export interface StringValidation {
|
|
|
10
10
|
*/
|
|
11
11
|
export interface StringValidator<V extends StringValidation = StringValidation> {
|
|
12
12
|
/**
|
|
13
|
-
* Validate a string and throw an
|
|
13
|
+
* Validate a string and throw an error if validation fails.
|
|
14
14
|
*
|
|
15
15
|
* @param s
|
|
16
16
|
* String.
|
package/src/transformer.ts
CHANGED
|
@@ -513,9 +513,7 @@ export class EncryptionTransformer extends Transformer {
|
|
|
513
513
|
* Value.
|
|
514
514
|
*/
|
|
515
515
|
private static bytesToValue(bytes: Uint8Array): bigint {
|
|
516
|
-
return bytes.reduce((accumulator, byte) =>
|
|
517
|
-
return accumulator << 8n | BigInt(byte);
|
|
518
|
-
}, 0n);
|
|
516
|
+
return bytes.reduce((accumulator, byte) => accumulator << 8n | BigInt(byte), 0n);
|
|
519
517
|
}
|
|
520
518
|
|
|
521
519
|
/**
|
|
@@ -2,16 +2,16 @@ import { I18NEnvironment, i18nInit } from "@aidc-toolkit/core";
|
|
|
2
2
|
import { describe, expect, test } from "vitest";
|
|
3
3
|
import {
|
|
4
4
|
ALPHABETIC_CREATOR,
|
|
5
|
-
ALPHANUMERIC_CREATOR,
|
|
5
|
+
ALPHANUMERIC_CREATOR,
|
|
6
6
|
CharacterSetCreator,
|
|
7
7
|
Exclusion,
|
|
8
8
|
HEXADECIMAL_CREATOR,
|
|
9
|
-
NUMERIC_CREATOR
|
|
9
|
+
NUMERIC_CREATOR,
|
|
10
|
+
Sequencer
|
|
10
11
|
} from "../src/index.js";
|
|
11
12
|
|
|
12
13
|
await i18nInit(I18NEnvironment.CLI, true);
|
|
13
14
|
|
|
14
|
-
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
15
15
|
function testCharacterSetCreator(name: string, characterSetCreator: CharacterSetCreator, characterSetSize: number, length: number, excludeFirstZero: boolean, excludeAllNumeric: boolean): void {
|
|
16
16
|
describe(name, () => {
|
|
17
17
|
test("Character set", () => {
|
|
@@ -45,7 +45,6 @@ function testCharacterSetCreator(name: string, characterSetCreator: CharacterSet
|
|
|
45
45
|
expect(characterSetCreator.exclusionSupport.includes(Exclusion.AllNumeric)).toBe(excludeAllNumeric);
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
49
48
|
function testCreate(exclusion: Exclusion): void {
|
|
50
49
|
let domain: number;
|
|
51
50
|
|
|
@@ -154,17 +153,41 @@ function testCharacterSetCreator(name: string, characterSetCreator: CharacterSet
|
|
|
154
153
|
test("Create sequence, exclude all numeric", () => {
|
|
155
154
|
testCreate(Exclusion.AllNumeric);
|
|
156
155
|
|
|
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
|
+
|
|
157
159
|
expect(() => characterSetCreator.valueFor("0000", Exclusion.AllNumeric)).toThrow("String must not be all numeric");
|
|
158
|
-
|
|
159
|
-
expect(() => characterSetCreator.valueFor("000" + characterSetCreator.character(characterSetCreator.characterIndex("9")! + 1), Exclusion.AllNumeric)).not.toThrow(RangeError);
|
|
160
|
+
expect(() => characterSetCreator.valueFor(`000${afterNine}`, Exclusion.AllNumeric)).not.toThrow(RangeError);
|
|
160
161
|
expect(() => characterSetCreator.valueFor("9999", Exclusion.AllNumeric)).toThrow("String must not be all numeric");
|
|
161
|
-
|
|
162
|
-
expect(() => characterSetCreator.valueFor("999" + characterSetCreator.character(characterSetCreator.characterIndex("9")! + 1), Exclusion.AllNumeric)).not.toThrow(RangeError);
|
|
162
|
+
expect(() => characterSetCreator.valueFor(`999${afterNine}`, Exclusion.AllNumeric)).not.toThrow(RangeError);
|
|
163
163
|
});
|
|
164
164
|
}
|
|
165
165
|
});
|
|
166
166
|
}
|
|
167
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
|
+
|
|
168
191
|
testCharacterSetCreator("Numeric", NUMERIC_CREATOR, 10, 4, true, false);
|
|
169
192
|
testCharacterSetCreator("Hexadecimal", HEXADECIMAL_CREATOR, 16, 4, true, true);
|
|
170
193
|
testCharacterSetCreator("Alphabetic", ALPHABETIC_CREATOR, 26, 3, false, false);
|
package/test/record.test.ts
CHANGED
package/test/reg_exp.test.ts
CHANGED
|
@@ -34,7 +34,6 @@ describe("Regular expression validator", () => {
|
|
|
34
34
|
test("Error message", () => {
|
|
35
35
|
expect(() => {
|
|
36
36
|
new class extends RegExpValidator {
|
|
37
|
-
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
38
37
|
protected override createErrorMessage(s: string): string {
|
|
39
38
|
return `Failed to validate "${s}"`;
|
|
40
39
|
}
|
package/test/transformer.test.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { I18NEnvironment, i18nInit } from "@aidc-toolkit/core";
|
|
2
2
|
import { describe, expect, test } from "vitest";
|
|
3
|
-
import {
|
|
3
|
+
import { EncryptionTransformer, IdentityTransformer, Sequencer, Transformer } from "../src/index.js";
|
|
4
4
|
|
|
5
5
|
await i18nInit(I18NEnvironment.CLI, true);
|
|
6
6
|
|
|
7
|
-
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
8
7
|
function testTransformer(domain: number, tweak?: number, callback?: (value: bigint, forwardValue: bigint) => void): void {
|
|
9
8
|
const transformer = Transformer.get(domain, tweak);
|
|
10
9
|
|
|
@@ -120,13 +119,9 @@ describe("Encryption", () => {
|
|
|
120
119
|
});
|
|
121
120
|
|
|
122
121
|
test("Byte boundary", () => {
|
|
123
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
124
122
|
expect((Transformer.get(256n, 1n) as EncryptionTransformer)["_domainBytes"]).toBe(1);
|
|
125
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
126
123
|
expect((Transformer.get(257n, 1n) as EncryptionTransformer)["_domainBytes"]).toBe(2);
|
|
127
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
128
124
|
expect((Transformer.get(65536n, 1n) as EncryptionTransformer)["_domainBytes"]).toBe(2);
|
|
129
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
130
125
|
expect((Transformer.get(65537n, 1n) as EncryptionTransformer)["_domainBytes"]).toBe(3);
|
|
131
126
|
|
|
132
127
|
testTransformer(256, 1);
|