@connectedxm/zpl-generator 0.0.1

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 ADDED
@@ -0,0 +1,422 @@
1
+ # ZPL Generator
2
+
3
+ A TypeScript library for generating ZPL (Zebra Programming Language) code from structured badge configurations. This library provides type-safe APIs for creating thermal printer labels with text fields, barcodes, and QR codes.
4
+
5
+ ## Features
6
+
7
+ - **Type-Safe Configuration**: Full TypeScript support with Zod validation schemas
8
+ - **Thermal Badge Support**: Generate ZPL for thermal transfer and direct thermal printers
9
+ - **Multiple Block Types**:
10
+ - Text fields with advanced formatting (word wrapping, alignment, vertical positioning)
11
+ - Barcodes (Code 128)
12
+ - QR codes with configurable error correction
13
+ - **Comprehensive Printer Settings**: Control print speed, darkness, orientation, media type, and more
14
+ - **Validation**: Built-in validation with detailed error messages
15
+ - **Word Wrapping**: Accurate line counting with optional word-width measurements for precise text layout
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install cxm-zpl-generator
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ```typescript
26
+ import { generate } from 'cxm-zpl-generator';
27
+ import {
28
+ ThermalBadge,
29
+ MediaType,
30
+ ThermalMediaType,
31
+ PrintOrientation,
32
+ FontOrientation,
33
+ TextAlignment,
34
+ VerticalAlignment,
35
+ PostPrintMode,
36
+ PrepeelMode,
37
+ AllMediaMode,
38
+ BackfeedAction,
39
+ ReverseMode,
40
+ PrintDensityAdjustment,
41
+ } from 'cxm-zpl-generator';
42
+
43
+ const badge: ThermalBadge = {
44
+ type: 'thermal',
45
+ tearOffAdjustment: 0,
46
+ backfeedActions: BackfeedAction.Normal,
47
+ media: MediaType.NonContinuousMarkSensing,
48
+ mediaOffset: 0,
49
+ thermalMediaType: ThermalMediaType.ThermalTransfer,
50
+ printOrientation: PrintOrientation.Normal,
51
+ mirror: MirrorMode.Normal,
52
+ labelHomeX: 20,
53
+ labelHomeY: 0,
54
+ printDensityAdjustment: PrintDensityAdjustment.Normal,
55
+ printSpeed: 1,
56
+ slewSpeed: 1,
57
+ backfeedSpeed: 1,
58
+ darkness: 30,
59
+ reverse: ReverseMode.Disable,
60
+ postPrintMode: PostPrintMode.TearOff,
61
+ prepeel: PrepeelMode.NoPrepeel,
62
+ printWidth: 900,
63
+ labelLength: 600,
64
+ allMedia: AllMediaMode.ContinuousOnly,
65
+ blocks: [
66
+ {
67
+ type: 'field',
68
+ name: 'title',
69
+ x: 0,
70
+ y: 100,
71
+ data: 'Hello World',
72
+ font: 'A',
73
+ fontHeight: 100,
74
+ maxWidth: 900,
75
+ maxLines: 1,
76
+ lineSpacing: 100,
77
+ alignment: TextAlignment.Center,
78
+ fontOrientation: FontOrientation.NoRotation,
79
+ hangingIndent: 0,
80
+ verticalAlignment: VerticalAlignment.Start,
81
+ },
82
+ ],
83
+ };
84
+
85
+ const zpl = generate(badge);
86
+ console.log(zpl);
87
+ // Output: ^XA
88
+ // ~TA000
89
+ // ~JSN
90
+ // ...
91
+ ```
92
+
93
+ ## API Reference
94
+
95
+ ### `generate(badge: Badge): string`
96
+
97
+ Generates ZPL code from a badge configuration.
98
+
99
+ **Parameters:**
100
+ - `badge`: A validated `Badge` object (must be of type `'thermal'`)
101
+
102
+ **Returns:** A string containing valid ZPL code
103
+
104
+ **Example:**
105
+ ```typescript
106
+ const zpl = generate(badge);
107
+ // Send zpl to your Zebra printer
108
+ ```
109
+
110
+ ### `validateBadge(data: unknown)`
111
+
112
+ Validates a badge configuration object. Returns a Zod `SafeParseReturnType` with success/error information.
113
+
114
+ **Example:**
115
+ ```typescript
116
+ import { validateBadge } from 'cxm-zpl-generator';
117
+
118
+ const result = validateBadge(jsonData);
119
+ if (result.success) {
120
+ const badge = result.data; // Type-safe Badge object
121
+ const zpl = generate(badge);
122
+ } else {
123
+ console.error(result.error.errors);
124
+ }
125
+ ```
126
+
127
+ ### `validateBadgeOrThrow(data: unknown)`
128
+
129
+ Validates a badge configuration and throws a `ZodError` if validation fails.
130
+
131
+ **Example:**
132
+ ```typescript
133
+ import { validateBadgeOrThrow } from 'cxm-zpl-generator';
134
+
135
+ try {
136
+ const badge = validateBadgeOrThrow(jsonData);
137
+ const zpl = generate(badge);
138
+ } catch (error) {
139
+ // Handle validation error
140
+ }
141
+ ```
142
+
143
+ ## Badge Configuration
144
+
145
+ ### Base Badge Properties
146
+
147
+ All thermal badges require the following configuration:
148
+
149
+ | Property | Type | Description |
150
+ |----------|------|-------------|
151
+ | `type` | `'thermal'` | Badge type (currently only thermal is supported) |
152
+ | `tearOffAdjustment` | `number` | Tear-off adjustment (0-120) |
153
+ | `backfeedActions` | `BackfeedAction` | Backfeed sequence configuration |
154
+ | `media` | `MediaType` | Media type (continuous, variable length, etc.) |
155
+ | `mediaOffset` | `number` | Media offset (-75 to 283) |
156
+ | `thermalMediaType` | `ThermalMediaType` | Direct thermal or thermal transfer |
157
+ | `printOrientation` | `PrintOrientation` | Normal or inverted |
158
+ | `mirror` | `MirrorMode` | Mirror mode setting |
159
+ | `labelHomeX` | `number` | Label home X coordinate (0-32000) |
160
+ | `labelHomeY` | `number` | Label home Y coordinate (0-32000) |
161
+ | `printDensityAdjustment` | `PrintDensityAdjustment?` | Optional print density adjustment |
162
+ | `printSpeed` | `number` | Print speed (1-14) |
163
+ | `slewSpeed` | `number` | Slew speed (1-14) |
164
+ | `backfeedSpeed` | `number` | Backfeed speed (1-14) |
165
+ | `darkness` | `number` | Print darkness (0-30) |
166
+ | `reverse` | `ReverseMode` | Reverse mode setting |
167
+ | `postPrintMode` | `PostPrintMode` | Post-print action (tear off, peel off, etc.) |
168
+ | `prepeel` | `PrepeelMode` | Prepeel mode setting |
169
+ | `printWidth` | `number` | Print width in dots (minimum 2) |
170
+ | `labelLength` | `number` | Label length in dots (1-32000) |
171
+ | `allMedia` | `AllMediaMode` | All media mode setting |
172
+ | `blocks` | `Block[]` | Array of content blocks |
173
+
174
+ ### Block Types
175
+
176
+ #### Field Block (Text)
177
+
178
+ Displays text with configurable font, size, alignment, and wrapping.
179
+
180
+ ```typescript
181
+ {
182
+ type: 'field',
183
+ name: 'field_name', // Identifier for the block
184
+ x: 0, // X position in dots
185
+ y: 100, // Y position in dots
186
+ data: 'Text content', // Text to display
187
+ font: 'A', // Font identifier (A-Z, 0-9)
188
+ fontHeight: 100, // Font height in dots (1-32000)
189
+ fontWidth?: number, // Optional font width in dots
190
+ fontOrientation: FontOrientation, // Text rotation
191
+ maxWidth: 900, // Maximum width for wrapping (0-9999)
192
+ maxLines: 3, // Maximum number of lines (1-9999)
193
+ lineSpacing: 0, // Line spacing (-9999 to 9999)
194
+ alignment: TextAlignment, // Text alignment (Left, Right, Center, Justified)
195
+ hangingIndent: 0, // Hanging indent (0-9999)
196
+ verticalAlignment: VerticalAlignment, // Vertical alignment (Start, End)
197
+ wordWidths?: WordWidth[], // Optional word width measurements for accurate wrapping
198
+ }
199
+ ```
200
+
201
+ **Vertical Alignment:**
202
+ - `VerticalAlignment.Start`: Text starts at the top of the field
203
+ - `VerticalAlignment.End`: Text is aligned to the bottom (padded with line breaks)
204
+
205
+ **Word Widths:**
206
+ For accurate text wrapping with proportional fonts, provide `wordWidths`:
207
+
208
+ ```typescript
209
+ wordWidths: [
210
+ { word: 'Hello', width: 50, spaceWidth: 10 },
211
+ { word: 'World', width: 60, spaceWidth: 10 },
212
+ ]
213
+ ```
214
+
215
+ #### Barcode Block
216
+
217
+ Generates a Code 128 barcode.
218
+
219
+ ```typescript
220
+ {
221
+ type: 'barcode',
222
+ name: 'barcode_name',
223
+ x: 0,
224
+ y: 200,
225
+ data: '1234567890', // Barcode data
226
+ barWidth: 5, // Bar width multiplier (4-9999)
227
+ orientation: FontOrientation, // Barcode orientation
228
+ height: 60, // Barcode height in dots (1-32000)
229
+ line: YesNo, // Show human-readable line below
230
+ lineAbove: YesNo, // Show human-readable line above
231
+ checkDigit: YesNo, // Include check digit
232
+ }
233
+ ```
234
+
235
+ #### QR Code Block
236
+
237
+ Generates a QR code.
238
+
239
+ ```typescript
240
+ {
241
+ type: 'qrcode',
242
+ name: 'qrcode_name',
243
+ x: 0,
244
+ y: 300,
245
+ data: 'https://example.com', // QR code data
246
+ orientation: 'N', // Must be 'N' (no rotation)
247
+ model: '2', // Must be '2' (Model 2)
248
+ magnification: 5, // Magnification factor (1-100)
249
+ errorCorrection: QRCodeErrorCorrection, // Error correction level
250
+ mask: 0, // Mask pattern (0-7)
251
+ }
252
+ ```
253
+
254
+ ## Enums and Constants
255
+
256
+ ### Media Types
257
+ - `MediaType.Continuous` - Continuous media
258
+ - `MediaType.VariableLengthContinuous` - Variable length continuous
259
+ - `MediaType.NonContinuousWebSensing` - Non-continuous web sensing
260
+ - `MediaType.NonContinuousWebSensingAlt` - Non-continuous web sensing (alternate)
261
+ - `MediaType.NonContinuousMarkSensing` - Non-continuous mark sensing
262
+ - `MediaType.AutoDetect` - Auto-detect media type
263
+
264
+ ### Thermal Media Types
265
+ - `ThermalMediaType.DirectThermal` - Direct thermal printing
266
+ - `ThermalMediaType.ThermalTransfer` - Thermal transfer printing
267
+
268
+ ### Text Alignment
269
+ - `TextAlignment.Left` - Left-aligned text
270
+ - `TextAlignment.Right` - Right-aligned text
271
+ - `TextAlignment.Center` - Center-aligned text
272
+ - `TextAlignment.Justified` - Justified text
273
+
274
+ ### Font Orientation
275
+ - `FontOrientation.NoRotation` - No rotation (0°)
276
+ - `FontOrientation.Rotate90` - Rotate 90° clockwise
277
+ - `FontOrientation.Rotate180` - Rotate 180°
278
+ - `FontOrientation.Rotate270` - Rotate 270° clockwise
279
+
280
+ ### Post Print Modes
281
+ - `PostPrintMode.TearOff` - Tear off after printing
282
+ - `PostPrintMode.PeelOff` - Peel off after printing
283
+ - `PostPrintMode.Rewind` - Rewind after printing
284
+ - `PostPrintMode.Applicator` - Applicator mode
285
+ - `PostPrintMode.Cut` - Cut after printing
286
+ - `PostPrintMode.DelayedCut` - Delayed cut
287
+ - `PostPrintMode.EncodeRFID` - Encode RFID
288
+ - `PostPrintMode.Kiosk` - Kiosk mode
289
+
290
+ ### QR Code Error Correction
291
+ - `QRCodeErrorCorrection.Highest` - Highest error correction (~30%)
292
+ - `QRCodeErrorCorrection.High` - High error correction (~25%)
293
+ - `QRCodeErrorCorrection.Medium` - Medium error correction (~15%)
294
+ - `QRCodeErrorCorrection.Lower` - Lower error correction (~7%)
295
+
296
+ ## Advanced Usage
297
+
298
+ ### Dynamic Content with Templates
299
+
300
+ You can use template strings in your badge data and replace them before generating ZPL:
301
+
302
+ ```typescript
303
+ const badge: ThermalBadge = {
304
+ // ... configuration
305
+ blocks: [
306
+ {
307
+ type: 'field',
308
+ name: 'name',
309
+ x: 0,
310
+ y: 100,
311
+ data: '{{firstName}} {{lastName}}', // Template string
312
+ // ... other properties
313
+ },
314
+ ],
315
+ };
316
+
317
+ // Replace template variables
318
+ const badgeWithData = {
319
+ ...badge,
320
+ blocks: badge.blocks.map(block => ({
321
+ ...block,
322
+ data: block.data
323
+ .replace('{{firstName}}', 'John')
324
+ .replace('{{lastName}}', 'Doe'),
325
+ })),
326
+ };
327
+
328
+ const zpl = generate(badgeWithData);
329
+ ```
330
+
331
+ ### Accurate Text Wrapping
332
+
333
+ For precise text layout with proportional fonts, measure word widths and provide them:
334
+
335
+ ```typescript
336
+ import { countLines } from 'cxm-zpl-generator';
337
+
338
+ // Measure word widths (e.g., using canvas or font metrics)
339
+ const wordWidths: WordWidth[] = [
340
+ { word: 'Hello', width: 50, spaceWidth: 10 },
341
+ { word: 'World', width: 60, spaceWidth: 10 },
342
+ ];
343
+
344
+ const fieldBlock: FieldBlock = {
345
+ type: 'field',
346
+ name: 'text',
347
+ x: 0,
348
+ y: 0,
349
+ data: 'Hello World',
350
+ font: 'A',
351
+ fontHeight: 20,
352
+ maxWidth: 100,
353
+ maxLines: 5,
354
+ lineSpacing: 0,
355
+ alignment: TextAlignment.Left,
356
+ fontOrientation: FontOrientation.NoRotation,
357
+ hangingIndent: 0,
358
+ verticalAlignment: VerticalAlignment.End,
359
+ wordWidths, // Provide measured widths
360
+ };
361
+
362
+ // countLines can be used to preview line count
363
+ const lines = countLines(fieldBlock);
364
+ console.log(`Text will occupy ${lines} lines`);
365
+ ```
366
+
367
+ ### Validating JSON Configuration
368
+
369
+ When loading badge configurations from JSON files or APIs:
370
+
371
+ ```typescript
372
+ import { validateBadgeOrThrow, generate } from 'cxm-zpl-generator';
373
+
374
+ // Load from JSON file or API
375
+ const jsonData = await fetch('/api/badge-config').then(r => r.json());
376
+
377
+ try {
378
+ const badge = validateBadgeOrThrow(jsonData);
379
+ const zpl = generate(badge);
380
+ // Send to printer
381
+ } catch (error) {
382
+ if (error instanceof ZodError) {
383
+ console.error('Validation errors:', error.errors);
384
+ }
385
+ }
386
+ ```
387
+
388
+ ## Examples
389
+
390
+ See the `examples/` directory for complete working examples:
391
+
392
+ - `simple-label.ts` - Basic label with text fields and barcode
393
+
394
+ ## Testing
395
+
396
+ Run tests with:
397
+
398
+ ```bash
399
+ npm test
400
+ ```
401
+
402
+ Watch mode:
403
+
404
+ ```bash
405
+ npm run test:watch
406
+ ```
407
+
408
+ ## Building
409
+
410
+ Build the library:
411
+
412
+ ```bash
413
+ npm run build
414
+ ```
415
+
416
+ ## License
417
+
418
+ ISC
419
+
420
+ ## Contributing
421
+
422
+ Contributions are welcome! Please ensure all tests pass and follow the existing code style.
@@ -0,0 +1,2 @@
1
+ export * from './src/generate';
2
+ export * from './src/validate';