@macrulez/devtoolz 0.2.1 → 0.3.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/README.md +97 -8
- package/dist/cli.js +185 -9
- package/dist/cli.js.map +1 -1
- package/dist/commands/case-check/report.js +8 -6
- package/dist/commands/case-check/report.js.map +1 -1
- package/dist/commands/circular-imports/report.js +11 -12
- package/dist/commands/circular-imports/report.js.map +1 -1
- package/dist/commands/console-strip/report.js +9 -7
- package/dist/commands/console-strip/report.js.map +1 -1
- package/dist/commands/dead-exports/report.js +6 -4
- package/dist/commands/dead-exports/report.js.map +1 -1
- package/dist/commands/empty-catch/report.js +5 -3
- package/dist/commands/empty-catch/report.js.map +1 -1
- package/dist/commands/exports-doctor/report.js +7 -5
- package/dist/commands/exports-doctor/report.js.map +1 -1
- package/dist/commands/full-check/report.js +24 -30
- package/dist/commands/full-check/report.js.map +1 -1
- package/dist/commands/image-hash/cache.d.ts +14 -0
- package/dist/commands/image-hash/cache.js +40 -0
- package/dist/commands/image-hash/cache.js.map +1 -0
- package/dist/commands/image-hash/core.d.ts +56 -0
- package/dist/commands/image-hash/core.js +293 -0
- package/dist/commands/image-hash/core.js.map +1 -0
- package/dist/commands/image-hash/hash.d.ts +19 -0
- package/dist/commands/image-hash/hash.js +97 -0
- package/dist/commands/image-hash/hash.js.map +1 -0
- package/dist/commands/image-hash/report.d.ts +3 -0
- package/dist/commands/image-hash/report.js +94 -0
- package/dist/commands/image-hash/report.js.map +1 -0
- package/dist/commands/image-hash/run.d.ts +60 -0
- package/dist/commands/image-hash/run.js +315 -0
- package/dist/commands/image-hash/run.js.map +1 -0
- package/dist/commands/image-hash/sharp-loader.d.ts +59 -0
- package/dist/commands/image-hash/sharp-loader.js +79 -0
- package/dist/commands/image-hash/sharp-loader.js.map +1 -0
- package/dist/commands/orphan-tests/report.js +7 -5
- package/dist/commands/orphan-tests/report.js.map +1 -1
- package/dist/commands/readme-check/report.js +7 -5
- package/dist/commands/readme-check/report.js.map +1 -1
- package/dist/commands/scripts-check/report.js +7 -5
- package/dist/commands/scripts-check/report.js.map +1 -1
- package/dist/commands/stale-ts-ignore/report.js +7 -5
- package/dist/commands/stale-ts-ignore/report.js.map +1 -1
- package/dist/commands/strip-comments/report.js +6 -4
- package/dist/commands/strip-comments/report.js.map +1 -1
- package/dist/commands/todo-report/report.js +7 -5
- package/dist/commands/todo-report/report.js.map +1 -1
- package/dist/commands/unused-deps/report.js +7 -5
- package/dist/commands/unused-deps/report.js.map +1 -1
- package/dist/format/colors.d.ts +4 -0
- package/dist/format/colors.js +4 -3
- package/dist/format/colors.js.map +1 -1
- package/dist/format/diff-render.js +2 -2
- package/dist/format/diff-render.js.map +1 -1
- package/dist/format/file-list.d.ts +1 -9
- package/dist/format/file-list.js +5 -16
- package/dist/format/file-list.js.map +1 -1
- package/dist/format/findings-list.d.ts +1 -8
- package/dist/format/findings-list.js +5 -14
- package/dist/format/findings-list.js.map +1 -1
- package/dist/format/style.d.ts +20 -0
- package/dist/format/style.js +36 -0
- package/dist/format/style.js.map +1 -0
- package/dist/format/table.d.ts +8 -0
- package/dist/format/table.js +44 -0
- package/dist/format/table.js.map +1 -0
- package/dist/format/vibes.d.ts +4 -1
- package/dist/format/vibes.js +25 -10
- package/dist/format/vibes.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/walk.d.ts +2 -0
- package/dist/utils/walk.js +4 -3
- package/dist/utils/walk.js.map +1 -1
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -127,7 +127,24 @@ looking for is never touched.
|
|
|
127
127
|
`.vue` files get an isolated per-file check (same technique as
|
|
128
128
|
`readme-check`'s own virtual-file typechecking) — a plain
|
|
129
129
|
`ts.Program` can't include `.vue` in a whole-project run at all.
|
|
130
|
-
- **`
|
|
130
|
+
- **`image-hash`** — generates [blurhash](https://blurha.sh) and/or
|
|
131
|
+
[thumbhash](https://evanw.github.io/thumbhash/) placeholders for raster
|
|
132
|
+
images (jpg, png, webp, gif, avif, tiff). Takes files and/or
|
|
133
|
+
directories — several of each, comma-separated too — and `-r` walks
|
|
134
|
+
subdirectories. Prints to stdout by default; `-o <file>` collects
|
|
135
|
+
everything into one file, `--per-file` / `--out-dir <dir>` writes a
|
|
136
|
+
file per image (`photo.jpg` → `photo.jpg.blurhash.txt`, with
|
|
137
|
+
`--suffix` and `--out-ext` to rename). Formats: `json`, `plain` (just
|
|
138
|
+
the hash text, no newline), `csv`, and `ts`/`js` modules you can import
|
|
139
|
+
straight into the app. Besides the two hashes it can produce the
|
|
140
|
+
dominant color and a tiny PNG preview (`-t all`), accepts `http(s)`
|
|
141
|
+
URLs and path lists from a file or stdin, and can keep an output file in
|
|
142
|
+
sync: `--cache` skips unchanged images, `--update --prune` merges into
|
|
143
|
+
the existing file, `--check` fails with exit code 1 when it is stale
|
|
144
|
+
(made for CI). `--dry-run` writes nothing and shows the result as a
|
|
145
|
+
table instead. Uses the native `sharp` library, which devtoolz
|
|
146
|
+
offers to install on first use — see Requirements.
|
|
147
|
+
- **`full-check`** — runs all thirteen other commands in one sweep, each in
|
|
131
148
|
its own safe read-only mode — the three that can write to disk
|
|
132
149
|
(`strip-comments`/`console-strip`/`case-check`) are always called as a
|
|
133
150
|
preview, `-y`/`--fix` are never passed. One summary table: which
|
|
@@ -145,22 +162,42 @@ only previews, `-y`/`--yes` is required to actually write anything,
|
|
|
145
162
|
`unused-deps`, `circular-imports`, `exports-doctor`, `readme-check`,
|
|
146
163
|
`empty-catch`, `todo-report`, `scripts-check`, `orphan-tests`,
|
|
147
164
|
`stale-ts-ignore`, and `full-check` are all read-only — none of them ever
|
|
148
|
-
write anything, there's nothing to preview or apply.
|
|
149
|
-
|
|
165
|
+
write anything, there's nothing to preview or apply. `image-hash` writes
|
|
166
|
+
files only when you name an output (`-o`, `--per-file`, `--out-dir`) and
|
|
167
|
+
prints to stdout otherwise. Every command supports `--json` for
|
|
168
|
+
machine-readable output.
|
|
150
169
|
|
|
151
170
|
## Tone
|
|
152
171
|
|
|
153
172
|
Not dead silent, not relentlessly jokey either — a small banner and some
|
|
154
173
|
personality when everything comes back clean, nothing cute mixed into the
|
|
155
|
-
actual findings list, which stays in aligned
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
174
|
+
actual findings list, which stays in aligned columns for quick scanning.
|
|
175
|
+
|
|
176
|
+
Output is colored with one palette across every command: file paths in
|
|
177
|
+
cyan with their `:line:column` dimmed, names and kinds in yellow, the
|
|
178
|
+
"N problems found" heading in bold red, what a command would do in bold
|
|
179
|
+
yellow and what it did in bold green, hints dimmed with the flags they
|
|
180
|
+
mention (`-y`, `--dry-run`) picked out in cyan, `✔`/`✖` in the
|
|
181
|
+
`full-check` table in green/red, and the diffs red/green as before.
|
|
182
|
+
|
|
183
|
+
Color turns itself off the moment output isn't a real interactive
|
|
184
|
+
terminal — piped, `CI` set, `NO_COLOR` set, `TERM=dumb`. `--color` (or
|
|
185
|
+
`FORCE_COLOR=1`) turns it back on anyway, which is what you want for
|
|
186
|
+
`devtoolz … --color | less -R` or a CI log that renders ANSI; `--plain`
|
|
187
|
+
turns color, the banner and the celebration copy all off, and `--quiet`
|
|
188
|
+
only drops the banner and clean-run output. The text is identical with
|
|
189
|
+
and without color — only escape codes are added.
|
|
160
190
|
|
|
161
191
|
## Requirements
|
|
162
192
|
|
|
163
193
|
- Node.js 20+
|
|
194
|
+
- `image-hash` only: the [`sharp`](https://sharp.pixelplumbing.com)
|
|
195
|
+
image library. It ships prebuilt binaries for the common platforms and
|
|
196
|
+
is not installed with devtoolz — the first `image-hash` run offers to
|
|
197
|
+
install it into `~/.devtoolz/deps` (`-y` / `--yes` agrees up front, which
|
|
198
|
+
is also what you want in CI; without a terminal and without `--yes` the
|
|
199
|
+
command stops and says so). A `sharp` you already have installed
|
|
200
|
+
alongside devtoolz is used as-is.
|
|
164
201
|
|
|
165
202
|
## Installation
|
|
166
203
|
|
|
@@ -210,6 +247,14 @@ devtoolz orphan-tests src # test files whose source disappe
|
|
|
210
247
|
|
|
211
248
|
devtoolz stale-ts-ignore # find @ts-ignore comments suppressing nothing
|
|
212
249
|
|
|
250
|
+
devtoolz image-hash public/img # blurhash + thumbhash of every image, as JSON on stdout
|
|
251
|
+
devtoolz image-hash a.jpg,b.png,photos -r -t blurhash -f csv -o hashes.csv
|
|
252
|
+
devtoolz image-hash public/img -r -f plain --per-file # photo.jpg.blurhash.txt + photo.jpg.thumbhash.txt
|
|
253
|
+
devtoolz image-hash public/img -r -f ts -t thumbhash -o src/placeholders.ts --name placeholders
|
|
254
|
+
devtoolz image-hash public/img -r --dry-run # write nothing, show a table of the hashes
|
|
255
|
+
devtoolz image-hash public/img -r -t all --components auto -o hashes.json --cache --update --prune
|
|
256
|
+
devtoolz image-hash public/img -r -o hashes.json --check # CI: exit 1 if hashes.json is stale
|
|
257
|
+
|
|
213
258
|
devtoolz full-check # run every command, one summary table
|
|
214
259
|
devtoolz full-check --skip stale-ts-ignore # same, minus the expensive one
|
|
215
260
|
```
|
|
@@ -416,6 +461,50 @@ problems scattered across it:
|
|
|
416
461
|
9 clean, 4 found something — see `devtoolz <command> --help` for full detail on any of them.
|
|
417
462
|
```
|
|
418
463
|
|
|
464
|
+
`devtoolz image-hash public/img -r -f plain --per-file` writing a text file
|
|
465
|
+
per hash next to each image:
|
|
466
|
+
|
|
467
|
+
```
|
|
468
|
+
🧰 devtoolz
|
|
469
|
+
|
|
470
|
+
Hashed 2 images.
|
|
471
|
+
|
|
472
|
+
Wrote 4 files:
|
|
473
|
+
public/img/hero.jpg.blurhash.txt
|
|
474
|
+
public/img/hero.jpg.thumbhash.txt
|
|
475
|
+
public/img/logo.png.blurhash.txt
|
|
476
|
+
public/img/logo.png.thumbhash.txt
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
`devtoolz image-hash hero.jpg -t blurhash` printing JSON to stdout, ready to
|
|
480
|
+
pipe or paste:
|
|
481
|
+
|
|
482
|
+
```json
|
|
483
|
+
{
|
|
484
|
+
"hero.jpg": {
|
|
485
|
+
"width": 1600,
|
|
486
|
+
"height": 900,
|
|
487
|
+
"blurhash": "LEHV6nWB2yk8pyo0adR*.7kCMdnj"
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
`devtoolz image-hash public/img -r -t blurhash --dry-run` shows what would be
|
|
493
|
+
generated as a table and writes nothing:
|
|
494
|
+
|
|
495
|
+
```
|
|
496
|
+
┌─────────────────────┬─────────┬──────────────────────────────┐
|
|
497
|
+
│ File │ Size │ BlurHash │
|
|
498
|
+
├─────────────────────┼─────────┼──────────────────────────────┤
|
|
499
|
+
│ public/img/blue.png │ 120×300 │ L704c9gSfQgSf:fRfQfRfQfQfQfQ │
|
|
500
|
+
│ public/img/red.jpg │ 200×100 │ L6T9R{,YfQ,Y|cjtfQjtfQfQfQfQ │
|
|
501
|
+
└─────────────────────┴─────────┴──────────────────────────────┘
|
|
502
|
+
|
|
503
|
+
Hashed 2 images.
|
|
504
|
+
|
|
505
|
+
(dry run — nothing written)
|
|
506
|
+
```
|
|
507
|
+
|
|
419
508
|
## Development
|
|
420
509
|
|
|
421
510
|
```bash
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
3
4
|
import { resolve } from 'node:path';
|
|
4
5
|
import { createInterface } from 'node:readline/promises';
|
|
5
6
|
import { runStripComments } from './commands/strip-comments/run.js';
|
|
@@ -31,6 +32,10 @@ import { runStaleTsIgnore } from './commands/stale-ts-ignore/run.js';
|
|
|
31
32
|
import { renderStaleTsIgnoreReport } from './commands/stale-ts-ignore/report.js';
|
|
32
33
|
import { runFullCheck, FULL_CHECK_COMMAND_NAMES, SLOW_FULL_CHECK_COMMAND, } from './commands/full-check/run.js';
|
|
33
34
|
import { renderFullCheckReport } from './commands/full-check/report.js';
|
|
35
|
+
import { runImageHash } from './commands/image-hash/run.js';
|
|
36
|
+
import { renderImageHashReport } from './commands/image-hash/report.js';
|
|
37
|
+
import { DEFAULT_CACHE_FILE, DEFAULT_IMAGE_EXTENSIONS, ImageHashUsageError, OUTPUT_FORMATS, parseComponents, parseExtensions, parseFileList, parseFormat, parseMaxPixels, parseSampleSize, parseTypes, } from './commands/image-hash/core.js';
|
|
38
|
+
import { createStyle } from './format/style.js';
|
|
34
39
|
function wrapText(text, width) {
|
|
35
40
|
const words = text.split(' ');
|
|
36
41
|
const lines = [];
|
|
@@ -156,6 +161,7 @@ program
|
|
|
156
161
|
.option('--json', 'machine-readable output', false)
|
|
157
162
|
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
158
163
|
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
164
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
159
165
|
.action((paths, options) => {
|
|
160
166
|
const report = runStripComments({
|
|
161
167
|
paths,
|
|
@@ -175,6 +181,7 @@ program
|
|
|
175
181
|
const text = renderStripCommentsReport(report, {
|
|
176
182
|
quiet: options.quiet,
|
|
177
183
|
plain: options.plain,
|
|
184
|
+
color: options.color,
|
|
178
185
|
dryRun: options.dryRun,
|
|
179
186
|
});
|
|
180
187
|
if (text)
|
|
@@ -198,6 +205,7 @@ program
|
|
|
198
205
|
.option('--json', 'machine-readable output', false)
|
|
199
206
|
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
200
207
|
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
208
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
201
209
|
.action((paths, options) => {
|
|
202
210
|
const report = runConsoleStrip({
|
|
203
211
|
paths,
|
|
@@ -218,6 +226,7 @@ program
|
|
|
218
226
|
const text = renderConsoleStripReport(report, {
|
|
219
227
|
quiet: options.quiet,
|
|
220
228
|
plain: options.plain,
|
|
229
|
+
color: options.color,
|
|
221
230
|
});
|
|
222
231
|
if (text)
|
|
223
232
|
console.log(text);
|
|
@@ -238,6 +247,7 @@ program
|
|
|
238
247
|
.option('--json', 'machine-readable output', false)
|
|
239
248
|
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
240
249
|
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
250
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
241
251
|
.action((paths, options) => {
|
|
242
252
|
const report = runDeadExports({
|
|
243
253
|
paths,
|
|
@@ -253,7 +263,11 @@ program
|
|
|
253
263
|
console.log(JSON.stringify(report, null, 2));
|
|
254
264
|
}
|
|
255
265
|
else {
|
|
256
|
-
const text = renderDeadExportsReport(report, {
|
|
266
|
+
const text = renderDeadExportsReport(report, {
|
|
267
|
+
quiet: options.quiet,
|
|
268
|
+
plain: options.plain,
|
|
269
|
+
color: options.color,
|
|
270
|
+
});
|
|
257
271
|
if (text)
|
|
258
272
|
console.log(text);
|
|
259
273
|
}
|
|
@@ -271,6 +285,7 @@ program
|
|
|
271
285
|
.option('--json', 'machine-readable output', false)
|
|
272
286
|
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
273
287
|
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
288
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
274
289
|
.action((paths, options) => {
|
|
275
290
|
const report = runCircularImports({
|
|
276
291
|
paths,
|
|
@@ -287,6 +302,7 @@ program
|
|
|
287
302
|
const text = renderCircularImportsReport(report, {
|
|
288
303
|
quiet: options.quiet,
|
|
289
304
|
plain: options.plain,
|
|
305
|
+
color: options.color,
|
|
290
306
|
});
|
|
291
307
|
if (text)
|
|
292
308
|
console.log(text);
|
|
@@ -305,6 +321,7 @@ program
|
|
|
305
321
|
.option('--json', 'machine-readable output', false)
|
|
306
322
|
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
307
323
|
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
324
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
308
325
|
.action((dir, options) => {
|
|
309
326
|
const report = runUnusedDeps({
|
|
310
327
|
dir: resolve(dir),
|
|
@@ -318,7 +335,11 @@ program
|
|
|
318
335
|
console.log(JSON.stringify(report, null, 2));
|
|
319
336
|
}
|
|
320
337
|
else {
|
|
321
|
-
const text = renderUnusedDepsReport(report, {
|
|
338
|
+
const text = renderUnusedDepsReport(report, {
|
|
339
|
+
quiet: options.quiet,
|
|
340
|
+
plain: options.plain,
|
|
341
|
+
color: options.color,
|
|
342
|
+
});
|
|
322
343
|
if (text)
|
|
323
344
|
console.log(text);
|
|
324
345
|
}
|
|
@@ -340,6 +361,7 @@ program
|
|
|
340
361
|
.option('--json', 'machine-readable output', false)
|
|
341
362
|
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
342
363
|
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
364
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
343
365
|
.action((paths, options) => {
|
|
344
366
|
const report = runCaseCheck({
|
|
345
367
|
paths,
|
|
@@ -357,7 +379,11 @@ program
|
|
|
357
379
|
console.log(JSON.stringify(report, null, 2));
|
|
358
380
|
}
|
|
359
381
|
else {
|
|
360
|
-
const text = renderCaseCheckReport(report, {
|
|
382
|
+
const text = renderCaseCheckReport(report, {
|
|
383
|
+
quiet: options.quiet,
|
|
384
|
+
plain: options.plain,
|
|
385
|
+
color: options.color,
|
|
386
|
+
});
|
|
361
387
|
if (text)
|
|
362
388
|
console.log(text);
|
|
363
389
|
}
|
|
@@ -370,13 +396,18 @@ program
|
|
|
370
396
|
.option('--json', 'machine-readable output', false)
|
|
371
397
|
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
372
398
|
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
399
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
373
400
|
.action((dir, options) => {
|
|
374
401
|
const report = runExportsDoctor({ dir: resolve(dir) });
|
|
375
402
|
if (options.json) {
|
|
376
403
|
console.log(JSON.stringify(report, null, 2));
|
|
377
404
|
}
|
|
378
405
|
else {
|
|
379
|
-
const text = renderExportsDoctorReport(report, {
|
|
406
|
+
const text = renderExportsDoctorReport(report, {
|
|
407
|
+
quiet: options.quiet,
|
|
408
|
+
plain: options.plain,
|
|
409
|
+
color: options.color,
|
|
410
|
+
});
|
|
380
411
|
if (text)
|
|
381
412
|
console.log(text);
|
|
382
413
|
}
|
|
@@ -392,6 +423,7 @@ program
|
|
|
392
423
|
.option('--json', 'machine-readable output', false)
|
|
393
424
|
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
394
425
|
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
426
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
395
427
|
.action((dir, options) => {
|
|
396
428
|
const report = runReadmeCheck({
|
|
397
429
|
dir: resolve(dir),
|
|
@@ -403,7 +435,11 @@ program
|
|
|
403
435
|
console.log(JSON.stringify(report, null, 2));
|
|
404
436
|
}
|
|
405
437
|
else {
|
|
406
|
-
const text = renderReadmeCheckReport(report, {
|
|
438
|
+
const text = renderReadmeCheckReport(report, {
|
|
439
|
+
quiet: options.quiet,
|
|
440
|
+
plain: options.plain,
|
|
441
|
+
color: options.color,
|
|
442
|
+
});
|
|
407
443
|
if (text)
|
|
408
444
|
console.log(text);
|
|
409
445
|
}
|
|
@@ -420,6 +456,7 @@ program
|
|
|
420
456
|
.option('--json', 'machine-readable output', false)
|
|
421
457
|
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
422
458
|
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
459
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
423
460
|
.action((paths, options) => {
|
|
424
461
|
const report = runEmptyCatch({
|
|
425
462
|
paths,
|
|
@@ -432,7 +469,11 @@ program
|
|
|
432
469
|
console.log(JSON.stringify(report, null, 2));
|
|
433
470
|
}
|
|
434
471
|
else {
|
|
435
|
-
const text = renderEmptyCatchReport(report, {
|
|
472
|
+
const text = renderEmptyCatchReport(report, {
|
|
473
|
+
quiet: options.quiet,
|
|
474
|
+
plain: options.plain,
|
|
475
|
+
color: options.color,
|
|
476
|
+
});
|
|
436
477
|
if (text)
|
|
437
478
|
console.log(text);
|
|
438
479
|
}
|
|
@@ -451,6 +492,7 @@ program
|
|
|
451
492
|
.option('--json', 'machine-readable output', false)
|
|
452
493
|
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
453
494
|
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
495
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
454
496
|
.action((paths, options) => {
|
|
455
497
|
const report = runTodoReport({
|
|
456
498
|
paths,
|
|
@@ -465,7 +507,11 @@ program
|
|
|
465
507
|
console.log(JSON.stringify(report, null, 2));
|
|
466
508
|
}
|
|
467
509
|
else {
|
|
468
|
-
const text = renderTodoReportReport(report, {
|
|
510
|
+
const text = renderTodoReportReport(report, {
|
|
511
|
+
quiet: options.quiet,
|
|
512
|
+
plain: options.plain,
|
|
513
|
+
color: options.color,
|
|
514
|
+
});
|
|
469
515
|
if (text)
|
|
470
516
|
console.log(text);
|
|
471
517
|
}
|
|
@@ -479,6 +525,7 @@ program
|
|
|
479
525
|
.option('--json', 'machine-readable output', false)
|
|
480
526
|
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
481
527
|
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
528
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
482
529
|
.action((dir, options) => {
|
|
483
530
|
const report = runScriptsCheck({ dir: resolve(dir), files: options.file });
|
|
484
531
|
if (options.json) {
|
|
@@ -488,6 +535,7 @@ program
|
|
|
488
535
|
const text = renderScriptsCheckReport(report, {
|
|
489
536
|
quiet: options.quiet,
|
|
490
537
|
plain: options.plain,
|
|
538
|
+
color: options.color,
|
|
491
539
|
});
|
|
492
540
|
if (text)
|
|
493
541
|
console.log(text);
|
|
@@ -509,6 +557,7 @@ program
|
|
|
509
557
|
.option('--json', 'machine-readable output', false)
|
|
510
558
|
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
511
559
|
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
560
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
512
561
|
.action((paths, options) => {
|
|
513
562
|
const report = runOrphanTests({
|
|
514
563
|
paths,
|
|
@@ -525,7 +574,11 @@ program
|
|
|
525
574
|
console.log(JSON.stringify(report, null, 2));
|
|
526
575
|
}
|
|
527
576
|
else {
|
|
528
|
-
const text = renderOrphanTestsReport(report, {
|
|
577
|
+
const text = renderOrphanTestsReport(report, {
|
|
578
|
+
quiet: options.quiet,
|
|
579
|
+
plain: options.plain,
|
|
580
|
+
color: options.color,
|
|
581
|
+
});
|
|
529
582
|
if (text)
|
|
530
583
|
console.log(text);
|
|
531
584
|
}
|
|
@@ -541,6 +594,7 @@ program
|
|
|
541
594
|
.option('--json', 'machine-readable output', false)
|
|
542
595
|
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
543
596
|
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
597
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
544
598
|
.action((dir, options) => {
|
|
545
599
|
const report = runStaleTsIgnore({
|
|
546
600
|
dir: resolve(dir),
|
|
@@ -556,12 +610,129 @@ program
|
|
|
556
610
|
const text = renderStaleTsIgnoreReport(report, {
|
|
557
611
|
quiet: options.quiet,
|
|
558
612
|
plain: options.plain,
|
|
613
|
+
color: options.color,
|
|
559
614
|
});
|
|
560
615
|
if (text)
|
|
561
616
|
console.log(text);
|
|
562
617
|
}
|
|
563
618
|
process.exitCode = report.exitCode;
|
|
564
619
|
});
|
|
620
|
+
program
|
|
621
|
+
.command('image-hash')
|
|
622
|
+
.description('Generate blurhash/thumbhash placeholders (and dominant color, tiny preview) for raster images — to stdout, one file, or a file per image')
|
|
623
|
+
.argument('[paths...]', 'image files, directories and http(s) URLs (several allowed, comma-separated too)', [])
|
|
624
|
+
.option('--cwd <path>', 'root paths are resolved against', process.cwd())
|
|
625
|
+
.option('-r, --recursive', 'also walk subdirectories of every given directory', false)
|
|
626
|
+
.option('--files-from <file>', 'read more paths/URLs from a file, one per line (- = stdin, # starts a comment)')
|
|
627
|
+
.option('--ext <list>', 'comma-separated image extensions to pick up from directories', DEFAULT_IMAGE_EXTENSIONS.join(','))
|
|
628
|
+
.option('--ignore <glob>', 'extra ignore pattern (repeatable), on top of the built-in defaults', (val, prev) => [...prev, val], [])
|
|
629
|
+
.option('--no-respect-gitignore', "don't also honor the project's .gitignore")
|
|
630
|
+
.option('-t, --type <list>', 'what to generate, comma-separated: blurhash, thumbhash, color (dominant), preview (tiny PNG data URI); both = blurhash+thumbhash, all = everything', 'both')
|
|
631
|
+
.option('--components <XxY|auto>', 'blurhash components, each side 1-9, or auto to pick them by aspect ratio', '4x3')
|
|
632
|
+
.option('--size <px>', 'longest side the image is scaled down to before hashing (1-100)', '100')
|
|
633
|
+
.option('--max-pixels <n>', 'refuse images with more pixels than this (0 = no limit; default: sharp limit, ~268 million)')
|
|
634
|
+
.option('-f, --format <format>', `format of the generated hashes: ${OUTPUT_FORMATS.join(', ')} (plain = just the hash text); --json prints the full report instead`, 'json')
|
|
635
|
+
.option('--name <identifier>', 'exported constant name for --format ts/js', 'imageHashes')
|
|
636
|
+
.option('--key-base <dir>', 'make the file keys in the output relative to this directory')
|
|
637
|
+
.option('--key-prefix <text>', 'text put in front of every file key, e.g. / for URL-style keys')
|
|
638
|
+
.option('-o, --out <file>', 'write everything into one file instead of stdout')
|
|
639
|
+
.option('--update', 'merge into the existing -o file instead of replacing it', false)
|
|
640
|
+
.option('--prune', 'with --update, drop entries whose image no longer exists', false)
|
|
641
|
+
.option('--per-file', 'write one file per image, next to the image', false)
|
|
642
|
+
.option('--out-dir <dir>', 'write the per-image files into this directory (implies --per-file)')
|
|
643
|
+
.option('--suffix <text>', 'per-image file name suffix after the image file name, {type} = blurhash/thumbhash/hash (default: .{type})')
|
|
644
|
+
.option('--out-ext <ext>', 'per-image file extension (default: by --format, plain = .txt)')
|
|
645
|
+
.option('--check', 'write nothing; exit 1 if the output files are missing or differ from the images', false)
|
|
646
|
+
.option('--cache [file]', `skip images that did not change since the last run, remembered in this file (default: ${DEFAULT_CACHE_FILE})`)
|
|
647
|
+
.option('--concurrency <n>', 'images processed in parallel', '4')
|
|
648
|
+
.option('--dry-run', 'write nothing — show the result as a table instead', false)
|
|
649
|
+
.option('-y, --yes', 'install the missing "sharp" image library without asking', false)
|
|
650
|
+
.option('--json', 'machine-readable output', false)
|
|
651
|
+
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
652
|
+
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
653
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
654
|
+
.action(async (paths, options) => {
|
|
655
|
+
const style = createStyle({ plain: options.plain, color: options.color });
|
|
656
|
+
const showProgress = !options.json && !options.quiet && Boolean(process.stderr.isTTY) && !options.plain;
|
|
657
|
+
let progressShown = false;
|
|
658
|
+
try {
|
|
659
|
+
const listed = options.filesFrom !== undefined
|
|
660
|
+
? parseFileList(readFileSync(options.filesFrom === '-' ? 0 : options.filesFrom, 'utf8'))
|
|
661
|
+
: [];
|
|
662
|
+
const report = await runImageHash({
|
|
663
|
+
paths: [...paths, ...listed],
|
|
664
|
+
cwd: resolve(options.cwd),
|
|
665
|
+
types: parseTypes(options.type),
|
|
666
|
+
recursive: options.recursive,
|
|
667
|
+
extensions: parseExtensions(options.ext),
|
|
668
|
+
ignoreGlobs: options.ignore,
|
|
669
|
+
respectGitignore: options.respectGitignore,
|
|
670
|
+
components: parseComponents(options.components),
|
|
671
|
+
size: parseSampleSize(options.size),
|
|
672
|
+
...(options.maxPixels !== undefined
|
|
673
|
+
? { maxPixels: parseMaxPixels(options.maxPixels) }
|
|
674
|
+
: {}),
|
|
675
|
+
format: parseFormat(options.format),
|
|
676
|
+
exportName: options.name,
|
|
677
|
+
...(options.keyBase !== undefined ? { keyBase: options.keyBase } : {}),
|
|
678
|
+
...(options.keyPrefix !== undefined ? { keyPrefix: options.keyPrefix } : {}),
|
|
679
|
+
...(options.out !== undefined ? { out: options.out } : {}),
|
|
680
|
+
update: options.update,
|
|
681
|
+
prune: options.prune,
|
|
682
|
+
perFile: options.perFile,
|
|
683
|
+
...(options.outDir !== undefined ? { outDir: options.outDir } : {}),
|
|
684
|
+
...(options.suffix !== undefined ? { suffix: options.suffix } : {}),
|
|
685
|
+
...(options.outExt !== undefined ? { outExtension: options.outExt } : {}),
|
|
686
|
+
check: options.check,
|
|
687
|
+
...(options.cache !== undefined
|
|
688
|
+
? { cache: options.cache === true ? DEFAULT_CACHE_FILE : String(options.cache) }
|
|
689
|
+
: {}),
|
|
690
|
+
concurrency: Math.max(1, Number.parseInt(options.concurrency, 10) || 4),
|
|
691
|
+
assumeYes: options.yes,
|
|
692
|
+
dryRun: options.dryRun,
|
|
693
|
+
...(showProgress
|
|
694
|
+
? {
|
|
695
|
+
onProgress: ({ done, total }) => {
|
|
696
|
+
if (total < 2)
|
|
697
|
+
return;
|
|
698
|
+
progressShown = true;
|
|
699
|
+
process.stderr.write(`\r${style.info(`Hashing ${done}/${total}`)}`);
|
|
700
|
+
},
|
|
701
|
+
}
|
|
702
|
+
: {}),
|
|
703
|
+
});
|
|
704
|
+
if (progressShown)
|
|
705
|
+
process.stderr.write('\r\x1b[K');
|
|
706
|
+
if (options.json) {
|
|
707
|
+
console.log(JSON.stringify(report, null, 2));
|
|
708
|
+
}
|
|
709
|
+
else if (report.stdout !== null) {
|
|
710
|
+
process.stdout.write(report.stdout);
|
|
711
|
+
for (const error of report.errors)
|
|
712
|
+
console.error(`${error.file} — ${error.message}`);
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
const text = renderImageHashReport(report, {
|
|
716
|
+
quiet: options.quiet,
|
|
717
|
+
plain: options.plain,
|
|
718
|
+
color: options.color,
|
|
719
|
+
});
|
|
720
|
+
if (text)
|
|
721
|
+
console.log(text);
|
|
722
|
+
}
|
|
723
|
+
process.exitCode = report.exitCode;
|
|
724
|
+
}
|
|
725
|
+
catch (error) {
|
|
726
|
+
if (progressShown)
|
|
727
|
+
process.stderr.write('\r\x1b[K');
|
|
728
|
+
if (error instanceof ImageHashUsageError) {
|
|
729
|
+
console.error(`error: ${error.message}`);
|
|
730
|
+
process.exitCode = 2;
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
throw error;
|
|
734
|
+
}
|
|
735
|
+
});
|
|
565
736
|
// Only `full-check` ever prompts — every other command here is a single,
|
|
566
737
|
// fast, non-interactive check. `stale-ts-ignore` is the one command a
|
|
567
738
|
// bare `full-check` can turn into a genuinely slow run, so this asks
|
|
@@ -606,6 +777,7 @@ program
|
|
|
606
777
|
.option('--json', 'machine-readable output', false)
|
|
607
778
|
.option('--quiet', 'suppress output when there is nothing to report', false)
|
|
608
779
|
.option('--plain', 'disable color/banner/celebration copy, even in a real terminal', false)
|
|
780
|
+
.option('--color', 'force colored output even when piped or in CI', false)
|
|
609
781
|
.action(async (dir, options) => {
|
|
610
782
|
const skip = new Set(options.skip);
|
|
611
783
|
const shouldPrompt = options.prompt &&
|
|
@@ -634,7 +806,11 @@ program
|
|
|
634
806
|
console.log(JSON.stringify(report, null, 2));
|
|
635
807
|
}
|
|
636
808
|
else {
|
|
637
|
-
const text = renderFullCheckReport(report, {
|
|
809
|
+
const text = renderFullCheckReport(report, {
|
|
810
|
+
quiet: options.quiet,
|
|
811
|
+
plain: options.plain,
|
|
812
|
+
color: options.color,
|
|
813
|
+
});
|
|
638
814
|
if (text)
|
|
639
815
|
console.log(text);
|
|
640
816
|
}
|