@aidc-toolkit/gs1 1.0.28-beta → 1.0.32-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/dist/gcp-length-cache.d.ts +42 -0
  2. package/dist/gcp-length-cache.d.ts.map +1 -0
  3. package/dist/gcp-length-cache.js +96 -0
  4. package/dist/gcp-length-cache.js.map +1 -0
  5. package/dist/gcp-length-data.d.ts +54 -0
  6. package/dist/gcp-length-data.d.ts.map +1 -0
  7. package/dist/gcp-length-data.js +29 -0
  8. package/dist/gcp-length-data.js.map +1 -0
  9. package/dist/gcp-length.d.ts +61 -0
  10. package/dist/gcp-length.d.ts.map +1 -0
  11. package/dist/gcp-length.js +301 -0
  12. package/dist/gcp-length.js.map +1 -0
  13. package/dist/gtin-creator.d.ts +0 -17
  14. package/dist/gtin-creator.d.ts.map +1 -1
  15. package/dist/gtin-creator.js +1 -93
  16. package/dist/gtin-creator.js.map +1 -1
  17. package/dist/gtin-validator.d.ts +1 -46
  18. package/dist/gtin-validator.d.ts.map +1 -1
  19. package/dist/gtin-validator.js +31 -125
  20. package/dist/gtin-validator.js.map +1 -1
  21. package/dist/identifier-validator.d.ts +1 -4
  22. package/dist/identifier-validator.d.ts.map +1 -1
  23. package/dist/identifier-validator.js +2 -5
  24. package/dist/identifier-validator.js.map +1 -1
  25. package/dist/index.d.ts +5 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +4 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/locale/en/locale-resources.d.ts +2 -1
  30. package/dist/locale/en/locale-resources.d.ts.map +1 -1
  31. package/dist/locale/en/locale-resources.js +3 -2
  32. package/dist/locale/en/locale-resources.js.map +1 -1
  33. package/dist/locale/fr/locale-resources.d.ts +2 -1
  34. package/dist/locale/fr/locale-resources.d.ts.map +1 -1
  35. package/dist/locale/fr/locale-resources.js +3 -2
  36. package/dist/locale/fr/locale-resources.js.map +1 -1
  37. package/dist/locale/i18n.d.ts +0 -3
  38. package/dist/locale/i18n.d.ts.map +1 -1
  39. package/dist/locale/i18n.js +2 -5
  40. package/dist/locale/i18n.js.map +1 -1
  41. package/dist/non-numeric-identifier-validator.js +1 -1
  42. package/dist/non-numeric-identifier-validator.js.map +1 -1
  43. package/dist/numeric-identifier-validator.js +2 -2
  44. package/dist/numeric-identifier-validator.js.map +1 -1
  45. package/dist/prefix-manager.d.ts +35 -0
  46. package/dist/prefix-manager.d.ts.map +1 -1
  47. package/dist/prefix-manager.js +56 -0
  48. package/dist/prefix-manager.js.map +1 -1
  49. package/dist/prefix-validator.d.ts +5 -4
  50. package/dist/prefix-validator.d.ts.map +1 -1
  51. package/dist/prefix-validator.js +18 -22
  52. package/dist/prefix-validator.js.map +1 -1
  53. package/dist/serializable-numeric-identifier-validator.d.ts +26 -0
  54. package/dist/serializable-numeric-identifier-validator.d.ts.map +1 -1
  55. package/dist/serializable-numeric-identifier-validator.js +19 -0
  56. package/dist/serializable-numeric-identifier-validator.js.map +1 -1
  57. package/dist/variable-measure.d.ts +68 -0
  58. package/dist/variable-measure.d.ts.map +1 -0
  59. package/dist/variable-measure.js +210 -0
  60. package/dist/variable-measure.js.map +1 -0
  61. package/dist/verified-by-gs1.d.ts +22 -0
  62. package/dist/verified-by-gs1.d.ts.map +1 -0
  63. package/dist/verified-by-gs1.js +46 -0
  64. package/dist/verified-by-gs1.js.map +1 -0
  65. package/package.json +8 -8
  66. package/src/gcp-length-cache.ts +117 -0
  67. package/src/gcp-length-data.ts +68 -0
  68. package/src/gcp-length.ts +418 -0
  69. package/src/gtin-creator.ts +1 -117
  70. package/src/gtin-validator.ts +42 -173
  71. package/src/identifier-validator.ts +2 -5
  72. package/src/index.ts +7 -1
  73. package/src/locale/en/locale-resources.ts +3 -2
  74. package/src/locale/fr/locale-resources.ts +3 -2
  75. package/src/locale/i18n.ts +2 -5
  76. package/src/non-numeric-identifier-validator.ts +1 -1
  77. package/src/numeric-identifier-validator.ts +2 -2
  78. package/src/prefix-manager.ts +65 -0
  79. package/src/prefix-validator.ts +19 -23
  80. package/src/serializable-numeric-identifier-validator.ts +36 -0
  81. package/src/variable-measure.ts +268 -0
  82. package/src/verified-by-gs1.ts +54 -0
  83. package/test/creator.test.ts +5 -5
  84. package/test/data/gcpprefixformatlist-1.json +662625 -0
  85. package/test/data/gcpprefixformatlist-2.json +735431 -0
  86. package/test/gcp-length.test.ts +405 -0
  87. package/test/gtin-creator.ts +4 -4
  88. package/test/gtin-validator.test.ts +205 -113
  89. package/test/gtin-validator.ts +30 -0
  90. package/test/identifier-creator.ts +6 -6
  91. package/test/non-numeric-identifier-creator.ts +0 -8
  92. package/test/non-serializable-numeric-identifier-creator.ts +4 -54
  93. package/test/numeric-identifier-creator.ts +4 -4
  94. package/test/prefix-manager.test.ts +5 -5
  95. package/test/serializable-numeric-identifier-creator.ts +32 -19
  96. package/test/validator.test.ts +6 -6
  97. package/test/variable-measure-rcn.test.ts +63 -68
  98. package/test/verified-by-gs1.test.ts +55 -0
  99. package/tsconfig-src.json +7 -1
  100. package/tsconfig-src.tsbuildinfo +1 -0
  101. package/tsconfig-tsup.json +7 -0
  102. package/tsconfig.json +1 -0
