mod.tsimport {
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;
}