From 2da8506965eff7803db74ab364bcdcff4812443c Mon Sep 17 00:00:00 2001 From: takker99 <37929109+takker99@users.noreply.github.com> Date: Fri, 19 Apr 2024 11:13:19 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat(patch):=20`update()`=E3=81=AE=E7=AC=AC?= =?UTF-8?q?2=E5=BC=95=E6=95=B0=E3=81=8B=E3=82=89=E3=80=81`Page`=E3=81=AE?= =?UTF-8?q?=E5=85=A8=E3=83=87=E3=83=BC=E3=82=BF=E3=82=92=E5=8F=96=E3=82=8A?= =?UTF-8?q?=E5=87=BA=E3=81=9B=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=97?= =?UTF-8?q?=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/_codeBlock.ts | 8 +++---- browser/websocket/deletePage.ts | 2 +- browser/websocket/makeChanges.ts | 21 +++++++++---------- browser/websocket/patch.ts | 36 +++++++++++++++++++------------- browser/websocket/pin.ts | 18 ++++++++-------- browser/websocket/pull.ts | 27 +++--------------------- 6 files changed, 49 insertions(+), 63 deletions(-) diff --git a/browser/websocket/_codeBlock.ts b/browser/websocket/_codeBlock.ts index c3f57fb..50d6f57 100644 --- a/browser/websocket/_codeBlock.ts +++ b/browser/websocket/_codeBlock.ts @@ -1,6 +1,6 @@ import { Change, Socket, wrap } from "../../deps/socket.ts"; +import {Page} from "../../deps/scrapbox-rest.ts"; import { TinyCodeBlock } from "../../rest/getCodeBlocks.ts"; -import { HeadData } from "./pull.ts"; import { getProjectId, getUserId } from "./id.ts"; import { pushWithRetry } from "./_fetch.ts"; @@ -14,7 +14,7 @@ export interface CodeTitle { /** コミットを送信する一連の処理 */ export const applyCommit = async ( commits: Change[], - head: HeadData, + page: Page, projectName: string, pageTitle: string, socket: Socket, @@ -26,9 +26,9 @@ export const applyCommit = async ( ]); const { request } = wrap(socket); return await pushWithRetry(request, commits, { - parentId: head.commitId, + parentId: page.commitId, projectId: projectId, - pageId: head.pageId, + pageId: page.id, userId: userId_, project: projectName, title: pageTitle, diff --git a/browser/websocket/deletePage.ts b/browser/websocket/deletePage.ts index c486f80..97eb82c 100644 --- a/browser/websocket/deletePage.ts +++ b/browser/websocket/deletePage.ts @@ -20,7 +20,7 @@ export const deletePage = async ( options?: DeletePageOptions, ): Promise => { const [ - { pageId, commitId: parentId, persistent }, + { id: pageId, commitId: parentId, persistent }, projectId, userId, ] = await Promise.all([ diff --git a/browser/websocket/makeChanges.ts b/browser/websocket/makeChanges.ts index a64a604..0f1111f 100644 --- a/browser/websocket/makeChanges.ts +++ b/browser/websocket/makeChanges.ts @@ -1,19 +1,18 @@ import { diffToChanges } from "./diffToChanges.ts"; -import type { Line } from "../../deps/scrapbox.ts"; -import { Block, Node, parse } from "../../deps/scrapbox.ts"; +import { Block, Line, Node, parse } from "../../deps/scrapbox.ts"; +import { Page } from "../../deps/scrapbox-rest.ts"; import type { Change } from "../../deps/socket.ts"; -import type { HeadData } from "./pull.ts"; import { toTitleLc } from "../../title.ts"; import { parseYoutube } from "../../parser/youtube.ts"; export interface Init { userId: string; - head: HeadData; + page: Page; } export function* makeChanges( left: Pick[], right: string[], - { userId, head }: Init, + { userId, page }: Init, ): Generator { // 改行文字が入るのを防ぐ const right_ = right.flatMap((text) => text.split("\n")); @@ -24,7 +23,7 @@ export function* makeChanges( // titleの差分を入れる // 空ページの場合もタイトル変更commitを入れる - if (left[0].text !== right_[0] || !head.persistent) { + if (left[0].text !== right_[0] || !page.persistent) { yield { title: right_[0] }; } @@ -38,18 +37,18 @@ export function* makeChanges( // リンクと画像の差分を入れる const [links, projectLinks, image] = findLinksAndImage(right_.join("\n")); if ( - head.links.length !== links.length || - !head.links.every((link) => links.includes(link)) + page.links.length !== links.length || + !page.links.every((link) => links.includes(link)) ) { yield { links }; } if ( - head.projectLinks.length !== projectLinks.length || - !head.projectLinks.every((link) => projectLinks.includes(link)) + page.projectLinks.length !== projectLinks.length || + !page.projectLinks.every((link) => projectLinks.includes(link)) ) { yield { projectLinks }; } - if (head.image !== image) { + if (page.image !== image) { yield { image }; } } diff --git a/browser/websocket/patch.ts b/browser/websocket/patch.ts index ac0c2d8..c0c8693 100644 --- a/browser/websocket/patch.ts +++ b/browser/websocket/patch.ts @@ -2,14 +2,22 @@ import { Socket, socketIO, wrap } from "../../deps/socket.ts"; import { connect, disconnect } from "./socket.ts"; import { getProjectId, getUserId } from "./id.ts"; import { makeChanges } from "./makeChanges.ts"; -import { HeadData, pull } from "./pull.ts"; -import type { Line } from "../../deps/scrapbox-rest.ts"; +import { pull } from "./pull.ts"; +import { Line, Page } from "../../deps/scrapbox-rest.ts"; import { pushCommit, pushWithRetry } from "./_fetch.ts"; export interface PatchOptions { socket?: Socket; } +export interface PatchMetadata extends Page { + /** 書き換えを再試行した回数 + * + * 初回は`0`で、再試行するたびに増える + */ + retry: number; +} + /** ページ全体を書き換える * * serverには書き換え前後の差分だけを送信する @@ -24,12 +32,12 @@ export const patch = async ( title: string, update: ( lines: Line[], - metadata: HeadData, + metadata: PatchMetadata, ) => string[] | undefined | Promise, options?: PatchOptions, ): Promise => { const [ - head_, + page_, projectId, userId, ] = await Promise.all([ @@ -38,7 +46,7 @@ export const patch = async ( getUserId(), ]); - let head = head_; + let page = page_; const injectedSocket = options?.socket; const socket = injectedSocket ?? await socketIO(); @@ -47,9 +55,9 @@ export const patch = async ( const { request } = wrap(socket); // 3回retryする - for (let i = 0; i < 3; i++) { + for (let retry = 0; retry < 3; retry++) { try { - const pending = update(head.lines, head); + const pending = update(page.lines, { ...page, retry }); const newLines = pending instanceof Promise ? await pending : pending; if (!newLines) return; @@ -57,8 +65,8 @@ export const patch = async ( if (newLines.length === 0) { await pushWithRetry(request, [{ deleted: true }], { projectId, - pageId: head.pageId, - parentId: head.commitId, + pageId: page.id, + parentId: page.commitId, userId, project, title, @@ -66,24 +74,24 @@ export const patch = async ( } const changes = [ - ...makeChanges(head.lines, newLines, { userId, head }), + ...makeChanges(page.lines, newLines, { userId, page }), ]; await pushCommit(request, changes, { - parentId: head.commitId, + parentId: page.commitId, projectId, - pageId: head.pageId, + pageId: page.id, userId, }); break; } catch (_e: unknown) { - if (i === 2) { + if (retry === 2) { throw Error("Faild to retry pushing."); } console.log( "Faild to push a commit. Retry after pulling new commits", ); try { - head = await pull(project, title); + page = await pull(project, title); } catch (e: unknown) { throw e; } diff --git a/browser/websocket/pin.ts b/browser/websocket/pin.ts index 602fd31..cd81569 100644 --- a/browser/websocket/pin.ts +++ b/browser/websocket/pin.ts @@ -27,7 +27,7 @@ export const pin = async ( options?: PinOptions, ): Promise => { const [ - head, + page, projectId, userId, ] = await Promise.all([ @@ -37,12 +37,12 @@ export const pin = async ( ]); // 既にピン留めされている場合は何もしない - if (head.pin > 0 || (!head.persistent && !(options?.create ?? false))) return; + if (page.pin > 0 || (!page.persistent && !(options?.create ?? false))) return; const init = { - parentId: head.commitId, + parentId: page.commitId, projectId, - pageId: head.pageId, + pageId: page.id, userId, project, title, @@ -53,7 +53,7 @@ export const pin = async ( const { request } = wrap(socket); // タイトルのみのページを作る - if (!head.persistent) { + if (!page.persistent) { const commitId = await pushWithRetry(request, [{ title }], init); init.parentId = commitId; } @@ -79,7 +79,7 @@ export const unpin = async ( options: UnPinOptions, ): Promise => { const [ - head, + page, projectId, userId, ] = await Promise.all([ @@ -89,12 +89,12 @@ export const unpin = async ( ]); // 既にピンが外れているか、そもそも存在しないページの場合は何もしない - if (head.pin == 0 || !head.persistent) return; + if (page.pin == 0 || !page.persistent) return; const init = { - parentId: head.commitId, + parentId: page.commitId, projectId, - pageId: head.pageId, + pageId: page.id, userId, project, title, diff --git a/browser/websocket/pull.ts b/browser/websocket/pull.ts index d3996bc..619ec7a 100644 --- a/browser/websocket/pull.ts +++ b/browser/websocket/pull.ts @@ -1,37 +1,16 @@ -import type { Line } from "../../deps/scrapbox-rest.ts"; +import { Page } from "../../deps/scrapbox-rest.ts"; import { getPage } from "../../rest/pages.ts"; -export interface HeadData { - commitId: string; - pageId: string; - persistent: boolean; - image: string | null; - pin: number; - links: string[]; - projectLinks: string[]; - lines: Line[]; -} export const pull = async ( project: string, title: string, -): Promise => { +): Promise => { const result = await getPage(project, title); // TODO: 編集不可なページはStream購読だけ提供する if (!result.ok) { throw new Error(`You have no privilege of editing "/${project}/${title}".`); } - const { commitId, persistent, image, links, projectLinks, lines, id, pin } = - result.value; - return { - commitId, - pageId: id, - persistent, - image, - links, - projectLinks, - pin, - lines, - }; + return result.value; }; From 9cc726b73ad95f23ebc5747c3fffe884f555b719 Mon Sep 17 00:00:00 2001 From: takker99 <37929109+takker99@users.noreply.github.com> Date: Fri, 19 Apr 2024 11:14:29 +0900 Subject: [PATCH 2/4] style: deno fmt --- browser/websocket/_codeBlock.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/websocket/_codeBlock.ts b/browser/websocket/_codeBlock.ts index 50d6f57..845b1b0 100644 --- a/browser/websocket/_codeBlock.ts +++ b/browser/websocket/_codeBlock.ts @@ -1,5 +1,5 @@ import { Change, Socket, wrap } from "../../deps/socket.ts"; -import {Page} from "../../deps/scrapbox-rest.ts"; +import { Page } from "../../deps/scrapbox-rest.ts"; import { TinyCodeBlock } from "../../rest/getCodeBlocks.ts"; import { getProjectId, getUserId } from "./id.ts"; import { pushWithRetry } from "./_fetch.ts"; From fd9b85131549b53bc75df11d8349fd4c0fb648d4 Mon Sep 17 00:00:00 2001 From: takker99 <37929109+takker99@users.noreply.github.com> Date: Fri, 19 Apr 2024 11:23:06 +0900 Subject: [PATCH 3/4] style: deno lint --- browser/dom/click.ts | 4 ++-- browser/dom/extractCodeFiles.test.ts | 2 +- browser/dom/isHeightViewable.ts | 2 +- browser/dom/motion.ts | 2 +- browser/dom/open.ts | 4 ++-- rest/auth.ts | 8 ++++---- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/browser/dom/click.ts b/browser/dom/click.ts index fa85786..8253ca6 100644 --- a/browser/dom/click.ts +++ b/browser/dom/click.ts @@ -53,8 +53,8 @@ export const holdDown = async ( target: element, clientX: options.X, clientY: options.Y, - pageX: options.X + window.scrollX, - pageY: options.Y + window.scrollY, + pageX: options.X + globalThis.scrollX, + pageY: options.Y + globalThis.scrollY, }); const mouseOptions = { button: options.button ?? 0, diff --git a/browser/dom/extractCodeFiles.test.ts b/browser/dom/extractCodeFiles.test.ts index 724e42b..a9aa551 100644 --- a/browser/dom/extractCodeFiles.test.ts +++ b/browser/dom/extractCodeFiles.test.ts @@ -1,7 +1,7 @@ import { extractCodeFiles } from "./extractCodeFiles.ts"; import { Line } from "../../deps/scrapbox.ts"; import { assertSnapshot } from "../../deps/testing.ts"; -import sample from "./sample-lines1.json" assert { type: "json" }; +import sample from "./sample-lines1.json" with { type: "json" }; Deno.test("extractCodeFiles", async (t) => { await assertSnapshot( diff --git a/browser/dom/isHeightViewable.ts b/browser/dom/isHeightViewable.ts index a67c92f..eda56a9 100644 --- a/browser/dom/isHeightViewable.ts +++ b/browser/dom/isHeightViewable.ts @@ -4,5 +4,5 @@ export const isHeightViewable = (element: HTMLElement): boolean => { const { top, bottom } = element.getBoundingClientRect(); - return top >= 0 && bottom <= window.innerHeight; + return top >= 0 && bottom <= globalThis.innerHeight; }; diff --git a/browser/dom/motion.ts b/browser/dom/motion.ts index 9554e05..f0f5b5e 100644 --- a/browser/dom/motion.ts +++ b/browser/dom/motion.ts @@ -161,7 +161,7 @@ const getVisibleLineCount = (): number => { if (clientHeight === undefined) { throw Error("Could not find .line:last-of-type"); } - return Math.round(window.innerHeight / clientHeight); + return Math.round(globalThis.innerHeight / clientHeight); }; /** 半ページ上にスクロールする diff --git a/browser/dom/open.ts b/browser/dom/open.ts index 22dc0d3..d9c31da 100644 --- a/browser/dom/open.ts +++ b/browser/dom/open.ts @@ -58,14 +58,14 @@ export const open = ( options?.newTab !== false && (options?.newTab === true || project !== scrapbox.Project.name) ) { - window.open(url); + globalThis.open(url); return; } if ( options?.reload !== false && (options?.reload === true || project !== scrapbox.Project.name) ) { - window.open(url, "_self"); + globalThis.open(url, "_self"); return; } diff --git a/rest/auth.ts b/rest/auth.ts index 3fa37d1..fe54500 100644 --- a/rest/auth.ts +++ b/rest/auth.ts @@ -3,9 +3,9 @@ import { BaseOptions } from "./util.ts"; // scrapbox.io内なら`window._csrf`にCSRF tokenが入っている declare global { - interface Window { - _csrf?: string; - } + // globalThisに変数を宣言するには、`var`を使うしかない + // deno-lint-ignore no-var + var _csrf: string | undefined; } /** HTTP headerのCookieに入れる文字列を作る @@ -21,7 +21,7 @@ export const cookie = (sid: string): string => `connect.sid=${sid}`; export const getCSRFToken = async ( init?: BaseOptions, ): Promise => { - if (window._csrf) return window._csrf; + if (globalThis._csrf) return globalThis._csrf; const user = await getProfile(init); return user.csrfToken; From 9fb16d4a347a423e98b5bb9dc2ea9a5ca5dbeb05 Mon Sep 17 00:00:00 2001 From: takker99 <37929109+takker99@users.noreply.github.com> Date: Fri, 19 Apr 2024 11:24:37 +0900 Subject: [PATCH 4/4] test: Update Deno version in Github Actions --- .github/workflows/ci.yml | 2 +- .github/workflows/udd.yml | 2 +- rest/__snapshots__/pages.test.ts.snap | 4 ++-- rest/__snapshots__/project.test.ts.snap | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4770db..599bee3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: - uses: actions/checkout@v2 - uses: denoland/setup-deno@v1 with: - deno-version: "1.36.1" + deno-version: "v1.x" - name: Check fmt run: deno fmt --check - name: Run lint diff --git a/.github/workflows/udd.yml b/.github/workflows/udd.yml index b283cd6..353f088 100644 --- a/.github/workflows/udd.yml +++ b/.github/workflows/udd.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v2 - uses: denoland/setup-deno@v1 with: - deno-version: "1.36.1" + deno-version: "v1.x" - name: Update dependencies run: > deno run --allow-net --allow-read --allow-write=deps/ diff --git a/rest/__snapshots__/pages.test.ts.snap b/rest/__snapshots__/pages.test.ts.snap index 94010c7..6fcbedf 100644 --- a/rest/__snapshots__/pages.test.ts.snap +++ b/rest/__snapshots__/pages.test.ts.snap @@ -6,7 +6,7 @@ Request { headers: Headers {}, method: "GET", redirect: "follow", - url: "https://scrapbox.io/api/pages/takker/%E3%83%86%E3%82%B9%E3%83%88%E3%83%9A%E3%83%BC%E3%82%B8?followRe"... 9 more characters + url: "https://scrapbox.io/api/pages/takker/%E3%83%86%E3%82%B9%E3%83%88%E3%83%9A%E3%83%BC%E3%82%B8?followRename=true", } `; @@ -16,6 +16,6 @@ Request { headers: Headers {}, method: "GET", redirect: "follow", - url: "https://scrapbox.io/api/pages/takker?sort=updated" + url: "https://scrapbox.io/api/pages/takker?sort=updated", } `; diff --git a/rest/__snapshots__/project.test.ts.snap b/rest/__snapshots__/project.test.ts.snap index f9e5ebd..efe1fc7 100644 --- a/rest/__snapshots__/project.test.ts.snap +++ b/rest/__snapshots__/project.test.ts.snap @@ -6,7 +6,7 @@ Request { headers: Headers {}, method: "GET", redirect: "follow", - url: "https://scrapbox.io/api/projects/takker" + url: "https://scrapbox.io/api/projects/takker", } `; @@ -16,6 +16,6 @@ Request { headers: Headers {}, method: "GET", redirect: "follow", - url: "https://scrapbox.io/api/projects?ids=dummy-id1&ids=dummy-id2" + url: "https://scrapbox.io/api/projects?ids=dummy-id1&ids=dummy-id2", } `;