83 lines
2.7 KiB
JavaScript
83 lines
2.7 KiB
JavaScript
import { readdir, readFile, writeFile } from "node:fs/promises";
|
|
import { createHash } from "node:crypto";
|
|
import { basename, join, relative } from "node:path";
|
|
|
|
const rawRoot = "research/jpw7/demo";
|
|
const decodedRoot = "research/jpw7/decoded";
|
|
const manifestPath = "fixtures/manifest.json";
|
|
|
|
const sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
const sorted = (values) => [...values].sort((left, right) => left.localeCompare(right, "zh-Hans-CN"));
|
|
const walk = async (root, prefix = "") => {
|
|
const entries = await readdir(join(root, prefix), { withFileTypes: true });
|
|
const paths = [];
|
|
for (const entry of entries) {
|
|
const child = join(prefix, entry.name);
|
|
if (entry.isDirectory()) paths.push(...await walk(root, child));
|
|
else paths.push(child);
|
|
}
|
|
return paths;
|
|
};
|
|
|
|
const rawPaths = sorted((await walk(rawRoot)).filter((path) => path.toLowerCase().endsWith(".jpwabc")));
|
|
const samples = [];
|
|
for (const rawRelativePath of rawPaths) {
|
|
const rawName = basename(rawRelativePath);
|
|
const candidates = [
|
|
`${rawName}.txt`,
|
|
`${rawName.replace(/\.jpwabc$/i, "")}.txt`,
|
|
`${rawRelativePath}.txt`,
|
|
rawName
|
|
];
|
|
let decodedName;
|
|
for (const candidate of candidates) {
|
|
try {
|
|
await readFile(join(decodedRoot, candidate));
|
|
decodedName = candidate;
|
|
break;
|
|
} catch {
|
|
// Try the next conventional decoded filename.
|
|
}
|
|
}
|
|
if (!decodedName) {
|
|
throw new Error(`No decoded pair found for ${rawName}`);
|
|
}
|
|
|
|
const rawPath = join(rawRoot, rawRelativePath);
|
|
const decodedPath = join(decodedRoot, decodedName);
|
|
const rawBytes = await readFile(rawPath);
|
|
const decodedBytes = await readFile(decodedPath);
|
|
samples.push({
|
|
id: rawRelativePath.replace(/\.jpwabc$/i, "").replaceAll("/", "::"),
|
|
sourceReadOnly: true,
|
|
rawPath: relative(".", rawPath),
|
|
decodedPath: relative(".", decodedPath),
|
|
rawBytes: rawBytes.byteLength,
|
|
decodedBytes: decodedBytes.byteLength,
|
|
rawSha256: sha256(rawBytes),
|
|
decodedSha256: sha256(decodedBytes),
|
|
classification: {
|
|
status: "pending",
|
|
firstResponsibleMilestone: "M1",
|
|
expected: [
|
|
"encoding-and-bom",
|
|
"section-inventory",
|
|
"core-semantics",
|
|
"unknown-content-retained",
|
|
"diagnostics-emitted"
|
|
]
|
|
}
|
|
});
|
|
}
|
|
|
|
const manifest = {
|
|
manifestVersion: 1,
|
|
purpose: "M0 read-only fixture baseline",
|
|
sampleCount: samples.length,
|
|
generatedBy: "scripts/generate-fixture-manifest.mjs",
|
|
sourceRoots: { raw: rawRoot, decoded: decodedRoot },
|
|
samples
|
|
};
|
|
await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
|
|
console.log(`Wrote ${manifestPath} with ${samples.length} sample pairs`);
|