@bobfrankston/brother-label 1.0.13 → 1.0.14
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 +20 -3
- package/api.d.ts +11 -0
- package/api.d.ts.map +1 -1
- package/api.js +105 -0
- package/api.js.map +1 -1
- package/api.ts +110 -0
- package/cli.js +219 -79
- package/cli.js.map +1 -1
- package/cli.ts +221 -61
- package/index.d.ts +1 -1
- package/index.d.ts.map +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/index.ts +3 -0
- package/package.json +3 -3
- package/brother-print.d.ts +0 -3
- package/brother-print.d.ts.map +0 -1
- package/brother-print.js +0 -629
- package/brother-print.js.map +0 -1
- package/brother-print.ts +0 -697
package/cli.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import * as fs from "fs";
|
|
7
7
|
import * as path from "path";
|
|
8
|
-
import {
|
|
9
|
-
|
|
8
|
+
import { print, render, renderSegments, printSegments, getConfig, setConfig, getConfigPath, listPrinters, } from "./api.js";
|
|
9
|
+
const VERSION = "1.0.13";
|
|
10
10
|
const VALID_TAPES = [6, 9, 12, 18, 24];
|
|
11
11
|
function parseTape(value) {
|
|
12
12
|
const num = parseInt(value.replace("mm", ""), 10);
|
|
@@ -72,98 +72,238 @@ function buildPrintOptions(input, opts) {
|
|
|
72
72
|
}
|
|
73
73
|
return options;
|
|
74
74
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
75
|
+
// Valued options: flag name(s) → canonical key
|
|
76
|
+
const VALUED_OPTIONS = [
|
|
77
|
+
[["-tape"], "tape"],
|
|
78
|
+
[["-p", "-printer"], "printer"],
|
|
79
|
+
[["-o", "-output"], "output"],
|
|
80
|
+
[["-a", "-aspect"], "aspect"],
|
|
81
|
+
[["-H", "-height"], "height"],
|
|
82
|
+
[["-s", "-sp", "-space"], "space"],
|
|
83
|
+
];
|
|
84
|
+
// Boolean flags: flag name(s) → canonical key
|
|
85
|
+
const BOOLEAN_FLAGS = [
|
|
86
|
+
[["-w", "-html"], "html"],
|
|
87
|
+
[["-i", "-image"], "image"],
|
|
88
|
+
[["-t"], "text"],
|
|
89
|
+
[["-help", "-h"], "help"],
|
|
90
|
+
[["-version", "-v"], "version"],
|
|
91
|
+
];
|
|
92
|
+
function parseArgs(argv) {
|
|
93
|
+
const args = argv.slice(2).map(a => a.startsWith("--") ? a.slice(1) : a);
|
|
94
|
+
const command = null;
|
|
95
|
+
const opts = {};
|
|
96
|
+
const segments = [];
|
|
97
|
+
let input = null;
|
|
98
|
+
let i = 0;
|
|
99
|
+
while (i < args.length) {
|
|
100
|
+
const arg = args[i];
|
|
101
|
+
// Segment flags: -text <value>, -qr <value>
|
|
102
|
+
if ((arg === "-text" || arg === "-qr") && i + 1 < args.length) {
|
|
103
|
+
segments.push({ type: arg === "-text" ? "text" : "qr", value: args[i + 1] });
|
|
104
|
+
i += 2;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
// Valued options
|
|
108
|
+
let matched = false;
|
|
109
|
+
for (const [names, key] of VALUED_OPTIONS) {
|
|
110
|
+
if (names.includes(arg) && i + 1 < args.length) {
|
|
111
|
+
opts[key] = args[i + 1];
|
|
112
|
+
i += 2;
|
|
113
|
+
matched = true;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (matched)
|
|
118
|
+
continue;
|
|
119
|
+
// Boolean flags
|
|
120
|
+
for (const [names, key] of BOOLEAN_FLAGS) {
|
|
121
|
+
if (names.includes(arg)) {
|
|
122
|
+
opts[key] = true;
|
|
123
|
+
i++;
|
|
124
|
+
matched = true;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (matched)
|
|
129
|
+
continue;
|
|
130
|
+
// Subcommands
|
|
131
|
+
if ((arg === "list" || arg === "config") && command === null && input === null) {
|
|
132
|
+
return { ...parseRest(args, i), command: arg };
|
|
133
|
+
}
|
|
134
|
+
// Bare string → positional input (first one wins)
|
|
135
|
+
if (input === null) {
|
|
136
|
+
input = arg;
|
|
137
|
+
}
|
|
138
|
+
i++;
|
|
139
|
+
}
|
|
140
|
+
return { command, opts, segments, input };
|
|
141
|
+
}
|
|
142
|
+
// After recognizing a subcommand, parse the rest for that subcommand's options
|
|
143
|
+
function parseRest(args, startIndex) {
|
|
144
|
+
const opts = {};
|
|
145
|
+
const segments = [];
|
|
146
|
+
let input = null;
|
|
147
|
+
let i = startIndex + 1;
|
|
148
|
+
while (i < args.length) {
|
|
149
|
+
const arg = args[i];
|
|
150
|
+
let matched = false;
|
|
151
|
+
for (const [names, key] of VALUED_OPTIONS) {
|
|
152
|
+
if (names.includes(arg) && i + 1 < args.length) {
|
|
153
|
+
opts[key] = args[i + 1];
|
|
154
|
+
i += 2;
|
|
155
|
+
matched = true;
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (matched)
|
|
160
|
+
continue;
|
|
161
|
+
for (const [names, key] of BOOLEAN_FLAGS) {
|
|
162
|
+
if (names.includes(arg)) {
|
|
163
|
+
opts[key] = true;
|
|
164
|
+
i++;
|
|
165
|
+
matched = true;
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (matched)
|
|
170
|
+
continue;
|
|
171
|
+
if (input === null)
|
|
172
|
+
input = arg;
|
|
173
|
+
i++;
|
|
174
|
+
}
|
|
175
|
+
return { command: null, opts, segments, input };
|
|
176
|
+
}
|
|
177
|
+
function showHelp() {
|
|
178
|
+
console.log(`Brother Label Printer CLI v${VERSION}
|
|
179
|
+
|
|
180
|
+
Usage:
|
|
181
|
+
brother-print [options] <input> Print text, file, or image
|
|
182
|
+
brother-print -text <v> -qr <v> ... Print ordered segments
|
|
183
|
+
brother-print list List available printers
|
|
184
|
+
brother-print config Show/set configuration
|
|
185
|
+
|
|
186
|
+
Options:
|
|
187
|
+
-tape <size> Tape size: 6, 9, 12, 18, 24 (mm)
|
|
188
|
+
-p, -printer <n> Printer name
|
|
189
|
+
-o, -output <file> Save to file instead of printing (png, jpg, bmp)
|
|
190
|
+
-a, -aspect <r> Aspect ratio width:height for HTML (e.g., 3.5:2)
|
|
191
|
+
-H, -height <size> Text height: 12mm, .5in, or 50% (of tape height)
|
|
192
|
+
-s, -space <size> Space between segments: 12px, 1mm, .2in
|
|
193
|
+
-t, -text Force input as literal text (or -text <v> for segments)
|
|
194
|
+
-qr <data> QR code segment
|
|
195
|
+
-w, -html Force input as HTML file path
|
|
196
|
+
-i, -image Force input as image file path
|
|
197
|
+
-help Show this help
|
|
198
|
+
-version Show version`);
|
|
199
|
+
}
|
|
200
|
+
// --- Main ---
|
|
201
|
+
async function main() {
|
|
202
|
+
const parsed = parseArgs(process.argv);
|
|
203
|
+
if (parsed.opts.help) {
|
|
204
|
+
showHelp();
|
|
93
205
|
return;
|
|
94
206
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
207
|
+
if (parsed.opts.version) {
|
|
208
|
+
console.log(VERSION);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
// Subcommands
|
|
212
|
+
if (parsed.command === "list") {
|
|
213
|
+
try {
|
|
214
|
+
const printers = await listPrinters();
|
|
215
|
+
if (printers.length === 0) {
|
|
216
|
+
console.log("No Brother printers found");
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
console.log("Brother printers:");
|
|
220
|
+
printers.forEach(p => console.log(` ${p.name}`));
|
|
221
|
+
}
|
|
102
222
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const tape = options.tape ?? getConfig().defaultTape ?? 24;
|
|
107
|
-
console.log(`Printed on ${tape}mm tape`);
|
|
223
|
+
catch (err) {
|
|
224
|
+
console.error(`Error: ${err.message}`);
|
|
225
|
+
process.exit(1);
|
|
108
226
|
}
|
|
227
|
+
return;
|
|
109
228
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
229
|
+
if (parsed.command === "config") {
|
|
230
|
+
try {
|
|
231
|
+
if (!parsed.opts.tape && !parsed.opts.printer) {
|
|
232
|
+
const config = getConfig();
|
|
233
|
+
console.log("Configuration:");
|
|
234
|
+
console.log(` File: ${getConfigPath()}`);
|
|
235
|
+
console.log(` Default tape: ${config.defaultTape ? config.defaultTape + "mm" : "(not set)"}`);
|
|
236
|
+
console.log(` Default printer: ${config.defaultPrinter ?? "(not set)"}`);
|
|
237
|
+
console.log("\nValid tape sizes: 6, 9, 12, 18, 24");
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (parsed.opts.tape) {
|
|
241
|
+
const tape = parseTape(parsed.opts.tape);
|
|
242
|
+
setConfig({ defaultTape: tape });
|
|
243
|
+
console.log(`Default tape set to: ${tape}mm`);
|
|
244
|
+
}
|
|
245
|
+
if (parsed.opts.printer) {
|
|
246
|
+
setConfig({ defaultPrinter: parsed.opts.printer });
|
|
247
|
+
console.log(`Default printer set to: ${parsed.opts.printer}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
console.error(`Error: ${err.message}`);
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
254
|
+
return;
|
|
113
255
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
256
|
+
// Multi-segment mode
|
|
257
|
+
if (parsed.segments.length > 0) {
|
|
258
|
+
try {
|
|
259
|
+
const tape = parsed.opts.tape ? parseTape(parsed.opts.tape) : undefined;
|
|
260
|
+
if (parsed.opts.output) {
|
|
261
|
+
const buffer = await renderSegments(parsed.segments, tape, parsed.opts.height, parsed.opts.space);
|
|
262
|
+
fs.writeFileSync(parsed.opts.output, buffer);
|
|
263
|
+
console.log(`Saved to ${parsed.opts.output}`);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
await printSegments(parsed.segments, { tape, printer: parsed.opts.printer, textHeight: parsed.opts.height, space: parsed.opts.space });
|
|
267
|
+
const effectiveTape = tape ?? getConfig().defaultTape ?? 24;
|
|
268
|
+
console.log(`Printed ${parsed.segments.length} segments on ${effectiveTape}mm tape`);
|
|
269
|
+
}
|
|
124
270
|
}
|
|
125
|
-
|
|
126
|
-
console.
|
|
127
|
-
|
|
271
|
+
catch (err) {
|
|
272
|
+
console.error(`Error: ${err.message}`);
|
|
273
|
+
process.exit(1);
|
|
128
274
|
}
|
|
275
|
+
return;
|
|
129
276
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
277
|
+
// Single input mode
|
|
278
|
+
if (!parsed.input) {
|
|
279
|
+
showHelp();
|
|
280
|
+
return;
|
|
133
281
|
}
|
|
134
|
-
});
|
|
135
|
-
// Config
|
|
136
|
-
program
|
|
137
|
-
.command("config")
|
|
138
|
-
.description("Show or set configuration")
|
|
139
|
-
.option("-t, --tape <size>", "Set default tape size: 6, 9, 12, 18, 24 (mm)")
|
|
140
|
-
.option("-p, --printer <name>", "Set default printer name")
|
|
141
|
-
.action((opts) => {
|
|
142
282
|
try {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
console.log(`
|
|
283
|
+
const options = buildPrintOptions(parsed.input, {
|
|
284
|
+
tape: parsed.opts.tape,
|
|
285
|
+
printer: parsed.opts.printer,
|
|
286
|
+
text: parsed.opts.text,
|
|
287
|
+
html: parsed.opts.html,
|
|
288
|
+
image: parsed.opts.image,
|
|
289
|
+
aspect: parsed.opts.aspect,
|
|
290
|
+
height: parsed.opts.height,
|
|
291
|
+
});
|
|
292
|
+
if (parsed.opts.output) {
|
|
293
|
+
const buffer = await render(options);
|
|
294
|
+
fs.writeFileSync(parsed.opts.output, buffer);
|
|
295
|
+
console.log(`Saved to ${parsed.opts.output}`);
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
await print(options);
|
|
299
|
+
const tape = options.tape ?? getConfig().defaultTape ?? 24;
|
|
300
|
+
console.log(`Printed on ${tape}mm tape`);
|
|
161
301
|
}
|
|
162
302
|
}
|
|
163
303
|
catch (err) {
|
|
164
304
|
console.error(`Error: ${err.message}`);
|
|
165
305
|
process.exit(1);
|
|
166
306
|
}
|
|
167
|
-
}
|
|
168
|
-
|
|
307
|
+
}
|
|
308
|
+
main();
|
|
169
309
|
//# sourceMappingURL=cli.js.map
|
package/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\r\n/**\r\n * Brother Label Printer CLI\r\n * Thin wrapper around the API\r\n */\r\n\r\nimport * as fs from \"fs\";\r\nimport * as path from \"path\";\r\nimport { program } from \"commander\";\r\nimport {\r\n print,\r\n render,\r\n getConfig,\r\n setConfig,\r\n getConfigPath,\r\n listPrinters,\r\n TapeSize,\r\n PrintOptions,\r\n} from \"./api.js\";\r\n\r\nconst VALID_TAPES: TapeSize[] = [6, 9, 12, 18, 24];\r\n\r\nfunction parseTape(value: string): TapeSize {\r\n const num = parseInt(value.replace(\"mm\", \"\"), 10) as TapeSize;\r\n if (!VALID_TAPES.includes(num)) {\r\n throw new Error(`Invalid tape size: ${value}. Valid: 6, 9, 12, 18, 24`);\r\n }\r\n return num;\r\n}\r\n\r\n// Detect content type from input string\r\nfunction buildPrintOptions(input: string, opts: { tape?: string; printer?: string; text?: boolean; html?: boolean; image?: boolean; aspect?: string; height?: string }): PrintOptions {\r\n const options: PrintOptions = {};\r\n\r\n // Parse tape option\r\n if (opts.tape) {\r\n options.tape = parseTape(opts.tape);\r\n }\r\n if (opts.printer) {\r\n options.printer = opts.printer;\r\n }\r\n if (opts.aspect) {\r\n options.aspect = opts.aspect;\r\n }\r\n if (opts.height) {\r\n options.textHeight = opts.height;\r\n }\r\n\r\n // Explicit type flags override auto-detection\r\n if (opts.text) {\r\n options.text = input;\r\n return options;\r\n }\r\n if (opts.html) {\r\n options.htmlPath = path.resolve(input);\r\n return options;\r\n }\r\n if (opts.image) {\r\n options.imagePath = path.resolve(input);\r\n return options;\r\n }\r\n\r\n // Auto-detect content type\r\n const lower = input.toLowerCase();\r\n if (lower.endsWith(\".html\") || lower.endsWith(\".htm\")) {\r\n options.htmlPath = path.resolve(input);\r\n } else if (lower.endsWith(\".txt\")) {\r\n options.textFile = path.resolve(input);\r\n } else if (lower.endsWith(\".png\") || lower.endsWith(\".jpg\") || lower.endsWith(\".jpeg\") || lower.endsWith(\".bmp\") || lower.endsWith(\".gif\")) {\r\n options.imagePath = path.resolve(input);\r\n } else if (fs.existsSync(input)) {\r\n // Exists but unknown extension - try to detect\r\n const ext = path.extname(lower);\r\n if (ext === \".html\" || ext === \".htm\") {\r\n options.htmlPath = path.resolve(input);\r\n } else {\r\n // Assume text file\r\n options.textFile = path.resolve(input);\r\n }\r\n } else {\r\n // Treat as literal text\r\n options.text = input;\r\n }\r\n\r\n return options;\r\n}\r\n\r\nprogram\r\n .name(\"brother-print\")\r\n .description(\"Print labels on Brother P-touch printers\")\r\n .version(\"1.0.0\");\r\n\r\n// Default command - print\r\nprogram\r\n .argument(\"[input]\", \"Text to print, or path to file (auto-detects type)\")\r\n .option(\"-t, --tape <size>\", \"Tape size: 6, 9, 12, 18, 24 (mm)\")\r\n .option(\"-p, --printer <name>\", \"Printer name\")\r\n .option(\"-o, --output <file>\", \"Save to file instead of printing (png, jpg, bmp)\")\r\n .option(\"-a, --aspect <ratio>\", \"Aspect ratio width:height for HTML (e.g., 3.5:2)\")\r\n .option(\"-H, --height <size>\", \"Text height: 12mm, .5in, or 50% (of tape height)\")\r\n .option(\"--text\", \"Force input as literal text\")\r\n .option(\"--html\", \"Force input as HTML file path\")\r\n .option(\"--image\", \"Force input as image file path\")\r\n .action(async (input: string | undefined, opts) => {\r\n if (!input) {\r\n program.help();\r\n return;\r\n }\r\n\r\n try {\r\n const options = buildPrintOptions(input, opts);\r\n\r\n if (opts.output) {\r\n // Render only, save to file\r\n const buffer = await render(options);\r\n fs.writeFileSync(opts.output, buffer);\r\n console.log(`Saved to ${opts.output}`);\r\n } else {\r\n // Print\r\n const result = await print(options);\r\n const tape = options.tape ?? getConfig().defaultTape ?? 24;\r\n console.log(`Printed on ${tape}mm tape`);\r\n }\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\n// List printers\r\nprogram\r\n .command(\"list\")\r\n .description(\"List available Brother printers\")\r\n .action(async () => {\r\n try {\r\n const printers = await listPrinters();\r\n if (printers.length === 0) {\r\n console.log(\"No Brother printers found\");\r\n } else {\r\n console.log(\"Brother printers:\");\r\n printers.forEach(p => console.log(` ${p.name}`));\r\n }\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\n// Config\r\nprogram\r\n .command(\"config\")\r\n .description(\"Show or set configuration\")\r\n .option(\"-t, --tape <size>\", \"Set default tape size: 6, 9, 12, 18, 24 (mm)\")\r\n .option(\"-p, --printer <name>\", \"Set default printer name\")\r\n .action((opts) => {\r\n try {\r\n if (!opts.tape && !opts.printer) {\r\n // Show config\r\n const config = getConfig();\r\n console.log(\"Configuration:\");\r\n console.log(` File: ${getConfigPath()}`);\r\n console.log(` Default tape: ${config.defaultTape ? config.defaultTape + \"mm\" : \"(not set)\"}`);\r\n console.log(` Default printer: ${config.defaultPrinter ?? \"(not set)\"}`);\r\n console.log(\"\\nValid tape sizes: 6, 9, 12, 18, 24\");\r\n return;\r\n }\r\n\r\n if (opts.tape) {\r\n const tape = parseTape(opts.tape);\r\n setConfig({ defaultTape: tape });\r\n console.log(`Default tape set to: ${tape}mm`);\r\n }\r\n\r\n if (opts.printer) {\r\n setConfig({ defaultPrinter: opts.printer });\r\n console.log(`Default printer set to: ${opts.printer}`);\r\n }\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram.parse();\r\n"]}
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\r\n/**\r\n * Brother Label Printer CLI\r\n * Thin wrapper around the API\r\n */\r\n\r\nimport * as fs from \"fs\";\r\nimport * as path from \"path\";\r\nimport {\r\n print,\r\n render,\r\n renderSegments,\r\n printSegments,\r\n getConfig,\r\n setConfig,\r\n getConfigPath,\r\n listPrinters,\r\n TapeSize,\r\n PrintOptions,\r\n Segment,\r\n} from \"./api.js\";\r\n\r\nconst VERSION = \"1.0.13\";\r\nconst VALID_TAPES: TapeSize[] = [6, 9, 12, 18, 24];\r\n\r\nfunction parseTape(value: string): TapeSize {\r\n const num = parseInt(value.replace(\"mm\", \"\"), 10) as TapeSize;\r\n if (!VALID_TAPES.includes(num)) {\r\n throw new Error(`Invalid tape size: ${value}. Valid: 6, 9, 12, 18, 24`);\r\n }\r\n return num;\r\n}\r\n\r\n// Detect content type from input string\r\nfunction buildPrintOptions(input: string, opts: { tape?: string; printer?: string; text?: boolean; html?: boolean; image?: boolean; aspect?: string; height?: string }): PrintOptions {\r\n const options: PrintOptions = {};\r\n\r\n // Parse tape option\r\n if (opts.tape) {\r\n options.tape = parseTape(opts.tape);\r\n }\r\n if (opts.printer) {\r\n options.printer = opts.printer;\r\n }\r\n if (opts.aspect) {\r\n options.aspect = opts.aspect;\r\n }\r\n if (opts.height) {\r\n options.textHeight = opts.height;\r\n }\r\n\r\n // Explicit type flags override auto-detection\r\n if (opts.text) {\r\n options.text = input;\r\n return options;\r\n }\r\n if (opts.html) {\r\n options.htmlPath = path.resolve(input);\r\n return options;\r\n }\r\n if (opts.image) {\r\n options.imagePath = path.resolve(input);\r\n return options;\r\n }\r\n\r\n // Auto-detect content type\r\n const lower = input.toLowerCase();\r\n if (lower.endsWith(\".html\") || lower.endsWith(\".htm\")) {\r\n options.htmlPath = path.resolve(input);\r\n } else if (lower.endsWith(\".txt\")) {\r\n options.textFile = path.resolve(input);\r\n } else if (lower.endsWith(\".png\") || lower.endsWith(\".jpg\") || lower.endsWith(\".jpeg\") || lower.endsWith(\".bmp\") || lower.endsWith(\".gif\")) {\r\n options.imagePath = path.resolve(input);\r\n } else if (fs.existsSync(input)) {\r\n // Exists but unknown extension - try to detect\r\n const ext = path.extname(lower);\r\n if (ext === \".html\" || ext === \".htm\") {\r\n options.htmlPath = path.resolve(input);\r\n } else {\r\n // Assume text file\r\n options.textFile = path.resolve(input);\r\n }\r\n } else {\r\n // Treat as literal text\r\n options.text = input;\r\n }\r\n\r\n return options;\r\n}\r\n\r\ninterface ParsedArgs {\r\n command: string | null;\r\n opts: Record<string, string | boolean>;\r\n segments: Segment[];\r\n input: string | null;\r\n}\r\n\r\n// Valued options: flag name(s) → canonical key\r\nconst VALUED_OPTIONS: [string[], string][] = [\r\n [[\"-tape\"], \"tape\"],\r\n [[\"-p\", \"-printer\"], \"printer\"],\r\n [[\"-o\", \"-output\"], \"output\"],\r\n [[\"-a\", \"-aspect\"], \"aspect\"],\r\n [[\"-H\", \"-height\"], \"height\"],\r\n [[\"-s\", \"-sp\", \"-space\"], \"space\"],\r\n];\r\n\r\n// Boolean flags: flag name(s) → canonical key\r\nconst BOOLEAN_FLAGS: [string[], string][] = [\r\n [[\"-w\", \"-html\"], \"html\"],\r\n [[\"-i\", \"-image\"], \"image\"],\r\n [[\"-t\"], \"text\"],\r\n [[\"-help\", \"-h\"], \"help\"],\r\n [[\"-version\", \"-v\"], \"version\"],\r\n];\r\n\r\nfunction parseArgs(argv: string[]): ParsedArgs {\r\n const args = argv.slice(2).map(a => a.startsWith(\"--\") ? a.slice(1) : a);\r\n const command: string | null = null;\r\n const opts: Record<string, string | boolean> = {};\r\n const segments: Segment[] = [];\r\n let input: string | null = null;\r\n let i = 0;\r\n\r\n while (i < args.length) {\r\n const arg = args[i];\r\n\r\n // Segment flags: -text <value>, -qr <value>\r\n if ((arg === \"-text\" || arg === \"-qr\") && i + 1 < args.length) {\r\n segments.push({ type: arg === \"-text\" ? \"text\" : \"qr\", value: args[i + 1] });\r\n i += 2;\r\n continue;\r\n }\r\n\r\n // Valued options\r\n let matched = false;\r\n for (const [names, key] of VALUED_OPTIONS) {\r\n if (names.includes(arg) && i + 1 < args.length) {\r\n opts[key] = args[i + 1];\r\n i += 2;\r\n matched = true;\r\n break;\r\n }\r\n }\r\n if (matched) continue;\r\n\r\n // Boolean flags\r\n for (const [names, key] of BOOLEAN_FLAGS) {\r\n if (names.includes(arg)) {\r\n opts[key] = true;\r\n i++;\r\n matched = true;\r\n break;\r\n }\r\n }\r\n if (matched) continue;\r\n\r\n // Subcommands\r\n if ((arg === \"list\" || arg === \"config\") && command === null && input === null) {\r\n return { ...parseRest(args, i), command: arg };\r\n }\r\n\r\n // Bare string → positional input (first one wins)\r\n if (input === null) {\r\n input = arg;\r\n }\r\n i++;\r\n }\r\n\r\n return { command, opts, segments, input };\r\n}\r\n\r\n// After recognizing a subcommand, parse the rest for that subcommand's options\r\nfunction parseRest(args: string[], startIndex: number): ParsedArgs {\r\n const opts: Record<string, string | boolean> = {};\r\n const segments: Segment[] = [];\r\n let input: string | null = null;\r\n let i = startIndex + 1;\r\n\r\n while (i < args.length) {\r\n const arg = args[i];\r\n let matched = false;\r\n for (const [names, key] of VALUED_OPTIONS) {\r\n if (names.includes(arg) && i + 1 < args.length) {\r\n opts[key] = args[i + 1];\r\n i += 2;\r\n matched = true;\r\n break;\r\n }\r\n }\r\n if (matched) continue;\r\n\r\n for (const [names, key] of BOOLEAN_FLAGS) {\r\n if (names.includes(arg)) {\r\n opts[key] = true;\r\n i++;\r\n matched = true;\r\n break;\r\n }\r\n }\r\n if (matched) continue;\r\n\r\n if (input === null) input = arg;\r\n i++;\r\n }\r\n\r\n return { command: null, opts, segments, input };\r\n}\r\n\r\nfunction showHelp(): void {\r\n console.log(`Brother Label Printer CLI v${VERSION}\r\n\r\nUsage:\r\n brother-print [options] <input> Print text, file, or image\r\n brother-print -text <v> -qr <v> ... Print ordered segments\r\n brother-print list List available printers\r\n brother-print config Show/set configuration\r\n\r\nOptions:\r\n -tape <size> Tape size: 6, 9, 12, 18, 24 (mm)\r\n -p, -printer <n> Printer name\r\n -o, -output <file> Save to file instead of printing (png, jpg, bmp)\r\n -a, -aspect <r> Aspect ratio width:height for HTML (e.g., 3.5:2)\r\n -H, -height <size> Text height: 12mm, .5in, or 50% (of tape height)\r\n -s, -space <size> Space between segments: 12px, 1mm, .2in\r\n -t, -text Force input as literal text (or -text <v> for segments)\r\n -qr <data> QR code segment\r\n -w, -html Force input as HTML file path\r\n -i, -image Force input as image file path\r\n -help Show this help\r\n -version Show version`);\r\n}\r\n\r\n// --- Main ---\r\n\r\nasync function main(): Promise<void> {\r\n const parsed = parseArgs(process.argv);\r\n\r\n if (parsed.opts.help) {\r\n showHelp();\r\n return;\r\n }\r\n if (parsed.opts.version) {\r\n console.log(VERSION);\r\n return;\r\n }\r\n\r\n // Subcommands\r\n if (parsed.command === \"list\") {\r\n try {\r\n const printers = await listPrinters();\r\n if (printers.length === 0) {\r\n console.log(\"No Brother printers found\");\r\n } else {\r\n console.log(\"Brother printers:\");\r\n printers.forEach(p => console.log(` ${p.name}`));\r\n }\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n return;\r\n }\r\n\r\n if (parsed.command === \"config\") {\r\n try {\r\n if (!parsed.opts.tape && !parsed.opts.printer) {\r\n const config = getConfig();\r\n console.log(\"Configuration:\");\r\n console.log(` File: ${getConfigPath()}`);\r\n console.log(` Default tape: ${config.defaultTape ? config.defaultTape + \"mm\" : \"(not set)\"}`);\r\n console.log(` Default printer: ${config.defaultPrinter ?? \"(not set)\"}`);\r\n console.log(\"\\nValid tape sizes: 6, 9, 12, 18, 24\");\r\n return;\r\n }\r\n if (parsed.opts.tape) {\r\n const tape = parseTape(parsed.opts.tape as string);\r\n setConfig({ defaultTape: tape });\r\n console.log(`Default tape set to: ${tape}mm`);\r\n }\r\n if (parsed.opts.printer) {\r\n setConfig({ defaultPrinter: parsed.opts.printer as string });\r\n console.log(`Default printer set to: ${parsed.opts.printer}`);\r\n }\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n return;\r\n }\r\n\r\n // Multi-segment mode\r\n if (parsed.segments.length > 0) {\r\n try {\r\n const tape = parsed.opts.tape ? parseTape(parsed.opts.tape as string) : undefined;\r\n if (parsed.opts.output) {\r\n const buffer = await renderSegments(parsed.segments, tape, parsed.opts.height as string | undefined, parsed.opts.space as string | undefined);\r\n fs.writeFileSync(parsed.opts.output as string, buffer);\r\n console.log(`Saved to ${parsed.opts.output}`);\r\n } else {\r\n await printSegments(parsed.segments, { tape, printer: parsed.opts.printer as string | undefined, textHeight: parsed.opts.height as string | undefined, space: parsed.opts.space as string | undefined });\r\n const effectiveTape = tape ?? getConfig().defaultTape ?? 24;\r\n console.log(`Printed ${parsed.segments.length} segments on ${effectiveTape}mm tape`);\r\n }\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n return;\r\n }\r\n\r\n // Single input mode\r\n if (!parsed.input) {\r\n showHelp();\r\n return;\r\n }\r\n\r\n try {\r\n const options = buildPrintOptions(parsed.input, {\r\n tape: parsed.opts.tape as string | undefined,\r\n printer: parsed.opts.printer as string | undefined,\r\n text: parsed.opts.text as boolean | undefined,\r\n html: parsed.opts.html as boolean | undefined,\r\n image: parsed.opts.image as boolean | undefined,\r\n aspect: parsed.opts.aspect as string | undefined,\r\n height: parsed.opts.height as string | undefined,\r\n });\r\n\r\n if (parsed.opts.output) {\r\n const buffer = await render(options);\r\n fs.writeFileSync(parsed.opts.output as string, buffer);\r\n console.log(`Saved to ${parsed.opts.output}`);\r\n } else {\r\n await print(options);\r\n const tape = options.tape ?? getConfig().defaultTape ?? 24;\r\n console.log(`Printed on ${tape}mm tape`);\r\n }\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n}\r\n\r\nmain();\r\n"]}
|