@macrulez/devtoolz 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { ALL_TYPES } from './core.js';
|
|
4
|
+
export function emptyCache() {
|
|
5
|
+
return { version: 1, files: {} };
|
|
6
|
+
}
|
|
7
|
+
export function loadCache(path) {
|
|
8
|
+
if (!existsSync(path))
|
|
9
|
+
return emptyCache();
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
12
|
+
if (parsed.version !== 1 || typeof parsed.files !== 'object' || parsed.files === null) {
|
|
13
|
+
return emptyCache();
|
|
14
|
+
}
|
|
15
|
+
return parsed;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return emptyCache();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function saveCache(path, cache) {
|
|
22
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
23
|
+
writeFileSync(path, `${JSON.stringify(cache)}\n`);
|
|
24
|
+
}
|
|
25
|
+
export function cacheHit(record, sig, params, types) {
|
|
26
|
+
if (!record || record.sig !== sig || record.params !== params)
|
|
27
|
+
return null;
|
|
28
|
+
for (const type of types) {
|
|
29
|
+
if (record[type] === undefined)
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const hit = { width: record.width, height: record.height };
|
|
33
|
+
for (const type of ALL_TYPES) {
|
|
34
|
+
const value = record[type];
|
|
35
|
+
if (value !== undefined)
|
|
36
|
+
hit[type] = value;
|
|
37
|
+
}
|
|
38
|
+
return hit;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/commands/image-hash/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,SAAS,EAAiB,MAAM,WAAW,CAAA;AAapD,MAAM,UAAU,UAAU;IACxB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;AAClC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,UAAU,EAAE,CAAA;IAC1C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAc,CAAA;QAClE,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACtF,OAAO,UAAU,EAAE,CAAA;QACrB,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,UAAU,EAAE,CAAA;IACrB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,KAAgB;IACtD,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7C,aAAa,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,UAAU,QAAQ,CACtB,MAA+B,EAC/B,GAAW,EACX,MAAc,EACd,KAAiB;IAEjB,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,GAAG,KAAK,GAAG,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,IAAI,CAAA;IAC1E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,IAAI,CAAA;IAC7C,CAAC;IACD,MAAM,GAAG,GAAmB,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAA;IAC1E,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;QAC1B,IAAI,KAAK,KAAK,SAAS;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;IAC5C,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export type HashType = 'blurhash' | 'thumbhash' | 'color' | 'preview';
|
|
2
|
+
export declare const ALL_TYPES: HashType[];
|
|
3
|
+
export declare const OUTPUT_FORMATS: readonly ["json", "plain", "csv", "ts", "js"];
|
|
4
|
+
export type OutputFormat = (typeof OUTPUT_FORMATS)[number];
|
|
5
|
+
export declare const DEFAULT_IMAGE_EXTENSIONS: string[];
|
|
6
|
+
export declare const DEFAULT_EXPORT_NAME = "imageHashes";
|
|
7
|
+
export declare const DEFAULT_BLURHASH_COMPONENTS: {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
};
|
|
11
|
+
export declare const DEFAULT_SAMPLE_SIZE = 100;
|
|
12
|
+
export declare const MAX_SAMPLE_SIZE = 100;
|
|
13
|
+
export declare const DEFAULT_CACHE_FILE = ".devtoolz-image-hash-cache.json";
|
|
14
|
+
export type Components = {
|
|
15
|
+
x: number;
|
|
16
|
+
y: number;
|
|
17
|
+
} | 'auto';
|
|
18
|
+
export declare class ImageHashUsageError extends Error {
|
|
19
|
+
}
|
|
20
|
+
export interface HashEntry {
|
|
21
|
+
file: string;
|
|
22
|
+
width: number;
|
|
23
|
+
height: number;
|
|
24
|
+
blurhash?: string;
|
|
25
|
+
thumbhash?: string;
|
|
26
|
+
color?: string;
|
|
27
|
+
preview?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface OutputUnit {
|
|
30
|
+
token: string;
|
|
31
|
+
content: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function parseTypes(value: string): HashType[];
|
|
34
|
+
export declare function orderTypes(types: Iterable<HashType>): HashType[];
|
|
35
|
+
export declare function parseFormat(value: string): OutputFormat;
|
|
36
|
+
export declare function parseComponents(value: string): Components;
|
|
37
|
+
export declare function resolveComponents(components: Components, width: number, height: number): {
|
|
38
|
+
x: number;
|
|
39
|
+
y: number;
|
|
40
|
+
};
|
|
41
|
+
export declare function componentsLabel(components: Components): string;
|
|
42
|
+
export declare function parseSampleSize(value: string): number;
|
|
43
|
+
export declare function parseMaxPixels(value: string): number;
|
|
44
|
+
export declare function parseExtensions(value: string): string[];
|
|
45
|
+
export declare function withUpperCaseVariants(extensions: string[]): string[];
|
|
46
|
+
export declare function validateExportName(name: string): string;
|
|
47
|
+
export declare function isUrl(value: string): boolean;
|
|
48
|
+
export declare function splitPathArguments(args: string[], exists?: (path: string) => boolean): string[];
|
|
49
|
+
export declare function parseFileList(text: string): string[];
|
|
50
|
+
export declare function defaultOutExtension(format: OutputFormat): string;
|
|
51
|
+
export declare function normalizeOutExtension(value: string | undefined, format: OutputFormat): string;
|
|
52
|
+
export declare function validateSuffix(suffix: string | undefined, types: HashType[], format: OutputFormat): string;
|
|
53
|
+
export declare function formatAggregate(entries: HashEntry[], types: HashType[], format: OutputFormat, exportName: string): string;
|
|
54
|
+
export declare function formatPerFile(entry: HashEntry, types: HashType[], format: OutputFormat): OutputUnit[];
|
|
55
|
+
export declare function outputFileName(imagePath: string, suffix: string, token: string, extension: string): string;
|
|
56
|
+
export declare function parseAggregate(content: string, format: OutputFormat): HashEntry[];
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { basename } from 'node:path';
|
|
3
|
+
export const ALL_TYPES = ['blurhash', 'thumbhash', 'color', 'preview'];
|
|
4
|
+
export const OUTPUT_FORMATS = ['json', 'plain', 'csv', 'ts', 'js'];
|
|
5
|
+
export const DEFAULT_IMAGE_EXTENSIONS = [
|
|
6
|
+
'.jpg',
|
|
7
|
+
'.jpeg',
|
|
8
|
+
'.png',
|
|
9
|
+
'.webp',
|
|
10
|
+
'.gif',
|
|
11
|
+
'.avif',
|
|
12
|
+
'.tif',
|
|
13
|
+
'.tiff',
|
|
14
|
+
];
|
|
15
|
+
export const DEFAULT_EXPORT_NAME = 'imageHashes';
|
|
16
|
+
export const DEFAULT_BLURHASH_COMPONENTS = { x: 4, y: 3 };
|
|
17
|
+
export const DEFAULT_SAMPLE_SIZE = 100;
|
|
18
|
+
export const MAX_SAMPLE_SIZE = 100;
|
|
19
|
+
export const DEFAULT_CACHE_FILE = '.devtoolz-image-hash-cache.json';
|
|
20
|
+
export class ImageHashUsageError extends Error {
|
|
21
|
+
}
|
|
22
|
+
export function parseTypes(value) {
|
|
23
|
+
const names = value
|
|
24
|
+
.split(',')
|
|
25
|
+
.map((name) => name.trim().toLowerCase())
|
|
26
|
+
.filter(Boolean);
|
|
27
|
+
const selected = new Set();
|
|
28
|
+
for (const name of names) {
|
|
29
|
+
if (name === 'both') {
|
|
30
|
+
selected.add('blurhash');
|
|
31
|
+
selected.add('thumbhash');
|
|
32
|
+
}
|
|
33
|
+
else if (name === 'all') {
|
|
34
|
+
ALL_TYPES.forEach((type) => selected.add(type));
|
|
35
|
+
}
|
|
36
|
+
else if (ALL_TYPES.includes(name)) {
|
|
37
|
+
selected.add(name);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
throw new ImageHashUsageError(`--type takes a comma-separated list of ${ALL_TYPES.join(', ')}, or both / all (got "${value}")`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (selected.size === 0) {
|
|
44
|
+
throw new ImageHashUsageError('--type needs at least one of blurhash, thumbhash, color, preview');
|
|
45
|
+
}
|
|
46
|
+
return ALL_TYPES.filter((type) => selected.has(type));
|
|
47
|
+
}
|
|
48
|
+
export function orderTypes(types) {
|
|
49
|
+
const set = new Set(types);
|
|
50
|
+
return ALL_TYPES.filter((type) => set.has(type));
|
|
51
|
+
}
|
|
52
|
+
export function parseFormat(value) {
|
|
53
|
+
const normalized = value.trim().toLowerCase();
|
|
54
|
+
const found = OUTPUT_FORMATS.find((format) => format === normalized);
|
|
55
|
+
if (!found) {
|
|
56
|
+
throw new ImageHashUsageError(`--format must be one of ${OUTPUT_FORMATS.join(', ')} (got "${value}")`);
|
|
57
|
+
}
|
|
58
|
+
return found;
|
|
59
|
+
}
|
|
60
|
+
export function parseComponents(value) {
|
|
61
|
+
if (value.trim().toLowerCase() === 'auto')
|
|
62
|
+
return 'auto';
|
|
63
|
+
const match = /^(\d+)x(\d+)$/i.exec(value.trim());
|
|
64
|
+
const x = match ? Number(match[1]) : 0;
|
|
65
|
+
const y = match ? Number(match[2]) : 0;
|
|
66
|
+
if (!match || x < 1 || x > 9 || y < 1 || y > 9) {
|
|
67
|
+
throw new ImageHashUsageError(`--components must look like 4x3 (each side from 1 to 9) or be "auto" (got "${value}")`);
|
|
68
|
+
}
|
|
69
|
+
return { x, y };
|
|
70
|
+
}
|
|
71
|
+
export function resolveComponents(components, width, height) {
|
|
72
|
+
if (components !== 'auto')
|
|
73
|
+
return components;
|
|
74
|
+
const aspect = width >= height ? width / height : height / width;
|
|
75
|
+
const long = 4;
|
|
76
|
+
const short = Math.min(4, Math.max(2, Math.round(long / Math.sqrt(aspect))));
|
|
77
|
+
return width >= height ? { x: long, y: short } : { x: short, y: long };
|
|
78
|
+
}
|
|
79
|
+
export function componentsLabel(components) {
|
|
80
|
+
return components === 'auto' ? 'auto' : `${components.x}x${components.y}`;
|
|
81
|
+
}
|
|
82
|
+
export function parseSampleSize(value) {
|
|
83
|
+
const size = Number(value);
|
|
84
|
+
if (!Number.isInteger(size) || size < 1 || size > MAX_SAMPLE_SIZE) {
|
|
85
|
+
throw new ImageHashUsageError(`--size must be a whole number from 1 to ${MAX_SAMPLE_SIZE} (got "${value}")`);
|
|
86
|
+
}
|
|
87
|
+
return size;
|
|
88
|
+
}
|
|
89
|
+
export function parseMaxPixels(value) {
|
|
90
|
+
const pixels = Number(value);
|
|
91
|
+
if (!Number.isInteger(pixels) || pixels < 0) {
|
|
92
|
+
throw new ImageHashUsageError(`--max-pixels must be a whole number, 0 for no limit (got "${value}")`);
|
|
93
|
+
}
|
|
94
|
+
return pixels;
|
|
95
|
+
}
|
|
96
|
+
export function parseExtensions(value) {
|
|
97
|
+
return value
|
|
98
|
+
.split(',')
|
|
99
|
+
.map((ext) => ext.trim())
|
|
100
|
+
.filter(Boolean)
|
|
101
|
+
.map((ext) => (ext.startsWith('.') ? ext : `.${ext}`).toLowerCase());
|
|
102
|
+
}
|
|
103
|
+
export function withUpperCaseVariants(extensions) {
|
|
104
|
+
return [...new Set(extensions.flatMap((ext) => [ext, ext.toUpperCase()]))];
|
|
105
|
+
}
|
|
106
|
+
export function validateExportName(name) {
|
|
107
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(name)) {
|
|
108
|
+
throw new ImageHashUsageError(`--name must be a valid identifier (got "${name}")`);
|
|
109
|
+
}
|
|
110
|
+
return name;
|
|
111
|
+
}
|
|
112
|
+
export function isUrl(value) {
|
|
113
|
+
return /^https?:\/\//i.test(value);
|
|
114
|
+
}
|
|
115
|
+
export function splitPathArguments(args, exists = existsSync) {
|
|
116
|
+
const out = [];
|
|
117
|
+
for (const arg of args) {
|
|
118
|
+
if (isUrl(arg) || exists(arg) || !arg.includes(',')) {
|
|
119
|
+
out.push(arg);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
for (const part of arg.split(',')) {
|
|
123
|
+
const trimmed = part.trim();
|
|
124
|
+
if (trimmed)
|
|
125
|
+
out.push(trimmed);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
export function parseFileList(text) {
|
|
131
|
+
return text
|
|
132
|
+
.split(/\r?\n/)
|
|
133
|
+
.map((line) => line.trim())
|
|
134
|
+
.filter((line) => line !== '' && !line.startsWith('#'));
|
|
135
|
+
}
|
|
136
|
+
export function defaultOutExtension(format) {
|
|
137
|
+
return format === 'plain' ? '.txt' : `.${format}`;
|
|
138
|
+
}
|
|
139
|
+
export function normalizeOutExtension(value, format) {
|
|
140
|
+
if (value === undefined)
|
|
141
|
+
return defaultOutExtension(format);
|
|
142
|
+
const trimmed = value.trim();
|
|
143
|
+
if (trimmed === '')
|
|
144
|
+
return '';
|
|
145
|
+
return trimmed.startsWith('.') ? trimmed : `.${trimmed}`;
|
|
146
|
+
}
|
|
147
|
+
export function validateSuffix(suffix, types, format) {
|
|
148
|
+
const resolved = suffix ?? '.{type}';
|
|
149
|
+
if (format === 'plain' && types.length > 1 && !resolved.includes('{type}')) {
|
|
150
|
+
throw new ImageHashUsageError('--suffix must contain {type} when --format plain writes several hashes per image, ' +
|
|
151
|
+
'otherwise the files would overwrite each other');
|
|
152
|
+
}
|
|
153
|
+
return resolved;
|
|
154
|
+
}
|
|
155
|
+
function csvField(value) {
|
|
156
|
+
return /[",\n]/.test(value) ? `"${value.replace(/"/g, '""')}"` : value;
|
|
157
|
+
}
|
|
158
|
+
function structured(entry, types) {
|
|
159
|
+
const out = { width: entry.width, height: entry.height };
|
|
160
|
+
for (const type of types) {
|
|
161
|
+
const value = entry[type];
|
|
162
|
+
if (value !== undefined)
|
|
163
|
+
out[type] = value;
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
function csvHeader(types, withFile) {
|
|
168
|
+
return [...(withFile ? ['file'] : []), 'width', 'height', ...types].join(',');
|
|
169
|
+
}
|
|
170
|
+
function csvRow(entry, types, withFile) {
|
|
171
|
+
return [
|
|
172
|
+
...(withFile ? [csvField(entry.file)] : []),
|
|
173
|
+
String(entry.width),
|
|
174
|
+
String(entry.height),
|
|
175
|
+
...types.map((type) => csvField(entry[type] ?? '')),
|
|
176
|
+
].join(',');
|
|
177
|
+
}
|
|
178
|
+
export function formatAggregate(entries, types, format, exportName) {
|
|
179
|
+
if (format === 'csv') {
|
|
180
|
+
return [csvHeader(types, true), ...entries.map((e) => csvRow(e, types, true))].join('\n') + '\n';
|
|
181
|
+
}
|
|
182
|
+
if (format === 'plain') {
|
|
183
|
+
return (entries.map((e) => [e.file, ...types.map((type) => e[type] ?? '')].join('\t')).join('\n') +
|
|
184
|
+
(entries.length > 0 ? '\n' : ''));
|
|
185
|
+
}
|
|
186
|
+
const map = {};
|
|
187
|
+
for (const entry of entries)
|
|
188
|
+
map[entry.file] = structured(entry, types);
|
|
189
|
+
const json = JSON.stringify(map, null, 2);
|
|
190
|
+
if (format === 'json')
|
|
191
|
+
return `${json}\n`;
|
|
192
|
+
const suffix = format === 'ts' ? ' as const' : '';
|
|
193
|
+
return `export const ${exportName} = ${json}${suffix}\n`;
|
|
194
|
+
}
|
|
195
|
+
export function formatPerFile(entry, types, format) {
|
|
196
|
+
if (format === 'plain') {
|
|
197
|
+
return types.map((type) => ({ token: type, content: entry[type] ?? '' }));
|
|
198
|
+
}
|
|
199
|
+
const token = types.length > 1 ? 'hash' : types[0];
|
|
200
|
+
const object = structured(entry, types);
|
|
201
|
+
if (format === 'csv') {
|
|
202
|
+
return [{ token, content: `${csvHeader(types, false)}\n${csvRow(entry, types, false)}\n` }];
|
|
203
|
+
}
|
|
204
|
+
const json = JSON.stringify(object, null, 2);
|
|
205
|
+
if (format === 'json')
|
|
206
|
+
return [{ token, content: `${json}\n` }];
|
|
207
|
+
const suffix = format === 'ts' ? ' as const' : '';
|
|
208
|
+
return [{ token, content: `export default ${json}${suffix}\n` }];
|
|
209
|
+
}
|
|
210
|
+
export function outputFileName(imagePath, suffix, token, extension) {
|
|
211
|
+
return `${basename(imagePath)}${suffix.replace(/\{type\}/g, token)}${extension}`;
|
|
212
|
+
}
|
|
213
|
+
function parseCsvLine(line) {
|
|
214
|
+
const fields = [];
|
|
215
|
+
let current = '';
|
|
216
|
+
let quoted = false;
|
|
217
|
+
for (let i = 0; i < line.length; i++) {
|
|
218
|
+
const char = line[i];
|
|
219
|
+
if (quoted) {
|
|
220
|
+
if (char === '"' && line[i + 1] === '"') {
|
|
221
|
+
current += '"';
|
|
222
|
+
i++;
|
|
223
|
+
}
|
|
224
|
+
else if (char === '"') {
|
|
225
|
+
quoted = false;
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
current += char;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else if (char === '"') {
|
|
232
|
+
quoted = true;
|
|
233
|
+
}
|
|
234
|
+
else if (char === ',') {
|
|
235
|
+
fields.push(current);
|
|
236
|
+
current = '';
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
current += char;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
fields.push(current);
|
|
243
|
+
return fields;
|
|
244
|
+
}
|
|
245
|
+
function entryFromRecord(file, record) {
|
|
246
|
+
const entry = {
|
|
247
|
+
file,
|
|
248
|
+
width: Number(record.width) || 0,
|
|
249
|
+
height: Number(record.height) || 0,
|
|
250
|
+
};
|
|
251
|
+
for (const type of ALL_TYPES) {
|
|
252
|
+
const value = record[type];
|
|
253
|
+
if (typeof value === 'string' && value !== '')
|
|
254
|
+
entry[type] = value;
|
|
255
|
+
}
|
|
256
|
+
return entry;
|
|
257
|
+
}
|
|
258
|
+
export function parseAggregate(content, format) {
|
|
259
|
+
const fail = () => {
|
|
260
|
+
throw new ImageHashUsageError('could not read the existing output file for --update; it must be a file this command ' +
|
|
261
|
+
'generated (json, ts, js or csv), not reformatted by hand or by Prettier');
|
|
262
|
+
};
|
|
263
|
+
if (format === 'plain') {
|
|
264
|
+
throw new ImageHashUsageError('--update works with --format json, ts, js or csv, not plain');
|
|
265
|
+
}
|
|
266
|
+
if (format === 'csv') {
|
|
267
|
+
const lines = content.split(/\r?\n/).filter((line) => line !== '');
|
|
268
|
+
const header = parseCsvLine(lines[0] ?? '');
|
|
269
|
+
if (header[0] !== 'file')
|
|
270
|
+
return fail();
|
|
271
|
+
return lines.slice(1).map((line) => {
|
|
272
|
+
const fields = parseCsvLine(line);
|
|
273
|
+
const record = {};
|
|
274
|
+
header.forEach((name, i) => (record[name] = fields[i]));
|
|
275
|
+
return entryFromRecord(fields[0], record);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
let body = content.trim();
|
|
279
|
+
if (format !== 'json') {
|
|
280
|
+
const match = /^[^{]*(\{[\s\S]*\})\s*(?:as\s+const)?\s*;?\s*$/.exec(body);
|
|
281
|
+
if (!match)
|
|
282
|
+
return fail();
|
|
283
|
+
body = match[1];
|
|
284
|
+
}
|
|
285
|
+
try {
|
|
286
|
+
const parsed = JSON.parse(body);
|
|
287
|
+
return Object.entries(parsed).map(([file, record]) => entryFromRecord(file, record));
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
return fail();
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../src/commands/image-hash/core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Components, type HashType } from './core.js';
|
|
2
|
+
import type { SharpFactory } from './sharp-loader.js';
|
|
3
|
+
export interface ComputeOptions {
|
|
4
|
+
types: HashType[];
|
|
5
|
+
size: number;
|
|
6
|
+
components: Components;
|
|
7
|
+
maxPixels?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ComputedHashes {
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
blurhash?: string;
|
|
13
|
+
thumbhash?: string;
|
|
14
|
+
color?: string;
|
|
15
|
+
preview?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function dominantColor(rgba: ArrayLike<number>): string | undefined;
|
|
18
|
+
export declare function friendlyMessage(error: unknown, maxPixels: number | undefined): string;
|
|
19
|
+
export declare function computeHashes(sharp: SharpFactory, input: string | Uint8Array, options: ComputeOptions): Promise<ComputedHashes>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { encode as encodeBlurhash } from 'blurhash';
|
|
2
|
+
import { rgbaToThumbHash, thumbHashToRGBA } from 'thumbhash';
|
|
3
|
+
import { resolveComponents } from './core.js';
|
|
4
|
+
export function dominantColor(rgba) {
|
|
5
|
+
const buckets = new Map();
|
|
6
|
+
for (let i = 0; i + 3 < rgba.length; i += 4) {
|
|
7
|
+
if (rgba[i + 3] < 128)
|
|
8
|
+
continue;
|
|
9
|
+
const r = rgba[i];
|
|
10
|
+
const g = rgba[i + 1];
|
|
11
|
+
const b = rgba[i + 2];
|
|
12
|
+
const key = ((r >> 4) << 8) | ((g >> 4) << 4) | (b >> 4);
|
|
13
|
+
const bucket = buckets.get(key);
|
|
14
|
+
if (bucket) {
|
|
15
|
+
bucket.count++;
|
|
16
|
+
bucket.r += r;
|
|
17
|
+
bucket.g += g;
|
|
18
|
+
bucket.b += b;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
buckets.set(key, { count: 1, r, g, b });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
let best;
|
|
25
|
+
for (const bucket of buckets.values()) {
|
|
26
|
+
if (!best || bucket.count > best.count)
|
|
27
|
+
best = bucket;
|
|
28
|
+
}
|
|
29
|
+
if (!best)
|
|
30
|
+
return undefined;
|
|
31
|
+
const hex = (sum) => Math.round(sum / best.count)
|
|
32
|
+
.toString(16)
|
|
33
|
+
.padStart(2, '0');
|
|
34
|
+
return `#${hex(best.r)}${hex(best.g)}${hex(best.b)}`;
|
|
35
|
+
}
|
|
36
|
+
export function friendlyMessage(error, maxPixels) {
|
|
37
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
38
|
+
if (/pixel limit/i.test(message)) {
|
|
39
|
+
const limit = maxPixels === undefined ? 'the default limit' : `${maxPixels} pixels`;
|
|
40
|
+
return `image is larger than ${limit} — raise it with --max-pixels (0 removes the limit)`;
|
|
41
|
+
}
|
|
42
|
+
if (/unsupported image format|corrupt header|bad seek|not a known file format/i.test(message)) {
|
|
43
|
+
return 'not a readable image — the file is corrupt or in an unsupported format';
|
|
44
|
+
}
|
|
45
|
+
if (/premature end|truncated|VipsJpeg|VipsPng|end of stream/i.test(message)) {
|
|
46
|
+
return 'the image file is truncated or damaged';
|
|
47
|
+
}
|
|
48
|
+
return message;
|
|
49
|
+
}
|
|
50
|
+
export async function computeHashes(sharp, input, options) {
|
|
51
|
+
const inputOptions = { failOn: 'truncated' };
|
|
52
|
+
if (options.maxPixels !== undefined) {
|
|
53
|
+
inputOptions.limitInputPixels = options.maxPixels === 0 ? false : options.maxPixels;
|
|
54
|
+
}
|
|
55
|
+
const metadata = await sharp(input, inputOptions).metadata();
|
|
56
|
+
const swapped = (metadata.orientation ?? 1) >= 5;
|
|
57
|
+
const width = (swapped ? metadata.height : metadata.width) ?? 0;
|
|
58
|
+
const height = (swapped ? metadata.width : metadata.height) ?? 0;
|
|
59
|
+
const { data, info } = await sharp(input, inputOptions)
|
|
60
|
+
.rotate()
|
|
61
|
+
.resize({ width: options.size, height: options.size, fit: 'inside', withoutEnlargement: true })
|
|
62
|
+
.toColourspace('srgb')
|
|
63
|
+
.ensureAlpha()
|
|
64
|
+
.raw()
|
|
65
|
+
.toBuffer({ resolveWithObject: true });
|
|
66
|
+
const result = {
|
|
67
|
+
width: width || info.width,
|
|
68
|
+
height: height || info.height,
|
|
69
|
+
};
|
|
70
|
+
if (options.types.includes('blurhash')) {
|
|
71
|
+
const components = resolveComponents(options.components, info.width, info.height);
|
|
72
|
+
result.blurhash = encodeBlurhash(new Uint8ClampedArray(data), info.width, info.height, components.x, components.y);
|
|
73
|
+
}
|
|
74
|
+
const needsThumbhash = options.types.includes('thumbhash') || options.types.includes('preview');
|
|
75
|
+
if (needsThumbhash) {
|
|
76
|
+
const hash = rgbaToThumbHash(info.width, info.height, data);
|
|
77
|
+
if (options.types.includes('thumbhash')) {
|
|
78
|
+
result.thumbhash = Buffer.from(hash).toString('base64');
|
|
79
|
+
}
|
|
80
|
+
if (options.types.includes('preview')) {
|
|
81
|
+
const decoded = thumbHashToRGBA(hash);
|
|
82
|
+
const png = await sharp(decoded.rgba, {
|
|
83
|
+
raw: { width: decoded.w, height: decoded.h, channels: 4 },
|
|
84
|
+
})
|
|
85
|
+
.png({ compressionLevel: 9 })
|
|
86
|
+
.toBuffer();
|
|
87
|
+
result.preview = `data:image/png;base64,${Buffer.from(png).toString('base64')}`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (options.types.includes('color')) {
|
|
91
|
+
const color = dominantColor(data);
|
|
92
|
+
if (color !== undefined)
|
|
93
|
+
result.color = color;
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../../src/commands/image-hash/hash.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { banner } from '../../format/vibes.js';
|
|
2
|
+
import { createStyle } from '../../format/style.js';
|
|
3
|
+
import { renderTable } from '../../format/table.js';
|
|
4
|
+
import { ALL_TYPES } from './core.js';
|
|
5
|
+
const TYPE_LABEL = {
|
|
6
|
+
blurhash: 'BlurHash',
|
|
7
|
+
thumbhash: 'ThumbHash',
|
|
8
|
+
color: 'Color',
|
|
9
|
+
preview: 'Preview',
|
|
10
|
+
};
|
|
11
|
+
const PREVIEW_CELL_WIDTH = 28;
|
|
12
|
+
function hashTypesIn(report) {
|
|
13
|
+
return ALL_TYPES.filter((type) => report.entries.some((entry) => entry[type] !== undefined));
|
|
14
|
+
}
|
|
15
|
+
function cellText(type, value) {
|
|
16
|
+
if (value === undefined)
|
|
17
|
+
return '';
|
|
18
|
+
if (type === 'preview' && value.length > PREVIEW_CELL_WIDTH) {
|
|
19
|
+
return `${value.slice(0, PREVIEW_CELL_WIDTH - 1)}…`;
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function imageHashTable(report, options) {
|
|
24
|
+
const s = createStyle(options);
|
|
25
|
+
const types = hashTypesIn(report);
|
|
26
|
+
const typeStyle = {
|
|
27
|
+
blurhash: s.name,
|
|
28
|
+
thumbhash: s.accent,
|
|
29
|
+
color: s.value,
|
|
30
|
+
preview: s.tag,
|
|
31
|
+
};
|
|
32
|
+
const columns = [
|
|
33
|
+
{ header: 'File', shrink: true, style: s.path },
|
|
34
|
+
{ header: 'Size', align: 'right', style: s.tag },
|
|
35
|
+
...types.map((type) => ({ header: TYPE_LABEL[type], style: typeStyle[type] })),
|
|
36
|
+
];
|
|
37
|
+
const rows = report.entries.map((entry) => [
|
|
38
|
+
entry.file,
|
|
39
|
+
`${entry.width}×${entry.height}`,
|
|
40
|
+
...types.map((type) => cellText(type, entry[type])),
|
|
41
|
+
]);
|
|
42
|
+
return renderTable(columns, rows, options);
|
|
43
|
+
}
|
|
44
|
+
export function renderImageHashReport(report, options = {}) {
|
|
45
|
+
const s = createStyle(options);
|
|
46
|
+
const lines = [];
|
|
47
|
+
const isClean = report.errors.length === 0 && report.outdated.length === 0;
|
|
48
|
+
if (options.quiet && isClean)
|
|
49
|
+
return '';
|
|
50
|
+
if (!options.quiet && !options.plain)
|
|
51
|
+
lines.push(banner(options), '');
|
|
52
|
+
if (report.dryRun && report.entries.length > 0) {
|
|
53
|
+
lines.push(...imageHashTable(report, options), '');
|
|
54
|
+
}
|
|
55
|
+
const count = report.entries.length;
|
|
56
|
+
const cachedNote = report.cached > 0 ? `, ${report.cached} from the cache` : '';
|
|
57
|
+
lines.push(s.info(`Hashed ${count} image${count === 1 ? '' : 's'}${cachedNote}.`));
|
|
58
|
+
if (report.check) {
|
|
59
|
+
if (report.outdated.length === 0) {
|
|
60
|
+
lines.push('', s.success(`All ${report.checked} output file${report.checked === 1 ? ' is' : 's are'} up to date.`));
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
lines.push('', s.problem(`${report.outdated.length} of ${report.checked} output file${report.checked === 1 ? '' : 's'} out of date:`));
|
|
64
|
+
for (const item of report.outdated) {
|
|
65
|
+
const reason = item.reason === 'missing' ? 'missing' : 'differs from the images';
|
|
66
|
+
lines.push(` ${s.path(item.file)} ${s.muted('—')} ${s.error(reason)}`);
|
|
67
|
+
}
|
|
68
|
+
lines.push('', s.hint('(regenerate them by running the same command without --check)'));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (report.written.length > 0) {
|
|
72
|
+
const verb = report.dryRun ? 'Would write' : 'Wrote';
|
|
73
|
+
const heading = `${verb} ${report.written.length} file${report.written.length === 1 ? '' : 's'}:`;
|
|
74
|
+
lines.push('', report.dryRun ? s.heading(heading) : s.success(heading));
|
|
75
|
+
for (const file of report.written)
|
|
76
|
+
lines.push(` ${s.path(file)}`);
|
|
77
|
+
}
|
|
78
|
+
if (report.pruned > 0) {
|
|
79
|
+
lines.push('', s.info(`Removed ${report.pruned} entr${report.pruned === 1 ? 'y' : 'ies'} whose image no longer exists.`));
|
|
80
|
+
}
|
|
81
|
+
if (report.dryRun) {
|
|
82
|
+
lines.push('', s.hint(report.written.length > 0
|
|
83
|
+
? '(dry run — nothing written; drop --dry-run to write the files)'
|
|
84
|
+
: '(dry run — nothing written)'));
|
|
85
|
+
}
|
|
86
|
+
if (report.errors.length > 0) {
|
|
87
|
+
lines.push('', s.problem(`${report.errors.length} problem${report.errors.length === 1 ? '' : 's'}:`));
|
|
88
|
+
for (const error of report.errors) {
|
|
89
|
+
lines.push(` ${s.path(error.file)} ${s.muted('—')} ${s.error(error.message)}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return lines.join('\n');
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/commands/image-hash/report.ts"],"names":[],"mappings":"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"}
|