generated at
pin-diary-6 pull:1
pin-diary-6へのPR

タイトルを pin-diary-6 pull#1 から pin-diary-6 pull:1 へ変更
# が入っているとハッシュタグを作成できなくなってしまうため

pin-diary-6の以下のバグの修正を行いましたMijinko_SD
既にページが作成されて書き込みされていた場合にテンプレートフォーマットを挿入すると、空行より下が分断されてしまうバグ
これはおそらく、ページを書き込んだ際に機能する空行承り太郎の空行を、テンプレートの一部として誤認してしまうのが原因
テンプレートが分断されていた場合は、固まったテンプレートを新たに挿入する形で解決しました
これ以外の解決策としては、テンプレートの一部が欠落していた場合、既存のテンプレート行(空行除く)に欠落しているテンプレートを追記する処理が考えられると思います
修正後のソースコード
6依存(未変更) にカテゴライズされているソースファイル以外は書き換えてあります
修正ありがとうございますtakker
返信遅れてすみません
お気になさらずMijinko_SD
修正反映は少々お待ち下さい
やること
diff確認
$ curl https://scrapbox.io/api/code/villagepump/pin-diary-5/util.ts > util_old.ts && curl https://scrapbox.io/api/code/Mijinko-other/pin-diary-6-sd-dev_2022-12-04/util.ts > util.ts && diff -y util_old.ts util.ts
arrow functionに書き換え
依存関係の見直し
pin-diary-6からpin-diary-5への依存をなくす
違うversionを参照しているとややこしい
今までのversionをgithubにサルページしておこうかな
前後に空白が混じっているだけで違う行判定されたくない……からかな?takker
なんとなく入れただけだと思われる
よくわからなかったですが、一応修正後のソースコードでも .trim() して判別する仕様にしてありますMijinko_SD
はーいtakker
2022-12-21完全に忘れてた()takker
でもinboxみたらちゃんとメモしてあったからヨシ!
来週から授業ないのでそのへんでやります~
修正した後から思ったのですが、本当にこの仕様(フォーマット挿入関連の仕様)で良かったのかなーってちょっと思い始めているMijinko_SD
フォーマットの文章の下に箇条書きで追記しにくくなった
人間の手が加えられないというところから、/shokai/WOM(Write Only Member)に書かれているような悪い特徴が出てしまっている気がする
2022/12/31 17:30:53 修正しましたMijinko_SD
結局のところ、「テンプレート行が分断されるのは許容するが、テンプレート行が1行でも欠損していた場合は新たに挿入し直す」という仕様になりました
前回のdevのソースコードからの差分としては、1行コメントアウトしただけ

単体テストを書いて確認しますtakker
変更点はpin-diary-5 format.ts およびそれが依存しているmodulesのみ
なので format.ts util.ts の単体テストだけを書けばいい
$ deno test -r=https://scrapbox.io https://scrapbox.io/api/code/villagepump/pin-diary-6_pull%231/format_test.ts https://scrapbox.io/api/code/villagepump/pin-diary-6_pull%231/util_test.ts

pin-diaryをそろそろgithubに移そうか考えているtakker
古い変更を言及するのがScrapboxだときつい
例えば今(2023-01-07 14:08:12 )、passさせた単体テストの結果について色々書き込んでいるが、ロジックを修正して単体テストの結果が変わると、コメントの意味がわからなくなる

format_test.ts
import { patchTemplate } from "./format.ts"; import { assertEquals } from "./deps_test.ts"; Deno.test("patchTemplate()", async (t) => { await t.step("その1", () => { const headers = [ "header start", "header content", "", "header end", ]; const lines = [ "何か", "aaa", "header content", " コメントが書いてあるかも", "header end modified", "", "本文とか", "おしまい", "footer end", " ↑footerの残骸", ]; const footers = [ "footer start", "footer content", "footer end", ]; assertEquals<string[]>(patchTemplate(lines, headers, footers), [ "header start", "header content", "", "header end", "", "何か", "aaa", "header content", " コメントが書いてあるかも", "header end modified",
うーん、ここのheaderが新規追加されちゃうかあtakker
(まだちゃんとコード読んでいないので、どういう条件でいい感じにformatが復元されるか理解していない)

format_test.ts
"", "本文とか", "おしまい", "footer end", " ↑footerの残骸", "", "footer start", "footer content", "footer end",
ここも、合体されてほしいtakker

format_test.ts
]); }); });

util_test.ts
import { patchLines } from "./util.ts"; import { assertEquals } from "./deps_test.ts"; Deno.test("patchLines()", async (t) => { await t.step("その1", () => { const template = [ "template start", "template template", "template end", ]; const lines = [ "何か", "aaa", "template template", " コメントが書いてあるかも", "template end modified", "", "本文とか", "おしまい", ]; assertEquals<string[]>(patchLines(lines, template), [ "template start", "template template", "template end", "何か", "aaa", "template template", " コメントが書いてあるかも", "template end modified", "", "本文とか", "おしまい", ]); }); });

deps_test.ts
export * from "https://deno.land/std@0.171.0/testing/asserts.ts";

format.ts
import { findSplitIndex, patchLines } from "./util.ts"; // linesにタイトルを入れないように export const patchTemplate = ( lines: string[], headers: string[], footers: string[], ): string[] => { // headerとfooterに相当する行を補う let bodies: string[] = lines; bodies = patchLines(bodies, headers, "head"); bodies = patchLines(bodies, footers, "tail"); // headerとfooterの間に余裕をもたせる const headerEnd = findSplitIndex(bodies, headers); const footerEnd = findSplitIndex(bodies, footers); if (headerEnd === null || footerEnd === null) { // バグってテンプレの挿入がうまくいかなかったら諦める console.log( "format.tsのコードがバグったためtemplateの挿入を諦めました。\n" + `headerEnd: ${headerEnd}, footerEnd: ${footerEnd}`, ); return lines; } const footerStart = footerEnd + 1 - footers.length; return [ ...bodies.slice(0, headerEnd + 1), "", ...bodies.slice(headerEnd + 1, footerStart).join("\n").trim().split("\n"), "", ...bodies.slice(footerStart), ]; };

util.ts
export const patchLines = ( lines: string[], appends: string[], position: "head" | "tail" = "head", ): string[] => { let appendsIndex = 0; for (const line of lines) { if (line.trim() == appends[appendsIndex].trim()) { if (appendsIndex == appends.length - 1) { // appendsと完全に一致するパターンが発見されたので行を挿入せずに終了する return lines; } ++appendsIndex; } else { // 何もしない // appendsIndex = 0; } } // 一致するパターンが見つからなかった場合はappendsを挿入する switch (position) { case "head": return [...appends, ...lines]; case "tail": return [...lines, ...appends]; } }; /** queryに合致するlinesの終了行を返す */ export const findSplitIndex = ( lines: string[], query: string[], ): number | null => { let queryCount = 0; for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) { if (lines[lineIndex].trim() == query[queryCount].trim()) { if (queryCount == query.length - 1) return Number(lineIndex); ++queryCount; } } return null; };