@@ -0,0 +1,210 @@
1
+ import { NUMERIC_CREATOR } from "@aidc-toolkit/utility";
2
+ import { checkDigit, hasValidCheckDigit, isValidPriceOrWeightCheckDigit, priceOrWeightCheckDigit } from "./check.js";
3
+ import { i18nextGS1 } from "./locale/i18n.js";
4
+ /**
5
+ * Variable measure trade item support functions.
6
+ */
7
+ // eslint-disable-next-line @typescript-eslint/no-extraneous-class -- Wrapper for future functionality.
8
+ export class VariableMeasure {
9
+ /**
10
+ * Parse a Restricted Circulation Number (RCN) using a variable measure trade item format. The format is a 12- or
11
+ * 13-character string (for RCN-12 or RCN-13 respectively), containing the following:
12
+ *
13
+ * - '2' - The first character of the RCN.
14
+ * - '0'-'9' - The second character of the RCN (RCN-13 only).
15
+ * - 'I' - One or more, in sequence, for the item reference.
16
+ * - 'P' - One or more, in sequence, for the price or weight.
17
+ * - 'V' - Zero or one, for the price or weight check digit.
18
+ * - 'C' - The check digit of the entire RCN.
19
+ *
20
+ * The 'I', 'P', and 'V' formats may be in any order.
21
+ *
22
+ * Some examples:
23
+ *
24
+ * - 2IIIIIVPPPPC - RCN-12 with a five-digit item reference, a price or weight check digit, and a four-digit price
25
+ * or weight.
26
+ * - 23IIIIVPPPPPC - RCN-13 with a four-digit item reference, a price or weight check digit, and a five-digit price
27
+ * or weight.
28
+ * - 2IIIIIIPPPPC - RCN-12 with a six-digit item reference and a four-digit price or eight.
29
+ * - 29IIIIIPPPPPC - RCN-13 with a five-digit item reference and a five-digit price or weight.
30
+ *
31
+ * @param format
32
+ * Format.
33
+ *
34
+ * @param rcn
35
+ * RCN.
36
+ *
37
+ * @returns
38
+ * RCN reference.
39
+ */
40
+ static parseRCN(format, rcn) {
41
+ const formatLength = format.length;
42
+ if (rcn.length !== formatLength) {
43
+ throw new RangeError(i18nextGS1.t("Identifier.invalidRCNLength"));
44
+ }
45
+ let validFormat = formatLength === 12 || formatLength === 13;
46
+ let validRCNPrefix = true;
47
+ let buildingItemReference = false;
48
+ let itemReference = "";
49
+ let buildingPriceOrWeight = false;
50
+ let priceOrWeight = "";
51
+ let priceOrWeightCheckDigit = "";
52
+ for (let index = 0; validFormat && index < formatLength; index++) {
53
+ const formatChar = format.charAt(index);
54
+ const rcnChar = rcn.charAt(index);
55
+ if (index === 0) {
56
+ validFormat = formatChar === "2";
57
+ validRCNPrefix = rcnChar === "2";
58
+ }
59
+ else if (formatLength === 13 && index === 1) {
60
+ validFormat = NUMERIC_CREATOR.characterIndex(formatChar) !== undefined;
61
+ validRCNPrefix = rcnChar === formatChar;
62
+ }
63
+ else if (index === formatLength - 1) {
64
+ validFormat = formatChar === "C";
65
+ }
66
+ else {
67
+ switch (formatChar) {
68
+ case "I":
69
+ if (!buildingItemReference) {
70
+ // Item reference can't appear more than once.
71
+ validFormat = itemReference === "";
72
+ buildingItemReference = true;
73
+ buildingPriceOrWeight = false;
74
+ }
75
+ itemReference += rcnChar;
76
+ break;
77
+ case "P":
78
+ if (!buildingPriceOrWeight) {
79
+ // Price or weight can't appear more than once.
80
+ validFormat = priceOrWeight === "";
81
+ buildingPriceOrWeight = true;
82
+ buildingItemReference = false;
83
+ }
84
+ priceOrWeight += rcnChar;
85
+ break;
86
+ case "V":
87
+ // Price or weight check digit can't appear more than once.
88
+ validFormat = priceOrWeightCheckDigit === "";
89
+ buildingItemReference = false;
90
+ buildingPriceOrWeight = false;
91
+ priceOrWeightCheckDigit = rcnChar;
92
+ break;
93
+ default:
94
+ validFormat = false;
95
+ break;
96
+ }
97
+ }
98
+ }
99
+ validFormat &&= itemReference !== "" && priceOrWeight !== "";
100
+ if (!validFormat) {
101
+ throw new RangeError(i18nextGS1.t("Identifier.invalidVariableMeasureRCNFormat"));
102
+ }
103
+ if (!validRCNPrefix) {
104
+ throw new RangeError(i18nextGS1.t("Identifier.invalidVariableMeasureRCNPrefix"));
105
+ }
106
+ if (priceOrWeightCheckDigit !== "" && !isValidPriceOrWeightCheckDigit(priceOrWeight, priceOrWeightCheckDigit)) {
107
+ throw new RangeError(i18nextGS1.t("Identifier.invalidVariableMeasurePriceOrWeight"));
108
+ }
109
+ if (!hasValidCheckDigit(rcn)) {
110
+ throw new RangeError(i18nextGS1.t("Identifier.invalidCheckDigit"));
111
+ }
112
+ return {
113
+ itemReference: Number(itemReference),
114
+ priceOrWeight: Number(priceOrWeight)
115
+ };
116
+ }
117
+ /**
118
+ * Create a Restricted Circulation Number (RCN) using a variable measure trade item format. See {@linkcode parseRCN}
119
+ * for format details.
120
+ *
121
+ * @param format
122
+ * Format.
123
+ *
124
+ * @param itemReference
125
+ * Item reference.
126
+ *
127
+ * @param priceOrWeight
128
+ * Price or weight (whole number only).
129
+ *
130
+ * @returns
131
+ * RCN-12 or RCN-13.
132
+ */
133
+ static createRCN(format, itemReference, priceOrWeight) {
134
+ const formatLength = format.length;
135
+ let validFormat = formatLength === 12 || formatLength === 13;
136
+ let rcnPrefix = "";
137
+ let buildingItemReference = false;
138
+ let itemReferenceString = "";
139
+ let itemReferenceLength = 0;
140
+ let buildingPriceOrWeight = false;
141
+ let priceOrWeightString = "";
142
+ let priceOrWeightLength = 0;
143
+ let calculatePriceOrWeightCheckDigit = false;
144
+ // RCN may be built in almost any order, so defer to builders that will be in ordered array.
145
+ const rcnPrefixBuilder = (partialRCN) => partialRCN + rcnPrefix;
146
+ const itemReferenceBuilder = (partialRCN) => partialRCN + itemReferenceString;
147
+ const priceOrWeightBuilder = (partialRCN) => partialRCN + priceOrWeightString;
148
+ const priceOrWeightCheckDigitBuilder = (partialRCN) => partialRCN + priceOrWeightCheckDigit(priceOrWeightString);
149
+ const checkDigitBuilder = (partialRCN) => partialRCN + checkDigit(partialRCN);
150
+ const rcnBuilders = [rcnPrefixBuilder];
151
+ for (let index = 0; validFormat && index < formatLength; index++) {
152
+ const formatChar = format.charAt(index);
153
+ if (index === 0) {
154
+ validFormat = formatChar === "2";
155
+ rcnPrefix = formatChar;
156
+ }
157
+ else if (formatLength === 13 && index === 1) {
158
+ validFormat = NUMERIC_CREATOR.characterIndex(formatChar) !== undefined;
159
+ rcnPrefix += formatChar;
160
+ }
161
+ else if (index === formatLength - 1) {
162
+ validFormat = formatChar === "C";
163
+ }
164
+ else {
165
+ switch (formatChar) {
166
+ case "I":
167
+ if (!buildingItemReference) {
168
+ // Item reference can't appear more than once.
169
+ validFormat = itemReferenceLength === 0;
170
+ buildingItemReference = true;
171
+ buildingPriceOrWeight = false;
172
+ rcnBuilders.push(itemReferenceBuilder);
173
+ }
174
+ itemReferenceLength++;
175
+ break;
176
+ case "P":
177
+ if (!buildingPriceOrWeight) {
178
+ // Price or weight can't appear more than once.
179
+ validFormat = priceOrWeightLength === 0;
180
+ buildingPriceOrWeight = true;
181
+ buildingItemReference = false;
182
+ rcnBuilders.push(priceOrWeightBuilder);
183
+ }
184
+ priceOrWeightLength++;
185
+ break;
186
+ case "V":
187
+ // Price or weight check digit can't appear more than once.
188
+ validFormat = !calculatePriceOrWeightCheckDigit;
189
+ buildingItemReference = false;
190
+ buildingPriceOrWeight = false;
191
+ calculatePriceOrWeightCheckDigit = true;
192
+ rcnBuilders.push(priceOrWeightCheckDigitBuilder);
193
+ break;
194
+ default:
195
+ validFormat = false;
196
+ break;
197
+ }
198
+ }
199
+ }
200
+ validFormat &&= itemReferenceLength !== 0 && priceOrWeightLength !== 0;
201
+ if (!validFormat) {
202
+ throw new RangeError(i18nextGS1.t("Identifier.invalidVariableMeasureRCNFormat"));
203
+ }
204
+ itemReferenceString = NUMERIC_CREATOR.create(itemReferenceLength, itemReference);
205
+ priceOrWeightString = NUMERIC_CREATOR.create(priceOrWeightLength, priceOrWeight);
206
+ rcnBuilders.push(checkDigitBuilder);
207
+ return rcnBuilders.reduce((partialRCN, rcnBuilder) => rcnBuilder(partialRCN), "");
208
+ }
209
+ }
210
+ //# sourceMappingURL=variable-measure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variable-measure.js","sourceRoot":"","sources":["../src/variable-measure.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { Hyperlink } from "@aidc-toolkit/core";
2
+ import { type IdentifierType } from "./identifier-type.js";
3
+ /**
4
+ * Create a Verified by GS1 hyperlink.
5
+ *
6
+ * @param identifierType
7
+ * Identifier type.
8
+ *
9
+ * @param identifier
10
+ * Identifier.
11
+ *
12
+ * @param text
13
+ * Text for hyperlink. If not provided, the identifier is used.
14
+ *
15
+ * @param details
16
+ * Details to display when hovering over hyperlink.
17
+ *
18
+ * @returns
19
+ * Verified by GS1 hyperlink.
20
+ */
21
+ export declare function verifiedByGS1(identifierType: IdentifierType, identifier: string, text?: string | undefined, details?: string): Hyperlink;
22
+ //# sourceMappingURL=verified-by-gs1.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verified-by-gs1.d.ts","sourceRoot":"","sources":["../src/verified-by-gs1.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAAE,KAAK,cAAc,EAAmB,MAAM,sBAAsB,CAAC;AAK5E;;;;;;;;;;;;;;;;;GAiBG;AAEH,wBAAgB,aAAa,CAAC,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,GAAG,SAAqB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CA2BnJ"}
@@ -0,0 +1,46 @@
1
+ import { GTINValidator } from "./gtin-validator.js";
2
+ import { IdentifierTypes } from "./identifier-type.js";
3
+ import { IdentifierValidators } from "./identifier-validators.js";
4
+ const VERIFIED_BY_GS1_REFERENCE_BASE = "https://www.gs1.org/services/verified-by-gs1/results?";
5
+ /**
6
+ * Create a Verified by GS1 hyperlink.
7
+ *
8
+ * @param identifierType
9
+ * Identifier type.
10
+ *
11
+ * @param identifier
12
+ * Identifier.
13
+ *
14
+ * @param text
15
+ * Text for hyperlink. If not provided, the identifier is used.
16
+ *
17
+ * @param details
18
+ * Details to display when hovering over hyperlink.
19
+ *
20
+ * @returns
21
+ * Verified by GS1 hyperlink.
22
+ */
23
+ // eslint-disable-next-line @typescript-eslint/no-useless-default-assignment -- Undefined is necessary to allow bypass of text.
24
+ export function verifiedByGS1(identifierType, identifier, text = undefined, details) {
25
+ let normalizedIdentifier;
26
+ let useKeyTypeParameter;
27
+ if (identifierType === IdentifierTypes.GTIN) {
28
+ // Normalization will validate resulting GTIN.
29
+ normalizedIdentifier = GTINValidator.normalize(identifier);
30
+ useKeyTypeParameter = true;
31
+ }
32
+ else {
33
+ const identifierValidator = IdentifierValidators[identifierType];
34
+ identifierValidator.validate(identifier);
35
+ normalizedIdentifier = identifier;
36
+ useKeyTypeParameter = identifierType === IdentifierTypes.GLN;
37
+ }
38
+ const lowerCaseIdentifierType = identifierType.toLowerCase();
39
+ const reference = useKeyTypeParameter ? `${VERIFIED_BY_GS1_REFERENCE_BASE}${lowerCaseIdentifierType}=${normalizedIdentifier}` : `${VERIFIED_BY_GS1_REFERENCE_BASE}key=${normalizedIdentifier}&key_type=${lowerCaseIdentifierType}`;
40
+ return {
41
+ reference,
42
+ text: text ?? identifier,
43
+ details
44
+ };
45
+ }
46
+ //# sourceMappingURL=verified-by-gs1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verified-by-gs1.js","sourceRoot":"","sources":["../src/verified-by-gs1.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAuB,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAElE,MAAM,8BAA8B,GAAG,uDAAuD,CAAC;AAE/F;;;;;;;;;;;;;;;;;GAiBG;AACH,+HAA+H;AAC/H,MAAM,UAAU,aAAa,CAAC,cAA8B,EAAE,UAAkB,EAAE,OAA2B,SAAS,EAAE,OAAgB;IACpI,IAAI,oBAA4B,CAAC;IACjC,IAAI,mBAA4B,CAAC;IAEjC,IAAI,cAAc,KAAK,eAAe,CAAC,IAAI,EAAE,CAAC;QAC1C,8CAA8C;QAC9C,oBAAoB,GAAG,aAAa,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAE3D,mBAAmB,GAAG,IAAI,CAAC;IAC/B,CAAC;SAAM,CAAC;QACJ,MAAM,mBAAmB,GAAG,oBAAoB,CAAC,cAAc,CAAC,CAAC;QAEjE,mBAAmB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAEzC,oBAAoB,GAAG,UAAU,CAAC;QAClC,mBAAmB,GAAG,cAAc,KAAK,eAAe,CAAC,GAAG,CAAC;IACjE,CAAC;IAED,MAAM,uBAAuB,GAAG,cAAc,CAAC,WAAW,EAAE,CAAC;IAE7D,MAAM,SAAS,GAAG,mBAAmB,CAAC,CAAC,CAAC,GAAG,8BAA8B,GAAG,uBAAuB,IAAI,oBAAoB,EAAE,CAAC,CAAC,CAAC,GAAG,8BAA8B,OAAO,oBAAoB,aAAa,uBAAuB,EAAE,CAAC;IAEnO,OAAO;QACH,SAAS;QACT,IAAI,EAAE,IAAI,IAAI,UAAU;QACxB,OAAO;KACV,CAAC;AACN,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aidc-toolkit/gs1",
3
- "version": "1.0.28-beta",
3
+ "version": "1.0.32-beta",
4
4
  "description": "GS1 AIDC Toolkit",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -21,17 +21,17 @@
