@aidc-toolkit/gs1 0.9.20-beta → 1.0.22-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.
Files changed (131) hide show
  1. package/dist/character-set.d.ts +4 -4
  2. package/dist/character-set.d.ts.map +1 -1
  3. package/dist/character-set.js +7 -7
  4. package/dist/character-set.js.map +1 -1
  5. package/dist/gtin-creator.d.ts +68 -0
  6. package/dist/gtin-creator.d.ts.map +1 -0
  7. package/dist/gtin-creator.js +158 -0
  8. package/dist/gtin-creator.js.map +1 -0
  9. package/dist/gtin-validator.d.ts +202 -0
  10. package/dist/gtin-validator.d.ts.map +1 -0
  11. package/dist/gtin-validator.js +470 -0
  12. package/dist/gtin-validator.js.map +1 -0
  13. package/dist/identifier-creator.d.ts +72 -0
  14. package/dist/identifier-creator.d.ts.map +1 -0
  15. package/dist/identifier-creator.js +50 -0
  16. package/dist/identifier-creator.js.map +1 -0
  17. package/dist/identifier-type.d.ts +58 -0
  18. package/dist/identifier-type.d.ts.map +1 -0
  19. package/dist/identifier-type.js +54 -0
  20. package/dist/identifier-type.js.map +1 -0
  21. package/dist/identifier-validator.d.ts +174 -0
  22. package/dist/identifier-validator.d.ts.map +1 -0
  23. package/dist/identifier-validator.js +145 -0
  24. package/dist/identifier-validator.js.map +1 -0
  25. package/dist/index.d.ts +16 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +16 -1
  28. package/dist/index.js.map +1 -1
  29. package/dist/locale/en/locale-strings.d.ts +3 -3
  30. package/dist/locale/en/locale-strings.js +3 -3
  31. package/dist/locale/en/locale-strings.js.map +1 -1
  32. package/dist/locale/fr/locale-strings.d.ts +3 -3
  33. package/dist/locale/fr/locale-strings.js +3 -3
  34. package/dist/locale/fr/locale-strings.js.map +1 -1
  35. package/dist/non-gtin-numeric-identifier-creator.d.ts +30 -0
  36. package/dist/non-gtin-numeric-identifier-creator.d.ts.map +1 -0
  37. package/dist/non-gtin-numeric-identifier-creator.js +30 -0
  38. package/dist/non-gtin-numeric-identifier-creator.js.map +1 -0
  39. package/dist/non-gtin-numeric-identifier-validator.d.ts +41 -0
  40. package/dist/non-gtin-numeric-identifier-validator.d.ts.map +1 -0
  41. package/dist/non-gtin-numeric-identifier-validator.js +40 -0
  42. package/dist/non-gtin-numeric-identifier-validator.js.map +1 -0
  43. package/dist/non-numeric-identifier-creator.d.ts +55 -0
  44. package/dist/non-numeric-identifier-creator.d.ts.map +1 -0
  45. package/dist/non-numeric-identifier-creator.js +93 -0
  46. package/dist/non-numeric-identifier-creator.js.map +1 -0
  47. package/dist/non-numeric-identifier-validator.d.ts +78 -0
  48. package/dist/non-numeric-identifier-validator.d.ts.map +1 -0
  49. package/dist/non-numeric-identifier-validator.js +95 -0
  50. package/dist/non-numeric-identifier-validator.js.map +1 -0
  51. package/dist/numeric-identifier-creator.d.ts +121 -0
  52. package/dist/numeric-identifier-creator.d.ts.map +1 -0
  53. package/dist/numeric-identifier-creator.js +135 -0
  54. package/dist/numeric-identifier-creator.js.map +1 -0
  55. package/dist/numeric-identifier-validator.d.ts +76 -0
  56. package/dist/numeric-identifier-validator.d.ts.map +1 -0
  57. package/dist/numeric-identifier-validator.js +84 -0
  58. package/dist/numeric-identifier-validator.js.map +1 -0
  59. package/dist/prefix-manager.d.ts +224 -0
  60. package/dist/prefix-manager.d.ts.map +1 -0
  61. package/dist/prefix-manager.js +369 -0
  62. package/dist/prefix-manager.js.map +1 -0
  63. package/dist/prefix-provider.d.ts +27 -0
  64. package/dist/prefix-provider.d.ts.map +1 -0
  65. package/dist/prefix-provider.js +2 -0
  66. package/dist/prefix-provider.js.map +1 -0
  67. package/dist/prefix-type.d.ts +22 -0
  68. package/dist/prefix-type.d.ts.map +1 -0
  69. package/dist/prefix-type.js +18 -0
  70. package/dist/prefix-type.js.map +1 -0
  71. package/dist/prefix-validator.d.ts +58 -0
  72. package/dist/prefix-validator.d.ts.map +1 -0
  73. package/dist/prefix-validator.js +154 -0
  74. package/dist/prefix-validator.js.map +1 -0
  75. package/dist/serializable-numeric-identifier-creator.d.ts +86 -0
  76. package/dist/serializable-numeric-identifier-creator.d.ts.map +1 -0
  77. package/dist/serializable-numeric-identifier-creator.js +116 -0
  78. package/dist/serializable-numeric-identifier-creator.js.map +1 -0
  79. package/dist/serializable-numeric-identifier-validator.d.ts +79 -0
  80. package/dist/serializable-numeric-identifier-validator.d.ts.map +1 -0
  81. package/dist/serializable-numeric-identifier-validator.js +99 -0
  82. package/dist/serializable-numeric-identifier-validator.js.map +1 -0
  83. package/gs1.iml +4 -1
  84. package/package.json +2 -3
  85. package/src/character-set.ts +7 -7
  86. package/src/gtin-creator.ts +195 -0
  87. package/src/gtin-validator.ts +564 -0
  88. package/src/identifier-creator.ts +97 -0
  89. package/src/identifier-type.ts +69 -0
  90. package/src/identifier-validator.ts +235 -0
  91. package/src/index.ts +16 -1
  92. package/src/locale/en/locale-strings.ts +3 -3
  93. package/src/locale/fr/locale-strings.ts +3 -3
  94. package/src/non-gtin-numeric-identifier-creator.ts +33 -0
  95. package/src/non-gtin-numeric-identifier-validator.ts +54 -0
  96. package/src/non-numeric-identifier-creator.ts +111 -0
  97. package/src/non-numeric-identifier-validator.ts +128 -0
  98. package/src/numeric-identifier-creator.ts +200 -0
  99. package/src/numeric-identifier-validator.ts +128 -0
  100. package/src/prefix-manager.ts +446 -0
  101. package/src/prefix-provider.ts +31 -0
  102. package/src/prefix-type.ts +24 -0
  103. package/src/prefix-validator.ts +191 -0
  104. package/src/serializable-numeric-identifier-creator.ts +128 -0
  105. package/src/serializable-numeric-identifier-validator.ts +124 -0
  106. package/test/check.test.ts +0 -4
  107. package/test/creator.test.ts +30 -0
  108. package/test/gtin-creator.ts +239 -0
  109. package/test/gtin-validator.test.ts +149 -0
  110. package/test/identifier-creator.ts +84 -0
  111. package/test/identifier-validator.ts +8 -0
  112. package/test/non-gtin-numeric-identifier-creator.ts +98 -0
  113. package/test/non-gtin-numeric-identifier-validator.ts +6 -0
  114. package/test/non-numeric-identifier-validator.ts +24 -0
  115. package/test/numeric-identifier-creator.ts +132 -0
  116. package/test/numeric-identifier-validator.ts +23 -0
  117. package/test/prefix-manager.test.ts +112 -0
  118. package/test/serializable-numeric-identifier-creator.ts +56 -0
  119. package/test/serializable-numeric-identifier-validator.ts +24 -0
  120. package/test/setup.ts +4 -0
  121. package/test/sparse.test.ts +56 -0
  122. package/test/utility.ts +22 -0
  123. package/test/validator.test.ts +52 -0
  124. package/test/variable-measure-rcn.test.ts +201 -0
  125. package/vitest.config.ts +7 -0
  126. package/dist/idkey.d.ts +0 -1346
  127. package/dist/idkey.d.ts.map +0 -1
  128. package/dist/idkey.js +0 -2024
  129. package/dist/idkey.js.map +0 -1
  130. package/src/idkey.ts +0 -2532
  131. package/test/idkey.test.ts +0 -1247
