nv-img-barcode-cmmn 1.0.1 → 1.0.3

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 (5) hide show
  1. package/TEST/tst0.js +71 -0
  2. package/gs1.js +840 -0
  3. package/index.js +2 -85
  4. package/package.json +1 -1
  5. package/ptrn.js +0 -161
package/TEST/tst0.js ADDED
@@ -0,0 +1,71 @@
1
+ const validate_and_fmt_int = (info,value)=>{
2
+ //整数
3
+ let num = Number(value);
4
+ if(!Object.is(num,NaN)) {
5
+ if(num<0) {return [false,`不可为负数`]}
6
+ if(num <=Number.MAX_SAFE_INTEGER){
7
+ if(parseInt(num) === num) {
8
+ value =String(num);
9
+ if(value.length<= info.length) {
10
+ value = '0'.repeat(info.length - value.length) + value;
11
+ return [true,value];
12
+ } else {
13
+ return [false,`${info.desc} 长度最多 ${info.length}`];
14
+ }
15
+ } else {
16
+ return [false,`${info.desc} 必须是整数数字`];
17
+ }
18
+ } else {
19
+ // num > Number.MAX_SAFE_INTEGER
20
+ num = BigInt(value);
21
+ value =String(num);
22
+ if(value.length<= info.length) {
23
+ value = '0'.repeat(info.length - value.length) + value;
24
+ return [true,value];
25
+ } else {
26
+ return [false,`${info.desc} 长度最多 ${info.length}`];
27
+ }
28
+ }
29
+ } else {
30
+ return [false,`${info.desc} 必须是整数数字`];
31
+ }
32
+ }
33
+
34
+ function test_logic() {
35
+ const info = { length: 6, desc: "测试字段" };
36
+
37
+ console.log('MAX_SAFE_INTEGER:', Number.MAX_SAFE_INTEGER);
38
+ console.log('2**53:', 2**53);
39
+ console.log('2**53 === Number.MAX_SAFE_INTEGER?', 2**53 === Number.MAX_SAFE_INTEGER);
40
+ console.log('');
41
+
42
+ const testCases = [
43
+ // 在安全范围内的数
44
+ { value: 9007199254740991, desc: "MAX_SAFE_INTEGER" }, // 应该成功
45
+ { value: 9007199254740992, desc: "刚好超出安全" }, // 应该进入BigInt分支
46
+ { value: 9999999999999999, desc: "9999万亿" }, // 1e16-1
47
+
48
+ // 明确超出安全范围的数
49
+ { value: 10000000000000000, desc: "1e16" }, // 1e16
50
+ { value: 99999999999999999, desc: "9.9e16" }, // 你提到的数
51
+ ];
52
+
53
+ testCases.forEach(test => {
54
+ const num = Number(test.value);
55
+ const isSafe = num <= Number.MAX_SAFE_INTEGER;
56
+
57
+ console.log(`${test.desc.padEnd(20)}: ${test.value}`);
58
+ console.log(` Number() = ${num}`);
59
+ console.log(` <= MAX_SAFE_INTEGER? ${isSafe}`);
60
+ console.log(` 会进入哪个分支? ${isSafe ? '安全分支' : 'BigInt分支'}`);
61
+
62
+ try {
63
+ const [success, result] = validate_and_fmt_int(info, test.value);
64
+ console.log(` 结果: ${success ? '成功' : '失败'} ${result || ''}`);
65
+ } catch (error) {
66
+ console.log(` 异常: ${error.message}`);
67
+ }
68
+ console.log('');
69
+ });
70
+ }
71
+ test_logic();
package/gs1.js ADDED
@@ -0,0 +1,840 @@
1
+ const GS1_AI_SPECS = {
2
+ '00': { name: 'SSCC', length: 18, format: 'numeric', desc: '物流单元标识符' },
3
+ '01': { name: 'GTIN', length: 14, format: 'numeric', desc: '全球贸易项目代码' },
4
+ '02': { name: 'CONTENT_GTIN', length: 14, format: 'numeric', desc: '物流单元内贸易项目GTIN' },
5
+ '10': { name: 'BATCH', length: 20, format: 'alphanumeric', desc: '批号' },
6
+ '11': { name: 'PROD_DATE', length: 6, format: 'date', desc: '生产日期(YYMMDD)' },
7
+ '12': { name: 'DUE_DATE', length: 6, format: 'date', desc: '付款截止日期(YYMMDD)' },
8
+ '13': { name: 'PACK_DATE', length: 6, format: 'date', desc: '包装日期(YYMMDD)' },
9
+ '15': { name: 'BEST_BEFORE', length: 6, format: 'date', desc: '保质期(YYMMDD)' },
10
+ '16': { name: 'SELL_BY', length: 6, format: 'date', desc: '销售日期(YYMMDD)' },
11
+ '17': { name: 'EXPIRY', length: 6, format: 'date', desc: '有效期(YYMMDD)' },
12
+ '19': { name: 'EXPIRY_ALT', length: 6, format: 'date', desc: '过期日期(YYMMDD)' },
13
+ '20': { name: 'VARIANT', length: 2, format: 'numeric', desc: '包装内部标识' },
14
+ '21': { name: 'SERIAL', length: 20, format: 'alphanumeric', desc: '序列号' },
15
+ '22': { name: 'MEDICAL_DATA', length: 20, format: 'alphanumeric', desc: '医疗产品附加数据' },
16
+ '23': { name: 'LOT_GROUP', length: 20, format: 'alphanumeric', desc: '组号' },
17
+ '30': { name: 'VAR_COUNT', length: 8, format: 'numeric', desc: '可变数量' },
18
+ '3100': { name: 'NET_WEIGHT_0', length: 6, format: 'numeric', decimal: 0, unit: 'kg', desc: '净重(kg)整数' },
19
+ '3101': { name: 'NET_WEIGHT_1', length: 6, format: 'numeric', decimal: 1, unit: 'kg', desc: '净重(kg)1位小数' },
20
+ '3102': { name: 'NET_WEIGHT_2', length: 6, format: 'numeric', decimal: 2, unit: 'kg', desc: '净重(kg)2位小数' },
21
+ '3103': { name: 'NET_WEIGHT_3', length: 6, format: 'numeric', decimal: 3, unit: 'kg', desc: '净重(kg)3位小数' },
22
+ '3104': { name: 'NET_WEIGHT_4', length: 6, format: 'numeric', decimal: 4, unit: 'kg', desc: '净重(kg)4位小数' },
23
+ '3105': { name: 'NET_WEIGHT_5', length: 6, format: 'numeric', decimal: 5, unit: 'kg', desc: '净重(kg)5位小数' },
24
+ '3110': { name: 'LENGTH_0', length: 6, format: 'numeric', decimal: 0, unit: 'm', desc: '长度(m)整数' },
25
+ '3111': { name: 'LENGTH_1', length: 6, format: 'numeric', decimal: 1, unit: 'm', desc: '长度(m)1位小数' },
26
+ '3112': { name: 'LENGTH_2', length: 6, format: 'numeric', decimal: 2, unit: 'm', desc: '长度(m)2位小数' },
27
+ '3113': { name: 'LENGTH_3', length: 6, format: 'numeric', decimal: 3, unit: 'm', desc: '长度(m)3位小数' },
28
+ '3114': { name: 'LENGTH_4', length: 6, format: 'numeric', decimal: 4, unit: 'm', desc: '长度(m)4位小数' },
29
+ '3115': { name: 'LENGTH_5', length: 6, format: 'numeric', decimal: 5, unit: 'm', desc: '长度(m)5位小数' },
30
+ '3120': { name: 'WIDTH_0', length: 6, format: 'numeric', decimal: 0, unit: 'm', desc: '宽度(m)整数' },
31
+ '3121': { name: 'WIDTH_1', length: 6, format: 'numeric', decimal: 1, unit: 'm', desc: '宽度(m)1位小数' },
32
+ '3122': { name: 'WIDTH_2', length: 6, format: 'numeric', decimal: 2, unit: 'm', desc: '宽度(m)2位小数' },
33
+ '3123': { name: 'WIDTH_3', length: 6, format: 'numeric', decimal: 3, unit: 'm', desc: '宽度(m)3位小数' },
34
+ '3124': { name: 'WIDTH_4', length: 6, format: 'numeric', decimal: 4, unit: 'm', desc: '宽度(m)4位小数' },
35
+ '3125': { name: 'WIDTH_5', length: 6, format: 'numeric', decimal: 5, unit: 'm', desc: '宽度(m)5位小数' },
36
+ '3130': { name: 'HEIGHT_0', length: 6, format: 'numeric', decimal: 0, unit: 'm', desc: '高度(m)整数' },
37
+ '3131': { name: 'HEIGHT_1', length: 6, format: 'numeric', decimal: 1, unit: 'm', desc: '高度(m)1位小数' },
38
+ '3132': { name: 'HEIGHT_2', length: 6, format: 'numeric', decimal: 2, unit: 'm', desc: '高度(m)2位小数' },
39
+ '3133': { name: 'HEIGHT_3', length: 6, format: 'numeric', decimal: 3, unit: 'm', desc: '高度(m)3位小数' },
40
+ '3134': { name: 'HEIGHT_4', length: 6, format: 'numeric', decimal: 4, unit: 'm', desc: '高度(m)4位小数' },
41
+ '3135': { name: 'HEIGHT_5', length: 6, format: 'numeric', decimal: 5, unit: 'm', desc: '高度(m)5位小数' },
42
+ '3140': { name: 'AREA_0', length: 6, format: 'numeric', decimal: 0, unit: 'm²', desc: '面积(m²)整数' },
43
+ '3141': { name: 'AREA_1', length: 6, format: 'numeric', decimal: 1, unit: 'm²', desc: '面积(m²)1位小数' },
44
+ '3142': { name: 'AREA_2', length: 6, format: 'numeric', decimal: 2, unit: 'm²', desc: '面积(m²)2位小数' },
45
+ '3143': { name: 'AREA_3', length: 6, format: 'numeric', decimal: 3, unit: 'm²', desc: '面积(m²)3位小数' },
46
+ '3144': { name: 'AREA_4', length: 6, format: 'numeric', decimal: 4, unit: 'm²', desc: '面积(m²)4位小数' },
47
+ '3145': { name: 'AREA_5', length: 6, format: 'numeric', decimal: 5, unit: 'm²', desc: '面积(m²)5位小数' },
48
+ '3150': { name: 'NET_VOLUME_L_0', length: 6, format: 'numeric', decimal: 0, unit: 'l', desc: '净容积(l)整数' },
49
+ '3151': { name: 'NET_VOLUME_L_1', length: 6, format: 'numeric', decimal: 1, unit: 'l', desc: '净容积(l)1位小数' },
50
+ '3152': { name: 'NET_VOLUME_L_2', length: 6, format: 'numeric', decimal: 2, unit: 'l', desc: '净容积(l)2位小数' },
51
+ '3153': { name: 'NET_VOLUME_L_3', length: 6, format: 'numeric', decimal: 3, unit: 'l', desc: '净容积(l)3位小数' },
52
+ '3154': { name: 'NET_VOLUME_L_4', length: 6, format: 'numeric', decimal: 4, unit: 'l', desc: '净容积(l)4位小数' },
53
+ '3155': { name: 'NET_VOLUME_L_5', length: 6, format: 'numeric', decimal: 5, unit: 'l', desc: '净容积(l)5位小数' },
54
+ '3160': { name: 'NET_VOLUME_M3_0', length: 6, format: 'numeric', decimal: 0, unit: 'm³', desc: '净体积(m³)整数' },
55
+ '3161': { name: 'NET_VOLUME_M3_1', length: 6, format: 'numeric', decimal: 1, unit: 'm³', desc: '净体积(m³)1位小数' },
56
+ '3162': { name: 'NET_VOLUME_M3_2', length: 6, format: 'numeric', decimal: 2, unit: 'm³', desc: '净体积(m³)2位小数' },
57
+ '3163': { name: 'NET_VOLUME_M3_3', length: 6, format: 'numeric', decimal: 3, unit: 'm³', desc: '净体积(m³)3位小数' },
58
+ '3164': { name: 'NET_VOLUME_M3_4', length: 6, format: 'numeric', decimal: 4, unit: 'm³', desc: '净体积(m³)4位小数' },
59
+ '3165': { name: 'NET_VOLUME_M3_5', length: 6, format: 'numeric', decimal: 5, unit: 'm³', desc: '净体积(m³)5位小数' },
60
+ '3200': { name: 'NET_WEIGHT_LB_0', length: 6, format: 'numeric', decimal: 0, unit: 'lb', desc: '净重(lb)整数' },
61
+ '3201': { name: 'NET_WEIGHT_LB_1', length: 6, format: 'numeric', decimal: 1, unit: 'lb', desc: '净重(lb)1位小数' },
62
+ '3202': { name: 'NET_WEIGHT_LB_2', length: 6, format: 'numeric', decimal: 2, unit: 'lb', desc: '净重(lb)2位小数' },
63
+ '3203': { name: 'NET_WEIGHT_LB_3', length: 6, format: 'numeric', decimal: 3, unit: 'lb', desc: '净重(lb)3位小数' },
64
+ '3204': { name: 'NET_WEIGHT_LB_4', length: 6, format: 'numeric', decimal: 4, unit: 'lb', desc: '净重(lb)4位小数' },
65
+ '3205': { name: 'NET_WEIGHT_LB_5', length: 6, format: 'numeric', decimal: 5, unit: 'lb', desc: '净重(lb)5位小数' },
66
+ '3300': { name: 'GROSS_WEIGHT_0', length: 6, format: 'numeric', decimal: 0, unit: 'kg', desc: '毛重(kg)整数' },
67
+ '3301': { name: 'GROSS_WEIGHT_1', length: 6, format: 'numeric', decimal: 1, unit: 'kg', desc: '毛重(kg)1位小数' },
68
+ '3302': { name: 'GROSS_WEIGHT_2', length: 6, format: 'numeric', decimal: 2, unit: 'kg', desc: '毛重(kg)2位小数' },
69
+ '3303': { name: 'GROSS_WEIGHT_3', length: 6, format: 'numeric', decimal: 3, unit: 'kg', desc: '毛重(kg)3位小数' },
70
+ '3304': { name: 'GROSS_WEIGHT_4', length: 6, format: 'numeric', decimal: 4, unit: 'kg', desc: '毛重(kg)4位小数' },
71
+ '3305': { name: 'GROSS_WEIGHT_5', length: 6, format: 'numeric', decimal: 5, unit: 'kg', desc: '毛重(kg)5位小数' },
72
+ '37': { name: 'COUNT', length: 8, format: 'numeric', desc: '物流单元内商品数量' },
73
+ '90': { name: 'INTERNAL_1', length: 30, format: 'alphanumeric', desc: '自定义0' },
74
+ '91': { name: 'INTERNAL_2', length: 90, format: 'alphanumeric', desc: '自定义1' },
75
+ '92': { name: 'INTERNAL_3', length: 90, format: 'alphanumeric', desc: '自定义2' },
76
+ '93': { name: 'INTERNAL_4', length: 90, format: 'alphanumeric', desc: '自定义3' },
77
+ '94': { name: 'INTERNAL_5', length: 90, format: 'alphanumeric', desc: '自定义4' },
78
+ '95': { name: 'INTERNAL_6', length: 90, format: 'alphanumeric', desc: '自定义5' },
79
+ '96': { name: 'INTERNAL_7', length: 90, format: 'alphanumeric', desc: '自定义6' },
80
+ '97': { name: 'INTERNAL_8', length: 90, format: 'alphanumeric', desc: '自定义7' },
81
+ '98': { name: 'INTERNAL_9', length: 90, format: 'alphanumeric', desc: '自定义8' },
82
+ '99': { name: 'INTERNAL_10', length: 90, format: 'alphanumeric', desc: '自定义9' }
83
+ };
84
+
85
+ const GS1_ALPHANUMERIC_REGEX = /^[A-Za-z0-9 !"*+,\-.\/:;=?_\x23\x24]+$/;
86
+ // ^
87
+ // [ # 字符集开始
88
+ // A-Za-z0-9 # 字母和数字
89
+ // \x20 # 空格(ASCII 32)
90
+ // !"*+,\-.\/:;=?_ # 允许的特殊字符
91
+ // \x23 # #(ASCII 35)
92
+ // \x24 # $(ASCII 36)
93
+ // ] # 字符集结束
94
+ // + # 至少一个字符
95
+ // $ # 字符串结束
96
+ const YYMMDD_REGEX = /^(\d{2})(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])$/;
97
+ const mts_to_yymmdd = (mts)=>{
98
+ ////时间戳转换为YYMMDD
99
+ const date = new Date(mts);
100
+ const year = date.getFullYear() % 100; // 取年份后两位
101
+ const month = date.getMonth() + 1; // 月份从0开始
102
+ const day = date.getDate(); // 获取日期
103
+
104
+ return [
105
+ year.toString().padStart(2, '0'), // YY
106
+ month.toString().padStart(2, '0'), // MM
107
+ day.toString().padStart(2, '0') // DD
108
+ ].join('');
109
+ }
110
+
111
+ const splitIntegerDecimal = (num) => {
112
+ // 转换为字符串
113
+ const str = String(num);
114
+
115
+ // 分割整数和小数部分
116
+ const parts = str.split('.');
117
+
118
+ // 处理整数部分
119
+ let integerPart = null;
120
+ const integerNum = parseInt(parts[0] || '0', 10);
121
+ if (integerNum !== 0) {
122
+ integerPart = integerNum;
123
+ }
124
+
125
+ // 处理小数部分
126
+ let decimalPart = null;
127
+ if (parts[1] && parts[1] !== '0') {
128
+ // 移除末尾的0
129
+ const decimalStr = parts[1].replace(/0+$/, '');
130
+ if (decimalStr && decimalStr !== '0') {
131
+ decimalPart = parseInt(decimalStr, 10);
132
+ }
133
+ }
134
+
135
+ return [integerPart, decimalPart];
136
+ };
137
+
138
+
139
+ const validate_and_fmt_int = (info,value)=>{
140
+ //整数
141
+ let num = Number(value);
142
+ if(!Object.is(num,NaN)) {
143
+ if(num<0) {return [false,`不可为负数`]}
144
+ if(num <=Number.MAX_SAFE_INTEGER){
145
+ if(parseInt(num) === num) {
146
+ value =String(num);
147
+ if(value.length<= info.length) {
148
+ value = '0'.repeat(info.length - value.length) + value;
149
+ return [true,value];
150
+ } else {
151
+ return [false,`${info.desc} 长度最多 ${info.length}`];
152
+ }
153
+ } else {
154
+ return [false,`${info.desc} 必须是整数数字`];
155
+ }
156
+ } else {
157
+ // num > Number.MAX_SAFE_INTEGER
158
+ num = BigInt(value);
159
+ value =String(num);
160
+ if(value.length<= info.length) {
161
+ value = '0'.repeat(info.length - value.length) + value;
162
+ return [true,value];
163
+ } else {
164
+ return [false,`${info.desc} 长度最多 ${info.length}`];
165
+ }
166
+ }
167
+ } else {
168
+ return [false,`${info.desc} 必须是整数数字`];
169
+ }
170
+ }
171
+
172
+ const validate_and_fmt_ai_value = (ai, value)=>{
173
+ ai = String(ai);
174
+ let info = GS1_AI_SPECS[ai];
175
+ if(info===undefined) {
176
+ return [false,"非法AI"]
177
+ } else {
178
+ if(info.format === "numeric") {
179
+ if(info.decimal === undefined|| info.decimal ===0) {
180
+ //整数
181
+ return validate_and_fmt_int(info,value);
182
+ } else {
183
+ //浮点
184
+ let num = Number(value);
185
+ let [ii,dd] = splitIntegerDecimal(num);
186
+ if(ii === null) {
187
+ if(dd === null) {
188
+ return [true,'0'.repeat(info.length)]
189
+ } else {
190
+ dd = "0." + String(dd);
191
+ dd = Number(dd);
192
+ dd = dd *(10**info.decimal);
193
+ dd = String(dd);
194
+ dd = '0'.repeat(info.length - dd.length)+dd;
195
+ return [true,dd]
196
+ }
197
+ } else {
198
+ if(dd === null) {
199
+ return validate_and_fmt_int(info,ii);
200
+ } else {
201
+ let ilen = String(ii).length;
202
+ let int_max_length = info.length - info.decimal;
203
+ if(ilen> int_max_length) {
204
+ return [false,`${info.desc} 长度最多 ${info.length}`]
205
+ } else {
206
+ const intPart = String(ii).padStart(int_max_length, '0');
207
+ let decStr = String(dd).padEnd(info.decimal, '0').substring(0, info.decimal);
208
+ const result = intPart + decStr;
209
+ return [true, result];
210
+ }
211
+ }
212
+ }
213
+ }
214
+ } else if(info.format === "date") {
215
+ if(typeof(value)==="number") {
216
+ ////视作时间戳
217
+ return [true,mts_to_yymmdd(value)]
218
+ } else {
219
+ value = String(value);
220
+ }
221
+ if(YYMMDD_REGEX.test(value)) {
222
+ return [true,value];
223
+ } else {
224
+ return [false,`${info.desc} 必需匹配 YYMMDD`];
225
+ }
226
+ } else {
227
+ //(info.format === "alphanumeric")
228
+ value = String(value);
229
+ if(GS1_ALPHANUMERIC_REGEX.test(value)) {
230
+ if(info.length>=value.length) {
231
+ return [true,value]
232
+ } else {
233
+ return [false,`${info.desc} 长度必需 <= ${info.length}`];
234
+ }
235
+ } else {
236
+ return [false,`${info.desc} 必需匹配 /^[A-Za-z0-9 !"%&'()*+,\-.\/:;<=>?_]+$/`];
237
+ }
238
+ }
239
+ }
240
+ }
241
+
242
+ let ALIAS = {
243
+ // 物流单元
244
+ '物流单元标识符': '00',
245
+ '物流单元': '00',
246
+ '运输包装代码': '00',
247
+ '托盘代码': '00',
248
+ // 商品代码
249
+ '商品条码': '01',
250
+ '商品代码': '01',
251
+ '产品代码': '01',
252
+ // 批次
253
+ '批次': '10',
254
+ '批号': '10',
255
+ 'lot': '10',
256
+ 'batch': '10',
257
+ // 日期相关
258
+ '生产日期': '11',
259
+ '制造日期': '11',
260
+ '保质期': '15',
261
+ '保鲜期': '15',
262
+ '有效期': '17',
263
+ '到期日': '17',
264
+ // 数量
265
+ '数量': '30',
266
+ '件数': '30',
267
+ 'quantity': '30',
268
+ '物流单元内商品数量': '37',
269
+ '整箱数量': '37',
270
+ // 序列号
271
+ '序列号': '21',
272
+ '流水号': '21',
273
+ 'serial': '21',
274
+ // 重量体积
275
+ '净重': '3100',
276
+ '重量': '3100',
277
+ '毛重': '3300',
278
+ '总重': '3300',
279
+ '长度': '3110',
280
+ '长': '3110',
281
+ '宽度': '3120',
282
+ '宽': '3120',
283
+ '高度': '3130',
284
+ '高': '3130',
285
+ '面积': '3140',
286
+ '体积': '3160',
287
+ '容积': '3150',
288
+ '容量': '3150',
289
+
290
+ // 包装
291
+ '包装内部标识': '20',
292
+ '包装标识': '20',
293
+
294
+ // 医疗
295
+ '医疗': '22',
296
+ '药品': '22',
297
+
298
+ // 组
299
+ '组号': '23',
300
+ '分组': '23',
301
+ };
302
+
303
+ let AI_TO_NAMES = {};
304
+ let NAME_TO_AI = {};
305
+ const reset_map = ()=> {
306
+ AI_TO_NAMES = {};
307
+ NAME_TO_AI = {};
308
+ for(let ai in GS1_AI_SPECS) {
309
+ NAME_TO_AI[ai] = ai; // 直接使用ai
310
+ AI_TO_NAMES[ai] = [ai];
311
+ let detail = GS1_AI_SPECS[ai];
312
+ let v = GS1_AI_SPECS[ai];
313
+ let name = v.name.toLowerCase(); NAME_TO_AI[name] = ai; // 使用英文名
314
+ ////使用中文名
315
+ {
316
+ let desc = v.desc.replace('(m)', '米')
317
+ .replace('(m²)', '平')
318
+ .replace('(m³)', '方')
319
+ .replace('(lb)', '磅')
320
+ .replace('(kg)', '公斤')
321
+ .replace('(l)', '升')
322
+ .replace(/[\(\)]/g, '') // 再清理一次可能的残留括号
323
+ .trim()
324
+ .toLowerCase()
325
+ ;
326
+ NAME_TO_AI[desc] = ai;
327
+ AI_TO_NAMES[ai].push(desc);
328
+ ////
329
+ }
330
+ }
331
+ }
332
+ reset_map();
333
+ let FIXED_NAMES ;
334
+ const update_map = ()=> {
335
+ reset_map();
336
+ ////使用ALIAS
337
+ {
338
+ for(let alias in ALIAS) {
339
+ let ai = ALIAS[alias];
340
+ if(GS1_AI_SPECS[ai]){
341
+ NAME_TO_AI[alias.toLowerCase()] = ai;
342
+ AI_TO_NAMES[ai].push(alias.toLowerCase());
343
+ } else {
344
+ }
345
+
346
+ }
347
+ }
348
+ FIXED_NAMES = Object.keys(NAME_TO_AI);
349
+ }
350
+ update_map();
351
+
352
+
353
+ const name_to_ai = (name)=>{
354
+ name = String(name).toLowerCase();
355
+ let ai = NAME_TO_AI[name];
356
+ return ai;
357
+ }
358
+ const ai_to_names = (ai)=>AI_TO_NAMES[ai];
359
+
360
+
361
+ const encd_one =(name_or_ai,value)=>{
362
+ let ai = name_to_ai(name_or_ai);
363
+ if (!ai) {
364
+ //无效的字段名或AI代码: "${name_or_ai} 请尝试使用 未使用的自定义ai 90-99"
365
+ return [null,name_to_ai];
366
+ }
367
+ let [cond,v] = validate_and_fmt_ai_value(ai,value);
368
+ if(cond) {
369
+ return [true,`(${ai})${v}`];
370
+ } else {
371
+ return [false,v];
372
+ }
373
+ }
374
+
375
+
376
+ ////
377
+ const _encd = (arr) => {
378
+ let succs = [];let fails = [];
379
+ const aloc_next_unused_dyn_slot = ()=>{
380
+ for(let ai=90;ai<=99;++ai) {if(st.has(ai)) {} else {st.add(ai);return ai;}}
381
+ return null;
382
+ }
383
+ let len = arr.length;let st = new Set();
384
+ if(len === 0) { fails.push("参数不能为空");
385
+ } else {
386
+ if(len %2 === 0) {} else {arr.push(undefined);}
387
+ for(let i=0;i<arr.length;i+=2) {
388
+ let name_or_ai = arr[i];
389
+ let value = arr[i+1];
390
+ if(value !== undefined) {
391
+ let [cond,vstr] = encd_one(name_or_ai,value);
392
+ if(cond === null) {
393
+ let ai = aloc_next_unused_dyn_slot();
394
+ if(ai!== null) {
395
+ let [cond1,vstr1] = encd_one(ai,value);
396
+ if (cond1) {
397
+ succs.push(vstr1);ALIAS[String(name_or_ai).toLowerCase()] = ai;update_map();
398
+ } else {
399
+ fails.push(`${name_or_ai} : ${vstr}`)
400
+ }
401
+ } else {
402
+ fails.push(`${name_or_ai} 不是合法AI 并且 90-99 动态ai 都已占用`)
403
+ }
404
+ } else if(cond === true) {
405
+ succs.push(vstr);
406
+ let ai = Number(name_to_ai(name_or_ai));
407
+ if(ai>=90 && ai<=99 ) {
408
+ st.add(ai); //已经被占用
409
+ } else {}
410
+ } else {
411
+ fails.push(`${name_or_ai} : ${vstr}`)
412
+ }
413
+ } else {
414
+ fails.push(`${name_or_ai} : "值不能为空"`)
415
+ }
416
+ }
417
+ }
418
+ return [succs,fails]
419
+ }
420
+ const encd = (...args)=>{
421
+ if(args.length === 0) {
422
+ return null;
423
+ } else if(args.length === 1) {
424
+ let arr = args[0];
425
+ if(Array.isArray(args[0])) {
426
+ } else {
427
+ arr = Object.entries(args[0]).flat();
428
+ }
429
+ let [succs,fails] = _encd(arr);
430
+ let succ_str = succs.join("");
431
+ return succ_str===""?null:succ_str;
432
+ } else {
433
+ let [succs,fails] = _encd(args);
434
+ let succ_str = succs.join("");
435
+ return succ_str===""?null:succ_str;
436
+ }
437
+ }
438
+
439
+ const decd = (gs1_str, options = {}) => {
440
+ const {
441
+ strict = true, // 严格模式,验证每个字段
442
+ useChineseKeys = true, // 使用中文描述作为键
443
+ includeMeta = false, // 包含元数据
444
+ parseAll = true, // 解析所有字段,包括未知AI
445
+ } = options;
446
+
447
+ // 验证输入
448
+ if (!gs1_str || typeof gs1_str !== 'string') {
449
+ return [false, '输入必须是字符串'];
450
+ }
451
+
452
+ gs1_str = gs1_str.trim();
453
+ if (gs1_str === '') {
454
+ return [false, '输入字符串不能为空'];
455
+ }
456
+
457
+ // 验证GS1格式
458
+ if (!/^(?:\(\d{2,4}\)[^()]*)+$/.test(gs1_str)) {
459
+ if (strict) {
460
+ return [false, '无效的GS1格式'];
461
+ }
462
+ }
463
+
464
+ let result = {};
465
+ const errors = [];
466
+ const warnings = [];
467
+
468
+ // 匹配所有字段
469
+ const segments = gs1_str.match(/\((\d{2,4})\)([^()]*)/g) || [];
470
+
471
+ if (segments.length === 0) {
472
+ return [false, '未找到有效的GS1字段'];
473
+ }
474
+
475
+ for (const segment of segments) {
476
+ const match = segment.match(/\((\d{2,4})\)([^()]*)/);
477
+ if (!match) {
478
+ warnings.push(`无法解析段: ${segment}`);
479
+ continue;
480
+ }
481
+
482
+ const ai = match[1];
483
+ const rawValue = match[2];
484
+ const spec = GS1_AI_SPECS[ai];
485
+
486
+ // 解析值
487
+ let parsedValue = rawValue;
488
+ let isValid = true;
489
+ let error = null;
490
+
491
+ if (spec) {
492
+ // 已知字段
493
+ try {
494
+ // 根据字段类型验证长度
495
+ if (spec.length) {
496
+ if (spec.format === 'numeric' || spec.format === 'date') {
497
+ // numeric 和 date 必须是固定长度
498
+ if (rawValue.length !== spec.length) {
499
+ isValid = false;
500
+ error = `长度应为${spec.length}位,实际为${rawValue.length}位`;
501
+ }
502
+ } else if (spec.format === 'alphanumeric') {
503
+ // alphanumeric 只需要不超过最大长度 ✅
504
+ if (rawValue.length > spec.length) {
505
+ isValid = false;
506
+ error = `长度不能超过${spec.length}位,实际为${rawValue.length}位`;
507
+ }
508
+ }
509
+ }
510
+
511
+ if (spec.format === 'numeric') {
512
+ // 验证是否为纯数字
513
+ if (!/^\d+$/.test(rawValue)) {
514
+ isValid = false;
515
+ error = '数值字段必须为纯数字';
516
+ } else if (spec.decimal > 0) {
517
+ // 有小数位的数值
518
+ const num = parseInt(rawValue, 10) / Math.pow(10, spec.decimal);
519
+ parsedValue = Number(num.toFixed(spec.decimal));
520
+ } else {
521
+ // 整数
522
+ parsedValue = parseInt(rawValue, 10);
523
+ if (isNaN(parsedValue)) {
524
+ isValid = false;
525
+ error = '无效的整数值';
526
+ }
527
+ }
528
+ } else if (spec.format === 'date') {
529
+ // 日期验证
530
+ if (!/^\d{6}$/.test(rawValue)) {
531
+ isValid = false;
532
+ error = '日期必须是6位数字';
533
+ }
534
+ } else if (spec.format === 'alphanumeric') {
535
+ // 验证字符集
536
+ if (!GS1_ALPHANUMERIC_REGEX.test(rawValue)) {
537
+ warnings.push(`AI(${ai}) 包含不允许的字符`);
538
+ }
539
+ }
540
+
541
+ if (!isValid && strict) {
542
+ errors.push(`AI(${ai}) ${spec.desc || spec.name}: ${error}`);
543
+ continue;
544
+ }
545
+
546
+ // 确定键名
547
+ let key;
548
+ if (useChineseKeys && spec.desc) {
549
+ // 使用中文描述(清理后)
550
+ key = spec.desc
551
+ .replace(/\([^)]*\)/g, '')
552
+ .replace('m²', '平')
553
+ .replace('m³', '方')
554
+ .replace('kg', '公斤')
555
+ .replace('lb', '磅')
556
+ .replace('L', '升')
557
+ .replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '')
558
+ .trim();
559
+
560
+ if (key === '') {
561
+ key = spec.name ? spec.name.toLowerCase() : ai;
562
+ }
563
+ } else {
564
+ // 使用英文名
565
+ key = spec.name ? spec.name.toLowerCase() : ai;
566
+ }
567
+
568
+ // 添加到结果
569
+ if (isValid || !strict) {
570
+ result[key] = parsedValue;
571
+ }
572
+
573
+ if (includeMeta) {
574
+ result[`${key}_ai`] = ai;
575
+ result[`${key}_raw`] = rawValue;
576
+ if (!isValid) {
577
+ result[`${key}_error`] = error;
578
+ }
579
+ }
580
+
581
+ } catch (err) {
582
+ const errorMsg = `AI(${ai}) 解析错误: ${err.message}`;
583
+ if (strict) {
584
+ errors.push(errorMsg);
585
+ } else {
586
+ warnings.push(errorMsg);
587
+ }
588
+ }
589
+
590
+ } else if (parseAll) {
591
+ // 未知字段
592
+ result[`ai_${ai}`] = rawValue;
593
+ warnings.push(`未知AI代码: ${ai}`);
594
+ } else {
595
+ warnings.push(`跳过未知AI代码: ${ai}`);
596
+ }
597
+ }
598
+
599
+ // 构建最终结果
600
+ if (errors.length > 0) {
601
+ const errorMsg = errors.join('; ');
602
+ if (warnings.length > 0) {
603
+ return [false, `${errorMsg} (警告: ${warnings.join('; ')})`];
604
+ }
605
+ return [false, errorMsg];
606
+ }
607
+
608
+ if (includeMeta) {
609
+ const meta = {};
610
+ if (warnings.length > 0) {
611
+ meta.warnings = warnings;
612
+ }
613
+ if (Object.keys(result).length > 0) {
614
+ meta.fieldCount = Object.keys(result).filter(k => !k.endsWith('_ai') && !k.endsWith('_raw') && !k.endsWith('_error')).length;
615
+ }
616
+
617
+ result._meta = meta;
618
+ } else if (warnings.length > 0) {
619
+ console.warn('GS1解析警告:', warnings.join('; '));
620
+ }
621
+
622
+ return [true, result];
623
+ };
624
+
625
+ const rand_one = (onlyChineseName = false, onlyEnglishName = false) => {
626
+ // 获取所有可用的字段名
627
+ let availableNames = [];
628
+
629
+ if (onlyChineseName && onlyEnglishName) {
630
+ // 两个都true,就返回所有
631
+ availableNames = Object.keys(NAME_TO_AI);
632
+ } else if (onlyChineseName) {
633
+ // 只返回中文名
634
+ availableNames = Object.keys(NAME_TO_AI).filter(name => {
635
+ return /[\u4e00-\u9fa5]/.test(name) ||
636
+ ALIAS[name] && /[\u4e00-\u9fa5]/.test(Object.keys(ALIAS).find(k => ALIAS[k] === ALIAS[name]));
637
+ });
638
+ } else if (onlyEnglishName) {
639
+ // 只返回英文名
640
+ availableNames = Object.keys(NAME_TO_AI).filter(name => {
641
+ return /^[a-zA-Z]/.test(name) &&
642
+ !/[\u4e00-\u9fa5]/.test(name) &&
643
+ !/^\d+$/.test(name);
644
+ });
645
+ } else {
646
+ // 返回所有
647
+ availableNames = Object.keys(NAME_TO_AI);
648
+ }
649
+
650
+ if (availableNames.length === 0) {
651
+ return null;
652
+ }
653
+
654
+ // 随机选择一个字段
655
+ const randomName = availableNames[Math.floor(Math.random() * availableNames.length)];
656
+ const ai = NAME_TO_AI[randomName];
657
+ const spec = GS1_AI_SPECS[ai];
658
+
659
+ if (!spec) {
660
+ return null;
661
+ }
662
+
663
+ // 根据字段类型生成随机值
664
+ let randomValue;
665
+
666
+ switch (spec.format) {
667
+ case 'numeric':
668
+ if (spec.decimal > 0) {
669
+ // 带小数的数值
670
+ const maxValue = Math.pow(10, spec.length - spec.decimal) - 1;
671
+ const integer = Math.floor(Math.random() * maxValue);
672
+ const decimal = Math.floor(Math.random() * Math.pow(10, spec.decimal));
673
+ randomValue = integer + decimal / Math.pow(10, spec.decimal);
674
+
675
+ // 格式化为指定小数位
676
+ randomValue = Number(randomValue.toFixed(spec.decimal));
677
+ } else {
678
+ // 整数
679
+ const maxValue = Math.pow(10, spec.length) - 1;
680
+ randomValue = Math.floor(Math.random() * maxValue);
681
+ }
682
+ break;
683
+
684
+ case 'date':
685
+ // 生成未来2年内的随机日期
686
+ const now = new Date();
687
+ const futureDate = new Date(now.getTime() + Math.random() * 2 * 365 * 24 * 60 * 60 * 1000);
688
+ const year = futureDate.getFullYear() % 100;
689
+ const month = futureDate.getMonth() + 1;
690
+ const day = futureDate.getDate();
691
+ randomValue = `${year.toString().padStart(2, '0')}${month.toString().padStart(2, '0')}${day.toString().padStart(2, '0')}`;
692
+ break;
693
+
694
+ case 'alphanumeric':
695
+ // 随机长度(1到最大长度)
696
+ const length = Math.floor(Math.random() * spec.length) + 1;
697
+
698
+ // 修正:使用安全的字符集
699
+ // 只使用字母、数字、连字符、下划线
700
+ const safeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
701
+
702
+ randomValue = '';
703
+ for (let i = 0; i < length; i++) {
704
+ randomValue += safeChars[Math.floor(Math.random() * safeChars.length)];
705
+ }
706
+
707
+ break;
708
+
709
+ default:
710
+ randomValue = '';
711
+ }
712
+
713
+ return {
714
+ name: randomName,
715
+ ai: ai,
716
+ value: randomValue,
717
+ spec: spec
718
+ };
719
+ };
720
+
721
+ const rand = (max_cnt = 5, min_cnt = 1, options = {}) => {
722
+ // 参数处理
723
+ min_cnt = min_cnt < 1 ? 1 : min_cnt;
724
+ max_cnt = max_cnt > min_cnt ? max_cnt : min_cnt;
725
+
726
+ // 从选项中获取参数
727
+ const {
728
+ onlyChineseName = false,
729
+ onlyEnglishName = false,
730
+ includeCustomAI = false,
731
+ uniqueAI = true,
732
+ maxTotalLength = 48,
733
+ returnObject = false, // 是否返回对象而不是字符串
734
+ } = options;
735
+
736
+ // 随机生成实际数量
737
+ const actualCount = Math.floor(Math.random() * (max_cnt - min_cnt + 1)) + min_cnt;
738
+
739
+ const fields = [];
740
+ const usedAIs = new Set();
741
+ let totalLength = 0;
742
+
743
+ for (let i = 0; i < actualCount; i++) {
744
+ let field;
745
+ let attempts = 0;
746
+ const maxAttempts = 20;
747
+
748
+ do {
749
+ field = rand_one(onlyChineseName, onlyEnglishName);
750
+ attempts++;
751
+
752
+ if (!field) break;
753
+
754
+ // 检查是否排除自定义AI
755
+ if (!includeCustomAI && /^9[0-9]$/.test(field.ai)) {
756
+ continue;
757
+ }
758
+
759
+ // 检查AI是否唯一
760
+ if (uniqueAI && usedAIs.has(field.ai)) {
761
+ continue;
762
+ }
763
+
764
+ // 检查总长度
765
+ const fieldLength = `(${field.ai})${field.value}`.length;
766
+ if (totalLength + fieldLength > maxTotalLength) {
767
+ continue;
768
+ }
769
+
770
+ break;
771
+ } while (attempts < maxAttempts);
772
+
773
+ if (!field || attempts >= maxAttempts) {
774
+ break;
775
+ }
776
+
777
+ usedAIs.add(field.ai);
778
+ totalLength += `(${field.ai})${field.value}`.length;
779
+ fields.push(field);
780
+ }
781
+
782
+ if (fields.length === 0) {
783
+ return returnObject ? { success: false, error: "未能生成任何字段" } : null;
784
+ }
785
+
786
+ // 编码为GS1字符串
787
+ const gs1Parts = [];
788
+
789
+ for (const field of fields) {
790
+ // 使用 encd 函数编码
791
+ const encoded = x.gs1.encd(field.name, field.value);
792
+ if (encoded) {
793
+ gs1Parts.push(encoded);
794
+ }
795
+ }
796
+
797
+ if (gs1Parts.length === 0) {
798
+ return returnObject ? {
799
+ success: false,
800
+ error: "所有字段编码失败"
801
+ } : null;
802
+ }
803
+
804
+ const gs1String = gs1Parts.join("");
805
+
806
+ if (returnObject) {
807
+ return {
808
+ success: true,
809
+ gs1: gs1String,
810
+ fields: fields,
811
+ count: fields.length,
812
+ length: gs1String.length,
813
+ withinLengthLimit: gs1String.length <= maxTotalLength
814
+ };
815
+ }
816
+
817
+ return gs1String;
818
+ };
819
+
820
+ module.exports = {
821
+ get GS1_AI_SPECS() {return GS1_AI_SPECS;},
822
+ get ALIAS() {return ALIAS;},
823
+ set ALIAS(d) {
824
+ ALIAS = d;
825
+ update_map();
826
+ },
827
+ get NAME_TO_AI() {return NAME_TO_AI;},
828
+ get AI_TO_NAMES() {return AI_TO_NAMES;},
829
+ get FIXED_NAMES() {return FIXED_NAMES;},
830
+ validate_and_fmt_ai_value,
831
+ name_to_ai,ai_to_names,
832
+ encd_one,
833
+ _encd,
834
+ encd,
835
+ decd,
836
+ list_names: ()=>FIXED_NAMES,
837
+ look_requirements: (name)=>GS1_AI_SPECS[name_to_ai(name)],
838
+ rand_one,rand,
839
+
840
+ }
package/index.js CHANGED
@@ -1,88 +1,5 @@
1
- const {
2
- code128_code_to_ptrn,
3
- code128_ptrn_to_code,
4
- CODE128_CODE_TO_PTRN
5
- } = require("./ptrn")
6
-
7
- const bytes_to_code128 = (bytes) => {
8
- const codes = [];
9
- const START_B = 104;
10
- codes.push(START_B);
11
-
12
- for (const b of bytes) {
13
- codes.push(b & 0x7f); // 与 decoder 对称
14
- }
15
-
16
- // checksum
17
- let sum = START_B;
18
- codes.slice(1).forEach((c, i) => {
19
- sum += c * (i + 1);
20
- });
21
- codes.push(sum % 103);
22
-
23
- // STOP
24
- codes.push(106);
25
-
26
- // codes -> modules
27
- return codes.flatMap(c => CODE128_CODE_TO_PTRN[c]);
28
- };
29
-
30
- const code128_to_bytes = (modules) => {
31
- const codes = [];
32
- let i = 0;
33
-
34
- while (i < modules.length) {
35
- let code = code128_ptrn_to_code(modules.slice(i, i + 6));
36
- if (code >= 0) {
37
- codes.push(code);
38
- i += 6;
39
- continue;
40
- }
41
-
42
- // 尝试 STOP
43
- if (i + 7 <= modules.length) {
44
- code = code128_ptrn_to_code(modules.slice(i, i + 7));
45
- if (code === 106) {
46
- codes.push(106);
47
- i += 7;
48
- break;
49
- }
50
- }
51
-
52
- // 不匹配也安全跳过:+1 移动
53
- i += 1;
54
- }
55
-
56
- // 安全处理 START / STOP
57
- if (codes.length === 0 || codes[0] !== 104) {
58
- // 没有 START_B,用空 payload
59
- return new Uint8Array(0);
60
- }
61
-
62
- // 去掉 START / checksum / STOP
63
- const payload = codes.slice(1, -2);
64
-
65
- // checksum 校验可选
66
- let sum = 104;
67
- payload.forEach((c, i) => sum += c * (i + 1));
68
- const checksum = codes[codes.length - 2] ?? 0;
69
- if (sum % 103 !== checksum) {
70
- // 可以返回 null 或空数组表示校验失败
71
- return new Uint8Array(0);
72
- }
73
-
74
- return Uint8Array.from(payload);
75
- };
76
-
77
- const normalize_runs_to_modules = (runs) => {
78
- const min = Math.min(...runs);
79
- return runs.map(r => Math.max(1, Math.round(r / min)));
80
- };
81
-
82
-
1
+ const gs1 = require("./gs1");
83
2
 
