isahaq-barcode 1.0.0

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.
@@ -0,0 +1,352 @@
1
+ /**
2
+ * Validator - Data validation for different barcode types
3
+ */
4
+
5
+ const { BarcodeTypes } = require('../types/BarcodeTypes');
6
+
7
+ class Validator {
8
+ constructor() {
9
+ this.patterns = {
10
+ // Numeric patterns
11
+ numeric: /^[0-9]+$/,
12
+ // Alphanumeric patterns
13
+ alphanumeric: /^[A-Za-z0-9]+$/,
14
+ // Code 39 pattern
15
+ code39: /^[A-Z0-9\s\-\.\$\/\+\%]+$/,
16
+ // Code 39 extended pattern
17
+ code39extended: /^[\x00-\x7F]+$/,
18
+ // EAN/UPC patterns
19
+ ean13: /^[0-9]{12,13}$/,
20
+ ean8: /^[0-9]{7,8}$/,
21
+ upca: /^[0-9]{11,12}$/,
22
+ upce: /^[0-9]{6,8}$/,
23
+ // QR Code pattern (supports Unicode)
24
+ qrcode: /^[\s\S]+$/,
25
+ // Data Matrix pattern
26
+ datamatrix: /^[\s\S]+$/,
27
+ // PDF417 pattern
28
+ pdf417: /^[\s\S]+$/,
29
+ };
30
+ }
31
+
32
+ /**
33
+ * Validate data for a specific barcode type
34
+ * @param {string} data - The data to validate
35
+ * @param {string} type - The barcode type
36
+ * @returns {Object} Validation result
37
+ */
38
+ validate(data, type) {
39
+ if (!data || typeof data !== 'string') {
40
+ return {
41
+ valid: false,
42
+ error: 'Data must be a non-empty string',
43
+ };
44
+ }
45
+
46
+ if (!BarcodeTypes.isValid(type)) {
47
+ return {
48
+ valid: false,
49
+ error: `Invalid barcode type: ${type}`,
50
+ };
51
+ }
52
+
53
+ // Get configuration for the barcode type
54
+ const config = BarcodeTypes.getConfig(type);
55
+
56
+ // Check length constraints
57
+ if (data.length < config.minLength) {
58
+ return {
59
+ valid: false,
60
+ error: `Data too short. Minimum length: ${config.minLength}`,
61
+ };
62
+ }
63
+
64
+ if (data.length > config.maxLength) {
65
+ return {
66
+ valid: false,
67
+ error: `Data too long. Maximum length: ${config.maxLength}`,
68
+ };
69
+ }
70
+
71
+ // Type-specific validation
72
+ const validationResult = this.validateByType(data, type);
73
+ if (!validationResult.valid) {
74
+ return validationResult;
75
+ }
76
+
77
+ return {
78
+ valid: true,
79
+ data,
80
+ type,
81
+ length: data.length,
82
+ charset: config.charset,
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Validate data by barcode type
88
+ * @param {string} data - The data to validate
89
+ * @param {string} type - The barcode type
90
+ * @returns {Object} Validation result
91
+ */
92
+ validateByType(data, type) {
93
+ switch (type) {
94
+ case 'code128':
95
+ case 'code128a':
96
+ case 'code128b':
97
+ case 'code128c':
98
+ case 'code128auto':
99
+ return this.validateCode128(data, type);
100
+
101
+ case 'code39':
102
+ case 'code39extended':
103
+ case 'code39checksum':
104
+ case 'code39auto':
105
+ return this.validateCode39(data, type);
106
+
107
+ case 'code93':
108
+ return this.validateCode93(data);
109
+
110
+ case 'ean13':
111
+ return this.validateEAN13(data);
112
+
113
+ case 'ean8':
114
+ return this.validateEAN8(data);
115
+
116
+ case 'upca':
117
+ return this.validateUPCA(data);
118
+
119
+ case 'upce':
120
+ return this.validateUPCE(data);
121
+
122
+ case 'qrcode':
123
+ return this.validateQRCode(data);
124
+
125
+ case 'datamatrix':
126
+ return this.validateDataMatrix(data);
127
+
128
+ case 'pdf417':
129
+ return this.validatePDF417(data);
130
+
131
+ default:
132
+ // For other types, just check if data is not empty
133
+ return {
134
+ valid: data.length > 0,
135
+ error: data.length === 0 ? 'Data cannot be empty' : null,
136
+ };
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Validate Code 128 data
142
+ * @param {string} data - The data to validate
143
+ * @param {string} type - The Code 128 variant
144
+ * @returns {Object} Validation result
145
+ */
146
+ validateCode128(data) {
147
+ // Code 128 supports ASCII characters
148
+ if (!/^[\x00-\x7F]+$/.test(data)) {
149
+ return {
150
+ valid: false,
151
+ error: 'Code 128 supports ASCII characters only',
152
+ };
153
+ }
154
+
155
+ return { valid: true };
156
+ }
157
+
158
+ /**
159
+ * Validate Code 39 data
160
+ * @param {string} data - The data to validate
161
+ * @param {string} type - The Code 39 variant
162
+ * @returns {Object} Validation result
163
+ */
164
+ validateCode39(data, type) {
165
+ if (type === 'code39extended') {
166
+ // Extended Code 39 supports full ASCII
167
+ if (!/^[\x00-\x7F]+$/.test(data)) {
168
+ return {
169
+ valid: false,
170
+ error: 'Extended Code 39 supports ASCII characters only',
171
+ };
172
+ }
173
+ } else {
174
+ // Standard Code 39 supports limited character set
175
+ if (!this.patterns.code39.test(data)) {
176
+ return {
177
+ valid: false,
178
+ error: 'Code 39 supports characters: A-Z, 0-9, space, -.$/+%',
179
+ };
180
+ }
181
+ }
182
+
183
+ return { valid: true };
184
+ }
185
+
186
+ /**
187
+ * Validate Code 93 data
188
+ * @param {string} data - The data to validate
189
+ * @returns {Object} Validation result
190
+ */
191
+ validateCode93(data) {
192
+ if (!this.patterns.alphanumeric.test(data)) {
193
+ return {
194
+ valid: false,
195
+ error: 'Code 93 supports alphanumeric characters only',
196
+ };
197
+ }
198
+
199
+ return { valid: true };
200
+ }
201
+
202
+ /**
203
+ * Validate EAN-13 data
204
+ * @param {string} data - The data to validate
205
+ * @returns {Object} Validation result
206
+ */
207
+ validateEAN13(data) {
208
+ if (!this.patterns.ean13.test(data)) {
209
+ return {
210
+ valid: false,
211
+ error: 'EAN-13 must be 12 or 13 digits',
212
+ };
213
+ }
214
+
215
+ // Validate check digit if 13 digits provided
216
+ if (data.length === 13) {
217
+ const checkDigit = this.calculateEANCheckDigit(data.substring(0, 12));
218
+ if (parseInt(data[12]) !== checkDigit) {
219
+ return {
220
+ valid: false,
221
+ error: 'Invalid EAN-13 check digit',
222
+ };
223
+ }
224
+ }
225
+
226
+ return { valid: true };
227
+ }
228
+
229
+ /**
230
+ * Validate EAN-8 data
231
+ * @param {string} data - The data to validate
232
+ * @returns {Object} Validation result
233
+ */
234
+ validateEAN8(data) {
235
+ if (!this.patterns.ean8.test(data)) {
236
+ return {
237
+ valid: false,
238
+ error: 'EAN-8 must be 7 or 8 digits',
239
+ };
240
+ }
241
+
242
+ // Validate check digit if 8 digits provided
243
+ if (data.length === 8) {
244
+ const checkDigit = this.calculateEANCheckDigit(data.substring(0, 7));
245
+ if (parseInt(data[7]) !== checkDigit) {
246
+ return {
247
+ valid: false,
248
+ error: 'Invalid EAN-8 check digit',
249
+ };
250
+ }
251
+ }
252
+
253
+ return { valid: true };
254
+ }
255
+
256
+ /**
257
+ * Validate UPC-A data
258
+ * @param {string} data - The data to validate
259
+ * @returns {Object} Validation result
260
+ */
261
+ validateUPCA(data) {
262
+ if (!this.patterns.upca.test(data)) {
263
+ return {
264
+ valid: false,
265
+ error: 'UPC-A must be 11 or 12 digits',
266
+ };
267
+ }
268
+
269
+ return { valid: true };
270
+ }
271
+
272
+ /**
273
+ * Validate UPC-E data
274
+ * @param {string} data - The data to validate
275
+ * @returns {Object} Validation result
276
+ */
277
+ validateUPCE(data) {
278
+ if (!this.patterns.upce.test(data)) {
279
+ return {
280
+ valid: false,
281
+ error: 'UPC-E must be 6 to 8 digits',
282
+ };
283
+ }
284
+
285
+ return { valid: true };
286
+ }
287
+
288
+ /**
289
+ * Validate QR Code data
290
+ * @param {string} data - The data to validate
291
+ * @returns {Object} Validation result
292
+ */
293
+ validateQRCode(data) {
294
+ // QR Code supports Unicode, so we just check if it's not empty
295
+ if (data.length === 0) {
296
+ return {
297
+ valid: false,
298
+ error: 'QR Code data cannot be empty',
299
+ };
300
+ }
301
+
302
+ return { valid: true };
303
+ }
304
+
305
+ /**
306
+ * Validate Data Matrix data
307
+ * @param {string} data - The data to validate
308
+ * @returns {Object} Validation result
309
+ */
310
+ validateDataMatrix(data) {
311
+ if (data.length === 0) {
312
+ return {
313
+ valid: false,
314
+ error: 'Data Matrix data cannot be empty',
315
+ };
316
+ }
317
+
318
+ return { valid: true };
319
+ }
320
+
321
+ /**
322
+ * Validate PDF417 data
323
+ * @param {string} data - The data to validate
324
+ * @returns {Object} Validation result
325
+ */
326
+ validatePDF417(data) {
327
+ if (data.length === 0) {
328
+ return {
329
+ valid: false,
330
+ error: 'PDF417 data cannot be empty',
331
+ };
332
+ }
333
+
334
+ return { valid: true };
335
+ }
336
+
337
+ /**
338
+ * Calculate EAN check digit
339
+ * @param {string} data - The data without check digit
340
+ * @returns {number} Check digit
341
+ */
342
+ calculateEANCheckDigit(data) {
343
+ let sum = 0;
344
+ for (let i = 0; i < data.length; i++) {
345
+ const digit = parseInt(data[i]);
346
+ sum += i % 2 === 0 ? digit : digit * 3;
347
+ }
348
+ return (10 - (sum % 10)) % 10;
349
+ }
350
+ }
351
+
352
+ module.exports = { Validator };
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Tests for BarcodeGenerator
3
+ */
4
+
5
+ const BarcodeGenerator = require('../index');
6
+
7
+ describe('BarcodeGenerator', () => {
8
+ describe('PNG Generation', () => {
9
+ test('should generate PNG barcode', () => {
10
+ const result = BarcodeGenerator.png('1234567890', 'code128');
11
+ expect(Buffer.isBuffer(result)).toBe(true);
12
+ });
13
+
14
+ test('should generate PNG barcode with options', () => {
15
+ const options = {
16
+ width: 3,
17
+ height: 150,
18
+ displayValue: false,
19
+ };
20
+ const result = BarcodeGenerator.png('1234567890', 'code128', options);
21
+ expect(Buffer.isBuffer(result)).toBe(true);
22
+ });
23
+
24
+ test('should throw error for invalid data', () => {
25
+ expect(() => {
26
+ BarcodeGenerator.png('', 'code128');
27
+ }).toThrow('Data must be a non-empty string');
28
+ });
29
+
30
+ test('should throw error for invalid barcode type', () => {
31
+ expect(() => {
32
+ BarcodeGenerator.png('1234567890', 'invalid-type');
33
+ }).toThrow('Invalid barcode type');
34
+ });
35
+ });
36
+
37
+ describe('SVG Generation', () => {
38
+ test('should generate SVG barcode', () => {
39
+ const result = BarcodeGenerator.svg('1234567890', 'code128');
40
+ expect(typeof result).toBe('string');
41
+ expect(result).toContain('<svg');
42
+ });
43
+
44
+ test('should generate SVG barcode with options', () => {
45
+ const options = {
46
+ width: 3,
47
+ height: 150,
48
+ displayValue: false,
49
+ };
50
+ const result = BarcodeGenerator.svg('1234567890', 'code128', options);
51
+ expect(typeof result).toBe('string');
52
+ });
53
+ });
54
+
55
+ describe('HTML Generation', () => {
56
+ test('should generate HTML barcode', () => {
57
+ const result = BarcodeGenerator.html('1234567890', 'code128');
58
+ expect(typeof result).toBe('string');
59
+ expect(result).toContain('<div');
60
+ });
61
+
62
+ test('should generate HTML barcode with options', () => {
63
+ const options = {
64
+ width: 3,
65
+ height: 150,
66
+ displayValue: false,
67
+ };
68
+ const result = BarcodeGenerator.html('1234567890', 'code128', options);
69
+ expect(typeof result).toBe('string');
70
+ });
71
+ });
72
+
73
+ describe('PDF Generation', () => {
74
+ test('should generate PDF barcode', async () => {
75
+ const result = await BarcodeGenerator.pdf('1234567890', 'code128');
76
+ expect(Buffer.isBuffer(result)).toBe(true);
77
+ });
78
+
79
+ test('should generate PDF barcode with options', async () => {
80
+ const options = {
81
+ width: 3,
82
+ height: 150,
83
+ displayValue: false,
84
+ };
85
+ const result = await BarcodeGenerator.pdf(
86
+ '1234567890',
87
+ 'code128',
88
+ options
89
+ );
90
+ expect(Buffer.isBuffer(result)).toBe(true);
91
+ });
92
+ });
93
+
94
+ describe('QR Code Generation', () => {
95
+ test('should generate QR code', () => {
96
+ const result = BarcodeGenerator.modernQr({
97
+ data: 'https://example.com',
98
+ size: 300,
99
+ });
100
+ expect(result).toBeDefined();
101
+ expect(typeof result.generate).toBe('function');
102
+ });
103
+
104
+ test('should generate QR code with logo', () => {
105
+ const result = BarcodeGenerator.modernQr({
106
+ data: 'https://example.com',
107
+ size: 300,
108
+ logoPath: 'path/to/logo.png',
109
+ logoSize: 60,
110
+ });
111
+ expect(result).toBeDefined();
112
+ });
113
+
114
+ test('should generate QR code with watermark', () => {
115
+ const result = BarcodeGenerator.modernQr({
116
+ data: 'https://example.com',
117
+ size: 300,
118
+ watermark: 'Watermark Text',
119
+ watermarkPosition: 'center',
120
+ });
121
+ expect(result).toBeDefined();
122
+ });
123
+ });
124
+
125
+ describe('Validation', () => {
126
+ test('should validate data for Code 128', () => {
127
+ const validation = BarcodeGenerator.validate('1234567890', 'code128');
128
+ expect(validation.valid).toBe(true);
129
+ });
130
+
131
+ test('should validate data for EAN-13', () => {
132
+ const validation = BarcodeGenerator.validate('1234567890123', 'ean13');
133
+ expect(validation.valid).toBe(true);
134
+ });
135
+
136
+ test('should reject invalid data for EAN-13', () => {
137
+ const validation = BarcodeGenerator.validate('123', 'ean13');
138
+ expect(validation.valid).toBe(false);
139
+ expect(validation.error).toContain('too short');
140
+ });
141
+ });
142
+
143
+ describe('Batch Generation', () => {
144
+ test('should generate multiple barcodes', () => {
145
+ const items = [
146
+ { data: '1234567890', type: 'code128', format: 'png' },
147
+ { data: '9876543210', type: 'code39', format: 'svg' },
148
+ ];
149
+ const results = BarcodeGenerator.batch(items);
150
+ expect(Array.isArray(results)).toBe(true);
151
+ expect(results.length).toBe(2);
152
+ });
153
+
154
+ test('should handle batch generation errors', () => {
155
+ const items = [
156
+ { data: '1234567890', type: 'code128', format: 'png' },
157
+ { data: '', type: 'code128', format: 'png' }, // Invalid data
158
+ ];
159
+ const results = BarcodeGenerator.batch(items);
160
+ expect(results[0].success).toBe(true);
161
+ expect(results[1].success).toBe(false);
162
+ });
163
+ });
164
+
165
+ describe('Utility Methods', () => {
166
+ test('should get barcode types', () => {
167
+ const types = BarcodeGenerator.getBarcodeTypes();
168
+ expect(Array.isArray(types)).toBe(true);
169
+ expect(types).toContain('code128');
170
+ expect(types).toContain('ean13');
171
+ });
172
+
173
+ test('should get render formats', () => {
174
+ const formats = BarcodeGenerator.getRenderFormats();
175
+ expect(Array.isArray(formats)).toBe(true);
176
+ expect(formats).toContain('png');
177
+ expect(formats).toContain('svg');
178
+ });
179
+
180
+ test('should get watermark positions', () => {
181
+ const positions = BarcodeGenerator.getWatermarkPositions();
182
+ expect(Array.isArray(positions)).toBe(true);
183
+ expect(positions).toContain('center');
184
+ expect(positions).toContain('top-left');
185
+ });
186
+ });
187
+ });
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Tests for BarcodeService
3
+ */
4
+
5
+ const BarcodeService = require('../src/services/BarcodeService');
6
+
7
+ describe('BarcodeService', () => {
8
+ let service;
9
+
10
+ beforeEach(() => {
11
+ service = new BarcodeService();
12
+ });
13
+
14
+ describe('PNG Generation', () => {
15
+ test('should generate PNG barcode', () => {
16
+ const result = service.png('1234567890', 'code128');
17
+ expect(Buffer.isBuffer(result)).toBe(true);
18
+ });
19
+
20
+ test('should generate PNG barcode with options', () => {
21
+ const options = {
22
+ width: 3,
23
+ height: 150,
24
+ displayValue: false,
25
+ };
26
+ const result = service.png('1234567890', 'code128', options);
27
+ expect(Buffer.isBuffer(result)).toBe(true);
28
+ });
29
+ });
30
+
31
+ describe('SVG Generation', () => {
32
+ test('should generate SVG barcode', () => {
33
+ const result = service.svg('1234567890', 'code128');
34
+ expect(typeof result).toBe('string');
35
+ });
36
+ });
37
+
38
+ describe('HTML Generation', () => {
39
+ test('should generate HTML barcode', () => {
40
+ const result = service.html('1234567890', 'code128');
41
+ expect(typeof result).toBe('string');
42
+ expect(result).toContain('<div');
43
+ });
44
+ });
45
+
46
+ describe('PDF Generation', () => {
47
+ test('should generate PDF barcode', async () => {
48
+ const result = await service.pdf('1234567890', 'code128');
49
+ expect(Buffer.isBuffer(result)).toBe(true);
50
+ });
51
+ });
52
+
53
+ describe('Validation', () => {
54
+ test('should validate data', () => {
55
+ const validation = service.validate('1234567890', 'code128');
56
+ expect(validation.valid).toBe(true);
57
+ });
58
+
59
+ test('should reject invalid data', () => {
60
+ const validation = service.validate('', 'code128');
61
+ expect(validation.valid).toBe(false);
62
+ });
63
+ });
64
+
65
+ describe('Batch Generation', () => {
66
+ test('should generate multiple barcodes', () => {
67
+ const items = [
68
+ { data: '1234567890', type: 'code128', format: 'png' },
69
+ { data: '9876543210', type: 'code39', format: 'svg' },
70
+ ];
71
+ const results = service.batch(items);
72
+ expect(Array.isArray(results)).toBe(true);
73
+ expect(results.length).toBe(2);
74
+ });
75
+ });
76
+ });