21
21
  "scripts": {
22
22
  "lint": "eslint",
23
23
  "tsc:core": "tsc --project tsconfig-src.json",
24
- "build:dev": "rimraf dist && npm run tsc:core -- --declarationMap --sourceMap",
25
- "build:release": "npm run tsc:core -- --noEmit && tsup",
24
+ "build:dev": "rimraf dist tsconfig-src.tsbuildinfo && npm run tsc:core -- --declarationMap --sourceMap",
25
+ "build:release": "npm run tsc:core -- --noEmit && tsup --tsconfig tsconfig-tsup.json",
26
26
  "build:doc": "npm run build:dev",
27
- "test": "vitest run"
27
+ "test": "tsc --project tsconfig-test.json --noEmit && vitest run"
28
28
  },
29
29
  "devDependencies": {
30
- "@aidc-toolkit/dev": "1.0.28-beta",
31
- "vitest": "^4.0.15"
30
+ "@aidc-toolkit/dev": "1.0.32-beta",
31
+ "vitest": "^4.0.16"
32
32
  },
33
33
  "dependencies": {
34
- "@aidc-toolkit/core": "1.0.28-beta",
35
- "@aidc-toolkit/utility": "1.0.28-beta"
34
+ "@aidc-toolkit/core": "1.0.32-beta",
35
+ "@aidc-toolkit/utility": "1.0.32-beta"
36
36
  }
