fidelity-kit 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +133 -5
- package/dist/commands/build.d.ts +2 -0
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +6 -2
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/dev.d.ts +7 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +9 -2
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/hash.d.ts +2 -0
- package/dist/commands/hash.d.ts.map +1 -1
- package/dist/commands/hash.js +7 -3
- package/dist/commands/hash.js.map +1 -1
- package/dist/commands/process.d.ts +6 -0
- package/dist/commands/process.d.ts.map +1 -1
- package/dist/commands/process.js +35 -7
- package/dist/commands/process.js.map +1 -1
- package/dist/commands/serve.d.ts +3 -1
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +2 -1
- package/dist/commands/serve.js.map +1 -1
- package/dist/core/compare.d.ts +4 -2
- package/dist/core/compare.d.ts.map +1 -1
- package/dist/core/compare.js +7 -5
- package/dist/core/compare.js.map +1 -1
- package/dist/core/hash.d.ts +2 -0
- package/dist/core/hash.d.ts.map +1 -1
- package/dist/core/hash.js +37 -10
- package/dist/core/hash.js.map +1 -1
- package/dist/core/hash.test.js +8 -1
- package/dist/core/hash.test.js.map +1 -1
- package/dist/core/process.d.ts +52 -3
- package/dist/core/process.d.ts.map +1 -1
- package/dist/core/process.js +450 -51
- package/dist/core/process.js.map +1 -1
- package/dist/core/process.test.d.ts +2 -0
- package/dist/core/process.test.d.ts.map +1 -0
- package/dist/core/process.test.js +269 -0
- package/dist/core/process.test.js.map +1 -0
- package/dist/core/progress.d.ts +8 -0
- package/dist/core/progress.d.ts.map +1 -0
- package/dist/core/progress.js +2 -0
- package/dist/core/progress.js.map +1 -0
- package/dist/core/scan.d.ts +8 -1
- package/dist/core/scan.d.ts.map +1 -1
- package/dist/core/scan.js +72 -7
- package/dist/core/scan.js.map +1 -1
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +8 -2
- package/dist/core/schema.js.map +1 -1
- package/dist/core/suite.test.js +61 -2
- package/dist/core/suite.test.js.map +1 -1
- package/dist/progress.d.ts +12 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +46 -0
- package/dist/progress.js.map +1 -0
- package/dist/progress.test.d.ts +2 -0
- package/dist/progress.test.d.ts.map +1 -0
- package/dist/progress.test.js +36 -0
- package/dist/progress.test.js.map +1 -0
- package/dist/run.d.ts +4 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +34 -6
- package/dist/run.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +25 -2
- package/dist/server.js.map +1 -1
- package/dist/server.test.js +55 -2
- package/dist/server.test.js.map +1 -1
- package/dist/watch.d.ts +9 -0
- package/dist/watch.d.ts.map +1 -0
- package/dist/watch.js +96 -0
- package/dist/watch.js.map +1 -0
- package/dist/watch.test.d.ts +2 -0
- package/dist/watch.test.d.ts.map +1 -0
- package/dist/watch.test.js +138 -0
- package/dist/watch.test.js.map +1 -0
- package/package.json +11 -1
- package/viewer/assets/{ViewControls-hn4PfGV3.js → ViewControls-Ck9smy3A.js} +2 -2
- package/viewer/assets/_-Bn1LyOgm.js +1 -0
- package/viewer/assets/{index-D9G4C6Ns.js → index-BZCd8VsK.js} +2 -2
- package/viewer/assets/index-VKD_ZeZu.css +2 -0
- package/viewer/assets/{routes-DmeR6gGl.js → routes-sEPFkb5w.js} +1 -1
- package/viewer/index.html +2 -2
- package/dist/.tsbuildinfo +0 -1
- package/viewer/assets/_-BAkV94Fq.js +0 -1
- package/viewer/assets/index-D8YJNCs_.css +0 -2
package/dist/watch.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { watch } from 'chokidar';
|
|
2
|
+
import { relative, resolve, sep } from 'node:path';
|
|
3
|
+
import { SuiteProcessor } from './core/process.js';
|
|
4
|
+
/** One processor and one batch in flight. Generated files are excluded before they reach either queue. */
|
|
5
|
+
export async function watchResults(root, onResult = () => { }, opts = {}) {
|
|
6
|
+
const base = resolve(root);
|
|
7
|
+
const processor = await SuiteProcessor.create(base, opts);
|
|
8
|
+
let timer;
|
|
9
|
+
let running;
|
|
10
|
+
let closed = false;
|
|
11
|
+
let initializing = true;
|
|
12
|
+
let pending = false;
|
|
13
|
+
let configWarning = false;
|
|
14
|
+
const rel = (path) => relative(base, path).split(sep).join('/');
|
|
15
|
+
const relevant = (path) => path === 'fidelity.json' || processor.sceneForInput(path) !== null;
|
|
16
|
+
const flush = () => {
|
|
17
|
+
timer = undefined;
|
|
18
|
+
if (closed)
|
|
19
|
+
return;
|
|
20
|
+
processor.settle();
|
|
21
|
+
if (initializing || running || !pending)
|
|
22
|
+
return;
|
|
23
|
+
pending = false;
|
|
24
|
+
if (!processor.needsFlush)
|
|
25
|
+
return;
|
|
26
|
+
running = processor
|
|
27
|
+
.flush()
|
|
28
|
+
.then(onResult)
|
|
29
|
+
.catch((error) => console.error('Watch update failed:', error))
|
|
30
|
+
.finally(() => {
|
|
31
|
+
running = undefined;
|
|
32
|
+
if (pending && !timer && !closed)
|
|
33
|
+
timer = setTimeout(flush, 250);
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
const watcher = watch(base, {
|
|
37
|
+
ignoreInitial: true,
|
|
38
|
+
awaitWriteFinish: { stabilityThreshold: 500, pollInterval: 100 },
|
|
39
|
+
ignored: (path, stats) => !!stats?.isFile() && !relevant(rel(path)),
|
|
40
|
+
});
|
|
41
|
+
watcher.on('all', (event, path) => {
|
|
42
|
+
const input = rel(path);
|
|
43
|
+
if (closed)
|
|
44
|
+
return;
|
|
45
|
+
if (input === 'fidelity.json') {
|
|
46
|
+
if (!configWarning)
|
|
47
|
+
console.warn('fidelity.json changed; restart to apply renderer, output, or configuration changes.');
|
|
48
|
+
configWarning = true;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (event === 'unlinkDir')
|
|
52
|
+
processor.removeDirectory(input, true);
|
|
53
|
+
else {
|
|
54
|
+
if (event === 'addDir' || !relevant(input))
|
|
55
|
+
return;
|
|
56
|
+
processor.notify([input], true);
|
|
57
|
+
}
|
|
58
|
+
pending = true;
|
|
59
|
+
if (timer)
|
|
60
|
+
clearTimeout(timer);
|
|
61
|
+
timer = setTimeout(flush, 250);
|
|
62
|
+
});
|
|
63
|
+
watcher.on('error', (error) => console.error('Watch error:', error));
|
|
64
|
+
try {
|
|
65
|
+
await new Promise((resolveReady, reject) => {
|
|
66
|
+
watcher.once('ready', resolveReady);
|
|
67
|
+
watcher.once('error', reject);
|
|
68
|
+
});
|
|
69
|
+
// Observe before scanning so changes during initial processing cannot fall through a startup gap.
|
|
70
|
+
onResult(await processor.initialize(opts.process ?? true));
|
|
71
|
+
initializing = false;
|
|
72
|
+
if (pending && !timer)
|
|
73
|
+
timer = setTimeout(flush, 250);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
closed = true;
|
|
77
|
+
if (timer)
|
|
78
|
+
clearTimeout(timer);
|
|
79
|
+
await watcher.close();
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
async close() {
|
|
84
|
+
closed = true;
|
|
85
|
+
if (timer)
|
|
86
|
+
clearTimeout(timer);
|
|
87
|
+
await watcher.close();
|
|
88
|
+
await running;
|
|
89
|
+
// Finish source events already accepted before shutdown.
|
|
90
|
+
processor.settle();
|
|
91
|
+
if (pending && processor.needsFlush)
|
|
92
|
+
onResult(await processor.flush());
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=watch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.test.d.ts","sourceRoot":"","sources":["../src/watch.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { mkdtemp, mkdir, readFile, utimes, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import sharp from 'sharp';
|
|
5
|
+
import { expect, test, vi } from 'vitest';
|
|
6
|
+
import * as comparison from './core/compare.js';
|
|
7
|
+
import { processChanges, processSuite } from './core/process.js';
|
|
8
|
+
import { watchResults } from './watch.js';
|
|
9
|
+
const image = (value) => sharp({ create: { width: 8, height: 8, channels: 3, background: { r: value, g: value, b: value } } })
|
|
10
|
+
.avif({ lossless: true })
|
|
11
|
+
.toBuffer();
|
|
12
|
+
const index = async (root) => JSON.parse(await readFile(join(root, 'index.json'), 'utf8'));
|
|
13
|
+
async function fixture() {
|
|
14
|
+
const root = await mkdtemp(join(tmpdir(), 'fk-watch-'));
|
|
15
|
+
await writeFile(join(root, 'fidelity.json'), JSON.stringify({ title: 'Watch', renderers: [{ id: 'ref', reference: true }, { id: 'a' }, { id: 'b' }] }));
|
|
16
|
+
const dir = join(root, 'one', 'beauty');
|
|
17
|
+
await mkdir(dir, { recursive: true });
|
|
18
|
+
for (const renderer of ['ref', 'a', 'b'])
|
|
19
|
+
await writeFile(join(dir, `${renderer}.avif`), await image(100));
|
|
20
|
+
await processSuite(root);
|
|
21
|
+
return { root, dir };
|
|
22
|
+
}
|
|
23
|
+
test('a changed renderer recomputes only its pair and updates the index; new scenes are inserted', async () => {
|
|
24
|
+
const { root, dir } = await fixture();
|
|
25
|
+
const before = await index(root);
|
|
26
|
+
const changed = join(dir, 'a.avif');
|
|
27
|
+
await writeFile(changed, await image(140));
|
|
28
|
+
const future = new Date(Date.now() + 2000);
|
|
29
|
+
await utimes(changed, future, future);
|
|
30
|
+
const progress = [];
|
|
31
|
+
expect(await processChanges(root, ['one/beauty/a.avif'], (update) => progress.push(update))).toMatchObject({
|
|
32
|
+
computed: 1,
|
|
33
|
+
failed: [],
|
|
34
|
+
});
|
|
35
|
+
expect(progress.at(-1)).toEqual({ phase: 'Writing index', completed: 1, total: 1, unit: 'files' });
|
|
36
|
+
expect(progress.find((update) => update.phase === 'Comparing' && update.completed === 1)).toBeDefined();
|
|
37
|
+
const after = await index(root);
|
|
38
|
+
expect(after.metrics['one/beauty/a.vs-ref.metrics.json'].maxError).toBeGreaterThan(0);
|
|
39
|
+
expect(after.metrics['one/beauty/b.vs-ref.metrics.json']).toEqual(before.metrics['one/beauty/b.vs-ref.metrics.json']);
|
|
40
|
+
const newDir = join(root, 'two', 'beauty');
|
|
41
|
+
await mkdir(newDir, { recursive: true });
|
|
42
|
+
await writeFile(join(newDir, 'ref.avif'), await image(90));
|
|
43
|
+
await writeFile(join(newDir, 'a.avif'), await image(110));
|
|
44
|
+
expect(await processChanges(root, ['two/beauty/a.avif'])).toMatchObject({ computed: 1, failed: [] });
|
|
45
|
+
expect((await index(root)).root.scenes.map((s) => s.path)).toEqual(['one', 'two']);
|
|
46
|
+
});
|
|
47
|
+
test('the watcher picks up an overwritten image and survives an invalid intermediate file', async () => {
|
|
48
|
+
const { root, dir } = await fixture();
|
|
49
|
+
const updates = [];
|
|
50
|
+
const watcher = await watchResults(root, (result) => updates.push(result.computed));
|
|
51
|
+
try {
|
|
52
|
+
await writeFile(join(dir, 'a.avif'), 'incomplete');
|
|
53
|
+
await new Promise((resolve) => setTimeout(resolve, 900));
|
|
54
|
+
await writeFile(join(dir, 'a.avif'), await image(160));
|
|
55
|
+
await new Promise((resolve, reject) => {
|
|
56
|
+
const deadline = setTimeout(() => reject(new Error('watch update timed out')), 6000);
|
|
57
|
+
const poll = setInterval(async () => {
|
|
58
|
+
if ((await index(root)).metrics['one/beauty/a.vs-ref.metrics.json']?.maxError > 0) {
|
|
59
|
+
clearTimeout(deadline);
|
|
60
|
+
clearInterval(poll);
|
|
61
|
+
resolve();
|
|
62
|
+
}
|
|
63
|
+
}, 100);
|
|
64
|
+
});
|
|
65
|
+
expect(updates).toContain(1);
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
await watcher.close();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
test('reference and metadata changes refresh the affected scene', async () => {
|
|
72
|
+
const { root, dir } = await fixture();
|
|
73
|
+
await writeFile(join(root, 'one', 'scene.json'), JSON.stringify({ title: 'Renamed', tags: ['new'] }));
|
|
74
|
+
expect(await processChanges(root, ['one/scene.json'])).toMatchObject({ computed: 0 });
|
|
75
|
+
expect((await index(root)).root.scenes[0]).toMatchObject({ title: 'Renamed', tags: ['new'] });
|
|
76
|
+
const changed = join(dir, 'ref.avif');
|
|
77
|
+
await writeFile(changed, await image(170));
|
|
78
|
+
const future = new Date(Date.now() + 2000);
|
|
79
|
+
await utimes(changed, future, future);
|
|
80
|
+
expect(await processChanges(root, ['one/beauty/ref.avif'])).toMatchObject({ computed: 2, failed: [] });
|
|
81
|
+
});
|
|
82
|
+
test('generated metrics, deltas, index and temporary writes never trigger watch updates', async () => {
|
|
83
|
+
const { root, dir } = await fixture();
|
|
84
|
+
const updates = [];
|
|
85
|
+
const watcher = await watchResults(root, (result) => updates.push(result.computed), { concurrency: 1 });
|
|
86
|
+
try {
|
|
87
|
+
const baseline = updates.length;
|
|
88
|
+
await writeFile(join(dir, 'a.vs-ref.metrics.json'), '{}');
|
|
89
|
+
await writeFile(join(dir, 'a.vs-ref.delta.avif'), await image(30));
|
|
90
|
+
await writeFile(join(dir, 'a.avif.write.tmp'), 'temporary');
|
|
91
|
+
await writeFile(join(root, 'index.json.write.tmp'), '{}');
|
|
92
|
+
await writeFile(join(root, 'index.json'), JSON.stringify(await index(root)));
|
|
93
|
+
await new Promise((resolve) => setTimeout(resolve, 1100));
|
|
94
|
+
expect(updates).toHaveLength(baseline);
|
|
95
|
+
await writeFile(join(dir, 'a.avif'), await image(190));
|
|
96
|
+
await expect.poll(() => updates.length, { timeout: 6000 }).toBe(baseline + 1);
|
|
97
|
+
expect(updates.at(-1)).toBe(1);
|
|
98
|
+
// The comparison itself writes all generated artifacts; none may feed back into the watcher.
|
|
99
|
+
await new Promise((resolve) => setTimeout(resolve, 1100));
|
|
100
|
+
expect(updates).toHaveLength(baseline + 1);
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
await watcher.close();
|
|
104
|
+
}
|
|
105
|
+
}, 10000);
|
|
106
|
+
test('changes during initial processing are observed and supersede the initial comparison', async () => {
|
|
107
|
+
const { root, dir } = await fixture();
|
|
108
|
+
await writeFile(join(dir, 'a.avif'), await image(130));
|
|
109
|
+
const started = Promise.withResolvers();
|
|
110
|
+
const release = Promise.withResolvers();
|
|
111
|
+
const original = comparison.compareImages;
|
|
112
|
+
const compare = vi.spyOn(comparison, 'compareImages').mockImplementationOnce(async (...args) => {
|
|
113
|
+
const result = await original(...args);
|
|
114
|
+
started.resolve();
|
|
115
|
+
await release.promise;
|
|
116
|
+
return result;
|
|
117
|
+
});
|
|
118
|
+
let watcher;
|
|
119
|
+
try {
|
|
120
|
+
const starting = watchResults(root);
|
|
121
|
+
await started.promise;
|
|
122
|
+
await writeFile(join(dir, 'a.avif'), await image(190));
|
|
123
|
+
// Let the real watcher deliver its stable-write notification while startup is still running.
|
|
124
|
+
await new Promise((resolve) => setTimeout(resolve, 900));
|
|
125
|
+
release.resolve();
|
|
126
|
+
watcher = await starting;
|
|
127
|
+
await expect
|
|
128
|
+
.poll(async () => (await index(root)).metrics['one/beauty/a.vs-ref.metrics.json']?.maxError, { timeout: 6000 })
|
|
129
|
+
.toBeGreaterThan(0.3);
|
|
130
|
+
expect(compare).toHaveBeenCalledTimes(2);
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
release.resolve();
|
|
134
|
+
await watcher?.close();
|
|
135
|
+
compare.mockRestore();
|
|
136
|
+
}
|
|
137
|
+
}, 10000);
|
|
138
|
+
//# sourceMappingURL=watch.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.test.js","sourceRoot":"","sources":["../src/watch.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fidelity-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Toolkit for renderer fidelity suites: metrics + delta CLI and a viewer served from any results folder.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"fidelity",
|
|
7
|
+
"image-comparison",
|
|
8
|
+
"image-diff",
|
|
9
|
+
"psnr",
|
|
10
|
+
"renderer",
|
|
11
|
+
"rendering",
|
|
12
|
+
"visual-regression"
|
|
13
|
+
],
|
|
5
14
|
"license": "MIT",
|
|
6
15
|
"repository": {
|
|
7
16
|
"type": "git",
|
|
@@ -34,6 +43,7 @@
|
|
|
34
43
|
"dependencies": {
|
|
35
44
|
"@clidoc/core": "^1.0.0",
|
|
36
45
|
"@clidoc/yargs": "^1.1.0",
|
|
46
|
+
"chokidar": "^5.0.0",
|
|
37
47
|
"p-limit": "^7.3.3",
|
|
38
48
|
"sharp": "^0.35.4",
|
|
39
49
|
"yargs": "^18.0.0",
|