eCourt-note/tests/scripts/patch-pdf-worker.test.ts
Your Name c5c6b65bd2 genesis+worker: design system Genesis ทั้งชุด + patch pdf.worker แก้ fake-space ไทย + ปิด review design/responsive/quality รอบ 2026-09-24 — (1) Genesis: ฟอนต์ General Sans self-host + DM Sans + Sarabun, AppNav 56px backdrop-blur แทน SessionBar, DotGrid หน้า login, palette/รัศมี/เงา/focus ตาม docs/DESIGN.md ครบทุกหน้า (2) postinstall scripts/patch-pdf-worker.mjs ถอด if (scaledDim) รอบ prevTransform ให้อัปเดตทุก glyph — กัน addFakeSpaces แทรก space กลางคำไทยใน PDF ที่ justify ด้วย letter-spacing + test กัน regression (tests/scripts/ + fixture thai_letterspacing.pdf, invariant #6) (3) ฟอร์มอัปโหลด + ช่องกลุ่ม typeId ทางเลือก — normDocumentGroup ที่ utils/external-file.ts เป็น single source ร่วมกับ N8 (4) token fixes: focus ring ปุ่ม pin + แถว bookmark ตามหน้า, ปุ่ม action ใน popup/composer/dialog เป็น rounded-md ทั้งคู่, selection preview เป็น tint ของ primary แทน blue-500 ดิบ, default สี shape/highlight รวมที่ utils/annotation-display, loading animate-pulse + จดข้อยกเว้น (เงา pin, font weights ของ viewer) ลง DESIGN.md (5) responsive: Export PDF max-lg:order-first ให้เห็นบน iPad, แถวบน header แถวเดียวเลื่อนได้บนจอแคบ, re-fit ความกว้างตอน toggle sidebar เฉพาะเมื่อยังไม่ซูมเอง, pin popover flip ขึ้นบนเมื่อใกล้ท้ายหน้า, toast hint ตอนสลับ tool กลางเอกสาร, ป้าย "ชนิด · ผู้ทำ" ของรายการผู้อื่นสำหรับจอสัมผัส (6) คุณภาพ: @layer ครอบ @media กันกฎ touch รั่ยไป desktop (Tailwind v3 ยก @layer ออกจาก media ทิ้ง wrapper — ยืนยันด้วย build จริง + วัดบนจอ), กฎ M5 ครอบ contenteditable กัน Safari zoom ตอนแก้ไข TEXTBOX บน iPad, COMMENT ใช้ box มาตราฐานเดียวตาม pin px จริง (render/scroll target/move-clamp/bookmark), ตัดหัวการ์ดซ้ำกับ h2 หน้ารายการ — พร้อมไฟล์ untracked ที่ postinstall/โค้ดอ้างถึงครบชุด (app/fonts/, AppNav, DotGrid, tests/) กัน fresh clone fail ที่ npm install (คำขอผู้ใช้ 2026-09-24)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 11:46:02 +07:00

68 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { readFileSync } from "node:fs";
import { join } from "node:path";
import { pathToFileURL } from "node:url";
import { describe, expect, it } from "vitest";
// patch fake-space ไทยของ pdf.js worker — scripts/patch-pdf-worker.mjs (bug 2026-09-24):
// pdf.js เก็บตำแหน่งอ้างอิง glyph ก่อนหน้า (prevTransform) เฉพาะ glyph ที่กว้าง ≠ 0
// ทำให้ charSpacing ของสระบน-ล่าง/วรรณยุกต์ (glyph กว้าง 0) สะสมเป็น gap จน
// addFakeSpaces แทรก " " กลางคำ ("ฉะนั้ น") — patch ถอด if ครอบการอัปเดตออก
// ให้อัปเดตทุก glyph แทน
const ROOT = process.cwd();
const WORKER = join(ROOT, "public", "pdf.worker.min.mjs");
// ไฟล์ Word→PDF ที่ justify ด้วย letter-spacing ทุก glyph (มี charSpacing ~0.05×fontSize)
// — เงื่อนไขที่ทำให้ heuristic ของ pdf.js แทรก fake space กลางคำไทย
// (อยู่ใน tests/fixtures/ ไม่ใช่ public/samples/ — ไม่ให้ seed-samples สร้าง
// รายการเอกสาร "ทดสอบ" บนหน้ารายการของทุก deploy)
const SAMPLE = join(ROOT, "tests", "fixtures", "thai_letterspacing.pdf");
describe("public/pdf.worker.min.mjs — ผ่าน patch fake-space ไทย", () => {
const code = readFileSync(WORKER, "utf8");
it("อัปเดต prevTransform ทุก glyph (รูปแบบก่อนแพตช์ C&&(h.prevTransform=…) หายไป)", () => {
// หลัง patch: }h.prevTransform=getCurrentTextTransform(); (เคยถูก if ครอบ
// จนเหลือ } ปิด block เปล่านำหน้า)
expect(code).toMatch(
/[;{}][A-Za-z$_][\w$]*\.prevTransform=getCurrentTextTransform\(\);/,
);
// ก่อน patch: C&&(h.prevTransform=getCurrentTextTransform());
expect(code).not.toMatch(
/&&\([A-Za-z$_][\w$]*\.prevTransform=getCurrentTextTransform\(\)\);/,
);
});
});
describe("getTextContent ผ่าน worker ที่ patch แล้ว — ไฟล์ justify letter-spacing", () => {
it("ไม่มี fake space กลางคำไทย (space ตามด้วยสระ/วรรณยุกต์ = ผิดเสมอ)", async () => {
const pdfjs = await import("pdfjs-dist/legacy/build/pdf.mjs");
pdfjs.GlobalWorkerOptions.workerSrc = pathToFileURL(WORKER).href;
const doc = await pdfjs.getDocument({
data: new Uint8Array(readFileSync(SAMPLE)),
}).promise;
// space หน้า combining mark ไม่มีทางถูกต้องในภาษาไทย (mark ต้องเกาะฐานหน้า)
const badRe = / [ัิีึืุู็่้๊๋์ํ]/;
const offenders: string[] = [];
let targetLine = "";
for (let p = 1; p <= doc.numPages; p++) {
const tc = await (await doc.getPage(p)).getTextContent();
for (const item of tc.items) {
if (!("str" in item)) continue;
if (!targetLine && item.str.includes("ฉะนั้น")) targetLine = item.str;
if (badRe.test(item.str)) {
offenders.push(`p${p}: ${JSON.stringify(item.str.slice(0, 60))}`);
}
}
}
expect(offenders).toEqual([]);
// บรรทัดเป้าหมาย (เคยได้ "ฉะนั้ น ให้ ท่ าน…คำฟ้ อง") — space จริง (glyph SPACE
// ในไฟล์) คงอยู้ครบ ส่วนช่อง letter-spacing เล็ก ๆ ที่ไม่ใช่ space จริงติดกัน
// ("ให้การแก้" — ในไฟล์ไม่มี space glyph ตรงนั้น)
expect(targetLine).toBe(
"ฉะนั้น ให้ ท่านทำคำให้การแก้คำฟ้อง พร้อมด้วยพยานหลักฐาน ๑ ชุด",
);
});
});