@aidc-toolkit/gs1 0.9.20-beta → 0.9.21-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,128 @@
1
+ import { mapIterable, type TransformerInput, type TransformerOutput } from "@aidc-toolkit/utility";
2
+ import { Mixin } from "ts-mixer";
3
+ import type { IdentifierType } from "./identifier-type.js";
4
+ import type { ContentCharacterSet } from "./identifier-validator.js";
5
+ import { AbstractNumericIdentifierCreator } from "./numeric-identifier-creator.js";
6
+ import type { PrefixProvider } from "./prefix-provider";
7
+ import { SerializableNumericIdentifierValidator } from "./serializable-numeric-identifier-validator.js";
8
+
9
+ /**
10
+ * Serializable numeric identifier creator.
11
+ */
12
+ export class SerializableNumericIdentifierCreator extends Mixin(SerializableNumericIdentifierValidator, AbstractNumericIdentifierCreator) {
13
+ /**
14
+ * Constructor. Typically called internally by a prefix manager but may be called by other code with another prefix
15
+ * provider type.
16
+ *
17
+ * @param prefixProvider
18
+ * Prefix provider.
19
+ *
20
+ * @param identifierType
21
+ * Identifier type.
22
+ *
23
+ * @param length
24
+ * Length.
25
+ *
26
+ * @param serialComponentLength
27
+ * Serial component length.
28
+ *
29
+ * @param serialComponentCharacterSet
30
+ * Serial component character set.
31
+ */
32
+ constructor(prefixProvider: PrefixProvider, identifierType: IdentifierType, length: number, serialComponentLength: number, serialComponentCharacterSet: ContentCharacterSet) {
33
+ super(identifierType, length, serialComponentLength, serialComponentCharacterSet);
34
+
35
+ this.init(prefixProvider, prefixProvider.gs1CompanyPrefix);
36
+ }
37
+
38
+ /**
39
+ * Concatenate a validated base identifier with serial component(s).
40
+ *
41
+ * @template TTransformerInput
42
+ * Transformer input type.
43
+ *
44
+ * @param baseIdentifier
45
+ * Base identifier.
46
+ *
47
+ * @param serialComponentOrComponents
48
+ * Serial component(s).
49
+ *
50
+ * @returns
51
+ * Serialized identifier(s).
52
+ */
53
+ private concatenateValidated<TTransformerInput extends TransformerInput<string>>(baseIdentifier: string, serialComponentOrComponents: TTransformerInput): TransformerOutput<TTransformerInput, string> {
54
+ // TODO Refactor type when https://github.com/microsoft/TypeScript/pull/56941 released.
55
+ let result: string | Iterable<string>;
56
+
57
+ const serialComponentCreator = this.serialComponentCreator;
58
+ const serialComponentValidation = this.serialComponentValidation;
59
+
60
+ /**
61
+ * Validate a serial component and concatenate it to the base identifier.
62
+ *
63
+ * @param serialComponent
64
+ * Serial component.
65
+ *
66
+ * @returns
67
+ * Serialized identifier.
68
+ */
69
+ function validateAndConcatenate(serialComponent: string): string {
70
+ serialComponentCreator.validate(serialComponent, serialComponentValidation);
71
+
72
+ return baseIdentifier + serialComponent;
73
+ }
74
+
75
+ if (typeof serialComponentOrComponents !== "object") {
76
+ result = validateAndConcatenate(serialComponentOrComponents);
77
+ } else {
78
+ result = mapIterable(serialComponentOrComponents, validateAndConcatenate);
79
+ }
80
+
81
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Type determination is handled above.
82
+ return result as TransformerOutput<TTransformerInput, string>;
83
+ }
84
+
85
+ /**
86
+ * Create serialized identifier(s) with a reference based on a numeric value concatenated with serial component(s).
87
+ * The value is converted to a reference of the appropriate length using a numeric creator.
88
+ *
89
+ * @template TTransformerInput
90
+ * Transformer input type.
91
+ *
92
+ * @param value
93
+ * Numeric value of the reference.
94
+ *
95
+ * @param serialComponentOrComponents
96
+ * Serial component(s).
97
+ *
98
+ * @param sparse
99
+ * If true, the value is mapped to a sparse sequence resistant to discovery. Default is false.
100
+ *
101
+ * @returns
102
+ * Serialized identifiers.
103
+ */
104
+ createSerialized<TTransformerInput extends TransformerInput<string>>(value: number, serialComponentOrComponents: TTransformerInput, sparse?: boolean): TransformerOutput<TTransformerInput, string> {
105
+ return this.concatenateValidated(this.create(value, sparse), serialComponentOrComponents);
106
+ }
107
+
108
+ /**
109
+ * Concatenate a base identifier with serial component(s).
110
+ *
111
+ * @template TTransformerInput
112
+ * Transformer input type.
113
+ *
114
+ * @param baseIdentifier
115
+ * Base identifier.
116
+ *
117
+ * @param serialComponentOrComponents
118
+ * Serial component(s).
119
+ *
120
+ * @returns
121
+ * Serialized identifier(s).
122
+ */
123
+ concatenate<TTransformerInput extends TransformerInput<string>>(baseIdentifier: string, serialComponentOrComponents: TTransformerInput): TransformerOutput<TTransformerInput, string> {
124
+ this.validate(baseIdentifier);
125
+
126
+ return this.concatenateValidated(baseIdentifier, serialComponentOrComponents);
127
+ }
128
+ }
@@ -0,0 +1,124 @@
1
+ import type { CharacterSetCreator, CharacterSetValidation } from "@aidc-toolkit/utility";
2
+ import { type IdentifierType, IdentifierTypes } from "./identifier-type.js";
3
+ import { type ContentCharacterSet, ContentCharacterSets, type IdentifierValidation } from "./identifier-validator.js";
4
+ import { i18nextGS1 } from "./locale/i18n.js";
5
+ import {
6
+ type NonGTINNumericIdentifierType,
7
+ NonGTINNumericIdentifierValidator
8
+ } from "./non-gtin-numeric-identifier-validator.js";
9
+ import { LeaderTypes } from "./numeric-identifier-validator.js";
10
+
11
+ /**
12
+ * Serializable numeric identifier type.
13
+ */
14
+ export type SerializableNumericIdentifierType = Exclude<NonGTINNumericIdentifierType, typeof IdentifierTypes.GLN | typeof IdentifierTypes.SSCC | typeof IdentifierTypes.GSRN | typeof IdentifierTypes.GSIN>;
15
+
16
+ /**
17
+ * Serializable numeric identifier validator. Validates both serialized and non-serialized forms of
18
+ * numeric identifiers that support serialization.
19
+ */
20
+ export class SerializableNumericIdentifierValidator extends NonGTINNumericIdentifierValidator {
21
+ /**
22
+ * Serial component length.
23
+ */
24
+ private readonly _serialComponentLength: number;
25
+
26
+ /**
27
+ * Serial component character set.
28
+ */
29
+ private readonly _serialComponentCharacterSet: ContentCharacterSet;
30
+
31
+ /**
32
+ * Serial component validation parameters.
33
+ */
34
+ private readonly _serialComponentValidation: CharacterSetValidation;
35
+
36
+ /**
37
+ * Serial component creator.
38
+ */
39
+ private readonly _serialComponentCreator: CharacterSetCreator;
40
+
41
+ /**
42
+ * Constructor.
43
+ *
44
+ * @param identifierType
45
+ * Identifier type.
46
+ *
47
+ * @param length
48
+ * Length.
49
+ *
50
+ * @param serialComponentLength
51
+ * Serial component length.
52
+ *
53
+ * @param serialComponentCharacterSet
54
+ * Serial component character set.
55
+ */
56
+ constructor(identifierType: IdentifierType, length: number, serialComponentLength: number, serialComponentCharacterSet: ContentCharacterSet) {
57
+ super(identifierType, length, LeaderTypes.None);
58
+
59
+ this._serialComponentLength = serialComponentLength;
60
+ this._serialComponentCharacterSet = serialComponentCharacterSet;
61
+
62
+ this._serialComponentValidation = {
63
+ minimumLength: 1,
64
+ maximumLength: serialComponentLength,
65
+ component: () => i18nextGS1.t("Identifier.serialComponent")
66
+ };
67
+
68
+ this._serialComponentCreator = SerializableNumericIdentifierValidator.creatorFor(serialComponentCharacterSet);
69
+ }
70
+
71
+ /**
72
+ * Get the serial component length.
73
+ */
74
+ get serialComponentLength(): number {
75
+ return this._serialComponentLength;
76
+ }
77
+
78
+ /**
79
+ * Get the serial component character set.
80
+ */
81
+ get serialComponentCharacterSet(): ContentCharacterSet {
82
+ return this._serialComponentCharacterSet;
83
+ }
84
+
85
+ /**
86
+ * Get the serial component validation parameters.
87
+ */
88
+ protected get serialComponentValidation(): CharacterSetValidation {
89
+ return this._serialComponentValidation;
90
+ }
91
+
92
+ /**
93
+ * Get the serial component creator.
94
+ */
95
+ get serialComponentCreator(): CharacterSetCreator {
96
+ return this._serialComponentCreator;
97
+ }
98
+
99
+ /**
100
+ * @inheritDoc
101
+ */
102
+ override validate(identifier: string, validation?: IdentifierValidation): void {
103
+ super.validate(identifier.substring(0, this.length), validation);
104
+
105
+ if (identifier.length > this.length) {
106
+ this.serialComponentCreator.validate(identifier.substring(this.length), this._serialComponentValidation);
107
+ }
108
+ }
109
+ }
110
+
111
+ /**
112
+ * GRAI validator.
113
+ */
114
+ export const GRAI_VALIDATOR = new SerializableNumericIdentifierValidator(IdentifierTypes.GRAI, 13, 16, ContentCharacterSets.AI82);
115
+
116
+ /**
117
+ * GDTI validator.
118
+ */
119
+ export const GDTI_VALIDATOR = new SerializableNumericIdentifierValidator(IdentifierTypes.GDTI, 13, 17, ContentCharacterSets.AI82);
120
+
121
+ /**
122
+ * GCN validator.
123
+ */
124
+ export const GCN_VALIDATOR = new SerializableNumericIdentifierValidator(IdentifierTypes.GCN, 13, 12, ContentCharacterSets.Numeric);
@@ -1,4 +1,3 @@
1
- import { I18nEnvironment } from "@aidc-toolkit/core";
2
1
  import { NUMERIC_CREATOR } from "@aidc-toolkit/utility";
