From cdba538d5ccfaef26456ed496e347ada0557f7eb Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Tue, 7 Feb 2023 08:01:23 +0900 Subject: [PATCH 01/39] =?UTF-8?q?BaseLine=E9=85=8D=E5=88=97=E3=81=8B?= =?UTF-8?q?=E3=82=89=E3=82=B3=E3=83=BC=E3=83=89=E3=83=96=E3=83=AD=E3=83=83?= =?UTF-8?q?=E3=82=AF=E3=82=92=E6=8A=BD=E5=87=BA=E3=81=99=E3=82=8B=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/getCodeBlocks.ts | 135 +++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 browser/websocket/getCodeBlocks.ts diff --git a/browser/websocket/getCodeBlocks.ts b/browser/websocket/getCodeBlocks.ts new file mode 100644 index 0000000..6a4c172 --- /dev/null +++ b/browser/websocket/getCodeBlocks.ts @@ -0,0 +1,135 @@ +import type { Line } from "../../deps/scrapbox-rest.ts"; +import { pull } from "./pull.ts"; + +/** pull()から取れる情報で構成したコードブロックの最低限の情報 */ +export interface TinyCodeBlock { + /** ファイル名 */ + filename: string; + + /** コードブロック内の強調表示に使う言語名 */ + lang: string; + + /** タイトル行 */ + titleLine: Line; + + /** コードブロックの中身(タイトル行を含まない) */ + bodyLines: Line[]; +} + +/** コードブロックのタイトル行の情報を保持しておくためのinterface */ +interface CodeTitle { + fileName: string; + lang: string; + indent: number; +} + +/** 他のページ(または取得済みの行データ)のコードブロックを全て取得する + * + * ファイル単位ではなく、コードブロック単位で返り値を生成する \ + * そのため、同じページ内に同名のコードブロックが複数あったとしても、分けた状態で返す + * + * @param target ページタイトルを指定するか、取得済みの行データを渡す + * @return コードブロックの配列 + */ +export const getCodeBlocks = async ( + target: { project: string; title: string } | { lines: Line[] }, +): Promise => { + const lines = await getLines(target); + const codeBlocks: TinyCodeBlock[] = []; + + let currentCode: CodeTitle & { isCodeBlock: boolean } = { + isCodeBlock: false, + fileName: "", + lang: "", + indent: 0, + }; + for (const line of lines) { + if (currentCode.isCodeBlock) { + const body = extractFromCodeBody(line.text, currentCode.indent); + if (body === null) { + currentCode.isCodeBlock = false; + continue; + } + codeBlocks[codeBlocks.length].bodyLines.push(line); + } else { + const matched = extractFromCodeTitle(line.text); + if (matched === null) { + currentCode.isCodeBlock = false; + continue; + } + currentCode = { isCodeBlock: true, ...matched }; + // codeBlocksへ追記する処理を書くのを忘れないように + codeBlocks.push({ + filename: currentCode.fileName, + lang: currentCode.lang, + titleLine: line, + bodyLines: [], + }); + } + } + return codeBlocks; +}; + +/** targetを`Line[]`に変換する */ +async function getLines( + target: { project: string; title: string } | { lines: Line[] }, +): Promise { + if ("lines" in target) { + return target.lines; + } else { + const head = await pull(target.project, target.title); + return head.lines; + } +} + +/** コードブロックのタイトル行から各種プロパティを抽出する + * + * @param lineText {string} 行テキスト + * @return `lineText`がコードタイトル行であれば`CodeTitle`を、そうでなければ`null`を返す + */ +function extractFromCodeTitle(lineText: string): CodeTitle | null { + const matched = lineText.match(/^(\s*)code:(.+?)(\(.+\)){0,1}\s*$/); + if (matched === null || matched.length < 2) return null; + const fileName = matched[2].trim(); + let lang = ""; + if (matched.length < 3) { + const ext = fileName.match(/.+\.(.*)$/); + if (ext === null) { + // `code:ext` + lang = fileName; + } else if (ext[1] === "") { + // `code:foo.`の形式はコードブロックとして成り立たないので排除する + return null; + } else { + // `code:foo.ext` + lang = fileName[1]; + } + } else { + lang = matched[3]; + } + return { + fileName: fileName, + lang: lang, + indent: matched[1].length, + }; +} + +/** 行テキストがコードブロックの一部であればそのテキストを、そうでなければnullを返す + * + * @param lineText {string} 行テキスト + * @param titleIndent {number} コードブロックのタイトル行のインデントの深さ + * @return `lineText`がコードブロックの一部であればそのテキストを、そうでなければ`null`を返す + */ +function extractFromCodeBody( + lineText: string, + titleIndent: number, +): string | null { + const matched = lineText.match(/^(\s*)(.*)$/); + if (matched === null || matched.length < 2) { + return null; + } + const indent = matched[1]; + const body = matched[2]; + if (indent.length <= titleIndent) return null; + return indent.slice(indent.length - titleIndent) + body; +} From b4bf4ffb217ce8b3b0cf0d7c3a27e79e9ad4ef7b Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Tue, 7 Feb 2023 17:22:30 +0900 Subject: [PATCH 02/39] =?UTF-8?q?=E9=80=94=E4=B8=AD=E8=A8=88=E7=AE=97?= =?UTF-8?q?=E3=81=AE=E8=A8=98=E8=BF=B0=E3=83=9F=E3=82=B9=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/getCodeBlocks.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/browser/websocket/getCodeBlocks.ts b/browser/websocket/getCodeBlocks.ts index 6a4c172..765607f 100644 --- a/browser/websocket/getCodeBlocks.ts +++ b/browser/websocket/getCodeBlocks.ts @@ -50,7 +50,7 @@ export const getCodeBlocks = async ( currentCode.isCodeBlock = false; continue; } - codeBlocks[codeBlocks.length].bodyLines.push(line); + codeBlocks[codeBlocks.length - 1].bodyLines.push(line); } else { const matched = extractFromCodeTitle(line.text); if (matched === null) { @@ -58,7 +58,6 @@ export const getCodeBlocks = async ( continue; } currentCode = { isCodeBlock: true, ...matched }; - // codeBlocksへ追記する処理を書くのを忘れないように codeBlocks.push({ filename: currentCode.fileName, lang: currentCode.lang, From 62a175384c5a7e175e243b5bf37228fb2389bb07 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Tue, 7 Feb 2023 20:12:05 +0900 Subject: [PATCH 03/39] =?UTF-8?q?TinyCodeBlock=E3=81=ABnextLine=E3=83=97?= =?UTF-8?q?=E3=83=AD=E3=83=91=E3=83=86=E3=82=A3=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/getCodeBlocks.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/browser/websocket/getCodeBlocks.ts b/browser/websocket/getCodeBlocks.ts index 765607f..0366578 100644 --- a/browser/websocket/getCodeBlocks.ts +++ b/browser/websocket/getCodeBlocks.ts @@ -14,6 +14,9 @@ export interface TinyCodeBlock { /** コードブロックの中身(タイトル行を含まない) */ bodyLines: Line[]; + + /** コードブロックの真下の行(無ければ`"_end"`) */ + nextLine: Line | "_end"; } /** コードブロックのタイトル行の情報を保持しておくためのinterface */ @@ -47,6 +50,7 @@ export const getCodeBlocks = async ( if (currentCode.isCodeBlock) { const body = extractFromCodeBody(line.text, currentCode.indent); if (body === null) { + codeBlocks[codeBlocks.length - 1].nextLine = line; currentCode.isCodeBlock = false; continue; } @@ -63,6 +67,7 @@ export const getCodeBlocks = async ( lang: currentCode.lang, titleLine: line, bodyLines: [], + nextLine: "_end", }); } } From 61ee5c6b864ee121eae5e38688713939a13eee83 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Tue, 7 Feb 2023 20:19:54 +0900 Subject: [PATCH 04/39] =?UTF-8?q?=E6=8B=A1=E5=BC=B5=E5=AD=90=E3=81=AE?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E3=81=8C=E3=81=86=E3=81=BE=E3=81=8F=E3=81=84?= =?UTF-8?q?=E3=81=A3=E3=81=A6=E3=81=84=E3=81=AA=E3=81=8B=E3=81=A3=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/getCodeBlocks.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/browser/websocket/getCodeBlocks.ts b/browser/websocket/getCodeBlocks.ts index 0366578..47b624c 100644 --- a/browser/websocket/getCodeBlocks.ts +++ b/browser/websocket/getCodeBlocks.ts @@ -93,10 +93,10 @@ async function getLines( */ function extractFromCodeTitle(lineText: string): CodeTitle | null { const matched = lineText.match(/^(\s*)code:(.+?)(\(.+\)){0,1}\s*$/); - if (matched === null || matched.length < 2) return null; + if (matched === null) return null; const fileName = matched[2].trim(); let lang = ""; - if (matched.length < 3) { + if (matched[3] === undefined) { const ext = fileName.match(/.+\.(.*)$/); if (ext === null) { // `code:ext` @@ -106,7 +106,7 @@ function extractFromCodeTitle(lineText: string): CodeTitle | null { return null; } else { // `code:foo.ext` - lang = fileName[1]; + lang = ext[1]; } } else { lang = matched[3]; From 3f9cdde72847f710ce53982e0c599b96c062e5b2 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Wed, 8 Feb 2023 17:31:30 +0900 Subject: [PATCH 05/39] =?UTF-8?q?=E3=82=8F=E3=81=8B=E3=82=8A=E3=81=AB?= =?UTF-8?q?=E3=81=8F=E3=81=84JSDoc=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/getCodeBlocks.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/websocket/getCodeBlocks.ts b/browser/websocket/getCodeBlocks.ts index 47b624c..c8523fd 100644 --- a/browser/websocket/getCodeBlocks.ts +++ b/browser/websocket/getCodeBlocks.ts @@ -31,7 +31,7 @@ interface CodeTitle { * ファイル単位ではなく、コードブロック単位で返り値を生成する \ * そのため、同じページ内に同名のコードブロックが複数あったとしても、分けた状態で返す * - * @param target ページタイトルを指定するか、取得済みの行データを渡す + * @param target ページタイトル、または取得済みの行データ * @return コードブロックの配列 */ export const getCodeBlocks = async ( From 6fea813657cae7af12908b198c32d96995595b7c Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Wed, 8 Feb 2023 17:31:53 +0900 Subject: [PATCH 06/39] =?UTF-8?q?getCodeBlocks=E3=82=92filter=E3=81=AB?= =?UTF-8?q?=E5=AF=BE=E5=BF=9C=E3=81=95=E3=81=9B=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/getCodeBlocks.ts | 33 ++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/browser/websocket/getCodeBlocks.ts b/browser/websocket/getCodeBlocks.ts index c8523fd..592c9f0 100644 --- a/browser/websocket/getCodeBlocks.ts +++ b/browser/websocket/getCodeBlocks.ts @@ -19,6 +19,14 @@ export interface TinyCodeBlock { nextLine: Line | "_end"; } +/** `getCodeBlocks()`に渡すfilter */ +export interface GetCodeBlocksFilter { + /** ファイル名 */ + filename: string; + /** syntax highlightに使用されている言語名 */ + lang: string; +} + /** コードブロックのタイトル行の情報を保持しておくためのinterface */ interface CodeTitle { fileName: string; @@ -32,16 +40,24 @@ interface CodeTitle { * そのため、同じページ内に同名のコードブロックが複数あったとしても、分けた状態で返す * * @param target ページタイトル、または取得済みの行データ + * @param filter 取得するコードブロックを絞り込むfilter * @return コードブロックの配列 */ export const getCodeBlocks = async ( target: { project: string; title: string } | { lines: Line[] }, + filter?: GetCodeBlocksFilter, ): Promise => { const lines = await getLines(target); const codeBlocks: TinyCodeBlock[] = []; - let currentCode: CodeTitle & { isCodeBlock: boolean } = { + let currentCode: CodeTitle & { + /** 読み取り中の行がコードブロックかどうか */ + isCodeBlock: boolean; + /** 読み取り中のコードブロックを保存するかどうか */ + isCollect: boolean; + } = { isCodeBlock: false, + isCollect: false, fileName: "", lang: "", indent: 0, @@ -54,6 +70,7 @@ export const getCodeBlocks = async ( currentCode.isCodeBlock = false; continue; } + if (!currentCode.isCollect) continue; codeBlocks[codeBlocks.length - 1].bodyLines.push(line); } else { const matched = extractFromCodeTitle(line.text); @@ -61,7 +78,9 @@ export const getCodeBlocks = async ( currentCode.isCodeBlock = false; continue; } - currentCode = { isCodeBlock: true, ...matched }; + const isCollect = isMatchFilter(matched, filter); + currentCode = { isCodeBlock: true, isCollect: isCollect, ...matched }; + if (!currentCode.isCollect) continue; codeBlocks.push({ filename: currentCode.fileName, lang: currentCode.lang, @@ -118,6 +137,16 @@ function extractFromCodeTitle(lineText: string): CodeTitle | null { }; } +/** コードタイトルのフィルターを検証する */ +function isMatchFilter( + codeTitle: CodeTitle, + filter?: GetCodeBlocksFilter, +): boolean { + if (filter?.filename && filter.filename !== codeTitle.fileName) return false; + if (filter?.lang && filter.lang !== codeTitle.lang) return false; + return true; +} + /** 行テキストがコードブロックの一部であればそのテキストを、そうでなければnullを返す * * @param lineText {string} 行テキスト From c530c2c26b31847c77049fa8c334d7158bb68ed1 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Wed, 8 Feb 2023 18:20:21 +0900 Subject: [PATCH 07/39] =?UTF-8?q?=E8=A8=AD=E5=AE=9A=E3=83=9F=E3=82=B9?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/getCodeBlocks.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/browser/websocket/getCodeBlocks.ts b/browser/websocket/getCodeBlocks.ts index 592c9f0..3ce14cc 100644 --- a/browser/websocket/getCodeBlocks.ts +++ b/browser/websocket/getCodeBlocks.ts @@ -22,9 +22,9 @@ export interface TinyCodeBlock { /** `getCodeBlocks()`に渡すfilter */ export interface GetCodeBlocksFilter { /** ファイル名 */ - filename: string; + filename?: string; /** syntax highlightに使用されている言語名 */ - lang: string; + lang?: string; } /** コードブロックのタイトル行の情報を保持しておくためのinterface */ From b04d8155519d703de8a0778ee6ac22e2563fc470 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Thu, 9 Feb 2023 00:51:47 +0900 Subject: [PATCH 08/39] =?UTF-8?q?=E3=83=AA=E3=83=86=E3=83=A9=E3=83=AB?= =?UTF-8?q?=E5=9E=8B=E3=81=AE=E4=B8=8D=E9=81=A9=E5=88=87=E3=81=AA=E4=BD=BF?= =?UTF-8?q?=E3=81=84=E6=96=B9=E3=81=8C=E3=81=95=E3=82=8C=E3=81=A6=E3=81=84?= =?UTF-8?q?=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/getCodeBlocks.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/browser/websocket/getCodeBlocks.ts b/browser/websocket/getCodeBlocks.ts index 3ce14cc..60ec575 100644 --- a/browser/websocket/getCodeBlocks.ts +++ b/browser/websocket/getCodeBlocks.ts @@ -15,8 +15,8 @@ export interface TinyCodeBlock { /** コードブロックの中身(タイトル行を含まない) */ bodyLines: Line[]; - /** コードブロックの真下の行(無ければ`"_end"`) */ - nextLine: Line | "_end"; + /** コードブロックの真下の行(無ければ`null`) */ + nextLine: Line | null; } /** `getCodeBlocks()`に渡すfilter */ @@ -86,7 +86,7 @@ export const getCodeBlocks = async ( lang: currentCode.lang, titleLine: line, bodyLines: [], - nextLine: "_end", + nextLine: null, }); } } From cb9d58ebfbb8f1ebe53394076c384ccbe342d774 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Thu, 9 Feb 2023 21:02:03 +0900 Subject: [PATCH 09/39] =?UTF-8?q?filter=E3=81=AE=E9=81=A9=E7=94=A8?= =?UTF-8?q?=E3=81=8C=E4=B8=8D=E5=AE=8C=E5=85=A8=E3=81=A0=E3=81=A3=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/getCodeBlocks.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/browser/websocket/getCodeBlocks.ts b/browser/websocket/getCodeBlocks.ts index 60ec575..cba3b2a 100644 --- a/browser/websocket/getCodeBlocks.ts +++ b/browser/websocket/getCodeBlocks.ts @@ -66,7 +66,9 @@ export const getCodeBlocks = async ( if (currentCode.isCodeBlock) { const body = extractFromCodeBody(line.text, currentCode.indent); if (body === null) { - codeBlocks[codeBlocks.length - 1].nextLine = line; + if (currentCode.isCollect) { + codeBlocks[codeBlocks.length - 1].nextLine = line; + } currentCode.isCodeBlock = false; continue; } From d38d4ff62edc4cef3486c132c253bfb61368659c Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Thu, 9 Feb 2023 23:00:37 +0900 Subject: [PATCH 10/39] =?UTF-8?q?`updateCodeFiles.ts`=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `api/code/:projectname/:pagetitle/:filename`で取得できるコードを直接書き換えることが出来る --- browser/websocket/updateCodeFile.ts | 265 ++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 browser/websocket/updateCodeFile.ts diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts new file mode 100644 index 0000000..3241afb --- /dev/null +++ b/browser/websocket/updateCodeFile.ts @@ -0,0 +1,265 @@ +import type { Line } from "../../deps/scrapbox-rest.ts"; +import { + Change, + DeleteCommit, + InsertCommit, + Socket, + socketIO, + UpdateCommit, + wrap, +} from "../../deps/socket.ts"; +import { HeadData, pull } from "./pull.ts"; +import { getCodeBlocks, TinyCodeBlock } from "./getCodeBlocks.ts"; +import { diffToChanges } from "./diffToChanges.ts"; +import { createNewLineId, getProjectId, getUserId } from "./id.ts"; +import { pushCommit } from "./_fetch.ts"; + +/** コードブロックの上書きに使う情報のinterface */ +export interface CodeFile { + /** ファイル名 */ + filename: string; + + /** コードブロックの中身(文字列のみ) */ + content: string | string[]; + + /** コードブロック内の強調表示に使う言語名(省略時はfilenameに含まれる拡張子を使用する) */ + lang?: string; +} + +/** updateCodeFile()に使われているオプション */ +export interface UpdateCodeFileOptions { + /** + * 指定したファイルが存在しなかった時、新しいコードブロックをページのどの位置に配置するか + * + * - `"notInsert"`(既定):存在しなかった場合は何もしない + * - `"top"`:ページ上部(タイトル行の真下) + * - `"bottom"`:ページ下部 + */ + insertPositionIfNotExist?: "top" | "bottom" | "notInsert"; + + /** WebSocketの通信に使うsocket */ + socket?: Socket; + + /** trueでデバッグ出力ON */ + debug?: boolean; +} + +/** REST API経由で取得できるようなコードファイルの中身をまるごと書き換える + * + * ファイルが存在していなかった場合、既定では何も書き換えない \ + * + * 対象と同じ名前のコードブロックが同じページの複数の行にまたがっていた場合も全て書き換える \ + * その際、書き換え後のコードをそれぞれのコードブロックへ分散させるが、それっぽく分けるだけで見た目などは保証しないので注意 + * + * @param codeFile 書き換え後のコードファイルの中身 + * @param project 書き換えたいページのプロジェクト名(Project urlの設定で使われている方) + * @param title 書き換えたいページのタイトル + * @param options [UpdateCodeFileOptions] その他の設定 + */ +export const updateCodeFile = async ( + codeFile: CodeFile, + project: string, + title: string, + options?: UpdateCodeFileOptions, +): Promise => { + /** optionsの既定値はこの中に入れる */ + const defaultOptions: Required = { + insertPositionIfNotExist: "notInsert", + socket: options?.socket ?? await socketIO(), + debug: false, + }; + const opt = options ? { ...defaultOptions, ...options } : defaultOptions; + const newCode = Array.isArray(codeFile.content) + ? codeFile.content + : codeFile.content.split("\n"); + const head = await pull(project, title); + const lines: Line[] = head.lines; + const codeBlocks = await getCodeBlocks({ + lines: lines, + }, { + filename: codeFile.filename, + }); + const codeBodies = flatCodeBodies(codeBlocks); + + if (codeBlocks.length <= 0) { + // 更新対象のコードブロックが存在していなかった場合は、新しいコードブロックを作成して終了する + if (opt.insertPositionIfNotExist === "notInsert") return; + const insertLineId = + opt.insertPositionIfNotExist === "top" && lines.length >= 1 + ? lines[1].id + : "_end"; + const commits = await makeCommitsNewCodeBlock( + codeFile, + insertLineId, + ); + if (codeBodies.length <= 0) { + await applyCommit(commits, head, project, opt.socket); + } + return; + } else if (codeBodies.length <= 0) { + // codeBodiesが無かった場合はdiffToChangesが例外を引き起こすので、その対策 + const insertLineId = codeBlocks[0].nextLine + ? codeBlocks[0].nextLine.id + : "_end"; + const commits = await makeCommitsNewCodeBlock( + codeFile, + insertLineId, + ); + if (codeBodies.length <= 0) { + await applyCommit(commits.splice(1), head, project, opt.socket); + } + return; + } + + const changes = [...diffToChanges( + codeBodies, + newCode, + { userId: await getUserId() }, + )]; + + // insert行のIDと各行のインデントを修正する + const commits = fixCommits(changes, codeBlocks); + + if (opt.debug) { + console.log("vvv original code Blocks vvv"); + console.log(codeBlocks); + console.log("vvv original code lines vvv"); + console.log(codeBodies); + console.log("vvv new codes vvv"); + console.log(newCode); + console.log("vvv commits vvv"); + console.log(commits); + } + + // 差分を送信 + await applyCommit(commits, head, project, opt.socket); + + if (!options?.socket) opt.socket.disconnect(); +}; + +/** TinyCodeBlocksの配列からコード本文をフラットな配列に格納して返す \ + * その際、コードブロックの左側に存在していたインデントは削除する + */ +function flatCodeBodies(codeBlocks: readonly TinyCodeBlock[]): Line[] { + return codeBlocks.map((block) => { + const title = block.titleLine.text; + const indent = title.length - title.trimStart().length + 1; + return block.bodyLines.map((body) => { + return { ...body, text: body.text.slice(indent) }; + }); + }).flat(); +} + +/** コミットを送信する一連の処理 */ +async function applyCommit( + commits: Change[], + head: HeadData, + projectName: string, + socket: Socket, +): ReturnType { + const [projectId, userId] = await Promise.all([ + getProjectId(projectName), + getUserId(), + ]); + + // 3回retryする + for (let i = 0; i < 3; i++) { + try { + // 差分を送信 + const { request } = wrap(socket); + const res = await pushCommit(request, commits, { + parentId: head.commitId, + projectId: projectId, + pageId: head.pageId, + userId: userId, + }); + return res; + } catch (_e: unknown) { + console.log( + "Faild to push a commit.", + ); + if (i === 2) break; + } + } + throw Error("Faild to retry pushing."); +} + +/** 新規コードブロックのコミットを作成する */ +async function makeCommitsNewCodeBlock( + code: CodeFile, + insertLineId: string, +): Promise { + const userId = await getUserId(); + const codeName = code.filename + (code.lang ? `(${code.lang})` : ""); + const codeBody = Array.isArray(code.content) + ? code.content + : code.content.split("\n"); + const commits: InsertCommit[] = [{ + _insert: insertLineId, + lines: { + id: createNewLineId(userId), + text: `code:${codeName}`, + }, + }]; + for (const bodyLine of codeBody) { + commits.push({ + _insert: insertLineId, + lines: { + id: createNewLineId(userId), + text: " " + bodyLine, + }, + }); + } + return commits; +} + +/** insert行のIDと各行のインデントを修正する */ +function fixCommits( + commits: (InsertCommit | UpdateCommit | DeleteCommit)[], + codeBlocks: TinyCodeBlock[], +) { + const idReplacePatterns: { + from: string; + to: string; + // indent: number; + }[] = (() => { + const patterns = []; + for (let i = 0; i < codeBlocks.length; i++) { + // コード本体の先頭ID -> 1つ前のコードブロックの真下の行のID + const currentCode = codeBlocks[i]; + const nextCode = codeBlocks[i + 1]; + if (!currentCode.nextLine) continue; + patterns.push({ + from: nextCode?.bodyLines[0].id ?? "_end", + to: currentCode.nextLine.id, + }); + } + return patterns; + })(); + for (const commit of commits) { + if ("_delete" in commit) continue; + else if ("_insert" in commit) { + // ID修正 + for (const pattern of idReplacePatterns) { + if (commit._insert !== pattern.from) continue; + commit._insert = pattern.to; + break; + } + } + // インデント挿入 + const belongBlock = codeBlocks.find((block) => { + const targetId = "_update" in commit ? commit._update : commit._insert; + if (block.bodyLines.some((e) => e.id === targetId)) return true; + if ("_update" in commit) return false; + if (targetId === block.nextLine?.id) return true; + return false; + }); + console.log("vvv belong vvv"); + console.log(belongBlock); + if (belongBlock === undefined) continue; + const titleText = belongBlock.titleLine.text; + const indent = titleText.length - titleText.trimStart().length + 1; + commit.lines.text = " ".repeat(indent) + commit.lines.text; + } + return commits; +} From e42ba95553413abddd246defab4b9b2eb4accbb6 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Thu, 9 Feb 2023 23:01:33 +0900 Subject: [PATCH 11/39] =?UTF-8?q?=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E3=81=AE=E5=89=8A=E9=99=A4=E3=81=97=E5=BF=98=E3=82=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/updateCodeFile.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts index 3241afb..62e239d 100644 --- a/browser/websocket/updateCodeFile.ts +++ b/browser/websocket/updateCodeFile.ts @@ -221,7 +221,6 @@ function fixCommits( const idReplacePatterns: { from: string; to: string; - // indent: number; }[] = (() => { const patterns = []; for (let i = 0; i < codeBlocks.length; i++) { @@ -254,8 +253,6 @@ function fixCommits( if (targetId === block.nextLine?.id) return true; return false; }); - console.log("vvv belong vvv"); - console.log(belongBlock); if (belongBlock === undefined) continue; const titleText = belongBlock.titleLine.text; const indent = titleText.length - titleText.trimStart().length + 1; From 626fb4a6aad301b5d7d9af2fcbae873ff4061095 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Fri, 10 Feb 2023 19:03:03 +0900 Subject: [PATCH 12/39] =?UTF-8?q?=E8=8B=A5=E5=B9=B2refactoring=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/updateCodeFile.ts | 42 +++++++++++------------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts index 62e239d..eba8299 100644 --- a/browser/websocket/updateCodeFile.ts +++ b/browser/websocket/updateCodeFile.ts @@ -12,7 +12,7 @@ import { HeadData, pull } from "./pull.ts"; import { getCodeBlocks, TinyCodeBlock } from "./getCodeBlocks.ts"; import { diffToChanges } from "./diffToChanges.ts"; import { createNewLineId, getProjectId, getUserId } from "./id.ts"; -import { pushCommit } from "./_fetch.ts"; +import { pushWithRetry } from "./_fetch.ts"; /** コードブロックの上書きに使う情報のinterface */ export interface CodeFile { @@ -93,7 +93,7 @@ export const updateCodeFile = async ( insertLineId, ); if (codeBodies.length <= 0) { - await applyCommit(commits, head, project, opt.socket); + await applyCommit(commits, head, project, title, opt.socket); } return; } else if (codeBodies.length <= 0) { @@ -106,7 +106,7 @@ export const updateCodeFile = async ( insertLineId, ); if (codeBodies.length <= 0) { - await applyCommit(commits.splice(1), head, project, opt.socket); + await applyCommit(commits.splice(1), head, project, title, opt.socket); } return; } @@ -132,7 +132,7 @@ export const updateCodeFile = async ( } // 差分を送信 - await applyCommit(commits, head, project, opt.socket); + await applyCommit(commits, head, project, title, opt.socket); if (!options?.socket) opt.socket.disconnect(); }; @@ -155,33 +155,23 @@ async function applyCommit( commits: Change[], head: HeadData, projectName: string, + pageTitle: string, socket: Socket, -): ReturnType { +): ReturnType { const [projectId, userId] = await Promise.all([ getProjectId(projectName), getUserId(), ]); - - // 3回retryする - for (let i = 0; i < 3; i++) { - try { - // 差分を送信 - const { request } = wrap(socket); - const res = await pushCommit(request, commits, { - parentId: head.commitId, - projectId: projectId, - pageId: head.pageId, - userId: userId, - }); - return res; - } catch (_e: unknown) { - console.log( - "Faild to push a commit.", - ); - if (i === 2) break; - } - } - throw Error("Faild to retry pushing."); + const { request } = wrap(socket); + return await pushWithRetry(request, commits, { + parentId: head.commitId, + projectId: projectId, + pageId: head.pageId, + userId: userId, + project: projectName, + title: pageTitle, + retry: 3, + }); } /** 新規コードブロックのコミットを作成する */ From c563d1531a24358bbbcb8352122f6c9e2695092a Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Fri, 10 Feb 2023 23:19:00 +0900 Subject: [PATCH 13/39] =?UTF-8?q?`updateCodeFile.ts`=E3=81=AE=E4=B8=80?= =?UTF-8?q?=E9=83=A8=E5=87=BD=E6=95=B0=E3=82=92`=5FcodeBlock.ts`=E3=81=B8?= =?UTF-8?q?=E5=88=86=E5=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit これらの函数はupdateCodeBlock.tsでも使用する可能性があるため --- browser/websocket/_codeBlock.ts | 58 +++++++++++++++++++++++++++ browser/websocket/updateCodeFile.ts | 61 ++--------------------------- 2 files changed, 61 insertions(+), 58 deletions(-) create mode 100644 browser/websocket/_codeBlock.ts diff --git a/browser/websocket/_codeBlock.ts b/browser/websocket/_codeBlock.ts new file mode 100644 index 0000000..6c28756 --- /dev/null +++ b/browser/websocket/_codeBlock.ts @@ -0,0 +1,58 @@ +import { Change, InsertCommit, Socket, wrap } from "../../deps/socket.ts"; +import { HeadData } from "./pull.ts"; +import { createNewLineId, getProjectId, getUserId } from "./id.ts"; +import { CodeFile } from "./updateCodeFile.ts"; +import { pushWithRetry } from "./_fetch.ts"; + +/** コミットを送信する一連の処理 */ +export async function applyCommit( + commits: Change[], + head: HeadData, + projectName: string, + pageTitle: string, + socket: Socket, +): ReturnType { + const [projectId, userId] = await Promise.all([ + getProjectId(projectName), + getUserId(), + ]); + const { request } = wrap(socket); + return await pushWithRetry(request, commits, { + parentId: head.commitId, + projectId: projectId, + pageId: head.pageId, + userId: userId, + project: projectName, + title: pageTitle, + retry: 3, + }); +} + +/** 新規コードブロックのコミットを作成する */ +export async function makeCommitsNewCodeBlock( + code: CodeFile, + insertLineId: string, +): Promise { + const userId = await getUserId(); + const codeName = code.filename + (code.lang ? `(${code.lang})` : ""); + const codeBody = Array.isArray(code.content) + ? code.content + : code.content.split("\n"); + const commits: InsertCommit[] = [{ + _insert: insertLineId, + lines: { + id: createNewLineId(userId), + text: `code:${codeName}`, + }, + }]; + for (const bodyLine of codeBody) { + commits.push({ + _insert: insertLineId, + lines: { + id: createNewLineId(userId), + text: " " + bodyLine, + }, + }); + } + return commits; +} diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts index eba8299..035d7f2 100644 --- a/browser/websocket/updateCodeFile.ts +++ b/browser/websocket/updateCodeFile.ts @@ -1,18 +1,16 @@ import type { Line } from "../../deps/scrapbox-rest.ts"; import { - Change, DeleteCommit, InsertCommit, Socket, socketIO, UpdateCommit, - wrap, } from "../../deps/socket.ts"; -import { HeadData, pull } from "./pull.ts"; +import { pull } from "./pull.ts"; import { getCodeBlocks, TinyCodeBlock } from "./getCodeBlocks.ts"; import { diffToChanges } from "./diffToChanges.ts"; -import { createNewLineId, getProjectId, getUserId } from "./id.ts"; -import { pushWithRetry } from "./_fetch.ts"; +import { getUserId } from "./id.ts"; +import { applyCommit, makeCommitsNewCodeBlock } from "./_codeBlock.ts"; /** コードブロックの上書きに使う情報のinterface */ export interface CodeFile { @@ -150,59 +148,6 @@ function flatCodeBodies(codeBlocks: readonly TinyCodeBlock[]): Line[] { }).flat(); } -/** コミットを送信する一連の処理 */ -async function applyCommit( - commits: Change[], - head: HeadData, - projectName: string, - pageTitle: string, - socket: Socket, -): ReturnType { - const [projectId, userId] = await Promise.all([ - getProjectId(projectName), - getUserId(), - ]); - const { request } = wrap(socket); - return await pushWithRetry(request, commits, { - parentId: head.commitId, - projectId: projectId, - pageId: head.pageId, - userId: userId, - project: projectName, - title: pageTitle, - retry: 3, - }); -} - -/** 新規コードブロックのコミットを作成する */ -async function makeCommitsNewCodeBlock( - code: CodeFile, - insertLineId: string, -): Promise { - const userId = await getUserId(); - const codeName = code.filename + (code.lang ? `(${code.lang})` : ""); - const codeBody = Array.isArray(code.content) - ? code.content - : code.content.split("\n"); - const commits: InsertCommit[] = [{ - _insert: insertLineId, - lines: { - id: createNewLineId(userId), - text: `code:${codeName}`, - }, - }]; - for (const bodyLine of codeBody) { - commits.push({ - _insert: insertLineId, - lines: { - id: createNewLineId(userId), - text: " " + bodyLine, - }, - }); - } - return commits; -} - /** insert行のIDと各行のインデントを修正する */ function fixCommits( commits: (InsertCommit | UpdateCommit | DeleteCommit)[], From e188921045291718288261c4a80c2a940d6d26e7 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Tue, 14 Feb 2023 01:24:04 +0900 Subject: [PATCH 14/39] =?UTF-8?q?refactoring=E3=82=92=E8=A9=A6=E3=81=BF?= =?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 | 15 +- browser/websocket/updateCodeFile.ts | 203 ++++++++++++++++------------ 2 files changed, 122 insertions(+), 96 deletions(-) diff --git a/browser/websocket/_codeBlock.ts b/browser/websocket/_codeBlock.ts index 6c28756..d665b30 100644 --- a/browser/websocket/_codeBlock.ts +++ b/browser/websocket/_codeBlock.ts @@ -29,30 +29,29 @@ export async function applyCommit( } /** 新規コードブロックのコミットを作成する */ -export async function makeCommitsNewCodeBlock( +export function* makeCommitsNewCodeBlock( code: CodeFile, insertLineId: string, -): Promise { - const userId = await getUserId(); + { userId }: { userId: string }, +): Generator { const codeName = code.filename + (code.lang ? `(${code.lang})` : ""); const codeBody = Array.isArray(code.content) ? code.content : code.content.split("\n"); - const commits: InsertCommit[] = [{ + yield { _insert: insertLineId, lines: { id: createNewLineId(userId), text: `code:${codeName}`, }, - }]; + }; for (const bodyLine of codeBody) { - commits.push({ + yield { _insert: insertLineId, lines: { id: createNewLineId(userId), text: " " + bodyLine, }, - }); + }; } - return commits; } diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts index 035d7f2..e01bc9f 100644 --- a/browser/websocket/updateCodeFile.ts +++ b/browser/websocket/updateCodeFile.ts @@ -8,8 +8,8 @@ import { } from "../../deps/socket.ts"; import { pull } from "./pull.ts"; import { getCodeBlocks, TinyCodeBlock } from "./getCodeBlocks.ts"; -import { diffToChanges } from "./diffToChanges.ts"; -import { getUserId } from "./id.ts"; +import { createNewLineId, getUserId } from "./id.ts"; +import { diff, toExtendedChanges } from "../../deps/onp.ts"; import { applyCommit, makeCommitsNewCodeBlock } from "./_codeBlock.ts"; /** コードブロックの上書きに使う情報のinterface */ @@ -35,10 +35,13 @@ export interface UpdateCodeFileOptions { */ insertPositionIfNotExist?: "top" | "bottom" | "notInsert"; + /** `true`の場合、コードブロック作成時に空行承り太郎(ページ末尾に必ず空行を設ける機能)を有効する(既定は`true`) */ + isInsertEmptyLineInTail?: boolean; + /** WebSocketの通信に使うsocket */ socket?: Socket; - /** trueでデバッグ出力ON */ + /** `true`でデバッグ出力ON */ debug?: boolean; } @@ -63,6 +66,7 @@ export const updateCodeFile = async ( /** optionsの既定値はこの中に入れる */ const defaultOptions: Required = { insertPositionIfNotExist: "notInsert", + isInsertEmptyLineInTail: true, socket: options?.socket ?? await socketIO(), debug: false, }; @@ -77,59 +81,22 @@ export const updateCodeFile = async ( }, { filename: codeFile.filename, }); - const codeBodies = flatCodeBodies(codeBlocks); - - if (codeBlocks.length <= 0) { - // 更新対象のコードブロックが存在していなかった場合は、新しいコードブロックを作成して終了する - if (opt.insertPositionIfNotExist === "notInsert") return; - const insertLineId = - opt.insertPositionIfNotExist === "top" && lines.length >= 1 - ? lines[1].id - : "_end"; - const commits = await makeCommitsNewCodeBlock( - codeFile, - insertLineId, - ); - if (codeBodies.length <= 0) { - await applyCommit(commits, head, project, title, opt.socket); - } - return; - } else if (codeBodies.length <= 0) { - // codeBodiesが無かった場合はdiffToChangesが例外を引き起こすので、その対策 - const insertLineId = codeBlocks[0].nextLine - ? codeBlocks[0].nextLine.id - : "_end"; - const commits = await makeCommitsNewCodeBlock( - codeFile, - insertLineId, - ); - if (codeBodies.length <= 0) { - await applyCommit(commits.splice(1), head, project, title, opt.socket); - } - return; - } - - const changes = [...diffToChanges( - codeBodies, - newCode, - { userId: await getUserId() }, - )]; - - // insert行のIDと各行のインデントを修正する - const commits = fixCommits(changes, codeBlocks); + const commits = [ + ...makeCommits(codeBlocks, codeFile, lines, { + ...opt, + userId: await getUserId(), + }), + ]; if (opt.debug) { console.log("vvv original code Blocks vvv"); console.log(codeBlocks); - console.log("vvv original code lines vvv"); - console.log(codeBodies); console.log("vvv new codes vvv"); console.log(newCode); console.log("vvv commits vvv"); console.log(commits); } - // 差分を送信 await applyCommit(commits, head, project, title, opt.socket); if (!options?.socket) opt.socket.disconnect(); @@ -148,50 +115,110 @@ function flatCodeBodies(codeBlocks: readonly TinyCodeBlock[]): Line[] { }).flat(); } -/** insert行のIDと各行のインデントを修正する */ -function fixCommits( - commits: (InsertCommit | UpdateCommit | DeleteCommit)[], +/** コードブロックの差分からコミットデータを作成する */ +function* makeCommits( codeBlocks: TinyCodeBlock[], -) { - const idReplacePatterns: { - from: string; - to: string; - }[] = (() => { - const patterns = []; - for (let i = 0; i < codeBlocks.length; i++) { - // コード本体の先頭ID -> 1つ前のコードブロックの真下の行のID - const currentCode = codeBlocks[i]; - const nextCode = codeBlocks[i + 1]; - if (!currentCode.nextLine) continue; - patterns.push({ - from: nextCode?.bodyLines[0].id ?? "_end", - to: currentCode.nextLine.id, - }); + codeFile: CodeFile, + lines: Line[], + { userId, insertPositionIfNotExist, isInsertEmptyLineInTail }: { + userId: string; + insertPositionIfNotExist: Required< + UpdateCodeFileOptions["insertPositionIfNotExist"] + >; + isInsertEmptyLineInTail: Required< + UpdateCodeFileOptions["isInsertEmptyLineInTail"] + >; + }, +): Generator { + function makeIndent(codeBlock: TinyCodeBlock): string { + const title = codeBlock.titleLine.text; + const count = title.length - title.trimStart().length + 1; + return " ".repeat(count); + } + + const codeBodies = flatCodeBodies(codeBlocks); + if (codeBodies.length <= 0) { + // ページ内にコードブロックが無かった場合は新しく作成して終了する + if (insertPositionIfNotExist === "notInsert") return; + const insertLineId = insertPositionIfNotExist === "top" && lines.length > 1 + ? lines[1].id + : "_end"; + const commits = makeCommitsNewCodeBlock( + codeFile, + insertLineId, + { userId }, + ); + let isInsertBottom = false; + for (const commit of commits) { + if (commit._insert == "_end") isInsertBottom = true; + yield commit; } - return patterns; - })(); - for (const commit of commits) { - if ("_delete" in commit) continue; - else if ("_insert" in commit) { - // ID修正 - for (const pattern of idReplacePatterns) { - if (commit._insert !== pattern.from) continue; - commit._insert = pattern.to; - break; - } + if (isInsertBottom && isInsertEmptyLineInTail) { + // 空行承り太郎 + yield { + _insert: "_end", + lines: { + id: createNewLineId(userId), + text: "", + }, + }; } - // インデント挿入 - const belongBlock = codeBlocks.find((block) => { - const targetId = "_update" in commit ? commit._update : commit._insert; - if (block.bodyLines.some((e) => e.id === targetId)) return true; - if ("_update" in commit) return false; - if (targetId === block.nextLine?.id) return true; - return false; - }); - if (belongBlock === undefined) continue; - const titleText = belongBlock.titleLine.text; - const indent = titleText.length - titleText.trimStart().length + 1; - commit.lines.text = " ".repeat(indent) + commit.lines.text; + return; + } + + // 差分を求める + const { buildSES } = diff( + codeBodies.map((e) => e.text), + Array.isArray(codeFile.content) + ? codeFile.content + : codeFile.content.split("\n"), + ); + let lineNo = 0; + for (const change of toExtendedChanges(buildSES())) { + // 差分からcommitを作成 + const { lineId, codeIndex } = + ((): { lineId: string; codeIndex: number } => { + if (lineNo >= codeBodies.length) { + const index = codeBlocks.length - 1; + return { + lineId: codeBlocks[index].nextLine?.id ?? "_end", + codeIndex: index, + }; + } + return { + lineId: codeBodies[lineNo].id, + codeIndex: codeBlocks.findIndex((e0) => + e0.bodyLines.some((e1) => e1.id == codeBodies[lineNo].id) + ), + }; + })(); + const codeBlock = codeBlocks[codeIndex]; + if (change.type == "added") { + const codeBlockInsert = + lineId == codeBlock.bodyLines[0].id && codeIndex >= 1 + ? codeBlocks[codeIndex - 1] + : codeBlocks[codeIndex]; + yield { + _insert: codeBlockInsert.nextLine?.id ?? "_end", + lines: { + id: createNewLineId(userId), + text: makeIndent(codeBlockInsert) + change.value, + }, + }; + continue; + } else if (change.type == "deleted") { + yield { + _delete: lineId, + lines: -1, + }; + } else if (change.type == "replaced") { + yield { + _update: lineId, + lines: { + text: makeIndent(codeBlock) + change.value, + }, + }; + } + lineNo++; } - return commits; } From 59b88ffd5404bc12d34dc0f8092089ebe8da8447 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Tue, 14 Feb 2023 02:49:44 +0900 Subject: [PATCH 15/39] =?UTF-8?q?=E6=97=A2=E5=AD=98=E3=81=AE=E3=82=B3?= =?UTF-8?q?=E3=83=BC=E3=83=89=E3=83=96=E3=83=AD=E3=83=83=E3=82=AF=E3=81=8C?= =?UTF-8?q?=E7=84=A1=E3=81=8B=E3=81=A3=E3=81=9F=E9=9A=9B=E3=81=AB=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E3=81=99=E3=82=8B=E3=82=B3=E3=83=BC=E3=83=89=E3=82=92?= =?UTF-8?q?=E6=9C=80=E5=B0=8F=E9=99=90=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/updateCodeFile.ts | 84 +++++++++++++++++------------ 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts index e01bc9f..0e8d958 100644 --- a/browser/websocket/updateCodeFile.ts +++ b/browser/websocket/updateCodeFile.ts @@ -10,7 +10,7 @@ import { pull } from "./pull.ts"; import { getCodeBlocks, TinyCodeBlock } from "./getCodeBlocks.ts"; import { createNewLineId, getUserId } from "./id.ts"; import { diff, toExtendedChanges } from "../../deps/onp.ts"; -import { applyCommit, makeCommitsNewCodeBlock } from "./_codeBlock.ts"; +import { applyCommit } from "./_codeBlock.ts"; /** コードブロックの上書きに使う情報のinterface */ export interface CodeFile { @@ -117,7 +117,7 @@ function flatCodeBodies(codeBlocks: readonly TinyCodeBlock[]): Line[] { /** コードブロックの差分からコミットデータを作成する */ function* makeCommits( - codeBlocks: TinyCodeBlock[], + _codeBlocks: readonly TinyCodeBlock[], codeFile: CodeFile, lines: Line[], { userId, insertPositionIfNotExist, isInsertEmptyLineInTail }: { @@ -130,40 +130,38 @@ function* makeCommits( >; }, ): Generator { - function makeIndent(codeBlock: TinyCodeBlock): string { + function makeIndent(codeBlock: Pick): string { const title = codeBlock.titleLine.text; const count = title.length - title.trimStart().length + 1; return " ".repeat(count); } - const codeBodies = flatCodeBodies(codeBlocks); - if (codeBodies.length <= 0) { - // ページ内にコードブロックが無かった場合は新しく作成して終了する + const codeBlocks: Pick< + TinyCodeBlock, + "titleLine" | "bodyLines" | "nextLine" + >[] = [..._codeBlocks]; + const codeBodies = flatCodeBodies(_codeBlocks); + if (codeBlocks.length <= 0) { + // ページ内にコードブロックが無かった場合は新しく作成 if (insertPositionIfNotExist === "notInsert") return; - const insertLineId = insertPositionIfNotExist === "top" && lines.length > 1 - ? lines[1].id - : "_end"; - const commits = makeCommitsNewCodeBlock( - codeFile, - insertLineId, - { userId }, - ); - let isInsertBottom = false; - for (const commit of commits) { - if (commit._insert == "_end") isInsertBottom = true; - yield commit; - } - if (isInsertBottom && isInsertEmptyLineInTail) { - // 空行承り太郎 - yield { - _insert: "_end", - lines: { - id: createNewLineId(userId), - text: "", - }, - }; - } - return; + const nextLine = insertPositionIfNotExist === "top" && lines.length > 1 + ? lines[1] + : null; + const title = { + // コードブロックのタイトル行 + _insert: nextLine?.id ?? "_end", + lines: { + id: createNewLineId(userId), + text: makeCodeBlockTitle(codeFile), + }, + }; + yield title; + // 新しく作成したコードブロックの情報を追記 + codeBlocks.push({ + titleLine: { ...title.lines, userId, created: -1, updated: -1 }, + bodyLines: [], + nextLine: nextLine, + }); } // 差分を求める @@ -174,6 +172,7 @@ function* makeCommits( : codeFile.content.split("\n"), ); let lineNo = 0; + let isInsertBottom = false; for (const change of toExtendedChanges(buildSES())) { // 差分からcommitを作成 const { lineId, codeIndex } = @@ -194,17 +193,19 @@ function* makeCommits( })(); const codeBlock = codeBlocks[codeIndex]; if (change.type == "added") { - const codeBlockInsert = - lineId == codeBlock.bodyLines[0].id && codeIndex >= 1 + const insertCodeBlock = + lineId == codeBlock.bodyLines[0]?.id && codeIndex >= 1 ? codeBlocks[codeIndex - 1] : codeBlocks[codeIndex]; + const id = insertCodeBlock?.nextLine?.id ?? "_end"; yield { - _insert: codeBlockInsert.nextLine?.id ?? "_end", + _insert: id, lines: { id: createNewLineId(userId), - text: makeIndent(codeBlockInsert) + change.value, + text: makeIndent(insertCodeBlock) + change.value, }, }; + if (id == "_end") isInsertBottom = true; continue; } else if (change.type == "deleted") { yield { @@ -221,4 +222,19 @@ function* makeCommits( } lineNo++; } + if (isInsertBottom && isInsertEmptyLineInTail) { + // 空行承り太郎 + yield { + _insert: "_end", + lines: { + id: createNewLineId(userId), + text: "", + }, + }; + } +} + +function makeCodeBlockTitle(code: CodeFile) { + const codeName = code.filename + (code.lang ? `(${code.lang})` : ""); + return `code:${codeName}`; } From 821844cde18446099ffbb1e7b05cb23a9ae1cbe0 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Tue, 14 Feb 2023 03:27:28 +0900 Subject: [PATCH 16/39] =?UTF-8?q?JSDoc=E3=81=AE=E4=B8=80=E8=B2=AB=E6=80=A7?= =?UTF-8?q?=E3=81=AE=E3=81=AA=E3=81=95=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/updateCodeFile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts index 0e8d958..87f2c8f 100644 --- a/browser/websocket/updateCodeFile.ts +++ b/browser/websocket/updateCodeFile.ts @@ -55,7 +55,7 @@ export interface UpdateCodeFileOptions { * @param codeFile 書き換え後のコードファイルの中身 * @param project 書き換えたいページのプロジェクト名(Project urlの設定で使われている方) * @param title 書き換えたいページのタイトル - * @param options [UpdateCodeFileOptions] その他の設定 + * @param options その他の設定 */ export const updateCodeFile = async ( codeFile: CodeFile, From 42cea0042a248152d4687d07c8789cc61fe14b6c Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Tue, 14 Feb 2023 19:19:25 +0900 Subject: [PATCH 17/39] =?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=89=E3=83=96?= =?UTF-8?q?=E3=83=AD=E3=83=83=E3=82=AF=E6=9C=AC=E4=BD=93=E3=81=AE=E3=82=A4?= =?UTF-8?q?=E3=83=B3=E3=83=87=E3=83=B3=E3=83=88=E8=A8=88=E7=AE=97=E5=87=A6?= =?UTF-8?q?=E7=90=86=E3=82=92=E5=88=86=E3=81=91=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/_codeBlock.ts | 38 +++++++---------------------- browser/websocket/updateCodeFile.ts | 9 +++---- 2 files changed, 12 insertions(+), 35 deletions(-) diff --git a/browser/websocket/_codeBlock.ts b/browser/websocket/_codeBlock.ts index d665b30..c719ad5 100644 --- a/browser/websocket/_codeBlock.ts +++ b/browser/websocket/_codeBlock.ts @@ -1,8 +1,8 @@ -import { Change, InsertCommit, Socket, wrap } from "../../deps/socket.ts"; +import { Change, Socket, wrap } from "../../deps/socket.ts"; import { HeadData } from "./pull.ts"; -import { createNewLineId, getProjectId, getUserId } from "./id.ts"; -import { CodeFile } from "./updateCodeFile.ts"; +import { getProjectId, getUserId } from "./id.ts"; import { pushWithRetry } from "./_fetch.ts"; +import { TinyCodeBlock } from "./getCodeBlocks.ts"; /** コミットを送信する一連の処理 */ export async function applyCommit( @@ -28,30 +28,10 @@ export async function applyCommit( }); } -/** 新規コードブロックのコミットを作成する */ -export function* makeCommitsNewCodeBlock( - code: CodeFile, - insertLineId: string, - { userId }: { userId: string }, -): Generator { - const codeName = code.filename + (code.lang ? `(${code.lang})` : ""); - const codeBody = Array.isArray(code.content) - ? code.content - : code.content.split("\n"); - yield { - _insert: insertLineId, - lines: { - id: createNewLineId(userId), - text: `code:${codeName}`, - }, - }; - for (const bodyLine of codeBody) { - yield { - _insert: insertLineId, - lines: { - id: createNewLineId(userId), - text: " " + bodyLine, - }, - }; - } +/** コードブロック本文のインデント数を計算する */ +export function countBodyIndent( + codeBlock: Pick, +): number { + return codeBlock.titleLine.text.length - + codeBlock.titleLine.text.trimStart().length + 1; } diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts index 87f2c8f..2ede039 100644 --- a/browser/websocket/updateCodeFile.ts +++ b/browser/websocket/updateCodeFile.ts @@ -10,7 +10,7 @@ import { pull } from "./pull.ts"; import { getCodeBlocks, TinyCodeBlock } from "./getCodeBlocks.ts"; import { createNewLineId, getUserId } from "./id.ts"; import { diff, toExtendedChanges } from "../../deps/onp.ts"; -import { applyCommit } from "./_codeBlock.ts"; +import { applyCommit, countBodyIndent } from "./_codeBlock.ts"; /** コードブロックの上書きに使う情報のinterface */ export interface CodeFile { @@ -107,8 +107,7 @@ export const updateCodeFile = async ( */ function flatCodeBodies(codeBlocks: readonly TinyCodeBlock[]): Line[] { return codeBlocks.map((block) => { - const title = block.titleLine.text; - const indent = title.length - title.trimStart().length + 1; + const indent = countBodyIndent(block); return block.bodyLines.map((body) => { return { ...body, text: body.text.slice(indent) }; }); @@ -131,9 +130,7 @@ function* makeCommits( }, ): Generator { function makeIndent(codeBlock: Pick): string { - const title = codeBlock.titleLine.text; - const count = title.length - title.trimStart().length + 1; - return " ".repeat(count); + return " ".repeat(countBodyIndent(codeBlock)); } const codeBlocks: Pick< From 488d2883b4de21e86d6f772b552cffc37034f29d Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Tue, 14 Feb 2023 23:57:29 +0900 Subject: [PATCH 18/39] =?UTF-8?q?TinyCodeBlock=E3=81=AE=E6=8B=A1=E5=BC=B5?= =?UTF-8?q?=E3=81=A8=E3=80=81=E3=81=9D=E3=82=8C=E3=81=AB=E4=BC=B4=E3=81=86?= =?UTF-8?q?updateCodeFile=E3=81=AE=E7=A0=B4=E5=A3=8A=E7=9A=84=E5=A4=89?= =?UTF-8?q?=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/getCodeBlocks.ts | 17 ++++++++++++----- browser/websocket/updateCodeFile.ts | 2 ++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/browser/websocket/getCodeBlocks.ts b/browser/websocket/getCodeBlocks.ts index cba3b2a..1608e21 100644 --- a/browser/websocket/getCodeBlocks.ts +++ b/browser/websocket/getCodeBlocks.ts @@ -17,6 +17,9 @@ export interface TinyCodeBlock { /** コードブロックの真下の行(無ければ`null`) */ nextLine: Line | null; + + /** コードブロックが存在するページの情報 */ + pageInfo: { projectName: string; pageTitle: string }; } /** `getCodeBlocks()`に渡すfilter */ @@ -39,12 +42,12 @@ interface CodeTitle { * ファイル単位ではなく、コードブロック単位で返り値を生成する \ * そのため、同じページ内に同名のコードブロックが複数あったとしても、分けた状態で返す * - * @param target ページタイトル、または取得済みの行データ + * @param target 取得するページの情報(linesを渡せば内部のページ取得処理を省略する) * @param filter 取得するコードブロックを絞り込むfilter * @return コードブロックの配列 */ export const getCodeBlocks = async ( - target: { project: string; title: string } | { lines: Line[] }, + target: { project: string; title: string; lines?: Line[] }, filter?: GetCodeBlocksFilter, ): Promise => { const lines = await getLines(target); @@ -89,6 +92,10 @@ export const getCodeBlocks = async ( titleLine: line, bodyLines: [], nextLine: null, + pageInfo: { + projectName: target.project, + pageTitle: target.title, + }, }); } } @@ -97,9 +104,9 @@ export const getCodeBlocks = async ( /** targetを`Line[]`に変換する */ async function getLines( - target: { project: string; title: string } | { lines: Line[] }, + target: { project: string; title: string; lines?: Line[] }, ): Promise { - if ("lines" in target) { + if (target.lines !== undefined) { return target.lines; } else { const head = await pull(target.project, target.title); @@ -127,7 +134,7 @@ function extractFromCodeTitle(lineText: string): CodeTitle | null { return null; } else { // `code:foo.ext` - lang = ext[1]; + lang = ext[1].slice(1, -1).trim(); } } else { lang = matched[3]; diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts index 2ede039..33a294b 100644 --- a/browser/websocket/updateCodeFile.ts +++ b/browser/websocket/updateCodeFile.ts @@ -77,6 +77,8 @@ export const updateCodeFile = async ( const head = await pull(project, title); const lines: Line[] = head.lines; const codeBlocks = await getCodeBlocks({ + project, + title, lines: lines, }, { filename: codeFile.filename, From 03240adad961ddafa1f7de58b5273dae6c7fd3df Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Wed, 15 Feb 2023 01:41:13 +0900 Subject: [PATCH 19/39] =?UTF-8?q?=E6=8C=87=E5=AE=9A=E3=81=97=E3=81=9F?= =?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=89=E3=83=96=E3=83=AD=E3=83=83=E3=82=AF?= =?UTF-8?q?=E3=82=92=E6=9B=B8=E3=81=8D=E6=8F=9B=E3=81=88=E3=82=89=E3=82=8C?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/_codeBlock.ts | 46 +++++++- browser/websocket/getCodeBlocks.ts | 46 +------- browser/websocket/updateCodeBlock.ts | 156 +++++++++++++++++++++++++++ browser/websocket/updateCodeFile.ts | 14 +++ 4 files changed, 217 insertions(+), 45 deletions(-) create mode 100644 browser/websocket/updateCodeBlock.ts diff --git a/browser/websocket/_codeBlock.ts b/browser/websocket/_codeBlock.ts index c719ad5..9467bfa 100644 --- a/browser/websocket/_codeBlock.ts +++ b/browser/websocket/_codeBlock.ts @@ -4,6 +4,13 @@ import { getProjectId, getUserId } from "./id.ts"; import { pushWithRetry } from "./_fetch.ts"; import { TinyCodeBlock } from "./getCodeBlocks.ts"; +/** コードブロックのタイトル行の情報を保持しておくためのinterface */ +export interface CodeTitle { + filename: string; + lang: string; + indent: number; +} + /** コミットを送信する一連の処理 */ export async function applyCommit( commits: Change[], @@ -11,23 +18,56 @@ export async function applyCommit( projectName: string, pageTitle: string, socket: Socket, + userId?: string, ): ReturnType { - const [projectId, userId] = await Promise.all([ + const [projectId, userId_] = await Promise.all([ getProjectId(projectName), - getUserId(), + userId ?? getUserId(), ]); const { request } = wrap(socket); return await pushWithRetry(request, commits, { parentId: head.commitId, projectId: projectId, pageId: head.pageId, - userId: userId, + userId: userId_, project: projectName, title: pageTitle, retry: 3, }); } +/** コードブロックのタイトル行から各種プロパティを抽出する + * + * @param lineText {string} 行テキスト + * @return `lineText`がコードタイトル行であれば`CodeTitle`を、そうでなければ`null`を返す + */ +export function extractFromCodeTitle(lineText: string): CodeTitle | null { + const matched = lineText.match(/^(\s*)code:(.+?)(\(.+\)){0,1}\s*$/); + if (matched === null) return null; + const filename = matched[2].trim(); + let lang = ""; + if (matched[3] === undefined) { + const ext = filename.match(/.+\.(.*)$/); + if (ext === null) { + // `code:ext` + lang = filename; + } else if (ext[1] === "") { + // `code:foo.`の形式はコードブロックとして成り立たないので排除する + return null; + } else { + // `code:foo.ext` + lang = ext[1].trim(); + } + } else { + lang = matched[3].slice(1, -1); + } + return { + filename: filename, + lang: lang, + indent: matched[1].length, + }; +} + /** コードブロック本文のインデント数を計算する */ export function countBodyIndent( codeBlock: Pick, diff --git a/browser/websocket/getCodeBlocks.ts b/browser/websocket/getCodeBlocks.ts index 1608e21..7f3eca0 100644 --- a/browser/websocket/getCodeBlocks.ts +++ b/browser/websocket/getCodeBlocks.ts @@ -1,5 +1,6 @@ import type { Line } from "../../deps/scrapbox-rest.ts"; import { pull } from "./pull.ts"; +import { CodeTitle, extractFromCodeTitle } from "./_codeBlock.ts"; /** pull()から取れる情報で構成したコードブロックの最低限の情報 */ export interface TinyCodeBlock { @@ -30,13 +31,6 @@ export interface GetCodeBlocksFilter { lang?: string; } -/** コードブロックのタイトル行の情報を保持しておくためのinterface */ -interface CodeTitle { - fileName: string; - lang: string; - indent: number; -} - /** 他のページ(または取得済みの行データ)のコードブロックを全て取得する * * ファイル単位ではなく、コードブロック単位で返り値を生成する \ @@ -61,7 +55,7 @@ export const getCodeBlocks = async ( } = { isCodeBlock: false, isCollect: false, - fileName: "", + filename: "", lang: "", indent: 0, }; @@ -87,7 +81,7 @@ export const getCodeBlocks = async ( currentCode = { isCodeBlock: true, isCollect: isCollect, ...matched }; if (!currentCode.isCollect) continue; codeBlocks.push({ - filename: currentCode.fileName, + filename: currentCode.filename, lang: currentCode.lang, titleLine: line, bodyLines: [], @@ -114,44 +108,12 @@ async function getLines( } } -/** コードブロックのタイトル行から各種プロパティを抽出する - * - * @param lineText {string} 行テキスト - * @return `lineText`がコードタイトル行であれば`CodeTitle`を、そうでなければ`null`を返す - */ -function extractFromCodeTitle(lineText: string): CodeTitle | null { - const matched = lineText.match(/^(\s*)code:(.+?)(\(.+\)){0,1}\s*$/); - if (matched === null) return null; - const fileName = matched[2].trim(); - let lang = ""; - if (matched[3] === undefined) { - const ext = fileName.match(/.+\.(.*)$/); - if (ext === null) { - // `code:ext` - lang = fileName; - } else if (ext[1] === "") { - // `code:foo.`の形式はコードブロックとして成り立たないので排除する - return null; - } else { - // `code:foo.ext` - lang = ext[1].slice(1, -1).trim(); - } - } else { - lang = matched[3]; - } - return { - fileName: fileName, - lang: lang, - indent: matched[1].length, - }; -} - /** コードタイトルのフィルターを検証する */ function isMatchFilter( codeTitle: CodeTitle, filter?: GetCodeBlocksFilter, ): boolean { - if (filter?.filename && filter.filename !== codeTitle.fileName) return false; + if (filter?.filename && filter.filename !== codeTitle.filename) return false; if (filter?.lang && filter.lang !== codeTitle.lang) return false; return true; } diff --git a/browser/websocket/updateCodeBlock.ts b/browser/websocket/updateCodeBlock.ts new file mode 100644 index 0000000..ddbccec --- /dev/null +++ b/browser/websocket/updateCodeBlock.ts @@ -0,0 +1,156 @@ +import { Line } from "../../deps/scrapbox-rest.ts"; +import { + DeleteCommit, + InsertCommit, + Socket, + socketIO, + UpdateCommit, +} from "../../deps/socket.ts"; +import { diffToChanges } from "./diffToChanges.ts"; +import { TinyCodeBlock } from "./getCodeBlocks.ts"; +import { getUserId } from "./id.ts"; +import { pull } from "./pull.ts"; +import { CodeFile, isCodeFile } from "./updateCodeFile.ts"; +import { + applyCommit, + countBodyIndent, + extractFromCodeTitle, +} from "./_codeBlock.ts"; + +export interface UpdateCodeBlockOptions { + /** WebSocketの通信に使うsocket */ + socket?: Socket; + + /** `true`でデバッグ出力ON */ + debug?: boolean; +} + +/** コードブロックの中身を更新する + * + * @param newCode 更新後のコードブロック + * @param target 更新対象のコードブロック + * @param project 更新対象のコードブロックが存在するプロジェクト名 + */ +export const updateCodeBlock = async ( + newCode: string | string[] | CodeFile, + target: TinyCodeBlock, + options?: UpdateCodeBlockOptions, +) => { + /** optionsの既定値はこの中に入れる */ + const defaultOptions: Required = { + socket: options?.socket ?? await socketIO(), + debug: false, + }; + const opt = options ? { ...defaultOptions, ...options } : defaultOptions; + const { projectName, pageTitle } = target.pageInfo; + const [ + head, + userId, + ] = await Promise.all([ + pull(projectName, pageTitle), + getUserId(), + ]); + const newCodeBody = getCodeBody(newCode); + const bodyIndent = countBodyIndent(target); + const oldCodeWithoutIndent: Line[] = target.bodyLines.map((e) => { + return { ...e, text: e.text.slice(bodyIndent) }; + }); + + const diffGenerator = diffToChanges(oldCodeWithoutIndent, newCodeBody, { + userId, + }); + const commits = [...fixCommits([...diffGenerator], target)]; + if (isCodeFile(newCode)) { + const titleCommit = makeTitleChangeCommit(newCode, target); + if (titleCommit) commits.push(titleCommit); + } + + if (opt.debug) { + console.log("vvv original code block vvv"); + console.log(target); + console.log("vvv new codes vvv"); + console.log(newCode); + console.log("vvv commits vvv"); + console.log(commits); + } + + await applyCommit(commits, head, projectName, pageTitle, opt.socket, userId); + if (!options?.socket) opt.socket.disconnect(); +}; + +function getCodeBody(code: string | string[] | CodeFile): string[] { + const content = isCodeFile(code) ? code.content : code; + if (Array.isArray(content)) return content; + return content.split("\n"); +} + +/** insertコミットの行IDとtextのインデントを修正する */ +function* fixCommits( + commits: readonly (DeleteCommit | InsertCommit | UpdateCommit)[], + target: TinyCodeBlock, +): Generator { + const { nextLine } = target; + const indent = " ".repeat(countBodyIndent(target)); + for (const commit of commits) { + if ("_delete" in commit) { + yield commit; + } else if ( + "_update" in commit + ) { + yield { + ...commit, + lines: { + ...commit.lines, + text: indent + commit.lines.text, + }, + }; + } else if ( + commit._insert != "_end" || + nextLine === null + ) { + yield { + ...commit, + lines: { + ...commit.lines, + text: indent + commit.lines.text, + }, + }; + } else { + yield { + _insert: nextLine.id, + lines: { + ...commit.lines, + text: indent + commit.lines.text, + }, + }; + } + } +} + +/** コードタイトルが違う場合は書き換える */ +function makeTitleChangeCommit( + code: CodeFile, + target: Pick, +): UpdateCommit | null { + const lineId = target.titleLine.id; + const targetTitle = extractFromCodeTitle(target.titleLine.text); + if ( + targetTitle && + code.filename.trim() == targetTitle.filename && + code.lang?.trim() == targetTitle.lang + ) return null; + const ext = (() => { + const matched = code.filename.match(/.+\.(.*)$/); + if (matched === null) return code.filename; + else if (matched[1] === "") return ""; + else return matched[1].trim(); + })(); + const title = code.filename + + (code.lang && code.lang != ext ? `(${code.lang})` : ""); + return { + _update: lineId, + lines: { + text: " ".repeat(countBodyIndent(target) - 1) + "code:" + title, + }, + }; +} diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts index 33a294b..5c475c5 100644 --- a/browser/websocket/updateCodeFile.ts +++ b/browser/websocket/updateCodeFile.ts @@ -45,6 +45,20 @@ export interface UpdateCodeFileOptions { debug?: boolean; } +/** objectがCodeFile型かどうかを判別する */ +export function isCodeFile(obj: unknown): obj is CodeFile { + if (Array.isArray(obj) || !(obj instanceof Object)) return false; + const code = obj as CodeFile; + const { filename, content, lang } = code; + return ( + typeof filename == "string" && + (typeof content == "string" || + (Array.isArray(content) && + (content.length == 0 || typeof content[0] == "string"))) && + (typeof lang == "string" || lang === undefined) + ); +} + /** REST API経由で取得できるようなコードファイルの中身をまるごと書き換える * * ファイルが存在していなかった場合、既定では何も書き換えない \ From a9471a6805671d1b4375a9a29ca5679b1a90e918 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Wed, 15 Feb 2023 01:45:01 +0900 Subject: [PATCH 20/39] =?UTF-8?q?JSDoc=E3=82=92=E8=BF=BD=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/updateCodeBlock.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/browser/websocket/updateCodeBlock.ts b/browser/websocket/updateCodeBlock.ts index ddbccec..df690ec 100644 --- a/browser/websocket/updateCodeBlock.ts +++ b/browser/websocket/updateCodeBlock.ts @@ -78,6 +78,7 @@ export const updateCodeBlock = async ( if (!options?.socket) opt.socket.disconnect(); }; +/** コード本文のテキストを取得する */ function getCodeBody(code: string | string[] | CodeFile): string[] { const content = isCodeFile(code) ? code.content : code; if (Array.isArray(content)) return content; From 4d727ec5898a192befe544ee94edbc7f8bb90dcd Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Wed, 15 Feb 2023 03:05:17 +0900 Subject: [PATCH 21/39] =?UTF-8?q?`updateCodeBlock()`=E3=81=AEJSDoc?= =?UTF-8?q?=E3=81=AE=E6=9B=B8=E3=81=8D=E5=BF=98=E3=82=8C=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/updateCodeBlock.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/browser/websocket/updateCodeBlock.ts b/browser/websocket/updateCodeBlock.ts index df690ec..50d6217 100644 --- a/browser/websocket/updateCodeBlock.ts +++ b/browser/websocket/updateCodeBlock.ts @@ -26,6 +26,9 @@ export interface UpdateCodeBlockOptions { } /** コードブロックの中身を更新する + * + * newCodeにCodeFileオブジェクトを渡すと、そのオブジェクトに添ってコードブロックのファイル名も書き換えます + * (文字列や文字列配列を渡した場合は書き換えません)。 * * @param newCode 更新後のコードブロック * @param target 更新対象のコードブロック From 25948803a4dc1431911f5dcef0a34f08b91facc3 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Wed, 15 Feb 2023 20:03:30 +0900 Subject: [PATCH 22/39] =?UTF-8?q?=E5=A4=96=E9=83=A8=E3=81=B8export?= =?UTF-8?q?=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/mod.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/browser/websocket/mod.ts b/browser/websocket/mod.ts index 703fb8a..ba991cb 100644 --- a/browser/websocket/mod.ts +++ b/browser/websocket/mod.ts @@ -3,3 +3,6 @@ export * from "./patch.ts"; export * from "./deletePage.ts"; export * from "./pin.ts"; export * from "./listen.ts"; +export * from "./getCodeBlocks.ts"; +export * from "./updateCodeBlock.ts"; +export * from "./updateCodeFile.ts"; From 721ffc192fc4d2ff8f3be6f2e590574eff7c28df Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Thu, 16 Feb 2023 17:15:55 +0900 Subject: [PATCH 23/39] =?UTF-8?q?`getCodeBlocks.ts`=E3=82=92`rest/`?= =?UTF-8?q?=E4=BB=A5=E4=B8=8B=E3=81=B8=E7=A7=BB=E5=8B=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/mod.ts | 1 - browser/websocket/updateCodeBlock.ts | 2 +- browser/websocket/updateCodeFile.ts | 2 +- {browser/websocket => rest}/getCodeBlocks.ts | 9 ++++++--- rest/mod.ts | 1 + 5 files changed, 9 insertions(+), 6 deletions(-) rename {browser/websocket => rest}/getCodeBlocks.ts (95%) diff --git a/browser/websocket/mod.ts b/browser/websocket/mod.ts index ba991cb..01c1cf2 100644 --- a/browser/websocket/mod.ts +++ b/browser/websocket/mod.ts @@ -3,6 +3,5 @@ export * from "./patch.ts"; export * from "./deletePage.ts"; export * from "./pin.ts"; export * from "./listen.ts"; -export * from "./getCodeBlocks.ts"; export * from "./updateCodeBlock.ts"; export * from "./updateCodeFile.ts"; diff --git a/browser/websocket/updateCodeBlock.ts b/browser/websocket/updateCodeBlock.ts index 50d6217..7877f69 100644 --- a/browser/websocket/updateCodeBlock.ts +++ b/browser/websocket/updateCodeBlock.ts @@ -6,8 +6,8 @@ import { socketIO, UpdateCommit, } from "../../deps/socket.ts"; +import { TinyCodeBlock } from "../../rest/getCodeBlocks.ts"; import { diffToChanges } from "./diffToChanges.ts"; -import { TinyCodeBlock } from "./getCodeBlocks.ts"; import { getUserId } from "./id.ts"; import { pull } from "./pull.ts"; import { CodeFile, isCodeFile } from "./updateCodeFile.ts"; diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts index 5c475c5..1b74d82 100644 --- a/browser/websocket/updateCodeFile.ts +++ b/browser/websocket/updateCodeFile.ts @@ -6,8 +6,8 @@ import { socketIO, UpdateCommit, } from "../../deps/socket.ts"; +import { getCodeBlocks, TinyCodeBlock } from "../../rest/getCodeBlocks.ts"; import { pull } from "./pull.ts"; -import { getCodeBlocks, TinyCodeBlock } from "./getCodeBlocks.ts"; import { createNewLineId, getUserId } from "./id.ts"; import { diff, toExtendedChanges } from "../../deps/onp.ts"; import { applyCommit, countBodyIndent } from "./_codeBlock.ts"; diff --git a/browser/websocket/getCodeBlocks.ts b/rest/getCodeBlocks.ts similarity index 95% rename from browser/websocket/getCodeBlocks.ts rename to rest/getCodeBlocks.ts index 7f3eca0..dd83adc 100644 --- a/browser/websocket/getCodeBlocks.ts +++ b/rest/getCodeBlocks.ts @@ -1,6 +1,9 @@ -import type { Line } from "../../deps/scrapbox-rest.ts"; -import { pull } from "./pull.ts"; -import { CodeTitle, extractFromCodeTitle } from "./_codeBlock.ts"; +import type { Line } from "../deps/scrapbox-rest.ts"; +import { pull } from "../browser/websocket/pull.ts"; +import { + CodeTitle, + extractFromCodeTitle, +} from "../browser/websocket/_codeBlock.ts"; /** pull()から取れる情報で構成したコードブロックの最低限の情報 */ export interface TinyCodeBlock { diff --git a/rest/mod.ts b/rest/mod.ts index 8ecdc31..01c93cc 100644 --- a/rest/mod.ts +++ b/rest/mod.ts @@ -12,3 +12,4 @@ export * from "./getGyazoToken.ts"; export * from "./auth.ts"; export * from "./util.ts"; export * from "./error.ts"; +export * from "./getCodeBlocks.ts"; From c31e11558de921d0768e4f27557ad760017e668e Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Thu, 16 Feb 2023 17:17:30 +0900 Subject: [PATCH 24/39] =?UTF-8?q?`=5FcodeBlocks.ts`=E3=81=AEimport?= =?UTF-8?q?=E5=85=83=E3=81=AE=E4=BF=AE=E6=AD=A3=E3=81=97=E5=BF=98=E3=82=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 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 9467bfa..32d02d7 100644 --- a/browser/websocket/_codeBlock.ts +++ b/browser/websocket/_codeBlock.ts @@ -1,8 +1,8 @@ import { Change, Socket, wrap } from "../../deps/socket.ts"; +import { TinyCodeBlock } from "../../rest/getCodeBlocks.ts"; import { HeadData } from "./pull.ts"; import { getProjectId, getUserId } from "./id.ts"; import { pushWithRetry } from "./_fetch.ts"; -import { TinyCodeBlock } from "./getCodeBlocks.ts"; /** コードブロックのタイトル行の情報を保持しておくためのinterface */ export interface CodeTitle { From 663fd1b7b36630d24181cd393c2620fced45917c Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Fri, 17 Feb 2023 02:11:33 +0900 Subject: [PATCH 25/39] =?UTF-8?q?`getCodeBlocks()`=E3=81=AE=E3=83=86?= =?UTF-8?q?=E3=82=B9=E3=83=88=E3=82=B3=E3=83=BC=E3=83=89=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rest/__snapshots__/getCodeBlocks.test.ts.snap | 337 ++++++++++++++++++ rest/getCodeBlocks.test.ts | 248 +++++++++++++ 2 files changed, 585 insertions(+) create mode 100644 rest/__snapshots__/getCodeBlocks.test.ts.snap create mode 100644 rest/getCodeBlocks.test.ts diff --git a/rest/__snapshots__/getCodeBlocks.test.ts.snap b/rest/__snapshots__/getCodeBlocks.test.ts.snap new file mode 100644 index 0000000..d09e35a --- /dev/null +++ b/rest/__snapshots__/getCodeBlocks.test.ts.snap @@ -0,0 +1,337 @@ +export const snapshot = {}; + +snapshot[`getCodeBlocks() 1`] = ` +[ + { + bodyLines: [ + { + created: 1672982822, + id: "63b7b1261280f00000c9bc27", + text: ' print("Hello World!")', + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + ], + filename: "コードブロック.py", + lang: "py", + nextLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc28", + text: "無名コードブロック", + updated: 1672983021, + userId: "5ef2bdebb60650001e1280f0", + }, + pageInfo: { + pageTitle: "コードブロック記法", + projectName: "takker", + }, + titleLine: { + created: 1672982821, + id: "63b7b1261280f00000c9bc26", + text: "code:コードブロック.py", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + }, + { + bodyLines: [ + { + created: 1672982822, + id: "63b7b1261280f00000c9bc2a", + text: ' print("Hello World!")', + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + ], + filename: "py", + lang: "py", + nextLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc2b", + text: "インデントつき", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + pageInfo: { + pageTitle: "コードブロック記法", + projectName: "takker", + }, + titleLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc29", + text: "code:py", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + }, + { + bodyLines: [ + { + created: 1672982822, + id: "63b7b1261280f00000c9bc2d", + text: " - インデント", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + { + created: 1672982822, + id: "63b7b1261280f00000c9bc2e", + text: " - インデント", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + ], + filename: "インデント.md", + lang: "md", + nextLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc2f", + text: "言語を強制", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + pageInfo: { + pageTitle: "コードブロック記法", + projectName: "takker", + }, + titleLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc2c", + text: " code:インデント.md", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + }, + { + bodyLines: [ + { + created: 1672982822, + id: "63b7b1261280f00000c9bc31", + text: \` console.log("I'm JavaScript");\`, + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + ], + filename: "python", + lang: "js", + nextLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc32", + text: "文芸的プログラミング", + updated: 1672982825, + userId: "5ef2bdebb60650001e1280f0", + }, + pageInfo: { + pageTitle: "コードブロック記法", + projectName: "takker", + }, + titleLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc30", + text: " code:python(js)", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + }, + { + bodyLines: [ + { + created: 1672982822, + id: "63b7b1261280f00000c9bc35", + text: " #include ", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + { + created: 1672982822, + id: "63b7b1261280f00000c9bc36", + text: " ", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + ], + filename: "main.cpp", + lang: "cpp", + nextLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc37", + text: " main函数の定義", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + pageInfo: { + pageTitle: "コードブロック記法", + projectName: "takker", + }, + titleLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc34", + text: " code:main.cpp", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + }, + { + bodyLines: [ + { + created: 1672982822, + id: "63b7b1261280f00000c9bc39", + text: " int main() {", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + { + created: 1672982822, + id: "63b7b1261280f00000c9bc3a", + text: ' std::cout << "Hello, C++" << "from scrapbox.io" << std::endl;', + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + { + created: 1672982822, + id: "63b7b1261280f00000c9bc3b", + text: " }", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + { + created: 1672982822, + id: "63b7b1261280f00000c9bc3c", + text: " ", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + ], + filename: "main.cpp", + lang: "cpp", + nextLine: { + created: 1672982673, + id: "63b7b0911280f00000c9bc23", + text: "", + updated: 1672982673, + userId: "5ef2bdebb60650001e1280f0", + }, + pageInfo: { + pageTitle: "コードブロック記法", + projectName: "takker", + }, + titleLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc38", + text: " code:main.cpp", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + }, +] +`; + +snapshot[`getCodeBlocks() > filename filter 1`] = ` +[ + { + bodyLines: [ + { + created: 1672982822, + id: "63b7b1261280f00000c9bc2d", + text: " - インデント", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + { + created: 1672982822, + id: "63b7b1261280f00000c9bc2e", + text: " - インデント", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + ], + filename: "インデント.md", + lang: "md", + nextLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc2f", + text: "言語を強制", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + pageInfo: { + pageTitle: "コードブロック記法", + projectName: "takker", + }, + titleLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc2c", + text: " code:インデント.md", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + }, +] +`; + +snapshot[`getCodeBlocks() > language name filter 1`] = ` +[ + { + bodyLines: [ + { + created: 1672982822, + id: "63b7b1261280f00000c9bc27", + text: ' print("Hello World!")', + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + ], + filename: "コードブロック.py", + lang: "py", + nextLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc28", + text: "無名コードブロック", + updated: 1672983021, + userId: "5ef2bdebb60650001e1280f0", + }, + pageInfo: { + pageTitle: "コードブロック記法", + projectName: "takker", + }, + titleLine: { + created: 1672982821, + id: "63b7b1261280f00000c9bc26", + text: "code:コードブロック.py", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + }, + { + bodyLines: [ + { + created: 1672982822, + id: "63b7b1261280f00000c9bc2a", + text: ' print("Hello World!")', + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + ], + filename: "py", + lang: "py", + nextLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc2b", + text: "インデントつき", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + pageInfo: { + pageTitle: "コードブロック記法", + projectName: "takker", + }, + titleLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc29", + text: "code:py", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + }, +] +`; diff --git a/rest/getCodeBlocks.test.ts b/rest/getCodeBlocks.test.ts new file mode 100644 index 0000000..f826c5f --- /dev/null +++ b/rest/getCodeBlocks.test.ts @@ -0,0 +1,248 @@ +/// + +import { Line } from "../deps/scrapbox-rest.ts"; +import { assertSnapshot } from "../deps/testing.ts"; +import { getCodeBlocks } from "./getCodeBlocks.ts"; + +// https://scrapbox.io/takker/コードブロック記法 +const project = "takker"; +const title = "コードブロック記法"; +const sample: Line[] = [ + { + "id": "63b7aeeb5defe7001ddae116", + "text": "コードブロック記法", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982645, + "updated": 1672982645, + }, + { + "id": "63b7b0761280f00000c9bc21", + "text": "ここでは[コードブロック]を表現する[scrapbox記法]を示す", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982645, + "updated": 1672982671, + }, + { + "id": "63b7b0791280f00000c9bc22", + "text": "", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982648, + "updated": 1672982648, + }, + { + "id": "63b7b12b1280f00000c9bc3d", + "text": "サンプル", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982826, + "updated": 1672982828, + }, + { + "id": "63b7b12c1280f00000c9bc3e", + "text": " from [/villagepump/記法サンプル#61dd289e7838e30000dc9cb5]", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982828, + "updated": 1672982835, + }, + { + "id": "63b7b1261280f00000c9bc26", + "text": "code:コードブロック.py", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982821, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc27", + "text": ' print("Hello World!")', + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc28", + "text": "無名コードブロック", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672983021, + }, + { + "id": "63b7b1261280f00000c9bc29", + "text": "code:py", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc2a", + "text": ' print("Hello World!")', + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc2b", + "text": "インデントつき", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc2c", + "text": " code:インデント.md", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc2d", + "text": " - インデント", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc2e", + "text": " - インデント", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc2f", + "text": "言語を強制", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc30", + "text": " code:python(js)", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc31", + "text": ' console.log("I\'m JavaScript");', + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc32", + "text": "文芸的プログラミング", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982825, + }, + { + "id": "63b7b1261280f00000c9bc33", + "text": " 標準ヘッダファイルをインクルード", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc34", + "text": " code:main.cpp", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc35", + "text": " #include ", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc36", + "text": " ", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc37", + "text": " main函数の定義", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc38", + "text": " code:main.cpp", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc39", + "text": " int main() {", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc3a", + "text": + ' std::cout << "Hello, C++" << "from scrapbox.io" << std::endl;', + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc3b", + "text": " }", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b1261280f00000c9bc3c", + "text": " ", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982822, + "updated": 1672982822, + }, + { + "id": "63b7b0911280f00000c9bc23", + "text": "", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982673, + "updated": 1672982673, + }, + { + "id": "63b7b0911280f00000c9bc24", + "text": "#2023-01-06 14:24:35 ", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982673, + "updated": 1672982674, + }, + { + "id": "63b7b0931280f00000c9bc25", + "text": "", + "userId": "5ef2bdebb60650001e1280f0", + "created": 1672982674, + "updated": 1672982674, + }, +]; + +Deno.test("getCodeBlocks()", async (t) => { + await assertSnapshot( + t, + await getCodeBlocks({ project, title, lines: sample }), + ); + await t.step("filename filter", async (st) => { + const codeBlock = await getCodeBlocks({ project, title, lines: sample }, { + filename: "インデント.md", + }); + await assertSnapshot(st, codeBlock); + }); + await t.step("language name filter", async (st) => { + const codeBlock = await getCodeBlocks({ project, title, lines: sample }, { + lang: "py", + }); + await assertSnapshot(st, codeBlock); + }); +}); From 3f82ce8b0daba1261ea4e19ddcbeaaa6567a5072 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Fri, 17 Feb 2023 02:51:32 +0900 Subject: [PATCH 26/39] =?UTF-8?q?isCodeFile()=E3=81=AE=E3=83=86=E3=82=B9?= =?UTF-8?q?=E3=83=88=E3=82=B3=E3=83=BC=E3=83=89=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/updateCodeFile.test.ts | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 browser/websocket/updateCodeFile.test.ts diff --git a/browser/websocket/updateCodeFile.test.ts b/browser/websocket/updateCodeFile.test.ts new file mode 100644 index 0000000..515a154 --- /dev/null +++ b/browser/websocket/updateCodeFile.test.ts @@ -0,0 +1,29 @@ +/// + +import { assert, assertFalse } from "../../deps/testing.ts"; +import { CodeFile, isCodeFile } from "./updateCodeFile.ts"; + +const codeFile: CodeFile = { + filename: "filename", + content: ["line 0", "line 1"], + lang: "language", +}; + +Deno.test("isCodeFile()", async (t) => { + await t.step("CodeFile object", () => { + assert(isCodeFile(codeFile)); + assert(isCodeFile({ ...codeFile, content: "line 0" })); + assert(isCodeFile({ ...codeFile, lang: undefined })); + }); + await t.step("similer objects", () => { + assertFalse(isCodeFile({ ...codeFile, filename: 10 })); + assertFalse(isCodeFile({ ...codeFile, content: 10 })); + assertFalse(isCodeFile({ ...codeFile, content: [0, 1] })); + assertFalse(isCodeFile({ ...codeFile, lang: 10 })); + }); + await t.step("other type values", () => { + assertFalse(isCodeFile(10)); + assertFalse(isCodeFile(undefined)); + assertFalse(isCodeFile(["0", "1", "2"])); + }); +}); From b440bd0574e79f123380c57ab7a05bc1dd91a3dc Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Fri, 17 Feb 2023 03:21:10 +0900 Subject: [PATCH 27/39] =?UTF-8?q?extractFromCodeTitle()=E3=81=AE=E3=83=86?= =?UTF-8?q?=E3=82=B9=E3=83=88=E3=82=B3=E3=83=BC=E3=83=89=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/_codeBlock.test.ts.snap | 57 +++++++++++++++++++ browser/websocket/_codeBlock.test.ts | 36 ++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 browser/websocket/__snapshots__/_codeBlock.test.ts.snap create mode 100644 browser/websocket/_codeBlock.test.ts diff --git a/browser/websocket/__snapshots__/_codeBlock.test.ts.snap b/browser/websocket/__snapshots__/_codeBlock.test.ts.snap new file mode 100644 index 0000000..361f07e --- /dev/null +++ b/browser/websocket/__snapshots__/_codeBlock.test.ts.snap @@ -0,0 +1,57 @@ +export const snapshot = {}; + +snapshot[`extractFromCodeTitle() > accurate titles > "code:foo.extA(extB)" 1`] = ` +{ + filename: "foo.extA", + indent: 0, + lang: "extB", +} +`; + +snapshot[`extractFromCodeTitle() > accurate titles > " code:foo.extA(extB)" 1`] = ` +{ + filename: "foo.extA", + indent: 1, + lang: "extB", +} +`; + +snapshot[`extractFromCodeTitle() > accurate titles > " code: foo.extA (extB)" 1`] = ` +{ + filename: "foo.extA", + indent: 2, + lang: "extB", +} +`; + +snapshot[`extractFromCodeTitle() > accurate titles > " code: foo (extB) " 1`] = ` +{ + filename: "foo", + indent: 2, + lang: "extB", +} +`; + +snapshot[`extractFromCodeTitle() > accurate titles > " code: foo.extA " 1`] = ` +{ + filename: "foo.extA", + indent: 2, + lang: "extA", +} +`; + +snapshot[`extractFromCodeTitle() > accurate titles > " code: foo " 1`] = ` +{ + filename: "foo", + indent: 2, + lang: "foo", +} +`; + +snapshot[`extractFromCodeTitle() > accurate titles > " code: .foo " 1`] = ` +{ + filename: ".foo", + indent: 2, + lang: ".foo", +} +`; diff --git a/browser/websocket/_codeBlock.test.ts b/browser/websocket/_codeBlock.test.ts new file mode 100644 index 0000000..64f1313 --- /dev/null +++ b/browser/websocket/_codeBlock.test.ts @@ -0,0 +1,36 @@ +/// + +import { assertEquals, assertSnapshot } from "../../deps/testing.ts"; +import { extractFromCodeTitle } from "./_codeBlock.ts"; + +Deno.test("extractFromCodeTitle()", async (t) => { + await t.step("accurate titles", async (st) => { + const titles = [ + "code:foo.extA(extB)", + " code:foo.extA(extB)", + " code: foo.extA (extB)", + " code: foo (extB) ", + " code: foo.extA ", + " code: foo ", + " code: .foo ", + ]; + for (const title of titles) { + await st.step(`"${title}"`, async (sst) => { + await assertSnapshot(sst, extractFromCodeTitle(title)); + }); + } + }); + + await t.step("inaccurate titles", async (st) => { + const nonTitles = [ + " code: foo. ", // コードブロックにはならないので`null`が正常 + "any:code: foo ", + " I'm not code block ", + ]; + for (const title of nonTitles) { + await st.step(`"${title}"`, async () => { + await assertEquals(null, extractFromCodeTitle(title)); + }); + } + }); +}); From 5baa0a9a9243f42c30bdcef30f630f55835352ac Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Fri, 17 Feb 2023 17:24:28 +0900 Subject: [PATCH 28/39] =?UTF-8?q?`CodeFile`=E3=82=92`SimpleCodeFile`?= =?UTF-8?q?=E3=81=B8=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/updateCodeBlock.ts | 14 ++++++------ browser/websocket/updateCodeFile.test.ts | 28 ++++++++++++------------ browser/websocket/updateCodeFile.ts | 14 ++++++------ 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/browser/websocket/updateCodeBlock.ts b/browser/websocket/updateCodeBlock.ts index 7877f69..9eeddf5 100644 --- a/browser/websocket/updateCodeBlock.ts +++ b/browser/websocket/updateCodeBlock.ts @@ -10,7 +10,7 @@ import { TinyCodeBlock } from "../../rest/getCodeBlocks.ts"; import { diffToChanges } from "./diffToChanges.ts"; import { getUserId } from "./id.ts"; import { pull } from "./pull.ts"; -import { CodeFile, isCodeFile } from "./updateCodeFile.ts"; +import { SimpleCodeFile, isSimpleCodeFile } from "./updateCodeFile.ts"; import { applyCommit, countBodyIndent, @@ -27,7 +27,7 @@ export interface UpdateCodeBlockOptions { /** コードブロックの中身を更新する * - * newCodeにCodeFileオブジェクトを渡すと、そのオブジェクトに添ってコードブロックのファイル名も書き換えます + * newCodeにSimpleCodeFileオブジェクトを渡すと、そのオブジェクトに添ってコードブロックのファイル名も書き換えます * (文字列や文字列配列を渡した場合は書き換えません)。 * * @param newCode 更新後のコードブロック @@ -35,7 +35,7 @@ export interface UpdateCodeBlockOptions { * @param project 更新対象のコードブロックが存在するプロジェクト名 */ export const updateCodeBlock = async ( - newCode: string | string[] | CodeFile, + newCode: string | string[] | SimpleCodeFile, target: TinyCodeBlock, options?: UpdateCodeBlockOptions, ) => { @@ -63,7 +63,7 @@ export const updateCodeBlock = async ( userId, }); const commits = [...fixCommits([...diffGenerator], target)]; - if (isCodeFile(newCode)) { + if (isSimpleCodeFile(newCode)) { const titleCommit = makeTitleChangeCommit(newCode, target); if (titleCommit) commits.push(titleCommit); } @@ -82,8 +82,8 @@ export const updateCodeBlock = async ( }; /** コード本文のテキストを取得する */ -function getCodeBody(code: string | string[] | CodeFile): string[] { - const content = isCodeFile(code) ? code.content : code; +function getCodeBody(code: string | string[] | SimpleCodeFile): string[] { + const content = isSimpleCodeFile(code) ? code.content : code; if (Array.isArray(content)) return content; return content.split("\n"); } @@ -133,7 +133,7 @@ function* fixCommits( /** コードタイトルが違う場合は書き換える */ function makeTitleChangeCommit( - code: CodeFile, + code: SimpleCodeFile, target: Pick, ): UpdateCommit | null { const lineId = target.titleLine.id; diff --git a/browser/websocket/updateCodeFile.test.ts b/browser/websocket/updateCodeFile.test.ts index 515a154..463e742 100644 --- a/browser/websocket/updateCodeFile.test.ts +++ b/browser/websocket/updateCodeFile.test.ts @@ -1,29 +1,29 @@ /// import { assert, assertFalse } from "../../deps/testing.ts"; -import { CodeFile, isCodeFile } from "./updateCodeFile.ts"; +import { SimpleCodeFile, isSimpleCodeFile } from "./updateCodeFile.ts"; -const codeFile: CodeFile = { +const codeFile: SimpleCodeFile = { filename: "filename", content: ["line 0", "line 1"], lang: "language", }; -Deno.test("isCodeFile()", async (t) => { - await t.step("CodeFile object", () => { - assert(isCodeFile(codeFile)); - assert(isCodeFile({ ...codeFile, content: "line 0" })); - assert(isCodeFile({ ...codeFile, lang: undefined })); +Deno.test("isSimpleCodeFile()", async (t) => { + await t.step("SimpleCodeFile object", () => { + assert(isSimpleCodeFile(codeFile)); + assert(isSimpleCodeFile({ ...codeFile, content: "line 0" })); + assert(isSimpleCodeFile({ ...codeFile, lang: undefined })); }); await t.step("similer objects", () => { - assertFalse(isCodeFile({ ...codeFile, filename: 10 })); - assertFalse(isCodeFile({ ...codeFile, content: 10 })); - assertFalse(isCodeFile({ ...codeFile, content: [0, 1] })); - assertFalse(isCodeFile({ ...codeFile, lang: 10 })); + assertFalse(isSimpleCodeFile({ ...codeFile, filename: 10 })); + assertFalse(isSimpleCodeFile({ ...codeFile, content: 10 })); + assertFalse(isSimpleCodeFile({ ...codeFile, content: [0, 1] })); + assertFalse(isSimpleCodeFile({ ...codeFile, lang: 10 })); }); await t.step("other type values", () => { - assertFalse(isCodeFile(10)); - assertFalse(isCodeFile(undefined)); - assertFalse(isCodeFile(["0", "1", "2"])); + assertFalse(isSimpleCodeFile(10)); + assertFalse(isSimpleCodeFile(undefined)); + assertFalse(isSimpleCodeFile(["0", "1", "2"])); }); }); diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts index 1b74d82..6e52f20 100644 --- a/browser/websocket/updateCodeFile.ts +++ b/browser/websocket/updateCodeFile.ts @@ -13,7 +13,7 @@ import { diff, toExtendedChanges } from "../../deps/onp.ts"; import { applyCommit, countBodyIndent } from "./_codeBlock.ts"; /** コードブロックの上書きに使う情報のinterface */ -export interface CodeFile { +export interface SimpleCodeFile { /** ファイル名 */ filename: string; @@ -45,10 +45,10 @@ export interface UpdateCodeFileOptions { debug?: boolean; } -/** objectがCodeFile型かどうかを判別する */ -export function isCodeFile(obj: unknown): obj is CodeFile { +/** objectがSimpleCodeFile型かどうかを判別する */ +export function isSimpleCodeFile(obj: unknown): obj is SimpleCodeFile { if (Array.isArray(obj) || !(obj instanceof Object)) return false; - const code = obj as CodeFile; + const code = obj as SimpleCodeFile; const { filename, content, lang } = code; return ( typeof filename == "string" && @@ -72,7 +72,7 @@ export function isCodeFile(obj: unknown): obj is CodeFile { * @param options その他の設定 */ export const updateCodeFile = async ( - codeFile: CodeFile, + codeFile: SimpleCodeFile, project: string, title: string, options?: UpdateCodeFileOptions, @@ -133,7 +133,7 @@ function flatCodeBodies(codeBlocks: readonly TinyCodeBlock[]): Line[] { /** コードブロックの差分からコミットデータを作成する */ function* makeCommits( _codeBlocks: readonly TinyCodeBlock[], - codeFile: CodeFile, + codeFile: SimpleCodeFile, lines: Line[], { userId, insertPositionIfNotExist, isInsertEmptyLineInTail }: { userId: string; @@ -247,7 +247,7 @@ function* makeCommits( } } -function makeCodeBlockTitle(code: CodeFile) { +function makeCodeBlockTitle(code: SimpleCodeFile) { const codeName = code.filename + (code.lang ? `(${code.lang})` : ""); return `code:${codeName}`; } From 7116444c93d9a2a4ec0b78e489182cb724f6101e Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Fri, 17 Feb 2023 17:25:29 +0900 Subject: [PATCH 29/39] =?UTF-8?q?deno=20fmt=E3=81=AE=E3=82=84=E3=82=8A?= =?UTF-8?q?=E5=BF=98=E3=82=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/updateCodeBlock.ts | 2 +- browser/websocket/updateCodeFile.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/browser/websocket/updateCodeBlock.ts b/browser/websocket/updateCodeBlock.ts index 9eeddf5..1a7d415 100644 --- a/browser/websocket/updateCodeBlock.ts +++ b/browser/websocket/updateCodeBlock.ts @@ -10,7 +10,7 @@ import { TinyCodeBlock } from "../../rest/getCodeBlocks.ts"; import { diffToChanges } from "./diffToChanges.ts"; import { getUserId } from "./id.ts"; import { pull } from "./pull.ts"; -import { SimpleCodeFile, isSimpleCodeFile } from "./updateCodeFile.ts"; +import { isSimpleCodeFile, SimpleCodeFile } from "./updateCodeFile.ts"; import { applyCommit, countBodyIndent, diff --git a/browser/websocket/updateCodeFile.test.ts b/browser/websocket/updateCodeFile.test.ts index 463e742..0091d9c 100644 --- a/browser/websocket/updateCodeFile.test.ts +++ b/browser/websocket/updateCodeFile.test.ts @@ -1,7 +1,7 @@ /// import { assert, assertFalse } from "../../deps/testing.ts"; -import { SimpleCodeFile, isSimpleCodeFile } from "./updateCodeFile.ts"; +import { isSimpleCodeFile, SimpleCodeFile } from "./updateCodeFile.ts"; const codeFile: SimpleCodeFile = { filename: "filename", From a5f735ae1b51390a6186c3f80ce61889a2af319a Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Sat, 18 Feb 2023 22:32:36 +0900 Subject: [PATCH 30/39] =?UTF-8?q?`isSimpleCodeFile()`=E3=82=92=E5=88=A5?= =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=B8=E5=88=86=E9=9B=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...eCodeFile.test.ts => isSimpleCodeFile.test.ts} | 5 ++--- browser/websocket/isSimpleCodeFile.ts | 15 +++++++++++++++ browser/websocket/updateCodeBlock.ts | 3 ++- browser/websocket/updateCodeFile.ts | 14 -------------- 4 files changed, 19 insertions(+), 18 deletions(-) rename browser/websocket/{updateCodeFile.test.ts => isSimpleCodeFile.test.ts} (89%) create mode 100644 browser/websocket/isSimpleCodeFile.ts diff --git a/browser/websocket/updateCodeFile.test.ts b/browser/websocket/isSimpleCodeFile.test.ts similarity index 89% rename from browser/websocket/updateCodeFile.test.ts rename to browser/websocket/isSimpleCodeFile.test.ts index 0091d9c..19a1761 100644 --- a/browser/websocket/updateCodeFile.test.ts +++ b/browser/websocket/isSimpleCodeFile.test.ts @@ -1,7 +1,6 @@ -/// - import { assert, assertFalse } from "../../deps/testing.ts"; -import { isSimpleCodeFile, SimpleCodeFile } from "./updateCodeFile.ts"; +import { isSimpleCodeFile } from "./isSimpleCodeFile.ts"; +import { SimpleCodeFile } from "./updateCodeFile.ts"; const codeFile: SimpleCodeFile = { filename: "filename", diff --git a/browser/websocket/isSimpleCodeFile.ts b/browser/websocket/isSimpleCodeFile.ts new file mode 100644 index 0000000..9c80127 --- /dev/null +++ b/browser/websocket/isSimpleCodeFile.ts @@ -0,0 +1,15 @@ +import { SimpleCodeFile } from "./updateCodeFile.ts"; + +/** objectがSimpleCodeFile型かどうかを判別する */ +export function isSimpleCodeFile(obj: unknown): obj is SimpleCodeFile { + if (Array.isArray(obj) || !(obj instanceof Object)) return false; + const code = obj as SimpleCodeFile; + const { filename, content, lang } = code; + return ( + typeof filename == "string" && + (typeof content == "string" || + (Array.isArray(content) && + (content.length == 0 || typeof content[0] == "string"))) && + (typeof lang == "string" || lang === undefined) + ); +} \ No newline at end of file diff --git a/browser/websocket/updateCodeBlock.ts b/browser/websocket/updateCodeBlock.ts index 1a7d415..512df66 100644 --- a/browser/websocket/updateCodeBlock.ts +++ b/browser/websocket/updateCodeBlock.ts @@ -9,8 +9,9 @@ import { import { TinyCodeBlock } from "../../rest/getCodeBlocks.ts"; import { diffToChanges } from "./diffToChanges.ts"; import { getUserId } from "./id.ts"; +import { isSimpleCodeFile } from "./isSimpleCodeFile.ts"; import { pull } from "./pull.ts"; -import { isSimpleCodeFile, SimpleCodeFile } from "./updateCodeFile.ts"; +import { SimpleCodeFile } from "./updateCodeFile.ts"; import { applyCommit, countBodyIndent, diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts index 6e52f20..8f76119 100644 --- a/browser/websocket/updateCodeFile.ts +++ b/browser/websocket/updateCodeFile.ts @@ -45,20 +45,6 @@ export interface UpdateCodeFileOptions { debug?: boolean; } -/** objectがSimpleCodeFile型かどうかを判別する */ -export function isSimpleCodeFile(obj: unknown): obj is SimpleCodeFile { - if (Array.isArray(obj) || !(obj instanceof Object)) return false; - const code = obj as SimpleCodeFile; - const { filename, content, lang } = code; - return ( - typeof filename == "string" && - (typeof content == "string" || - (Array.isArray(content) && - (content.length == 0 || typeof content[0] == "string"))) && - (typeof lang == "string" || lang === undefined) - ); -} - /** REST API経由で取得できるようなコードファイルの中身をまるごと書き換える * * ファイルが存在していなかった場合、既定では何も書き換えない \ From 8e45e092ebad6e5f72a4699af02a4ad43636a7ad Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Sat, 18 Feb 2023 22:35:01 +0900 Subject: [PATCH 31/39] =?UTF-8?q?deno=20fmt=E3=81=AE=E3=82=84=E3=82=8A?= =?UTF-8?q?=E5=BF=98=E3=82=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/isSimpleCodeFile.ts | 30 +++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/browser/websocket/isSimpleCodeFile.ts b/browser/websocket/isSimpleCodeFile.ts index 9c80127..3aabccf 100644 --- a/browser/websocket/isSimpleCodeFile.ts +++ b/browser/websocket/isSimpleCodeFile.ts @@ -1,15 +1,15 @@ -import { SimpleCodeFile } from "./updateCodeFile.ts"; - -/** objectがSimpleCodeFile型かどうかを判別する */ -export function isSimpleCodeFile(obj: unknown): obj is SimpleCodeFile { - if (Array.isArray(obj) || !(obj instanceof Object)) return false; - const code = obj as SimpleCodeFile; - const { filename, content, lang } = code; - return ( - typeof filename == "string" && - (typeof content == "string" || - (Array.isArray(content) && - (content.length == 0 || typeof content[0] == "string"))) && - (typeof lang == "string" || lang === undefined) - ); -} \ No newline at end of file +import { SimpleCodeFile } from "./updateCodeFile.ts"; + +/** objectがSimpleCodeFile型かどうかを判別する */ +export function isSimpleCodeFile(obj: unknown): obj is SimpleCodeFile { + if (Array.isArray(obj) || !(obj instanceof Object)) return false; + const code = obj as SimpleCodeFile; + const { filename, content, lang } = code; + return ( + typeof filename == "string" && + (typeof content == "string" || + (Array.isArray(content) && + (content.length == 0 || typeof content[0] == "string"))) && + (typeof lang == "string" || lang === undefined) + ); +} From ca6e48c553129a851779afacbc95ac10bd2217bc Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Sat, 25 Feb 2023 02:12:59 +0900 Subject: [PATCH 32/39] =?UTF-8?q?debug=E6=96=87=E3=81=AB=E8=89=B2=E3=82=92?= =?UTF-8?q?=E4=BB=98=E3=81=91=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/updateCodeBlock.ts | 6 +++--- browser/websocket/updateCodeFile.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/browser/websocket/updateCodeBlock.ts b/browser/websocket/updateCodeBlock.ts index 512df66..62866dd 100644 --- a/browser/websocket/updateCodeBlock.ts +++ b/browser/websocket/updateCodeBlock.ts @@ -70,11 +70,11 @@ export const updateCodeBlock = async ( } if (opt.debug) { - console.log("vvv original code block vvv"); + console.log("%cvvv original code block vvv", "color: limegreen;"); console.log(target); - console.log("vvv new codes vvv"); + console.log("%cvvv new codes vvv", "color: limegreen;"); console.log(newCode); - console.log("vvv commits vvv"); + console.log("%cvvv commits vvv", "color: limegreen;"); console.log(commits); } diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts index 8f76119..0c6c5a8 100644 --- a/browser/websocket/updateCodeFile.ts +++ b/browser/websocket/updateCodeFile.ts @@ -91,11 +91,11 @@ export const updateCodeFile = async ( ]; if (opt.debug) { - console.log("vvv original code Blocks vvv"); + console.log("%cvvv original code Blocks vvv", "color: limegreen;"); console.log(codeBlocks); - console.log("vvv new codes vvv"); + console.log("%cvvv new codes vvv", "color: limegreen;"); console.log(newCode); - console.log("vvv commits vvv"); + console.log("%cvvv commits vvv", "color: limegreen;"); console.log(commits); } From 5b53e79e4f8f6c30de1be5ac45211888d90fea8a Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Tue, 28 Feb 2023 13:58:15 +0900 Subject: [PATCH 33/39] =?UTF-8?q?`getCodeBlocks()`=E3=81=AEfilter=E5=87=A6?= =?UTF-8?q?=E7=90=86=E3=81=AErefactoring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rest/getCodeBlocks.ts | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/rest/getCodeBlocks.ts b/rest/getCodeBlocks.ts index dd83adc..c34ed1e 100644 --- a/rest/getCodeBlocks.ts +++ b/rest/getCodeBlocks.ts @@ -53,11 +53,8 @@ export const getCodeBlocks = async ( let currentCode: CodeTitle & { /** 読み取り中の行がコードブロックかどうか */ isCodeBlock: boolean; - /** 読み取り中のコードブロックを保存するかどうか */ - isCollect: boolean; } = { isCodeBlock: false, - isCollect: false, filename: "", lang: "", indent: 0, @@ -66,13 +63,10 @@ export const getCodeBlocks = async ( if (currentCode.isCodeBlock) { const body = extractFromCodeBody(line.text, currentCode.indent); if (body === null) { - if (currentCode.isCollect) { - codeBlocks[codeBlocks.length - 1].nextLine = line; - } + codeBlocks[codeBlocks.length - 1].nextLine = line; currentCode.isCodeBlock = false; continue; } - if (!currentCode.isCollect) continue; codeBlocks[codeBlocks.length - 1].bodyLines.push(line); } else { const matched = extractFromCodeTitle(line.text); @@ -80,9 +74,7 @@ export const getCodeBlocks = async ( currentCode.isCodeBlock = false; continue; } - const isCollect = isMatchFilter(matched, filter); - currentCode = { isCodeBlock: true, isCollect: isCollect, ...matched }; - if (!currentCode.isCollect) continue; + currentCode = { isCodeBlock: true, ...matched }; codeBlocks.push({ filename: currentCode.filename, lang: currentCode.lang, @@ -96,7 +88,7 @@ export const getCodeBlocks = async ( }); } } - return codeBlocks; + return codeBlocks.filter((codeBlock) => isMatchFilter(codeBlock, filter)); }; /** targetを`Line[]`に変換する */ @@ -111,13 +103,13 @@ async function getLines( } } -/** コードタイトルのフィルターを検証する */ +/** コードブロックのフィルターに合致しているか検証する */ function isMatchFilter( - codeTitle: CodeTitle, + codeBlock: TinyCodeBlock, filter?: GetCodeBlocksFilter, ): boolean { - if (filter?.filename && filter.filename !== codeTitle.filename) return false; - if (filter?.lang && filter.lang !== codeTitle.lang) return false; + if (filter?.filename && filter.filename !== codeBlock.filename) return false; + if (filter?.lang && filter.lang !== codeBlock.lang) return false; return true; } From 37cbabf5a16d78426e97390540f48514bffd84bc Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Tue, 28 Feb 2023 14:25:07 +0900 Subject: [PATCH 34/39] =?UTF-8?q?`assertSnapshot()`=E3=81=AB=E9=A0=BC?= =?UTF-8?q?=E3=82=8A=E5=88=87=E3=82=8A=E3=81=AB=E3=81=AA=E3=82=89=E3=81=AA?= =?UTF-8?q?=E3=81=84=E5=AE=9F=E8=A3=85=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rest/getCodeBlocks.test.ts | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/rest/getCodeBlocks.test.ts b/rest/getCodeBlocks.test.ts index f826c5f..4324694 100644 --- a/rest/getCodeBlocks.test.ts +++ b/rest/getCodeBlocks.test.ts @@ -1,7 +1,7 @@ /// import { Line } from "../deps/scrapbox-rest.ts"; -import { assertSnapshot } from "../deps/testing.ts"; +import { assertEquals, assertSnapshot } from "../deps/testing.ts"; import { getCodeBlocks } from "./getCodeBlocks.ts"; // https://scrapbox.io/takker/コードブロック記法 @@ -234,15 +234,27 @@ Deno.test("getCodeBlocks()", async (t) => { await getCodeBlocks({ project, title, lines: sample }), ); await t.step("filename filter", async (st) => { - const codeBlock = await getCodeBlocks({ project, title, lines: sample }, { - filename: "インデント.md", + const filename = "インデント.md"; + const codeBlocks = await getCodeBlocks({ project, title, lines: sample }, { + filename, }); - await assertSnapshot(st, codeBlock); + const yet = []; + for (const codeBlock of codeBlocks) { + yet.push(assertEquals(codeBlock.filename, filename)); + } + await Promise.all(yet); + await assertSnapshot(st, codeBlocks); }); await t.step("language name filter", async (st) => { - const codeBlock = await getCodeBlocks({ project, title, lines: sample }, { - lang: "py", + const lang = "py"; + const codeBlocks = await getCodeBlocks({ project, title, lines: sample }, { + lang, }); - await assertSnapshot(st, codeBlock); + const yet = []; + for (const codeBlock of codeBlocks) { + yet.push(assertEquals(codeBlock.lang, lang)); + } + await Promise.all(yet); + await assertSnapshot(st, codeBlocks); }); }); From ee8566b060561b12fd47c8ab3704ad9e4bb999e8 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Tue, 28 Feb 2023 14:41:19 +0900 Subject: [PATCH 35/39] =?UTF-8?q?`isMatchFilter()`=E3=81=AE=E5=AE=9F?= =?UTF-8?q?=E8=A3=85=E3=82=92=E5=B0=91=E3=81=97=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rest/getCodeBlocks.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rest/getCodeBlocks.ts b/rest/getCodeBlocks.ts index c34ed1e..23111e3 100644 --- a/rest/getCodeBlocks.ts +++ b/rest/getCodeBlocks.ts @@ -108,9 +108,11 @@ function isMatchFilter( codeBlock: TinyCodeBlock, filter?: GetCodeBlocksFilter, ): boolean { - if (filter?.filename && filter.filename !== codeBlock.filename) return false; - if (filter?.lang && filter.lang !== codeBlock.lang) return false; - return true; + const equals = (a: unknown, b: unknown) => !a || a === b; + return ( + equals(filter?.filename, codeBlock.filename) && + equals(filter?.lang, codeBlock.lang) + ); } /** 行テキストがコードブロックの一部であればそのテキストを、そうでなければnullを返す From b871342da0acd933f78ce7f86735a92ab564f8b7 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Tue, 28 Feb 2023 14:47:56 +0900 Subject: [PATCH 36/39] =?UTF-8?q?`getCodeBlocks()`=E3=81=8C=E3=82=BF?= =?UTF-8?q?=E3=82=A4=E3=83=88=E3=83=AB=E8=A1=8C=E3=81=AE=E8=A1=8CID?= =?UTF-8?q?=E3=81=AEfilter=E3=81=AB=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rest/__snapshots__/getCodeBlocks.test.ts.snap | 43 +++++++++++++++++++ rest/getCodeBlocks.test.ts | 12 ++++++ rest/getCodeBlocks.ts | 5 ++- 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/rest/__snapshots__/getCodeBlocks.test.ts.snap b/rest/__snapshots__/getCodeBlocks.test.ts.snap index d09e35a..6b50471 100644 --- a/rest/__snapshots__/getCodeBlocks.test.ts.snap +++ b/rest/__snapshots__/getCodeBlocks.test.ts.snap @@ -335,3 +335,46 @@ snapshot[`getCodeBlocks() > language name filter 1`] = ` }, ] `; + +snapshot[`getCodeBlocks() > title line ID filter 1`] = ` +[ + { + bodyLines: [ + { + created: 1672982822, + id: "63b7b1261280f00000c9bc35", + text: " #include ", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + { + created: 1672982822, + id: "63b7b1261280f00000c9bc36", + text: " ", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + ], + filename: "main.cpp", + lang: "cpp", + nextLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc37", + text: " main函数の定義", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + pageInfo: { + pageTitle: "コードブロック記法", + projectName: "takker", + }, + titleLine: { + created: 1672982822, + id: "63b7b1261280f00000c9bc34", + text: " code:main.cpp", + updated: 1672982822, + userId: "5ef2bdebb60650001e1280f0", + }, + }, +] +`; diff --git a/rest/getCodeBlocks.test.ts b/rest/getCodeBlocks.test.ts index 4324694..e409e59 100644 --- a/rest/getCodeBlocks.test.ts +++ b/rest/getCodeBlocks.test.ts @@ -257,4 +257,16 @@ Deno.test("getCodeBlocks()", async (t) => { await Promise.all(yet); await assertSnapshot(st, codeBlocks); }); + await t.step("title line ID filter", async (st) => { + const titleLineId = "63b7b1261280f00000c9bc34"; + const codeBlocks = await getCodeBlocks({ project, title, lines: sample }, { + titleLineId, + }); + const yet = []; + for (const codeBlock of codeBlocks) { + yet.push(assertEquals(codeBlock.titleLine.id, titleLineId)); + } + await Promise.all(yet); + await assertSnapshot(st, codeBlocks); + }); }); diff --git a/rest/getCodeBlocks.ts b/rest/getCodeBlocks.ts index 23111e3..ef41187 100644 --- a/rest/getCodeBlocks.ts +++ b/rest/getCodeBlocks.ts @@ -32,6 +32,8 @@ export interface GetCodeBlocksFilter { filename?: string; /** syntax highlightに使用されている言語名 */ lang?: string; + /** タイトル行の行ID */ + titleLineId?: string; } /** 他のページ(または取得済みの行データ)のコードブロックを全て取得する @@ -111,7 +113,8 @@ function isMatchFilter( const equals = (a: unknown, b: unknown) => !a || a === b; return ( equals(filter?.filename, codeBlock.filename) && - equals(filter?.lang, codeBlock.lang) + equals(filter?.lang, codeBlock.lang) && + equals(filter?.titleLineId, codeBlock.titleLine.id) ); } From 24006a9830323d03f75b7164f6e15f35fe3f3256 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Wed, 1 Mar 2023 20:07:31 +0900 Subject: [PATCH 37/39] =?UTF-8?q?=E8=A1=8C=E3=81=AE=E6=9C=AB=E5=B0=BE?= =?UTF-8?q?=E3=81=AB`\r`=E3=81=8C=E5=90=AB=E3=81=BE=E3=82=8C=E3=81=A6?= =?UTF-8?q?=E3=81=84=E3=81=9F=E5=A0=B4=E5=90=88`bodyLines`=E3=81=AE?= =?UTF-8?q?=E5=8F=96=E5=BE=97=E3=81=AB=E5=A4=B1=E6=95=97=E3=81=97=E3=81=A6?= =?UTF-8?q?=E3=81=84=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rest/__snapshots__/getCodeBlocks.test.ts.snap | 4 ++-- rest/getCodeBlocks.test.ts | 2 +- rest/getCodeBlocks.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rest/__snapshots__/getCodeBlocks.test.ts.snap b/rest/__snapshots__/getCodeBlocks.test.ts.snap index 6b50471..3fb040d 100644 --- a/rest/__snapshots__/getCodeBlocks.test.ts.snap +++ b/rest/__snapshots__/getCodeBlocks.test.ts.snap @@ -69,7 +69,7 @@ snapshot[`getCodeBlocks() 1`] = ` { created: 1672982822, id: "63b7b1261280f00000c9bc2d", - text: " - インデント", + text: " - インデント\\r", updated: 1672982822, userId: "5ef2bdebb60650001e1280f0", }, @@ -233,7 +233,7 @@ snapshot[`getCodeBlocks() > filename filter 1`] = ` { created: 1672982822, id: "63b7b1261280f00000c9bc2d", - text: " - インデント", + text: " - インデント\\r", updated: 1672982822, userId: "5ef2bdebb60650001e1280f0", }, diff --git a/rest/getCodeBlocks.test.ts b/rest/getCodeBlocks.test.ts index e409e59..02fd99a 100644 --- a/rest/getCodeBlocks.test.ts +++ b/rest/getCodeBlocks.test.ts @@ -94,7 +94,7 @@ const sample: Line[] = [ }, { "id": "63b7b1261280f00000c9bc2d", - "text": " - インデント", + "text": " - インデント\r", "userId": "5ef2bdebb60650001e1280f0", "created": 1672982822, "updated": 1672982822, diff --git a/rest/getCodeBlocks.ts b/rest/getCodeBlocks.ts index ef41187..f9c084b 100644 --- a/rest/getCodeBlocks.ts +++ b/rest/getCodeBlocks.ts @@ -128,7 +128,7 @@ function extractFromCodeBody( lineText: string, titleIndent: number, ): string | null { - const matched = lineText.match(/^(\s*)(.*)$/); + const matched = lineText.replaceAll("\r", "").match(/^(\s*)(.*)$/); if (matched === null || matched.length < 2) { return null; } From ec79ffd5530e91cc46a87e4b488d7ba6259cc458 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Fri, 24 Mar 2023 19:39:53 +0900 Subject: [PATCH 38/39] =?UTF-8?q?Fix:=20function=E3=82=92arrow=20function?= =?UTF-8?q?=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `getCodeBlocks.ts`のみ --- rest/getCodeBlocks.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/rest/getCodeBlocks.ts b/rest/getCodeBlocks.ts index f9c084b..549e026 100644 --- a/rest/getCodeBlocks.ts +++ b/rest/getCodeBlocks.ts @@ -94,29 +94,29 @@ export const getCodeBlocks = async ( }; /** targetを`Line[]`に変換する */ -async function getLines( +const getLines = async ( target: { project: string; title: string; lines?: Line[] }, -): Promise { +): Promise => { if (target.lines !== undefined) { return target.lines; } else { const head = await pull(target.project, target.title); return head.lines; } -} +}; /** コードブロックのフィルターに合致しているか検証する */ -function isMatchFilter( +const isMatchFilter = ( codeBlock: TinyCodeBlock, filter?: GetCodeBlocksFilter, -): boolean { +): boolean => { const equals = (a: unknown, b: unknown) => !a || a === b; return ( equals(filter?.filename, codeBlock.filename) && equals(filter?.lang, codeBlock.lang) && equals(filter?.titleLineId, codeBlock.titleLine.id) ); -} +}; /** 行テキストがコードブロックの一部であればそのテキストを、そうでなければnullを返す * @@ -124,10 +124,10 @@ function isMatchFilter( * @param titleIndent {number} コードブロックのタイトル行のインデントの深さ * @return `lineText`がコードブロックの一部であればそのテキストを、そうでなければ`null`を返す */ -function extractFromCodeBody( +const extractFromCodeBody = ( lineText: string, titleIndent: number, -): string | null { +): string | null => { const matched = lineText.replaceAll("\r", "").match(/^(\s*)(.*)$/); if (matched === null || matched.length < 2) { return null; @@ -136,4 +136,4 @@ function extractFromCodeBody( const body = matched[2]; if (indent.length <= titleIndent) return null; return indent.slice(indent.length - titleIndent) + body; -} +}; From ca423336e6c79dde52c786ae81153cbe9a72a028 Mon Sep 17 00:00:00 2001 From: MijinkoSD <79152329+MijinkoSD@users.noreply.github.com> Date: Fri, 24 Mar 2023 20:08:25 +0900 Subject: [PATCH 39/39] =?UTF-8?q?Fix:=20function=E3=82=92arrow=20function?= =?UTF-8?q?=E3=81=AB=E3=81=99=E3=82=8B=EF=BC=88=E5=AE=8C=E7=B5=90=E7=B7=A8?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/websocket/_codeBlock.ts | 10 +++++----- browser/websocket/updateCodeBlock.ts | 10 +++++----- browser/websocket/updateCodeFile.ts | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/browser/websocket/_codeBlock.ts b/browser/websocket/_codeBlock.ts index 32d02d7..c3f57fb 100644 --- a/browser/websocket/_codeBlock.ts +++ b/browser/websocket/_codeBlock.ts @@ -12,14 +12,14 @@ export interface CodeTitle { } /** コミットを送信する一連の処理 */ -export async function applyCommit( +export const applyCommit = async ( commits: Change[], head: HeadData, projectName: string, pageTitle: string, socket: Socket, userId?: string, -): ReturnType { +): ReturnType => { const [projectId, userId_] = await Promise.all([ getProjectId(projectName), userId ?? getUserId(), @@ -34,14 +34,14 @@ export async function applyCommit( title: pageTitle, retry: 3, }); -} +}; /** コードブロックのタイトル行から各種プロパティを抽出する * * @param lineText {string} 行テキスト * @return `lineText`がコードタイトル行であれば`CodeTitle`を、そうでなければ`null`を返す */ -export function extractFromCodeTitle(lineText: string): CodeTitle | null { +export const extractFromCodeTitle = (lineText: string): CodeTitle | null => { const matched = lineText.match(/^(\s*)code:(.+?)(\(.+\)){0,1}\s*$/); if (matched === null) return null; const filename = matched[2].trim(); @@ -66,7 +66,7 @@ export function extractFromCodeTitle(lineText: string): CodeTitle | null { lang: lang, indent: matched[1].length, }; -} +}; /** コードブロック本文のインデント数を計算する */ export function countBodyIndent( diff --git a/browser/websocket/updateCodeBlock.ts b/browser/websocket/updateCodeBlock.ts index 62866dd..fab7791 100644 --- a/browser/websocket/updateCodeBlock.ts +++ b/browser/websocket/updateCodeBlock.ts @@ -83,11 +83,11 @@ export const updateCodeBlock = async ( }; /** コード本文のテキストを取得する */ -function getCodeBody(code: string | string[] | SimpleCodeFile): string[] { +const getCodeBody = (code: string | string[] | SimpleCodeFile): string[] => { const content = isSimpleCodeFile(code) ? code.content : code; if (Array.isArray(content)) return content; return content.split("\n"); -} +}; /** insertコミットの行IDとtextのインデントを修正する */ function* fixCommits( @@ -133,10 +133,10 @@ function* fixCommits( } /** コードタイトルが違う場合は書き換える */ -function makeTitleChangeCommit( +const makeTitleChangeCommit = ( code: SimpleCodeFile, target: Pick, -): UpdateCommit | null { +): UpdateCommit | null => { const lineId = target.titleLine.id; const targetTitle = extractFromCodeTitle(target.titleLine.text); if ( @@ -158,4 +158,4 @@ function makeTitleChangeCommit( text: " ".repeat(countBodyIndent(target) - 1) + "code:" + title, }, }; -} +}; diff --git a/browser/websocket/updateCodeFile.ts b/browser/websocket/updateCodeFile.ts index 0c6c5a8..edad586 100644 --- a/browser/websocket/updateCodeFile.ts +++ b/browser/websocket/updateCodeFile.ts @@ -107,14 +107,14 @@ export const updateCodeFile = async ( /** TinyCodeBlocksの配列からコード本文をフラットな配列に格納して返す \ * その際、コードブロックの左側に存在していたインデントは削除する */ -function flatCodeBodies(codeBlocks: readonly TinyCodeBlock[]): Line[] { +const flatCodeBodies = (codeBlocks: readonly TinyCodeBlock[]): Line[] => { return codeBlocks.map((block) => { const indent = countBodyIndent(block); return block.bodyLines.map((body) => { return { ...body, text: body.text.slice(indent) }; }); }).flat(); -} +}; /** コードブロックの差分からコミットデータを作成する */ function* makeCommits( @@ -233,7 +233,7 @@ function* makeCommits( } } -function makeCodeBlockTitle(code: SimpleCodeFile) { +const makeCodeBlockTitle = (code: SimpleCodeFile) => { const codeName = code.filename + (code.lang ? `(${code.lang})` : ""); return `code:${codeName}`; -} +};