retail-print-kit 0.0.0-stage → 0.2.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.
- package/LICENSE +21 -0
- package/README.md +209 -2
- package/bin/retail-print-kit.js +318 -0
- package/dist/browser/retail-print-kit.js +26 -0
- package/dist/browser/retail-print-kit.js.map +7 -0
- package/dist/browser/retail-print-kit.mjs +25 -0
- package/dist/browser.d.ts +15 -0
- package/dist/browser.js +35 -0
- package/dist/core/barcode1d.d.ts +12 -0
- package/dist/core/barcode1d.js +192 -0
- package/dist/core/bitmap.d.ts +31 -0
- package/dist/core/bitmap.js +126 -0
- package/dist/core/builder.d.ts +58 -0
- package/dist/core/builder.js +177 -0
- package/dist/core/encode.d.ts +8 -0
- package/dist/core/encode.js +17 -0
- package/dist/core/escpos-encoder.d.ts +4 -0
- package/dist/core/escpos-encoder.js +150 -0
- package/dist/core/identify.d.ts +22 -0
- package/dist/core/identify.js +71 -0
- package/dist/core/image.d.ts +13 -0
- package/dist/core/image.js +32 -0
- package/dist/core/ops.d.ts +78 -0
- package/dist/core/ops.js +2 -0
- package/dist/core/printer.d.ts +35 -0
- package/dist/core/printer.js +96 -0
- package/dist/core/rasterizer.d.ts +29 -0
- package/dist/core/rasterizer.js +199 -0
- package/dist/core/star-graphic-encoder.d.ts +12 -0
- package/dist/core/star-graphic-encoder.js +48 -0
- package/dist/core/star-line-encoder.d.ts +8 -0
- package/dist/core/star-line-encoder.js +119 -0
- package/dist/core/status.d.ts +22 -0
- package/dist/core/status.js +52 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +49 -0
- package/dist/label/builder.d.ts +39 -0
- package/dist/label/builder.js +37 -0
- package/dist/label/ezpl.d.ts +6 -0
- package/dist/label/ezpl.js +78 -0
- package/dist/label/index.d.ts +12 -0
- package/dist/label/index.js +42 -0
- package/dist/label/svg.d.ts +3 -0
- package/dist/label/svg.js +46 -0
- package/dist/label/template.d.ts +61 -0
- package/dist/label/template.js +33 -0
- package/dist/label/tspl.d.ts +3 -0
- package/dist/label/tspl.js +83 -0
- package/dist/label/types.d.ts +69 -0
- package/dist/label/types.js +10 -0
- package/dist/label/zpl.d.ts +3 -0
- package/dist/label/zpl.js +57 -0
- package/dist/preview/html.d.ts +14 -0
- package/dist/preview/html.js +132 -0
- package/dist/preview/index.d.ts +8 -0
- package/dist/preview/index.js +14 -0
- package/dist/preview/png.d.ts +3 -0
- package/dist/preview/png.js +89 -0
- package/dist/profiles/epson.d.ts +10 -0
- package/dist/profiles/epson.js +54 -0
- package/dist/profiles/index.d.ts +7 -0
- package/dist/profiles/index.js +36 -0
- package/dist/profiles/star.d.ts +7 -0
- package/dist/profiles/star.js +39 -0
- package/dist/profiles/types.d.ts +41 -0
- package/dist/profiles/types.js +2 -0
- package/dist/template/expr.d.ts +16 -0
- package/dist/template/expr.js +85 -0
- package/dist/template/index.d.ts +4 -0
- package/dist/template/index.js +27 -0
- package/dist/template/render.d.ts +8 -0
- package/dist/template/render.js +119 -0
- package/dist/template/types.d.ts +81 -0
- package/dist/template/types.js +2 -0
- package/dist/transports/discover.d.ts +21 -0
- package/dist/transports/discover.js +73 -0
- package/dist/transports/net.d.ts +20 -0
- package/dist/transports/net.js +72 -0
- package/dist/transports/serial.d.ts +20 -0
- package/dist/transports/serial.js +71 -0
- package/dist/transports/types.d.ts +16 -0
- package/dist/transports/types.js +41 -0
- package/dist/transports/usb.d.ts +30 -0
- package/dist/transports/usb.js +128 -0
- package/dist/util/base64.d.ts +2 -0
- package/dist/util/base64.js +38 -0
- package/package.json +133 -4
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.opsToHtml = opsToHtml;
|
|
4
|
+
const bitmap_1 = require("../core/bitmap");
|
|
5
|
+
const barcode1d_1 = require("../core/barcode1d");
|
|
6
|
+
const png_1 = require("./png");
|
|
7
|
+
const base64_1 = require("../util/base64");
|
|
8
|
+
function esc(s) {
|
|
9
|
+
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Paper-like HTML of the ops: monospaced lines at the profile's column count, with size, style,
|
|
13
|
+
* alignment and font honoured, and QR / barcodes / images inlined as PNG. Meant for on-screen
|
|
14
|
+
* preview and for a designer; not byte-exact with any printer.
|
|
15
|
+
*/
|
|
16
|
+
function opsToHtml(ops, profile, options = {}) {
|
|
17
|
+
const cell = options.cellWidth ?? 8;
|
|
18
|
+
const paperPx = profile.columns.a * cell;
|
|
19
|
+
const state = { align: 'left', font: 'a', w: 1, h: 1, style: {} };
|
|
20
|
+
const lines = [];
|
|
21
|
+
let pending = '';
|
|
22
|
+
const styleAttr = () => {
|
|
23
|
+
const parts = [`text-align:${state.align}`];
|
|
24
|
+
if (state.w !== 1 || state.h !== 1)
|
|
25
|
+
parts.push(`transform:scale(${state.w},${state.h});transform-origin:${state.align} top`, `height:${state.h}em`);
|
|
26
|
+
if (state.font === 'b')
|
|
27
|
+
parts.push('font-size:0.78em');
|
|
28
|
+
if (state.style.bold)
|
|
29
|
+
parts.push('font-weight:bold');
|
|
30
|
+
if (state.style.underline)
|
|
31
|
+
parts.push(`text-decoration:underline${state.style.underline === 2 ? ' double' : ''}`);
|
|
32
|
+
if (state.style.invert)
|
|
33
|
+
parts.push('background:#000;color:#fff');
|
|
34
|
+
return parts.join(';');
|
|
35
|
+
};
|
|
36
|
+
const flush = (force) => {
|
|
37
|
+
if (!pending && !force)
|
|
38
|
+
return;
|
|
39
|
+
const cols = Math.max(1, Math.floor(profile.columns[state.font] / state.w));
|
|
40
|
+
const parts = [];
|
|
41
|
+
for (let i = 0; i < pending.length; i += cols)
|
|
42
|
+
parts.push(pending.slice(i, i + cols));
|
|
43
|
+
if (!parts.length)
|
|
44
|
+
parts.push('');
|
|
45
|
+
for (const p of parts)
|
|
46
|
+
lines.push(`<div class="l" style="${styleAttr()}">${esc(p) || ' '}</div>`);
|
|
47
|
+
pending = '';
|
|
48
|
+
};
|
|
49
|
+
const img = (png, width, alt) => lines.push(`<div class="l" style="text-align:${state.align}"><img alt="${esc(alt)}" width="${Math.round((width / profile.dots) * paperPx)}" src="data:image/png;base64,${(0, base64_1.toBase64)(png)}"></div>`);
|
|
50
|
+
for (const op of ops) {
|
|
51
|
+
switch (op.kind) {
|
|
52
|
+
case 'text': {
|
|
53
|
+
const ls = op.text.split('\n');
|
|
54
|
+
for (let i = 0; i < ls.length; i++) {
|
|
55
|
+
pending += ls[i];
|
|
56
|
+
if (i < ls.length - 1)
|
|
57
|
+
flush(true);
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
case 'newline':
|
|
62
|
+
for (let i = 0; i < op.count; i++)
|
|
63
|
+
flush(true);
|
|
64
|
+
break;
|
|
65
|
+
case 'feed':
|
|
66
|
+
flush(false);
|
|
67
|
+
for (let i = 0; i < op.lines; i++)
|
|
68
|
+
lines.push('<div class="l"> </div>');
|
|
69
|
+
break;
|
|
70
|
+
case 'align':
|
|
71
|
+
flush(false);
|
|
72
|
+
state.align = op.align;
|
|
73
|
+
break;
|
|
74
|
+
case 'font':
|
|
75
|
+
flush(false);
|
|
76
|
+
state.font = op.font;
|
|
77
|
+
break;
|
|
78
|
+
case 'size':
|
|
79
|
+
flush(false);
|
|
80
|
+
state.w = op.width;
|
|
81
|
+
state.h = op.height;
|
|
82
|
+
break;
|
|
83
|
+
case 'style':
|
|
84
|
+
flush(false);
|
|
85
|
+
state.style = op.style;
|
|
86
|
+
break;
|
|
87
|
+
case 'qr': {
|
|
88
|
+
flush(false);
|
|
89
|
+
const b = (0, bitmap_1.qrBitmap)(op.data, op.options);
|
|
90
|
+
img((0, png_1.bitmapToPng)(b), b.width, `QR ${op.data}`);
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case 'barcode': {
|
|
94
|
+
flush(false);
|
|
95
|
+
const b = (0, barcode1d_1.barcodeBitmap)(op.type, op.data, op.options.width ?? 2, op.options.height ?? 80);
|
|
96
|
+
img((0, png_1.bitmapToPng)(b), b.width, `${op.type} ${op.data}`);
|
|
97
|
+
const pos = op.options.position ?? 'below';
|
|
98
|
+
if (pos === 'below' || pos === 'both') {
|
|
99
|
+
pending = op.data;
|
|
100
|
+
flush(true);
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
case 'raster': {
|
|
105
|
+
flush(false);
|
|
106
|
+
img((0, png_1.bitmapToPng)({ width: op.width, height: op.height, bits: op.bits }), op.width, 'image');
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case 'cut':
|
|
110
|
+
flush(false);
|
|
111
|
+
lines.push('<div class="cut"></div>');
|
|
112
|
+
break;
|
|
113
|
+
case 'drawer':
|
|
114
|
+
flush(false);
|
|
115
|
+
lines.push('<div class="note">[drawer kick]</div>');
|
|
116
|
+
break;
|
|
117
|
+
default: break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
flush(false);
|
|
121
|
+
const body = `<div class="paper" style="width:${paperPx}px">${lines.join('')}</div>`;
|
|
122
|
+
if (options.document === false)
|
|
123
|
+
return body;
|
|
124
|
+
return `<!doctype html><html><head><meta charset="utf-8"><title>${esc(profile.model)} preview</title><style>
|
|
125
|
+
body{background:#777;margin:0;padding:16px;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:${cell * 1.6}px;line-height:1.25}
|
|
126
|
+
.paper{background:#fff;color:#000;padding:12px ${cell}px;margin:0 auto;box-shadow:0 2px 8px rgba(0,0,0,.4);box-sizing:content-box}
|
|
127
|
+
.l{white-space:pre;overflow:hidden;min-height:1.25em}
|
|
128
|
+
.cut{border-top:2px dashed #999;margin:6px -${cell}px}
|
|
129
|
+
.note{color:#999;font-size:.7em;text-align:center}
|
|
130
|
+
img{image-rendering:pixelated;vertical-align:top}
|
|
131
|
+
</style></head><body>${body}</body></html>`;
|
|
132
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Op } from '../core/ops';
|
|
2
|
+
import { Profile } from '../profiles/types';
|
|
3
|
+
import { Rasterizer } from '../core/rasterizer';
|
|
4
|
+
export { bitmapToPng } from './png';
|
|
5
|
+
export { opsToHtml } from './html';
|
|
6
|
+
export type { HtmlPreviewOptions } from './html';
|
|
7
|
+
/** PNG of the ops as a bitmap printer would lay them out (needs a canvas, see CanvasRasterizer). */
|
|
8
|
+
export declare function opsToPng(ops: Op[], profile: Profile, rasterizer?: Rasterizer): Uint8Array;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.opsToHtml = exports.bitmapToPng = void 0;
|
|
4
|
+
exports.opsToPng = opsToPng;
|
|
5
|
+
const rasterizer_1 = require("../core/rasterizer");
|
|
6
|
+
const png_1 = require("./png");
|
|
7
|
+
var png_2 = require("./png");
|
|
8
|
+
Object.defineProperty(exports, "bitmapToPng", { enumerable: true, get: function () { return png_2.bitmapToPng; } });
|
|
9
|
+
var html_1 = require("./html");
|
|
10
|
+
Object.defineProperty(exports, "opsToHtml", { enumerable: true, get: function () { return html_1.opsToHtml; } });
|
|
11
|
+
/** PNG of the ops as a bitmap printer would lay them out (needs a canvas, see CanvasRasterizer). */
|
|
12
|
+
function opsToPng(ops, profile, rasterizer = new rasterizer_1.CanvasRasterizer()) {
|
|
13
|
+
return (0, png_1.bitmapToPng)(rasterizer.render(ops, profile));
|
|
14
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bitmapToPng = bitmapToPng;
|
|
4
|
+
const bitmap_1 = require("../core/bitmap");
|
|
5
|
+
const CRC_TABLE = (() => {
|
|
6
|
+
const t = new Uint32Array(256);
|
|
7
|
+
for (let n = 0; n < 256; n++) {
|
|
8
|
+
let c = n;
|
|
9
|
+
for (let k = 0; k < 8; k++)
|
|
10
|
+
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
11
|
+
t[n] = c >>> 0;
|
|
12
|
+
}
|
|
13
|
+
return t;
|
|
14
|
+
})();
|
|
15
|
+
function crc32(buf) {
|
|
16
|
+
let c = 0xffffffff;
|
|
17
|
+
for (const b of buf)
|
|
18
|
+
c = CRC_TABLE[(c ^ b) & 0xff] ^ (c >>> 8);
|
|
19
|
+
return (c ^ 0xffffffff) >>> 0;
|
|
20
|
+
}
|
|
21
|
+
function u32(n) {
|
|
22
|
+
return [(n >>> 24) & 0xff, (n >>> 16) & 0xff, (n >>> 8) & 0xff, n & 0xff];
|
|
23
|
+
}
|
|
24
|
+
function concat(parts) {
|
|
25
|
+
const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
|
|
26
|
+
let o = 0;
|
|
27
|
+
for (const p of parts) {
|
|
28
|
+
out.set(p, o);
|
|
29
|
+
o += p.length;
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
function chunk(type, data) {
|
|
34
|
+
const body = concat([new Uint8Array([...type].map((c) => c.charCodeAt(0))), data]);
|
|
35
|
+
return concat([new Uint8Array(u32(data.length)), body, new Uint8Array(u32(crc32(body)))]);
|
|
36
|
+
}
|
|
37
|
+
function adler32(data) {
|
|
38
|
+
let a = 1;
|
|
39
|
+
let b = 0;
|
|
40
|
+
for (const d of data) {
|
|
41
|
+
a = (a + d) % 65521;
|
|
42
|
+
b = (b + a) % 65521;
|
|
43
|
+
}
|
|
44
|
+
return ((b << 16) | a) >>> 0;
|
|
45
|
+
}
|
|
46
|
+
/** zlib stream with stored (uncompressed) deflate blocks; used where Node's zlib is unavailable. */
|
|
47
|
+
function deflateStored(data) {
|
|
48
|
+
const blocks = [new Uint8Array([0x78, 0x01])];
|
|
49
|
+
const MAX = 65535;
|
|
50
|
+
for (let i = 0; i < data.length || i === 0; i += MAX) {
|
|
51
|
+
const slice = data.subarray(i, Math.min(i + MAX, data.length));
|
|
52
|
+
const last = i + MAX >= data.length ? 1 : 0;
|
|
53
|
+
const len = slice.length;
|
|
54
|
+
blocks.push(new Uint8Array([last, len & 0xff, len >> 8, ~len & 0xff, (~len >> 8) & 0xff]), slice);
|
|
55
|
+
if (data.length === 0)
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
blocks.push(new Uint8Array(u32(adler32(data))));
|
|
59
|
+
return concat(blocks);
|
|
60
|
+
}
|
|
61
|
+
function deflate(data) {
|
|
62
|
+
try {
|
|
63
|
+
const zlib = require('zlib');
|
|
64
|
+
const out = zlib.deflateSync(data);
|
|
65
|
+
return new Uint8Array(out.buffer, out.byteOffset, out.byteLength);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return deflateStored(data);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** Encodes a 1-bit bitmap as a PNG (1-bit greyscale, black = ink). No dependencies; works in browsers. */
|
|
72
|
+
function bitmapToPng(b) {
|
|
73
|
+
const rowBytes = Math.ceil(b.width / 8);
|
|
74
|
+
const raw = new Uint8Array((rowBytes + 1) * b.height);
|
|
75
|
+
for (let y = 0; y < b.height; y++) {
|
|
76
|
+
for (let x = 0; x < b.width; x++) {
|
|
77
|
+
if (!(0, bitmap_1.getPixel)(b, x, y))
|
|
78
|
+
raw[y * (rowBytes + 1) + 1 + (x >> 3)] |= 0x80 >> (x & 7);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const ihdr = new Uint8Array([...u32(b.width), ...u32(b.height), 1, 0, 0, 0, 0]);
|
|
82
|
+
const png = concat([
|
|
83
|
+
new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),
|
|
84
|
+
chunk('IHDR', ihdr),
|
|
85
|
+
chunk('IDAT', deflate(raw)),
|
|
86
|
+
chunk('IEND', new Uint8Array(0)),
|
|
87
|
+
]);
|
|
88
|
+
return typeof Buffer !== 'undefined' ? Buffer.from(png.buffer, png.byteOffset, png.byteLength) : png;
|
|
89
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Profile } from './types';
|
|
2
|
+
export declare const epsonTmT88: Profile;
|
|
3
|
+
export declare const epsonTmT20: Profile;
|
|
4
|
+
export declare const epsonTmM30: Profile;
|
|
5
|
+
/**
|
|
6
|
+
* Cheap Epson-compatible units (Xprinter, Rongta, HPRT, POS-X and similar). They answer to the
|
|
7
|
+
* common subset but often mishandle GS V 65/66, so cutting feeds with LF first and uses GS V 0/1.
|
|
8
|
+
*/
|
|
9
|
+
export declare const genericEscPos: Profile;
|
|
10
|
+
export declare const genericEscPos58: Profile;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.genericEscPos58 = exports.genericEscPos = exports.epsonTmM30 = exports.epsonTmT20 = exports.epsonTmT88 = void 0;
|
|
4
|
+
const epsonBase = {
|
|
5
|
+
vendor: 'Epson',
|
|
6
|
+
set: 'escpos',
|
|
7
|
+
paper: 80,
|
|
8
|
+
dots: 576,
|
|
9
|
+
columns: { a: 48, b: 64 },
|
|
10
|
+
encoding: 'cp437',
|
|
11
|
+
codepage: 0,
|
|
12
|
+
cut: 'feed-and-cut',
|
|
13
|
+
drawer: { on: 25, off: 250 },
|
|
14
|
+
features: { nativeQr: true, raster: true, italic: false, invert: true, beep: false },
|
|
15
|
+
};
|
|
16
|
+
exports.epsonTmT88 = {
|
|
17
|
+
...epsonBase,
|
|
18
|
+
id: 'epson-tm-t88',
|
|
19
|
+
model: 'TM-T88V / VI / VII',
|
|
20
|
+
usb: [{ vendorId: 0x04b8 }],
|
|
21
|
+
};
|
|
22
|
+
exports.epsonTmT20 = {
|
|
23
|
+
...epsonBase,
|
|
24
|
+
id: 'epson-tm-t20',
|
|
25
|
+
model: 'TM-T20III',
|
|
26
|
+
usb: [{ vendorId: 0x04b8 }],
|
|
27
|
+
};
|
|
28
|
+
exports.epsonTmM30 = {
|
|
29
|
+
...epsonBase,
|
|
30
|
+
id: 'epson-tm-m30',
|
|
31
|
+
model: 'TM-m30II / III',
|
|
32
|
+
usb: [{ vendorId: 0x04b8 }],
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Cheap Epson-compatible units (Xprinter, Rongta, HPRT, POS-X and similar). They answer to the
|
|
36
|
+
* common subset but often mishandle GS V 65/66, so cutting feeds with LF first and uses GS V 0/1.
|
|
37
|
+
*/
|
|
38
|
+
exports.genericEscPos = {
|
|
39
|
+
...epsonBase,
|
|
40
|
+
vendor: 'Generic',
|
|
41
|
+
id: 'generic-escpos',
|
|
42
|
+
model: 'ESC/POS compatible 80 mm',
|
|
43
|
+
cut: 'legacy',
|
|
44
|
+
drawer: { on: 60, off: 120 },
|
|
45
|
+
features: { nativeQr: true, raster: true, italic: false, invert: true, beep: true },
|
|
46
|
+
};
|
|
47
|
+
exports.genericEscPos58 = {
|
|
48
|
+
...exports.genericEscPos,
|
|
49
|
+
id: 'generic-escpos-58',
|
|
50
|
+
model: 'ESC/POS compatible 58 mm',
|
|
51
|
+
paper: 58,
|
|
52
|
+
dots: 384,
|
|
53
|
+
columns: { a: 32, b: 42 },
|
|
54
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Profile } from './types';
|
|
2
|
+
import { epsonTmT88, epsonTmT20, epsonTmM30, genericEscPos, genericEscPos58 } from './epson';
|
|
3
|
+
import { starTsp650, starMcPrint3, starTsp100 } from './star';
|
|
4
|
+
export * from './types';
|
|
5
|
+
export { epsonTmT88, epsonTmT20, epsonTmM30, genericEscPos, genericEscPos58, starTsp650, starMcPrint3, starTsp100 };
|
|
6
|
+
export declare const profiles: Record<string, Profile>;
|
|
7
|
+
export declare function profileById(id: string): Profile;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.profiles = exports.starTsp100 = exports.starMcPrint3 = exports.starTsp650 = exports.genericEscPos58 = exports.genericEscPos = exports.epsonTmM30 = exports.epsonTmT20 = exports.epsonTmT88 = void 0;
|
|
18
|
+
exports.profileById = profileById;
|
|
19
|
+
const epson_1 = require("./epson");
|
|
20
|
+
Object.defineProperty(exports, "epsonTmT88", { enumerable: true, get: function () { return epson_1.epsonTmT88; } });
|
|
21
|
+
Object.defineProperty(exports, "epsonTmT20", { enumerable: true, get: function () { return epson_1.epsonTmT20; } });
|
|
22
|
+
Object.defineProperty(exports, "epsonTmM30", { enumerable: true, get: function () { return epson_1.epsonTmM30; } });
|
|
23
|
+
Object.defineProperty(exports, "genericEscPos", { enumerable: true, get: function () { return epson_1.genericEscPos; } });
|
|
24
|
+
Object.defineProperty(exports, "genericEscPos58", { enumerable: true, get: function () { return epson_1.genericEscPos58; } });
|
|
25
|
+
const star_1 = require("./star");
|
|
26
|
+
Object.defineProperty(exports, "starTsp650", { enumerable: true, get: function () { return star_1.starTsp650; } });
|
|
27
|
+
Object.defineProperty(exports, "starMcPrint3", { enumerable: true, get: function () { return star_1.starMcPrint3; } });
|
|
28
|
+
Object.defineProperty(exports, "starTsp100", { enumerable: true, get: function () { return star_1.starTsp100; } });
|
|
29
|
+
__exportStar(require("./types"), exports);
|
|
30
|
+
exports.profiles = Object.fromEntries([epson_1.epsonTmT88, epson_1.epsonTmT20, epson_1.epsonTmM30, epson_1.genericEscPos, epson_1.genericEscPos58, star_1.starTsp650, star_1.starMcPrint3, star_1.starTsp100].map((p) => [p.id, p]));
|
|
31
|
+
function profileById(id) {
|
|
32
|
+
const p = exports.profiles[id];
|
|
33
|
+
if (!p)
|
|
34
|
+
throw new Error(`retail-print-kit: unknown profile "${id}"`);
|
|
35
|
+
return p;
|
|
36
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Profile } from './types';
|
|
2
|
+
/** TSP650II, TSP700II, TSP800II in Star Line Mode (the factory setting). */
|
|
3
|
+
export declare const starTsp650: Profile;
|
|
4
|
+
/** mC-Print3 / mC-Print2 in Star Line Mode. */
|
|
5
|
+
export declare const starMcPrint3: Profile;
|
|
6
|
+
/** TSP100 / TSP143 family: raster only, everything is rendered to a bitmap first. */
|
|
7
|
+
export declare const starTsp100: Profile;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.starTsp100 = exports.starMcPrint3 = exports.starTsp650 = void 0;
|
|
4
|
+
const starBase = {
|
|
5
|
+
vendor: 'Star Micronics',
|
|
6
|
+
paper: 80,
|
|
7
|
+
dots: 576,
|
|
8
|
+
columns: { a: 48, b: 64 },
|
|
9
|
+
encoding: 'cp437',
|
|
10
|
+
codepage: 1,
|
|
11
|
+
cut: 'feed-and-cut',
|
|
12
|
+
drawer: { on: 100, off: 100 },
|
|
13
|
+
usb: [{ vendorId: 0x0519 }],
|
|
14
|
+
};
|
|
15
|
+
/** TSP650II, TSP700II, TSP800II in Star Line Mode (the factory setting). */
|
|
16
|
+
exports.starTsp650 = {
|
|
17
|
+
...starBase,
|
|
18
|
+
id: 'star-tsp650',
|
|
19
|
+
model: 'TSP650II / TSP700II (Star Line Mode)',
|
|
20
|
+
set: 'star-line',
|
|
21
|
+
features: { nativeQr: true, raster: true, italic: false, invert: true, beep: false },
|
|
22
|
+
};
|
|
23
|
+
/** mC-Print3 / mC-Print2 in Star Line Mode. */
|
|
24
|
+
exports.starMcPrint3 = {
|
|
25
|
+
...starBase,
|
|
26
|
+
id: 'star-mc-print3',
|
|
27
|
+
model: 'mC-Print3 (Star Line Mode)',
|
|
28
|
+
set: 'star-line',
|
|
29
|
+
features: { nativeQr: true, raster: true, italic: false, invert: true, beep: false },
|
|
30
|
+
};
|
|
31
|
+
/** TSP100 / TSP143 family: raster only, everything is rendered to a bitmap first. */
|
|
32
|
+
exports.starTsp100 = {
|
|
33
|
+
...starBase,
|
|
34
|
+
id: 'star-tsp100',
|
|
35
|
+
model: 'TSP100 / TSP143 (raster)',
|
|
36
|
+
set: 'star-graphic',
|
|
37
|
+
codepage: null,
|
|
38
|
+
features: { nativeQr: false, raster: true, italic: false, invert: true, beep: false },
|
|
39
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export type CommandSet = 'escpos' | 'star-line' | 'star-graphic';
|
|
2
|
+
export interface DrawerPulse {
|
|
3
|
+
/** ESC p t1: on time in units of 2 ms. */
|
|
4
|
+
on: number;
|
|
5
|
+
/** ESC p t2: off time in units of 2 ms. */
|
|
6
|
+
off: number;
|
|
7
|
+
}
|
|
8
|
+
export interface Profile {
|
|
9
|
+
id: string;
|
|
10
|
+
vendor: string;
|
|
11
|
+
model: string;
|
|
12
|
+
set: CommandSet;
|
|
13
|
+
/** Paper width in millimetres. */
|
|
14
|
+
paper: 58 | 76 | 80;
|
|
15
|
+
/** Printable dots across the paper (8 dots per mm on 203 dpi heads). */
|
|
16
|
+
dots: number;
|
|
17
|
+
/** Characters per line for font A and font B. */
|
|
18
|
+
columns: {
|
|
19
|
+
a: number;
|
|
20
|
+
b: number;
|
|
21
|
+
};
|
|
22
|
+
/** iconv-lite encoding name used for text. */
|
|
23
|
+
encoding: string;
|
|
24
|
+
/** ESC t n value selected on open; null leaves the printer default. */
|
|
25
|
+
codepage: number | null;
|
|
26
|
+
/** Full/partial cut using GS V 65/66 with feed (Epson) or GS V 0/1 after LF feed (legacy). */
|
|
27
|
+
cut: 'feed-and-cut' | 'legacy';
|
|
28
|
+
drawer: DrawerPulse;
|
|
29
|
+
features: {
|
|
30
|
+
nativeQr: boolean;
|
|
31
|
+
raster: boolean;
|
|
32
|
+
italic: boolean;
|
|
33
|
+
invert: boolean;
|
|
34
|
+
beep: boolean;
|
|
35
|
+
};
|
|
36
|
+
/** USB vendor and product ids that identify this printer, when known. */
|
|
37
|
+
usb?: Array<{
|
|
38
|
+
vendorId: number;
|
|
39
|
+
productId?: number;
|
|
40
|
+
}>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template values: `{{path}}` and `{{path | filter | filter:arg}}`. Paths are dotted, resolved
|
|
3
|
+
* against the current scope first, then the root data. `this` is the current scope, `@index`
|
|
4
|
+
* the position in an `each`. Missing values print as empty strings.
|
|
5
|
+
*/
|
|
6
|
+
export interface Scope {
|
|
7
|
+
root: unknown;
|
|
8
|
+
current: unknown;
|
|
9
|
+
index?: number;
|
|
10
|
+
}
|
|
11
|
+
export type Filter = (value: unknown, arg?: string) => unknown;
|
|
12
|
+
export declare const filters: Record<string, Filter>;
|
|
13
|
+
export declare function lookup(path: string, scope: Scope): unknown;
|
|
14
|
+
export declare function evaluate(expression: string, scope: Scope): unknown;
|
|
15
|
+
export declare function interpolate(text: string, scope: Scope): string;
|
|
16
|
+
export declare function truthy(expression: string, scope: Scope): boolean;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.filters = void 0;
|
|
4
|
+
exports.lookup = lookup;
|
|
5
|
+
exports.evaluate = evaluate;
|
|
6
|
+
exports.interpolate = interpolate;
|
|
7
|
+
exports.truthy = truthy;
|
|
8
|
+
exports.filters = {
|
|
9
|
+
upper: (v) => String(v ?? '').toUpperCase(),
|
|
10
|
+
lower: (v) => String(v ?? '').toLowerCase(),
|
|
11
|
+
trim: (v) => String(v ?? '').trim(),
|
|
12
|
+
money: (v, arg) => {
|
|
13
|
+
const n = Number(v);
|
|
14
|
+
if (!isFinite(n))
|
|
15
|
+
return '';
|
|
16
|
+
const s = Math.abs(n).toFixed(2);
|
|
17
|
+
return `${n < 0 ? '-' : ''}${arg ?? ''}${s}`;
|
|
18
|
+
},
|
|
19
|
+
fixed: (v, arg) => {
|
|
20
|
+
const n = Number(v);
|
|
21
|
+
return isFinite(n) ? n.toFixed(Number(arg ?? 2)) : '';
|
|
22
|
+
},
|
|
23
|
+
pad: (v, arg) => String(v ?? '').padStart(Number(arg ?? 0)),
|
|
24
|
+
padEnd: (v, arg) => String(v ?? '').padEnd(Number(arg ?? 0)),
|
|
25
|
+
default: (v, arg) => (v === undefined || v === null || v === '' ? arg ?? '' : v),
|
|
26
|
+
date: (v, arg) => {
|
|
27
|
+
const d = v instanceof Date ? v : new Date(String(v));
|
|
28
|
+
if (isNaN(d.getTime()))
|
|
29
|
+
return '';
|
|
30
|
+
return arg === 'time' ? d.toLocaleTimeString() : arg === 'datetime' ? d.toLocaleString() : d.toLocaleDateString();
|
|
31
|
+
},
|
|
32
|
+
count: (v) => (Array.isArray(v) ? v.length : 0),
|
|
33
|
+
};
|
|
34
|
+
function lookup(path, scope) {
|
|
35
|
+
const p = path.trim();
|
|
36
|
+
if (p === 'this')
|
|
37
|
+
return scope.current;
|
|
38
|
+
if (p === '@index')
|
|
39
|
+
return scope.index;
|
|
40
|
+
if (p === '@number')
|
|
41
|
+
return scope.index === undefined ? undefined : scope.index + 1;
|
|
42
|
+
if (/^-?\d+(\.\d+)?$/.test(p))
|
|
43
|
+
return Number(p);
|
|
44
|
+
if (/^'.*'$/.test(p) || /^".*"$/.test(p))
|
|
45
|
+
return p.slice(1, -1);
|
|
46
|
+
const fromCurrent = walk(scope.current, p);
|
|
47
|
+
if (fromCurrent !== undefined)
|
|
48
|
+
return fromCurrent;
|
|
49
|
+
return walk(scope.root, p);
|
|
50
|
+
}
|
|
51
|
+
function walk(obj, path) {
|
|
52
|
+
let cur = obj;
|
|
53
|
+
for (const part of path.split('.')) {
|
|
54
|
+
if (cur === null || cur === undefined)
|
|
55
|
+
return undefined;
|
|
56
|
+
cur = cur[part];
|
|
57
|
+
}
|
|
58
|
+
return cur;
|
|
59
|
+
}
|
|
60
|
+
function evaluate(expression, scope) {
|
|
61
|
+
const [head, ...pipes] = expression.split('|').map((s) => s.trim());
|
|
62
|
+
let value = lookup(head, scope);
|
|
63
|
+
for (const pipe of pipes) {
|
|
64
|
+
const idx = pipe.indexOf(':');
|
|
65
|
+
const name = idx === -1 ? pipe : pipe.slice(0, idx);
|
|
66
|
+
const arg = idx === -1 ? undefined : pipe.slice(idx + 1);
|
|
67
|
+
const f = exports.filters[name];
|
|
68
|
+
if (!f)
|
|
69
|
+
throw new Error(`retail-print-kit: unknown template filter "${name}"`);
|
|
70
|
+
value = f(value, arg);
|
|
71
|
+
}
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
function interpolate(text, scope) {
|
|
75
|
+
return text.replace(/\{\{([^}]+)\}\}/g, (_, expr) => {
|
|
76
|
+
const v = evaluate(expr, scope);
|
|
77
|
+
return v === undefined || v === null ? '' : String(v);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function truthy(expression, scope) {
|
|
81
|
+
const not = expression.trim().startsWith('!');
|
|
82
|
+
const v = evaluate(not ? expression.trim().slice(1) : expression, scope);
|
|
83
|
+
const t = Array.isArray(v) ? v.length > 0 : !!v;
|
|
84
|
+
return not ? !t : t;
|
|
85
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.truthy = exports.lookup = exports.evaluate = exports.interpolate = exports.filters = exports.renderBlocks = exports.render = void 0;
|
|
18
|
+
__exportStar(require("./types"), exports);
|
|
19
|
+
var render_1 = require("./render");
|
|
20
|
+
Object.defineProperty(exports, "render", { enumerable: true, get: function () { return render_1.render; } });
|
|
21
|
+
Object.defineProperty(exports, "renderBlocks", { enumerable: true, get: function () { return render_1.renderBlocks; } });
|
|
22
|
+
var expr_1 = require("./expr");
|
|
23
|
+
Object.defineProperty(exports, "filters", { enumerable: true, get: function () { return expr_1.filters; } });
|
|
24
|
+
Object.defineProperty(exports, "interpolate", { enumerable: true, get: function () { return expr_1.interpolate; } });
|
|
25
|
+
Object.defineProperty(exports, "evaluate", { enumerable: true, get: function () { return expr_1.evaluate; } });
|
|
26
|
+
Object.defineProperty(exports, "lookup", { enumerable: true, get: function () { return expr_1.lookup; } });
|
|
27
|
+
Object.defineProperty(exports, "truthy", { enumerable: true, get: function () { return expr_1.truthy; } });
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Op } from '../core/ops';
|
|
2
|
+
import { OpBuilder } from '../core/builder';
|
|
3
|
+
import { Profile } from '../profiles/types';
|
|
4
|
+
import { Block, Template } from './types';
|
|
5
|
+
import { Scope } from './expr';
|
|
6
|
+
/** Renders a template with data into ops for the given profile. */
|
|
7
|
+
export declare function render(template: Template, data: unknown, profile: Profile): Op[];
|
|
8
|
+
export declare function renderBlocks(blocks: Block[], scope: Scope, b: OpBuilder): void;
|