@qrdx/cli 0.0.1 → 0.0.2
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 +4 -4
- package/dist/index.js +117 -30
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# qrdx
|
|
1
|
+
# @qrdx/cli
|
|
2
2
|
|
|
3
3
|
QR code generator CLI for developers. Generate styled, scannable QR codes as SVG or PNG — fully non-interactive, CI-friendly.
|
|
4
4
|
|
|
@@ -9,7 +9,7 @@ QR code generator CLI for developers. Generate styled, scannable QR codes as SVG
|
|
|
9
9
|
npm install -g qrdx
|
|
10
10
|
|
|
11
11
|
# Or install the standalone CLI package
|
|
12
|
-
npm install -g qrdx
|
|
12
|
+
npm install -g @qrdx/cli
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Or run without installing:
|
|
@@ -72,9 +72,9 @@ qrdx generate
|
|
|
72
72
|
|
|
73
73
|
**Body** (`--body`): `square` `circle` `circle-large` `diamond` `circle-mixed` `pacman` `rounded` `small-square` `vertical-line`
|
|
74
74
|
|
|
75
|
-
**Eye** (`--eye`): `square` `rounded` `gear` `circle` `diya` `
|
|
75
|
+
**Eye** (`--eye`): `square` `rounded` `gear` `circle` `diya` `extra-rounded` `message` `pointy` `curly`
|
|
76
76
|
|
|
77
|
-
**Dot** (`--dot`): `square` `rounded` `circle` `
|
|
77
|
+
**Dot** (`--dot`): `square` `rounded` `circle` `diamond` `message` `message-reverse` `diya` `diya-reverse` `rounded-triangle` `star` `banner`
|
|
78
78
|
|
|
79
79
|
## Interactive mode
|
|
80
80
|
|
package/dist/index.js
CHANGED
|
@@ -55,6 +55,16 @@ var RESET = "\x1B[0m";
|
|
|
55
55
|
var TEXT = "\x1B[38;5;145m";
|
|
56
56
|
var GREEN = "\x1B[38;5;114m";
|
|
57
57
|
var DIM = "\x1B[38;5;102m";
|
|
58
|
+
function parseColorFlag(value) {
|
|
59
|
+
const trimmed = value.trim();
|
|
60
|
+
if (trimmed.startsWith("{")) {
|
|
61
|
+
try {
|
|
62
|
+
return JSON.parse(trimmed);
|
|
63
|
+
} catch {
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return trimmed;
|
|
67
|
+
}
|
|
58
68
|
var IS_TTY = Boolean(process.stdin.isTTY);
|
|
59
69
|
function parseFlags(args) {
|
|
60
70
|
const flags = {};
|
|
@@ -93,19 +103,19 @@ function parseFlags(args) {
|
|
|
93
103
|
i += 2;
|
|
94
104
|
break;
|
|
95
105
|
case "--fg":
|
|
96
|
-
flags.fg = next;
|
|
106
|
+
flags.fg = next ? parseColorFlag(next) : void 0;
|
|
97
107
|
i += 2;
|
|
98
108
|
break;
|
|
99
109
|
case "--bg":
|
|
100
|
-
flags.bg = next;
|
|
110
|
+
flags.bg = next ? parseColorFlag(next) : void 0;
|
|
101
111
|
i += 2;
|
|
102
112
|
break;
|
|
103
113
|
case "--eye-color":
|
|
104
|
-
flags.eyeColor = next;
|
|
114
|
+
flags.eyeColor = next ? parseColorFlag(next) : void 0;
|
|
105
115
|
i += 2;
|
|
106
116
|
break;
|
|
107
117
|
case "--dot-color":
|
|
108
|
-
flags.dotColor = next;
|
|
118
|
+
flags.dotColor = next ? parseColorFlag(next) : void 0;
|
|
109
119
|
i += 2;
|
|
110
120
|
break;
|
|
111
121
|
case "--logo":
|
|
@@ -113,7 +123,7 @@ function parseFlags(args) {
|
|
|
113
123
|
i += 2;
|
|
114
124
|
break;
|
|
115
125
|
case "--margin":
|
|
116
|
-
flags.margin = next ? Number.parseInt(next, 10) :
|
|
126
|
+
flags.margin = next ? Number.parseInt(next, 10) : qrdx.DEFAULT_MARGIN;
|
|
117
127
|
i += 2;
|
|
118
128
|
break;
|
|
119
129
|
case "--size":
|
|
@@ -124,6 +134,10 @@ function parseFlags(args) {
|
|
|
124
134
|
flags.noLogo = true;
|
|
125
135
|
i++;
|
|
126
136
|
break;
|
|
137
|
+
case "--template":
|
|
138
|
+
flags.template = next;
|
|
139
|
+
i += 2;
|
|
140
|
+
break;
|
|
127
141
|
default:
|
|
128
142
|
i++;
|
|
129
143
|
}
|
|
@@ -148,7 +162,7 @@ async function runGenerate(args) {
|
|
|
148
162
|
const flags = parseFlags(args);
|
|
149
163
|
const nonInteractive = !IS_TTY;
|
|
150
164
|
const hasAdvancedFlags = Boolean(
|
|
151
|
-
flags.body || flags.eye || flags.dot || flags.fg || flags.bg || flags.eyeColor || flags.dotColor || flags.logo || flags.level || flags.margin !== void 0
|
|
165
|
+
flags.body || flags.eye || flags.dot || flags.fg || flags.bg || flags.eyeColor || flags.dotColor || flags.logo || flags.level || flags.margin !== void 0 || flags.template
|
|
152
166
|
);
|
|
153
167
|
p__namespace.intro(`${TEXT}qrdx${RESET} ${DIM}\u2014 QR Code Generator${RESET}`);
|
|
154
168
|
let value = flags.value;
|
|
@@ -209,7 +223,8 @@ async function runGenerate(args) {
|
|
|
209
223
|
let eyeColor = flags.eyeColor;
|
|
210
224
|
let dotColor = flags.dotColor;
|
|
211
225
|
let logo = flags.logo;
|
|
212
|
-
let margin = flags.margin ??
|
|
226
|
+
let margin = flags.margin ?? qrdx.DEFAULT_MARGIN;
|
|
227
|
+
let template = flags.template;
|
|
213
228
|
if (wantAdvanced && !nonInteractive) {
|
|
214
229
|
if (!flags.level) {
|
|
215
230
|
const res = await p__namespace.select({
|
|
@@ -266,42 +281,75 @@ async function runGenerate(args) {
|
|
|
266
281
|
}
|
|
267
282
|
if (!flags.fg) {
|
|
268
283
|
const res = await p__namespace.text({
|
|
269
|
-
message:
|
|
284
|
+
message: `Foreground color ${DIM}(hex or JSON gradient)${RESET}`,
|
|
270
285
|
placeholder: "#000000",
|
|
271
286
|
defaultValue: "#000000",
|
|
272
287
|
validate(v) {
|
|
273
|
-
if (v
|
|
274
|
-
return
|
|
288
|
+
if (!v) {
|
|
289
|
+
return void 0;
|
|
290
|
+
}
|
|
291
|
+
if (v.trim().startsWith("{")) {
|
|
292
|
+
try {
|
|
293
|
+
JSON.parse(v.trim());
|
|
294
|
+
} catch {
|
|
295
|
+
return "Enter a valid hex color or JSON gradient object";
|
|
296
|
+
}
|
|
297
|
+
return void 0;
|
|
298
|
+
}
|
|
299
|
+
if (!/^#[0-9a-fA-F]{3,8}$/.test(v)) {
|
|
300
|
+
return "Enter a valid hex color (e.g. #000000) or JSON gradient";
|
|
275
301
|
}
|
|
276
302
|
}
|
|
277
303
|
});
|
|
278
304
|
if (isCancel2(res)) {
|
|
279
305
|
handleCancel();
|
|
280
306
|
}
|
|
281
|
-
fg = res || "#000000";
|
|
307
|
+
fg = parseColorFlag(res || "#000000");
|
|
282
308
|
}
|
|
283
309
|
if (!flags.bg) {
|
|
284
310
|
const res = await p__namespace.text({
|
|
285
|
-
message:
|
|
311
|
+
message: `Background color ${DIM}(hex or JSON gradient)${RESET}`,
|
|
286
312
|
placeholder: "#ffffff",
|
|
287
313
|
defaultValue: "#ffffff",
|
|
288
314
|
validate(v) {
|
|
289
|
-
if (v
|
|
290
|
-
return
|
|
315
|
+
if (!v) {
|
|
316
|
+
return void 0;
|
|
317
|
+
}
|
|
318
|
+
if (v.trim().startsWith("{")) {
|
|
319
|
+
try {
|
|
320
|
+
JSON.parse(v.trim());
|
|
321
|
+
} catch {
|
|
322
|
+
return "Enter a valid hex color or JSON gradient object";
|
|
323
|
+
}
|
|
324
|
+
return void 0;
|
|
325
|
+
}
|
|
326
|
+
if (!/^#[0-9a-fA-F]{3,8}$/.test(v)) {
|
|
327
|
+
return "Enter a valid hex color (e.g. #ffffff) or JSON gradient";
|
|
291
328
|
}
|
|
292
329
|
}
|
|
293
330
|
});
|
|
294
331
|
if (isCancel2(res)) {
|
|
295
332
|
handleCancel();
|
|
296
333
|
}
|
|
297
|
-
bg = res || "#ffffff";
|
|
334
|
+
bg = parseColorFlag(res || "#ffffff");
|
|
298
335
|
}
|
|
299
336
|
if (eyeColor === void 0) {
|
|
300
337
|
const res = await p__namespace.text({
|
|
301
338
|
message: `Corner eye color ${DIM}(leave blank to match foreground)${RESET}`,
|
|
302
|
-
placeholder:
|
|
339
|
+
placeholder: "leave blank",
|
|
303
340
|
validate(v) {
|
|
304
|
-
if (v
|
|
341
|
+
if (!v) {
|
|
342
|
+
return void 0;
|
|
343
|
+
}
|
|
344
|
+
if (v.trim().startsWith("{")) {
|
|
345
|
+
try {
|
|
346
|
+
JSON.parse(v.trim());
|
|
347
|
+
} catch {
|
|
348
|
+
return "Enter a valid hex color or JSON gradient object";
|
|
349
|
+
}
|
|
350
|
+
return void 0;
|
|
351
|
+
}
|
|
352
|
+
if (!/^#[0-9a-fA-F]{3,8}$/.test(v)) {
|
|
305
353
|
return "Enter a valid hex color or leave blank";
|
|
306
354
|
}
|
|
307
355
|
}
|
|
@@ -309,14 +357,26 @@ async function runGenerate(args) {
|
|
|
309
357
|
if (isCancel2(res)) {
|
|
310
358
|
handleCancel();
|
|
311
359
|
}
|
|
312
|
-
|
|
360
|
+
const eyeVal = res;
|
|
361
|
+
eyeColor = eyeVal ? parseColorFlag(eyeVal) : void 0;
|
|
313
362
|
}
|
|
314
363
|
if (dotColor === void 0) {
|
|
315
364
|
const res = await p__namespace.text({
|
|
316
365
|
message: `Corner dot color ${DIM}(leave blank to match foreground)${RESET}`,
|
|
317
|
-
placeholder:
|
|
366
|
+
placeholder: "leave blank",
|
|
318
367
|
validate(v) {
|
|
319
|
-
if (v
|
|
368
|
+
if (!v) {
|
|
369
|
+
return void 0;
|
|
370
|
+
}
|
|
371
|
+
if (v.trim().startsWith("{")) {
|
|
372
|
+
try {
|
|
373
|
+
JSON.parse(v.trim());
|
|
374
|
+
} catch {
|
|
375
|
+
return "Enter a valid hex color or JSON gradient object";
|
|
376
|
+
}
|
|
377
|
+
return void 0;
|
|
378
|
+
}
|
|
379
|
+
if (!/^#[0-9a-fA-F]{3,8}$/.test(v)) {
|
|
320
380
|
return "Enter a valid hex color or leave blank";
|
|
321
381
|
}
|
|
322
382
|
}
|
|
@@ -324,7 +384,23 @@ async function runGenerate(args) {
|
|
|
324
384
|
if (isCancel2(res)) {
|
|
325
385
|
handleCancel();
|
|
326
386
|
}
|
|
327
|
-
|
|
387
|
+
const dotVal = res;
|
|
388
|
+
dotColor = dotVal ? parseColorFlag(dotVal) : void 0;
|
|
389
|
+
}
|
|
390
|
+
if (!flags.template) {
|
|
391
|
+
const templateIds = qrdx.getTemplateIds();
|
|
392
|
+
const res = await p__namespace.select({
|
|
393
|
+
message: `Template ${DIM}(decorative wrapper around the QR code)${RESET}`,
|
|
394
|
+
options: [
|
|
395
|
+
{ value: "", label: "none" },
|
|
396
|
+
...templateIds.filter((id) => id !== "default").map((id) => ({ value: id, label: id }))
|
|
397
|
+
],
|
|
398
|
+
initialValue: ""
|
|
399
|
+
});
|
|
400
|
+
if (isCancel2(res)) {
|
|
401
|
+
handleCancel();
|
|
402
|
+
}
|
|
403
|
+
template = res || void 0;
|
|
328
404
|
}
|
|
329
405
|
if (logo === void 0 && !flags.noLogo) {
|
|
330
406
|
const addLogo = await p__namespace.confirm({
|
|
@@ -358,8 +434,8 @@ async function runGenerate(args) {
|
|
|
358
434
|
if (flags.margin === void 0) {
|
|
359
435
|
const res = await p__namespace.text({
|
|
360
436
|
message: "Quiet zone margin (modules)",
|
|
361
|
-
placeholder:
|
|
362
|
-
defaultValue:
|
|
437
|
+
placeholder: String(qrdx.DEFAULT_MARGIN),
|
|
438
|
+
defaultValue: String(qrdx.DEFAULT_MARGIN),
|
|
363
439
|
validate(v) {
|
|
364
440
|
if (v && Number.isNaN(Number.parseInt(v, 10))) {
|
|
365
441
|
return "Enter a number";
|
|
@@ -372,7 +448,7 @@ async function runGenerate(args) {
|
|
|
372
448
|
if (isCancel2(res)) {
|
|
373
449
|
handleCancel();
|
|
374
450
|
}
|
|
375
|
-
margin = Number.parseInt(res ||
|
|
451
|
+
margin = Number.parseInt(res || String(qrdx.DEFAULT_MARGIN), 10);
|
|
376
452
|
}
|
|
377
453
|
}
|
|
378
454
|
const spinner2 = p__namespace.spinner();
|
|
@@ -390,6 +466,7 @@ async function runGenerate(args) {
|
|
|
390
466
|
...dotColor ? { dotColor } : {},
|
|
391
467
|
margin,
|
|
392
468
|
size,
|
|
469
|
+
...template ? { templateId: template } : {},
|
|
393
470
|
...logo ? {
|
|
394
471
|
imageSettings: {
|
|
395
472
|
src: logo,
|
|
@@ -473,7 +550,7 @@ function showBanner() {
|
|
|
473
550
|
` ${DIM2}$${RESET2} ${TEXT2}qrdx --version${RESET2} ${DIM2}Show version${RESET2}`
|
|
474
551
|
);
|
|
475
552
|
console.log();
|
|
476
|
-
console.log(` ${DIM2}try:${RESET2} npx qrdx
|
|
553
|
+
console.log(` ${DIM2}try:${RESET2} npx @qrdx/cli generate "https://qrdx.dev"`);
|
|
477
554
|
console.log();
|
|
478
555
|
}
|
|
479
556
|
function showHelp() {
|
|
@@ -498,13 +575,20 @@ ${BOLD}Generate Options:${RESET2}
|
|
|
498
575
|
${DIM2}square, rounded, circle, diamond, message,${RESET2}
|
|
499
576
|
${DIM2}message-reverse, diya, diya-reverse,${RESET2}
|
|
500
577
|
${DIM2}rounded-triangle, star, banner${RESET2}
|
|
501
|
-
--fg Foreground color ${DIM2}(default: #000000)${RESET2}
|
|
502
|
-
--bg Background color ${DIM2}(default: #ffffff)${RESET2}
|
|
503
|
-
--eye-color Corner eye color ${DIM2}(default: matches --fg)${RESET2}
|
|
504
|
-
--dot-color Corner dot color ${DIM2}(default: matches --fg)${RESET2}
|
|
578
|
+
--fg Foreground color \u2014 hex or JSON gradient ${DIM2}(default: #000000)${RESET2}
|
|
579
|
+
--bg Background color \u2014 hex or JSON gradient ${DIM2}(default: #ffffff)${RESET2}
|
|
580
|
+
--eye-color Corner eye color \u2014 hex or JSON gradient ${DIM2}(default: matches --fg)${RESET2}
|
|
581
|
+
--dot-color Corner dot color \u2014 hex or JSON gradient ${DIM2}(default: matches --fg)${RESET2}
|
|
505
582
|
--logo Logo URL for center image
|
|
506
583
|
--margin Quiet zone margin in modules ${DIM2}(default: 0)${RESET2}
|
|
507
584
|
--size Output pixel size for SVG/PNG ${DIM2}(default: 512)${RESET2}
|
|
585
|
+
--template Decorative template wrapper:
|
|
586
|
+
${DIM2}Arrow, StandardBox, SquareBorder, StrikedBox, Halloween${RESET2}
|
|
587
|
+
|
|
588
|
+
${BOLD}Gradient Colors:${RESET2}
|
|
589
|
+
Pass a JSON object to --fg / --bg / --eye-color / --dot-color for gradients:
|
|
590
|
+
${DIM2}Linear: '{"type":"linear","stops":[{"color":"#f00","offset":0},{"color":"#00f","offset":100}],"angle":45}'${RESET2}
|
|
591
|
+
${DIM2}Radial: '{"type":"radial","stops":[{"color":"#f00","offset":0},{"color":"#00f","offset":100}]}'${RESET2}
|
|
508
592
|
|
|
509
593
|
${BOLD}Global Options:${RESET2}
|
|
510
594
|
--help, -h Show this help message
|
|
@@ -516,7 +600,10 @@ ${BOLD}Examples:${RESET2}
|
|
|
516
600
|
${DIM2}$${RESET2} qrdx generate "https://qrdx.dev" -o qr.svg
|
|
517
601
|
${DIM2}$${RESET2} qrdx generate "https://qrdx.dev" -o qr.png --body circle --eye gear --dot star
|
|
518
602
|
${DIM2}$${RESET2} qrdx generate "https://qrdx.dev" --fg "#ff0000" --bg "#ffffff" --size 1024
|
|
519
|
-
${DIM2}$${RESET2} qrdx generate "https://qrdx.dev" --logo "https://qrdx.dev/logo.png" -o branded.svg
|
|
603
|
+
${DIM2}$${RESET2} qrdx generate "https://qrdx.dev" --logo "https://qrdx.dev/logo.png" --level H -o branded.svg
|
|
604
|
+
${DIM2}$${RESET2} qrdx generate "https://qrdx.dev" --template Arrow -o arrow.svg
|
|
605
|
+
${DIM2}$${RESET2} qrdx generate "https://qrdx.dev" --template Halloween --body circle --eye gear -o halloween.svg
|
|
606
|
+
${DIM2}$${RESET2} qrdx generate "https://qrdx.dev" --fg '{"type":"linear","stops":[{"color":"#6366f1","offset":0},{"color":"#ec4899","offset":100}],"angle":135}' -o gradient.svg
|
|
520
607
|
|
|
521
608
|
Visit ${TEXT2}https://qrdx.dev${RESET2} for more.
|
|
522
609
|
`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qrdx/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "QR code generator CLI for developers",
|
|
5
5
|
"bin": {
|
|
6
6
|
"qrdx": "./dist/index.js"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"react": "^19.0.0",
|
|
16
16
|
"react-dom": "^19.0.0",
|
|
17
17
|
"sharp": "^0.34.2",
|
|
18
|
-
"qrdx": "0.0.
|
|
18
|
+
"qrdx": "0.0.46"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "^25.1.0",
|