import assert from "node:assert/strict"; import fs from "node:fs"; import path from "node:path"; const root = path.resolve(import.meta.dirname, ".."); const sourcePath = path.join( root, "client", "src", "sections", "superAgent", "utils", "workspace.js" ); const source = fs.readFileSync(sourcePath, "utf8"); const streamHookSource = fs.readFileSync( path.join(root, "client", "src", "sections", "superAgent", "hooks", "useSuperAgentStream.js"), "utf8" ); const containerSource = fs.readFileSync( path.join(root, "client", "src", "sections", "superAgent", "container", "index.jsx"), "utf8" ); function loadWorkspaceUtils() { const transformed = source.replace(/export const ([A-Za-z0-9_]+) =/g, "const $1 =") + "\nreturn { normalizeCatalogWorkspace, toCheckpointCatalog, mergeAuthoritativeSectionList, buildSectionDisplayHierarchy, shouldMarkSectionDirty };"; return new Function(transformed)(); } const { normalizeCatalogWorkspace, toCheckpointCatalog, mergeAuthoritativeSectionList, buildSectionDisplayHierarchy, shouldMarkSectionDirty, } = loadWorkspaceUtils(); const normalized = normalizeCatalogWorkspace({ chapters: [ { id: "ch1", title: "技术方案", subsections: [ { id: "ch1s1", title: "网络安全方案", subsections: [{ id: "ch1s1a", title: "实施保障措施" }], }, ], }, ], }); assert.equal(normalized[0].children[0].children[0].title, "实施保障措施"); const edited = [ { ...normalized[0], subsections: [{ id: "stale", title: "旧目录" }], children: [ { ...normalized[0].children[0], title: "网络安全方案(已修改)", children: [ ...normalized[0].children[0].children, { key: "1-1-2", title: "新增条目", name: "新增条目", children: [] }, ], }, ], }, ]; const checkpointCatalog = toCheckpointCatalog(edited); assert.equal(checkpointCatalog[0].subsections[0].title, "网络安全方案(已修改)"); assert.equal(checkpointCatalog[0].subsections[0].subsections[1].title, "新增条目"); assert.equal(checkpointCatalog[0].subsections[0].subsections[1].id, "1-1-2"); assert.equal("children" in checkpointCatalog[0], false); assert.equal( checkpointCatalog[0].subsections.some((item) => item.id === "stale"), false ); const mergedSections = mergeAuthoritativeSectionList( [ { id: "ch1", title: "一、报价部分", content: "" }, { id: "ch1s1", title: "磋商函", content: "本地旧内容", order: 1 }, ], [{ id: "ch1s1", title: "磋商函", content: "服务端正文", order: 1 }], new Set() ); assert.deepEqual(mergedSections.map((item) => item.id), ["ch1s1"]); assert.equal(mergedSections[0].content, "服务端正文"); const dirtyMergedSections = mergeAuthoritativeSectionList( [{ id: "ch1s1", title: "磋商函", content: "尚未保存的本地修改", order: 1 }], [{ id: "ch1s1", title: "磋商函", content: "服务端旧正文", order: 1 }], new Set(["ch1s1"]) ); assert.equal(dirtyMergedSections[0].content, "尚未保存的本地修改"); const displaySections = buildSectionDisplayHierarchy([ { id: "ch1s1", parent_id: "ch1", parent_title: "报价部分", title: "磋商函", order: 1 }, { id: "ch1s2", parent_id: "ch1", parent_title: "报价部分", title: "报价一览表", order: 2 }, { id: "ch2s1", parent_id: "ch2", parent_title: "资格审查部分", title: "法定代表人身份证明", order: 3 }, { id: "ch3s1", parent_id: "ch3", parent_title: "符合性审查部分", title: "技术、商务要求响应表", order: 4 }, { id: "ch4s1", parent_id: "ch4", parent_title: "技术和商务部分", title: "项目理解与总体方案概述", order: 5 }, { id: "ch4s2", parent_id: "ch4", parent_title: "技术和商务部分", title: "网络及网络安全运维方案", order: 6 }, ]); assert.equal(displaySections[0].parentDisplayTitle, "一、报价部分"); assert.equal(displaySections[0].displayTitle, "1.1 磋商函"); assert.equal(displaySections[1].startsParentGroup, false); assert.equal(displaySections[4].parentDisplayTitle, "四、技术和商务部分"); assert.equal(displaySections[4].displayTitle, "4.1 项目理解与总体方案概述"); assert.equal(displaySections[5].displayTitle, "4.2 网络及网络安全运维方案"); assert.equal( shouldMarkSectionDirty({ hasUserFocus: false, previousContent: "", nextContent: "
" }), false ); assert.equal( shouldMarkSectionDirty({ hasUserFocus: true, previousContent: "正文", nextContent: "修改后正文" }), true ); assert.match(streamHookSource, /"custom:generation"/); assert.match(streamHookSource, /"custom:section"/); assert.match(streamHookSource, /"custom:workspace"/); assert.match(streamHookSource, /replay:\s*false/); assert.match(containerSource, /workspace\.updated/); assert.match(containerSource, /section\.completed/); assert.match(containerSource, /syncSessionProgressSections/); assert.match(containerSource, /refreshSessionContentWorkspace/);