Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions websocket/makeChanges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ import type { Page } from "@cosense/types/rest";
import type { Change } from "./change.ts";
import { findMetadata, getHelpfeels } from "./findMetadata.ts";
import { isSameArray } from "./isSameArray.ts";
import { isString } from "@core/unknownutil/is/string";

export function* makeChanges(
before: Page,
after: string[],
after: (string | { text: string })[],
userId: string,
): Generator<Change, void, unknown> {
// Prevent newline characters from being included in the text
// This ensures consistent line handling across different platforms
const after_ = after.flatMap((text) => text.split("\n"));
const after_ = after.flatMap((text) =>
(isString(text) ? text : text.text).split("\n")
);

// First, yield changes in the main content
// Content changes must be processed before metadata to maintain consistency
Expand Down
49 changes: 31 additions & 18 deletions websocket/patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { suggestUnDupTitle } from "./suggestUnDupTitle.ts";
import type { Result } from "option-t/plain_result";
import type { Socket } from "socket.io-client";

export type PatchOptions = PushOptions;

export interface PatchMetadata extends Page {
/** Number of retry attempts for page modification
*
Expand All @@ -17,6 +15,30 @@ export interface PatchMetadata extends Page {
attempts: number;
}

/**
* Function used in {@linkcode patch} to generate a patch from the current page state
*
* This function is used to generate a patch from the current page state.
* It receives the current page lines and metadata and returns the new page content.
* The function can be synchronous or asynchronous.
*
* @param lines - Current page lines
* @param metadata - Current page metadata
* @returns one of the following or a {@linkcode Promise} resolving to one:
* - `(string | { text: string; })[]`: New page content
* - `[]`: Delete the page
* - `undefined`: Abort modification
*/
export type MakePatchFn = (
lines: BaseLine[],
metadata: PatchMetadata,
) =>
| (string | { text: string })[]
| undefined
| Promise<(string | { text: string })[] | undefined>;

export type PatchOptions = PushOptions;

/** Modify an entire Scrapbox page by computing and sending only the differences
*
* This function handles the entire page modification process:
Expand All @@ -26,29 +48,20 @@ export interface PatchMetadata extends Page {
* 4. Handles errors (e.g., duplicate titles)
* 5. Retries on conflicts
*
* @param project - Project ID containing the target page
* @param title - Title of the page to modify
* @param update - Function to generate new content:
* - Input: Current page lines and metadata
* - Return values:
* - `string[]`: New page content
* - `undefined`: Abort modification
* - `[]`: Delete the page
* Can be async (returns `Promise`)
* @param options - Optional WebSocket configuration
* @param project Project ID containing the target page
* @param title Title of the page to modify
* @param update Function to generate new content
* @param options Optional WebSocket configuration
*
* Special cases:
* - If update returns undefined: Operation is cancelled
* - If update returns []: Page is deleted
* - If `update` returns `undefined`: Operation is cancelled
* - If `update` returns `[]`: Page is deleted
* - On duplicate title: Automatically suggests non-conflicting title
*/
export const patch = (
project: string,
title: string,
update: (
lines: BaseLine[],
metadata: PatchMetadata,
) => string[] | undefined | Promise<string[] | undefined>,
update: MakePatchFn,
options?: PatchOptions,
): Promise<Result<string, PushError | Socket.DisconnectReason>> =>
push(
Expand Down
Loading