#!/usr/bin/env node import assert from "node:assert/strict"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { spawn } from "node:child_process"; import { buildHistorySourceManifest } from "./history-source-indexer.mjs"; const root = fs.mkdtempSync(path.join(os.tmpdir(), "history-source-indexer-")); try { const gpt = path.join(root, "conversations.json"); fs.writeFileSync(gpt, JSON.stringify([{ id: 1, text: "含有 { [ 字符" }, { id: 2, nested: { ok: true } }])); const notionDirectory = path.join(root, "notion"); const extractedPart = path.join(notionDirectory, "Export-test"); fs.mkdirSync(extractedPart, { recursive: true }); fs.writeFileSync(path.join(extractedPart, "page.md"), "private title"); fs.writeFileSync(path.join(extractedPart, "table.csv"), "a,b"); const inner = path.join(root, "Part-1.zip"); const outer = path.join(root, "notion.zip"); await new Promise((resolve, reject) => { const child = spawn("zip", ["-qr", inner, "."], { cwd: extractedPart }); child.on("close", (code) => code === 0 ? resolve() : reject(new Error("inner_zip_failed"))); }); await new Promise((resolve, reject) => { const child = spawn("zip", ["-qj", outer, inner]); child.on("close", (code) => code === 0 ? resolve() : reject(new Error("outer_zip_failed"))); }); const manifest = await buildHistorySourceManifest({ gpt, notion: outer, notionDirectory }); assert.equal(manifest.contains_original_language, false); assert.equal(manifest.contains_page_titles, false); assert.equal(manifest.contains_absolute_paths, false); assert.equal(manifest.sources[0].item_count, 2); assert.equal(manifest.sources[1].item_count, 1); assert.equal(manifest.sources[1].inventory.csv_count, 1); assert.equal(JSON.stringify(manifest).includes("private title"), false); assert.equal(JSON.stringify(manifest).includes(root), false); process.stdout.write("history source indexer tests: PASS\n"); } finally { fs.rmSync(root, { recursive: true, force: true }); }