3
2
  import { describe, expect, test } from "vitest";
4
3
  import {
@@ -7,13 +6,10 @@ import {
7
6
  checkDigitSum,
8
7
  hasValidCheckCharacterPair,
9
8
  hasValidCheckDigit,
10
- i18nGS1Init,
11
9
  isValidPriceOrWeightCheckDigit,
12
10
  priceOrWeightCheckDigit
13
11
  } from "../src";
14
12
 
15
- await i18nGS1Init(I18nEnvironment.CLI, true);
16
-
17
13
  describe("Check digit", () => {
18
14
  const testNumericString = "1234567890";
19
15
 
@@ -0,0 +1,30 @@
1
+ import { describe } from "vitest";
2
+ import { PrefixManager, PrefixTypes } from "../src";
3
+ import { testGTINCreator } from "./gtin-creator.js";
4
+ import {
5
+ testNonGTINNumericIdentifierCreator,
6
+ testNonNumericIdentifierCreator
7
+ } from "./non-gtin-numeric-identifier-creator.js";
8
+ import { testSerializableNumericIdentifierCreator } from "./serializable-numeric-identifier-creator.js";
9
+
10
+ describe("Creators", () => {
11
+ testGTINCreator(PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "952123456").gtinCreator);
12
+ testGTINCreator(PrefixManager.get(PrefixTypes.UPCCompanyPrefix, "61414112").gtinCreator);
13
+ testGTINCreator(PrefixManager.get(PrefixTypes.GS18Prefix, "9521").gtinCreator);
14
+
15
+ // Different lengths required to balance testing completeness and run time.
16
+ const shortPrefixManager = PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "952123456");
17
+ const longPrefixManager = PrefixManager.get(PrefixTypes.GS1CompanyPrefix, "952123456789");
18
+
19
+ testNonGTINNumericIdentifierCreator(shortPrefixManager.glnCreator);
20
+ testNonGTINNumericIdentifierCreator(longPrefixManager.ssccCreator);
21
+ testSerializableNumericIdentifierCreator(shortPrefixManager.graiCreator);
22
+ testNonNumericIdentifierCreator(shortPrefixManager.giaiCreator);
23
+ testNonGTINNumericIdentifierCreator(longPrefixManager.gsrnCreator);
24
+ testSerializableNumericIdentifierCreator(shortPrefixManager.gdtiCreator);
25
+ testNonNumericIdentifierCreator(shortPrefixManager.gincCreator);
26
+ testNonGTINNumericIdentifierCreator(longPrefixManager.gsinCreator);
27
+ testSerializableNumericIdentifierCreator(shortPrefixManager.gcnCreator);
28
+ testNonNumericIdentifierCreator(shortPrefixManager.cpidCreator);
29
+ testNonNumericIdentifierCreator(shortPrefixManager.gmnCreator);
30
+ });
@@ -0,0 +1,239 @@
1
+ import { CharacterSetCreator, Sequence } from "@aidc-toolkit/utility";
2
+ import { expect, test } from "vitest";
3
+ import { type GTINCreator, GTINTypes, GTINValidator, hasValidCheckDigit, PrefixTypes } from "../src";
4
+ import { testNumericIdentifierCreator } from "./numeric-identifier-creator.js";
5
+
6
+ export function testGTINCreator(creator: GTINCreator): void {
7
+ testNumericIdentifierCreator(creator, () => {
8
+ test("Length", () => {
9
+ switch (creator.prefixType) {
10
+ case PrefixTypes.GS1CompanyPrefix:
11
+ expect(creator.length).toBe(13);
12
+ break;
13
+
14
+ case PrefixTypes.UPCCompanyPrefix:
15
+ expect(creator.length).toBe(12);
16
+ break;
17
+
18
+ case PrefixTypes.GS18Prefix:
19
+ expect(creator.length).toBe(8);
20
+ break;
21
+ }
22
+ });
23
+ }, () => {
24
+ const gs1CompanyPrefix = creator.prefixProvider.gs1CompanyPrefix;
25
+ const prefix = creator.prefix;
26
+ const prefixLength = prefix.length;
27
+ const prefixSubstringStart = 14 - creator.length;
28
+ const prefixSubstringEnd = prefixSubstringStart + prefixLength;
29
+ const referenceLength = creator.length - prefixLength - 1;
30
+ const referenceCount = Number(CharacterSetCreator.powerOf10(referenceLength));
31
+ const referenceSubstringStart = prefixSubstringEnd;
32
+ const referenceSubstringEnd = referenceSubstringStart + referenceLength;
33
+
34
+ function validate(gtin: string, index: number, sparse: boolean): void {
35
+ expect(() => {
36
+ GTINValidator.validateGTIN14(gtin);
37
+ }).not.toThrow(RangeError);
38
+ expect(gtin).toBe(creator.createGTIN14("5", index, sparse));
39
+
40
+ expect(gtin.length).toBe(14);
41
+ expect(gtin.charAt(0)).toBe("5");
42
+ expect(gtin.substring(1, prefixSubstringEnd)).toBe(gs1CompanyPrefix);
43
+ expect(gtin.substring(prefixSubstringStart, prefixSubstringEnd)).toBe(prefix);
44
+ expect(hasValidCheckDigit(gtin)).toBe(true);
45
+ }
46
+
47
+ test("GTIN-14 straight", () => {
48
+ let index = 0;
49
+
50
+ for (const gtin of creator.createGTIN14("5", new Sequence(0, referenceCount))) {
51
+ expect(Number(gtin.substring(referenceSubstringStart, referenceSubstringEnd))).toBe(index);
52
+
53
+ validate(gtin, index, false);
54
+
55
+ index++;
56
+ }
57
+
58
+ expect(index).toBe(referenceCount);
59
+
60
+ const randomValues = new Array<number>();
61
+ const identifiers = new Array<string>();
62
+
63
+ for (let i = 0; i < 1000; i++) {
64
+ const randomValue = Math.floor(Math.random() * creator.capacity);
65
+
66
+ randomValues.push(randomValue);
67
+ identifiers.push(creator.createGTIN14("5", randomValue));
68
+ }
69
+
70
+ expect(Array.from(creator.createGTIN14("5", randomValues))).toStrictEqual(identifiers);
71
+ });
72
+
73
+ test("GTIN-14 sparse", () => {
74
+ const sparseReferenceCount = Math.min(referenceCount, 1000);
75
+
76
+ // Reference count of 1 is neither sequential nor sparse so treat it as sparse.
77
+ let sequential = sparseReferenceCount !== 1;
78
+
79
+ const sequenceSet = new Set<string>();
80
+
81
+ let index = 0;
82
+
83
+ for (const gtin of creator.createGTIN14("5", new Sequence(0, sparseReferenceCount), true)) {
84
+ sequential &&= Number(gtin.substring(referenceSubstringStart, referenceSubstringEnd)) === index;
85
+
86
+ validate(gtin, index, true);
87
+
88
+ expect(sequenceSet.has(gtin)).toBe(false);
89
+ sequenceSet.add(gtin);
90
+
91
+ index++;
92
+ }
93
+
94
+ expect(sequential).toBe(false);
95
+ expect(index).toBe(sparseReferenceCount);
96
+
97
+ const randomValues = new Array<number>();
98
+ const identifiers = new Array<string>();
99
+
100
+ for (let i = 0; i < 1000; i++) {
101
+ const randomValue = Math.floor(Math.random() * creator.capacity);
102
+
103
+ randomValues.push(randomValue);
104
+ identifiers.push(creator.createGTIN14("5", randomValue, true));
105
+ }
106
+
107
+ expect(Array.from(creator.createGTIN14("5", randomValues, true))).toStrictEqual(identifiers);
108
+ });
109
+
110
+ if (creator.gtinType === GTINTypes.GTIN12) {
111
+ test("Zero-suppress GTIN-12 rule 1", () => {
112
+ expect(GTINValidator.zeroSuppress("012345000058")).toBe("01234558");
113
+ expect(GTINValidator.zeroSuppress("012345000065")).toBe("01234565");
114
+ expect(GTINValidator.zeroSuppress("012345000072")).toBe("01234572");
115
+ expect(GTINValidator.zeroSuppress("012345000089")).toBe("01234589");
116
+ expect(GTINValidator.zeroSuppress("012345000096")).toBe("01234596");
117
+ });
118
+
119
+ test("Zero-suppress GTIN-12 rule 2", () => {
120
+ expect(GTINValidator.zeroSuppress("045670000080")).toBe("04567840");
121
+ });
122
+
123
+ test("Zero-suppress GTIN-12 rule 3", () => {
124
+ expect(GTINValidator.zeroSuppress("034000005673")).toBe("03456703");
125
+ expect(GTINValidator.zeroSuppress("034100005672")).toBe("03456712");
126
+ expect(GTINValidator.zeroSuppress("034200005671")).toBe("03456721");
127
+ });
128
+
129
+ test("Zero-suppress GTIN-12 rule 4", () => {
130
+ expect(GTINValidator.zeroSuppress("098300000752")).toBe("09837532");
131
+ expect(GTINValidator.zeroSuppress("098400000751")).toBe("09847531");
132
+ expect(GTINValidator.zeroSuppress("098500000750")).toBe("09857530");
133
+ expect(GTINValidator.zeroSuppress("098600000759")).toBe("09867539");
134
+ expect(GTINValidator.zeroSuppress("098700000758")).toBe("09877538");
135
+ expect(GTINValidator.zeroSuppress("098800000757")).toBe("09887537");
136
+ expect(GTINValidator.zeroSuppress("098900000756")).toBe("09897536");
137
+ });
138
+
139
+ test("Non-zero-suppressible GTIN-12 rule 1", () => {
140
+ expect(() => GTINValidator.zeroSuppress("012345100055")).toThrow("GTIN-12 not zero-suppressible");
141
+ expect(() => GTINValidator.zeroSuppress("012345010057")).toThrow("GTIN-12 not zero-suppressible");
142
+ expect(() => GTINValidator.zeroSuppress("012345001055")).toThrow("GTIN-12 not zero-suppressible");
143
+ expect(() => GTINValidator.zeroSuppress("012345000157")).toThrow("GTIN-12 not zero-suppressible");
144
+ expect(() => GTINValidator.zeroSuppress("012345000041")).toThrow("GTIN-12 not zero-suppressible");
145
+ expect(() => GTINValidator.zeroSuppress("012345000003")).toThrow("GTIN-12 not zero-suppressible");
146
+ });
147
+
148
+ test("Non-zero-suppressible GTIN-12 rule 2", () => {
149
+ expect(() => GTINValidator.zeroSuppress("045670100087")).toThrow("GTIN-12 not zero-suppressible");
150
+ expect(() => GTINValidator.zeroSuppress("045670010089")).toThrow("GTIN-12 not zero-suppressible");
151
+ expect(() => GTINValidator.zeroSuppress("045670001087")).toThrow("GTIN-12 not zero-suppressible");
152
+ expect(() => GTINValidator.zeroSuppress("045670000189")).toThrow("GTIN-12 not zero-suppressible");
153
+ });
154
+
155
+ test("Non-zero-suppressible GTIN-12 rule 3", () => {
156
+ expect(() => GTINValidator.zeroSuppress("034010005670")).toThrow("GTIN-12 not zero-suppressible");
157
+ expect(() => GTINValidator.zeroSuppress("034001005672")).toThrow("GTIN-12 not zero-suppressible");
158
+ expect(() => GTINValidator.zeroSuppress("034000105670")).toThrow("GTIN-12 not zero-suppressible");
159
+ expect(() => GTINValidator.zeroSuppress("034000015672")).toThrow("GTIN-12 not zero-suppressible");
160
+ });
161
+
162
+ test("Non-zero-suppressible GTIN-12 rule 4", () => {
163
+ expect(() => GTINValidator.zeroSuppress("098310000759")).toThrow("GTIN-12 not zero-suppressible");
164
+ expect(() => GTINValidator.zeroSuppress("098301000751")).toThrow("GTIN-12 not zero-suppressible");
165
+ expect(() => GTINValidator.zeroSuppress("098300100759")).toThrow("GTIN-12 not zero-suppressible");
166
+ expect(() => GTINValidator.zeroSuppress("098300010751")).toThrow("GTIN-12 not zero-suppressible");
167
+ expect(() => GTINValidator.zeroSuppress("098300001759")).toThrow("GTIN-12 not zero-suppressible");
168
+ });
169
+
170
+ test("Zero-suppress other error", () => {
171
+ expect(() => GTINValidator.zeroSuppress("0012345000059")).toThrow("GTIN must be 12 digits long");
172
+ expect(() => GTINValidator.zeroSuppress("012345000059")).toThrow("Invalid check digit");
173
+ expect(() => GTINValidator.zeroSuppress("112345000055")).toThrow("GTIN-12 not zero-suppressible");
174
+ });
175
+
176
+ test("Zero-expand GTIN-12 rule 1", () => {
177
+ expect(GTINValidator.zeroExpand("01234558")).toBe("012345000058");
178
+ expect(GTINValidator.zeroExpand("01234565")).toBe("012345000065");
179
+ expect(GTINValidator.zeroExpand("01234572")).toBe("012345000072");
180
+ expect(GTINValidator.zeroExpand("01234589")).toBe("012345000089");
181
+ expect(GTINValidator.zeroExpand("01234596")).toBe("012345000096");
182
+ expect(() => GTINValidator.zeroExpand("00000154")).toThrow("U.P.C. Company Prefix can't start with \"0000\"");
183
+ });
184
+
185
+ test("Zero-expand GTIN-12 rule 2", () => {
186
+ expect(GTINValidator.zeroExpand("04567840")).toBe("045670000080");
187
+ expect(() => GTINValidator.zeroExpand("00001047")).toThrow("U.P.C. Company Prefix can't start with \"0000\"");
188
+ });
189
+
190
+ test("Zero-expand GTIN-12 rule 3", () => {
191
+ expect(GTINValidator.zeroExpand("03456703")).toBe("034000005673");
192
+ expect(GTINValidator.zeroExpand("03456712")).toBe("034100005672");
193
+ expect(GTINValidator.zeroExpand("03456721")).toBe("034200005671");
194
+ expect(() => GTINValidator.zeroExpand("00000028")).not.toThrow(RangeError);
195
+ });
196
+
197
+ test("Zero-expand GTIN-12 rule 4", () => {
198
+ expect(GTINValidator.zeroExpand("09837532")).toBe("098300000752");
199
+ expect(GTINValidator.zeroExpand("09847531")).toBe("098400000751");
200
+ expect(GTINValidator.zeroExpand("09857530")).toBe("098500000750");
201
+ expect(GTINValidator.zeroExpand("09867539")).toBe("098600000759");
202
+ expect(GTINValidator.zeroExpand("09877538")).toBe("098700000758");
203
+ expect(GTINValidator.zeroExpand("09887537")).toBe("098800000757");
204
+ expect(GTINValidator.zeroExpand("09897536")).toBe("098900000756");
205
+ expect(() => GTINValidator.zeroExpand("00030037")).not.toThrow(RangeError);
206
+ });
207
+
208
+ test("Zero-expand error", () => {
209
+ expect(() => GTINValidator.zeroExpand("001234505")).toThrow("Length 9 must be less than or equal to 8");
210
+ expect(() => GTINValidator.zeroExpand("01234506")).toThrow("Invalid check digit");
211
+ expect(() => GTINValidator.zeroExpand("11234506")).toThrow("Invalid zero-suppressed GTIN-12");
212
+ expect(() => GTINValidator.zeroExpand("09800037")).toThrow("Invalid zero-suppressed GTIN-12");
213
+ expect(() => GTINValidator.zeroExpand("09800047")).toThrow("Invalid zero-suppressed GTIN-12");
214
+ expect(() => GTINValidator.zeroExpand("09800052")).toThrow("Invalid zero-suppressed GTIN-12");
215
+ });
216
+ }
217
+
218
+ test("GTIN-14", () => {
219
+ const gtin = creator.create(0, true);
220
+
221
+ expect(gtin.length).toBe(creator.length);
222
+
223
+ let gtin14 = GTINValidator.convertToGTIN14("0", gtin);
224
+
225
+ expect(gtin14.length).toBe(14);
226
+ expect(GTINValidator.normalize(gtin14)).toBe(gtin);
227
+
228
+ gtin14 = GTINValidator.convertToGTIN14("1", gtin);
229
+
230
+ expect(gtin14.length).toBe(14);
231
+ expect(GTINValidator.normalize(gtin14)).not.toBe(gtin);
232
+
233
+ gtin14 = GTINValidator.convertToGTIN14("2", gtin14);
234
+
235
+ expect(gtin14.length).toBe(14);
236
+ expect(GTINValidator.normalize(gtin14)).not.toBe(gtin);
237
+ });
238
+ });
239
+ }