import { disconnect, connect, patch, replaceLinks, useStatusBar, } from "../scrapbox-userscript-std/mod.ts"; import type { ErrorLike } from "../scrapbox-jp%2Ftypes/rest.ts"; import { getLinks } from "../複数のリンクをまとめて置換するUserScript/mod.ts"; import { isErr, unwrapErr, unwrapOk } from "npm:option-t@49/plain_result"; export const replace = async (text: string, projects: string[]) => { const link = getLinks(text)[0]; if (!link) return; const newLink = window.prompt( `Replace "${link}" to this in ${ projects.map((project) => `"/${project}"`).join(", ") }`, link, ) ?.replace?.(/[\[\]\n]/g, " ") ?? ""; if (newLink === "") return; const { render, dispose } = useStatusBar(); const socket = unwrapOk(await connect()); try { render( { type: "spinner" }, { type: "text", text: `Replacing links in ${projects.length} projects...`, }, ); let count = 0; const replacedNums = await Promise.all(projects.map(async (project) => { const [result] = await Promise.all([ // 本当はhasBackLinksOrIcons === trueのときのみ置換したい replaceLinks(project, link, newLink), patch(project, link, (lines, { persistent }) => { if (!persistent) return; return [ newLink, ...lines.map((line) => line.text).slice(1), ]; }, { socket }), ]); if (isErr(result)) { render( { type: "exclamation-triangle" }, { type: "text", text: `${unwrapErr(result).name} ${unwrapErr(result).message}`, }, ); throw toError(unwrapErr(result)); } count++; render( { type: "spinner" }, { type: "text", text: `Replacing links in ${projects.length - count} projects...`, }, ); return unwrapOk(result); })); const replaced = replacedNums.reduce((acc, cur) => acc + cur, 0); render( { type: "check-circle" }, { type: "text", text: `Successfully replaced ${replaced} links.` }, ); } finally { await disconnect(socket); setTimeout(dispose, 1000); } } const toError = (e: ErrorLike) => { const error = new Error(); error.name = e.name; error.message = e.message; return error; }