portakal-lite 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/LICENSE +25 -0
- package/README.md +159 -0
- package/dist/builder.d.ts +39 -0
- package/dist/builder.js +250 -0
- package/dist/builder.js.map +1 -0
- package/dist/errors.d.ts +11 -0
- package/dist/errors.js +18 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/lang/tsc.d.ts +16 -0
- package/dist/lang/tsc.js +217 -0
- package/dist/lang/tsc.js.map +1 -0
- package/dist/lang/zpl.d.ts +16 -0
- package/dist/lang/zpl.js +262 -0
- package/dist/lang/zpl.js.map +1 -0
- package/dist/languages/tsc.d.ts +3 -0
- package/dist/languages/tsc.js +161 -0
- package/dist/languages/tsc.js.map +1 -0
- package/dist/languages/zpl.d.ts +3 -0
- package/dist/languages/zpl.js +205 -0
- package/dist/languages/zpl.js.map +1 -0
- package/dist/profiles.d.ts +61 -0
- package/dist/profiles.js +102 -0
- package/dist/profiles.js.map +1 -0
- package/dist/raster.d.ts +39 -0
- package/dist/raster.js +204 -0
- package/dist/raster.js.map +1 -0
- package/dist/receipt.d.ts +22 -0
- package/dist/receipt.js +91 -0
- package/dist/receipt.js.map +1 -0
- package/dist/types.d.ts +336 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +15 -0
- package/dist/utils.js +28 -0
- package/dist/utils.js.map +1 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 productdevbook (portakal — https://github.com/productdevbook/portakal)
|
|
4
|
+
|
|
5
|
+
Portions of this software are derived from portakal
|
|
6
|
+
(https://github.com/productdevbook/portakal), which is distributed under the
|
|
7
|
+
MIT License.
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in all
|
|
17
|
+
copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# portakal-lite
|
|
2
|
+
|
|
3
|
+
A standalone, security-hardened label compiler for **TSC/TSPL2** and **ZPL II** printers, extracted from [portakal](https://github.com/productdevbook/portakal).
|
|
4
|
+
Integrates [etiket](https://github.com/productdevbook/etiket) package for seamless barcode and qrcode generation for preview svg image.
|
|
5
|
+
|
|
6
|
+
- Fluent `label()` builder — text, boxes, lines, circles, ellipses, reverse/erase regions, images, raw commands
|
|
7
|
+
- `.barcode()` / `.qrcode()` — 40+ symbologies via [etiket](https://github.com/productdevbook/etiket)
|
|
8
|
+
- `tsc.compile()` / `zpl.compile()` → **printer-ready string** (no transport, no connection — you send it)
|
|
9
|
+
- `tsc.preview()` / `zpl.preview()` → SVG rendering with per-language font metrics
|
|
10
|
+
- Receipt layout helpers: `formatPair`, `formatRow`, `formatTable`, `separator`, `wordWrap`
|
|
11
|
+
- One runtime dependency (`etiket`, itself zero-dep), pure ESM, works in Node, browsers, Deno, Bun
|
|
12
|
+
- Command-injection hardened (see [Security](#security))
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm install portakal-lite
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick start
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { label, tsc, zpl } from "portakal-lite";
|
|
24
|
+
|
|
25
|
+
const myLabel = label({ width: 40, height: 30 }) // mm
|
|
26
|
+
.text("ACME Corp", { x: 10, y: 10, font: "2", size: 2 })
|
|
27
|
+
.box({ x: 5, y: 5, width: 300, height: 200, thickness: 2 })
|
|
28
|
+
.line({ x1: 5, y1: 55, x2: 310, y2: 55 });
|
|
29
|
+
|
|
30
|
+
const tscCode = tsc.compile(myLabel); // TSC/TSPL2 commands
|
|
31
|
+
const zplCode = zpl.compile(myLabel); // ZPL II commands
|
|
32
|
+
const svg = zpl.preview(myLabel); // SVG preview
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Barcodes & QR codes
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { label, tsc, zpl } from "portakal-lite";
|
|
39
|
+
|
|
40
|
+
const myLabel = label({ width: 40, height: 30 })
|
|
41
|
+
.barcode("123456789", { x: 10, y: 10 }) // Code 128 (native)
|
|
42
|
+
.qrcode("https://example.com", { x: 250, y: 10, cellSize: 6 }) // QR (native)
|
|
43
|
+
.barcode("4006381333931", { x: 10, y: 100, symbology: "ean13" }) // EAN-13 (raster)
|
|
44
|
+
.datamatrix("DM-DATA", { x: 250, y: 100, cellSize: 4 }); // Data Matrix (raster)
|
|
45
|
+
|
|
46
|
+
const tscCode = tsc.compile(myLabel);
|
|
47
|
+
const zplCode = zpl.compile(myLabel);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Two rendering paths:**
|
|
51
|
+
- **Native printer commands** for `code128` and `qr` (TSC `BARCODE`/`QRCODE`, ZPL `^BC`/`^BQ`) — smallest output, uses the printer's built-in encoder.
|
|
52
|
+
- **Raster graphics** for every other symbology — encoded by etiket and embedded as TSC `BITMAP` / ZPL `^GFA`. Real, scannable, consistent across printers.
|
|
53
|
+
|
|
54
|
+
**Supported symbologies** (via etiket): `code128`, `qr`, `ean13`, `ean8`, `upca`, `upce`, `code39`, `code39ext`, `code93`, `code93ext`, `itf`, `itf14`, `codabar`, `msi`, `pharmacode`, `code11`, `gs1-128`, `gs1-databar*`, `isbn`, `issn`, `ismn`, `code32`, `pzn`, postal (`postnet`, `planet`, `rm4scc`, `kix`, ...), and 2D via `.datamatrix()` / `.pdf417()` / `.aztec()` / `.qrcode()`.
|
|
55
|
+
|
|
56
|
+
Barcode options: `x`, `y`, `height`, `moduleWidth`, `ratio`, `rotation`, `readable`, `fontSize`, plus etiket encoding passthrough (`code128Charset`, `code39CheckDigit`, `msiCheckDigit`, `codabarStart/Stop`, ...).
|
|
57
|
+
|
|
58
|
+
QR options: `x`, `y`, `cellSize`, `ecc` (`L`/`M`/`Q`/`H`), `rotation`, `version`, `mode`, `mask`, `eci`, `gs1`.
|
|
59
|
+
|
|
60
|
+
### Send the compiled file to a printer
|
|
61
|
+
|
|
62
|
+
The package only produces the string — wire it to your printer however you like:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { label, tsc } from "portakal-lite";
|
|
66
|
+
import net from "node:net";
|
|
67
|
+
|
|
68
|
+
const commands = tsc.compile(
|
|
69
|
+
label({ width: 40, height: 30 }).text("Hello", { x: 10, y: 10 }),
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// TCP label printers usually listen on port 9100
|
|
73
|
+
const socket = net.createConnection({ host: "192.168.1.100", port: 9100 });
|
|
74
|
+
socket.write(commands);
|
|
75
|
+
socket.end();
|
|
76
|
+
|
|
77
|
+
// ...or write to a file for a print spooler
|
|
78
|
+
// fs.writeFileSync("label.prn", commands);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Receipt-style aligned lines
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { label, tsc, formatPair, separator } from "portakal-lite";
|
|
85
|
+
|
|
86
|
+
const line = formatPair("SKU: PRD-00123", "$12.99", 32);
|
|
87
|
+
// "SKU: PRD-00123 $12.99"
|
|
88
|
+
|
|
89
|
+
const b = label({ width: 40, height: 30 })
|
|
90
|
+
.text(separator("=", 32), { x: 10, y: 10 })
|
|
91
|
+
.text(formatPair("Item", "$25.98", 32), { x: 10, y: 30 })
|
|
92
|
+
.text(formatPair("TOTAL", "$29.48", 32), { x: 10, y: 50 });
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## API
|
|
96
|
+
|
|
97
|
+
### `label(config)`
|
|
98
|
+
|
|
99
|
+
| Option | Default | Notes |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| `width` | required | Label width |
|
|
102
|
+
| `height` | — | Label height (omit for continuous/receipt) |
|
|
103
|
+
| `unit` | `"mm"` | `"mm"` \| `"inch"` \| `"dot"` |
|
|
104
|
+
| `dpi` | `203` | Printer DPI |
|
|
105
|
+
| `printer` | — | Profile: `tsc-te200`, `tsc-te310`, `zebra-zd420`, `zebra-zt410` |
|
|
106
|
+
| `gap` | `3` (mm) | Label gap |
|
|
107
|
+
| `speed` | `4` | 1–18 |
|
|
108
|
+
| `density` | `8` | 0–15 |
|
|
109
|
+
| `direction` | `0` | `0` \| `1` |
|
|
110
|
+
| `copies` | `1` | ≥ 1 |
|
|
111
|
+
|
|
112
|
+
### Elements
|
|
113
|
+
|
|
114
|
+
- `.text(content, { x, y, font, size, xScale, yScale, rotation, bold, reverse, align, maxWidth, lineSpacing })`
|
|
115
|
+
- `.barcode(content, { symbology, x, y, height, moduleWidth, ratio, rotation, readable, fontSize, ...etiket })`
|
|
116
|
+
- `.qrcode(content, { x, y, cellSize, ecc, rotation, version, mode, mask, ... })`
|
|
117
|
+
- `.datamatrix(content, opts)` / `.pdf417(content, opts)` / `.aztec(content, opts)`
|
|
118
|
+
- `.box({ x, y, width, height, thickness, radius })`
|
|
119
|
+
- `.line({ x1, y1, x2, y2, thickness })`
|
|
120
|
+
- `.circle({ x, y, diameter, thickness })`
|
|
121
|
+
- `.ellipse({ x, y, width, height, thickness })`
|
|
122
|
+
- `.reverse({ x, y, width, height })` / `.erase({ x, y, width, height })`
|
|
123
|
+
- `.image(monochromeBitmap, { x, y, width, height })`
|
|
124
|
+
- `.raw(string)` — verbatim passthrough (see Security)
|
|
125
|
+
|
|
126
|
+
`MonochromeBitmap` is a 1-bit packed `Uint8Array`: `{ data, width, height, bytesPerRow }` with `bytesPerRow === Math.ceil(width / 8)`.
|
|
127
|
+
|
|
128
|
+
## Examples
|
|
129
|
+
|
|
130
|
+
Runnable examples live in [`examples/`](./examples) — build the package first (`npm run build`), then run any:
|
|
131
|
+
|
|
132
|
+
```sh
|
|
133
|
+
node examples/basic-label.js # text + box + Code 128 + QR, both languages
|
|
134
|
+
node examples/shipping-label.js # shipping label with tracking barcode + QR
|
|
135
|
+
node examples/receipt-label.js # receipt-style label with order barcode
|
|
136
|
+
node examples/max-symbologies.js # native + rasterized (EAN-13, UPC-A, Code 39, ITF, DataMatrix, PDF417, Aztec)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Security
|
|
140
|
+
|
|
141
|
+
The compilers are hardened against command injection — the most important thing to know before putting untrusted data (user input, database fields) into a label.
|
|
142
|
+
|
|
143
|
+
- **ZPL**: text is emitted with `^FH_` and Zebra hex-escapes. `^`, `~`, `_` and control characters become `_HH`, so content can never break out of `^FD` and inject commands. Example: `^FS^XA^FDINJECT^XZ` compiles to `_5EFS_5EXA_5EFDINJECT_5EXZ`. Non-Latin-1 text is encoded as UTF-8 bytes (printer set to `^CI28`). This applies to barcode/QR content too (native `^BC`/`^BQ`).
|
|
144
|
+
- **TSC**: text is sanitized — control characters stripped, `"` replaced with `'` — so it cannot break out of the quoted `TEXT`/`BLOCK`/`BARCODE`/`QRCODE` argument and inject `CLS`/`PRINT` lines.
|
|
145
|
+
- **Raster path is injection-safe by construction**: for non-native symbologies, the content becomes pixels (`BITMAP`/`^GFA`), never command text.
|
|
146
|
+
- **Content caps**: Code 128 ≤ 4096 chars, QR ≤ 708 bytes, and rasterized bitmaps capped (≤ 65535 dots/axis, ≤ 2 MB total) so hostile input can't balloon the output file (DoS).
|
|
147
|
+
- **Config validation**: non-finite numbers (`NaN`, `Infinity`), out-of-range `speed`/`density`/`copies`, label sizes above 65535 dots, invalid `rotation`/`ecc`/`symbology` all throw `InvalidConfigError` instead of emitting malformed commands.
|
|
148
|
+
- **Image validation**: bitmap shape (`bytesPerRow`, data length) is validated before generating `BITMAP`/`^GFA`.
|
|
149
|
+
- **SVG preview** escapes XML, so label text cannot inject markup/scripts into the preview.
|
|
150
|
+
- **`.raw()` is trusted input**: it passes strings through verbatim as printer commands. Never pass untrusted strings to `.raw()` — that is your escape hatch and your responsibility.
|
|
151
|
+
- No `eval`, no `fs`/`net`/`child_process` in the library. Runtime deps: only `etiket` (itself zero-dep, MIT).
|
|
152
|
+
|
|
153
|
+
## Differences from portakal
|
|
154
|
+
|
|
155
|
+
`portakal-lite` keeps the label builder, TSC/ZPL compilers, per-language preview, receipt helpers, and adds barcode/QR support backed by etiket. It drops the other 7 languages, parsers, `validate()`, cross-compiler, image dithering, encoding engine, and the transport layer. Behavior of the generated TSC/ZPL commands is identical to portakal's, plus the hardening above.
|
|
156
|
+
|
|
157
|
+
## License
|
|
158
|
+
|
|
159
|
+
MIT. Derived from [portakal](https://github.com/productdevbook/portakal) (MIT) — see [LICENSE](./LICENSE). Barcode/QR encoding via [etiket](https://github.com/productdevbook/etiket) (MIT).
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { BarcodeOptions, BarcodeSymbology, BoxOptions, CircleOptions, EllipseOptions, EraseOptions, ImageOptions, LabelConfig, LineOptions, MatrixBarcodeOptions, MonochromeBitmap, QrCodeOptions, ResolvedLabel, ReverseOptions, TextOptions } from "./types.js";
|
|
2
|
+
export declare class LabelBuilder {
|
|
3
|
+
private readonly config;
|
|
4
|
+
private readonly elements;
|
|
5
|
+
constructor(config: LabelConfig);
|
|
6
|
+
text(content: string, options?: TextOptions): this;
|
|
7
|
+
image(bitmap: MonochromeBitmap, options?: ImageOptions): this;
|
|
8
|
+
box(options: BoxOptions): this;
|
|
9
|
+
line(options: LineOptions): this;
|
|
10
|
+
circle(options: CircleOptions): this;
|
|
11
|
+
ellipse(options: EllipseOptions): this;
|
|
12
|
+
reverse(options: ReverseOptions): this;
|
|
13
|
+
erase(options: EraseOptions): this;
|
|
14
|
+
/**
|
|
15
|
+
* Add a barcode. `symbology` defaults to "code128" (printer-native); any
|
|
16
|
+
* other etiket symbology (ean13, upca, code39, itf, ...) is rasterized.
|
|
17
|
+
*/
|
|
18
|
+
barcode(content: string, options?: BarcodeOptions & {
|
|
19
|
+
symbology?: BarcodeSymbology;
|
|
20
|
+
}): this;
|
|
21
|
+
/** Add a printer-native QR code. */
|
|
22
|
+
qrcode(content: string, options?: QrCodeOptions): this;
|
|
23
|
+
/** Add a Data Matrix symbol (rasterized via etiket). */
|
|
24
|
+
datamatrix(content: string, options?: MatrixBarcodeOptions): this;
|
|
25
|
+
/** Add a PDF417 symbol (rasterized via etiket). */
|
|
26
|
+
pdf417(content: string, options?: MatrixBarcodeOptions): this;
|
|
27
|
+
/** Add an Aztec symbol (rasterized via etiket). */
|
|
28
|
+
aztec(content: string, options?: MatrixBarcodeOptions): this;
|
|
29
|
+
raw(content: string | Uint8Array): this;
|
|
30
|
+
resolve(): ResolvedLabel;
|
|
31
|
+
/**
|
|
32
|
+
* Ensure every numeric option on every element is finite, so malformed
|
|
33
|
+
* coordinates (NaN, Infinity) can never reach the generated commands.
|
|
34
|
+
*/
|
|
35
|
+
private validateElementNumbers;
|
|
36
|
+
/** Validate barcode/QR/matrix content size, rotation, ecc, and numeric ranges. */
|
|
37
|
+
private validateSymbology;
|
|
38
|
+
}
|
|
39
|
+
export declare function label(config: LabelConfig): LabelBuilder;
|
package/dist/builder.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { InvalidConfigError } from "./errors.js";
|
|
2
|
+
import { toDots, defaultFontBase } from "./utils.js";
|
|
3
|
+
import { getProfile } from "./profiles.js";
|
|
4
|
+
/** Hard cap for label dimensions in dots — protects 16-bit printer fields (ZPL ^PW/^LL). */
|
|
5
|
+
const MAX_DOTS = 65535;
|
|
6
|
+
export class LabelBuilder {
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.elements = [];
|
|
9
|
+
if (config.printer) {
|
|
10
|
+
const profile = getProfile(config.printer);
|
|
11
|
+
if (profile) {
|
|
12
|
+
config = {
|
|
13
|
+
...config,
|
|
14
|
+
width: config.width || profile.paperWidth,
|
|
15
|
+
dpi: config.dpi ?? profile.dpi,
|
|
16
|
+
unit: config.unit ?? "mm",
|
|
17
|
+
fontBase: config.fontBase ?? profile.fontBase,
|
|
18
|
+
font0Mode: config.font0Mode ?? profile.font0Mode,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (!config.width || config.width <= 0 || !Number.isFinite(config.width)) {
|
|
23
|
+
throw new InvalidConfigError("Label width must be a positive finite number");
|
|
24
|
+
}
|
|
25
|
+
this.config = config;
|
|
26
|
+
}
|
|
27
|
+
text(content, options = {}) {
|
|
28
|
+
this.elements.push({ type: "text", content, options });
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
image(bitmap, options = {}) {
|
|
32
|
+
this.elements.push({ type: "image", bitmap, options });
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
box(options) {
|
|
36
|
+
this.elements.push({ type: "box", options });
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
line(options) {
|
|
40
|
+
this.elements.push({ type: "line", options });
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
circle(options) {
|
|
44
|
+
this.elements.push({ type: "circle", options });
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
ellipse(options) {
|
|
48
|
+
this.elements.push({ type: "ellipse", options });
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
reverse(options) {
|
|
52
|
+
this.elements.push({ type: "reverse", options });
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
erase(options) {
|
|
56
|
+
this.elements.push({ type: "erase", options });
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Add a barcode. `symbology` defaults to "code128" (printer-native); any
|
|
61
|
+
* other etiket symbology (ean13, upca, code39, itf, ...) is rasterized.
|
|
62
|
+
*/
|
|
63
|
+
barcode(content, options = {}) {
|
|
64
|
+
const { symbology = "code128", ...rest } = options;
|
|
65
|
+
this.elements.push({ type: "barcode", content, symbology, options: rest });
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
/** Add a printer-native QR code. */
|
|
69
|
+
qrcode(content, options = {}) {
|
|
70
|
+
this.elements.push({ type: "qrcode", content, options });
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
/** Add a Data Matrix symbol (rasterized via etiket). */
|
|
74
|
+
datamatrix(content, options = {}) {
|
|
75
|
+
this.elements.push({ type: "matrix", content, symbology: "datamatrix", options });
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
/** Add a PDF417 symbol (rasterized via etiket). */
|
|
79
|
+
pdf417(content, options = {}) {
|
|
80
|
+
this.elements.push({ type: "matrix", content, symbology: "pdf417", options });
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
83
|
+
/** Add an Aztec symbol (rasterized via etiket). */
|
|
84
|
+
aztec(content, options = {}) {
|
|
85
|
+
this.elements.push({ type: "matrix", content, symbology: "aztec", options });
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
88
|
+
raw(content) {
|
|
89
|
+
this.elements.push({ type: "raw", content });
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
resolve() {
|
|
93
|
+
const unit = this.config.unit ?? "mm";
|
|
94
|
+
const dpi = this.config.dpi ?? 203;
|
|
95
|
+
if (!Number.isFinite(dpi) || dpi <= 0) {
|
|
96
|
+
throw new InvalidConfigError("dpi must be a positive finite number");
|
|
97
|
+
}
|
|
98
|
+
if (this.config.height != null && !Number.isFinite(this.config.height)) {
|
|
99
|
+
throw new InvalidConfigError("Label height must be a finite number");
|
|
100
|
+
}
|
|
101
|
+
if (this.config.gap != null && !Number.isFinite(this.config.gap)) {
|
|
102
|
+
throw new InvalidConfigError("Label gap must be a finite number");
|
|
103
|
+
}
|
|
104
|
+
const widthDots = toDots(this.config.width, unit, dpi);
|
|
105
|
+
const heightDots = this.config.height ? toDots(this.config.height, unit, dpi) : 0;
|
|
106
|
+
if (widthDots <= 0 || widthDots > MAX_DOTS) {
|
|
107
|
+
throw new InvalidConfigError(`Label width ${widthDots} dots is out of range (1-${MAX_DOTS})`);
|
|
108
|
+
}
|
|
109
|
+
if (heightDots > MAX_DOTS) {
|
|
110
|
+
throw new InvalidConfigError(`Label height ${heightDots} dots is out of range (0-${MAX_DOTS})`);
|
|
111
|
+
}
|
|
112
|
+
const speed = this.config.speed ?? 4;
|
|
113
|
+
const density = this.config.density ?? 8;
|
|
114
|
+
const direction = this.config.direction ?? 0;
|
|
115
|
+
const copies = this.config.copies ?? 1;
|
|
116
|
+
if (!Number.isInteger(speed) || speed < 1 || speed > 18) {
|
|
117
|
+
throw new InvalidConfigError("speed must be an integer between 1 and 18");
|
|
118
|
+
}
|
|
119
|
+
if (!Number.isInteger(density) || density < 0 || density > 15) {
|
|
120
|
+
throw new InvalidConfigError("density must be an integer between 0 and 15");
|
|
121
|
+
}
|
|
122
|
+
if (direction !== 0 && direction !== 1) {
|
|
123
|
+
throw new InvalidConfigError("direction must be 0 or 1");
|
|
124
|
+
}
|
|
125
|
+
if (!Number.isInteger(copies) || copies < 1) {
|
|
126
|
+
throw new InvalidConfigError("copies must be a positive integer");
|
|
127
|
+
}
|
|
128
|
+
this.validateElementNumbers();
|
|
129
|
+
return {
|
|
130
|
+
widthDots,
|
|
131
|
+
heightDots,
|
|
132
|
+
dpi,
|
|
133
|
+
fontBase: this.config.fontBase ?? defaultFontBase(dpi),
|
|
134
|
+
font0Mode: this.config.font0Mode ?? "multiplier",
|
|
135
|
+
charWidthFactor: this.config.charWidthFactor ?? 0.6,
|
|
136
|
+
gapDots: this.config.gap != null ? toDots(this.config.gap, unit, dpi) : toDots(3, "mm", dpi),
|
|
137
|
+
marginDots: this.config.margin != null ? toDots(this.config.margin, unit, dpi) : 0,
|
|
138
|
+
speed,
|
|
139
|
+
density,
|
|
140
|
+
direction,
|
|
141
|
+
copies,
|
|
142
|
+
elements: this.elements,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Ensure every numeric option on every element is finite, so malformed
|
|
147
|
+
* coordinates (NaN, Infinity) can never reach the generated commands.
|
|
148
|
+
*/
|
|
149
|
+
validateElementNumbers() {
|
|
150
|
+
for (const el of this.elements) {
|
|
151
|
+
if (el.type === "raw")
|
|
152
|
+
continue;
|
|
153
|
+
const o = el.options;
|
|
154
|
+
for (const key of Object.keys(o)) {
|
|
155
|
+
const v = o[key];
|
|
156
|
+
if (typeof v === "number" && !Number.isFinite(v)) {
|
|
157
|
+
throw new InvalidConfigError(`Element "${el.type}" option "${key}" must be a finite number, got ${String(v)}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Bitmap data is trusted binary (packed 1-bit); validate shape instead.
|
|
161
|
+
if (el.type === "image") {
|
|
162
|
+
const bmp = el.bitmap;
|
|
163
|
+
if (!Number.isInteger(bmp.width) ||
|
|
164
|
+
bmp.width <= 0 ||
|
|
165
|
+
!Number.isInteger(bmp.height) ||
|
|
166
|
+
bmp.height <= 0 ||
|
|
167
|
+
!(bmp.data instanceof Uint8Array)) {
|
|
168
|
+
throw new InvalidConfigError("image bitmap must have positive integer dimensions and Uint8Array data");
|
|
169
|
+
}
|
|
170
|
+
if (bmp.bytesPerRow !== Math.ceil(bmp.width / 8)) {
|
|
171
|
+
throw new InvalidConfigError("image bitmap bytesPerRow must equal ceil(width / 8)");
|
|
172
|
+
}
|
|
173
|
+
const expected = bmp.bytesPerRow * bmp.height;
|
|
174
|
+
if (bmp.data.length !== expected) {
|
|
175
|
+
throw new InvalidConfigError(`image bitmap data length ${bmp.data.length} does not match ${expected} bytes (bytesPerRow × height)`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Barcode/QR/matrix: content caps + option ranges (printer command limits).
|
|
179
|
+
if (el.type === "barcode" || el.type === "qrcode" || el.type === "matrix") {
|
|
180
|
+
this.validateSymbology(el);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/** Validate barcode/QR/matrix content size, rotation, ecc, and numeric ranges. */
|
|
185
|
+
validateSymbology(el) {
|
|
186
|
+
const opts = el.options;
|
|
187
|
+
const MAX_CODE128 = 4096; // printer-native limit for a single Code 128
|
|
188
|
+
const MAX_QR_BYTES = 708; // QR v40-L: 708 bytes max data capacity
|
|
189
|
+
if (el.type === "barcode" && el.content.length > MAX_CODE128) {
|
|
190
|
+
throw new InvalidConfigError(`barcode content exceeds ${MAX_CODE128} characters (got ${el.content.length})`);
|
|
191
|
+
}
|
|
192
|
+
if (el.type === "qrcode") {
|
|
193
|
+
let bytes = 0;
|
|
194
|
+
for (let i = 0; i < el.content.length; i++) {
|
|
195
|
+
bytes += el.content.charCodeAt(i) <= 0x7f ? 1 : 2; // ~UTF-8 estimate
|
|
196
|
+
}
|
|
197
|
+
if (bytes > MAX_QR_BYTES) {
|
|
198
|
+
throw new InvalidConfigError(`qrcode content exceeds ${MAX_QR_BYTES} bytes (got ~${bytes})`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const rotation = opts.rotation ?? 0;
|
|
202
|
+
if (rotation !== 0 && rotation !== 90 && rotation !== 180 && rotation !== 270) {
|
|
203
|
+
throw new InvalidConfigError("rotation must be one of 0, 90, 180, 270");
|
|
204
|
+
}
|
|
205
|
+
if (el.type === "qrcode") {
|
|
206
|
+
const ecc = opts.ecc ?? "M";
|
|
207
|
+
if (ecc !== "L" && ecc !== "M" && ecc !== "Q" && ecc !== "H") {
|
|
208
|
+
throw new InvalidConfigError('qrcode ecc must be one of "L", "M", "Q", "H"');
|
|
209
|
+
}
|
|
210
|
+
const mask = opts.mask;
|
|
211
|
+
if (mask != null && (!Number.isInteger(mask) || mask < 0 || mask > 7)) {
|
|
212
|
+
throw new InvalidConfigError("qrcode mask must be an integer between 0 and 7");
|
|
213
|
+
}
|
|
214
|
+
const cellSize = opts.cellSize ?? 6;
|
|
215
|
+
if (!Number.isInteger(cellSize) || cellSize < 1 || cellSize > 32) {
|
|
216
|
+
throw new InvalidConfigError("qrcode cellSize must be an integer between 1 and 32");
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else if (el.type === "matrix") {
|
|
220
|
+
const cellSize = opts.cellSize ?? 6;
|
|
221
|
+
if (!Number.isInteger(cellSize) || cellSize < 1 || cellSize > 32) {
|
|
222
|
+
throw new InvalidConfigError("matrix cellSize must be an integer between 1 and 32");
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
const height = opts.height ?? 80;
|
|
227
|
+
if (!Number.isInteger(height) || height < 10 || height > 4000) {
|
|
228
|
+
throw new InvalidConfigError("barcode height must be an integer between 10 and 4000");
|
|
229
|
+
}
|
|
230
|
+
const moduleWidth = opts.moduleWidth ?? 2;
|
|
231
|
+
if (!Number.isInteger(moduleWidth) ||
|
|
232
|
+
moduleWidth < 1 ||
|
|
233
|
+
moduleWidth > 10) {
|
|
234
|
+
throw new InvalidConfigError("barcode moduleWidth must be an integer between 1 and 10");
|
|
235
|
+
}
|
|
236
|
+
const ratio = opts.ratio ?? 2;
|
|
237
|
+
if (!Number.isInteger(ratio) || ratio < 1 || ratio > 4) {
|
|
238
|
+
throw new InvalidConfigError("barcode ratio must be an integer between 1 and 4");
|
|
239
|
+
}
|
|
240
|
+
const fontSize = opts.fontSize ?? 2;
|
|
241
|
+
if (!Number.isInteger(fontSize) || fontSize < 1 || fontSize > 10) {
|
|
242
|
+
throw new InvalidConfigError("barcode fontSize must be an integer between 1 and 10");
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
export function label(config) {
|
|
248
|
+
return new LabelBuilder(config);
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error classes. Copied from portakal (https://github.com/productdevbook/portakal) — MIT.
|
|
3
|
+
*/
|
|
4
|
+
/** Base error class */
|
|
5
|
+
export declare class PortakalError extends Error {
|
|
6
|
+
constructor(message: string);
|
|
7
|
+
}
|
|
8
|
+
/** Thrown when label configuration or element values are invalid */
|
|
9
|
+
export declare class InvalidConfigError extends PortakalError {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error classes. Copied from portakal (https://github.com/productdevbook/portakal) — MIT.
|
|
3
|
+
*/
|
|
4
|
+
/** Base error class */
|
|
5
|
+
export class PortakalError extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "PortakalError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/** Thrown when label configuration or element values are invalid */
|
|
12
|
+
export class InvalidConfigError extends PortakalError {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "InvalidConfigError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,uBAAuB;AACvB,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED,oEAAoE;AACpE,MAAM,OAAO,kBAAmB,SAAQ,aAAa;IACnD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* portakal-lite — standalone TSC/TSPL2 + ZPL II label compiler.
|
|
3
|
+
* Fluent label builder, compile + SVG preview, receipt layout helpers.
|
|
4
|
+
* Zero dependencies, no transport layer.
|
|
5
|
+
*
|
|
6
|
+
* Derived from portakal (https://github.com/productdevbook/portakal) — MIT.
|
|
7
|
+
*/
|
|
8
|
+
export { label, LabelBuilder } from "./builder.js";
|
|
9
|
+
export { PortakalError, InvalidConfigError } from "./errors.js";
|
|
10
|
+
export { toDots } from "./utils.js";
|
|
11
|
+
export { formatRow, formatPair, formatTable, separator, wordWrap, } from "./receipt.js";
|
|
12
|
+
export type { Column } from "./receipt.js";
|
|
13
|
+
export { compileToTSC } from "./languages/tsc.js";
|
|
14
|
+
export { compileToZPL } from "./languages/zpl.js";
|
|
15
|
+
export { tsc } from "./lang/tsc.js";
|
|
16
|
+
export { zpl } from "./lang/zpl.js";
|
|
17
|
+
export { PRINTER_PROFILES, getProfile, listProfiles, findByLanguage, } from "./profiles.js";
|
|
18
|
+
export type { PrinterProfile, PrinterLanguage, CutterType, ImageMode, } from "./profiles.js";
|
|
19
|
+
export type { Alignment, BarcodeOptions, BarcodeSymbology, BoxOptions, CircleOptions, DitherAlgorithm, EllipseOptions, EraseOptions, ImageOptions, LabelConfig, LabelElement, LineOptions, MatrixBarcodeOptions, MonochromeBitmap, QrCodeOptions, ResolvedLabel, ReverseOptions, Rotation, TextOptions, Unit, } from "./types.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* portakal-lite — standalone TSC/TSPL2 + ZPL II label compiler.
|
|
3
|
+
* Fluent label builder, compile + SVG preview, receipt layout helpers.
|
|
4
|
+
* Zero dependencies, no transport layer.
|
|
5
|
+
*
|
|
6
|
+
* Derived from portakal (https://github.com/productdevbook/portakal) — MIT.
|
|
7
|
+
*/
|
|
8
|
+
export { label, LabelBuilder } from "./builder.js";
|
|
9
|
+
export { PortakalError, InvalidConfigError } from "./errors.js";
|
|
10
|
+
export { toDots } from "./utils.js";
|
|
11
|
+
export { formatRow, formatPair, formatTable, separator, wordWrap, } from "./receipt.js";
|
|
12
|
+
export { compileToTSC } from "./languages/tsc.js";
|
|
13
|
+
export { compileToZPL } from "./languages/zpl.js";
|
|
14
|
+
export { tsc } from "./lang/tsc.js";
|
|
15
|
+
export { zpl } from "./lang/zpl.js";
|
|
16
|
+
export { PRINTER_PROFILES, getProfile, listProfiles, findByLanguage, } from "./profiles.js";
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EACL,SAAS,EACT,UAAU,EACV,WAAW,EACX,SAAS,EACT,QAAQ,GACT,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,cAAc,GACf,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TSC/TSPL2 language module — compile + preview.
|
|
3
|
+
* Preview code copied from portakal (https://github.com/productdevbook/portakal) — MIT.
|
|
4
|
+
* parse/validate are intentionally omitted from this package.
|
|
5
|
+
*/
|
|
6
|
+
import type { LabelBuilder } from "../builder.js";
|
|
7
|
+
import type { ResolvedLabel } from "../types.js";
|
|
8
|
+
/** TSC language module */
|
|
9
|
+
export declare const tsc: {
|
|
10
|
+
/** Compile label to TSC/TSPL2 commands */
|
|
11
|
+
compile(builder: LabelBuilder): string;
|
|
12
|
+
/** Render label preview with TSC-specific font metrics */
|
|
13
|
+
preview(builder: LabelBuilder): string;
|
|
14
|
+
/** Render from resolved label */
|
|
15
|
+
previewResolved(resolved: ResolvedLabel): string;
|
|
16
|
+
};
|