@aidc-toolkit/gs1 1.0.40-beta → 1.0.42-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/README.md +2 -19
- package/dist/gcp-length-cache.d.ts +6 -1
- package/dist/gcp-length-cache.d.ts.map +1 -1
- package/dist/gcp-length-cache.js +7 -2
- package/dist/gcp-length-cache.js.map +1 -1
- package/dist/gcp-length-tree.d.ts +33 -0
- package/dist/gcp-length-tree.d.ts.map +1 -0
- package/dist/gcp-length-tree.js +13 -0
- package/dist/gcp-length-tree.js.map +1 -0
- package/dist/gcp-length.d.ts +63 -49
- package/dist/gcp-length.d.ts.map +1 -1
- package/dist/gcp-length.js +319 -262
- package/dist/gcp-length.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/locale/en/locale-resources.d.ts +2 -0
- package/dist/locale/en/locale-resources.d.ts.map +1 -1
- package/dist/locale/en/locale-resources.js +3 -1
- package/dist/locale/en/locale-resources.js.map +1 -1
- package/dist/locale/fr/locale-resources.d.ts +2 -0
- package/dist/locale/fr/locale-resources.d.ts.map +1 -1
- package/dist/locale/fr/locale-resources.js +3 -1
- package/dist/locale/fr/locale-resources.js.map +1 -1
- package/dist/prefix-manager.d.ts +0 -35
- package/dist/prefix-manager.d.ts.map +1 -1
- package/dist/prefix-manager.js +0 -56
- package/dist/prefix-manager.js.map +1 -1
- package/package.json +4 -4
- package/src/gcp-length-cache.ts +7 -2
- package/src/gcp-length-tree.ts +39 -0
- package/src/gcp-length.ts +348 -297
- package/src/index.ts +3 -1
- package/src/locale/en/locale-resources.ts +3 -1
- package/src/locale/fr/locale-resources.ts +3 -1
- package/src/prefix-manager.ts +0 -65
- package/test/gcp-length.test.ts +39 -31
- package/tsconfig-src.tsbuildinfo +1 -1
package/dist/gcp-length.js
CHANGED
|
@@ -1,300 +1,357 @@
|
|
|
1
1
|
import { omit } from "@aidc-toolkit/core";
|
|
2
2
|
import { isGCPLengthData } from "./gcp-length-data.js";
|
|
3
|
+
import * as GCPLengthTree from "./gcp-length-tree.js";
|
|
3
4
|
import { GTINLengths } from "./gtin-length.js";
|
|
4
5
|
import { GTINValidator } from "./gtin-validator.js";
|
|
5
6
|
import { IdentifierTypes } from "./identifier-type.js";
|
|
6
7
|
import { IdentifierValidators, isNumericIdentifierValidator } from "./identifier-validators.js";
|
|
7
8
|
import { LeaderTypes } from "./leader-type.js";
|
|
9
|
+
import { i18nextGS1 } from "./locale/i18n.js";
|
|
8
10
|
/**
|
|
9
|
-
*
|
|
11
|
+
* GS1 Company Prefix length service. The constructor takes a {@linkcode GCPLengthCache} object, which is responsible
|
|
12
|
+
* for managing the cache and source.
|
|
10
13
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
14
|
+
* The first step is to load the GS1 Company Prefix length data. This is done using the
|
|
15
|
+
* {@linkcode GCPLength.load | load()} method, which works as follows:
|
|
13
16
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
* Entry in binary data to indicate that child node is undefined.
|
|
22
|
-
*/
|
|
23
|
-
const BINARY_UNDEFINED = 0x0F;
|
|
24
|
-
/**
|
|
25
|
-
* Entry in binary data to indicate that child node is a branch.
|
|
26
|
-
*/
|
|
27
|
-
const BINARY_BRANCH = 0x0E;
|
|
28
|
-
/**
|
|
29
|
-
* Build the GS1 Company Prefix length tree from a binary data array.
|
|
30
|
-
*
|
|
31
|
-
* @param binaryData
|
|
32
|
-
* Binary data array.
|
|
33
|
-
*
|
|
34
|
-
* @param childNodes
|
|
35
|
-
* Child nodes array to fill.
|
|
17
|
+
* - If the next check date/time is in the future, the method returns immediately, regardless of whether any data is
|
|
18
|
+
* available. It does this to prevent a large number of requests to the source in the event of a failure.
|
|
19
|
+
* - Otherwise, if the cache date/time is undefined or less than the source date/time, it loads from the source,
|
|
20
|
+
* converts the data if necessary, and updates the cache.
|
|
21
|
+
* - Otherwise, it continues with the cached data.
|
|
22
|
+
* - The next check date/time is updated to the later of the source date/time plus one week and the current date/time
|
|
23
|
+
* plus one day.
|
|
36
24
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
25
|
+
* The base class implementation of the `GCPLengthCache` manages only the cache itself, and it requires an
|
|
26
|
+
* application-provided storage implementation. The source is expected to be either a {@linkcode GCPLengthData} object
|
|
27
|
+
* (created via another cache implementation) or a {@linkcode GCPLengthSourceJSON} object, which is the format of the
|
|
28
|
+
* file provided by GS1.
|
|
39
29
|
*
|
|
40
|
-
* @
|
|
41
|
-
*
|
|
30
|
+
* Once the data is loaded, the {@linkcode GCPLength.lengthOf | lengthOf()} method can be used to get the length of a
|
|
31
|
+
* GS1 Company Prefix for an identifier type and identifier.
|
|
42
32
|
*/
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
33
|
+
export class GCPLength {
|
|
34
|
+
/**
|
|
35
|
+
* Entry in binary data to indicate that child node is undefined.
|
|
36
|
+
*/
|
|
37
|
+
static #BINARY_UNDEFINED = 0x0F;
|
|
38
|
+
/**
|
|
39
|
+
* Entry in binary data to indicate that child node is a branch.
|
|
40
|
+
*/
|
|
41
|
+
static #BINARY_BRANCH = 0x0E;
|
|
42
|
+
/**
|
|
43
|
+
* GS1 Company Prefix length cache.
|
|
44
|
+
*/
|
|
45
|
+
#gcpLengthCache;
|
|
46
|
+
/**
|
|
47
|
+
* GS1 Company Prefix length tree root.
|
|
48
|
+
*/
|
|
49
|
+
#root;
|
|
50
|
+
/**
|
|
51
|
+
* Constructor.
|
|
52
|
+
*
|
|
53
|
+
* @param gcpLengthCache
|
|
54
|
+
* GS1 Company Prefix length cache.
|
|
55
|
+
*/
|
|
56
|
+
constructor(gcpLengthCache) {
|
|
57
|
+
this.#gcpLengthCache = gcpLengthCache;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get the GS1 Company Prefix length tree root.
|
|
61
|
+
*
|
|
62
|
+
* @returns
|
|
63
|
+
* GS1 Company Prefix length tree root.
|
|
64
|
+
*/
|
|
65
|
+
get root() {
|
|
66
|
+
if (this.#root === undefined) {
|
|
67
|
+
throw new RangeError(i18nextGS1.t("GCPLength.gs1CompanyPrefixLengthDataNotLoaded"));
|
|
68
|
+
}
|
|
69
|
+
return this.#root;
|
|
51
70
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Get the date/time the GS1 Company Prefix length data was last updated.
|
|
73
|
+
*/
|
|
74
|
+
get dateTime() {
|
|
75
|
+
return this.root.dateTime;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get the disclaimer for the GS1 Company Prefix length data.
|
|
79
|
+
*/
|
|
80
|
+
get disclaimer() {
|
|
81
|
+
return this.root.disclaimer;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Build the GS1 Company Prefix length tree from a binary data array.
|
|
85
|
+
*
|
|
86
|
+
* @param binaryData
|
|
87
|
+
* Binary data array.
|
|
88
|
+
*
|
|
89
|
+
* @param childNodes
|
|
90
|
+
* Child nodes array to fill.
|
|
91
|
+
*
|
|
92
|
+
* @param startIndex
|
|
93
|
+
* Start index into binary data array.
|
|
94
|
+
*
|
|
95
|
+
* @returns
|
|
96
|
+
* End index into binary data array.
|
|
97
|
+
*/
|
|
98
|
+
static #fromBinary(binaryData, childNodes, startIndex) {
|
|
99
|
+
let endIndex = startIndex;
|
|
100
|
+
const decompressedLengths = new Array(10);
|
|
101
|
+
// Decompress lengths for the child nodes.
|
|
102
|
+
for (let childNodeIndex = 0; childNodeIndex < 10; childNodeIndex += 2) {
|
|
103
|
+
const byte = binaryData[endIndex++];
|
|
104
|
+
decompressedLengths[childNodeIndex] = byte >> 4;
|
|
105
|
+
decompressedLengths[childNodeIndex + 1] = byte & 0x0F;
|
|
106
|
+
}
|
|
107
|
+
for (let childNodeIndex = 0; childNodeIndex < 10; childNodeIndex++) {
|
|
108
|
+
const length = decompressedLengths[childNodeIndex];
|
|
109
|
+
if (length !== GCPLength.#BINARY_UNDEFINED) {
|
|
110
|
+
let childNode;
|
|
111
|
+
if (length === GCPLength.#BINARY_BRANCH) {
|
|
112
|
+
const childNodes = [];
|
|
113
|
+
endIndex = GCPLength.#fromBinary(binaryData, childNodes, endIndex);
|
|
114
|
+
childNode = {
|
|
115
|
+
childNodes
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
childNode = {
|
|
120
|
+
length
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
// eslint-disable-next-line no-param-reassign -- Purpose is to build tree.
|
|
124
|
+
childNodes[childNodeIndex] = childNode;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return endIndex;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Add an entry to the tree by recursively walking the tree to a leaf.
|
|
131
|
+
*
|
|
132
|
+
* @param branch
|
|
133
|
+
* Current (interim) branch under construction.
|
|
134
|
+
*
|
|
135
|
+
* @param prefix
|
|
136
|
+
* Remainder of current prefix.
|
|
137
|
+
*
|
|
138
|
+
* @param length
|
|
139
|
+
* Current prefix length.
|
|
140
|
+
*
|
|
141
|
+
* @returns
|
|
142
|
+
* Number of branches added; used to determine size of binary array.
|
|
143
|
+
*/
|
|
144
|
+
static #addEntry(branch, prefix, length) {
|
|
145
|
+
const digit = Number(prefix.charAt(0));
|
|
146
|
+
const existingChildNode = branch.childNodes[digit];
|
|
147
|
+
let branchesAdded = 0;
|
|
148
|
+
if (prefix.length !== 1) {
|
|
149
|
+
let childBranch;
|
|
150
|
+
if (existingChildNode === undefined) {
|
|
151
|
+
childBranch = {
|
|
58
152
|
childNodes: []
|
|
59
153
|
};
|
|
60
|
-
|
|
154
|
+
branchesAdded++;
|
|
61
155
|
}
|
|
62
156
|
else {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
157
|
+
if (GCPLengthTree.isLeaf(existingChildNode)) {
|
|
158
|
+
// File format error or application bug; localization not necessary.
|
|
159
|
+
throw new Error("Overlapping entry");
|
|
160
|
+
}
|
|
161
|
+
childBranch = existingChildNode;
|
|
66
162
|
}
|
|
67
163
|
// eslint-disable-next-line no-param-reassign -- Purpose is to build tree.
|
|
68
|
-
childNodes[
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return endIndex;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Add an entry to the tree by recursively walking the tree to a leaf.
|
|
75
|
-
*
|
|
76
|
-
* @param branch
|
|
77
|
-
* Current branch.
|
|
78
|
-
*
|
|
79
|
-
* @param prefix
|
|
80
|
-
* Remainder of current prefix.
|
|
81
|
-
*
|
|
82
|
-
* @param length
|
|
83
|
-
* Current prefix length.
|
|
84
|
-
*
|
|
85
|
-
* @returns
|
|
86
|
-
* Number of branches added; used to determine size of binary array.
|
|
87
|
-
*/
|
|
88
|
-
function addEntry(branch, prefix, length) {
|
|
89
|
-
const digit = Number(prefix.charAt(0));
|
|
90
|
-
const existingChildNode = branch.childNodes[digit];
|
|
91
|
-
let branchesAdded = 0;
|
|
92
|
-
if (prefix.length !== 1) {
|
|
93
|
-
let childBranch;
|
|
94
|
-
if (existingChildNode === undefined) {
|
|
95
|
-
childBranch = {
|
|
96
|
-
childNodes: []
|
|
97
|
-
};
|
|
98
|
-
branchesAdded++;
|
|
164
|
+
branch.childNodes[digit] = childBranch;
|
|
165
|
+
// Continue with remainder of prefix.
|
|
166
|
+
branchesAdded += GCPLength.#addEntry(childBranch, prefix.substring(1), length);
|
|
99
167
|
}
|
|
100
168
|
else {
|
|
101
|
-
if (
|
|
169
|
+
if (existingChildNode !== undefined) {
|
|
102
170
|
// File format error or application bug; localization not necessary.
|
|
103
|
-
throw new Error("
|
|
171
|
+
throw new Error("Duplicate entry");
|
|
104
172
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
// Continue with remainder of prefix.
|
|
110
|
-
branchesAdded += addEntry(childBranch, prefix.substring(1), length);
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
if (existingChildNode !== undefined) {
|
|
114
|
-
// File format error or application bug; localization not necessary.
|
|
115
|
-
throw new Error("Duplicate entry");
|
|
173
|
+
// eslint-disable-next-line no-param-reassign -- Purpose is to build tree.
|
|
174
|
+
branch.childNodes[digit] = {
|
|
175
|
+
length
|
|
176
|
+
};
|
|
116
177
|
}
|
|
117
|
-
|
|
118
|
-
branch.childNodes[digit] = {
|
|
119
|
-
length
|
|
120
|
-
};
|
|
178
|
+
return branchesAdded;
|
|
121
179
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
function childNodeValue(childNode) {
|
|
135
|
-
return childNode !== undefined ? isLeaf(childNode) ? childNode.length : BINARY_BRANCH : BINARY_UNDEFINED;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Add a branch to a binary data array.
|
|
139
|
-
*
|
|
140
|
-
* @param binaryData
|
|
141
|
-
* Binary data array.
|
|
142
|
-
*
|
|
143
|
-
* @param branch
|
|
144
|
-
* Branch.
|
|
145
|
-
*
|
|
146
|
-
* @param startIndex
|
|
147
|
-
* Start index into binary data array.
|
|
148
|
-
*
|
|
149
|
-
* @returns
|
|
150
|
-
* End index into binary data array.
|
|
151
|
-
*/
|
|
152
|
-
function toBinary(binaryData, branch, startIndex) {
|
|
153
|
-
let endIndex = startIndex;
|
|
154
|
-
const childNodes = branch.childNodes;
|
|
155
|
-
// Add length or non-leaf indicators, compressing 10 nibbles into 5 bytes.
|
|
156
|
-
for (let childNodeIndex = 0; childNodeIndex < 10; childNodeIndex += 2) {
|
|
157
|
-
// eslint-disable-next-line no-param-reassign -- Purpose is to build array.
|
|
158
|
-
binaryData[endIndex++] = (childNodeValue(childNodes[childNodeIndex]) << 4) | childNodeValue(childNodes[childNodeIndex + 1]);
|
|
180
|
+
/**
|
|
181
|
+
* Get the length of a child node if defined and it's a leaf, otherwise mark it with 0x0E if defined (branch) or 0x0F
|
|
182
|
+
* (no branch) if not.
|
|
183
|
+
*
|
|
184
|
+
* @param childNode
|
|
185
|
+
* Child node.
|
|
186
|
+
*
|
|
187
|
+
* @returns
|
|
188
|
+
* Child node length, 0x0E (branch), or 0x0F (undefined).
|
|
189
|
+
*/
|
|
190
|
+
static #childNodeValue(childNode) {
|
|
191
|
+
return childNode !== undefined ? GCPLengthTree.isLeaf(childNode) ? childNode.length : GCPLength.#BINARY_BRANCH : GCPLength.#BINARY_UNDEFINED;
|
|
159
192
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Add a branch to a binary data array.
|
|
195
|
+
*
|
|
196
|
+
* @param binaryData
|
|
197
|
+
* Binary data array.
|
|
198
|
+
*
|
|
199
|
+
* @param branch
|
|
200
|
+
* Branch.
|
|
201
|
+
*
|
|
202
|
+
* @param startIndex
|
|
203
|
+
* Start index into binary data array.
|
|
204
|
+
*
|
|
205
|
+
* @returns
|
|
206
|
+
* End index into binary data array.
|
|
207
|
+
*/
|
|
208
|
+
static #toBinary(binaryData, branch, startIndex) {
|
|
209
|
+
let endIndex = startIndex;
|
|
210
|
+
const childNodes = branch.childNodes;
|
|
211
|
+
// Add length or non-leaf indicators, compressing 10 nibbles into 5 bytes.
|
|
212
|
+
for (let childNodeIndex = 0; childNodeIndex < 10; childNodeIndex += 2) {
|
|
213
|
+
// eslint-disable-next-line no-param-reassign -- Purpose is to build array.
|
|
214
|
+
binaryData[endIndex++] = (GCPLength.#childNodeValue(childNodes[childNodeIndex]) << 4) | GCPLength.#childNodeValue(childNodes[childNodeIndex + 1]);
|
|
164
215
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
* Add days to a date.
|
|
170
|
-
*
|
|
171
|
-
* @param date
|
|
172
|
-
* Date.
|
|
173
|
-
*
|
|
174
|
-
* @param days
|
|
175
|
-
* Days.
|
|
176
|
-
*
|
|
177
|
-
* @returns
|
|
178
|
-
* New date.
|
|
179
|
-
*/
|
|
180
|
-
function addDays(date, days) {
|
|
181
|
-
const futureDate = new Date(date);
|
|
182
|
-
futureDate.setDate(futureDate.getDate() + days);
|
|
183
|
-
return futureDate;
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Load the GS1 Company Prefix length data.
|
|
187
|
-
*
|
|
188
|
-
* @param gcpLengthCache
|
|
189
|
-
* GS1 Company Prefix length cache.
|
|
190
|
-
*
|
|
191
|
-
* @returns
|
|
192
|
-
* Root of tree.
|
|
193
|
-
*/
|
|
194
|
-
export async function loadData(gcpLengthCache) {
|
|
195
|
-
let root = undefined;
|
|
196
|
-
let nextCheckDateTime = await gcpLengthCache.nextCheckDateTime;
|
|
197
|
-
let cacheDateTime = await gcpLengthCache.cacheDateTime;
|
|
198
|
-
const now = new Date();
|
|
199
|
-
const tomorrow = addDays(now, 1);
|
|
200
|
-
if (nextCheckDateTime === undefined || nextCheckDateTime.getTime() <= now.getTime()) {
|
|
201
|
-
const sourceDateTime = await gcpLengthCache.sourceDateTime;
|
|
202
|
-
if (cacheDateTime === undefined || cacheDateTime.getTime() < sourceDateTime.getTime()) {
|
|
203
|
-
const sourceData = await gcpLengthCache.sourceData;
|
|
204
|
-
let cacheData;
|
|
205
|
-
if (isGCPLengthData(sourceData)) {
|
|
206
|
-
root = {
|
|
207
|
-
dateTime: sourceData.dateTime,
|
|
208
|
-
disclaimer: sourceData.disclaimer,
|
|
209
|
-
childNodes: []
|
|
210
|
-
};
|
|
211
|
-
fromBinary(sourceData.data, root.childNodes, 0);
|
|
212
|
-
cacheData = sourceData;
|
|
216
|
+
// Process child nodes.
|
|
217
|
+
for (const childNode of childNodes) {
|
|
218
|
+
if (childNode !== undefined && !GCPLengthTree.isLeaf(childNode)) {
|
|
219
|
+
endIndex = GCPLength.#toBinary(binaryData, childNode, endIndex);
|
|
213
220
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
221
|
+
}
|
|
222
|
+
return endIndex;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Add days to a date.
|
|
226
|
+
*
|
|
227
|
+
* @param date
|
|
228
|
+
* Date.
|
|
229
|
+
*
|
|
230
|
+
* @param days
|
|
231
|
+
* Days.
|
|
232
|
+
*
|
|
233
|
+
* @returns
|
|
234
|
+
* Future date.
|
|
235
|
+
*/
|
|
236
|
+
static #addDays(date, days) {
|
|
237
|
+
const futureDate = new Date(date);
|
|
238
|
+
futureDate.setDate(futureDate.getDate() + days);
|
|
239
|
+
return futureDate;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Load the GS1 Company Prefix length data.
|
|
243
|
+
*/
|
|
244
|
+
async load() {
|
|
245
|
+
let root = undefined;
|
|
246
|
+
const gcpLengthCache = this.#gcpLengthCache;
|
|
247
|
+
let nextCheckDateTime = await gcpLengthCache.nextCheckDateTime;
|
|
248
|
+
let cacheDateTime = await gcpLengthCache.cacheDateTime;
|
|
249
|
+
const now = new Date();
|
|
250
|
+
const tomorrow = GCPLength.#addDays(now, 1);
|
|
251
|
+
if (nextCheckDateTime === undefined || nextCheckDateTime.getTime() <= now.getTime()) {
|
|
252
|
+
const sourceDateTime = await gcpLengthCache.sourceDateTime;
|
|
253
|
+
if (cacheDateTime === undefined || cacheDateTime.getTime() < sourceDateTime.getTime()) {
|
|
254
|
+
const sourceData = await gcpLengthCache.sourceData;
|
|
255
|
+
let cacheData;
|
|
256
|
+
if (isGCPLengthData(sourceData)) {
|
|
257
|
+
const childNodes = [];
|
|
258
|
+
GCPLength.#fromBinary(sourceData.data, childNodes, 0);
|
|
259
|
+
root = {
|
|
260
|
+
dateTime: sourceData.dateTime,
|
|
261
|
+
disclaimer: sourceData.disclaimer,
|
|
262
|
+
childNodes
|
|
263
|
+
};
|
|
264
|
+
cacheData = sourceData;
|
|
233
265
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
266
|
+
else {
|
|
267
|
+
const interimRoot = {
|
|
268
|
+
childNodes: []
|
|
269
|
+
};
|
|
270
|
+
let branchesAdded = 1;
|
|
271
|
+
for (const entry of sourceData.GCPPrefixFormatList.entry) {
|
|
272
|
+
branchesAdded += GCPLength.#addEntry(interimRoot, entry.prefix, entry.gcpLength);
|
|
273
|
+
}
|
|
274
|
+
root = {
|
|
275
|
+
dateTime: new Date(sourceData.GCPPrefixFormatList.date),
|
|
276
|
+
// Join disclaimer as a single string.
|
|
277
|
+
disclaimer: `${sourceData._disclaimer.reduce((lines, line) => {
|
|
278
|
+
if (lines.length === 0 || lines[lines.length - 1] === "" || line === "") {
|
|
279
|
+
lines.push(line);
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
// Lines are part of the same paragraph.
|
|
283
|
+
lines.push(`${lines.pop()} ${line}`);
|
|
284
|
+
}
|
|
285
|
+
return lines;
|
|
286
|
+
}, []).join("\n")}\n`,
|
|
287
|
+
...interimRoot
|
|
288
|
+
};
|
|
289
|
+
// Each branch has ten (some possibly undefined) entries, two per byte.
|
|
290
|
+
const data = new Uint8Array(branchesAdded * 5);
|
|
291
|
+
GCPLength.#toBinary(data, root, 0);
|
|
292
|
+
cacheData = {
|
|
293
|
+
...omit(root, "childNodes"),
|
|
294
|
+
data
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
// Next check date/time is a week from source date/time or tomorrow, whichever is later.
|
|
298
|
+
nextCheckDateTime = GCPLength.#addDays(sourceDateTime, 7);
|
|
299
|
+
if (nextCheckDateTime.getTime() < tomorrow.getTime()) {
|
|
300
|
+
nextCheckDateTime = tomorrow;
|
|
301
|
+
}
|
|
302
|
+
cacheDateTime = sourceDateTime;
|
|
303
|
+
await gcpLengthCache.update(nextCheckDateTime, cacheDateTime, cacheData);
|
|
241
304
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
nextCheckDateTime = tomorrow;
|
|
305
|
+
else {
|
|
306
|
+
// Next check date/time is tomorrow.
|
|
307
|
+
await gcpLengthCache.update(tomorrow);
|
|
246
308
|
}
|
|
247
|
-
cacheDateTime = sourceDateTime;
|
|
248
|
-
await gcpLengthCache.update(nextCheckDateTime, cacheDateTime, cacheData);
|
|
249
309
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
await gcpLengthCache.
|
|
310
|
+
// Root is undefined if cache data is still valid or retrying after prior failure.
|
|
311
|
+
if (root === undefined && cacheDateTime !== undefined) {
|
|
312
|
+
const cacheData = await gcpLengthCache.cacheData;
|
|
313
|
+
const childNodes = [];
|
|
314
|
+
GCPLength.#fromBinary(cacheData.data, childNodes, 0);
|
|
315
|
+
root = {
|
|
316
|
+
...omit(cacheData, "data"),
|
|
317
|
+
childNodes
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
// Update root only if successful.
|
|
321
|
+
if (root !== undefined) {
|
|
322
|
+
this.#root = root;
|
|
253
323
|
}
|
|
254
324
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
identifierPrefix = GTINValidator.normalize(identifier).padStart(GTINLengths.GTIN14, "0").substring(1);
|
|
286
|
-
}
|
|
287
|
-
else {
|
|
288
|
-
const identifierValidator = IdentifierValidators[identifierType];
|
|
289
|
-
identifierValidator.validate(identifier);
|
|
290
|
-
identifierPrefix = !isNumericIdentifierValidator(identifierValidator) || identifierValidator.leaderType !== LeaderTypes.ExtensionDigit ? identifier : identifier.substring(1);
|
|
291
|
-
}
|
|
292
|
-
let node = root;
|
|
293
|
-
let digitIndex = 0;
|
|
294
|
-
// Traverse tree until exhausted or at a leaf.
|
|
295
|
-
while (node !== undefined && !isLeaf(node)) {
|
|
296
|
-
node = node.childNodes[Number(identifierPrefix.charAt(digitIndex++))];
|
|
325
|
+
/**
|
|
326
|
+
* Get the length of a GS1 Company Prefix for an identifier.
|
|
327
|
+
*
|
|
328
|
+
* @param identifierType
|
|
329
|
+
* Identifier type.
|
|
330
|
+
*
|
|
331
|
+
* @param identifier
|
|
332
|
+
* Identifier.
|
|
333
|
+
*
|
|
334
|
+
* @returns
|
|
335
|
+
* Length of GS1 Company Prefix, 0 if not a GS1 Company Prefix, or -1 if not found.
|
|
336
|
+
*/
|
|
337
|
+
lengthOf(identifierType, identifier) {
|
|
338
|
+
let identifierPrefix;
|
|
339
|
+
if (identifierType === IdentifierTypes.GTIN) {
|
|
340
|
+
// Normalize the GTIN, pad to 14 digits, and extract the identifier prefix at the first character.
|
|
341
|
+
identifierPrefix = GTINValidator.normalize(identifier).padStart(GTINLengths.GTIN14, "0").substring(1);
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
const identifierValidator = IdentifierValidators[identifierType];
|
|
345
|
+
identifierValidator.validate(identifier);
|
|
346
|
+
identifierPrefix = !isNumericIdentifierValidator(identifierValidator) || identifierValidator.leaderType !== LeaderTypes.ExtensionDigit ? identifier : identifier.substring(1);
|
|
347
|
+
}
|
|
348
|
+
let node = this.root;
|
|
349
|
+
let digitIndex = 0;
|
|
350
|
+
// Traverse tree until exhausted or at a leaf.
|
|
351
|
+
while (node !== undefined && !GCPLengthTree.isLeaf(node)) {
|
|
352
|
+
node = node.childNodes[Number(identifierPrefix.charAt(digitIndex++))];
|
|
353
|
+
}
|
|
354
|
+
return node?.length ?? -1;
|
|
297
355
|
}
|
|
298
|
-
return node?.length ?? -1;
|
|
299
356
|
}
|
|
300
357
|
//# sourceMappingURL=gcp-length.js.map
|