@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.
- package/dist/character-set.d.ts +4 -4
- package/dist/character-set.d.ts.map +1 -1
- package/dist/character-set.js +7 -7
- package/dist/character-set.js.map +1 -1
- package/dist/gtin-creator.d.ts +68 -0
- package/dist/gtin-creator.d.ts.map +1 -0
- package/dist/gtin-creator.js +158 -0
- package/dist/gtin-creator.js.map +1 -0
- package/dist/gtin-validator.d.ts +202 -0
- package/dist/gtin-validator.d.ts.map +1 -0
- package/dist/gtin-validator.js +470 -0
- package/dist/gtin-validator.js.map +1 -0
- package/dist/identifier-creator.d.ts +72 -0
- package/dist/identifier-creator.d.ts.map +1 -0
- package/dist/identifier-creator.js +50 -0
- package/dist/identifier-creator.js.map +1 -0
- package/dist/identifier-type.d.ts +58 -0
- package/dist/identifier-type.d.ts.map +1 -0
- package/dist/identifier-type.js +54 -0
- package/dist/identifier-type.js.map +1 -0
- package/dist/identifier-validator.d.ts +174 -0
- package/dist/identifier-validator.d.ts.map +1 -0
- package/dist/identifier-validator.js +145 -0
- package/dist/identifier-validator.js.map +1 -0
- package/dist/index.d.ts +16 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/locale/en/locale-strings.d.ts +3 -3
- package/dist/locale/en/locale-strings.js +3 -3
- package/dist/locale/en/locale-strings.js.map +1 -1
- package/dist/locale/fr/locale-strings.d.ts +3 -3
- package/dist/locale/fr/locale-strings.js +3 -3
- package/dist/locale/fr/locale-strings.js.map +1 -1
- package/dist/non-gtin-numeric-identifier-creator.d.ts +30 -0
- package/dist/non-gtin-numeric-identifier-creator.d.ts.map +1 -0
- package/dist/non-gtin-numeric-identifier-creator.js +30 -0
- package/dist/non-gtin-numeric-identifier-creator.js.map +1 -0
- package/dist/non-gtin-numeric-identifier-validator.d.ts +41 -0
- package/dist/non-gtin-numeric-identifier-validator.d.ts.map +1 -0
- package/dist/non-gtin-numeric-identifier-validator.js +40 -0
- package/dist/non-gtin-numeric-identifier-validator.js.map +1 -0
- package/dist/non-numeric-identifier-creator.d.ts +55 -0
- package/dist/non-numeric-identifier-creator.d.ts.map +1 -0
- package/dist/non-numeric-identifier-creator.js +93 -0
- package/dist/non-numeric-identifier-creator.js.map +1 -0
- package/dist/non-numeric-identifier-validator.d.ts +78 -0
- package/dist/non-numeric-identifier-validator.d.ts.map +1 -0
- package/dist/non-numeric-identifier-validator.js +95 -0
- package/dist/non-numeric-identifier-validator.js.map +1 -0
- package/dist/numeric-identifier-creator.d.ts +121 -0
- package/dist/numeric-identifier-creator.d.ts.map +1 -0
- package/dist/numeric-identifier-creator.js +135 -0
- package/dist/numeric-identifier-creator.js.map +1 -0
- package/dist/numeric-identifier-validator.d.ts +76 -0
- package/dist/numeric-identifier-validator.d.ts.map +1 -0
- package/dist/numeric-identifier-validator.js +84 -0
- package/dist/numeric-identifier-validator.js.map +1 -0
- package/dist/prefix-manager.d.ts +224 -0
- package/dist/prefix-manager.d.ts.map +1 -0
- package/dist/prefix-manager.js +369 -0
- package/dist/prefix-manager.js.map +1 -0
- package/dist/prefix-provider.d.ts +27 -0
- package/dist/prefix-provider.d.ts.map +1 -0
- package/dist/prefix-provider.js +2 -0
- package/dist/prefix-provider.js.map +1 -0
- package/dist/prefix-type.d.ts +22 -0
- package/dist/prefix-type.d.ts.map +1 -0
- package/dist/prefix-type.js +18 -0
- package/dist/prefix-type.js.map +1 -0
- package/dist/prefix-validator.d.ts +58 -0
- package/dist/prefix-validator.d.ts.map +1 -0
- package/dist/prefix-validator.js +154 -0
- package/dist/prefix-validator.js.map +1 -0
- package/dist/serializable-numeric-identifier-creator.d.ts +86 -0
- package/dist/serializable-numeric-identifier-creator.d.ts.map +1 -0
- package/dist/serializable-numeric-identifier-creator.js +116 -0
- package/dist/serializable-numeric-identifier-creator.js.map +1 -0
- package/dist/serializable-numeric-identifier-validator.d.ts +79 -0
- package/dist/serializable-numeric-identifier-validator.d.ts.map +1 -0
- package/dist/serializable-numeric-identifier-validator.js +99 -0
- package/dist/serializable-numeric-identifier-validator.js.map +1 -0
- package/gs1.iml +4 -1
- package/package.json +2 -3
- package/src/character-set.ts +7 -7
- package/src/gtin-creator.ts +195 -0
- package/src/gtin-validator.ts +564 -0
- package/src/identifier-creator.ts +97 -0
- package/src/identifier-type.ts +69 -0
- package/src/identifier-validator.ts +235 -0
- package/src/index.ts +16 -1
- package/src/locale/en/locale-strings.ts +3 -3
- package/src/locale/fr/locale-strings.ts +3 -3
- package/src/non-gtin-numeric-identifier-creator.ts +33 -0
- package/src/non-gtin-numeric-identifier-validator.ts +54 -0
- package/src/non-numeric-identifier-creator.ts +111 -0
- package/src/non-numeric-identifier-validator.ts +128 -0
- package/src/numeric-identifier-creator.ts +200 -0
- package/src/numeric-identifier-validator.ts +128 -0
- package/src/prefix-manager.ts +446 -0
- package/src/prefix-provider.ts +31 -0
- package/src/prefix-type.ts +24 -0
- package/src/prefix-validator.ts +191 -0
- package/src/serializable-numeric-identifier-creator.ts +128 -0
- package/src/serializable-numeric-identifier-validator.ts +124 -0
- package/test/check.test.ts +0 -4
- package/test/creator.test.ts +30 -0
- package/test/gtin-creator.ts +239 -0
- package/test/gtin-validator.test.ts +149 -0
- package/test/identifier-creator.ts +84 -0
- package/test/identifier-validator.ts +8 -0
- package/test/non-gtin-numeric-identifier-creator.ts +98 -0
- package/test/non-gtin-numeric-identifier-validator.ts +6 -0
- package/test/non-numeric-identifier-validator.ts +24 -0
- package/test/numeric-identifier-creator.ts +132 -0
- package/test/numeric-identifier-validator.ts +23 -0
- package/test/prefix-manager.test.ts +112 -0
- package/test/serializable-numeric-identifier-creator.ts +56 -0
- package/test/serializable-numeric-identifier-validator.ts +24 -0
- package/test/setup.ts +4 -0
- package/test/sparse.test.ts +56 -0
- package/test/utility.ts +22 -0
- package/test/validator.test.ts +52 -0
- package/test/variable-measure-rcn.test.ts +201 -0
- package/vitest.config.ts +7 -0
- package/dist/idkey.d.ts +0 -1346
- package/dist/idkey.d.ts.map +0 -1
- package/dist/idkey.js +0 -2024
- package/dist/idkey.js.map +0 -1
- package/src/idkey.ts +0 -2532
- package/test/idkey.test.ts +0 -1247
package/src/idkey.ts
DELETED
|
@@ -1,2532 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CharacterSetCreator,
|
|
3
|
-
type CharacterSetValidation,
|
|
4
|
-
Exclusion,
|
|
5
|
-
mapIterable,
|
|
6
|
-
NUMERIC_CREATOR,
|
|
7
|
-
RegExpValidator,
|
|
8
|
-
type StringValidation,
|
|
9
|
-
type StringValidator,
|
|
10
|
-
type TransformerInput,
|
|
11
|
-
type TransformerOutput
|
|
12
|
-
} from "@aidc-toolkit/utility";
|
|
13
|
-
import { Mixin } from "ts-mixer";
|
|
14
|
-
import { AI39_CREATOR, AI82_CREATOR } from "./character-set.js";
|
|
15
|
-
import {
|
|
16
|
-
checkCharacterPair,
|
|
17
|
-
checkDigit,
|
|
18
|
-
checkDigitSum,
|
|
19
|
-
hasValidCheckCharacterPair,
|
|
20
|
-
hasValidCheckDigit,
|
|
21
|
-
isValidPriceOrWeightCheckDigit,
|
|
22
|
-
priceOrWeightCheckDigit
|
|
23
|
-
} from "./check.js";
|
|
24
|
-
import { i18nextGS1 } from "./locale/i18n.js";
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Identification key type.
|
|
28
|
-
*/
|
|
29
|
-
export enum IdentificationKeyType {
|
|
30
|
-
/**
|
|
31
|
-
* Global Trade Item Number.
|
|
32
|
-
*/
|
|
33
|
-
GTIN = "GTIN",
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Global Location Number.
|
|
37
|
-
*/
|
|
38
|
-
GLN = "GLN",
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Serial Shipping Container Code.
|
|
42
|
-
*/
|
|
43
|
-
SSCC = "SSCC",
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Global Returnable Asset Identifier.
|
|
47
|
-
*/
|
|
48
|
-
GRAI = "GRAI",
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Global Individual Asset Identifier.
|
|
52
|
-
*/
|
|
53
|
-
GIAI = "GIAI",
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Global Service Relation Number.
|
|
57
|
-
*/
|
|
58
|
-
GSRN = "GSRN",
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Global Document Type Identifier.
|
|
62
|
-
*/
|
|
63
|
-
GDTI = "GDTI",
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Global Identification Number for Consignment.
|
|
67
|
-
*/
|
|
68
|
-
GINC = "GINC",
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Global Shipment Identification Number.
|
|
72
|
-
*/
|
|
73
|
-
GSIN = "GSIN",
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Global Coupon Number.
|
|
77
|
-
*/
|
|
78
|
-
GCN = "GCN",
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Component/Part Identifier.
|
|
82
|
-
*/
|
|
83
|
-
CPID = "CPID",
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Global Model Number.
|
|
87
|
-
*/
|
|
88
|
-
GMN = "GMN"
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Prefix type.
|
|
93
|
-
*/
|
|
94
|
-
export enum PrefixType {
|
|
95
|
-
/**
|
|
96
|
-
* GS1 Company Prefix.
|
|
97
|
-
*/
|
|
98
|
-
GS1CompanyPrefix,
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* U.P.C. Company Prefix.
|
|
102
|
-
*/
|
|
103
|
-
UPCCompanyPrefix,
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* GS1-8 Prefix.
|
|
107
|
-
*/
|
|
108
|
-
GS18Prefix
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Character set supported by the reference portion of an identification key or the serial component of a numeric
|
|
113
|
-
* identification key.
|
|
114
|
-
*/
|
|
115
|
-
export enum ContentCharacterSet {
|
|
116
|
-
/**
|
|
117
|
-
* Numeric.
|
|
118
|
-
*/
|
|
119
|
-
Numeric,
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* GS1 AI encodable character set 82.
|
|
123
|
-
*/
|
|
124
|
-
AI82,
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* GS1 AI encodable character set 39.
|
|
128
|
-
*/
|
|
129
|
-
AI39
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Identification key validation parameters.
|
|
134
|
-
*/
|
|
135
|
-
export interface IdentificationKeyValidation extends StringValidation {
|
|
136
|
-
/**
|
|
137
|
-
* Position offset within a larger string. Strings are sometimes composed of multiple substrings; this parameter
|
|
138
|
-
* ensures that the error notes the proper position in the string.
|
|
139
|
-
*/
|
|
140
|
-
positionOffset?: number | undefined;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Identification key validator. Validates an identification key against its definition in section 3 of the {@link
|
|
145
|
-
* https://www.gs1.org/genspecs | GS1 General Specifications}.
|
|
146
|
-
*
|
|
147
|
-
* @template TIdentificationKeyValidation
|
|
148
|
-
* Identification key validation type.
|
|
149
|
-
*/
|
|
150
|
-
export interface IdentificationKeyValidator<TIdentificationKeyValidation extends IdentificationKeyValidation = IdentificationKeyValidation> extends StringValidator<TIdentificationKeyValidation> {
|
|
151
|
-
/**
|
|
152
|
-
* Get the identification key type. Per the GS1 General Specifications, the identification key type determines
|
|
153
|
-
* the remaining properties.
|
|
154
|
-
*/
|
|
155
|
-
get identificationKeyType(): IdentificationKeyType;
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Get the prefix type supported by the identification key type. For all identification key types except the GTIN,
|
|
159
|
-
* this is {@linkcode PrefixType.GS1CompanyPrefix}. For the GTIN, the prefix type determines the length.
|
|
160
|
-
*/
|
|
161
|
-
get prefixType(): PrefixType;
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Get the length. For numeric identification key types, the length is fixed; for alphanumeric identification key
|
|
165
|
-
* types, the length is the maximum.
|
|
166
|
-
*/
|
|
167
|
-
get length(): number;
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Get the reference character set.
|
|
171
|
-
*/
|
|
172
|
-
get referenceCharacterSet(): ContentCharacterSet;
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Get the reference creator.
|
|
176
|
-
*/
|
|
177
|
-
get referenceCreator(): CharacterSetCreator;
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Validate an identification key and throw an error if validation fails.
|
|
181
|
-
*
|
|
182
|
-
* @param identificationKey
|
|
183
|
-
* Identification key.
|
|
184
|
-
*
|
|
185
|
-
* @param validation
|
|
186
|
-
* Identification key validation parameters.
|
|
187
|
-
*/
|
|
188
|
-
validate: (identificationKey: string, validation?: TIdentificationKeyValidation) => void;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Abstract identification key validator. Implements common functionality for an identification key validator.
|
|
193
|
-
*/
|
|
194
|
-
abstract class AbstractIdentificationKeyValidator<TIdentificationKeyValidation extends IdentificationKeyValidation = IdentificationKeyValidation> implements IdentificationKeyValidator<TIdentificationKeyValidation> {
|
|
195
|
-
private static readonly CHARACTER_SET_CREATORS = [
|
|
196
|
-
NUMERIC_CREATOR, AI82_CREATOR, AI39_CREATOR
|
|
197
|
-
];
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Identification key type.
|
|
201
|
-
*/
|
|
202
|
-
private readonly _identificationKeyType: IdentificationKeyType;
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Prefix type.
|
|
206
|
-
*/
|
|
207
|
-
private readonly _prefixType: PrefixType;
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Length.
|
|
211
|
-
*/
|
|
212
|
-
private readonly _length: number;
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Reference character set.
|
|
216
|
-
*/
|
|
217
|
-
private readonly _referenceCharacterSet: ContentCharacterSet;
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Reference creator.
|
|
221
|
-
*/
|
|
222
|
-
private readonly _referenceCreator: CharacterSetCreator;
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Get the character set creator for a character set.
|
|
226
|
-
*
|
|
227
|
-
* @param characterSet
|
|
228
|
-
* Character set.
|
|
229
|
-
*
|
|
230
|
-
* @returns
|
|
231
|
-
* Character set creator.
|
|
232
|
-
*/
|
|
233
|
-
protected static creatorFor(characterSet: ContentCharacterSet): CharacterSetCreator {
|
|
234
|
-
return AbstractIdentificationKeyValidator.CHARACTER_SET_CREATORS[characterSet];
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Constructor.
|
|
239
|
-
*
|
|
240
|
-
* @param identificationKeyType
|
|
241
|
-
* Identification key type.
|
|
242
|
-
*
|
|
243
|
-
* @param prefixType
|
|
244
|
-
* Prefix type.
|
|
245
|
-
*
|
|
246
|
-
* @param length
|
|
247
|
-
* Length.
|
|
248
|
-
*
|
|
249
|
-
* @param referenceCharacterSet
|
|
250
|
-
* Reference character set.
|
|
251
|
-
*/
|
|
252
|
-
protected constructor(identificationKeyType: IdentificationKeyType, prefixType: PrefixType, length: number, referenceCharacterSet: ContentCharacterSet) {
|
|
253
|
-
this._identificationKeyType = identificationKeyType;
|
|
254
|
-
this._prefixType = prefixType;
|
|
255
|
-
this._length = length;
|
|
256
|
-
this._referenceCharacterSet = referenceCharacterSet;
|
|
257
|
-
this._referenceCreator = AbstractIdentificationKeyValidator.creatorFor(referenceCharacterSet);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* @inheritDoc
|
|
262
|
-
*/
|
|
263
|
-
get identificationKeyType(): IdentificationKeyType {
|
|
264
|
-
return this._identificationKeyType;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* @inheritDoc
|
|
269
|
-
*/
|
|
270
|
-
get prefixType(): PrefixType {
|
|
271
|
-
return this._prefixType;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* @inheritDoc
|
|
276
|
-
*/
|
|
277
|
-
get length(): number {
|
|
278
|
-
return this._length;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* @inheritDoc
|
|
283
|
-
*/
|
|
284
|
-
get referenceCharacterSet(): ContentCharacterSet {
|
|
285
|
-
return this._referenceCharacterSet;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* @inheritDoc
|
|
290
|
-
*/
|
|
291
|
-
get referenceCreator(): CharacterSetCreator {
|
|
292
|
-
return this._referenceCreator;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Pad an identification key on the left with zero-value character for validation purposes. This is done to align an
|
|
297
|
-
* identification key with a position offset for any error message that may be thrown by the reference validator.
|
|
298
|
-
*
|
|
299
|
-
* @param identificationKey
|
|
300
|
-
* Identification key.
|
|
301
|
-
*
|
|
302
|
-
* @param validation
|
|
303
|
-
* Identification key validation parameters.
|
|
304
|
-
*
|
|
305
|
-
* @returns
|
|
306
|
-
* Padded identification key.
|
|
307
|
-
*/
|
|
308
|
-
protected padIdentificationKey(identificationKey: string, validation: IdentificationKeyValidation | undefined): string {
|
|
309
|
-
// Identification key is returned as is if position offset is undefined.
|
|
310
|
-
return validation?.positionOffset === undefined ? identificationKey : this.referenceCreator.character(0).repeat(validation.positionOffset).concat(identificationKey);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* Validate the prefix within an identification key.
|
|
315
|
-
*
|
|
316
|
-
* @param partialIdentificationKey
|
|
317
|
-
* Partial identification key.
|
|
318
|
-
*
|
|
319
|
-
* @param positionOffset
|
|
320
|
-
* Position offset within a larger string.
|
|
321
|
-
*/
|
|
322
|
-
protected validatePrefix(partialIdentificationKey: string, positionOffset?: number): void {
|
|
323
|
-
// Delegate to prefix manager with support for U.P.C. Company Prefix but not GS1-8 Prefix.
|
|
324
|
-
PrefixManager.validatePrefix(this.prefixType, true, false, partialIdentificationKey, true, this.referenceCharacterSet === ContentCharacterSet.Numeric, positionOffset);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
abstract validate(identificationKey: string, validation?: TIdentificationKeyValidation): void;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Leader type.
|
|
332
|
-
*/
|
|
333
|
-
export enum LeaderType {
|
|
334
|
-
/**
|
|
335
|
-
* No leader.
|
|
336
|
-
*/
|
|
337
|
-
None,
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* Indicator digit (GTIN only).
|
|
341
|
-
*/
|
|
342
|
-
IndicatorDigit,
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Extension digit (SSCC only).
|
|
346
|
-
*/
|
|
347
|
-
ExtensionDigit
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Numeric identification key validator. Validates a numeric identification key.
|
|
352
|
-
*/
|
|
353
|
-
export interface NumericIdentificationKeyValidator extends IdentificationKeyValidator {
|
|
354
|
-
/**
|
|
355
|
-
* Get the leader type.
|
|
356
|
-
*/
|
|
357
|
-
get leaderType(): LeaderType;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Abstract numeric identification key validator. Implements common functionality for a numeric identification key
|
|
362
|
-
* validator.
|
|
363
|
-
*/
|
|
364
|
-
abstract class AbstractNumericIdentificationKeyValidator extends AbstractIdentificationKeyValidator implements NumericIdentificationKeyValidator {
|
|
365
|
-
/**
|
|
366
|
-
* Leader type.
|
|
367
|
-
*/
|
|
368
|
-
private readonly _leaderType: LeaderType;
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* Prefix position, determined by the leader type.
|
|
372
|
-
*/
|
|
373
|
-
private readonly _prefixPosition: number;
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
* Constructor.
|
|
377
|
-
*
|
|
378
|
-
* @param identificationKeyType
|
|
379
|
-
* Identification key type.
|
|
380
|
-
*
|
|
381
|
-
* @param prefixType
|
|
382
|
-
* Prefix type.
|
|
383
|
-
*
|
|
384
|
-
* @param length
|
|
385
|
-
* Length.
|
|
386
|
-
*
|
|
387
|
-
* @param leaderType
|
|
388
|
-
* Leader type.
|
|
389
|
-
*/
|
|
390
|
-
protected constructor(identificationKeyType: IdentificationKeyType, prefixType: PrefixType, length: number, leaderType: LeaderType) {
|
|
391
|
-
super(identificationKeyType, prefixType, length, ContentCharacterSet.Numeric);
|
|
392
|
-
|
|
393
|
-
this._leaderType = leaderType;
|
|
394
|
-
this._prefixPosition = Number(this.leaderType === LeaderType.ExtensionDigit);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* @inheritDoc
|
|
399
|
-
*/
|
|
400
|
-
get leaderType(): LeaderType {
|
|
401
|
-
return this._leaderType;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* @inheritDoc
|
|
406
|
-
*/
|
|
407
|
-
validate(identificationKey: string, validation?: IdentificationKeyValidation): void {
|
|
408
|
-
// Validate the prefix, with care taken for its position within the identification key.
|
|
409
|
-
if (this._prefixPosition === 0) {
|
|
410
|
-
super.validatePrefix(identificationKey, validation?.positionOffset);
|
|
411
|
-
} else {
|
|
412
|
-
super.validatePrefix(identificationKey.substring(this._prefixPosition), validation?.positionOffset === undefined ? this._prefixPosition : validation.positionOffset + this._prefixPosition);
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// Validate the length.
|
|
416
|
-
if (identificationKey.length !== this.length) {
|
|
417
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.identificationKeyTypeLength", {
|
|
418
|
-
identificationKeyType: this.identificationKeyType,
|
|
419
|
-
length: this.length
|
|
420
|
-
}));
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// Validating the check digit will also validate the characters.
|
|
424
|
-
if (!hasValidCheckDigit(this.padIdentificationKey(identificationKey, validation))) {
|
|
425
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidCheckDigit"));
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* GTIN type. The numeric values of this enumeration are equal to the lengths of the GTIN types.
|
|
432
|
-
*/
|
|
433
|
-
export enum GTINType {
|
|
434
|
-
/**
|
|
435
|
-
* GTIN-13.
|
|
436
|
-
*/
|
|
437
|
-
GTIN13 = 13,
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* GTIN-12.
|
|
441
|
-
*/
|
|
442
|
-
GTIN12 = 12,
|
|
443
|
-
|
|
444
|
-
/**
|
|
445
|
-
* GTIN-8.
|
|
446
|
-
*/
|
|
447
|
-
GTIN8 = 8,
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* GTIN-14.
|
|
451
|
-
*/
|
|
452
|
-
GTIN14 = 14
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
/**
|
|
456
|
-
* Level at which GTIN is to be validated.
|
|
457
|
-
*/
|
|
458
|
-
export enum GTINLevel {
|
|
459
|
-
/**
|
|
460
|
-
* Any level (level is ignored).
|
|
461
|
-
*/
|
|
462
|
-
Any,
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* Retail consumer trade item level, supporting GTIN-13, GTIN-12 (optionally zero-suppressed), and GTIN-8.
|
|
466
|
-
*/
|
|
467
|
-
RetailConsumer,
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* Other than retail consumer trade item level, supporting GTIN-13, GTIN-12 (not zero-suppressed), and GTIN-14.
|
|
471
|
-
*/
|
|
472
|
-
OtherThanRetailConsumer
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
/**
|
|
476
|
-
* Restricted Circulation Number reference.
|
|
477
|
-
*/
|
|
478
|
-
export interface RCNReference {
|
|
479
|
-
/**
|
|
480
|
-
* Item reference.
|
|
481
|
-
*/
|
|
482
|
-
itemReference: number;
|
|
483
|
-
|
|
484
|
-
/**
|
|
485
|
-
* Price or weight (whole number only).
|
|
486
|
-
*/
|
|
487
|
-
priceOrWeight: number;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
/**
|
|
491
|
-
* GTIN validator.
|
|
492
|
-
*/
|
|
493
|
-
export class GTINValidator extends AbstractNumericIdentificationKeyValidator {
|
|
494
|
-
/**
|
|
495
|
-
* Validation parameters for optional indicator digit.
|
|
496
|
-
*/
|
|
497
|
-
private static readonly OPTIONAL_INDICATOR_DIGIT_VALIDATION: CharacterSetValidation = {
|
|
498
|
-
minimumLength: 0,
|
|
499
|
-
maximumLength: 1,
|
|
500
|
-
component: () => i18nextGS1.t("IdentificationKey.indicatorDigit")
|
|
501
|
-
};
|
|
502
|
-
|
|
503
|
-
/**
|
|
504
|
-
* Validation parameters for zero-suppressed GTIN-12.
|
|
505
|
-
*/
|
|
506
|
-
private static readonly ZERO_SUPPRESSED_GTIN12_VALIDATION: CharacterSetValidation = {
|
|
507
|
-
minimumLength: 8,
|
|
508
|
-
maximumLength: 8
|
|
509
|
-
};
|
|
510
|
-
|
|
511
|
-
/**
|
|
512
|
-
* Constructor.
|
|
513
|
-
*
|
|
514
|
-
* @param gtinType
|
|
515
|
-
* GTIN type.
|
|
516
|
-
*/
|
|
517
|
-
constructor(gtinType: GTINType) {
|
|
518
|
-
let prefixType: PrefixType;
|
|
519
|
-
|
|
520
|
-
// Determine the prefix type based on the GTIN type.
|
|
521
|
-
switch (gtinType) {
|
|
522
|
-
case GTINType.GTIN13:
|
|
523
|
-
prefixType = PrefixType.GS1CompanyPrefix;
|
|
524
|
-
break;
|
|
525
|
-
|
|
526
|
-
case GTINType.GTIN12:
|
|
527
|
-
prefixType = PrefixType.UPCCompanyPrefix;
|
|
528
|
-
break;
|
|
529
|
-
|
|
530
|
-
case GTINType.GTIN8:
|
|
531
|
-
prefixType = PrefixType.GS18Prefix;
|
|
532
|
-
break;
|
|
533
|
-
|
|
534
|
-
default:
|
|
535
|
-
// Should never get here.
|
|
536
|
-
throw new Error("Not supported");
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
super(IdentificationKeyType.GTIN, prefixType, gtinType, LeaderType.IndicatorDigit);
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
/**
|
|
543
|
-
* @inheritDoc
|
|
544
|
-
*/
|
|
545
|
-
get gtinType(): GTINType {
|
|
546
|
-
// Length maps to GTIN type enumeration.
|
|
547
|
-
return this.length satisfies GTINType;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/**
|
|
551
|
-
* @inheritDoc
|
|
552
|
-
*/
|
|
553
|
-
protected override validatePrefix(partialIdentificationKey: string, positionOffset?: number): void {
|
|
554
|
-
// Delegate to prefix manager requiring exact match for prefix type.
|
|
555
|
-
PrefixManager.validatePrefix(this.prefixType, false, false, partialIdentificationKey, true, true, positionOffset);
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
/**
|
|
559
|
-
* Zero suppress a GTIN-12.
|
|
560
|
-
*
|
|
561
|
-
* @param gtin12
|
|
562
|
-
* GTIN-12.
|
|
563
|
-
*
|
|
564
|
-
* @returns
|
|
565
|
-
* Zero-suppressed GTIN-12.
|
|
566
|
-
*/
|
|
567
|
-
static zeroSuppress(gtin12: string): string {
|
|
568
|
-
GTIN12_VALIDATOR.validate(gtin12);
|
|
569
|
-
|
|
570
|
-
// Convert to individual digits.
|
|
571
|
-
const d = Array.from(gtin12);
|
|
572
|
-
|
|
573
|
-
let zeroSuppressedGTIN12: string | undefined;
|
|
574
|
-
|
|
575
|
-
// All rules require that digits in positions 1, 5, and 6 be zero.
|
|
576
|
-
if (d[0] === "0" && d[6] === "0" && d[7] === "0") {
|
|
577
|
-
if (d[10] >= "5" && d[8] === "0" && d[9] === "0" && d[5] !== "0") {
|
|
578
|
-
zeroSuppressedGTIN12 = `0${d[1]}${d[2]}${d[3]}${d[4]}${d[5]}${d[10]}${d[11]}`;
|
|
579
|
-
} else if (d[5] === "0" && d[8] === "0" && d[9] === "0" && d[4] !== "0") {
|
|
580
|
-
zeroSuppressedGTIN12 = `0${d[1]}${d[2]}${d[3]}${d[4]}${d[10]}4${d[11]}`;
|
|
581
|
-
} else if (d[3] <= "2" && d[4] === "0" && d[5] === "0") {
|
|
582
|
-
zeroSuppressedGTIN12 = `0${d[1]}${d[2]}${d[8]}${d[9]}${d[10]}${d[3]}${d[11]}`;
|
|
583
|
-
} else if (d[3] >= "3" && d[4] === "0" && d[5] === "0" && d[8] === "0") {
|
|
584
|
-
zeroSuppressedGTIN12 = `0${d[1]}${d[2]}${d[3]}${d[9]}${d[10]}3${d[11]}`;
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
if (zeroSuppressedGTIN12 === undefined) {
|
|
589
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidZeroSuppressibleGTIN12"));
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
return zeroSuppressedGTIN12;
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
/**
|
|
596
|
-
* Zero expand a zero-suppressed GTIN-12.
|
|
597
|
-
*
|
|
598
|
-
* @param zeroSuppressedGTIN12
|
|
599
|
-
* Zero-suppressed GTIN-12.
|
|
600
|
-
*
|
|
601
|
-
* @returns
|
|
602
|
-
* GTIN-12.
|
|
603
|
-
*/
|
|
604
|
-
static zeroExpand(zeroSuppressedGTIN12: string): string {
|
|
605
|
-
NUMERIC_CREATOR.validate(zeroSuppressedGTIN12, GTINValidator.ZERO_SUPPRESSED_GTIN12_VALIDATION);
|
|
606
|
-
|
|
607
|
-
// Convert to individual digits.
|
|
608
|
-
const d = Array.from(zeroSuppressedGTIN12);
|
|
609
|
-
|
|
610
|
-
let gtin12: string | undefined;
|
|
611
|
-
|
|
612
|
-
// Zero-suppressed GTIN-12 always starts with 0.
|
|
613
|
-
if (d[0] === "0") {
|
|
614
|
-
if (d[6] >= "5" && d[5] !== "0") {
|
|
615
|
-
gtin12 = `0${d[1]}${d[2]}${d[3]}${d[4]}${d[5]}0000${d[6]}${d[7]}`;
|
|
616
|
-
} else if (d[6] === "4" && d[4] !== "0") {
|
|
617
|
-
gtin12 = `0${d[1]}${d[2]}${d[3]}${d[4]}00000${d[5]}${d[7]}`;
|
|
618
|
-
} else if (d[6] <= "2") {
|
|
619
|
-
gtin12 = `0${d[1]}${d[2]}${d[6]}0000${d[3]}${d[4]}${d[5]}${d[7]}`;
|
|
620
|
-
} else if (d[6] === "3" && d[3] >= "3") {
|
|
621
|
-
gtin12 = `0${d[1]}${d[2]}${d[3]}00000${d[4]}${d[5]}${d[7]}`;
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
if (gtin12 === undefined) {
|
|
626
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidZeroSuppressedGTIN12"));
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
// Make sure that resulting GTIN-12 is valid.
|
|
630
|
-
GTIN12_VALIDATOR.validate(gtin12);
|
|
631
|
-
|
|
632
|
-
return gtin12;
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
/**
|
|
636
|
-
* Convert a GTIN of any length to a GTIN-14 with an optional indicator digit.
|
|
637
|
-
*
|
|
638
|
-
* @param indicatorDigit
|
|
639
|
-
* Indicator digit. If blank, assumes "0" if the GTIN is not already a GTIN-14.
|
|
640
|
-
*
|
|
641
|
-
* @param gtin
|
|
642
|
-
* GTIN.
|
|
643
|
-
*
|
|
644
|
-
* @returns
|
|
645
|
-
* GTIN-14.
|
|
646
|
-
*/
|
|
647
|
-
static convertToGTIN14(indicatorDigit: string, gtin: string): string {
|
|
648
|
-
GTINCreator.validateAny(gtin);
|
|
649
|
-
|
|
650
|
-
NUMERIC_CREATOR.validate(indicatorDigit, GTINValidator.OPTIONAL_INDICATOR_DIGIT_VALIDATION);
|
|
651
|
-
|
|
652
|
-
// Check digit doesn't change by prepending zeros.
|
|
653
|
-
let gtin14 = gtin.padStart(GTINType.GTIN14, "0");
|
|
654
|
-
|
|
655
|
-
// If indicator digit provided and is different, recalculate the check digit.
|
|
656
|
-
if (indicatorDigit.length !== 0 && indicatorDigit !== gtin14.charAt(0)) {
|
|
657
|
-
const partialGTIN14 = indicatorDigit + gtin14.substring(1, GTINType.GTIN14 - 1);
|
|
658
|
-
|
|
659
|
-
gtin14 = partialGTIN14 + checkDigit(partialGTIN14);
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
return gtin14;
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
/**
|
|
666
|
-
* Normalize a GTIN of any length.
|
|
667
|
-
* - A GTIN-14 that starts with six zeros or a GTIN-13 that starts with five zeros is normalized to GTIN-8.
|
|
668
|
-
* - A GTIN-14 that starts with two zeros or a GTIN-13 that starts with one zero is normalized to GTIN-12.
|
|
669
|
-
* - A GTIN-14 that starts with one zero is normalized to GTIN-13.
|
|
670
|
-
* - Otherwise, the GTIN is unchanged.
|
|
671
|
-
*
|
|
672
|
-
* @param gtin
|
|
673
|
-
* GTIN.
|
|
674
|
-
*
|
|
675
|
-
* @returns
|
|
676
|
-
* Normalized GTIN.
|
|
677
|
-
*/
|
|
678
|
-
static normalize(gtin: string): string {
|
|
679
|
-
const gtinLength = gtin.length;
|
|
680
|
-
|
|
681
|
-
let normalizedGTIN: string;
|
|
682
|
-
|
|
683
|
-
switch (gtinLength) {
|
|
684
|
-
case GTINType.GTIN13 as number:
|
|
685
|
-
if (!gtin.startsWith("0")) {
|
|
686
|
-
// GTIN is GTIN-13.
|
|
687
|
-
normalizedGTIN = gtin;
|
|
688
|
-
} else if (!gtin.startsWith("00000")) {
|
|
689
|
-
// GTIN is GTIN-12.
|
|
690
|
-
normalizedGTIN = gtin.substring(1);
|
|
691
|
-
} else if (!gtin.startsWith("000000")) {
|
|
692
|
-
// GTIN is GTIN-8.
|
|
693
|
-
normalizedGTIN = gtin.substring(5);
|
|
694
|
-
} else {
|
|
695
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidZeroSuppressedGTIN12AsGTIN13"));
|
|
696
|
-
}
|
|
697
|
-
break;
|
|
698
|
-
|
|
699
|
-
case GTINType.GTIN12 as number:
|
|
700
|
-
// GTIN is GTIN-12.
|
|
701
|
-
normalizedGTIN = gtin;
|
|
702
|
-
break;
|
|
703
|
-
|
|
704
|
-
case GTINType.GTIN8 as number:
|
|
705
|
-
if (!gtin.startsWith("0")) {
|
|
706
|
-
// GTIN is GTIN-8.
|
|
707
|
-
normalizedGTIN = gtin;
|
|
708
|
-
} else {
|
|
709
|
-
// GTIN is zero-suppressed GTIN-12.
|
|
710
|
-
normalizedGTIN = GTINValidator.zeroExpand(gtin);
|
|
711
|
-
}
|
|
712
|
-
break;
|
|
713
|
-
|
|
714
|
-
case GTINType.GTIN14 as number:
|
|
715
|
-
if (!gtin.startsWith("0")) {
|
|
716
|
-
// GTIN is GTIN-14.
|
|
717
|
-
normalizedGTIN = gtin;
|
|
718
|
-
} else if (!gtin.startsWith("00")) {
|
|
719
|
-
// GTIN is GTIN-13.
|
|
720
|
-
normalizedGTIN = gtin.substring(1);
|
|
721
|
-
} else if (!gtin.startsWith("000000")) {
|
|
722
|
-
// GTIN is GTIN-12.
|
|
723
|
-
normalizedGTIN = gtin.substring(2);
|
|
724
|
-
} else if (!gtin.startsWith("0000000")) {
|
|
725
|
-
// GTIN is GTIN-8.
|
|
726
|
-
normalizedGTIN = gtin.substring(6);
|
|
727
|
-
} else {
|
|
728
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidZeroSuppressedGTIN12AsGTIN14"));
|
|
729
|
-
}
|
|
730
|
-
break;
|
|
731
|
-
|
|
732
|
-
default:
|
|
733
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidGTINLength"));
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
// Validation applies to the normalized GTIN.
|
|
737
|
-
GTINCreator.validateAny(normalizedGTIN);
|
|
738
|
-
|
|
739
|
-
return normalizedGTIN;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
/**
|
|
743
|
-
* Validate any GTIN, optionally against a level.
|
|
744
|
-
*
|
|
745
|
-
* @param gtin
|
|
746
|
-
* GTIN.
|
|
747
|
-
*
|
|
748
|
-
* @param gtinLevel
|
|
749
|
-
* Level at which GTIN is to be validated.
|
|
750
|
-
*/
|
|
751
|
-
static validateAny(gtin: string, gtinLevel: GTINLevel = GTINLevel.Any): void {
|
|
752
|
-
// Assume length-validated GTIN is the GTIN (true for all except zero-suppressed GTIN-12).
|
|
753
|
-
let lengthValidatedGTIN = gtin;
|
|
754
|
-
|
|
755
|
-
let gtinLevelRestriction: GTINLevel;
|
|
756
|
-
|
|
757
|
-
switch (gtin.length) {
|
|
758
|
-
case GTINType.GTIN13 as number:
|
|
759
|
-
if (gtin.startsWith("0")) {
|
|
760
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidGTIN13AtRetail"));
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
// Validate prefix requiring exact match for prefix type.
|
|
764
|
-
PrefixManager.validatePrefix(PrefixType.GS1CompanyPrefix, false, false, gtin, true, true);
|
|
765
|
-
|
|
766
|
-
gtinLevelRestriction = GTINLevel.Any;
|
|
767
|
-
break;
|
|
768
|
-
|
|
769
|
-
case GTINType.GTIN12 as number:
|
|
770
|
-
// Validate prefix requiring exact match for prefix type.
|
|
771
|
-
PrefixManager.validatePrefix(PrefixType.UPCCompanyPrefix, false, false, gtin, true, true);
|
|
772
|
-
|
|
773
|
-
gtinLevelRestriction = GTINLevel.Any;
|
|
774
|
-
break;
|
|
775
|
-
|
|
776
|
-
case GTINType.GTIN8 as number:
|
|
777
|
-
// Zero-suppressed GTIN-12 always starts with 0.
|
|
778
|
-
if (!gtin.startsWith("0")) {
|
|
779
|
-
// Validate prefix requiring exact match for prefix type.
|
|
780
|
-
PrefixManager.validatePrefix(PrefixType.GS18Prefix, false, false, gtin, true, true);
|
|
781
|
-
} else {
|
|
782
|
-
lengthValidatedGTIN = GTINValidator.zeroExpand(gtin);
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
gtinLevelRestriction = GTINLevel.RetailConsumer;
|
|
786
|
-
break;
|
|
787
|
-
|
|
788
|
-
case GTINType.GTIN14 as number:
|
|
789
|
-
// Validate prefix supporting any prefix type.
|
|
790
|
-
PrefixManager.validatePrefix(PrefixType.GS1CompanyPrefix, true, true, gtin.substring(1), true, true);
|
|
791
|
-
|
|
792
|
-
gtinLevelRestriction = GTINLevel.OtherThanRetailConsumer;
|
|
793
|
-
break;
|
|
794
|
-
|
|
795
|
-
default:
|
|
796
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidGTINLength"));
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
// Validating the check digit will also validate the characters.
|
|
800
|
-
if (!hasValidCheckDigit(lengthValidatedGTIN)) {
|
|
801
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidCheckDigit"));
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
// Validate against level if required.
|
|
805
|
-
if (gtinLevel !== GTINLevel.Any && gtinLevelRestriction !== GTINLevel.Any && gtinLevelRestriction !== gtinLevel) {
|
|
806
|
-
throw new RangeError(i18nextGS1.t(gtinLevel === GTINLevel.RetailConsumer ? "IdentificationKey.invalidGTINAtRetail" : "IdentificationKey.invalidGTINAtOtherThanRetail"));
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
/**
|
|
811
|
-
* Validate a GTIN-14.
|
|
812
|
-
*
|
|
813
|
-
* @param gtin14
|
|
814
|
-
* GTIN-14.
|
|
815
|
-
*/
|
|
816
|
-
static validateGTIN14(gtin14: string): void {
|
|
817
|
-
if (gtin14.length as GTINType !== GTINType.GTIN14) {
|
|
818
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidGTIN14Length"));
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
GTINCreator.validateAny(gtin14);
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
/**
|
|
825
|
-
* Parse a Restricted Circulation Number (RCN) using a variable measure trade item format. The format is a 12- or
|
|
826
|
-
* 13-character string (for RCN-12 or RCN-13 respectively), containing the following:
|
|
827
|
-
*
|
|
828
|
-
* - '2' - The first character of the RCN.
|
|
829
|
-
* - '0'-'9' - The second character of the RCN (RCN-13 only).
|
|
830
|
-
* - 'I' - One or more, in sequence, for the item reference.
|
|
831
|
-
* - 'P' - One or more, in sequence, for the price or weight.
|
|
832
|
-
* - 'V' - Zero or one, for the price or weight check digit.
|
|
833
|
-
* - 'C' - The check digit of the entire RCN.
|
|
834
|
-
*
|
|
835
|
-
* The 'I', 'P', and 'V' formats may be in any order.
|
|
836
|
-
*
|
|
837
|
-
* Some examples:
|
|
838
|
-
*
|
|
839
|
-
* - 2IIIIIVPPPPC - RCN-12 with a five-digit item reference, a price or weight check digit, and a four-digit price
|
|
840
|
-
* or weight.
|
|
841
|
-
* - 23IIIIVPPPPPC - RCN-13 with a four-digit item reference, a price or weight check digit, and a five-digit price
|
|
842
|
-
* or weight.
|
|
843
|
-
* - 2IIIIIIPPPPC - RCN-12 with a six-digit item reference and a four-digit price or eight.
|
|
844
|
-
* - 29IIIIIPPPPPC - RCN-13 with a five-digit item reference and a five-digit price or weight.
|
|
845
|
-
*
|
|
846
|
-
* @param format
|
|
847
|
-
* Format.
|
|
848
|
-
*
|
|
849
|
-
* @param rcn
|
|
850
|
-
* RCN.
|
|
851
|
-
*
|
|
852
|
-
* @returns
|
|
853
|
-
* RCN reference.
|
|
854
|
-
*/
|
|
855
|
-
static parseVariableMeasureRCN(format: string, rcn: string): RCNReference {
|
|
856
|
-
const formatLength = format.length;
|
|
857
|
-
|
|
858
|
-
if (rcn.length !== formatLength) {
|
|
859
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidRCNLength"));
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
let validFormat = formatLength === 12 || formatLength === 13;
|
|
863
|
-
let validRCNPrefix = true;
|
|
864
|
-
|
|
865
|
-
let buildingItemReference = false;
|
|
866
|
-
let itemReference = "";
|
|
867
|
-
|
|
868
|
-
let buildingPriceOrWeight = false;
|
|
869
|
-
let priceOrWeight = "";
|
|
870
|
-
|
|
871
|
-
let priceOrWeightCheckDigit = "";
|
|
872
|
-
|
|
873
|
-
for (let index = 0; validFormat && index < formatLength; index++) {
|
|
874
|
-
const formatChar = format.charAt(index);
|
|
875
|
-
const rcnChar = rcn.charAt(index);
|
|
876
|
-
|
|
877
|
-
if (index === 0) {
|
|
878
|
-
validFormat = formatChar === "2";
|
|
879
|
-
validRCNPrefix = rcnChar === "2";
|
|
880
|
-
} else if (formatLength === 13 && index === 1) {
|
|
881
|
-
validFormat = NUMERIC_CREATOR.characterIndex(formatChar) !== undefined;
|
|
882
|
-
validRCNPrefix = rcnChar === formatChar;
|
|
883
|
-
} else if (index === formatLength - 1) {
|
|
884
|
-
validFormat = formatChar === "C";
|
|
885
|
-
} else {
|
|
886
|
-
switch (formatChar) {
|
|
887
|
-
case "I":
|
|
888
|
-
if (!buildingItemReference) {
|
|
889
|
-
// Item reference can't appear more than once.
|
|
890
|
-
validFormat = itemReference === "";
|
|
891
|
-
|
|
892
|
-
buildingItemReference = true;
|
|
893
|
-
buildingPriceOrWeight = false;
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
itemReference += rcnChar;
|
|
897
|
-
break;
|
|
898
|
-
|
|
899
|
-
case "P":
|
|
900
|
-
if (!buildingPriceOrWeight) {
|
|
901
|
-
// Price or weight can't appear more than once.
|
|
902
|
-
validFormat = priceOrWeight === "";
|
|
903
|
-
|
|
904
|
-
buildingPriceOrWeight = true;
|
|
905
|
-
buildingItemReference = false;
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
priceOrWeight += rcnChar;
|
|
909
|
-
break;
|
|
910
|
-
|
|
911
|
-
case "V":
|
|
912
|
-
// Price or weight check digit can't appear more than once.
|
|
913
|
-
validFormat = priceOrWeightCheckDigit === "";
|
|
914
|
-
|
|
915
|
-
buildingItemReference = false;
|
|
916
|
-
buildingPriceOrWeight = false;
|
|
917
|
-
|
|
918
|
-
priceOrWeightCheckDigit = rcnChar;
|
|
919
|
-
break;
|
|
920
|
-
|
|
921
|
-
default:
|
|
922
|
-
validFormat = false;
|
|
923
|
-
break;
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
validFormat &&= itemReference !== "" && priceOrWeight !== "";
|
|
929
|
-
|
|
930
|
-
if (!validFormat) {
|
|
931
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidVariableMeasureRCNFormat"));
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
if (!validRCNPrefix) {
|
|
935
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidVariableMeasureRCNPrefix"));
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
if (priceOrWeightCheckDigit !== "" && !isValidPriceOrWeightCheckDigit(priceOrWeight, priceOrWeightCheckDigit)) {
|
|
939
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidVariableMeasurePriceOrWeight"));
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
if (!hasValidCheckDigit(rcn)) {
|
|
943
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidCheckDigit"));
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
return {
|
|
947
|
-
itemReference: Number(itemReference),
|
|
948
|
-
priceOrWeight: Number(priceOrWeight)
|
|
949
|
-
};
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
/**
|
|
954
|
-
* Non-GTIN numeric identification key validator.
|
|
955
|
-
*/
|
|
956
|
-
export class NonGTINNumericIdentificationKeyValidator extends AbstractNumericIdentificationKeyValidator {
|
|
957
|
-
/**
|
|
958
|
-
* Constructor.
|
|
959
|
-
*
|
|
960
|
-
* @param identificationKeyType
|
|
961
|
-
* Identification key type.
|
|
962
|
-
*
|
|
963
|
-
* @param length
|
|
964
|
-
* Length.
|
|
965
|
-
*
|
|
966
|
-
* @param leaderType
|
|
967
|
-
* Leader type.
|
|
968
|
-
*/
|
|
969
|
-
constructor(identificationKeyType: IdentificationKeyType, length: number, leaderType: LeaderType = LeaderType.None) {
|
|
970
|
-
super(identificationKeyType, PrefixType.GS1CompanyPrefix, length, leaderType);
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
/**
|
|
975
|
-
* Serializable numeric identification key validator. Validates both serialized and non-serialized forms of
|
|
976
|
-
* numeric identification keys that support serialization.
|
|
977
|
-
*/
|
|
978
|
-
export class SerializableNumericIdentificationKeyValidator extends NonGTINNumericIdentificationKeyValidator {
|
|
979
|
-
/**
|
|
980
|
-
* Serial component length.
|
|
981
|
-
*/
|
|
982
|
-
private readonly _serialComponentLength: number;
|
|
983
|
-
|
|
984
|
-
/**
|
|
985
|
-
* Serial component character set.
|
|
986
|
-
*/
|
|
987
|
-
private readonly _serialComponentCharacterSet: ContentCharacterSet;
|
|
988
|
-
|
|
989
|
-
/**
|
|
990
|
-
* Serial component validation parameters.
|
|
991
|
-
*/
|
|
992
|
-
private readonly _serialComponentValidation: CharacterSetValidation;
|
|
993
|
-
|
|
994
|
-
/**
|
|
995
|
-
* Serial component creator.
|
|
996
|
-
*/
|
|
997
|
-
private readonly _serialComponentCreator: CharacterSetCreator;
|
|
998
|
-
|
|
999
|
-
/**
|
|
1000
|
-
* Constructor.
|
|
1001
|
-
*
|
|
1002
|
-
* @param identificationKeyType
|
|
1003
|
-
* Identification key type.
|
|
1004
|
-
*
|
|
1005
|
-
* @param length
|
|
1006
|
-
* Length.
|
|
1007
|
-
*
|
|
1008
|
-
* @param serialComponentLength
|
|
1009
|
-
* Serial component length.
|
|
1010
|
-
*
|
|
1011
|
-
* @param serialComponentCharacterSet
|
|
1012
|
-
* Serial component character set.
|
|
1013
|
-
*/
|
|
1014
|
-
constructor(identificationKeyType: IdentificationKeyType, length: number, serialComponentLength: number, serialComponentCharacterSet: ContentCharacterSet) {
|
|
1015
|
-
super(identificationKeyType, length, LeaderType.None);
|
|
1016
|
-
|
|
1017
|
-
this._serialComponentLength = serialComponentLength;
|
|
1018
|
-
this._serialComponentCharacterSet = serialComponentCharacterSet;
|
|
1019
|
-
|
|
1020
|
-
this._serialComponentValidation = {
|
|
1021
|
-
minimumLength: 1,
|
|
1022
|
-
maximumLength: serialComponentLength,
|
|
1023
|
-
component: () => i18nextGS1.t("IdentificationKey.serialComponent")
|
|
1024
|
-
};
|
|
1025
|
-
|
|
1026
|
-
this._serialComponentCreator = SerializableNumericIdentificationKeyValidator.creatorFor(serialComponentCharacterSet);
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
/**
|
|
1030
|
-
* Get the serial component length.
|
|
1031
|
-
*/
|
|
1032
|
-
get serialComponentLength(): number {
|
|
1033
|
-
return this._serialComponentLength;
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
/**
|
|
1037
|
-
* Get the serial component character set.
|
|
1038
|
-
*/
|
|
1039
|
-
get serialComponentCharacterSet(): ContentCharacterSet {
|
|
1040
|
-
return this._serialComponentCharacterSet;
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
/**
|
|
1044
|
-
* Get the serial component validation parameters.
|
|
1045
|
-
*/
|
|
1046
|
-
protected get serialComponentValidation(): CharacterSetValidation {
|
|
1047
|
-
return this._serialComponentValidation;
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
/**
|
|
1051
|
-
* Get the serial component creator.
|
|
1052
|
-
*/
|
|
1053
|
-
get serialComponentCreator(): CharacterSetCreator {
|
|
1054
|
-
return this._serialComponentCreator;
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
|
-
/**
|
|
1058
|
-
* @inheritDoc
|
|
1059
|
-
*/
|
|
1060
|
-
override validate(identificationKey: string, validation?: IdentificationKeyValidation): void {
|
|
1061
|
-
super.validate(identificationKey.substring(0, this.length), validation);
|
|
1062
|
-
|
|
1063
|
-
if (identificationKey.length > this.length) {
|
|
1064
|
-
this.serialComponentCreator.validate(identificationKey.substring(this.length), this._serialComponentValidation);
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
/**
|
|
1070
|
-
* Non-numeric identification key validation parameters.
|
|
1071
|
-
*/
|
|
1072
|
-
export interface NonNumericIdentificationKeyValidation extends IdentificationKeyValidation {
|
|
1073
|
-
/**
|
|
1074
|
-
* Exclusion support for reference. Prevents non-numeric identification key from being mistaken for numeric
|
|
1075
|
-
* identification key.
|
|
1076
|
-
*/
|
|
1077
|
-
exclusion?: Exclusion.None | Exclusion.AllNumeric | undefined;
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
/**
|
|
1081
|
-
* Non-numeric identification key validator.
|
|
1082
|
-
*/
|
|
1083
|
-
export class NonNumericIdentificationKeyValidator extends AbstractIdentificationKeyValidator<NonNumericIdentificationKeyValidation> {
|
|
1084
|
-
/**
|
|
1085
|
-
* Validator to ensure that an identification key (minus check character pair) is not all numeric.
|
|
1086
|
-
*/
|
|
1087
|
-
private static readonly NOT_ALL_NUMERIC_VALIDATOR = new class extends RegExpValidator {
|
|
1088
|
-
/**
|
|
1089
|
-
* @inheritDoc
|
|
1090
|
-
*/
|
|
1091
|
-
protected override createErrorMessage(_s: string): string {
|
|
1092
|
-
return i18nextGS1.t("IdentificationKey.referenceCantBeAllNumeric");
|
|
1093
|
-
}
|
|
1094
|
-
}(/\D/);
|
|
1095
|
-
|
|
1096
|
-
/**
|
|
1097
|
-
* True if the identification key requires a check character pair.
|
|
1098
|
-
*/
|
|
1099
|
-
private readonly _requiresCheckCharacterPair: boolean;
|
|
1100
|
-
|
|
1101
|
-
/**
|
|
1102
|
-
* Constructor.
|
|
1103
|
-
*
|
|
1104
|
-
* @param identificationKeyType
|
|
1105
|
-
* Identification key type.
|
|
1106
|
-
*
|
|
1107
|
-
* @param length
|
|
1108
|
-
* Length.
|
|
1109
|
-
*
|
|
1110
|
-
* @param referenceCharacterSet
|
|
1111
|
-
* Reference character set.
|
|
1112
|
-
*
|
|
1113
|
-
* @param requiresCheckCharacterPair
|
|
1114
|
-
* True if the identification key requires a check character pair.
|
|
1115
|
-
*/
|
|
1116
|
-
constructor(identificationKeyType: IdentificationKeyType, length: number, referenceCharacterSet: ContentCharacterSet, requiresCheckCharacterPair = false) {
|
|
1117
|
-
super(identificationKeyType, PrefixType.GS1CompanyPrefix, length, referenceCharacterSet);
|
|
1118
|
-
|
|
1119
|
-
this._requiresCheckCharacterPair = requiresCheckCharacterPair;
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
/**
|
|
1123
|
-
* Determine if the identification key requires a check character pair.
|
|
1124
|
-
*/
|
|
1125
|
-
get requiresCheckCharacterPair(): boolean {
|
|
1126
|
-
return this._requiresCheckCharacterPair;
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
/**
|
|
1130
|
-
* Validate a non-numeric identification key and throw an error if validation fails.
|
|
1131
|
-
*
|
|
1132
|
-
* @param identificationKey
|
|
1133
|
-
* Identification key.
|
|
1134
|
-
*
|
|
1135
|
-
* @param validation
|
|
1136
|
-
* Validation parameters.
|
|
1137
|
-
*/
|
|
1138
|
-
validate(identificationKey: string, validation?: NonNumericIdentificationKeyValidation): void {
|
|
1139
|
-
const partialIdentificationKey = this.requiresCheckCharacterPair ? identificationKey.substring(0, identificationKey.length - 2) : identificationKey;
|
|
1140
|
-
|
|
1141
|
-
super.validatePrefix(partialIdentificationKey, validation?.positionOffset);
|
|
1142
|
-
|
|
1143
|
-
if (!this.requiresCheckCharacterPair) {
|
|
1144
|
-
this.referenceCreator.validate(identificationKey, {
|
|
1145
|
-
maximumLength: this.length,
|
|
1146
|
-
positionOffset: validation?.positionOffset
|
|
1147
|
-
});
|
|
1148
|
-
// Validating the check character pair will also validate the characters.
|
|
1149
|
-
} else if (!hasValidCheckCharacterPair(this.padIdentificationKey(identificationKey, validation))) {
|
|
1150
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidCheckCharacterPair"));
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
// Check for all-numeric identification key (minus check character pair) if excluded.
|
|
1154
|
-
if (validation?.exclusion === Exclusion.AllNumeric) {
|
|
1155
|
-
NonNumericIdentificationKeyValidator.NOT_ALL_NUMERIC_VALIDATOR.validate(partialIdentificationKey);
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
/**
|
|
1161
|
-
* GTIN-13 validator.
|
|
1162
|
-
*/
|
|
1163
|
-
export const GTIN13_VALIDATOR = new GTINValidator(GTINType.GTIN13);
|
|
1164
|
-
|
|
1165
|
-
/**
|
|
1166
|
-
* GTIN-12 validator.
|
|
1167
|
-
*/
|
|
1168
|
-
export const GTIN12_VALIDATOR = new GTINValidator(GTINType.GTIN12);
|
|
1169
|
-
|
|
1170
|
-
/**
|
|
1171
|
-
* GTIN-8 validator.
|
|
1172
|
-
*/
|
|
1173
|
-
export const GTIN8_VALIDATOR = new GTINValidator(GTINType.GTIN8);
|
|
1174
|
-
|
|
1175
|
-
/**
|
|
1176
|
-
* GTIN validators indexed by prefix type.
|
|
1177
|
-
*/
|
|
1178
|
-
export const GTIN_VALIDATORS = [
|
|
1179
|
-
GTIN13_VALIDATOR, GTIN12_VALIDATOR, GTIN8_VALIDATOR
|
|
1180
|
-
];
|
|
1181
|
-
|
|
1182
|
-
/**
|
|
1183
|
-
* GLN validator.
|
|
1184
|
-
*/
|
|
1185
|
-
export const GLN_VALIDATOR = new NonGTINNumericIdentificationKeyValidator(IdentificationKeyType.GLN, 13);
|
|
1186
|
-
|
|
1187
|
-
/**
|
|
1188
|
-
* SSCC validator.
|
|
1189
|
-
*/
|
|
1190
|
-
export const SSCC_VALIDATOR = new NonGTINNumericIdentificationKeyValidator(IdentificationKeyType.SSCC, 18, LeaderType.ExtensionDigit);
|
|
1191
|
-
|
|
1192
|
-
/**
|
|
1193
|
-
* GRAI validator.
|
|
1194
|
-
*/
|
|
1195
|
-
export const GRAI_VALIDATOR = new SerializableNumericIdentificationKeyValidator(IdentificationKeyType.GRAI, 13, 16, ContentCharacterSet.AI82);
|
|
1196
|
-
|
|
1197
|
-
/**
|
|
1198
|
-
* GIAI validator.
|
|
1199
|
-
*/
|
|
1200
|
-
export const GIAI_VALIDATOR = new NonNumericIdentificationKeyValidator(IdentificationKeyType.GIAI, 30, ContentCharacterSet.AI82);
|
|
1201
|
-
|
|
1202
|
-
/**
|
|
1203
|
-
* GSRN validator.
|
|
1204
|
-
*/
|
|
1205
|
-
export const GSRN_VALIDATOR = new NonGTINNumericIdentificationKeyValidator(IdentificationKeyType.GSRN, 18);
|
|
1206
|
-
|
|
1207
|
-
/**
|
|
1208
|
-
* GDTI validator.
|
|
1209
|
-
*/
|
|
1210
|
-
export const GDTI_VALIDATOR = new SerializableNumericIdentificationKeyValidator(IdentificationKeyType.GDTI, 13, 17, ContentCharacterSet.AI82);
|
|
1211
|
-
|
|
1212
|
-
/**
|
|
1213
|
-
* GINC validator.
|
|
1214
|
-
*/
|
|
1215
|
-
export const GINC_VALIDATOR = new NonNumericIdentificationKeyValidator(IdentificationKeyType.GINC, 30, ContentCharacterSet.AI82);
|
|
1216
|
-
|
|
1217
|
-
/**
|
|
1218
|
-
* GSIN validator.
|
|
1219
|
-
*/
|
|
1220
|
-
export const GSIN_VALIDATOR = new NonGTINNumericIdentificationKeyValidator(IdentificationKeyType.GSIN, 17);
|
|
1221
|
-
|
|
1222
|
-
/**
|
|
1223
|
-
* GCN validator.
|
|
1224
|
-
*/
|
|
1225
|
-
export const GCN_VALIDATOR = new SerializableNumericIdentificationKeyValidator(IdentificationKeyType.GCN, 13, 12, ContentCharacterSet.Numeric);
|
|
1226
|
-
|
|
1227
|
-
/**
|
|
1228
|
-
* CPID validator.
|
|
1229
|
-
*/
|
|
1230
|
-
export const CPID_VALIDATOR = new NonNumericIdentificationKeyValidator(IdentificationKeyType.CPID, 30, ContentCharacterSet.AI39);
|
|
1231
|
-
|
|
1232
|
-
/**
|
|
1233
|
-
* GMN validator.
|
|
1234
|
-
*/
|
|
1235
|
-
export const GMN_VALIDATOR = new NonNumericIdentificationKeyValidator(IdentificationKeyType.GMN, 25, ContentCharacterSet.AI82, true);
|
|
1236
|
-
|
|
1237
|
-
/**
|
|
1238
|
-
* Identification key creator. Creates an identification key based on its definition in section 3 of the {@link
|
|
1239
|
-
* https://www.gs1.org/genspecs | GS1 General Specifications}.
|
|
1240
|
-
*
|
|
1241
|
-
* Keys are created based on a prefix defined in a prefix manager to which the identification key creator is bound.
|
|
1242
|
-
*/
|
|
1243
|
-
export interface IdentificationKeyCreator extends IdentificationKeyValidator {
|
|
1244
|
-
/**
|
|
1245
|
-
* Get the prefix manager to which this identification key creator is bound.
|
|
1246
|
-
*/
|
|
1247
|
-
get prefixManager(): PrefixManager;
|
|
1248
|
-
|
|
1249
|
-
/**
|
|
1250
|
-
* Get the prefix, equivalent to calling {@linkcode PrefixManager.prefix | prefixManager.prefix} for a GTIN or
|
|
1251
|
-
* {@linkcode PrefixManager.gs1CompanyPrefix | prefixManager.gs1CompanyPrefix} for all other identification key
|
|
1252
|
-
* types.
|
|
1253
|
-
*/
|
|
1254
|
-
get prefix(): string;
|
|
1255
|
-
|
|
1256
|
-
/**
|
|
1257
|
-
* Get the reference length.
|
|
1258
|
-
*/
|
|
1259
|
-
get referenceLength(): number;
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
/**
|
|
1263
|
-
* Abstract identification key creator. Implements common functionality for an identification key creator, bound to a
|
|
1264
|
-
* {@link PrefixManager}.
|
|
1265
|
-
*/
|
|
1266
|
-
abstract class AbstractIdentificationKeyCreator implements IdentificationKeyCreator {
|
|
1267
|
-
/**
|
|
1268
|
-
* Prefix manager.
|
|
1269
|
-
*/
|
|
1270
|
-
private _prefixManager!: PrefixManager;
|
|
1271
|
-
|
|
1272
|
-
/**
|
|
1273
|
-
* Reference length.
|
|
1274
|
-
*/
|
|
1275
|
-
private _referenceLength!: number;
|
|
1276
|
-
|
|
1277
|
-
/**
|
|
1278
|
-
* Initialize the prefix manager. This method is in lieu of a constructor due to the mixin architecture.
|
|
1279
|
-
*
|
|
1280
|
-
* @param prefixManager
|
|
1281
|
-
* Prefix manager.
|
|
1282
|
-
*
|
|
1283
|
-
* @param prefix
|
|
1284
|
-
* Prefix within prefix manager to use to calculate reference length.
|
|
1285
|
-
*
|
|
1286
|
-
* @param checkAllowance
|
|
1287
|
-
* Number of characters to allow for check digit or check character pair.
|
|
1288
|
-
*/
|
|
1289
|
-
protected init(prefixManager: PrefixManager, prefix: string, checkAllowance: number): void {
|
|
1290
|
-
this._prefixManager = prefixManager;
|
|
1291
|
-
|
|
1292
|
-
// Reference length allows for prefix and optionally check digit or check character pair.
|
|
1293
|
-
this._referenceLength = this.length - prefix.length - checkAllowance;
|
|
1294
|
-
}
|
|
1295
|
-
|
|
1296
|
-
abstract get identificationKeyType(): IdentificationKeyType;
|
|
1297
|
-
|
|
1298
|
-
abstract get prefixType(): PrefixType;
|
|
1299
|
-
|
|
1300
|
-
abstract get length(): number;
|
|
1301
|
-
|
|
1302
|
-
abstract get referenceCharacterSet(): ContentCharacterSet;
|
|
1303
|
-
|
|
1304
|
-
abstract get referenceCreator(): CharacterSetCreator;
|
|
1305
|
-
|
|
1306
|
-
/**
|
|
1307
|
-
* @inheritDoc
|
|
1308
|
-
*/
|
|
1309
|
-
get prefixManager(): PrefixManager {
|
|
1310
|
-
return this._prefixManager;
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
/**
|
|
1314
|
-
* @inheritDoc
|
|
1315
|
-
*/
|
|
1316
|
-
get prefix(): string {
|
|
1317
|
-
return this.prefixManager.gs1CompanyPrefix;
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
/**
|
|
1321
|
-
* @inheritDoc
|
|
1322
|
-
*/
|
|
1323
|
-
get referenceLength(): number {
|
|
1324
|
-
return this._referenceLength;
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
abstract validate(identificationKey: string, validation?: IdentificationKeyValidation): void;
|
|
1328
|
-
}
|
|
1329
|
-
|
|
1330
|
-
/**
|
|
1331
|
-
* Numeric identification key creator. Creates one or many numeric identification keys.
|
|
1332
|
-
*/
|
|
1333
|
-
export interface NumericIdentificationKeyCreator extends NumericIdentificationKeyValidator, IdentificationKeyCreator {
|
|
1334
|
-
/**
|
|
1335
|
-
* Get the capacity (`10**referenceLength`).
|
|
1336
|
-
*/
|
|
1337
|
-
get capacity(): number;
|
|
1338
|
-
|
|
1339
|
-
/**
|
|
1340
|
-
* Create identification key(s) with reference(s) based on numeric value(s). The value(s) is/are converted to
|
|
1341
|
-
* references of the appropriate length using {@linkcode NUMERIC_CREATOR}.
|
|
1342
|
-
*
|
|
1343
|
-
* @template TTransformerInput
|
|
1344
|
-
* Transformer input type.
|
|
1345
|
-
*
|
|
1346
|
-
* @param valueOrValues
|
|
1347
|
-
* Numeric value(s).
|
|
1348
|
-
*
|
|
1349
|
-
* @param sparse
|
|
1350
|
-
* If true, the value(s) are mapped to a sparse sequence resistant to discovery. Default is false.
|
|
1351
|
-
*
|
|
1352
|
-
* @returns
|
|
1353
|
-
* Identification key(s).
|
|
1354
|
-
*/
|
|
1355
|
-
create: <TTransformerInput extends TransformerInput<number | bigint>>(valueOrValues: TTransformerInput, sparse?: boolean) => TransformerOutput<TTransformerInput, string>;
|
|
1356
|
-
|
|
1357
|
-
/**
|
|
1358
|
-
* Create all identification keys for the prefix from `0` to `capacity - 1`.
|
|
1359
|
-
*
|
|
1360
|
-
* The implementation creates the strings only as needed using an internal generator function. Although the result
|
|
1361
|
-
* is equivalent to calling `creator.create(new Sequence(0, creator.capacity))`, this method is significantly
|
|
1362
|
-
* faster.
|
|
1363
|
-
*
|
|
1364
|
-
* @returns
|
|
1365
|
-
* All identification keys for the prefix.
|
|
1366
|
-
*/
|
|
1367
|
-
createAll: () => Iterable<string>;
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
|
-
/**
|
|
1371
|
-
* Abstract numeric identification key creator. Implements common functionality for a numeric identification key
|
|
1372
|
-
* creator.
|
|
1373
|
-
*/
|
|
1374
|
-
abstract class AbstractNumericIdentificationKeyCreator extends AbstractIdentificationKeyCreator implements NumericIdentificationKeyCreator {
|
|
1375
|
-
/**
|
|
1376
|
-
* Capacity.
|
|
1377
|
-
*/
|
|
1378
|
-
private _capacity!: number;
|
|
1379
|
-
|
|
1380
|
-
/**
|
|
1381
|
-
* Tweak for sparse creation.
|
|
1382
|
-
*/
|
|
1383
|
-
private _tweak = 0n;
|
|
1384
|
-
|
|
1385
|
-
/**
|
|
1386
|
-
* Initialize the prefix manager. This method is in lieu of a constructor due to the mixin architecture.
|
|
1387
|
-
*
|
|
1388
|
-
* @param prefixManager
|
|
1389
|
-
* Prefix manager.
|
|
1390
|
-
*
|
|
1391
|
-
* @param prefix
|
|
1392
|
-
* Prefix within prefix manager to use to calculate reference length.
|
|
1393
|
-
*/
|
|
1394
|
-
protected override init(prefixManager: PrefixManager, prefix: string): void {
|
|
1395
|
-
super.init(prefixManager, prefix, 1);
|
|
1396
|
-
|
|
1397
|
-
// Capacity is always in number range.
|
|
1398
|
-
this._capacity = Number(CharacterSetCreator.powerOf10(this.referenceLength));
|
|
1399
|
-
}
|
|
1400
|
-
|
|
1401
|
-
abstract get leaderType(): LeaderType;
|
|
1402
|
-
|
|
1403
|
-
/**
|
|
1404
|
-
* @inheritDoc
|
|
1405
|
-
*/
|
|
1406
|
-
get capacity(): number {
|
|
1407
|
-
return this._capacity;
|
|
1408
|
-
}
|
|
1409
|
-
|
|
1410
|
-
/**
|
|
1411
|
-
* Get the tweak for sparse creation.
|
|
1412
|
-
*/
|
|
1413
|
-
get tweak(): bigint {
|
|
1414
|
-
return this._tweak;
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
|
-
/**
|
|
1418
|
-
* Set the tweak for sparse creation.
|
|
1419
|
-
*/
|
|
1420
|
-
set tweak(value: bigint) {
|
|
1421
|
-
this._tweak = value;
|
|
1422
|
-
}
|
|
1423
|
-
|
|
1424
|
-
/**
|
|
1425
|
-
* Build an identification key from a reference by merging it with the prefix and adding the check digit.
|
|
1426
|
-
*
|
|
1427
|
-
* @param reference
|
|
1428
|
-
* Identification key reference.
|
|
1429
|
-
*
|
|
1430
|
-
* @returns
|
|
1431
|
-
* Identification key.
|
|
1432
|
-
*/
|
|
1433
|
-
private buildIdentificationKey(reference: string): string {
|
|
1434
|
-
const partialIdentificationKey = this.leaderType === LeaderType.ExtensionDigit ? reference.substring(0, 1) + this.prefix + reference.substring(1) : this.prefix + reference;
|
|
1435
|
-
|
|
1436
|
-
return partialIdentificationKey + checkDigit(partialIdentificationKey);
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
|
-
/**
|
|
1440
|
-
* @inheritDoc
|
|
1441
|
-
*/
|
|
1442
|
-
create<TTransformerInput extends TransformerInput<number | bigint>>(valueOrValues: TTransformerInput, sparse = false): TransformerOutput<TTransformerInput, string> {
|
|
1443
|
-
return NUMERIC_CREATOR.create(this.referenceLength, valueOrValues, Exclusion.None, sparse ? this.tweak : undefined, reference => this.buildIdentificationKey(reference));
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
/**
|
|
1447
|
-
* Create all identification keys from a partial identification key. Call is recursive until remaining reference
|
|
1448
|
-
* length is 0.
|
|
1449
|
-
*
|
|
1450
|
-
* @param partialIdentificationKey
|
|
1451
|
-
* Partial identification key. Initial value is `this.prefix`.
|
|
1452
|
-
*
|
|
1453
|
-
* @param remainingReferenceLength
|
|
1454
|
-
* Remaining reference length. Initial value is `this.referenceLength`.
|
|
1455
|
-
*
|
|
1456
|
-
* @param extensionWeight
|
|
1457
|
-
* If this value is not zero, the identification key has an extension digit, this call is setting it, and this value
|
|
1458
|
-
* is applied to the calculation of the check digit.
|
|
1459
|
-
*
|
|
1460
|
-
* @param weight
|
|
1461
|
-
* If the extension weight is zero, this value is applied to the calculation of the check digit.
|
|
1462
|
-
*
|
|
1463
|
-
* @param partialCheckDigitSum
|
|
1464
|
-
* Partial check digit sum for the partial identification key.
|
|
1465
|
-
*
|
|
1466
|
-
* @yields
|
|
1467
|
-
* Identification key.
|
|
1468
|
-
*/
|
|
1469
|
-
private static * createAllPartial(partialIdentificationKey: string, remainingReferenceLength: number, extensionWeight: number, weight: number, partialCheckDigitSum: number): Generator<string> {
|
|
1470
|
-
if (remainingReferenceLength === 0) {
|
|
1471
|
-
// Finalize check digit calculation and append.
|
|
1472
|
-
yield partialIdentificationKey + NUMERIC_CREATOR.character(9 - (partialCheckDigitSum + 9) % 10);
|
|
1473
|
-
} else {
|
|
1474
|
-
const nextRemainingReferenceLength = remainingReferenceLength - 1;
|
|
1475
|
-
|
|
1476
|
-
let nextPartialCheckDigitSum = partialCheckDigitSum;
|
|
1477
|
-
|
|
1478
|
-
if (extensionWeight !== 0) {
|
|
1479
|
-
// Apply every digit to the extension digit.
|
|
1480
|
-
for (const c of NUMERIC_CREATOR.characterSet) {
|
|
1481
|
-
yield * AbstractNumericIdentificationKeyCreator.createAllPartial(c + partialIdentificationKey, nextRemainingReferenceLength, 0, weight, nextPartialCheckDigitSum);
|
|
1482
|
-
|
|
1483
|
-
nextPartialCheckDigitSum += extensionWeight;
|
|
1484
|
-
}
|
|
1485
|
-
} else {
|
|
1486
|
-
const nextWeight = 4 - weight;
|
|
1487
|
-
|
|
1488
|
-
// Apply every digit to the current character in the identification key.
|
|
1489
|
-
for (const c of NUMERIC_CREATOR.characterSet) {
|
|
1490
|
-
yield * AbstractNumericIdentificationKeyCreator.createAllPartial(partialIdentificationKey + c, nextRemainingReferenceLength, 0, nextWeight, nextPartialCheckDigitSum);
|
|
1491
|
-
|
|
1492
|
-
nextPartialCheckDigitSum += weight;
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
/**
|
|
1499
|
-
* @inheritDoc
|
|
1500
|
-
*/
|
|
1501
|
-
createAll(): Iterable<string> {
|
|
1502
|
-
const hasExtensionDigit = this.leaderType === LeaderType.ExtensionDigit;
|
|
1503
|
-
const prefix = this.prefix;
|
|
1504
|
-
const length = this.length;
|
|
1505
|
-
const referenceLength = this.referenceLength;
|
|
1506
|
-
|
|
1507
|
-
// Start weight is for reference excluding extension digit, which has its weight calculated separately.
|
|
1508
|
-
const startWeight = 3 - 2 * ((referenceLength + 1 - Number(hasExtensionDigit)) % 2);
|
|
1509
|
-
|
|
1510
|
-
// Returning separate Iterable object makes iteration repeatable.
|
|
1511
|
-
return {
|
|
1512
|
-
[Symbol.iterator]() {
|
|
1513
|
-
return AbstractNumericIdentificationKeyCreator.createAllPartial(prefix, referenceLength, hasExtensionDigit ? 3 - 2 * length % 2 : 0, startWeight, checkDigitSum(startWeight === 3, prefix));
|
|
1514
|
-
}
|
|
1515
|
-
};
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
|
-
/**
|
|
1520
|
-
* GTIN creator. Applicable to GTIN-13, GTIN-12, and GTIN-8 types; no applicable to GTIN-14 type.
|
|
1521
|
-
*/
|
|
1522
|
-
export class GTINCreator extends Mixin(GTINValidator, AbstractNumericIdentificationKeyCreator) {
|
|
1523
|
-
/**
|
|
1524
|
-
* Validation parameters for required indicator digit.
|
|
1525
|
-
*/
|
|
1526
|
-
private static readonly REQUIRED_INDICATOR_DIGIT_VALIDATION: CharacterSetValidation = {
|
|
1527
|
-
minimumLength: 1,
|
|
1528
|
-
maximumLength: 1,
|
|
1529
|
-
component: () => i18nextGS1.t("IdentificationKey.indicatorDigit")
|
|
1530
|
-
};
|
|
1531
|
-
|
|
1532
|
-
/**
|
|
1533
|
-
* Constructor. Called internally by {@link PrefixManager.gtinCreator}; should not be called by other code.
|
|
1534
|
-
*
|
|
1535
|
-
* @param prefixManager
|
|
1536
|
-
* Prefix manager.
|
|
1537
|
-
*
|
|
1538
|
-
* @param gtinType
|
|
1539
|
-
* GTIN type.
|
|
1540
|
-
*/
|
|
1541
|
-
constructor(prefixManager: PrefixManager, gtinType: GTINType) {
|
|
1542
|
-
super(gtinType);
|
|
1543
|
-
|
|
1544
|
-
this.init(prefixManager, prefixManager.prefix);
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
/**
|
|
1548
|
-
* @inheritDoc
|
|
1549
|
-
*/
|
|
1550
|
-
override get prefix(): string {
|
|
1551
|
-
return this.prefixManager.prefix;
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1554
|
-
/**
|
|
1555
|
-
* Create GTIN-14(s) with an indicator digit and reference(s) based on numeric value(s). The value(s) is/are
|
|
1556
|
-
* converted to reference(s) of the appropriate length using {@linkcode NUMERIC_CREATOR}.
|
|
1557
|
-
*
|
|
1558
|
-
* @template TTransformerInput
|
|
1559
|
-
* Transformer input type.
|
|
1560
|
-
*
|
|
1561
|
-
* @param indicatorDigit
|
|
1562
|
-
* Indicator digit.
|
|
1563
|
-
*
|
|
1564
|
-
* @param valueOrValues
|
|
1565
|
-
* Numeric value(s).
|
|
1566
|
-
*
|
|
1567
|
-
* @param sparse
|
|
1568
|
-
* If true, the value(s) is/are mapped to a sparse sequence resistant to discovery. Default is false.
|
|
1569
|
-
*
|
|
1570
|
-
* @returns
|
|
1571
|
-
* GTIN-14(s).
|
|
1572
|
-
*/
|
|
1573
|
-
createGTIN14<TTransformerInput extends TransformerInput<number | bigint>>(indicatorDigit: string, valueOrValues: TTransformerInput, sparse = false): TransformerOutput<TTransformerInput, string> {
|
|
1574
|
-
NUMERIC_CREATOR.validate(indicatorDigit, GTINCreator.REQUIRED_INDICATOR_DIGIT_VALIDATION);
|
|
1575
|
-
|
|
1576
|
-
return NUMERIC_CREATOR.create(GTINType.GTIN13 - this.prefixManager.gs1CompanyPrefix.length - 1, valueOrValues, Exclusion.None, sparse ? this.tweak : undefined, (reference) => {
|
|
1577
|
-
const partialIdentificationKey = indicatorDigit + this.prefixManager.gs1CompanyPrefix + reference;
|
|
1578
|
-
|
|
1579
|
-
return partialIdentificationKey + checkDigit(partialIdentificationKey);
|
|
1580
|
-
});
|
|
1581
|
-
}
|
|
1582
|
-
|
|
1583
|
-
/**
|
|
1584
|
-
* Create a Restricted Circulation Number (RCN) using a variable measure trade item format. See {@linkcode
|
|
1585
|
-
* GTINValidator.parseVariableMeasureRCN} for format details.
|
|
1586
|
-
*
|
|
1587
|
-
* @param format
|
|
1588
|
-
* Format.
|
|
1589
|
-
*
|
|
1590
|
-
* @param itemReference
|
|
1591
|
-
* Item reference.
|
|
1592
|
-
*
|
|
1593
|
-
* @param priceOrWeight
|
|
1594
|
-
* Price or weight (whole number only).
|
|
1595
|
-
*
|
|
1596
|
-
* @returns
|
|
1597
|
-
* RCN-12 or RCN-13.
|
|
1598
|
-
*/
|
|
1599
|
-
static createVariableMeasureRCN(format: string, itemReference: number, priceOrWeight: number): string {
|
|
1600
|
-
const formatLength = format.length;
|
|
1601
|
-
|
|
1602
|
-
let validFormat = formatLength === 12 || formatLength === 13;
|
|
1603
|
-
|
|
1604
|
-
let rcnPrefix = "";
|
|
1605
|
-
|
|
1606
|
-
let buildingItemReference = false;
|
|
1607
|
-
let itemReferenceString = "";
|
|
1608
|
-
let itemReferenceLength = 0;
|
|
1609
|
-
|
|
1610
|
-
let buildingPriceOrWeight = false;
|
|
1611
|
-
let priceOrWeightString = "";
|
|
1612
|
-
let priceOrWeightLength = 0;
|
|
1613
|
-
|
|
1614
|
-
let calculatePriceOrWeightCheckDigit = false;
|
|
1615
|
-
|
|
1616
|
-
// RCN may be built in almost any order, so defer to builders that will be in ordered array.
|
|
1617
|
-
const rcnPrefixBuilder = (partialRCN: string): string => partialRCN + rcnPrefix;
|
|
1618
|
-
const itemReferenceBuilder = (partialRCN: string): string => partialRCN + itemReferenceString;
|
|
1619
|
-
const priceOrWeightBuilder = (partialRCN: string): string => partialRCN + priceOrWeightString;
|
|
1620
|
-
const priceOrWeightCheckDigitBuilder = (partialRCN: string): string => partialRCN + priceOrWeightCheckDigit(priceOrWeightString);
|
|
1621
|
-
const checkDigitBuilder = (partialRCN: string): string => partialRCN + checkDigit(partialRCN);
|
|
1622
|
-
|
|
1623
|
-
const rcnBuilders = [rcnPrefixBuilder];
|
|
1624
|
-
|
|
1625
|
-
for (let index = 0; validFormat && index < formatLength; index++) {
|
|
1626
|
-
const formatChar = format.charAt(index);
|
|
1627
|
-
|
|
1628
|
-
if (index === 0) {
|
|
1629
|
-
validFormat = formatChar === "2";
|
|
1630
|
-
rcnPrefix = formatChar;
|
|
1631
|
-
} else if (formatLength === 13 && index === 1) {
|
|
1632
|
-
validFormat = NUMERIC_CREATOR.characterIndex(formatChar) !== undefined;
|
|
1633
|
-
rcnPrefix += formatChar;
|
|
1634
|
-
} else if (index === formatLength - 1) {
|
|
1635
|
-
validFormat = formatChar === "C";
|
|
1636
|
-
} else {
|
|
1637
|
-
switch (formatChar) {
|
|
1638
|
-
case "I":
|
|
1639
|
-
if (!buildingItemReference) {
|
|
1640
|
-
// Item reference can't appear more than once.
|
|
1641
|
-
validFormat = itemReferenceLength === 0;
|
|
1642
|
-
|
|
1643
|
-
buildingItemReference = true;
|
|
1644
|
-
buildingPriceOrWeight = false;
|
|
1645
|
-
|
|
1646
|
-
rcnBuilders.push(itemReferenceBuilder);
|
|
1647
|
-
}
|
|
1648
|
-
|
|
1649
|
-
itemReferenceLength++;
|
|
1650
|
-
break;
|
|
1651
|
-
|
|
1652
|
-
case "P":
|
|
1653
|
-
if (!buildingPriceOrWeight) {
|
|
1654
|
-
// Price or weight can't appear more than once.
|
|
1655
|
-
validFormat = priceOrWeightLength === 0;
|
|
1656
|
-
|
|
1657
|
-
buildingPriceOrWeight = true;
|
|
1658
|
-
buildingItemReference = false;
|
|
1659
|
-
|
|
1660
|
-
rcnBuilders.push(priceOrWeightBuilder);
|
|
1661
|
-
}
|
|
1662
|
-
|
|
1663
|
-
priceOrWeightLength++;
|
|
1664
|
-
break;
|
|
1665
|
-
|
|
1666
|
-
case "V":
|
|
1667
|
-
// Price or weight check digit can't appear more than once.
|
|
1668
|
-
validFormat = !calculatePriceOrWeightCheckDigit;
|
|
1669
|
-
|
|
1670
|
-
buildingItemReference = false;
|
|
1671
|
-
buildingPriceOrWeight = false;
|
|
1672
|
-
|
|
1673
|
-
calculatePriceOrWeightCheckDigit = true;
|
|
1674
|
-
|
|
1675
|
-
rcnBuilders.push(priceOrWeightCheckDigitBuilder);
|
|
1676
|
-
break;
|
|
1677
|
-
|
|
1678
|
-
default:
|
|
1679
|
-
validFormat = false;
|
|
1680
|
-
break;
|
|
1681
|
-
}
|
|
1682
|
-
}
|
|
1683
|
-
}
|
|
1684
|
-
|
|
1685
|
-
validFormat &&= itemReferenceLength !== 0 && priceOrWeightLength !== 0;
|
|
1686
|
-
|
|
1687
|
-
if (!validFormat) {
|
|
1688
|
-
throw new RangeError(i18nextGS1.t("IdentificationKey.invalidVariableMeasureRCNFormat"));
|
|
1689
|
-
}
|
|
1690
|
-
|
|
1691
|
-
itemReferenceString = NUMERIC_CREATOR.create(itemReferenceLength, itemReference);
|
|
1692
|
-
priceOrWeightString = NUMERIC_CREATOR.create(priceOrWeightLength, priceOrWeight);
|
|
1693
|
-
|
|
1694
|
-
rcnBuilders.push(checkDigitBuilder);
|
|
1695
|
-
|
|
1696
|
-
return rcnBuilders.reduce((partialRCN, rcnBuilder) => rcnBuilder(partialRCN), "");
|
|
1697
|
-
}
|
|
1698
|
-
}
|
|
1699
|
-
|
|
1700
|
-
/**
|
|
1701
|
-
* Non-GTIN numeric identification key creator.
|
|
1702
|
-
*/
|
|
1703
|
-
export class NonGTINNumericIdentificationKeyCreator extends Mixin(NonGTINNumericIdentificationKeyValidator, AbstractNumericIdentificationKeyCreator) {
|
|
1704
|
-
/**
|
|
1705
|
-
* Constructor. Called internally by {@link PrefixManager} non-GTIN numeric identification key creator getters;
|
|
1706
|
-
* should not be called by other code.
|
|
1707
|
-
*
|
|
1708
|
-
* @param prefixManager
|
|
1709
|
-
* Prefix manager.
|
|
1710
|
-
*
|
|
1711
|
-
* @param identificationKeyType
|
|
1712
|
-
* Identification key type.
|
|
1713
|
-
*
|
|
1714
|
-
* @param length
|
|
1715
|
-
* Length.
|
|
1716
|
-
*
|
|
1717
|
-
* @param leaderType
|
|
1718
|
-
* Leader type.
|
|
1719
|
-
*/
|
|
1720
|
-
constructor(prefixManager: PrefixManager, identificationKeyType: IdentificationKeyType, length: number, leaderType: LeaderType = LeaderType.None) {
|
|
1721
|
-
super(identificationKeyType, length, leaderType);
|
|
1722
|
-
|
|
1723
|
-
this.init(prefixManager, prefixManager.gs1CompanyPrefix);
|
|
1724
|
-
}
|
|
1725
|
-
}
|
|
1726
|
-
|
|
1727
|
-
/**
|
|
1728
|
-
* Serializable numeric identification key creator.
|
|
1729
|
-
*/
|
|
1730
|
-
export class SerializableNumericIdentificationKeyCreator extends Mixin(SerializableNumericIdentificationKeyValidator, AbstractNumericIdentificationKeyCreator) {
|
|
1731
|
-
/**
|
|
1732
|
-
* Constructor. Called internally by {@link PrefixManager} serialized numeric identification key creator getters;
|
|
1733
|
-
* should not be called by other code.
|
|
1734
|
-
*
|
|
1735
|
-
* @param prefixManager
|
|
1736
|
-
* Prefix manager.
|
|
1737
|
-
*
|
|
1738
|
-
* @param identificationKeyType
|
|
1739
|
-
* Identification key type.
|
|
1740
|
-
*
|
|
1741
|
-
* @param length
|
|
1742
|
-
* Length.
|
|
1743
|
-
*
|
|
1744
|
-
* @param serialComponentLength
|
|
1745
|
-
* Serial component length.
|
|
1746
|
-
*
|
|
1747
|
-
* @param serialComponentCharacterSet
|
|
1748
|
-
* Serial component character set.
|
|
1749
|
-
*/
|
|
1750
|
-
constructor(prefixManager: PrefixManager, identificationKeyType: IdentificationKeyType, length: number, serialComponentLength: number, serialComponentCharacterSet: ContentCharacterSet) {
|
|
1751
|
-
super(identificationKeyType, length, serialComponentLength, serialComponentCharacterSet);
|
|
1752
|
-
|
|
1753
|
-
this.init(prefixManager, prefixManager.gs1CompanyPrefix);
|
|
1754
|
-
}
|
|
1755
|
-
|
|
1756
|
-
/**
|
|
1757
|
-
* Concatenate a validated base identification key with serial component(s).
|
|
1758
|
-
*
|
|
1759
|
-
* @template TTransformerInput
|
|
1760
|
-
* Transformer input type.
|
|
1761
|
-
*
|
|
1762
|
-
* @param baseIdentificationKey
|
|
1763
|
-
* Base identification key.
|
|
1764
|
-
*
|
|
1765
|
-
* @param serialComponentOrComponents
|
|
1766
|
-
* Serial component(s).
|
|
1767
|
-
*
|
|
1768
|
-
* @returns
|
|
1769
|
-
* Serialized identification key(s).
|
|
1770
|
-
*/
|
|
1771
|
-
private concatenateValidated<TTransformerInput extends TransformerInput<string>>(baseIdentificationKey: string, serialComponentOrComponents: TTransformerInput): TransformerOutput<TTransformerInput, string> {
|
|
1772
|
-
// TODO Refactor type when https://github.com/microsoft/TypeScript/pull/56941 released.
|
|
1773
|
-
let result: string | Iterable<string>;
|
|
1774
|
-
|
|
1775
|
-
const serialComponentCreator = this.serialComponentCreator;
|
|
1776
|
-
const serialComponentValidation = this.serialComponentValidation;
|
|
1777
|
-
|
|
1778
|
-
/**
|
|
1779
|
-
* Validate a serial component and concatenate it to the base identification key.
|
|
1780
|
-
*
|
|
1781
|
-
* @param serialComponent
|
|
1782
|
-
* Serial component.
|
|
1783
|
-
*
|
|
1784
|
-
* @returns
|
|
1785
|
-
* Serialized identification key.
|
|
1786
|
-
*/
|
|
1787
|
-
function validateAndConcatenate(serialComponent: string): string {
|
|
1788
|
-
serialComponentCreator.validate(serialComponent, serialComponentValidation);
|
|
1789
|
-
|
|
1790
|
-
return baseIdentificationKey + serialComponent;
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
if (typeof serialComponentOrComponents !== "object") {
|
|
1794
|
-
result = validateAndConcatenate(serialComponentOrComponents);
|
|
1795
|
-
} else {
|
|
1796
|
-
result = mapIterable(serialComponentOrComponents, validateAndConcatenate);
|
|
1797
|
-
}
|
|
1798
|
-
|
|
1799
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Type determination is handled above.
|
|
1800
|
-
return result as TransformerOutput<TTransformerInput, string>;
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
/**
|
|
1804
|
-
* Create serialized identification key(s) with a reference based on a numeric value concatenated with serial
|
|
1805
|
-
* component(s). The value is converted to a reference of the appropriate length using {@linkcode NUMERIC_CREATOR}.
|
|
1806
|
-
*
|
|
1807
|
-
* @template TTransformerInput
|
|
1808
|
-
* Transformer input type.
|
|
1809
|
-
*
|
|
1810
|
-
* @param value
|
|
1811
|
-
* Numeric value of the reference.
|
|
1812
|
-
*
|
|
1813
|
-
* @param serialComponentOrComponents
|
|
1814
|
-
* Serial component(s).
|
|
1815
|
-
*
|
|
1816
|
-
* @param sparse
|
|
1817
|
-
* If true, the value is mapped to a sparse sequence resistant to discovery. Default is false.
|
|
1818
|
-
*
|
|
1819
|
-
* @returns
|
|
1820
|
-
* Serialized identification keys.
|
|
1821
|
-
*/
|
|
1822
|
-
createSerialized<TTransformerInput extends TransformerInput<string>>(value: number, serialComponentOrComponents: TTransformerInput, sparse?: boolean): TransformerOutput<TTransformerInput, string> {
|
|
1823
|
-
return this.concatenateValidated(this.create(value, sparse), serialComponentOrComponents);
|
|
1824
|
-
}
|
|
1825
|
-
|
|
1826
|
-
/**
|
|
1827
|
-
* Concatenate a base identification key with serial component(s).
|
|
1828
|
-
*
|
|
1829
|
-
* @template TTransformerInput
|
|
1830
|
-
* Transformer input type.
|
|
1831
|
-
*
|
|
1832
|
-
* @param baseIdentificationKey
|
|
1833
|
-
* Base identification key.
|
|
1834
|
-
*
|
|
1835
|
-
* @param serialComponentOrComponents
|
|
1836
|
-
* Serial component(s).
|
|
1837
|
-
*
|
|
1838
|
-
* @returns
|
|
1839
|
-
* Serialized identification key(s).
|
|
1840
|
-
*/
|
|
1841
|
-
concatenate<TTransformerInput extends TransformerInput<string>>(baseIdentificationKey: string, serialComponentOrComponents: TTransformerInput): TransformerOutput<TTransformerInput, string> {
|
|
1842
|
-
this.validate(baseIdentificationKey);
|
|
1843
|
-
|
|
1844
|
-
return this.concatenateValidated(baseIdentificationKey, serialComponentOrComponents);
|
|
1845
|
-
}
|
|
1846
|
-
}
|
|
1847
|
-
|
|
1848
|
-
/**
|
|
1849
|
-
* Non-numeric identification key creator.
|
|
1850
|
-
*/
|
|
1851
|
-
export class NonNumericIdentificationKeyCreator extends Mixin(NonNumericIdentificationKeyValidator, AbstractIdentificationKeyCreator) {
|
|
1852
|
-
/**
|
|
1853
|
-
* Reference validation parameters.
|
|
1854
|
-
*/
|
|
1855
|
-
private readonly _referenceValidation: CharacterSetValidation;
|
|
1856
|
-
|
|
1857
|
-
/**
|
|
1858
|
-
* Constructor. Called internally by {@link PrefixManager} non-numeric identification key creator getters; should
|
|
1859
|
-
* not be called by other code.
|
|
1860
|
-
*
|
|
1861
|
-
* @param prefixManager
|
|
1862
|
-
* Prefix manager.
|
|
1863
|
-
*
|
|
1864
|
-
* @param identificationKeyType
|
|
1865
|
-
* Identification key type.
|
|
1866
|
-
*
|
|
1867
|
-
* @param length
|
|
1868
|
-
* Length.
|
|
1869
|
-
*
|
|
1870
|
-
* @param referenceCharacterSet
|
|
1871
|
-
* Reference character set.
|
|
1872
|
-
*
|
|
1873
|
-
* @param requiresCheckCharacterPair
|
|
1874
|
-
* True if the identification key requires a check character pair.
|
|
1875
|
-
*/
|
|
1876
|
-
constructor(prefixManager: PrefixManager, identificationKeyType: IdentificationKeyType, length: number, referenceCharacterSet: ContentCharacterSet, requiresCheckCharacterPair = false) {
|
|
1877
|
-
super(identificationKeyType, length, referenceCharacterSet, requiresCheckCharacterPair);
|
|
1878
|
-
|
|
1879
|
-
this.init(prefixManager, prefixManager.gs1CompanyPrefix, 2 * Number(requiresCheckCharacterPair));
|
|
1880
|
-
|
|
1881
|
-
this._referenceValidation = {
|
|
1882
|
-
minimumLength: 1,
|
|
1883
|
-
// Maximum reference length has to account for prefix and check character pair.
|
|
1884
|
-
maximumLength: this.referenceLength,
|
|
1885
|
-
component: () => i18nextGS1.t("IdentificationKey.reference")
|
|
1886
|
-
};
|
|
1887
|
-
}
|
|
1888
|
-
|
|
1889
|
-
/**
|
|
1890
|
-
* Get the reference validation parameters.
|
|
1891
|
-
*/
|
|
1892
|
-
protected get referenceValidation(): CharacterSetValidation {
|
|
1893
|
-
return this._referenceValidation;
|
|
1894
|
-
}
|
|
1895
|
-
|
|
1896
|
-
/**
|
|
1897
|
-
* Create identification key(s) with reference(s).
|
|
1898
|
-
*
|
|
1899
|
-
* @template TTransformerInput
|
|
1900
|
-
* Transformer input type.
|
|
1901
|
-
*
|
|
1902
|
-
* @param referenceOrReferences
|
|
1903
|
-
* Reference(s).
|
|
1904
|
-
*
|
|
1905
|
-
* @returns
|
|
1906
|
-
* Identification key(s).
|
|
1907
|
-
*/
|
|
1908
|
-
create<TTransformerInput extends TransformerInput<string>>(referenceOrReferences: TTransformerInput): TransformerOutput<TTransformerInput, string> {
|
|
1909
|
-
// TODO Refactor type when https://github.com/microsoft/TypeScript/pull/56941 released.
|
|
1910
|
-
let result: string | Iterable<string>;
|
|
1911
|
-
|
|
1912
|
-
const referenceCreator = this.referenceCreator;
|
|
1913
|
-
const referenceValidation = this.referenceValidation;
|
|
1914
|
-
const prefix = this.prefix;
|
|
1915
|
-
const requiresCheckCharacterPair = this.requiresCheckCharacterPair;
|
|
1916
|
-
|
|
1917
|
-
/**
|
|
1918
|
-
* Validate a reference and create an identification key.
|
|
1919
|
-
*
|
|
1920
|
-
* @param reference
|
|
1921
|
-
* Reference.
|
|
1922
|
-
*
|
|
1923
|
-
* @returns
|
|
1924
|
-
* Identification key.
|
|
1925
|
-
*/
|
|
1926
|
-
function validateAndCreate(reference: string): string {
|
|
1927
|
-
referenceCreator.validate(reference, referenceValidation);
|
|
1928
|
-
|
|
1929
|
-
const partialIdentificationKey = prefix + reference;
|
|
1930
|
-
|
|
1931
|
-
return requiresCheckCharacterPair ? partialIdentificationKey + checkCharacterPair(partialIdentificationKey) : partialIdentificationKey;
|
|
1932
|
-
}
|
|
1933
|
-
|
|
1934
|
-
if (typeof referenceOrReferences !== "object") {
|
|
1935
|
-
result = validateAndCreate(referenceOrReferences);
|
|
1936
|
-
} else {
|
|
1937
|
-
result = mapIterable(referenceOrReferences, validateAndCreate);
|
|
1938
|
-
}
|
|
1939
|
-
|
|
1940
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Type determination is handled above.
|
|
1941
|
-
return result as TransformerOutput<TTransformerInput, string>;
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1944
|
-
|
|
1945
|
-
/**
|
|
1946
|
-
* Prefix validation parameters.
|
|
1947
|
-
*/
|
|
1948
|
-
interface PrefixValidation extends CharacterSetValidation {
|
|
1949
|
-
/**
|
|
1950
|
-
* Minimum length.
|
|
1951
|
-
*/
|
|
1952
|
-
minimumLength: number;
|
|
1953
|
-
|
|
1954
|
-
/**
|
|
1955
|
-
* Maximum length.
|
|
1956
|
-
*/
|
|
1957
|
-
maximumLength: number;
|
|
1958
|
-
|
|
1959
|
-
/**
|
|
1960
|
-
* Callback to localized prefix type name.
|
|
1961
|
-
*/
|
|
1962
|
-
component: () => string;
|
|
1963
|
-
}
|
|
1964
|
-
|
|
1965
|
-
/**
|
|
1966
|
-
* Prefix manager. This is the core class for identification key creation.
|
|
1967
|
-
*
|
|
1968
|
-
* A prefix manager may be created for any {@link PrefixType | prefix type}. As most applications work with a limited
|
|
1969
|
-
* number of prefixes for creating identification keys, prefix managers are cached in memory and may be reused.
|
|
1970
|
-
*
|
|
1971
|
-
* Prefix managers are keyed by GS1 Company Prefix, so the prefix type that is requested may not match the prefix type
|
|
1972
|
-
* of the returned prefix manager. For example, the prefix manager for GS1 Company Prefix 0614141 is identical to the
|
|
1973
|
-
* one for U.P.C. Company Prefix 614141, with the prefix type equal to {@link PrefixType.UPCCompanyPrefix} and the
|
|
1974
|
-
* prefix equal to "614141".
|
|
1975
|
-
*
|
|
1976
|
-
* To support the creation of sparse identification keys, a prefix manager maintains a {@link tweakFactor | tweak
|
|
1977
|
-
* factor} which is used, along with a type-specific multiplier, as the tweak when creating numeric identification keys.
|
|
1978
|
-
* The default tweak factor is the numeric value of the GS1 Company Prefix representation of the prefix preceded by '1'
|
|
1979
|
-
* to ensure uniqueness (i.e., so that prefixes 0 N1 N2 N3... and N1 N2 N3... produce different tweak factors). This is
|
|
1980
|
-
* usually sufficient for obfuscation, but as the sparse creation algorithm is reversible and as the GS1 Company Prefix
|
|
1981
|
-
* is discoverable via {@link https://www.gs1.org/services/verified-by-gs1 | Verified by GS1}, a user-defined tweak
|
|
1982
|
-
* factor should be used if a higher degree of obfuscation is required. When using a tweak factor other than the
|
|
1983
|
-
* default, care should be taken to restore it when resuming the application. A tweak factor of 0 creates a straight
|
|
1984
|
-
* sequence.
|
|
1985
|
-
*/
|
|
1986
|
-
export class PrefixManager {
|
|
1987
|
-
/**
|
|
1988
|
-
* Cached prefix managers, keyed by GS1 Company Prefix.
|
|
1989
|
-
*/
|
|
1990
|
-
private static readonly PREFIX_MANAGERS_MAP = new Map<string, PrefixManager>();
|
|
1991
|
-
|
|
1992
|
-
/**
|
|
1993
|
-
* GS1 Company Prefix minimum length.
|
|
1994
|
-
*/
|
|
1995
|
-
static readonly GS1_COMPANY_PREFIX_MINIMUM_LENGTH = 4;
|
|
1996
|
-
|
|
1997
|
-
/**
|
|
1998
|
-
* GS1 Company Prefix maximum length.
|
|
1999
|
-
*/
|
|
2000
|
-
static readonly GS1_COMPANY_PREFIX_MAXIMUM_LENGTH = 12;
|
|
2001
|
-
|
|
2002
|
-
/**
|
|
2003
|
-
* U.P.C. Company Prefix minimum length.
|
|
2004
|
-
*/
|
|
2005
|
-
static readonly UPC_COMPANY_PREFIX_MINIMUM_LENGTH = 6;
|
|
2006
|
-
|
|
2007
|
-
/**
|
|
2008
|
-
* U.P.C. Company Prefix maximum length.
|
|
2009
|
-
*/
|
|
2010
|
-
static readonly UPC_COMPANY_PREFIX_MAXIMUM_LENGTH = 11;
|
|
2011
|
-
|
|
2012
|
-
/**
|
|
2013
|
-
* GS1-8 Prefix minimum length.
|
|
2014
|
-
*/
|
|
2015
|
-
static readonly GS1_8_PREFIX_MINIMUM_LENGTH = 2;
|
|
2016
|
-
|
|
2017
|
-
/**
|
|
2018
|
-
* GS1-8 Prefix maximum length.
|
|
2019
|
-
*/
|
|
2020
|
-
static readonly GS1_8_PREFIX_MAXIMUM_LENGTH = 7;
|
|
2021
|
-
|
|
2022
|
-
/**
|
|
2023
|
-
* Validation parameters for GS1 Company Prefix.
|
|
2024
|
-
*/
|
|
2025
|
-
private static readonly GS1_COMPANY_PREFIX_VALIDATION: PrefixValidation = {
|
|
2026
|
-
minimumLength: PrefixManager.GS1_COMPANY_PREFIX_MINIMUM_LENGTH,
|
|
2027
|
-
maximumLength: PrefixManager.GS1_COMPANY_PREFIX_MAXIMUM_LENGTH,
|
|
2028
|
-
component: () => i18nextGS1.t("Prefix.gs1CompanyPrefix")
|
|
2029
|
-
};
|
|
2030
|
-
|
|
2031
|
-
/**
|
|
2032
|
-
* Validation parameters for U.P.C. Company Prefix expressed as GS1 Company Prefix.
|
|
2033
|
-
*/
|
|
2034
|
-
private static readonly UPC_COMPANY_PREFIX_AS_GS1_COMPANY_PREFIX_VALIDATION: PrefixValidation = {
|
|
2035
|
-
minimumLength: PrefixManager.UPC_COMPANY_PREFIX_MINIMUM_LENGTH + 1,
|
|
2036
|
-
maximumLength: PrefixManager.UPC_COMPANY_PREFIX_MAXIMUM_LENGTH + 1,
|
|
2037
|
-
component: () => i18nextGS1.t("Prefix.gs1CompanyPrefix")
|
|
2038
|
-
};
|
|
2039
|
-
|
|
2040
|
-
/**
|
|
2041
|
-
* Validation parameters for GS1-8 Prefix expressed as GS1 Company Prefix.
|
|
2042
|
-
*/
|
|
2043
|
-
private static readonly GS1_8_PREFIX_AS_GS1_COMPANY_PREFIX_VALIDATION: PrefixValidation = {
|
|
2044
|
-
minimumLength: PrefixManager.GS1_8_PREFIX_MINIMUM_LENGTH + 5,
|
|
2045
|
-
maximumLength: PrefixManager.GS1_8_PREFIX_MAXIMUM_LENGTH + 5,
|
|
2046
|
-
component: () => i18nextGS1.t("Prefix.gs1CompanyPrefix")
|
|
2047
|
-
};
|
|
2048
|
-
|
|
2049
|
-
/**
|
|
2050
|
-
* Validation parameters for U.P.C. Company Prefix.
|
|
2051
|
-
*/
|
|
2052
|
-
private static readonly UPC_COMPANY_PREFIX_VALIDATION: PrefixValidation = {
|
|
2053
|
-
minimumLength: PrefixManager.UPC_COMPANY_PREFIX_MINIMUM_LENGTH,
|
|
2054
|
-
maximumLength: PrefixManager.UPC_COMPANY_PREFIX_MAXIMUM_LENGTH,
|
|
2055
|
-
component: () => i18nextGS1.t("Prefix.upcCompanyPrefix")
|
|
2056
|
-
};
|
|
2057
|
-
|
|
2058
|
-
/**
|
|
2059
|
-
* Validation parameters for GS1-8 Prefix.
|
|
2060
|
-
*/
|
|
2061
|
-
private static readonly GS1_8_PREFIX_VALIDATION: PrefixValidation = {
|
|
2062
|
-
minimumLength: PrefixManager.GS1_8_PREFIX_MINIMUM_LENGTH,
|
|
2063
|
-
maximumLength: PrefixManager.GS1_8_PREFIX_MAXIMUM_LENGTH,
|
|
2064
|
-
component: () => i18nextGS1.t("Prefix.gs18Prefix")
|
|
2065
|
-
};
|
|
2066
|
-
|
|
2067
|
-
/**
|
|
2068
|
-
* Creator tweak factors. Different numeric identification key types have different tweak factors so that sparse
|
|
2069
|
-
* creation generates different sequences for each.
|
|
2070
|
-
*/
|
|
2071
|
-
private static readonly CREATOR_TWEAK_FACTORS_MAP: ReadonlyMap<IdentificationKeyType, bigint> = new Map([
|
|
2072
|
-
[IdentificationKeyType.GTIN, 1987n],
|
|
2073
|
-
[IdentificationKeyType.GLN, 4241n],
|
|
2074
|
-
[IdentificationKeyType.SSCC, 8087n],
|
|
2075
|
-
[IdentificationKeyType.GRAI, 3221n],
|
|
2076
|
-
[IdentificationKeyType.GSRN, 2341n],
|
|
2077
|
-
[IdentificationKeyType.GDTI, 7333n],
|
|
2078
|
-
[IdentificationKeyType.GSIN, 5623n],
|
|
2079
|
-
[IdentificationKeyType.GCN, 6869n]
|
|
2080
|
-
]);
|
|
2081
|
-
|
|
2082
|
-
/**
|
|
2083
|
-
* Normalized prefix type.
|
|
2084
|
-
*/
|
|
2085
|
-
private readonly _prefixType: PrefixType;
|
|
2086
|
-
|
|
2087
|
-
/**
|
|
2088
|
-
* Normalized prefix.
|
|
2089
|
-
*/
|
|
2090
|
-
private readonly _prefix: string;
|
|
2091
|
-
|
|
2092
|
-
/**
|
|
2093
|
-
* Prefix as GS1 Company Prefix.
|
|
2094
|
-
*/
|
|
2095
|
-
private readonly _gs1CompanyPrefix: string;
|
|
2096
|
-
|
|
2097
|
-
/**
|
|
2098
|
-
* U.P.C. Company Prefix if prefix type is {@link PrefixType.UPCCompanyPrefix}.
|
|
2099
|
-
*/
|
|
2100
|
-
private readonly _upcCompanyPrefix: string | undefined;
|
|
2101
|
-
|
|
2102
|
-
/**
|
|
2103
|
-
* GS1-8 Prefix if prefix type is {@link PrefixType.GS18Prefix}.
|
|
2104
|
-
*/
|
|
2105
|
-
private readonly _gs18Prefix: string | undefined;
|
|
2106
|
-
|
|
2107
|
-
/**
|
|
2108
|
-
* Default tweak factor.
|
|
2109
|
-
*/
|
|
2110
|
-
private readonly _defaultTweakFactor: bigint;
|
|
2111
|
-
|
|
2112
|
-
/**
|
|
2113
|
-
* Tweak factor.
|
|
2114
|
-
*/
|
|
2115
|
-
private _tweakFactor = 0n;
|
|
2116
|
-
|
|
2117
|
-
/**
|
|
2118
|
-
* Cached identification key creators.
|
|
2119
|
-
*/
|
|
2120
|
-
private readonly _identificationKeyCreatorsMap = new Map<IdentificationKeyType, IdentificationKeyCreator>();
|
|
2121
|
-
|
|
2122
|
-
/**
|
|
2123
|
-
* Constructor.
|
|
2124
|
-
*
|
|
2125
|
-
* @param gs1CompanyPrefix
|
|
2126
|
-
* GS1 Company Prefix.
|
|
2127
|
-
*/
|
|
2128
|
-
private constructor(gs1CompanyPrefix: string) {
|
|
2129
|
-
this._gs1CompanyPrefix = gs1CompanyPrefix;
|
|
2130
|
-
|
|
2131
|
-
// Determine the prefix type and populate the remaining fields.
|
|
2132
|
-
if (!gs1CompanyPrefix.startsWith("0")) {
|
|
2133
|
-
this._prefixType = PrefixType.GS1CompanyPrefix;
|
|
2134
|
-
this._prefix = this._gs1CompanyPrefix;
|
|
2135
|
-
} else if (!gs1CompanyPrefix.startsWith("00000")) {
|
|
2136
|
-
this._prefixType = PrefixType.UPCCompanyPrefix;
|
|
2137
|
-
this._upcCompanyPrefix = gs1CompanyPrefix.substring(1);
|
|
2138
|
-
this._prefix = this._upcCompanyPrefix;
|
|
2139
|
-
} else {
|
|
2140
|
-
this._prefixType = PrefixType.GS18Prefix;
|
|
2141
|
-
this._gs18Prefix = gs1CompanyPrefix.substring(5);
|
|
2142
|
-
this._prefix = this._gs18Prefix;
|
|
2143
|
-
}
|
|
2144
|
-
|
|
2145
|
-
// Default tweak factor is the numeric value of the GS1 Company Prefix preceded by '1'.
|
|
2146
|
-
this._defaultTweakFactor = BigInt(`1${this.gs1CompanyPrefix}`);
|
|
2147
|
-
|
|
2148
|
-
this.resetTweakFactor();
|
|
2149
|
-
}
|
|
2150
|
-
|
|
2151
|
-
/**
|
|
2152
|
-
* Get the prefix type.
|
|
2153
|
-
*/
|
|
2154
|
-
get prefixType(): PrefixType {
|
|
2155
|
-
return this._prefixType;
|
|
2156
|
-
}
|
|
2157
|
-
|
|
2158
|
-
/**
|
|
2159
|
-
* Get the prefix.
|
|
2160
|
-
*/
|
|
2161
|
-
get prefix(): string {
|
|
2162
|
-
return this._prefix;
|
|
2163
|
-
}
|
|
2164
|
-
|
|
2165
|
-
/**
|
|
2166
|
-
* Get the GS1 Company Prefix.
|
|
2167
|
-
*/
|
|
2168
|
-
get gs1CompanyPrefix(): string {
|
|
2169
|
-
return this._gs1CompanyPrefix;
|
|
2170
|
-
}
|
|
2171
|
-
|
|
2172
|
-
/**
|
|
2173
|
-
* Get the U.P.C. Company Prefix if prefix type is {@link PrefixType.UPCCompanyPrefix} or undefined if not.
|
|
2174
|
-
*/
|
|
2175
|
-
get upcCompanyPrefix(): string | undefined {
|
|
2176
|
-
return this._upcCompanyPrefix;
|
|
2177
|
-
}
|
|
2178
|
-
|
|
2179
|
-
/**
|
|
2180
|
-
* Get the GS1-8 Prefix if prefix type is {@link PrefixType.GS18Prefix} or undefined if not.
|
|
2181
|
-
*/
|
|
2182
|
-
get gs18Prefix(): string | undefined {
|
|
2183
|
-
return this._gs18Prefix;
|
|
2184
|
-
}
|
|
2185
|
-
|
|
2186
|
-
/**
|
|
2187
|
-
* Set the tweak for an identification key creator if it's a numeric identification key creator.
|
|
2188
|
-
*
|
|
2189
|
-
* @param creator
|
|
2190
|
-
* Identification key creator.
|
|
2191
|
-
*/
|
|
2192
|
-
private setCreatorTweak(creator: IdentificationKeyCreator): void {
|
|
2193
|
-
const creatorTweakFactor = PrefixManager.CREATOR_TWEAK_FACTORS_MAP.get(creator.identificationKeyType);
|
|
2194
|
-
|
|
2195
|
-
// Creator tweak factor is defined for numeric identification keys only.
|
|
2196
|
-
if (creatorTweakFactor !== undefined) {
|
|
2197
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion,no-param-reassign -- Explicit cast without testing is necessary as "instanceof" doesn't work for mixin types. Method purpose is to set the tweak.
|
|
2198
|
-
(creator as AbstractNumericIdentificationKeyCreator).tweak = this.tweakFactor * creatorTweakFactor;
|
|
2199
|
-
}
|
|
2200
|
-
}
|
|
2201
|
-
|
|
2202
|
-
/**
|
|
2203
|
-
* Get the tweak factor.
|
|
2204
|
-
*/
|
|
2205
|
-
get tweakFactor(): bigint {
|
|
2206
|
-
return this._tweakFactor;
|
|
2207
|
-
}
|
|
2208
|
-
|
|
2209
|
-
/**
|
|
2210
|
-
* Set the tweak factor.
|
|
2211
|
-
*
|
|
2212
|
-
* @param value
|
|
2213
|
-
* Tweak factor.
|
|
2214
|
-
*/
|
|
2215
|
-
set tweakFactor(value: number | bigint) {
|
|
2216
|
-
const tweakFactor = BigInt(value);
|
|
2217
|
-
|
|
2218
|
-
if (this._tweakFactor !== tweakFactor) {
|
|
2219
|
-
this._tweakFactor = tweakFactor;
|
|
2220
|
-
|
|
2221
|
-
for (const creator of this._identificationKeyCreatorsMap.values()) {
|
|
2222
|
-
this.setCreatorTweak(creator);
|
|
2223
|
-
}
|
|
2224
|
-
}
|
|
2225
|
-
}
|
|
2226
|
-
|
|
2227
|
-
/**
|
|
2228
|
-
* Reset the tweak factor to its default (numeric value of the GS1 Company Prefix preceded by '1').
|
|
2229
|
-
*/
|
|
2230
|
-
resetTweakFactor(): void {
|
|
2231
|
-
this.tweakFactor = this._defaultTweakFactor;
|
|
2232
|
-
}
|
|
2233
|
-
|
|
2234
|
-
/**
|
|
2235
|
-
* Get a prefix manager.
|
|
2236
|
-
*
|
|
2237
|
-
* @param prefixType
|
|
2238
|
-
* Prefix type.
|
|
2239
|
-
*
|
|
2240
|
-
* @param prefix
|
|
2241
|
-
* Prefix.
|
|
2242
|
-
*
|
|
2243
|
-
* @returns
|
|
2244
|
-
* Prefix manager with normalized prefix type and prefix.
|
|
2245
|
-
*/
|
|
2246
|
-
static get(prefixType: PrefixType, prefix: string): PrefixManager {
|
|
2247
|
-
PrefixManager.validatePrefix(prefixType, true, true, prefix);
|
|
2248
|
-
|
|
2249
|
-
let gs1CompanyPrefix: string;
|
|
2250
|
-
|
|
2251
|
-
switch (prefixType) {
|
|
2252
|
-
case PrefixType.GS1CompanyPrefix:
|
|
2253
|
-
gs1CompanyPrefix = prefix;
|
|
2254
|
-
break;
|
|
2255
|
-
|
|
2256
|
-
case PrefixType.UPCCompanyPrefix:
|
|
2257
|
-
gs1CompanyPrefix = "0" + prefix;
|
|
2258
|
-
break;
|
|
2259
|
-
|
|
2260
|
-
case PrefixType.GS18Prefix:
|
|
2261
|
-
gs1CompanyPrefix = "00000" + prefix;
|
|
2262
|
-
break;
|
|
2263
|
-
|
|
2264
|
-
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- Method may be called by unsafe means.
|
|
2265
|
-
default:
|
|
2266
|
-
throw new RangeError(i18nextGS1.t("Prefix.invalidPrefixType"));
|
|
2267
|
-
}
|
|
2268
|
-
|
|
2269
|
-
let prefixManager = PrefixManager.PREFIX_MANAGERS_MAP.get(gs1CompanyPrefix);
|
|
2270
|
-
|
|
2271
|
-
if (prefixManager === undefined) {
|
|
2272
|
-
prefixManager = new PrefixManager(gs1CompanyPrefix);
|
|
2273
|
-
PrefixManager.PREFIX_MANAGERS_MAP.set(gs1CompanyPrefix, prefixManager);
|
|
2274
|
-
}
|
|
2275
|
-
|
|
2276
|
-
return prefixManager;
|
|
2277
|
-
}
|
|
2278
|
-
|
|
2279
|
-
/**
|
|
2280
|
-
* Validate a prefix.
|
|
2281
|
-
*
|
|
2282
|
-
* @param prefixType
|
|
2283
|
-
* Prefix type.
|
|
2284
|
-
*
|
|
2285
|
-
* @param allowUPCCompanyPrefix
|
|
2286
|
-
* If true, a U.P.C. Company Prefix expressed as a GS1 Company Prefix is permitted.
|
|
2287
|
-
*
|
|
2288
|
-
* @param allowGS18Prefix
|
|
2289
|
-
* If true, a GS1-8 Prefix expressed as a GS1 Company Prefix is permitted.
|
|
2290
|
-
*
|
|
2291
|
-
* @param prefix
|
|
2292
|
-
* Prefix.
|
|
2293
|
-
*
|
|
2294
|
-
* @param isFromIdentificationKey
|
|
2295
|
-
* If true, the prefix is from an identification key and should be trimmed before its character set is validated.
|
|
2296
|
-
*
|
|
2297
|
-
* @param isNumericIdentificationKey
|
|
2298
|
-
* If true, the prefix is from a numeric identification key and its character set will be validated by the caller.
|
|
2299
|
-
*
|
|
2300
|
-
* @param positionOffset
|
|
2301
|
-
* Position offset within a larger string.
|
|
2302
|
-
*/
|
|
2303
|
-
static validatePrefix(prefixType: PrefixType, allowUPCCompanyPrefix: boolean, allowGS18Prefix: boolean, prefix: string, isFromIdentificationKey = false, isNumericIdentificationKey = false, positionOffset?: number): void {
|
|
2304
|
-
let baseValidation: PrefixValidation;
|
|
2305
|
-
|
|
2306
|
-
// Validate the prefix type and determine the prefix validation parameters.
|
|
2307
|
-
switch (prefixType) {
|
|
2308
|
-
case PrefixType.GS1CompanyPrefix:
|
|
2309
|
-
if (!prefix.startsWith("0")) {
|
|
2310
|
-
baseValidation = PrefixManager.GS1_COMPANY_PREFIX_VALIDATION;
|
|
2311
|
-
} else if (!prefix.startsWith("00000")) {
|
|
2312
|
-
if (!allowUPCCompanyPrefix) {
|
|
2313
|
-
throw new RangeError(i18nextGS1.t("Prefix.gs1CompanyPrefixCantStartWith0"));
|
|
2314
|
-
}
|
|
2315
|
-
|
|
2316
|
-
baseValidation = PrefixManager.UPC_COMPANY_PREFIX_AS_GS1_COMPANY_PREFIX_VALIDATION;
|
|
2317
|
-
} else if (!prefix.startsWith("000000")) {
|
|
2318
|
-
if (!allowGS18Prefix) {
|
|
2319
|
-
throw new RangeError(i18nextGS1.t("Prefix.gs1CompanyPrefixCantStartWith00000"));
|
|
2320
|
-
}
|
|
2321
|
-
|
|
2322
|
-
baseValidation = PrefixManager.GS1_8_PREFIX_AS_GS1_COMPANY_PREFIX_VALIDATION;
|
|
2323
|
-
} else {
|
|
2324
|
-
throw new RangeError(i18nextGS1.t("Prefix.gs1CompanyPrefixCantStartWith000000"));
|
|
2325
|
-
}
|
|
2326
|
-
break;
|
|
2327
|
-
|
|
2328
|
-
case PrefixType.UPCCompanyPrefix:
|
|
2329
|
-
if (prefix.startsWith("0000")) {
|
|
2330
|
-
throw new RangeError(i18nextGS1.t("Prefix.upcCompanyPrefixCantStartWith0000"));
|
|
2331
|
-
}
|
|
2332
|
-
|
|
2333
|
-
baseValidation = PrefixManager.UPC_COMPANY_PREFIX_VALIDATION;
|
|
2334
|
-
break;
|
|
2335
|
-
|
|
2336
|
-
case PrefixType.GS18Prefix:
|
|
2337
|
-
if (prefix.startsWith("0")) {
|
|
2338
|
-
throw new RangeError(i18nextGS1.t("Prefix.gs18PrefixCantStartWith0"));
|
|
2339
|
-
}
|
|
2340
|
-
|
|
2341
|
-
baseValidation = PrefixManager.GS1_8_PREFIX_VALIDATION;
|
|
2342
|
-
break;
|
|
2343
|
-
}
|
|
2344
|
-
|
|
2345
|
-
const mergedValidation: PrefixValidation = {
|
|
2346
|
-
...baseValidation,
|
|
2347
|
-
positionOffset
|
|
2348
|
-
};
|
|
2349
|
-
|
|
2350
|
-
// If from key and numeric, key validation will take care of character set validation.
|
|
2351
|
-
if (!isFromIdentificationKey) {
|
|
2352
|
-
NUMERIC_CREATOR.validate(prefix, mergedValidation);
|
|
2353
|
-
} else if (!isNumericIdentificationKey) {
|
|
2354
|
-
// Validate only the minimum length, allowing at least one character for the (possibly non-numeric) reference.
|
|
2355
|
-
NUMERIC_CREATOR.validate(prefix.substring(0, Math.min(mergedValidation.minimumLength, prefix.length - 1)), mergedValidation);
|
|
2356
|
-
}
|
|
2357
|
-
}
|
|
2358
|
-
|
|
2359
|
-
/**
|
|
2360
|
-
* Get an identification key creator.
|
|
2361
|
-
*
|
|
2362
|
-
* @param identificationKeyType
|
|
2363
|
-
* Identification key type.
|
|
2364
|
-
*
|
|
2365
|
-
* @param constructorCallback
|
|
2366
|
-
* Constructor callback.
|
|
2367
|
-
*
|
|
2368
|
-
* @returns
|
|
2369
|
-
* Identification key creator.
|
|
2370
|
-
*/
|
|
2371
|
-
private getIdentificationKeyCreator<TIdentificationKeyCreator extends IdentificationKeyCreator>(identificationKeyType: IdentificationKeyType, constructorCallback: () => TIdentificationKeyCreator): TIdentificationKeyCreator {
|
|
2372
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Type is paired with constructor callback.
|
|
2373
|
-
let creator = this._identificationKeyCreatorsMap.get(identificationKeyType) as TIdentificationKeyCreator | undefined;
|
|
2374
|
-
|
|
2375
|
-
if (creator === undefined) {
|
|
2376
|
-
if (this.prefixType === PrefixType.GS18Prefix && identificationKeyType !== IdentificationKeyType.GTIN) {
|
|
2377
|
-
throw new RangeError(i18nextGS1.t("Prefix.identificationKeyTypeNotSupportedByGS18Prefix", {
|
|
2378
|
-
identificationKeyType
|
|
2379
|
-
}));
|
|
2380
|
-
}
|
|
2381
|
-
|
|
2382
|
-
creator = constructorCallback();
|
|
2383
|
-
|
|
2384
|
-
this.setCreatorTweak(creator);
|
|
2385
|
-
|
|
2386
|
-
this._identificationKeyCreatorsMap.set(identificationKeyType, creator);
|
|
2387
|
-
}
|
|
2388
|
-
|
|
2389
|
-
return creator;
|
|
2390
|
-
}
|
|
2391
|
-
|
|
2392
|
-
/**
|
|
2393
|
-
* Get non-GTIN numeric identification key creator.
|
|
2394
|
-
*
|
|
2395
|
-
* @param validator
|
|
2396
|
-
* Validator on which identification key creator is based.
|
|
2397
|
-
*
|
|
2398
|
-
* @returns
|
|
2399
|
-
* Identification key creator.
|
|
2400
|
-
*/
|
|
2401
|
-
private getNonGTINNumericIdentificationKeyCreator(validator: NonGTINNumericIdentificationKeyValidator): NonGTINNumericIdentificationKeyCreator {
|
|
2402
|
-
return this.getIdentificationKeyCreator(validator.identificationKeyType, () => new NonGTINNumericIdentificationKeyCreator(this, validator.identificationKeyType, validator.length, validator.leaderType));
|
|
2403
|
-
}
|
|
2404
|
-
|
|
2405
|
-
/**
|
|
2406
|
-
* Get serialized numeric identification key creator.
|
|
2407
|
-
*
|
|
2408
|
-
* @param validator
|
|
2409
|
-
* Validator on which identification key creator is based.
|
|
2410
|
-
*
|
|
2411
|
-
* @returns
|
|
2412
|
-
* Identification key creator.
|
|
2413
|
-
*/
|
|
2414
|
-
private getSerializableNumericIdentificationKeyCreator(validator: SerializableNumericIdentificationKeyValidator): SerializableNumericIdentificationKeyCreator {
|
|
2415
|
-
return this.getIdentificationKeyCreator(validator.identificationKeyType, () => new SerializableNumericIdentificationKeyCreator(this, validator.identificationKeyType, validator.length, validator.serialComponentLength, validator.serialComponentCharacterSet));
|
|
2416
|
-
}
|
|
2417
|
-
|
|
2418
|
-
/**
|
|
2419
|
-
* Get non-numeric identification key creator.
|
|
2420
|
-
*
|
|
2421
|
-
* @param validator
|
|
2422
|
-
* Validator on which identification key creator is based.
|
|
2423
|
-
*
|
|
2424
|
-
* @returns
|
|
2425
|
-
* Identification key creator.
|
|
2426
|
-
*/
|
|
2427
|
-
private getNonNumericIdentificationKeyCreator(validator: NonNumericIdentificationKeyValidator): NonNumericIdentificationKeyCreator {
|
|
2428
|
-
return this.getIdentificationKeyCreator(validator.identificationKeyType, () => new NonNumericIdentificationKeyCreator(this, validator.identificationKeyType, validator.length, validator.referenceCharacterSet, validator.requiresCheckCharacterPair));
|
|
2429
|
-
}
|
|
2430
|
-
|
|
2431
|
-
/**
|
|
2432
|
-
* Get GTIN creator.
|
|
2433
|
-
*/
|
|
2434
|
-
get gtinCreator(): GTINCreator {
|
|
2435
|
-
return this.getIdentificationKeyCreator(IdentificationKeyType.GTIN, () => {
|
|
2436
|
-
let gtinType: GTINType;
|
|
2437
|
-
|
|
2438
|
-
switch (this.prefixType) {
|
|
2439
|
-
case PrefixType.GS1CompanyPrefix:
|
|
2440
|
-
gtinType = GTINType.GTIN13;
|
|
2441
|
-
break;
|
|
2442
|
-
|
|
2443
|
-
case PrefixType.UPCCompanyPrefix:
|
|
2444
|
-
gtinType = GTINType.GTIN12;
|
|
2445
|
-
break;
|
|
2446
|
-
|
|
2447
|
-
case PrefixType.GS18Prefix:
|
|
2448
|
-
gtinType = GTINType.GTIN8;
|
|
2449
|
-
break;
|
|
2450
|
-
}
|
|
2451
|
-
|
|
2452
|
-
return new GTINCreator(this, gtinType);
|
|
2453
|
-
});
|
|
2454
|
-
}
|
|
2455
|
-
|
|
2456
|
-
/**
|
|
2457
|
-
* Get GLN creator.
|
|
2458
|
-
*/
|
|
2459
|
-
get glnCreator(): NonGTINNumericIdentificationKeyCreator {
|
|
2460
|
-
return this.getNonGTINNumericIdentificationKeyCreator(GLN_VALIDATOR);
|
|
2461
|
-
}
|
|
2462
|
-
|
|
2463
|
-
/**
|
|
2464
|
-
* Get SSCC creator.
|
|
2465
|
-
*/
|
|
2466
|
-
get ssccCreator(): NonGTINNumericIdentificationKeyCreator {
|
|
2467
|
-
return this.getNonGTINNumericIdentificationKeyCreator(SSCC_VALIDATOR);
|
|
2468
|
-
}
|
|
2469
|
-
|
|
2470
|
-
/**
|
|
2471
|
-
* Get GRAI creator.
|
|
2472
|
-
*/
|
|
2473
|
-
get graiCreator(): SerializableNumericIdentificationKeyCreator {
|
|
2474
|
-
return this.getSerializableNumericIdentificationKeyCreator(GRAI_VALIDATOR);
|
|
2475
|
-
}
|
|
2476
|
-
|
|
2477
|
-
/**
|
|
2478
|
-
* Get GIAI creator.
|
|
2479
|
-
*/
|
|
2480
|
-
get giaiCreator(): NonNumericIdentificationKeyCreator {
|
|
2481
|
-
return this.getNonNumericIdentificationKeyCreator(GIAI_VALIDATOR);
|
|
2482
|
-
}
|
|
2483
|
-
|
|
2484
|
-
/**
|
|
2485
|
-
* Get GSRN creator.
|
|
2486
|
-
*/
|
|
2487
|
-
get gsrnCreator(): NonGTINNumericIdentificationKeyCreator {
|
|
2488
|
-
return this.getNonGTINNumericIdentificationKeyCreator(GSRN_VALIDATOR);
|
|
2489
|
-
}
|
|
2490
|
-
|
|
2491
|
-
/**
|
|
2492
|
-
* Get GDTI creator.
|
|
2493
|
-
*/
|
|
2494
|
-
get gdtiCreator(): SerializableNumericIdentificationKeyCreator {
|
|
2495
|
-
return this.getSerializableNumericIdentificationKeyCreator(GDTI_VALIDATOR);
|
|
2496
|
-
}
|
|
2497
|
-
|
|
2498
|
-
/**
|
|
2499
|
-
* Get GINC creator.
|
|
2500
|
-
*/
|
|
2501
|
-
get gincCreator(): NonNumericIdentificationKeyCreator {
|
|
2502
|
-
return this.getNonNumericIdentificationKeyCreator(GINC_VALIDATOR);
|
|
2503
|
-
}
|
|
2504
|
-
|
|
2505
|
-
/**
|
|
2506
|
-
* Get GSIN creator.
|
|
2507
|
-
*/
|
|
2508
|
-
get gsinCreator(): NonGTINNumericIdentificationKeyCreator {
|
|
2509
|
-
return this.getNonGTINNumericIdentificationKeyCreator(GSIN_VALIDATOR);
|
|
2510
|
-
}
|
|
2511
|
-
|
|
2512
|
-
/**
|
|
2513
|
-
* Get GCN creator.
|
|
2514
|
-
*/
|
|
2515
|
-
get gcnCreator(): SerializableNumericIdentificationKeyCreator {
|
|
2516
|
-
return this.getSerializableNumericIdentificationKeyCreator(GCN_VALIDATOR);
|
|
2517
|
-
}
|
|
2518
|
-
|
|
2519
|
-
/**
|
|
2520
|
-
* Get CPID creator.
|
|
2521
|
-
*/
|
|
2522
|
-
get cpidCreator(): NonNumericIdentificationKeyCreator {
|
|
2523
|
-
return this.getNonNumericIdentificationKeyCreator(CPID_VALIDATOR);
|
|
2524
|
-
}
|
|
2525
|
-
|
|
2526
|
-
/**
|
|
2527
|
-
* Get GMN creator.
|
|
2528
|
-
*/
|
|
2529
|
-
get gmnCreator(): NonNumericIdentificationKeyCreator {
|
|
2530
|
-
return this.getNonNumericIdentificationKeyCreator(GMN_VALIDATOR);
|
|
2531
|
-
}
|
|
2532
|
-
}
|