84
3
  module.exports = {
85
- bytes_to_code128,
86
- code128_to_bytes,
87
- normalize_runs_to_modules,
4
+ gs1
88
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nv-img-barcode-cmmn",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
package/ptrn.js DELETED
@@ -1,161 +0,0 @@
1
- // Code 128 patterns (ISO/IEC 15417)
2
- const CODE128_CODE_TO_PTRN = [
3
- [2,1,2,2,2,2], // 0
4
- [2,2,2,1,2,2], // 1
5
- [2,2,2,2,2,1], // 2
6
- [1,2,1,2,2,3], // 3
7
- [1,2,1,3,2,2], // 4
8
- [1,3,1,2,2,2], // 5
9
- [1,2,2,2,1,3], // 6
10
- [1,2,2,3,1,2], // 7
11
- [1,3,2,2,1,2], // 8
12
- [2,2,1,2,1,3], // 9
13
- [2,2,1,3,1,2], // 10
14
- [2,3,1,2,1,2], // 11
15
- [1,1,2,2,3,2], // 12
16
- [1,2,2,1,3,2], // 13
17
- [1,2,2,2,3,1], // 14
18
- [1,1,3,2,2,2], // 15
19
- [1,2,3,1,2,2], // 16
20
- [1,2,3,2,2,1], // 17
21
- [2,2,3,2,1,1], // 18
22
- [2,2,1,1,3,2], // 19
23
- [2,2,1,2,3,1], // 20
24
- [2,1,3,2,1,2], // 21
25
- [2,2,3,1,1,2], // 22
26
- [3,1,2,1,3,1], // 23
27
- [3,1,1,2,2,2], // 24
28
- [3,2,1,1,2,2], // 25
29
- [3,2,1,2,2,1], // 26
30
- [3,1,2,2,1,2], // 27
31
- [3,2,2,1,1,2], // 28
32
- [3,2,2,2,1,1], // 29
33
- [2,1,2,1,2,3], // 30
34
- [2,1,2,3,2,1], // 31
35
- [2,3,2,1,2,1], // 32
36
- [1,1,1,3,2,3], // 33
37
- [1,3,1,1,2,3], // 34
38
- [1,3,1,3,2,1], // 35
39
- [1,1,2,3,1,3], // 36
40
- [1,3,2,1,1,3], // 37
41
- [1,3,2,3,1,1], // 38
42
- [2,1,1,3,1,3], // 39
43
- [2,3,1,1,1,3], // 40
44
- [2,3,1,3,1,1], // 41
45
- [1,1,2,1,3,3], // 42
46
- [1,1,2,3,3,1], // 43
47
- [1,3,2,1,3,1], // 44
48
- [1,1,3,1,2,3], // 45
49
- [1,1,3,3,2,1], // 46
50
- [1,3,3,1,2,1], // 47
51
- [3,1,3,1,2,1], // 48
52
- [2,1,1,3,3,1], // 49
53
- [2,3,1,1,3,1], // 50
54
- [2,1,3,1,1,3], // 51
55
- [2,1,3,3,1,1], // 52
56
- [2,1,3,1,3,1], // 53
57
- [3,1,1,1,2,3], // 54
58
- [3,1,1,3,2,1], // 55
59
- [3,3,1,1,2,1], // 56
60
- [3,1,2,1,1,3], // 57
61
- [3,1,2,3,1,1], // 58
62
- [3,3,2,1,1,1], // 59
63
- [3,1,4,1,1,1], // 60
64
- [2,2,1,4,1,1], // 61
65
- [4,3,1,1,1,1], // 62
66
- [1,1,1,2,2,4], // 63
67
- [1,1,1,4,2,2], // 64
68
- [1,2,1,1,2,4], // 65
69
- [1,2,1,4,2,1], // 66
70
- [1,4,1,1,2,2], // 67
71
- [1,4,1,2,2,1], // 68
72
- [1,1,2,2,1,4], // 69
73
- [1,1,2,4,1,2], // 70
74
- [1,2,2,1,1,4], // 71
75
- [1,2,2,4,1,1], // 72
76
- [1,4,2,1,1,2], // 73
77
- [1,4,2,2,1,1], // 74
78
- [2,4,1,2,1,1], // 75
79
- [2,2,1,1,1,4], // 76
80
- [4,1,3,1,1,1], // 77
81
- [2,4,1,1,1,2], // 78
82
- [1,3,4,1,1,1], // 79
83
- [1,1,1,2,4,2], // 80
84
- [1,2,1,1,4,2], // 81
85
- [1,2,1,2,4,1], // 82
86
- [1,1,4,2,1,2], // 83
87
- [1,2,4,1,1,2], // 84
88
- [1,2,4,2,1,1], // 85
89
- [4,1,1,2,1,2], // 86
90
- [4,2,1,1,1,2], // 87
91
- [4,2,1,2,1,1], // 88
92
- [2,1,2,1,4,1], // 89
93
- [2,1,4,1,2,1], // 90
94
- [4,1,2,1,2,1], // 91
95
- [1,1,1,1,4,3], // 92
96
- [1,1,1,3,4,1], // 93
97
- [1,3,1,1,4,1], // 94
98
- [1,1,4,1,1,3], // 95
99
- [1,1,4,3,1,1], // 96
100
- [4,1,1,1,1,3], // 97
101
- [4,1,1,3,1,1], // 98
102
- [1,1,3,1,4,1], // 99
103
- [1,1,4,1,3,1], // 100
104
- [3,1,1,1,4,1], // 101
105
- [4,1,1,1,3,1], // 102
106
- [2,1,1,4,1,2], // 103 START A
107
- [2,1,1,2,1,4], // 104 START B
108
- [2,1,1,2,3,2], // 105 START C
109
- [2,3,3,1,1,1,2], // 106 STOP (7 modules!)
110
- ];
111
-
112
- const arr_to_intkey = (arr)=> parseInt(arr.join(""),5);
113
-
114
- const [MIN_KEY,CODE128_PTRN_TO_CODE] = JSON.parse(JSON.stringify(
115
- (() => {
116
- const mp = {};
117
- for (let i = 0; i < CODE128_CODE_TO_PTRN.length; i++) {
118
- const arr = CODE128_CODE_TO_PTRN[i];
119
- mp[arr_to_intkey(arr)]=i;
120
- }
121
- let ks = Object.keys(mp);
122
- ks = ks.map(r=>Number(r));
123
- ks.sort((a,b)=>a-b);
124
- let MIN = ks[0];
125
- let MAX = ks[ks.length-1];
126
- let arr = [];
127
- for(let i=0;i<=MAX;++i) {arr[i] = 0;}
128
- for(let k of ks) { arr[k-MIN] = mp[k];}
129
- return [MIN,arr];
130
- })()
131
- ));
132
-
133
-
134
- const code128_code_to_ptrn = (cd) => CODE128_CODE_TO_PTRN[cd]; //->Array<>
135
- const code128_ptrn_to_code = (arr)=> {
136
- const key = arr_to_intkey(arr);
137
- const idx = key - MIN_KEY;
138
- return CODE128_PTRN_TO_CODE[idx];
139
- }
140
-
141
-
142
- module.exports = {
143
- CODE128_CODE_TO_PTRN,
144
- MIN_KEY,
145
- CODE128_PTRN_TO_CODE,
146
- ////
147
- arr_to_intkey,
148
- code128_code_to_ptrn,
149
- code128_ptrn_to_code
150
- }
151
-
152
- if(module.id===".") {
153
- for(let i=0;i<CODE128_CODE_TO_PTRN.length;++i) {
154
- let expected = CODE128_CODE_TO_PTRN[i];
155
- let actual = code128_ptrn_to_code(CODE128_CODE_TO_PTRN[i]);
156
- if(actual!== i) {
157
- throw({expected,actual})
158
- } else {
159
- }
160
- }
161
- } else {}