37
37
  }
@@ -0,0 +1,117 @@
1
+ import { Cache } from "@aidc-toolkit/core";
2
+ import { type GCPLengthData, type GCPLengthHeader, parseGCPLengthHeader } from "./gcp-length-data.js";
3
+ import { i18nextGS1 } from "./locale/i18n.js";
4
+
5
+ /**
6
+ * GS1 Company Prefix length cache.
7
+ */
8
+ export abstract class GCPLengthCache extends Cache<GCPLengthData, GCPLengthData | string> {
9
+ }
10
+
11
+ /**
12
+ * GS1 Company Prefix length cache with remote source.
13
+ */
14
+ export abstract class RemoteGCPLengthCache extends GCPLengthCache {
15
+ /**
16
+ * Default base URL pointing to AIDC Toolkit website data directory.
17
+ */
18
+ static DEFAULT_BASE_URL = "https://aidc-toolkit.com/data/";
19
+
20
+ /**
21
+ * File containing header information (date/time and disclaimer).
22
+ */
23
+ static SOURCE_HEADER_FILE_NAME = "gcp-length-header.json";
24
+
25
+ /**
26
+ * File containing tree data in binary form.
27
+ */
28
+ static SOURCE_DATA_FILE_NAME = "gcp-length-data.bin";
29
+
30
+ /**
31
+ * Base URL.
32
+ */
33
+ readonly #baseURL: string;
34
+
35
+ /**
36
+ * GS1 Company Prefix header data.
37
+ */
38
+ #gcpLengthHeader?: GCPLengthHeader | undefined;
39
+
40
+ /**
41
+ * Constructor.
42
+ *
43
+ * @param baseURL
44
+ * Base URL. The URL must end with a slash, and must host the {@linkcode SOURCE_HEADER_FILE_NAME} and {@linkcode
45
+ * SOURCE_DATA_FILE_NAME} files.
46
+ */
47
+ constructor(baseURL: string = RemoteGCPLengthCache.DEFAULT_BASE_URL) {
48
+ super();
49
+
50
+ this.#baseURL = baseURL;
51
+ }
52
+
53
+ /**
54
+ * Get a remote file. If an exception is thrown, retrying is delayed for ten minutes to prevent repeated network
55
+ * calls.
56
+ *
57
+ * @param fileName
58
+ * File name relative to base URL.
59
+ *
60
+ * @returns
61
+ * Response.
62
+ */
63
+ async #getRemoteFile(fileName: string): Promise<Response> {
64
+ return fetch(`${this.#baseURL}${fileName}`).then((response) => {
65
+ if (!response.ok) {
66
+ throw new RangeError(i18nextGS1.t("Prefix.gs1CompanyPrefixLengthDataHTTPError", {
67
+ status: response.status
68
+ }));
69
+ }
70
+
71
+ return response;
72
+ }).catch(async (e: unknown) => {
73
+ // Try again in ten minutes.
74
+ const nowPlus10Minutes = new Date();
75
+ nowPlus10Minutes.setMinutes(nowPlus10Minutes.getMinutes() + 10);
76
+
77
+ await this.update(nowPlus10Minutes);
78
+
79
+ throw e;
80
+ });
81
+ }
82
+
83
+ /**
84
+ * @inheritDoc
85
+ */
86
+ get sourceDateTime(): Promise<Date> {
87
+ return this.#getRemoteFile(RemoteGCPLengthCache.SOURCE_HEADER_FILE_NAME).then(async response =>
88
+ response.text()
89
+ ).then((s) => {
90
+ this.#gcpLengthHeader = parseGCPLengthHeader(s);
91
+
92
+ return this.#gcpLengthHeader.dateTime;
93
+ });
94
+ }
95
+
96
+ /**
97
+ * @inheritDoc
98
+ */
99
+ get sourceData(): Promise<GCPLengthData> {
100
+ if (this.#gcpLengthHeader === undefined) {
101
+ // Application error; no localization necessary.
102
+ throw new Error("GS1 Company Prefix length header not loaded");
103
+ }
104
+
105
+ const gcpLengthHeader = this.#gcpLengthHeader;
106
+
107
+ // Clear header to allow for retry in case of failure.
108
+ this.#gcpLengthHeader = undefined;
109
+
110
+ return this.#getRemoteFile(RemoteGCPLengthCache.SOURCE_DATA_FILE_NAME).then(async response =>
111
+ response.arrayBuffer()
112
+ ).then(a => ({
113
+ ...gcpLengthHeader,
114
+ data: new Uint8Array(a)
115
+ }));
116
+ }
117
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * GS1 Company Prefix length header.
3
+ */
4
+ export interface GCPLengthHeader {
5
+ /**
6
+ * Date/time the data was last updated.
7
+ */
8
+ readonly dateTime: Date;
9
+
10
+ /**
11
+ * Disclaimer.
12
+ */
13
+ readonly disclaimer: string;
14
+ }
15
+
16
+ /**
17
+ * Parse a JSON string representing a GS1 Company Prefix length header.
18
+ *
19
+ * @param s
20
+ * JSON string.
21
+ *
22
+ * @returns
23
+ * GS1 Company Prefix length header.
24
+ */
25
+ export function parseGCPLengthHeader(s: string): GCPLengthHeader {
26
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- File format is known.
27
+ return JSON.parse(s, (key, value: unknown) =>
28
+ key === "dateTime" && typeof value === "string" ? new Date(value) : value
29
+ ) as GCPLengthHeader;
30
+ }
31
+
32
+ /**
33
+ * Generate a JSON string representing a GS1 Company Prefix length header.
34
+ *
35
+ * @param gcpLengthHeader
36
+ * GS1 Company Prefix length header.
37
+ *
38
+ * @param space
39
+ * JSON string indentation.
40
+ *
41
+ * @returns
42
+ * JSON string.
43
+ */
44
+ export function stringifyGCPLengthHeader(gcpLengthHeader: GCPLengthHeader, space?: string | number): string {
45
+ return JSON.stringify(gcpLengthHeader, (key, value: unknown) =>
46
+ key === "dateTime" && value instanceof Date ? value.toISOString() : value,
47
+ space);
48
+ }
49
+
50
+ /**
51
+ * GS1 Company Prefix length data.
52
+ */
53
+ export interface GCPLengthData extends GCPLengthHeader {
54
+ /**
55
+ * Date/time the data was last updated.
56
+ */
57
+ readonly dateTime: Date;
58
+
59
+ /**
60
+ * Disclaimer.
61
+ */
62
+ readonly disclaimer: string;
63
+
64
+ /**
65
+ * Tree data in binary form.
66
+ */
67
+ readonly data: Uint8Array;
68
+ }