/** * @description 表示文本内容的追加增量。 */ export interface TextContentAppend { type: "append" text: string } /** * @description 表示文本内容的移除增量。 */ export interface TextContentRemove { type: "remove" text: string } /** * @description 表示文本内容的重置增量。 */ export interface TextContentReset { type: "reset" } /** * @description 表示文本内容可接受的增量类型。 */ export type TextContentDelta = TextContentAppend | TextContentRemove | TextContentReset /** * @description 表示一份文本内容快照及其增量历史。 */ export interface TextContent { deltaList: TextContentDelta[] total: string } /** * @description 在现有文本内容快照上应用一个增量,并返回新的内容快照。 * * `append` 会把文本追加到末尾,`remove` 仅在末尾文本匹配时移除,`reset` 会把总文本清空。 */ export const applyDeltaToTextContent = ( textContent: TextContent, delta: TextContentDelta, ): TextContent => { const clone = structuredClone(textContent) const { deltaList, total } = clone const newDeltaList = [...deltaList, delta] let newTotal = total switch (delta.type) { case "append": { // append delta text to the end of the total newTotal = newTotal + delta.text break } case "remove": { // remove delta text from the end of the total, if it exists newTotal = newTotal.endsWith(delta.text) ? newTotal.slice(0, newTotal.length - delta.text.length) : newTotal break } case "reset": { newTotal = "" break } default: { throw new Error(`Unknown delta type: ${String(delta)}`) } } return { deltaList: newDeltaList, total: newTotal, } } /** * @description 表示数值内容的追加增量。 */ export interface NumberContentAppend { type: "append" value: number } /** * @description 表示数值内容的移除增量。 */ export interface NumberContentRemove { type: "remove" value: number } /** * @description 表示数值内容的重置增量。 */ export interface NumberContentReset { type: "reset" } /** * @description 表示数值内容可接受的增量类型。 */ export type NumberContentDelta = NumberContentAppend | NumberContentRemove | NumberContentReset /** * @description 表示一份数值内容快照及其增量历史。 */ export interface NumberContent { deltaList: NumberContentDelta[] total: number } /** * @description 在现有数值内容快照上应用一个增量,并返回新的内容快照。 * * `append` 会累加数值,`remove` 会扣减数值,`reset` 会把总值重置为 0。 */ export const applyDeltaToNumberContent = ( numberContent: NumberContent, delta: NumberContentDelta, ): NumberContent => { const clone = structuredClone(numberContent) const { deltaList, total } = clone const newDeltaList = [...deltaList, delta] let newTotal = total switch (delta.type) { case "append": { newTotal = newTotal + delta.value break } case "remove": { newTotal = newTotal - delta.value break } case "reset": { newTotal = 0 break } default: { throw new Error(`Unknown delta type: ${String(delta)}`) } } return { deltaList: newDeltaList, total: newTotal, } }