@@ -0,0 +1,149 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import {
3
+ GTINLevels,
4
+ type GTINType,
5
+ GTINTypes,
6
+ GTINValidator,
7
+ IdentifierTypes,
8
+ LeaderTypes,
9
+ type PrefixType,
10
+ PrefixTypes
11
+ } from "../src";
12
+ import { validateNumericIdentifierValidator } from "./numeric-identifier-validator.js";
13
+
14
+ export function validateGTINValidator(validator: GTINValidator, isCreator: boolean, gtinType: GTINType): void {
15
+ let prefixType: PrefixType;
16
+
17
+ switch (gtinType) {
18
+ case GTINTypes.GTIN13:
19
+ prefixType = PrefixTypes.GS1CompanyPrefix;
20
+ break;
21
+
22
+ case GTINTypes.GTIN12:
23
+ prefixType = PrefixTypes.UPCCompanyPrefix;
24
+ break;
25
+
26
+ case GTINTypes.GTIN8:
27
+ prefixType = PrefixTypes.GS18Prefix;
28
+ break;
29
+
30
+ default:
31
+ throw new Error("Not supported");
32
+ }
33
+
34
+ validateNumericIdentifierValidator(validator, isCreator, IdentifierTypes.GTIN, prefixType, gtinType, LeaderTypes.IndicatorDigit);
35
+
36
+ expect(validator.gtinType).toBe(gtinType);
37
+ }
38
+
39
+ describe("GTIN validation and normalization", () => {
40
+ test("Validation", () => {
41
+ expect(() => {
42
+ GTINValidator.validateAny("9521873000122", GTINLevels.Any);
43
+ }).not.toThrow(RangeError);
44
+ expect(() => {
45
+ GTINValidator.validateAny("19521873000129", GTINLevels.Any);
46
+ }).not.toThrow(RangeError);
47
+ expect(() => {
48
+ GTINValidator.validateAny("9521873000160", GTINLevels.Any);
49
+ }).not.toThrow(RangeError);
50
+ expect(() => {
51
+ GTINValidator.validateAny("95216843", GTINLevels.Any);
52
+ }).not.toThrow(RangeError);
53
+ expect(() => {
54
+ GTINValidator.validateAny("95217800031", GTINLevels.Any);
55
+ }).toThrow("GTIN must be 13, 12, 8, or 14 digits long");
56
+ expect(() => {
57
+ GTINValidator.validateAny("614141773985", GTINLevels.Any);
58
+ }).not.toThrow(RangeError);
59
+ expect(() => {
60
+ GTINValidator.validateAny("614141773991", GTINLevels.Any);
61
+ }).toThrow("Invalid check digit");
62
+ expect(() => {
63
+ GTINValidator.validateAny("09867539", GTINLevels.Any);
64
+ }).not.toThrow(RangeError);
65
+ expect(() => {
66
+ GTINValidator.validateAny("09800037", GTINLevels.Any);
67
+ }).toThrow("Invalid zero-suppressed GTIN-12");
68
+ expect(() => {
69
+ GTINValidator.validateAny("9521873000122", GTINLevels.RetailConsumer);
70
+ }).not.toThrow(RangeError);
71
+ expect(() => {
72
+ GTINValidator.validateAny("19521873000129", GTINLevels.RetailConsumer);
73
+ }).toThrow("GTIN not supported at retail consumer trade item level");
74
+ expect(() => {
75
+ GTINValidator.validateAny("9521873000160", GTINLevels.RetailConsumer);
76
+ }).not.toThrow(RangeError);
77
+ expect(() => {
78
+ GTINValidator.validateAny("95216843", GTINLevels.RetailConsumer);
79
+ }).not.toThrow(RangeError);
80
+ expect(() => {
81
+ GTINValidator.validateAny("95217800031", GTINLevels.RetailConsumer);
82
+ }).toThrow("GTIN must be 13, 12, 8, or 14 digits long");
83
+ expect(() => {
84
+ GTINValidator.validateAny("614141773985", GTINLevels.RetailConsumer);
85
+ }).not.toThrow(RangeError);
86
+ expect(() => {
87
+ GTINValidator.validateAny("0614141773985", GTINLevels.RetailConsumer);
88
+ }).toThrow("GTIN-13 at retail consumer trade item level can't start with zero");
89
+ expect(() => {
90
+ GTINValidator.validateAny("614141773991", GTINLevels.RetailConsumer);
91
+ }).toThrow("Invalid check digit");
92
+ expect(() => {
93
+ GTINValidator.validateAny("09867539", GTINLevels.RetailConsumer);
94
+ }).not.toThrow(RangeError);
95
+ expect(() => {
96
+ GTINValidator.validateAny("09800037", GTINLevels.RetailConsumer);
97
+ }).toThrow("Invalid zero-suppressed GTIN-12");
98
+ expect(() => {
99
+ GTINValidator.validateAny("9521873000122", GTINLevels.OtherThanRetailConsumer);
100
+ }).not.toThrow(RangeError);
101
+ expect(() => {
102
+ GTINValidator.validateAny("19521873000129", GTINLevels.OtherThanRetailConsumer);
103
+ }).not.toThrow(RangeError);
104
+ expect(() => {
105
+ GTINValidator.validateAny("9521873000160", GTINLevels.OtherThanRetailConsumer);
106
+ }).not.toThrow(RangeError);
107
+ expect(() => {
108
+ GTINValidator.validateAny("95216843", GTINLevels.OtherThanRetailConsumer);
109
+ }).toThrow("GTIN not supported at other than retail consumer trade item level");
110
+ expect(() => {
111
+ GTINValidator.validateAny("95217800031", GTINLevels.OtherThanRetailConsumer);
112
+ }).toThrow("GTIN must be 13, 12, 8, or 14 digits long");
113
+ expect(() => {
114
+ GTINValidator.validateAny("614141773985", GTINLevels.OtherThanRetailConsumer);
115
+ }).not.toThrow(RangeError);
116
+ expect(() => {
117
+ GTINValidator.validateAny("614141773991", GTINLevels.OtherThanRetailConsumer);
118
+ }).toThrow("Invalid check digit");
119
+ expect(() => {
120
+ GTINValidator.validateAny("09867539", GTINLevels.OtherThanRetailConsumer);
121
+ }).toThrow("GTIN not supported at other than retail consumer trade item level");
122
+ expect(() => {
123
+ GTINValidator.validateAny("09800037", GTINLevels.OtherThanRetailConsumer);
124
+ }).toThrow("Invalid zero-suppressed GTIN-12");
125
+ });
126
+
127
+ test("Normalization", () => {
128
+ // GTIN-14.
129
+ expect(GTINValidator.normalize("09526543219996")).toBe("9526543219996");
130
+ expect(GTINValidator.normalize("00614141009992")).toBe("614141009992");
131
+ expect(() => GTINValidator.normalize("00000001234505")).toThrow("Invalid zero-suppressed GTIN-12 as GTIN-14");
132
+ expect(GTINValidator.normalize("00000095209999")).toBe("95209999");
133
+ expect(GTINValidator.normalize("49526543219994")).toBe("49526543219994");
134
+
135
+ // GTIN-13.
136
+ expect(GTINValidator.normalize("9526543219996")).toBe("9526543219996");
137
+ expect(GTINValidator.normalize("0614141009992")).toBe("614141009992");
138
+ expect(() => GTINValidator.normalize("0000001234505")).toThrow("Invalid zero-suppressed GTIN-12 as GTIN-13");
139
+ expect(GTINValidator.normalize("0000095209999")).toBe("95209999");
140
+
141
+ // GTIN-12.
142
+ expect(GTINValidator.normalize("614141009992")).toBe("614141009992");
143
+ expect(GTINValidator.normalize("01234505")).toBe("012000003455");
144
+ expect(() => GTINValidator.normalize("09800037")).toThrow("Invalid zero-suppressed GTIN-12");
145
+
146
+ // GTIN-8.
147
+ expect(GTINValidator.normalize("95209999")).toBe("95209999");
148
+ });
149
+ });
@@ -0,0 +1,84 @@
1
+ import { expect } from "vitest";
2
+ import {
3
+ ContentCharacterSets,
4
+ type GTINType,
5
+ GTINTypes,
6
+ IdentifierTypes,
7
+ LeaderTypes,
8
+ type PrefixManager,
9
+ PrefixTypes
10
+ } from "../src";
11
+ import { validateGTINValidator } from "./gtin-validator.test.js";
12
+ import { validateNonGTINNumericIdentifierValidator } from "./non-gtin-numeric-identifier-validator.js";
13
+ import { validateNonNumericIdentifierValidator } from "./non-numeric-identifier-validator.js";
14
+ import { validateSerializableNumericIdentifierValidator } from "./serializable-numeric-identifier-validator.js";
15
+
16
+ export function validateIdentifierCreators(prefixManager: PrefixManager): void {
17
+ let gtinType: GTINType;
18
+
19
+ switch (prefixManager.prefixType) {
20
+ case PrefixTypes.GS1CompanyPrefix:
21
+ expect(prefixManager.prefix).toBe(prefixManager.gs1CompanyPrefix);
22
+ gtinType = GTINTypes.GTIN13;
23
+ break;
24
+
25
+ case PrefixTypes.UPCCompanyPrefix:
26
+ expect(prefixManager.prefix).toBe(prefixManager.upcCompanyPrefix);
27
+ gtinType = GTINTypes.GTIN12;
28
+ break;
29
+
30
+ case PrefixTypes.GS18Prefix:
31
+ expect(prefixManager.prefix).toBe(prefixManager.gs18Prefix);
32
+ gtinType = GTINTypes.GTIN8;
33
+ break;
34
+ }
35
+
36
+ expect(prefixManager.gtinCreator).toBe(prefixManager.gtinCreator);
37
+
38
+ validateGTINValidator(prefixManager.gtinCreator, true, gtinType);
39
+
40
+ if (prefixManager.prefixType !== PrefixTypes.GS18Prefix) {
41
+ // Validate creator caching.
42
+ expect(prefixManager.glnCreator).toBe(prefixManager.glnCreator);
43
+ expect(prefixManager.ssccCreator).toBe(prefixManager.ssccCreator);
44
+ expect(prefixManager.graiCreator).toBe(prefixManager.graiCreator);
45
+ expect(prefixManager.giaiCreator).toBe(prefixManager.giaiCreator);
46
+ expect(prefixManager.gsrnCreator).toBe(prefixManager.gsrnCreator);
47
+ expect(prefixManager.gdtiCreator).toBe(prefixManager.gdtiCreator);
48
+ expect(prefixManager.gincCreator).toBe(prefixManager.gincCreator);
49
+ expect(prefixManager.gsinCreator).toBe(prefixManager.gsinCreator);
50
+ expect(prefixManager.gcnCreator).toBe(prefixManager.gcnCreator);
51
+ expect(prefixManager.cpidCreator).toBe(prefixManager.cpidCreator);
52
+ expect(prefixManager.gmnCreator).toBe(prefixManager.gmnCreator);
53
+
54
+ validateNonGTINNumericIdentifierValidator(prefixManager.glnCreator, true, IdentifierTypes.GLN, 13, LeaderTypes.None);
55
+ validateNonGTINNumericIdentifierValidator(prefixManager.ssccCreator, true, IdentifierTypes.SSCC, 18, LeaderTypes.ExtensionDigit);
56
+ validateSerializableNumericIdentifierValidator(prefixManager.graiCreator, true, IdentifierTypes.GRAI, 13, LeaderTypes.None, 16, ContentCharacterSets.AI82);
57
+ validateNonNumericIdentifierValidator(prefixManager.giaiCreator, true, IdentifierTypes.GIAI, 30, ContentCharacterSets.AI82, false);
58
+ validateNonGTINNumericIdentifierValidator(prefixManager.gsrnCreator, true, IdentifierTypes.GSRN, 18, LeaderTypes.None);
59
+ validateSerializableNumericIdentifierValidator(prefixManager.gdtiCreator, true, IdentifierTypes.GDTI, 13, LeaderTypes.None, 17, ContentCharacterSets.AI82);
60
+ validateNonNumericIdentifierValidator(prefixManager.gincCreator, true, IdentifierTypes.GINC, 30, ContentCharacterSets.AI82, false);
61
+ validateNonGTINNumericIdentifierValidator(prefixManager.gsinCreator, true, IdentifierTypes.GSIN, 17, LeaderTypes.None);
62
+ validateSerializableNumericIdentifierValidator(prefixManager.gcnCreator, true, IdentifierTypes.GCN, 13, LeaderTypes.None, 12, ContentCharacterSets.Numeric);
63
+ validateNonNumericIdentifierValidator(prefixManager.cpidCreator, true, IdentifierTypes.CPID, 30, ContentCharacterSets.AI39, false);
64
+ validateNonNumericIdentifierValidator(prefixManager.gmnCreator, true, IdentifierTypes.GMN, 25, ContentCharacterSets.AI82, true);
65
+ } else {
66
+ expect(() => prefixManager.glnCreator).toThrow("GLN not supported by GS1-8 Prefix");
67
+ expect(() => prefixManager.ssccCreator).toThrow("SSCC not supported by GS1-8 Prefix");
68
+ expect(() => prefixManager.graiCreator).toThrow("GRAI not supported by GS1-8 Prefix");
69
+ expect(() => prefixManager.giaiCreator).toThrow("GIAI not supported by GS1-8 Prefix");
70
+ expect(() => prefixManager.gsrnCreator).toThrow("GSRN not supported by GS1-8 Prefix");
71
+ expect(() => prefixManager.gdtiCreator).toThrow("GDTI not supported by GS1-8 Prefix");
72
+ expect(() => prefixManager.gincCreator).toThrow("GINC not supported by GS1-8 Prefix");
73
+ expect(() => prefixManager.gsinCreator).toThrow("GSIN not supported by GS1-8 Prefix");
74
+ expect(() => prefixManager.gcnCreator).toThrow("GCN not supported by GS1-8 Prefix");
75
+ expect(() => prefixManager.cpidCreator).toThrow("CPID not supported by GS1-8 Prefix");
76
+ expect(() => prefixManager.gmnCreator).toThrow("GMN not supported by GS1-8 Prefix");
77
+ }
78
+ }
79
+
80
+ export function testIdentifierCreatorCallback(callback?: () => void): void {
81
+ if (callback !== undefined) {
82
+ callback();
83
+ }
84
+ }
@@ -0,0 +1,8 @@
1
+ import { expect } from "vitest";
2
+ import type { IdentifierType, IdentifierValidator, PrefixType } from "../src";
3
+
4
+ export function validateIdentifierValidator(creator: IdentifierValidator, identifierType: IdentifierType, prefixType: PrefixType, length: number): void {
5
+ expect(creator.identifierType).toBe(identifierType);
6
+ expect(creator.prefixType).toBe(prefixType);
7
+ expect(creator.length).toBe(length);
8
+ }
@@ -0,0 +1,98 @@
1
+ import { Exclusions, Sequence } from "@aidc-toolkit/utility";
2
+ import { describe, expect, test } from "vitest";
3
+ import {
4
+ hasValidCheckCharacterPair,
5
+ type NonGTINNumericIdentifierCreator,
6
+ type NonNumericIdentifierCreator
7
+ } from "../src";
8
+ import { testNumericIdentifierCreator } from "./numeric-identifier-creator.js";
9
+
10
+ export function testNonGTINNumericIdentifierCreator(creator: NonGTINNumericIdentifierCreator, preTestCallback?: () => void, postTestCallback?: () => void): void {
11
+ testNumericIdentifierCreator(creator, preTestCallback, postTestCallback);
12
+ }
13
+
14
+ const TEST_REFERENCE_LENGTH = 2;
15
+
16
+ export function testNonNumericIdentifierCreator(creator: NonNumericIdentifierCreator): void {
17
+ describe(creator.identifierType, () => {
18
+ const prefix = creator.prefix;
19
+ const prefixLength = prefix.length;
20
+ const referenceLength = creator.length - prefixLength - 2 * Number(creator.requiresCheckCharacterPair);
21
+ const referenceCount = creator.referenceCreator.characterSetSize ** TEST_REFERENCE_LENGTH;
22
+ const referenceSubstringStart = prefixLength;
23
+ const referenceSubstringEnd = prefixLength + TEST_REFERENCE_LENGTH;
24
+
25
+ test("Straight", () => {
26
+ expect(creator.referenceLength).toBe(referenceLength);
27
+
28
+ let index = 0;
29
+
30
+ for (const identifier of creator.create(creator.referenceCreator.create(TEST_REFERENCE_LENGTH, new Sequence(0, referenceCount)))) {
31
+ expect(() => {
32
+ creator.validate(identifier);
33
+ }).not.toThrow(RangeError);
34
+
35
+ expect(Number(creator.referenceCreator.valueFor(identifier.substring(referenceSubstringStart, referenceSubstringEnd)))).toBe(index);
36
+
37
+ expect(identifier.length).toBeLessThanOrEqual(creator.length);
38
+ expect(identifier.substring(0, prefixLength)).toBe(prefix);
39
+ expect(!creator.requiresCheckCharacterPair || hasValidCheckCharacterPair(identifier)).toBe(true);
40
+
41
+ expect(identifier).toBe(creator.referenceCreator.create(TEST_REFERENCE_LENGTH, index, Exclusions.None, undefined, reference => creator.create(reference)));
42
+
43
+ index++;
44
+ }
45
+
46
+ expect(index).toBe(referenceCount);
47
+ });
48
+
49
+ test("Sparse", () => {
50
+ let sequential = true;
51
+
52
+ let index = 0;
53
+
54
+ for (const identifier of creator.create(creator.referenceCreator.create(TEST_REFERENCE_LENGTH, new Sequence(0, referenceCount), Exclusions.None, 123456n))) {
55
+ expect(() => {
56
+ creator.validate(identifier);
57
+ }).not.toThrow(RangeError);
58
+
59
+ expect(Number(creator.referenceCreator.valueFor(identifier.substring(referenceSubstringStart, referenceSubstringEnd), Exclusions.None, 123456n))).toBe(index);
60
+
61
+ sequential &&= Number(creator.referenceCreator.valueFor(identifier.substring(referenceSubstringStart, referenceSubstringEnd))) === index;
62
+
63
+ expect(identifier.length).toBeLessThanOrEqual(creator.length);
64
+ expect(identifier.substring(0, prefixLength)).toBe(prefix);
65
+ expect(!creator.requiresCheckCharacterPair || hasValidCheckCharacterPair(identifier)).toBe(true);
66
+
67
+ expect(identifier).toBe(creator.referenceCreator.create(TEST_REFERENCE_LENGTH, index, Exclusions.None, 123456n, reference => creator.create(reference)));
68
+
69
+ index++;
70
+ }
71
+
72
+ expect(sequential).toBe(false);
73
+ expect(index).toBe(referenceCount);
74
+ });
75
+
76
+ test("Position offset", () => {
77
+ expect(() => {
78
+ creator.validate(creator.create("ABC123"), {
79
+ positionOffset: 4
80
+ });
81
+ }).not.toThrow(RangeError);
82
+ });
83
+
84
+ test("Not all numeric", () => {
85
+ expect(() => {
86
+ creator.validate(creator.create("01234"), {
87
+ exclusion: Exclusions.AllNumeric
88
+ });
89
+ }).toThrow("Reference can't be all-numeric");
90
+
91
+ expect(() => {
92
+ creator.validate(creator.create("O1234"), {
93
+ exclusion: Exclusions.AllNumeric
94
+ });
95
+ }).not.toThrow(RangeError);
96
+ });
97
+ });
98
+ }
@@ -0,0 +1,6 @@
1
+ import { type IdentifierType, type LeaderType, type NonGTINNumericIdentifierValidator, PrefixTypes } from "../src";
2
+ import { validateNumericIdentifierValidator } from "./numeric-identifier-validator.js";
3
+
4
+ export function validateNonGTINNumericIdentifierValidator(validator: NonGTINNumericIdentifierValidator, isCreator: boolean, identifierType: IdentifierType, length: number, leaderType: LeaderType): void {
5
+ validateNumericIdentifierValidator(validator, isCreator, identifierType, PrefixTypes.GS1CompanyPrefix, length, leaderType);
6
+ }
@@ -0,0 +1,24 @@
1
+ import { expect } from "vitest";
2
+ import {
3
+ type ContentCharacterSet,
4
+ type IdentifierType,
5
+ type NonNumericIdentifierCreator,
6
+ type NonNumericIdentifierValidator,
7
+ PrefixTypes
8
+ } from "../src";
9
+ import { validateIdentifierValidator } from "./identifier-validator.js";
10
+ import { creatorFor } from "./utility.js";
11
+
12
+ export function validateNonNumericIdentifierValidator(validator: NonNumericIdentifierValidator, isCreator: boolean, identifierType: IdentifierType, length: number, referenceCharacterSet: ContentCharacterSet, requiresCheckCharacterPair: boolean): void {
13
+ validateIdentifierValidator(validator, identifierType, PrefixTypes.GS1CompanyPrefix, length);
14
+
15
+ const referenceCreator = creatorFor(referenceCharacterSet);
16
+
17
+ expect(validator.referenceCharacterSet).toBe(referenceCharacterSet);
18
+ expect(validator.referenceCreator).toBe(referenceCreator);
19
+ expect(validator.requiresCheckCharacterPair).toBe(requiresCheckCharacterPair);
20
+
21
+ if (isCreator) {
22
+ expect((validator as NonNumericIdentifierCreator).referenceCreator).toBe(referenceCreator);
23
+ }
24
+ }
@@ -0,0 +1,132 @@
1
+ import { CharacterSetCreator, Sequence } from "@aidc-toolkit/utility";
2
+ import { describe, expect, test } from "vitest";
3
+ import { hasValidCheckDigit, IdentifierTypes, LeaderTypes, type NumericIdentifierCreator } from "../src";
4
+ import { testIdentifierCreatorCallback } from "./identifier-creator.js";
5
+
6
+ export function testNumericIdentifierCreator(creator: NumericIdentifierCreator, preTestCallback?: () => void, postTestCallback?: () => void): void {
7
+ describe(creator.identifierType === IdentifierTypes.GTIN ? `${creator.identifierType}-${creator.length}` : creator.identifierType, () => {
8
+ testIdentifierCreatorCallback(preTestCallback);
9
+
10
+ const prefix = creator.prefix;
11
+ const prefixLength = prefix.length;
12
+ const hasExtensionDigit = creator.leaderType === LeaderTypes.ExtensionDigit;
13
+ const prefixSubstringStart = Number(hasExtensionDigit);
14
+ const prefixSubstringEnd = prefixSubstringStart + prefixLength;
15
+ const referenceLength = creator.length - prefixLength - 1;
16
+ const referenceCount = Number(CharacterSetCreator.powerOf10(referenceLength));
17
+ const referenceSubstringStart = prefixSubstringEnd;
18
+ const referenceSubstringEnd = referenceSubstringStart + referenceLength - prefixSubstringStart;
19
+
20
+ function validate(identifier: string, index: number, sparse: boolean): void {
21
+ expect(() => {
22
+ creator.validate(identifier);
23
+ }).not.toThrow(RangeError);
24
+ expect(identifier).toBe(creator.create(index, sparse));
25
+
26
+ expect(identifier.length).toBe(creator.length);
27
+ expect(identifier.substring(prefixSubstringStart, prefixSubstringEnd)).toBe(prefix);
28
+ expect(hasValidCheckDigit(identifier)).toBe(true);
29
+ }
30
+
31
+ test("Straight", {
32
+ // Test can take a long time.
33
+ timeout: 20 * 1000
34
+ }, () => {
35
+ expect(creator.referenceLength).toBe(referenceLength);
36
+ expect(creator.capacity).toBe(Number(CharacterSetCreator.powerOf10(referenceLength)));
37
+
38
+ const sequenceIterator = creator.create(new Sequence(0, referenceCount))[Symbol.iterator]();
39
+
40
+ let index = 0;
41
+
42
+ for (const identifier of creator.createAll()) {
43
+ validate(identifier, index, false);
44
+
45
+ expect(Number((hasExtensionDigit ? identifier.charAt(0) : "") + identifier.substring(referenceSubstringStart, referenceSubstringEnd))).toBe(index);
46
+ expect(sequenceIterator.next().value).toBe(identifier);
47
+
48
+ index++;
49
+ }
50
+
51
+ expect(index).toBe(referenceCount);
52
+ expect(sequenceIterator.next().value).toBeUndefined();
53
+
54
+ const randomValues = new Array<number>();
55
+ const identifiers = new Array<string>();
56
+
57
+ for (let i = 0; i < 1000; i++) {
58
+ const randomValue = Math.floor(Math.random() * creator.capacity);
59
+
60
+ randomValues.push(randomValue);
61
+ identifiers.push(creator.create(randomValue));
62
+ }
63
+
64
+ expect(Array.from(creator.create(randomValues))).toStrictEqual(identifiers);
65
+ });
66
+
67
+ test("Sparse", () => {
68
+ const sparseReferenceCount = Math.min(referenceCount, 1000);
69
+
70
+ // Reference count of 1 is neither sequential nor sparse so treat it as sparse.
71
+ let sequential = sparseReferenceCount !== 1;
72
+
73
+ const sequenceSet = new Set<string>();
74
+
75
+ let index = 0;
76
+
77
+ for (const identifier of creator.create(new Sequence(0, sparseReferenceCount), true)) {
78
+ validate(identifier, index, true);
79
+
80
+ sequential &&= Number((hasExtensionDigit ? identifier.charAt(0) : "") + identifier.substring(referenceSubstringStart, referenceSubstringEnd)) === index;
81
+
82
+ expect(sequenceSet.has(identifier)).toBe(false);
83
+ sequenceSet.add(identifier);
84
+
85
+ index++;
86
+ }
87
+
88
+ expect(sequential).toBe(false);
89
+ expect(index).toBe(sparseReferenceCount);
90
+
91
+ const randomValues = new Array<number>();
92
+ const identifiers = new Array<string>();
93
+
94
+ for (let i = 0; i < 1000; i++) {
95
+ const randomValue = Math.floor(Math.random() * creator.capacity);
96
+
97
+ randomValues.push(randomValue);
98
+ identifiers.push(creator.create(randomValue, true));
99
+ }
100
+
101
+ expect(Array.from(creator.create(randomValues, true))).toStrictEqual(identifiers);
102
+ });
103
+
104
+ test("Validation position", () => {
105
+ const identifier = creator.create(0);
106
+
107
+ const badIdentifier1 = `${identifier.substring(0, identifier.length - 2)}O${identifier.substring(identifier.length - 1)}`;
108
+
109
+ expect(badIdentifier1.length).toBe(creator.length);
110
+ expect(() => {
111
+ creator.validate(badIdentifier1);
112
+ }).toThrow(`Invalid character 'O' at position ${creator.length - 1}`);
113
+
114
+ const badIdentifier2 = `${identifier.substring(0, 2)}O${identifier.substring(3)}`;
115
+
116
+ expect(badIdentifier2.length).toBe(creator.length);
117
+ expect(() => {
118
+ creator.validate(badIdentifier2);
119
+ }).toThrow("Invalid character 'O' at position 3");
120
+ });
121
+
122
+ test("Position offset", () => {
123
+ expect(() => {
124
+ creator.validate(creator.create(0), {
125
+ positionOffset: 4
126
+ });
127
+ }).not.toThrow(RangeError);
128
+ });
129
+
130
+ testIdentifierCreatorCallback(postTestCallback);
131
+ });
132
+ }
@@ -0,0 +1,23 @@
1
+ import { NUMERIC_CREATOR } from "@aidc-toolkit/utility";
2
+ import { expect } from "vitest";
3
+ import {
4
+ ContentCharacterSets,
5
+ type IdentifierType,
6
+ type LeaderType,
7
+ type NumericIdentifierCreator,
8
+ type NumericIdentifierValidator,
9
+ type PrefixType
10
+ } from "../src";
11
+ import { validateIdentifierValidator } from "./identifier-validator.js";
12
+
13
+ export function validateNumericIdentifierValidator(validator: NumericIdentifierValidator, isCreator: boolean, identifierType: IdentifierType, prefixType: PrefixType, length: number, leaderType: LeaderType): void {
14
+ validateIdentifierValidator(validator, identifierType, prefixType, length);
15
+
16
+ expect(validator.leaderType).toBe(leaderType);
17
+ expect(validator.referenceCharacterSet).toBe(ContentCharacterSets.Numeric);
18
+ expect(validator.referenceCreator).toBe(NUMERIC_CREATOR);
19
+
20
+ if (isCreator) {
21
+ expect((validator as NumericIdentifierCreator).referenceCreator).toBe(NUMERIC_CREATOR);
22
+ }
23
+ }
@@ -0,0 +1,112 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { PrefixManager, PrefixTypes } from "../src";
3
+ import { validateIdentifierCreators } from "./identifier-creator.js";
4
+
5
+ describe("Prefix manager", () => {
6
+ let prefixManager: PrefixManager;
7
+
8
+ function validateGTINStartsWithPrefix(length: number): void {
9
+ expect(prefixManager.gtinCreator.length).toBe(length);
10
+
11
+ const gtin = prefixManager.gtinCreator.create(0);
12
+
13
+ expect(gtin.startsWith(prefixManager.prefix)).toBe(true);
14
+ expect(gtin.length).toBe(length);
15
+
16
+ const gtin14 = prefixManager.gtinCreator.createGTIN14("5", 0);
17
+
18
+ expect(gtin14.startsWith("5" + prefixManager.gs1CompanyPrefix)).toBe(true);
19
+ expect(gtin14.length).toBe(14);
20
+ }
21
+
22
+ function validateNonGTINStartsWithGS1CompanyPrefix(): void {
23
+ const gln = prefixManager.glnCreator.create(0);
24
+
25
+ expect(gln.startsWith(prefixManager.gs1CompanyPrefix)).toBe(true);
26
+ expect(gln.length).toBe(prefixManager.glnCreator.length);
27
+
28
+ const grai = prefixManager.graiCreator.createSerialized(0, "1234");
29
+
30
+ expect(grai.startsWith(prefixManager.gs1CompanyPrefix)).toBe(true);
31
+ expect(grai.length).toBe(prefixManager.graiCreator.length + 4);
32
+
33
+ const giai = prefixManager.giaiCreator.create("1234");
34
+
35
+ expect(giai.startsWith(prefixManager.gs1CompanyPrefix)).toBe(true);
36
+ expect(giai.length).toBe(prefixManager.gs1CompanyPrefix.length + 4);
37
+ }
38
+
39
+ test("Prefix equivalence", () => {
40
+ expect(PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "9521234")).toBe(PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "9521234"));
41
+
42
+ expect(PrefixManager.get(PrefixTypes.UPCCompanyPrefix, "614141")).toBe(PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "0614141"));
43
+
44
+ expect(PrefixManager.get(PrefixTypes.GS18Prefix, "952")).toBe(PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "00000952"));
45
+ });
46
+
47
+ test("GS1 Company Prefix 9521234", () => {
48
+ prefixManager = PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "9521234");
49
+
50
+ expect(prefixManager.prefixType).toBe(PrefixTypes.GS1CompanyPrefix);
51
+ expect(prefixManager.prefix).toBe("9521234");
52
+ expect(prefixManager.gs1CompanyPrefix).toBe(prefixManager.prefix);
53
+ expect(prefixManager.upcCompanyPrefix).toBeUndefined();
54
+ expect(prefixManager.gs18Prefix).toBeUndefined();
55
+
56
+ validateGTINStartsWithPrefix(13);
57
+ validateNonGTINStartsWithGS1CompanyPrefix();
58
+
59
+ validateIdentifierCreators(prefixManager);
60
+ });
61
+
62
+ test("U.P.C. Company Prefix 614141", () => {
63
+ prefixManager = PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "0614141");
64
+
65
+ expect(prefixManager.prefixType).toBe(PrefixTypes.UPCCompanyPrefix);
66
+ expect(prefixManager.prefix).toBe("614141");
67
+ expect(prefixManager.gs1CompanyPrefix).toBe("0" + prefixManager.prefix);
68
+ expect(prefixManager.upcCompanyPrefix).toBe(prefixManager.prefix);
69
+ expect(prefixManager.gs18Prefix).toBeUndefined();
70
+
71
+ validateGTINStartsWithPrefix(12);
72
+ validateNonGTINStartsWithGS1CompanyPrefix();
73
+
74
+ validateIdentifierCreators(prefixManager);
75
+ });
76
+
77
+ test("GS1-8 Prefix 952", () => {
78
+ prefixManager = PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "00000952");
79
+
80
+ expect(prefixManager.prefixType).toBe(PrefixTypes.GS18Prefix);
81
+ expect(prefixManager.prefix).toBe("952");
82
+ expect(prefixManager.gs1CompanyPrefix).toBe("00000" + prefixManager.prefix);
83
+ expect(prefixManager.upcCompanyPrefix).toBeUndefined();
84
+ expect(prefixManager.gs18Prefix).toBe(prefixManager.prefix);
85
+
86
+ validateGTINStartsWithPrefix(8);
87
+
88
+ validateIdentifierCreators(prefixManager);
89
+ });
90
+
91
+ test("Prefix validation", () => {
92
+ expect(() => PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "952")).toThrow("Length 3 of GS1 Company Prefix must be greater than or equal to 4");
93
+ expect(() => PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "9520")).not.toThrow(RangeError);
94
+ expect(() => PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "952123456789")).not.toThrow(RangeError);
95
+ expect(() => PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "9521234567890")).toThrow("Length 13 of GS1 Company Prefix must be less than or equal to 12");
96
+
97
+ expect(() => PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "952123A56789")).toThrow("Invalid character 'A' at position 7 of GS1 Company Prefix");
98
+
99
+ expect(() => PrefixManager.get(PrefixTypes.UPCCompanyPrefix, "61414")).toThrow("Length 5 of U.P.C. Company Prefix must be greater than or equal to 6");
100
+ expect(() => PrefixManager.get(PrefixTypes.UPCCompanyPrefix, "614141")).not.toThrow(RangeError);
101
+ expect(() => PrefixManager.get(PrefixTypes.UPCCompanyPrefix, "61414112345")).not.toThrow(RangeError);
102
+ expect(() => PrefixManager.get(PrefixTypes.UPCCompanyPrefix, "614141123456")).toThrow("Length 12 of U.P.C. Company Prefix must be less than or equal to 11");
103
+ expect(() => PrefixManager.get(PrefixTypes.UPCCompanyPrefix, "000614")).not.toThrow(RangeError);
104
+ expect(() => PrefixManager.get(PrefixTypes.UPCCompanyPrefix, "000061")).toThrow("U.P.C. Company Prefix can't start with \"0000\"");
105
+
106
+ expect(() => PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "00000952")).not.toThrow(RangeError);
107
+ expect(() => PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "000000952")).toThrow("GS1 Company Prefix can't start with \"000000\"");
108
+
109
+ expect(() => PrefixManager.get(PrefixTypes.GS18Prefix, "952")).not.toThrow(RangeError);
110
+ expect(() => PrefixManager.get(PrefixTypes.GS18Prefix, "0952")).toThrow("GS1-8 Prefix can't start with \"0\"");
111
+ });
112
+ });