- 冲突「采纳改法」:有补丁瞬时改入终稿并选中;无补丁但可定位则采纳时调 AI(refiner)重写该段套入;定位不到提示手改 - 正文改为行内高亮叠层编辑器(与页面同底色、随内容增高、无滚动条),点冲突卡/锚点整页滚到并选中+闪烁 - 仅对可在正文定位的冲突显示「跳转」/锚点;locate 支持从 where 引号抽原文,杜绝定位失败刷屏 - 伏笔建议卡:新埋一键登记(预填表单)/ 疑似回收一键标记 CLOSED(复用现有端点) - 审稿页草稿自动保存(防抖 PUT /draft),与「验收本章」解耦,刷新不丢 - 写作路由带章号 ?chapter=N + 验收成功面板/大纲页「写下一章」入口;写作目录从大纲列出全部章节 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
45 lines
1.7 KiB
TypeScript
45 lines
1.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import { applyConflictFix, hasApplicableFix } from "./applyFix";
|
|
|
|
describe("hasApplicableFix", () => {
|
|
it("requires non-empty original and string replacement", () => {
|
|
expect(hasApplicableFix("迈巴赫", "奔驰")).toBe(true);
|
|
expect(hasApplicableFix("删我", "")).toBe(true); // 空串=删除,仍可应用
|
|
expect(hasApplicableFix(null, "奔驰")).toBe(false);
|
|
expect(hasApplicableFix("", "奔驰")).toBe(false);
|
|
expect(hasApplicableFix("迈巴赫", null)).toBe(false);
|
|
expect(hasApplicableFix(undefined, undefined)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("applyConflictFix", () => {
|
|
it("replaces the first occurrence of original with replacement", () => {
|
|
const out = applyConflictFix(
|
|
"他乘坐迈巴赫扬长而去,迈巴赫的尾灯。",
|
|
"迈巴赫",
|
|
"奔驰",
|
|
);
|
|
expect(out.status).toBe("applied");
|
|
expect(out.text).toBe("他乘坐奔驰扬长而去,迈巴赫的尾灯。");
|
|
});
|
|
|
|
it("returns not-found and leaves text untouched when original is absent (drift)", () => {
|
|
const out = applyConflictFix("作者已经手改过的终稿。", "迈巴赫", "奔驰");
|
|
expect(out.status).toBe("not-found");
|
|
expect(out.text).toBe("作者已经手改过的终稿。");
|
|
});
|
|
|
|
it("returns no-patch when conflict carries no applicable patch", () => {
|
|
const out = applyConflictFix("正文", null, null);
|
|
expect(out.status).toBe("no-patch");
|
|
expect(out.text).toBe("正文");
|
|
});
|
|
|
|
it("does not mutate the input string", () => {
|
|
const original = "迈巴赫尾灯";
|
|
applyConflictFix(original, "迈巴赫", "奔驰");
|
|
expect(original).toBe("迈巴赫尾灯");
|
|
});
|
|
});
|