formlift 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/coords.ts","../src/core/fields.ts","../src/core/layout.ts","../src/core/detect.ts","../src/core/questions.ts","../src/core/filters.ts"],"sourcesContent":["import type { Position } from './form-logic'\n\n// Field positions are fractions (0..1) of their PDF page, measured from the page's top left. The overlay is\n// placed with CSS percentages, so zoom, window size and screen never move a field; only these conversions\n// touch pixels.\n\nconst clamp = (n: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, n))\nexport const MIN_SIZE = 0.01\n\n/** Snaps a fraction to the grid (`grid` = step as a fraction of the page, 0 = off). */\nexport const snap = (n: number, grid: number) => (grid > 0 ? Math.round(n / grid) * grid : n)\n\n/** A point on the page element (client pixels) as page fractions. */\nexport function toPage(\n clientX: number,\n clientY: number,\n rect: { left: number; top: number; width: number; height: number },\n) {\n return { x: clamp((clientX - rect.left) / rect.width, 0, 1), y: clamp((clientY - rect.top) / rect.height, 0, 1) }\n}\n\n/** Keeps a box inside its page and at least MIN_SIZE big. */\nexport function fitInPage(p: Position): Position {\n const width = clamp(p.width, MIN_SIZE, 1)\n const height = clamp(p.height, MIN_SIZE, 1)\n return { ...p, width, height, x: clamp(p.x, 0, 1 - width), y: clamp(p.y, 0, 1 - height) }\n}\n\n/** Moves a box by a fraction delta (dragged), snapped, kept inside the page. */\nexport function moveBy(p: Position, dx: number, dy: number, grid = 0): Position {\n return fitInPage({ ...p, x: snap(p.x + dx, grid), y: snap(p.y + dy, grid) })\n}\n\n/** Resizes from the bottom-right corner by a fraction delta, snapped, kept inside the page. */\nexport function resizeBy(p: Position, dw: number, dh: number, grid = 0): Position {\n const width = clamp(snap(p.x + p.width + dw, grid) - p.x, MIN_SIZE, 1 - p.x)\n const height = clamp(snap(p.y + p.height + dh, grid) - p.y, MIN_SIZE, 1 - p.y)\n return { ...p, width, height }\n}\n\n/** CSS that places a box on its page element. */\nexport const boxStyle = (p: Position) => ({\n left: `${p.x * 100}%`,\n top: `${p.y * 100}%`,\n width: `${p.width * 100}%`,\n height: `${p.height * 100}%`,\n})\n","import type { FieldDef, FieldType } from './form-logic'\nimport { fitInPage } from './coords'\n\n// Default box per type, in page fractions (an A4 page is ~0.6 wide in these units per 1/2 page).\nconst SIZES: Partial<Record<FieldType, [number, number]>> = {\n textarea: [0.4, 0.08],\n checkbox: [0.025, 0.018],\n radio: [0.35, 0.025],\n signature: [0.25, 0.06],\n}\n\nconst newId = () =>\n typeof crypto !== 'undefined' && crypto.randomUUID ? crypto.randomUUID() : `f${Date.now()}${Math.random()}`\n\n/** A key not used yet: text_1, text_2… */\nexport function uniqueKey(base: string, fields: FieldDef[]) {\n const used = new Set(fields.map((f) => f.key))\n let i = 1\n while (used.has(`${base}_${i}`)) i++\n return `${base}_${i}`\n}\n\n/** A field key from a label: \"IMO NUMBER\" → imo_number_1 (unique among `fields`). */\nexport function keyFor(label: string, type: FieldType, fields: { key: string }[]) {\n const slug = label\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '')\n .slice(0, 40)\n const base = /^[a-z]/.test(slug) ? slug : `${type}${slug ? '_' + slug : ''}`\n const used = new Set(fields.map((f) => f.key))\n let i = 1\n while (used.has(`${base}_${i}`)) i++\n return `${base}_${i}`\n}\n\ntype Cond = FieldDef['visibleWhen']\nconst renameIn = (c: Cond, from: string, to: string): Cond =>\n c && {\n ...c,\n rules: c.rules.map((r) =>\n 'rules' in r ? renameIn(r, from, to)! : r.fieldKey === from ? { ...r, fieldKey: to } : r,\n ),\n }\n\n/**\n * `fields` with `f` put in place of the field with its id. Keys are never typed: a new label gives a new key\n * (unique, from the label), and every condition that used the old key follows it.\n */\nexport function withField(fields: FieldDef[], f: FieldDef): FieldDef[] {\n const old = fields.find((x) => x.id === f.id)\n if (!old) return fields\n const others = fields.filter((x) => x.id !== f.id)\n const key =\n old.label === f.label && old.type === f.type && !others.some((x) => x.key === f.key)\n ? f.key\n : keyFor(f.label, f.type, others)\n const next = { ...f, key }\n if (key === old.key) return fields.map((x) => (x.id === f.id ? next : x))\n return fields.map((x) => {\n const y = { ...(x.id === f.id ? next : x) }\n for (const k of ['visibleWhen', 'requiredWhen', 'readOnlyWhen'] as const)\n if (y[k]) y[k] = renameIn(y[k], old.key, key)\n return y\n })\n}\n\n/** A new manual field of `type`, centred on the dropped point. */\nexport function newField(type: FieldType, page: number, x: number, y: number, fields: FieldDef[]): FieldDef {\n const [width, height] = SIZES[type] ?? [0.25, 0.025]\n // Label \"Text\", key text_1: the same pair a label edit would give (see withField).\n const label = type[0].toUpperCase() + type.slice(1)\n return {\n id: newId(),\n key: keyFor(label, type, fields),\n type,\n label,\n source: 'manual',\n position: fitInPage({ page, x: x - width / 2, y: y - height / 2, width, height }),\n ...(type === 'dropdown' || type === 'radio' ? { options: ['Option 1', 'Option 2'] } : {}),\n }\n}\n\n/** A copy a little lower, with its own id and key. */\nexport function duplicate(f: FieldDef, fields: FieldDef[]): FieldDef {\n return {\n ...structuredClone(f),\n id: newId(),\n key: uniqueKey(f.key.replace(/_\\d+$/, ''), fields),\n source: 'manual',\n confidence: undefined,\n position: fitInPage({ ...f.position, y: f.position.y + f.position.height + 0.005 }),\n }\n}\n\n/** Moves the field at `from` one step up (-1) or down (+1) in the list = tab / fill order. */\nexport function reorder(fields: FieldDef[], id: string, step: -1 | 1) {\n const i = fields.findIndex((f) => f.id === id)\n const j = i + step\n if (i < 0 || j < 0 || j >= fields.length) return fields\n const out = [...fields]\n ;[out[i], out[j]] = [out[j], out[i]]\n return out\n}\n","import type { FieldDef, Layout, LayoutElement } from './form-logic'\nimport { fitInPage } from './coords'\n\n/** A field list and a layout, changed together (page moves renumber both). */\nexport interface Doc {\n fields: FieldDef[]\n layout: Layout\n}\n\nconst newId = () =>\n typeof crypto !== 'undefined' && crypto.randomUUID ? crypto.randomUUID() : `e${Date.now()}${Math.random()}`\n\n/** Renumbers every field and element through `map` (old page → new page, or null = gone with its page). */\nfunction remap(doc: Doc, pages: Layout['pages'], map: (page: number) => number | null): Doc {\n return {\n fields: doc.fields.flatMap((f) => {\n const page = map(f.position.page)\n return page == null ? [] : [{ ...f, position: { ...f.position, page } }]\n }),\n layout: {\n pages,\n elements: doc.layout.elements.flatMap((e) => {\n const page = map(e.page)\n return page == null ? [] : [{ ...e, page }]\n }),\n },\n }\n}\n\n/** Swaps page `n` (1-based) with its neighbour above (-1) or below (+1). */\nexport function movePage(doc: Doc, n: number, step: -1 | 1): Doc {\n const m = n + step\n if (m < 1 || m > doc.layout.pages.length) return doc\n const pages = [...doc.layout.pages]\n ;[pages[n - 1], pages[m - 1]] = [pages[m - 1], pages[n - 1]]\n return remap(doc, pages, (p) => (p === n ? m : p === m ? n : p))\n}\n\n/** Removes page `n` with the fields and items on it. */\nexport function deletePage(doc: Doc, n: number): Doc {\n if (doc.layout.pages.length <= 1) return doc\n const pages = doc.layout.pages.filter((_, i) => i !== n - 1)\n return remap(doc, pages, (p) => (p === n ? null : p > n ? p - 1 : p))\n}\n\n/** Adds a blank page after page `n` (0 = at the start), the size of page `n` (or of the first page). */\nexport function insertBlankPage(doc: Doc, n: number): Doc {\n const like = doc.layout.pages[Math.max(0, n - 1)] ?? { width: 595, height: 842 }\n const pages = [...doc.layout.pages]\n pages.splice(n, 0, { source: null, width: like.width, height: like.height })\n return remap(doc, pages, (p) => (p > n ? p + 1 : p))\n}\n\n/** What each layout tool draws when dropped. */\nexport const ELEMENT_TOOLS = {\n text: { label: 'Text', size: [0.3, 0.025], make: { type: 'text', text: 'New text', fontSize: 11 } },\n box: { label: 'Box', size: [0.3, 0.08], make: { type: 'box', stroke: '#000000', strokeWidth: 1 } },\n whiteout: { label: 'White-out (hide)', size: [0.2, 0.03], make: { type: 'box', fill: '#ffffff' } },\n line: { label: 'Line', size: [0.3, 0], make: { type: 'line', stroke: '#000000', strokeWidth: 1 } },\n} as const satisfies Record<string, { label: string; size: [number, number]; make: Partial<LayoutElement> }>\nexport type ElementTool = keyof typeof ELEMENT_TOOLS\n\n/** A new item from a tool, centred on the dropped point. */\nexport function newElement(tool: ElementTool, page: number, x: number, y: number): LayoutElement {\n const t = ELEMENT_TOOLS[tool]\n const [width, height] = t.size\n const p = fitInPage({ page, x: x - width / 2, y: y - height / 2, width, height: Math.max(height, 0.01) })\n return { id: newId(), page, ...t.make, position: { x: p.x, y: p.y, width, height } } as LayoutElement\n}\n\n/** A text item that hides an original line and shows `line.text` (editable) in its place. */\nexport function replaceLine(line: TextLine, page: number): LayoutElement {\n return {\n id: newId(),\n type: 'text',\n page,\n // A little bigger than the glyphs so no edge of the original shows through.\n position: fitInPage({\n page,\n x: line.x - 0.002,\n y: line.y - 0.002,\n width: Math.min(1, line.width + 0.006),\n height: Math.min(1, line.height + 0.004),\n }),\n text: line.text,\n fontSize: Math.round(line.fontSize * 10) / 10,\n fill: '#ffffff',\n replaces: line.text,\n ...(line.bold && { bold: true }),\n ...(line.italic && { italic: true }),\n }\n}\n\n/** Text width in points: canvas measureText in the browser; injectable for tests. */\nexport type Measure = (text: string, e: LayoutElement) => number\nlet canvas: HTMLCanvasElement | null = null\nexport const measureText: Measure = (text, e) => {\n canvas ??= document.createElement('canvas')\n const ctx = canvas.getContext('2d')\n if (!ctx) return 0\n const family = {\n sans: 'Helvetica, Arial, sans-serif',\n serif: 'Times New Roman, Times, serif',\n mono: 'Courier New, monospace',\n }\n ctx.font = `${e.italic ? 'italic ' : ''}${e.bold ? 'bold ' : ''}${e.fontSize ?? 10}px ${family[e.font ?? 'sans']}`\n return ctx.measureText(text).width\n}\n\n/**\n * Widens a text item to fit its longest line (never narrower, never past the page edge), so new text that is\n * longer than the line it replaces is not cut off. `pageWidth` in points.\n */\nexport function fitTextWidth(e: LayoutElement, pageWidth: number, measure: Measure = measureText): LayoutElement {\n if (e.type !== 'text' || !e.text) return e\n const longest = Math.max(...e.text.split('\\n').map((l) => measure(l, e)))\n const needed = (longest + 4) / pageWidth\n if (needed <= e.position.width) return e\n return { ...e, position: { ...e.position, width: Math.min(needed, 1 - e.position.x) } }\n}\n\nexport const duplicateElement = (e: LayoutElement): LayoutElement => ({\n ...structuredClone(e),\n id: newId(),\n replaces: undefined,\n position: { ...e.position, y: Math.min(1 - e.position.height, e.position.y + e.position.height + 0.005) },\n})\n\n// ---------- lines of text in the original PDF ----------\n\n/** One line (or column cell) of original text, in page fractions; fontSize in points. */\nexport interface TextLine {\n text: string\n x: number\n y: number\n width: number\n height: number\n fontSize: number\n bold?: boolean\n italic?: boolean\n}\n\n/** pdf.js text item: transform = [a, b, c, d, e, f] in PDF space, width in PDF units. */\nexport interface PdfTextItem {\n str: string\n transform: number[]\n width: number\n fontName?: string\n}\n\n/**\n * Groups pdf.js text items into lines. Items on the same baseline join when the gap between them is small (a\n * space); a wide gap (another column, a table cell) starts a new line. `viewBox` = [x0, y0, x1, y1] of the page.\n */\nexport function toLines(\n items: PdfTextItem[],\n viewBox: number[],\n /** The real font name of a pdf.js font id ('ABCDEF+Arial-BoldMT'), to tell bold / italic text. */\n fontOf: (id: string) => string | undefined = () => undefined,\n): TextLine[] {\n const [x0, y0, x1, y1] = viewBox\n const W = x1 - x0\n const H = y1 - y0\n const glyphs = items\n // Horizontal text only. Whitespace items are dropped: some PDFs fill the gap between columns with one wide\n // space item, which would join \"SHIP:\" and \"GT:\" into one line; the gap rule below adds word spaces back.\n .filter((i) => i.str.trim().length && Math.abs(i.transform[1]) < 0.01)\n .map((i) => {\n const size = Math.hypot(i.transform[2], i.transform[3]) || 1\n const font = (i.fontName && fontOf(i.fontName)) || ''\n return {\n str: i.str,\n x: i.transform[4] - x0,\n base: y1 - i.transform[5],\n w: i.width,\n size,\n bold: /bold|black|heavy|semibold|demi/i.test(font),\n italic: /italic|oblique/i.test(font),\n }\n })\n .sort((a, b) => a.base - b.base || a.x - b.x)\n\n const lines: { text: string; x: number; end: number; base: number; size: number; bold: boolean; italic: boolean }[] =\n []\n for (const g of glyphs) {\n const last = lines[lines.length - 1]\n const sameLine = last && Math.abs(g.base - last.base) < Math.max(g.size, last.size) * 0.4\n const gap = last ? g.x - last.end : Infinity\n if (sameLine && gap < Math.max(g.size, last.size) * 1.5 && gap > -last.size) {\n last.text += gap > g.size * 0.15 && !last.text.endsWith(' ') && !g.str.startsWith(' ') ? ' ' + g.str : g.str\n last.end = Math.max(last.end, g.x + g.w)\n last.size = Math.max(last.size, g.size)\n } else\n lines.push({ text: g.str, x: g.x, end: g.x + g.w, base: g.base, size: g.size, bold: g.bold, italic: g.italic })\n }\n return lines\n .map((l) => ({ ...l, text: l.text.trim() }))\n .filter((l) => l.text)\n .map((l) => ({\n text: l.text,\n x: l.x / W,\n y: (l.base - l.size * 0.92) / H,\n width: (l.end - l.x) / W,\n height: (l.size * 1.18) / H,\n fontSize: l.size,\n ...(l.bold && { bold: true }),\n ...(l.italic && { italic: true }),\n }))\n}\n","// Automatic field suggestions from a PDF page's drawing, no AI service needed:\n// - small stroked squares → checkbox\n// - empty cells of ruled tables → text area (or text when one line high)\n// - dotted / solid answer lines, \"____\" → text input (stacked lines → one text area)\n// Labels come from the text next to them (left of a line, beside a box, row + column headers of a cell).\n// Everything here works in PDF points with the origin at the page's top left; results are page fractions.\n// Suggestions get source 'ai' + a confidence, so the editor shows them as dashed boxes for the admin to check.\n\nimport type { FieldDef, FieldType } from './form-logic'\nimport { fitInPage } from './coords'\nimport { keyFor } from './fields'\nimport { toLines, type TextLine } from './layout'\n\nexport interface Seg {\n x0: number\n y0: number\n x1: number\n y1: number\n dashed: boolean\n}\nexport interface Rect {\n x: number\n y: number\n w: number\n h: number\n stroked: boolean\n filled: boolean\n /** Drawn with curves (a circle or rounded box). */\n round?: boolean\n}\nexport interface Shapes {\n hlines: Seg[]\n vlines: Seg[]\n rects: Rect[]\n}\n\ntype Matrix = [number, number, number, number, number, number]\nconst mul = (m: Matrix, n: number[]): Matrix => [\n m[0] * n[0] + m[2] * n[1],\n m[1] * n[0] + m[3] * n[1],\n m[0] * n[2] + m[2] * n[3],\n m[1] * n[2] + m[3] * n[3],\n m[0] * n[4] + m[2] * n[5] + m[4],\n m[1] * n[4] + m[3] * n[5] + m[5],\n]\n\n/** The pdf.js operator codes this needs (pdfjs `OPS`). */\nexport interface Ops {\n save: number\n restore: number\n transform: number\n setDash: number\n constructPath: number\n paintFormXObjectBegin: number\n paintFormXObjectEnd: number\n stroke: number\n closeStroke: number\n fill: number\n eoFill: number\n fillStroke: number\n eoFillStroke: number\n closeFillStroke: number\n closeEOFillStroke: number\n}\n// pdf.js DrawOPS inside a constructPath's path data.\nconst MOVE = 0\nconst LINE = 1\nconst CURVE = 2\nconst CLOSE = 3\n\n/**\n * Lines and rectangles a page draws, in points from the top left, from pdf.js `page.getOperatorList()`.\n * Follows the transform stack (save / restore / cm / form XObjects) and the dash state.\n */\nexport function extractShapes(fnArray: number[], argsArray: unknown[][], OPS: Ops, viewBox: number[]): Shapes {\n const [vx0, , , vy1] = viewBox\n const out: Shapes = { hlines: [], vlines: [], rects: [] }\n let state = { ctm: [1, 0, 0, 1, 0, 0] as Matrix, dashed: false }\n const stack: (typeof state)[] = []\n const strokeOps = new Set([\n OPS.stroke,\n OPS.closeStroke,\n OPS.fillStroke,\n OPS.eoFillStroke,\n OPS.closeFillStroke,\n OPS.closeEOFillStroke,\n ])\n const fillOps = new Set([\n OPS.fill,\n OPS.eoFill,\n OPS.fillStroke,\n OPS.eoFillStroke,\n OPS.closeFillStroke,\n OPS.closeEOFillStroke,\n ])\n\n for (let i = 0; i < fnArray.length; i++) {\n const fn = fnArray[i]\n const args = argsArray[i]\n if (fn === OPS.save) stack.push(state)\n else if (fn === OPS.restore) state = stack.pop() ?? state\n else if (fn === OPS.transform) state = { ...state, ctm: mul(state.ctm, args as number[]) }\n else if (fn === OPS.setDash)\n state = { ...state, dashed: Array.isArray(args[0]) && (args[0] as number[]).length > 0 }\n else if (fn === OPS.paintFormXObjectBegin) {\n stack.push(state)\n if (Array.isArray(args[0])) state = { ...state, ctm: mul(state.ctm, args[0] as number[]) }\n } else if (fn === OPS.paintFormXObjectEnd) state = stack.pop() ?? state\n else if (fn === OPS.constructPath) {\n const op = args[0] as number\n const path = (args[1] as unknown[] | undefined)?.[0] as ArrayLike<number> | undefined\n const stroked = strokeOps.has(op)\n const filled = fillOps.has(op)\n if ((!stroked && !filled) || !path || typeof path.length !== 'number') continue\n const m = state.ctm\n const pt = (x: number, y: number) => [m[0] * x + m[2] * y + m[4] - vx0, vy1 - (m[1] * x + m[3] * y + m[5])] // Split into sub-paths of points. A sub-path with curves is only kept as its box: a dot (part of a dotted\n // line) or a small round box (radio button / round checkbox).\n const subs: number[][][] = []\n const curved: number[][][] = []\n let cur: number[][] = []\n let isCurved = false\n const end = () => {\n if (cur.length) (isCurved ? curved : subs).push(cur)\n cur = []\n isCurved = false\n }\n for (let k = 0; k < path.length;) {\n const code = path[k++]\n if (code === MOVE) {\n end()\n cur = [pt(path[k++], path[k++])]\n } else if (code === LINE) cur.push(pt(path[k++], path[k++]))\n else if (code === CURVE) {\n cur.push(pt(path[k++], path[k++]), pt(path[k++], path[k++]), pt(path[k++], path[k++]))\n isCurved = true\n } else if (code === CLOSE) {\n if (cur.length) cur.push(cur[0])\n } else break\n }\n end()\n for (const c of curved) {\n const xs = c.map((p) => p[0])\n const ys = c.map((p) => p[1])\n const x = Math.min(...xs)\n const y = Math.min(...ys)\n out.rects.push({ x, y, w: Math.max(...xs) - x, h: Math.max(...ys) - y, stroked, filled, round: true })\n }\n for (const s of subs) {\n const xs = s.map((p) => p[0])\n const ys = s.map((p) => p[1])\n const x = Math.min(...xs)\n const y = Math.min(...ys)\n const w = Math.max(...xs) - x\n const h = Math.max(...ys) - y\n const axisAligned = s.every(\n (p, j) => j === 0 || Math.abs(p[0] - s[j - 1][0]) < 0.5 || Math.abs(p[1] - s[j - 1][1]) < 0.5,\n )\n if (s.length >= 4 && axisAligned && w > 0.5 && h > 0.5) {\n // A thin filled rectangle is how some tools draw a rule.\n if (filled && !stroked && h < 2 && w > 10)\n out.hlines.push({ x0: x, y0: y + h / 2, x1: x + w, y1: y + h / 2, dashed: false })\n else if (filled && !stroked && w < 2 && h > 10)\n out.vlines.push({ x0: x + w / 2, y0: y, x1: x + w / 2, y1: y + h, dashed: false })\n else out.rects.push({ x, y, w, h, stroked, filled })\n // (Not for checkbox-sized squares; a flat table row of 15 pt still counts.)\n if (stroked && (w > 16 || h > 16)) {\n // A stroked box's edges are rules too (table outlines).\n out.hlines.push(\n { x0: x, y0: y, x1: x + w, y1: y, dashed: state.dashed },\n { x0: x, y0: y + h, x1: x + w, y1: y + h, dashed: state.dashed },\n )\n out.vlines.push(\n { x0: x, y0: y, x1: x, y1: y + h, dashed: state.dashed },\n { x0: x + w, y0: y, x1: x + w, y1: y + h, dashed: state.dashed },\n )\n }\n continue\n }\n if (!stroked) continue\n for (let j = 1; j < s.length; j++) {\n const [ax, ay] = s[j - 1]\n const [bx, by] = s[j]\n if (Math.abs(ay - by) < 0.5 && Math.abs(bx - ax) > 1)\n out.hlines.push({ x0: Math.min(ax, bx), y0: ay, x1: Math.max(ax, bx), y1: ay, dashed: state.dashed })\n else if (Math.abs(ax - bx) < 0.5 && Math.abs(by - ay) > 1)\n out.vlines.push({ x0: ax, y0: Math.min(ay, by), x1: ax, y1: Math.max(ay, by), dashed: state.dashed })\n }\n }\n }\n }\n return withDottedLines(out)\n}\n\n/** Dotted lines drawn as rows of tiny dots or squares become one dashed line. */\nfunction withDottedLines(shapes: Shapes): Shapes {\n const isDot = (r: Rect) => r.w <= 2.5 && r.h <= 2.5\n const dots = shapes.rects.filter(isDot).sort((a, b) => a.y - b.y || a.x - b.x)\n if (dots.length < 5) return shapes\n const hlines = [...shapes.hlines]\n let run: Rect[] = []\n const flush = () => {\n if (run.length >= 5) {\n const y = run[0].y + run[0].h / 2\n hlines.push({ x0: run[0].x, x1: run[run.length - 1].x + run[run.length - 1].w, y0: y, y1: y, dashed: true })\n }\n run = []\n }\n for (const d of dots) {\n const last = run[run.length - 1]\n if (last && Math.abs(d.y - last.y) < 0.6 && d.x - (last.x + last.w) < 6) run.push(d)\n else {\n flush()\n run = [d]\n }\n }\n flush()\n return { ...shapes, hlines, rects: shapes.rects.filter((r) => !isDot(r)) }\n}\n\n// Characters fonts use for an empty / ticked box. Word and other tools often type them instead of drawing.\nconst BOX_CHARS = /[\\u2610\\u2611\\u2612\\u25A1\\u25A2\\u25FB\\u25FD\\u274F\\u2750\\u2751\\u2752]/\n\n/**\n * Splits checkbox characters (☐ ☑ □ ❏ …) out of pdf.js text items: each becomes a box, and the item keeps only\n * the rest of its text (shifted right), so \"☐ Loading\" gives a box and the label \"Loading\".\n */\nexport function splitBoxChars<T extends { str: string; transform: number[]; width: number }>(\n items: T[],\n viewBox: number[],\n): { items: T[]; boxes: Rect[] } {\n const [x0, , , y1] = viewBox\n const boxes: Rect[] = []\n const out: T[] = []\n for (const i of items) {\n if (!BOX_CHARS.test(i.str)) {\n out.push(i)\n continue\n }\n const chars = [...i.str]\n const per = i.width / Math.max(1, chars.length)\n const size = Math.hypot(i.transform[2], i.transform[3]) || 10\n let rest = ''\n let restStart = -1\n const flush = (end: number) => {\n if (rest.trim()) {\n const t = [...i.transform]\n t[4] += per * restStart\n out.push({ ...i, str: rest, width: per * (end - restStart), transform: t })\n }\n rest = ''\n restStart = -1\n }\n chars.forEach((ch, k) => {\n if (BOX_CHARS.test(ch)) {\n flush(k)\n const side = Math.min(per, size) * 0.85\n boxes.push({\n x: i.transform[4] - x0 + per * k + (per - side) / 2,\n y: y1 - i.transform[5] - size * 0.78,\n w: side,\n h: side,\n stroked: true,\n filled: false,\n })\n } else {\n if (restStart < 0) restStart = k\n rest += ch\n }\n })\n flush(chars.length)\n }\n return { items: out, boxes }\n}\n\n// ---------- detection ----------\n\n/** A text line in points (top-left origin). */\ninterface PtText {\n text: string\n x0: number\n y0: number\n x1: number\n y1: number\n}\ninterface Suggestion {\n type: FieldType\n label: string\n x: number\n y: number\n w: number\n h: number\n confidence: number\n}\n\nconst cluster = (values: number[], tol: number) => {\n const sorted = [...values].sort((a, b) => a - b)\n const out: number[] = []\n for (const v of sorted) if (!out.length || v - out[out.length - 1] > tol) out.push(v)\n return out\n}\nconst overlap = (a0: number, a1: number, b0: number, b1: number) => Math.max(0, Math.min(a1, b1) - Math.max(a0, b0))\n// Labels that say little on their own (\"Comments:\" under an item); named after the item above them.\nconst GENERIC = /^(comments?|remarks?|notes?|observations?|findings?)$/i\n// A label is short; a long sentence next to a line is prose, not the line's name. One that ends in \":\" is a\n// label whatever its length (shortened).\nconst cleanLabel = (s: string) => {\n const t = s\n .replace(/[:.\\s_]+$/, '')\n .replace(/^[\\s•▪\\-–☐☑☒□]+/, '')\n .trim()\n if (t.length <= 60) return t\n return /:\\s*$/.test(s) ? t.slice(0, 57).trimEnd() + '…' : ''\n}\n\nfunction typeFor(label: string): FieldType {\n if (/\\bsign(ature)?\\b/i.test(label)) return 'signature'\n if (/\\bdate\\b|\\bfrom\\b|\\bto\\b|\\bdob\\b/i.test(label)) return 'date'\n if (/e-?mail/i.test(label)) return 'email'\n if (/phone|mobile|\\btel\\b|contact no/i.test(label)) return 'phone'\n return 'text'\n}\n\n/**\n * Collinear pieces of one border joined into one line. Word draws a table's borders cell by cell and leaves\n * gaps of 2–3 pt where rows meet, so a column wall would otherwise never cover a whole row.\n */\nfunction joinSegs(lines: Seg[], vertical: boolean): Seg[] {\n const at = (l: Seg) => (vertical ? l.x0 : l.y0)\n const from = (l: Seg) => (vertical ? l.y0 : l.x0)\n const to = (l: Seg) => (vertical ? l.y1 : l.x1)\n const sorted = [...lines].sort((a, b) => at(a) - at(b) || from(a) - from(b))\n const out: Seg[] = []\n for (const l of sorted) {\n const last = out.find((o) => Math.abs(at(o) - at(l)) < 1 && from(l) <= to(o) + 3 && to(l) >= from(o))\n if (!last) out.push({ ...l })\n else if (vertical) last.y1 = Math.max(last.y1, l.y1)\n else last.x1 = Math.max(last.x1, l.x1)\n }\n return out\n}\n\n/** Cells of ruled tables: regions between solid lines that are closed on every side. */\nfunction tableCells(h: Seg[], v: Seg[], lastTextY = Infinity) {\n const TOL = 2\n const vs = joinSegs(\n v.filter((l) => !l.dashed && l.y1 - l.y0 > 8),\n true,\n )\n // A dotted line is an answer line, except where the table's walls end on it with nothing written below: the\n // open edge of a table that goes on to the next page.\n // (Walls that also start on it make it a dotted border between rows, which stays an answer line.)\n const across = (w: Seg, l: Seg) => w.x0 > l.x0 - TOL && w.x0 < l.x1 + TOL\n const edge = (l: Seg) =>\n l.y0 > lastTextY &&\n vs.filter((w) => across(w, l) && Math.abs(w.y1 - l.y0) < 1.5).length >= 2 &&\n !vs.some((w) => across(w, l) && Math.abs(w.y0 - l.y0) < 3)\n const hs = joinSegs(\n h.filter((l) => (!l.dashed || edge(l)) && l.x1 - l.x0 > 8),\n false,\n )\n if (hs.length < 2 || vs.length < 2) return []\n const xs = cluster(\n vs.map((l) => l.x0),\n TOL,\n )\n const ys = cluster(\n hs.map((l) => l.y0),\n TOL,\n )\n if (xs.length < 2 || ys.length < 2 || xs.length * ys.length > 20000) return []\n const covered = (lines: Seg[], at: number, from: number, to: number, horizontal: boolean) =>\n lines.some((l) =>\n horizontal\n ? Math.abs(l.y0 - at) <= TOL && l.x0 <= from + TOL && l.x1 >= to - TOL\n : Math.abs(l.x0 - at) <= TOL && l.y0 <= from + TOL && l.y1 >= to - TOL,\n )\n const C = xs.length - 1\n const R = ys.length - 1\n // Walls between neighbouring grid cells; union cells with no wall between them.\n const parent = Array.from({ length: C * R }, (_, i) => i)\n const find = (i: number): number => (parent[i] === i ? i : (parent[i] = find(parent[i])))\n const id = (c: number, r: number) => r * C + c\n for (let r = 0; r < R; r++)\n for (let c = 0; c < C; c++) {\n if (c + 1 < C && !covered(vs, xs[c + 1], ys[r], ys[r + 1], false)) parent[find(id(c, r))] = find(id(c + 1, r))\n if (r + 1 < R && !covered(hs, ys[r + 1], xs[c], xs[c + 1], true)) parent[find(id(c, r))] = find(id(c, r + 1))\n }\n const groups = new Map<number, { c0: number; c1: number; r0: number; r1: number; n: number }>()\n for (let r = 0; r < R; r++)\n for (let c = 0; c < C; c++) {\n const g = groups.get(find(id(c, r)))\n if (!g) groups.set(find(id(c, r)), { c0: c, c1: c, r0: r, r1: r, n: 1 })\n else\n Object.assign(g, {\n c0: Math.min(g.c0, c),\n c1: Math.max(g.c1, c),\n r0: Math.min(g.r0, r),\n r1: Math.max(g.r1, r),\n n: g.n + 1,\n })\n }\n const cells: { x0: number; y0: number; x1: number; y1: number }[] = []\n for (const g of groups.values()) {\n if (g.n !== (g.c1 - g.c0 + 1) * (g.r1 - g.r0 + 1)) continue // not a rectangle\n const x0 = xs[g.c0]\n const x1 = xs[g.c1 + 1]\n const y0 = ys[g.r0]\n const y1 = ys[g.r1 + 1]\n // Closed on all four sides, or it is the space around / between tables.\n if (\n covered(hs, y0, x0, x1, true) &&\n covered(hs, y1, x0, x1, true) &&\n covered(vs, x0, y0, y1, false) &&\n covered(vs, x1, y0, y1, false)\n )\n cells.push({ x0, y0, x1, y1 })\n }\n return cells\n}\n\n/**\n * Suggested fields for one page. `lines` = the page's text lines (utils/layout toLines, page fractions),\n * `underscores` = text runs of \"____\" (points), `existing` = fields already on the page (no duplicates),\n * `prevText` = the previous page's heading-like last line (names a box that starts this page).\n */\nexport function detectFields(\n shapes: Shapes,\n lines: TextLine[],\n size: { width: number; height: number },\n page: number,\n existing: FieldDef[] = [],\n underscores: Seg[] = [],\n prevText = '',\n): Omit<FieldDef, 'id' | 'key'>[] {\n const W = size.width\n const H = size.height\n const texts: PtText[] = lines.map((l) => ({\n text: l.text,\n x0: l.x * W,\n y0: l.y * H,\n x1: (l.x + l.width) * W,\n y1: (l.y + l.height) * H,\n }))\n // Sizes follow the page's own text: its typical line height (a form in 7 pt text has smaller boxes than one\n // in 14 pt). Without text, 10 pt type is assumed.\n const heights = texts.map((t) => t.y1 - t.y0).sort((a, b) => a - b)\n const lineH = Math.min(30, Math.max(9, (heights[Math.floor(heights.length / 2)] ?? 11.8) * 1.1))\n const em = lineH / 1.3\n const out: Suggestion[] = []\n const textIn = (x0: number, y0: number, x1: number, y1: number) =>\n texts.filter((t) => {\n const cx = (t.x0 + t.x1) / 2\n const cy = (t.y0 + t.y1) / 2\n return cx > x0 && cx < x1 && cy > y0 && cy < y1 && !/^_+$/.test(t.text)\n })\n\n // Ruled tables first: cells name the checkboxes and answer boxes inside them.\n const cells = tableCells(\n shapes.hlines,\n shapes.vlines,\n texts.filter((t) => !/^page \\d+/i.test(t.text)).reduce((m, t) => Math.max(m, t.y1), 0), // footer aside\n )\n type Cell = (typeof cells)[number]\n const textCells = cells.filter((c) => textIn(c.x0, c.y0, c.x1, c.y1).length)\n const cellText = (c: Cell) =>\n cleanLabel(\n textIn(c.x0, c.y0, c.x1, c.y1)\n .map((t) => t.text)\n .join(' '),\n )\n // \"Row – Column\": the nearest text cell on the left in the same row, and the table's header row (the topmost\n // text cell in the unbroken run of cells straight above, so another table above never names the column).\n // A header exactly as wide as the column wins over wider cells above it (the form's own header block, e.g.\n // \"Number of Observations\" above a \"No.\" column).\n // `longRow`: a long row name (a question) is shortened instead of dropped (checkboxes in Y / N / NA columns).\n const headersOf = (c: Cell, longRow = false) => {\n const colHead: Cell[] = []\n const sameCol = (t: Cell) => Math.abs(t.x0 - c.x0) < 2 && Math.abs(t.x1 - c.x1) < 2\n let emptyAbove = 0 // answer cells of the same column above (a section bar may cut the column)\n for (let up = c; ;) {\n const next = cells.find(\n (t) =>\n t.y0 < up.y0 - 1 && // strictly above: a cell under 2.5 pt tall would otherwise find itself forever\n Math.abs(t.y1 - up.y0) < 2.5 &&\n overlap(t.x0, t.x1, c.x0, c.x1) > 0.6 * Math.min(t.x1 - t.x0, c.x1 - c.x0),\n )\n if (!next) break\n if (textCells.includes(next)) colHead.push(next)\n else if (sameCol(next) && !colHead.some(sameCol)) emptyAbove++ // only between the cell and its header\n up = next\n }\n const rowHead = textCells\n .filter((t) => t.x1 <= c.x0 + 2 && overlap(t.y0, t.y1, c.y0, c.y1) > 0.6 * Math.min(t.y1 - t.y0, c.y1 - c.y0))\n .sort((a, b) => b.x1 - a.x1)\n // Only in a list (3+ empty rows stacked in the column); a lone blank cell keeps the old, stricter naming.\n let run = 1\n for (const down of [false, true])\n for (let cur = c; ;) {\n const n = cells.find(\n (t) =>\n sameCol(t) &&\n !textCells.includes(t) &&\n (down ? t.y0 > cur.y0 + 1 : t.y0 < cur.y0 - 1) &&\n Math.abs(down ? t.y0 - cur.y1 : cur.y0 - t.y1) < 2.5,\n )\n if (!n) break\n run++\n cur = n\n }\n const list = run >= 3 || emptyAbove >= 2\n const own = list ? colHead.filter((t) => sameCol(t) && cellText(t)) : []\n // A wide box right under its own heading bar (\"Suggestion / Feedback from Crew\" over an empty box).\n const bar = colHead[0]\n const underBar =\n bar && !rowHead.length && sameCol(bar) && Math.abs(bar.y1 - c.y0) < 2.5 && c.x1 - c.x0 > 0.5 * W && cellText(bar)\n const top = underBar ? bar : (own[0] ?? colHead[colHead.length - 1])\n const col = top ? cellText(top) : ''\n const rowRaw = rowHead.length\n ? textIn(rowHead[0].x0, rowHead[0].y0, rowHead[0].x1, rowHead[0].y1)\n .map((t) => t.text)\n .join(' ')\n : ''\n const row = cleanLabel(rowRaw) || (longRow && rowRaw ? rowRaw.slice(0, 57).trimEnd() + '…' : '')\n return [row, col].filter(Boolean).join(' – ')\n }\n const cellAt = (x: number, y: number) => cells.find((c) => x > c.x0 && x < c.x1 && y > c.y0 && y < c.y1)\n const proseRight = (c: Cell) =>\n textCells.some(\n (t) =>\n t.x0 >= c.x1 - 2 &&\n overlap(t.y0, t.y1, c.y0, c.y1) > 0.6 * (c.y1 - c.y0) &&\n textIn(t.x0, t.y0, t.x1, t.y1).reduce((n, x) => n + x.text.length, 0) > 80,\n )\n\n // 1. Checkboxes: small square outlines, named by the text beside them or, in a grid, by row and column.\n const minBox = Math.max(4, em * 0.45)\n const maxBox = Math.max(16, em * 1.8)\n const boxes = shapes.rects.filter(\n (r) =>\n r.stroked &&\n r.w >= minBox &&\n r.w <= maxBox &&\n r.h >= minBox &&\n r.h <= maxBox &&\n Math.abs(r.w - r.h) < Math.max(2.5, r.w * 0.2),\n )\n for (const b of boxes) {\n const cy = b.y + b.h / 2\n // In a ruled table only the box's own cell can name it (not the question in the cell beside it).\n const own = cellAt(b.x + b.w / 2, cy)\n const near = texts\n .filter((t) => cy > t.y0 - 2 && cy < t.y1 + 2)\n .filter((t) => !own || ((t.x0 + t.x1) / 2 > own.x0 && (t.x0 + t.x1) / 2 < own.x1))\n .map((t) => ({ t, gap: t.x0 >= b.x + b.w - 1 ? t.x0 - (b.x + b.w) : b.x - t.x1 }))\n .filter((n) => n.gap > -2 && n.gap < 40)\n .sort((p, q) => p.gap - q.gap)[0]\n const cell = near ? undefined : cellAt(b.x + b.w / 2, cy)\n out.push({\n type: 'checkbox',\n label: near ? cleanLabel(near.t.text) : cell ? headersOf(cell, true) : '',\n x: b.x - 1,\n y: b.y - 1,\n w: b.w + 2,\n h: b.h + 2,\n confidence: 0.9,\n })\n }\n\n // 2. Table cells without text, named by row and column.\n const fieldCells: Cell[] = []\n for (const c of cells) {\n if (c.x1 - c.x0 <= 20 || c.y1 - c.y0 <= 10 || textIn(c.x0, c.y0, c.x1, c.y1).length) continue\n if (boxes.some((b) => b.x > c.x0 && b.x < c.x1 && b.y > c.y0 && b.y < c.y1)) continue // a cell holding checkboxes\n // A blank cell in a column of checkboxes (Y / N / NA; a row continued from the previous page) is not a text box.\n const boxCells = cells.filter(\n (t) =>\n Math.abs(t.x0 - c.x0) < 2 &&\n Math.abs(t.x1 - c.x1) < 2 &&\n boxes.some((b) => b.x > t.x0 && b.x < t.x1 && b.y > t.y0 && b.y < t.y1),\n )\n if (boxCells.length >= 2) continue\n let label = headersOf(c)\n // A lone empty box (no table around it) a few lines tall is a free-text answer, named by the text right above\n // it, or by the end of the previous page when it starts the page (\"PART 1 – SUMMARY\" ... next page: the box).\n const lone = !cells.some(\n (t) =>\n t !== c &&\n ((overlap(t.x0, t.x1, c.x0, c.x1) > 2 && (Math.abs(t.y1 - c.y0) < 2.5 || Math.abs(t.y0 - c.y1) < 2.5)) ||\n (overlap(t.y0, t.y1, c.y0, c.y1) > 2 && (Math.abs(t.x1 - c.x0) < 2.5 || Math.abs(t.x0 - c.x1) < 2.5))),\n )\n if (!label && lone && c.y1 - c.y0 > lineH * 3 && c.x1 - c.x0 > em * 15) {\n const above = texts\n .filter((t) => t.y1 <= c.y0 + 1 && c.y0 - t.y1 < lineH * 4 && overlap(t.x0, t.x1, c.x0, c.x1) > 0)\n .sort((a, b) => b.y1 - a.y1)[0]\n const atTop = !texts.some((t) => t.y1 <= c.y0 + 1)\n label = above ? cleanLabel(above.text) : atTop ? cleanLabel(prevText) : ''\n if (!label && !atTop) continue\n label ||= 'Text'\n }\n // A row of answer cells (every cell in it blank) under a header too long to be a name (\"OPEN ITEMS, MEMORANDA,\n // … (Where Class records …)\"): the header's start names it.\n const head = cells.find(\n (t) =>\n textCells.includes(t) && Math.abs(t.y1 - c.y0) < 2.5 && Math.abs(t.x0 - c.x0) < 2 && Math.abs(t.x1 - c.x1) < 2,\n )\n const mates = cells.filter((t) => t !== c && Math.abs(t.y0 - c.y0) < 2 && Math.abs(t.y1 - c.y1) < 2)\n if (!label && head && mates.length && !mates.some((t) => textCells.includes(t))) {\n const raw = textIn(head.x0, head.y0, head.x1, head.y1)\n .map((t) => t.text)\n .join(' ')\n .replace(/\\s*\\(.*$/, '') // the note in brackets\n label =\n cleanLabel(raw) ||\n raw\n .slice(0, 58)\n .replace(/\\s+\\S*$/, '')\n .replace(/[,;:\\s]+$/, '') + '…'\n }\n // A blank cell beside a block of instructions is layout, not an answer box.\n const besideProse = textCells.some(\n (t) => t.x0 >= c.x1 - 2 && overlap(t.y0, t.y1, c.y0, c.y1) > 0.6 * (c.y1 - c.y0) && cellText(t).length === 0,\n )\n // A cell with no row or column name is spacing in the layout (beside headings, instructions), not an answer box.\n if (!label || besideProse || proseRight(c)) continue\n fieldCells.push(c)\n const tall = c.y1 - c.y0 > lineH * 2.2\n const pad = 1.5\n out.push({\n type: tall ? 'textarea' : typeFor(label),\n label,\n x: c.x0 + pad,\n y: c.y0 + pad,\n w: c.x1 - c.x0 - 2 * pad,\n h: c.y1 - c.y0 - 2 * pad,\n confidence: 0.75,\n })\n }\n\n // 3. Answer lines: dotted / solid rules with free space above, and \"____\" text (not inside a cell that is\n // already an answer box; a box with a question in it can still hold answer lines).\n const inAnyCell = (x: number, y: number) =>\n fieldCells.some((c) => x > c.x0 + 1 && x < c.x1 - 1 && y > c.y0 + 1 && y < c.y1 - 1)\n const isWall = (l: Seg) =>\n cells.some((c) => (Math.abs(l.y0 - c.y0) < 2 || Math.abs(l.y0 - c.y1) < 2) && l.x0 < c.x1 && l.x1 > c.x0)\n let rules = [...shapes.hlines, ...underscores]\n .filter((l) => l.x1 - l.x0 >= 25 && !isWall(l) && !inAnyCell((l.x0 + l.x1) / 2, l.y0))\n // Underlined words: text sits right on top of a solid rule (dotted rules are always answer lines).\n .filter(\n (l) =>\n l.dashed ||\n !texts.some(\n (t) => l.y0 - t.y1 > -3 && l.y0 - t.y1 < 4 && overlap(t.x0, t.x1, l.x0, l.x1) > 0.3 * (l.x1 - l.x0),\n ),\n )\n // A rule that crosses an inner column line of a table is a row border (some tables use dotted ones).\n .filter((l) => !shapes.vlines.some((v) => v.x0 > l.x0 + 4 && v.x0 < l.x1 - 4 && v.y0 < l.y0 + 1 && v.y1 > l.y0 - 1))\n .sort((a, b) => a.y0 - b.y0 || a.x0 - b.x0)\n // Pieces of one rule (dotted lines drawn in parts) join up.\n const joined: Seg[] = []\n for (const l of rules) {\n const last = joined.find((j) => Math.abs(j.y0 - l.y0) < 1 && l.x0 - j.x1 < 4 && l.x1 > j.x0)\n if (last) last.x1 = Math.max(last.x1, l.x1)\n else joined.push({ ...l })\n }\n rules = joined\n // Rules stacked under each other with the same width and nothing written between = one text area. Rules that\n // share their row with other rules are a grid (NAME / SIGNATURE / DATE rows): each row stays its own field.\n const inGrid = (l: Seg) => rules.some((r) => r !== l && Math.abs(r.y0 - l.y0) < 2)\n const used = new Set<Seg>()\n for (const l of rules) {\n if (used.has(l)) continue\n const stack = [l]\n for (const m of inGrid(l) ? [] : rules) {\n const last = stack[stack.length - 1]\n if (used.has(m) || stack.includes(m)) continue\n const gap = m.y0 - last.y0\n if (\n gap > 4 &&\n gap < lineH * 1.9 &&\n Math.abs(m.x0 - last.x0) < 4 &&\n Math.abs(m.x1 - last.x1) < 4 &&\n !textIn(m.x0, last.y0 + 1, m.x1, m.y0 - 1).length\n )\n stack.push(m)\n }\n stack.forEach((s) => used.add(s))\n const first = stack[0]\n const lastRule = stack[stack.length - 1]\n // Label: text on the same line to the left, or just above-left for a block.\n // Label: text on the same line to the left (with no other answer line in between), plus a column header\n // right above when the rule sits in a row of rules (RANK / NAME / SIGNATURE / DATE).\n const left = texts\n .filter((t) => t.x1 <= first.x0 + 6 && first.x0 - t.x1 < 220 && first.y0 >= t.y0 - 2 && first.y0 - t.y1 < 10)\n .filter(\n (t) =>\n !rules.some((r) => r !== first && Math.abs(r.y0 - first.y0) < 2 && r.x0 >= t.x1 - 1 && r.x1 <= first.x0 + 1),\n )\n .sort((a, b) => b.x1 - a.x1)[0]\n const rowOfRules = rules.filter((r) => Math.abs(r.y0 - first.y0) < 2).length >= 3\n // A solid rule across most of the page is a separator unless a \"Label:\" right before it names it; dotted\n // rules are always answer lines.\n const wide = !first.dashed && first.x1 - first.x0 > 0.7 * W\n if (wide && !/:\\s*$/.test(left?.text ?? '')) continue\n const header =\n (rowOfRules || !left) && !wide\n ? texts\n .filter((t) => t.y1 <= first.y0 - 2 && first.y0 - t.y1 < (rowOfRules ? 250 : 90))\n .filter(\n (t) =>\n (t.x0 + t.x1) / 2 > first.x0 &&\n (t.x0 + t.x1) / 2 < first.x1 &&\n t.x1 - t.x0 < (first.x1 - first.x0) * 1.2,\n )\n .sort((a, b) => b.y1 - a.y1)\n : []\n // A header written on two lines (\"DATE\" over \"(Reviewed)\") is read as one.\n const head = header[0]\n const headAbove = head && header.find((t) => t !== head && head.y0 - t.y1 < 6 && head.y0 >= t.y1 - 1)\n const label = [left, headAbove, head]\n .filter((t) => t)\n .map((t) => cleanLabel(t!.text))\n .filter(Boolean)\n .join(' – ')\n // An unnamed line across the page is a border (e.g. the bottom of a table), not an answer line.\n if (!label && first.x1 - first.x0 > 0.7 * W) continue\n // Top: about one line above the rule, but below any text above it.\n const above = texts\n .filter((t) => t.y1 <= first.y0 - 1 && overlap(t.x0, t.x1, first.x0, first.x1) > 2 && first.y0 - t.y1 < lineH)\n .reduce((m, t) => Math.max(m, t.y1), -Infinity)\n const top = Math.max(first.y0 - lineH, above + 0.5)\n // The next row starts right under it, from its left end: a separator between rows, not an answer line.\n if (texts.some((t) => t.y0 - lastRule.y0 > -1 && t.y0 - lastRule.y0 < 4 && Math.abs(t.x0 - first.x0) < 8)) continue\n // No room to write above it (text right on top): a separator under a paragraph, not an answer line. if (lastRule.y0 - top < lineH * 0.6) continue\n const multi = stack.length > 1\n out.push({\n type: multi ? 'textarea' : typeFor(label),\n label,\n x: first.x0,\n y: top,\n w: first.x1 - first.x0,\n h: lastRule.y0 - top,\n confidence: label ? 0.8 : 0.5,\n })\n }\n\n // 4. \"Label:\" followed by empty space up to the border of the ruled box it is in. Outside a box a line\n // ending in \":\" is usually a heading (\"Steps:\", \"Result:\"), so it is left alone.\n // A box with only \"Finding\" / \"Remarks\" / \"Comments\" written in it (no \":\"), taller than two lines, is an answer\n // box too, unless it heads a column of blank cells (a table's \"Remarks\" column header).\n const soleWord = (t: PtText) => {\n if (!GENERIC.test(cleanLabel(t.text))) return false\n const midY = (t.y0 + t.y1) / 2\n const cell = cells.find((c) => t.x0 > c.x0 - 1 && t.x1 < c.x1 + 1 && midY > c.y0 && midY < c.y1)\n if (!cell || cell.y1 - cell.y0 < lineH * 2.2 || textIn(cell.x0, cell.y0, cell.x1, cell.y1).length !== 1)\n return false\n return !cells.some(\n (b) =>\n Math.abs(b.y0 - cell.y1) < 2.5 &&\n Math.abs(b.x0 - cell.x0) < 2 &&\n Math.abs(b.x1 - cell.x1) < 2 &&\n !textIn(b.x0, b.y0, b.x1, b.y1).length,\n )\n }\n for (const t of texts) {\n if (!(/:\\s*$/.test(t.text) || soleWord(t)) || t.text.length > 40) continue\n // The last line of a wrapped label (\"Structural concerns / and Class Survey / File:\") is not a label of its own.\n const prev = texts.find(\n (o) => o !== t && Math.abs(o.x0 - t.x0) < 2 && t.y0 - o.y1 > -2 && t.y0 - o.y1 < lineH * 0.6,\n )\n if (prev && !/:\\s*$/.test(prev.text) && !GENERIC.test(cleanLabel(t.text))) continue\n const midY = (t.y0 + t.y1) / 2\n if (out.some((o) => midY > o.y - 2 && midY < o.y + o.h + 2 && o.x >= t.x1 - 4 && o.x - t.x1 < 250)) continue\n const cell = cells.find((c) => t.x0 > c.x0 - 1 && t.x1 < c.x1 + 1 && midY > c.y0 && midY < c.y1)\n if (!cell) continue\n // A box full of prose (a list of guidance or findings) holds no questions: \"… including:\" is a sentence.\n // (\"Comments:\" under an item is a real answer place however long the item.)\n const prose = textIn(cell.x0, cell.y0, cell.x1, cell.y1).filter((o) => o.text.length > 60).length >= 3\n if (prose && !GENERIC.test(cleanLabel(t.text))) continue\n const right = Math.min(\n cell.x1 - 2,\n ...texts.filter((o) => o !== t && o.x0 > t.x1 && overlap(o.y0, o.y1, t.y0, t.y1) > 0).map((o) => o.x0 - 4),\n ...shapes.vlines.filter((v) => v.x0 > t.x1 + 2 && v.y0 < midY && v.y1 > midY).map((v) => v.x0 - 2),\n )\n const top = Math.max(cell.y0 + 1.5, t.y0 - 2)\n const bottom = Math.min(\n cell.y1 - 1.5,\n ...texts.filter((o) => o.y0 > t.y1 && overlap(o.x0, o.x1, t.x1, right) > 0).map((o) => o.y0 - 1),\n )\n const x = t.x1 + 4\n if (right - x < em * 5 || bottom - top < lineH * 0.6 || textIn(x, top, right, bottom).length) continue\n // A heading bar (label on a filled band) is not a question.\n if (\n shapes.rects.some(\n (r) =>\n r.filled && !r.stroked && r.x <= t.x0 && r.x + r.w >= right - 2 && r.y <= t.y0 + 1 && r.y + r.h >= t.y1 - 1,\n )\n )\n continue\n let label = cleanLabel(t.text)\n // \"Comments:\" / \"Remarks:\" say little on their own: name them after the numbered item above them.\n if (GENERIC.test(label)) {\n const item = texts\n .filter((o) => o.y1 <= t.y0 + 1 && t.y0 - o.y1 < 400 && /^\\d+(\\.\\d+)+[a-z]?\\b/i.test(o.text))\n .sort((a, b) => b.y1 - a.y1)[0]\n // A box with only \"Finding\" in it: the block it closes, when a box right above starts with a short heading\n // (\"HW\", \"PR\", \"HF\"): one Finding box per block, each with its own name.\n let tag = ''\n for (let y = cell.y0, k = /:\\s*$/.test(t.text) ? 3 : 0; k < 3 && !tag; k++) {\n const block = cells.find((c) => Math.abs(c.y1 - y) < 2.5 && t.x0 > c.x0 - 1 && t.x0 < c.x1)\n if (!block) break\n const head = textIn(block.x0, block.y0, block.x1, block.y1).sort((p, q) => p.y0 - q.y0 || p.x0 - q.x0)[0]\n if (head && head.text.trim().length <= 12 && head.y0 - block.y0 < lineH * 1.5) tag = head.text.trim()\n y = block.y0\n }\n if (item) label = `${item.text.slice(0, 60).trim()}${tag ? ` – ${tag}` : ''} – ${label}`\n }\n out.push({\n type: bottom - top > lineH * 2.2 ? 'textarea' : typeFor(label),\n label,\n x,\n y: top,\n w: right - x,\n h: bottom - top,\n confidence: 0.65,\n })\n }\n\n // 5. Tables drawn with shading only (Word tables without borders): a shaded label cell followed by empty space\n // in its row is an answer box, split by the shaded column headers above it (\"Signature:\" / \"Date:\").\n const shade = shapes.rects\n .filter((r) => r.filled && !r.stroked && !r.round && r.h >= lineH * 0.8 && r.h <= lineH * 4 && r.w > em * 2)\n // Word paints a cell and its paragraph: keep the outer one (and one of exact duplicates).\n .filter(\n (r, i, all) =>\n !all.some(\n (o, j) =>\n j !== i &&\n o.x <= r.x + 0.5 &&\n o.y <= r.y + 0.5 &&\n o.x + o.w >= r.x + r.w - 0.5 &&\n o.y + o.h >= r.y + r.h - 0.5 &&\n (o.w * o.h > r.w * r.h + 1 || j < i),\n ),\n )\n const shadeText = (r: Rect) => textIn(r.x, r.y, r.x + r.w, r.y + r.h)\n const labelled = shade.filter((r) => shadeText(r).length)\n for (const L of labelled) {\n const label = cleanLabel(\n shadeText(L)\n .map((t) => t.text)\n .join(' '),\n )\n if (!label) continue\n const y0 = L.y\n const y1 = L.y + L.h\n const x0 = L.x + L.w\n const inRow = (a0: number, a1: number) => overlap(a0, a1, y0, y1) > 0.5 * Math.min(a1 - a0, L.h)\n // Up to the next label / text / checkbox in the row, else the right edge of the shaded block around it (the\n // shaded rects joined to it, row by row; a lone shaded title has no block).\n const block = [L]\n for (let k = 0; k < block.length; k++) {\n const s = block[k]\n for (const r of shade)\n if (\n !block.includes(r) &&\n overlap(r.x, r.x + r.w, s.x, s.x + s.w) > 0 &&\n (Math.abs(r.y - (s.y + s.h)) < 3 || Math.abs(s.y - (r.y + r.h)) < 3)\n )\n block.push(r)\n else if (!block.includes(r) && Math.abs(r.y - s.y) < 2 && Math.abs(r.h - s.h) < 2) block.push(r) // same row\n }\n const end = Math.min(\n Math.max(x0, ...block.map((r) => r.x + r.w)),\n ...labelled.filter((r) => r !== L && r.x >= x0 - 1 && inRow(r.y, r.y + r.h)).map((r) => r.x),\n ...texts.filter((t) => t.x0 >= x0 - 1 && inRow(t.y0, t.y1)).map((t) => t.x0 - 4),\n ...boxes.filter((b) => b.x >= x0 - 1 && inRow(b.y, b.y + b.h)).map((b) => b.x - 4),\n )\n if (end - x0 < em * 4) continue\n const heads = labelled.filter(\n (r) => r.y + r.h <= y0 + 1 && y0 - (r.y + r.h) < 120 && r.x >= x0 - 2 && r.x + r.w <= end + 2,\n )\n const headY = Math.max(...heads.map((r) => r.y + r.h))\n const cols = heads.filter((r) => Math.abs(r.y + r.h - headY) < 2).sort((a, b) => a.x - b.x)\n const split = cols.length && cols.reduce((n, r) => n + r.w, 0) > 0.8 * (end - x0)\n const parts = split\n ? cols.map((r) => ({\n a: Math.max(x0, r.x),\n b: Math.min(end, r.x + r.w),\n name: cleanLabel(\n shadeText(r)\n .map((t) => t.text)\n .join(' '),\n ),\n }))\n : [{ a: x0, b: end, name: '' }]\n for (const p of parts) {\n const name = [label, p.name].filter(Boolean).join(' – ')\n out.push({\n type: y1 - y0 > lineH * 2.2 ? 'textarea' : typeFor(p.name || label),\n label: name,\n x: p.a + 1.5,\n y: y0 + 1,\n w: p.b - p.a - 3,\n h: y1 - y0 - 2,\n confidence: 0.6,\n })\n }\n }\n\n // Page fractions; skip what overlaps an existing field or an earlier suggestion.\n const taken = existing.filter((f) => f.position.page === page).map((f) => f.position)\n const result: Omit<FieldDef, 'id' | 'key'>[] = []\n for (const s of out) {\n if (s.w < 4 || s.h < 4) continue\n const position = fitInPage({ page, x: s.x / W, y: s.y / H, width: s.w / W, height: s.h / H })\n const clash = taken.some((p) => {\n const inter =\n overlap(p.x, p.x + p.width, position.x, position.x + position.width) *\n overlap(p.y, p.y + p.height, position.y, position.y + position.height)\n return inter > 0.3 * Math.min(p.width * p.height, position.width * position.height)\n })\n if (clash) continue\n taken.push(position)\n result.push({ type: s.type, label: s.label, source: 'ai', confidence: s.confidence, position })\n }\n return result\n}\n\n/**\n * \"____\" runs inside text items, as answer lines (points, top-left origin), and the items without them, so\n * \"Signature: ______\" gives the line and the label \"Signature:\". Assumes even character widths.\n */\nexport function splitUnderscores<T extends { str: string; transform: number[]; width: number }>(\n items: T[],\n viewBox: number[],\n): { items: T[]; rules: Seg[] } {\n const [x0, , , y1] = viewBox\n const rules: Seg[] = []\n const out: T[] = []\n for (const i of items) {\n if (!i.str.includes('____')) {\n out.push(i)\n continue\n }\n const per = i.width / i.str.length\n let from = 0\n for (const m of i.str.matchAll(/_{4,}/g)) {\n const at = m.index ?? 0\n const start = i.transform[4] - x0 + per * at\n const y = y1 - i.transform[5] + 1\n // Typed, so treated like a dotted line (never an underline under words).\n rules.push({ x0: start, x1: start + per * m[0].length, y0: y, y1: y, dashed: true })\n const piece = i.str.slice(from, at)\n if (piece.trim()) {\n const t = [...i.transform]\n t[4] += per * from\n out.push({ ...i, str: piece, width: per * piece.length, transform: t })\n }\n from = at + m[0].length\n }\n const tail = i.str.slice(from)\n if (tail.trim()) {\n const t = [...i.transform]\n t[4] += per * from\n out.push({ ...i, str: tail, width: per * tail.length, transform: t })\n }\n }\n return { items: out, rules }\n}\n\n// ---------- whole document ----------\n\nexport { keyFor }\n\n/** What detection needs from a pdf.js document (PDFDocumentProxy). */\ninterface PdfDoc {\n getPage(n: number): Promise<{\n view: number[]\n getOperatorList(o?: { intent?: string }): Promise<{ fnArray: number[]; argsArray: unknown[] }>\n getTextContent(): Promise<{ items: unknown[] }>\n }>\n}\n\n/**\n * Suggested fields for every page of a layout (original pages only; blank pages have nothing to detect).\n * Runs page by page so the page stays responsive; `onProgress(done, total)`; stop early with `signal`.\n * New fields get ids and keys; existing fields are never duplicated.\n */\nexport async function detectDocument(\n pdf: PdfDoc,\n OPS: Ops,\n pages: { source: number | null; width: number; height: number }[],\n existing: FieldDef[],\n onProgress?: (done: number, total: number) => void,\n signal?: AbortSignal,\n): Promise<FieldDef[]> {\n const found: FieldDef[] = []\n let prevText = ''\n for (let i = 0; i < pages.length; i++) {\n if (signal?.aborted) break\n const p = pages[i]\n if (!p.source) prevText = ''\n else {\n const page = await pdf.getPage(p.source)\n // 'print' intent: its operator list is not the one the canvas renderer caches and rewrites.\n const ops = await page.getOperatorList({ intent: 'print' })\n const text = await page.getTextContent()\n const split = splitBoxChars(text.items as { str: string; transform: number[]; width: number }[], page.view)\n const typed = splitUnderscores(split.items, page.view)\n const items = typed.items\n const drawn = extractShapes(ops.fnArray, ops.argsArray as unknown[][], OPS, page.view)\n const shapes = { ...drawn, rects: [...drawn.rects, ...split.boxes] }\n const size = { width: page.view[2] - page.view[0], height: page.view[3] - page.view[1] }\n const all = [...existing, ...found]\n const lines = toLines(items, page.view)\n for (const s of detectFields(shapes, lines, size, i + 1, all, typed.rules, prevText)) {\n const id =\n typeof crypto !== 'undefined' && crypto.randomUUID ? crypto.randomUUID() : `d${Date.now()}${Math.random()}`\n found.push({ ...s, id, key: keyFor(s.label, s.type, [...existing, ...found]), label: s.label || s.type })\n }\n // The page's last lines, bottom up: a heading under a note (\"PART 1 – SUMMARY\" / \"(concise overview…)\").\n const bottom = [...lines].sort((a, b) => b.y - a.y).slice(0, 2)\n prevText = bottom.map((l) => l.text).find((t) => t.length <= 60 || /:\\s*$/.test(t)) ?? ''\n }\n onProgress?.(i + 1, pages.length)\n }\n return found\n}\n","// The form as a list of questions (the List view): fields on one line of the document that belong together —\n// \"2.1.1 Were the Master… – Y / N / NA\" and the Remarks box beside them — become one question, so it can be\n// searched and filtered as a whole. Grids of boxes and tables are one question each, laid out in the document's\n// rows and columns. Titles are the document's own text when the page text is given.\nimport type { AnswerValue, Answers, FieldDef, FieldType } from './form-logic'\nimport type { TextLine } from './layout'\n\nexport interface Question {\n id: string\n title: string\n page: number\n parts: { field: FieldDef; name: string }[]\n /** Option grid or table: parts per line of the document, to lay them out in the same rows. */\n rows?: number[]\n /** Table: its column names (parts are row by row, left to right), and each row's own name when rows have one. */\n columns?: string[]\n rowNames?: string[]\n /** The category heading the question sits under (e.g. \"HW\", \"PR\", \"HF\" in inspection checklists), when the form has them. */\n category?: string\n /** The numbered question heading it answers (\"2.1.1 Maintenance of statutory Certificates\"), when written above. */\n section?: string\n /** A column of boxes named by the text block left of it (its options come first). */\n block?: boolean\n /** \"Classification: Core , Risk: H , Assigned to: MASTER\" written in its numbered question: filters. */\n tags?: Record<string, string>\n /** What a run of rows with the same choices asks (\"Evaluation of the level of compliance…\"), shown over them. */\n intro?: string\n}\n\n/** Text lines of a form page (page fractions, top-left origin, as field positions), when known. */\nexport type PageText = (page: number) => TextLine[] | undefined\n\n// \"Row – Column\" labels (auto-detect, or typed that way): the row is the question, the column names the part.\nconst SEP = ' – '\nconst rowOf = (label: string) => (label.includes(SEP) ? label.slice(0, label.lastIndexOf(SEP)) : null)\nconst colOf = (label: string) => (label.includes(SEP) ? label.slice(label.lastIndexOf(SEP) + SEP.length) : label)\n// A field named only like a column (Y, No, Remarks…) belongs to the question on its line.\n// A row number: \"1\", \"2.\", \"3)\", \"a)\", \"iv.\"\nconst SERIAL = /^(\\d{1,3}|[a-z]|[ivx]{1,5})[.)]?$/i\nconst COLUMN = /^(y|n|n ?a|yes|no|remarks?|comments?|observations?|notes?)$/i\n\n// \"LAST PSC INSPECTION: Place\": a question and the name of its first part.\nconst LEAD = /^(.+?):\\s+(\\S.*)$/\n\nconst byX = (a: FieldDef, b: FieldDef) => a.position.x - b.position.x\nconst norm = (s: string) =>\n s\n .replace(/[:.\\s…]+$/, '')\n .trim()\n .toLowerCase()\nconst top = (fs: FieldDef[]) => Math.min(...fs.map((f) => f.position.y))\nconst bottom = (fs: FieldDef[]) => Math.max(...fs.map((f) => f.position.y + f.position.height))\nconst left = (fs: FieldDef[]) => Math.min(...fs.map((f) => f.position.x))\nconst right = (fs: FieldDef[]) => Math.max(...fs.map((f) => f.position.x + f.position.width))\n\n// The question written on the fields' line, left of them: the nearest column of text (not the item number or\n// category columns further left), in reading order.\nfunction rowText(lines: TextLine[], fs: FieldDef[]) {\n const y0 = top(fs)\n const y1 = bottom(fs)\n const x = left(fs)\n // The fields' own names written beside them (\"Yes ☐ No ☐\") are not the question.\n const own = new Set(fs.map((f) => norm(f.label)))\n const beside = lines.filter(\n (l) =>\n l.y + l.height / 2 > y0 - 0.002 &&\n l.y + l.height / 2 < y1 + 0.002 &&\n l.x + l.width <= x + 0.005 &&\n !own.has(norm(l.text)),\n )\n if (!beside.length) return ''\n const nearest = beside.reduce((a, b) => (b.x + b.width > a.x + a.width ? b : a))\n return beside\n .filter((l) => l.x >= nearest.x - 0.02)\n .sort((a, b) => a.y - b.y || a.x - b.x)\n .map((l) => l.text.trim())\n .join(' ')\n .replace(/\\s+/g, ' ')\n}\n\n// A table's title: the nearest line above its first row that is at least half as wide as the row (a title or\n// heading bar, not a single column header).\nfunction tableTitle(lines: TextLine[], first: FieldDef[]) {\n const y0 = top(first)\n const span = right(first) - left(first)\n const above = lines.filter((l) => l.y + l.height <= y0 + 0.002).sort((a, b) => b.y - a.y)\n let at: TextLine | undefined = above.find((l) => y0 - l.y < 0.15 && l.width >= 0.5 * span)\n // Up through the lines right above it (a note under the title runs on for lines): the block's first line.\n for (let cur = at; cur; cur = at) {\n const c: TextLine = cur\n at = above.find((l) => l.y < c.y - 0.001 && c.y - (l.y + l.height) < 0.6 * c.height) ?? c\n if (at === c) break\n }\n return at?.text.trim() ?? ''\n}\n\n// A grid of options (\"Loading ☐ Discharging ☐ …\"): lines of bare checkboxes named only by their own text. Its\n// heading is the line right above the grid with no field on it (\"OPERATIONS AT THE TIME OF INSPECTION:\"), else\n// the text left of the boxes on their line (\"If the ship was detained… ☐ Verified ☐ N/A\").\n// A \" – \" inside a name (\"Log-24a (Job Orders – Engine)\") is part of the name when no two boxes share the part\n// before it: a real \"Row – Column\" line repeats its row (\"2.1.1 … – Y\", \"2.1.1 … – N\").\nconst isOptions = (line: FieldDef[]) => {\n const rows = line.map((f) => rowOf(f.label)).filter(Boolean)\n const shared = rows.length > 0 && (line.length < 2 || new Set(rows).size < rows.length)\n return (\n !shared &&\n line.every(\n (f) =>\n (f.type === 'checkbox' || f.type === 'radio') &&\n !COLUMN.test(f.label.trim()) &&\n !COLUMN.test(colOf(f.label).trim()),\n )\n )\n}\n\nfunction heading(lines: TextLine[], line: FieldDef[], fields: FieldDef[]) {\n const y0 = top(line)\n const h = bottom(line) - y0\n const names = new Set(fields.map((f) => norm(f.label)))\n const free = (l: TextLine) => {\n const mid = l.y + l.height / 2\n return !names.has(norm(l.text)) && !fields.some((f) => mid > f.position.y && mid < f.position.y + f.position.height)\n }\n // The grid's width: its boxes and their names written beside them. A heading sits over it, not off to a side\n // (\"Practical Guidelines\" centred over a column of text is not the heading of boxes at the left edge).\n const own = new Set(line.map((f) => norm(f.label)))\n const named = lines.filter((l) => own.has(norm(l.text)) && l.y + l.height > y0 && l.y < y0 + h)\n const x0 = Math.min(left(line), ...named.map((l) => l.x))\n const x1 = Math.max(right(line), ...named.map((l) => l.x + l.width))\n // Text running on to the right of the boxes on their line (\"☐ Human The Inspector is expected to…\"): the boxes\n // are a side column of a text block, not a grid of options.\n if (\n lines.some(\n (l) => !own.has(norm(l.text)) && l.x >= x1 - 0.002 && l.y + l.height / 2 > y0 && l.y + l.height / 2 < y0 + h,\n )\n )\n return null\n const upFrom = (y: number, gap: (l: TextLine) => number) =>\n lines\n .filter((l) => l.y + l.height <= y + 0.002 && y - (l.y + l.height) < gap(l) && l.x < x1 && l.x + l.width > x0)\n .sort((a, b) => b.y - a.y)[0]\n const above = upFrom(y0, (l) => 1.5 * Math.max(h, l.height))\n if (!above || !free(above)) return rowText(lines, line)\n // A heading of a few lines (\"Qualifications\" over \"(tick all boxes that apply)\"): the lines set tight above.\n const block = [above]\n for (let l = above; block.length < 3; ) {\n const up = upFrom(l.y, (u) => 0.6 * u.height)\n if (!up || !free(up)) break\n block.unshift((l = up))\n }\n return block.map((l) => l.text.trim()).join(' ')\n}\n\n// A table's header row: the line of text right above its first row, one name over each column (\"Training\n// Topic\", \"Name/Rank\", \"Date\"). Only when every column has its own name there; a single column's name is centred\n// over it (the last line of a paragraph above starts at the margin instead).\nfunction headerRow(lines: TextLine[], first: FieldDef[]) {\n const y0 = top(first)\n const h = bottom(first) - y0\n const above = lines.filter((l) => l.y + l.height <= y0 + 0.002 && y0 - (l.y + l.height) < 1.5 * Math.max(h, l.height))\n const at = Math.max(...above.map((l) => l.y))\n const row = above.filter((l) => Math.abs(l.y - at) < 0.5 * l.height)\n const names = first.map((f) => {\n const over = row.filter((l) => {\n const mid = l.x + l.width / 2\n return mid > f.position.x && mid < f.position.x + f.position.width\n })\n const one = over.length === 1 ? over[0] : null\n const centred =\n one && Math.abs(one.x + one.width / 2 - (f.position.x + f.position.width / 2)) < 0.1 * f.position.width\n return one && (first.length > 1 || centred) ? one.text.trim() : ''\n })\n return names.every(Boolean) ? names : null\n}\n\n/** Questions in document order: page, then top to bottom. */\nexport interface ToQuestionsOptions {\n /**\n * Category headings: a line that is only a code like this (\"HW\", \"PR\", \"HF\") marks the questions under it, when\n * two codes or more come back. Default /^[A-Z]{2,4}$/. false = no categories (set Question.category yourself).\n */\n categoryCode?: RegExp | false\n}\n\nexport function toQuestions(\n fields: FieldDef[],\n textOf: PageText = () => undefined,\n { categoryCode = CODE }: ToQuestionsOptions = {},\n): Question[] {\n const sorted = [...fields].sort(\n (a, b) => a.position.page - b.position.page || a.position.y - b.position.y || a.position.x - b.position.x,\n )\n // Columns of boxes beside a block of text (\"A. Vessel is free of: A1… A4…\" │ ☐ Yes ☐ No ☐ NA): one question each.\n const stacks = findStacks(sorted, textOf)\n const stacked = new Set(stacks.flatMap((s) => s.fields))\n // Lines: fields that overlap the first field of the line vertically by half the smaller height.\n const lines: FieldDef[][] = []\n for (const f of sorted.filter((x) => !stacked.has(x))) {\n const line = lines[lines.length - 1]\n const head = line?.[0]\n const p = f.position\n const q = head?.position\n const shared = q ? Math.min(p.y + p.height, q.y + q.height) - Math.max(p.y, q.y) : 0\n if (q && q.page === p.page && shared >= 0.5 * Math.min(p.height, q.height)) line.push(f)\n else lines.push([f])\n }\n // Tables: lines of fields named by their columns (\"RANK\", \"NAME\", \"SIGNATURE\", \"DATE\"), repeated on the line\n // above or below with the same columns. A row may carry the table's side heading on one field (\"INSPECTOR\n // – RANK\"); lines whose fields all share a row name (\"2.1.1 … – Y / N\") are questions, not table rows.\n // Numbered rows (\"1 – Type of Training Need\", or a box named just \"1.\"): the number is the row's name, so\n // lines of them are a table (one column when each line has one field), not questions named \"1\", \"2\"…\n const serial = (f: FieldDef) => {\n const r = (rowOf(f.label) ?? f.label).trim()\n return SERIAL.test(r) && !COLUMN.test(r) ? r : ''\n }\n const column = (f: FieldDef) => (rowOf(f.label) ? colOf(f.label).trim() : serial(f) ? '' : f.label.trim())\n const sig = (line: FieldDef[]) =>\n (line.length >= 2 && line.filter((f) => rowOf(f.label)).length <= 1) ||\n (line.length > 0 && !!serial(line[0]) && line.every((f) => serial(f) === serial(line[0])))\n ? `${line[0].position.page}:${line.map(column).sort().join('|')}`\n : ''\n // Line i carries on the table of line i - 1: same columns, and stacked right under it (rows of a table touch;\n // a gap of more than a row is another table, even with the same columns).\n const follows = (i: number) => {\n const [a, b] = [lines[i - 1], lines[i]]\n return !!a && !!b && !!sig(b) && sig(a) === sig(b) && top(b) - bottom(a) < 1.5 * (bottom(a) - top(a))\n }\n const inTable = lines.map((_, i) => follows(i) || follows(i + 1))\n\n const out: Question[] = []\n // Sections of option grids: a grid's first line finds the heading, the lines right under it share it.\n // A line of boxes with no heading at all (\"☐ Full time ☐ Part time ☐ Contract\") is one question named by its\n // options, and the next line does not join it (no heading says they belong together).\n const section: (string | undefined)[] = lines.map(() => undefined)\n const headed: boolean[] = lines.map(() => false)\n lines.forEach((line, i) => {\n if (inTable[i] || !isOptions(line)) return\n const prev = lines[i - 1]\n const page = line[0].position.page\n // Rows of the same grid sit closer than 1.5 box heights apart (double-spaced lists too).\n if (\n headed[i - 1] &&\n prev[0].position.page === page &&\n top(line) - bottom(prev) < 1.5 * (bottom(prev) - top(prev))\n ) {\n section[i] = section[i - 1]\n headed[i] = true\n return\n }\n const text = heading(\n textOf(page) ?? [],\n line,\n sorted.filter((f) => f.position.page === page),\n )\n if (text === null) return\n if (text) [section[i], headed[i]] = [text, true]\n else if (line.length > 1)\n section[i] = [...line]\n .sort(byX)\n .map((f) => f.label || f.key)\n .join(' / ')\n })\n\n lines.forEach((line, i) => {\n const page = line[0].position.page\n const text = textOf(page) ?? []\n // An option grid is one question under its heading; each box is named by its own label.\n const grid = section[i]\n if (grid) {\n const parts = [...line].sort(byX).map((field) => ({ field, name: field.label || field.key }))\n const last = out[out.length - 1]\n if (grid === section[i - 1]) {\n last.parts.push(...parts)\n last.rows!.push(parts.length)\n } else out.push({ id: line[0].id, title: grid, page, parts, rows: [parts.length] })\n return\n }\n // A table is one question laid out as on the document: columns, rows, each row's name on its left.\n if (inTable[i]) {\n const list = [...line].sort(byX)\n const parts = list.map((field) => ({ field, name: column(field) }))\n const name = serial(list[0]) || (list.map((f) => rowOf(f.label)).find(Boolean) ?? rowText(text, list))\n if (!follows(i))\n out.push({\n id: list[0].id,\n title: tableTitle(text, line),\n page,\n parts,\n rows: [parts.length],\n columns: parts.map((p) => p.name),\n rowNames: [name],\n })\n else {\n const t = out[out.length - 1]\n t.parts.push(...parts)\n t.rows!.push(parts.length)\n t.rowNames!.push(name)\n }\n if (follows(i + 1)) return\n // Done: titled by the table's title, else its one side heading (\"INSPECTOR\"), else its columns.\n const t = out[out.length - 1]\n // Column names repeated, or the table's own title, were not read from the column headers: not shown.\n const cols = t.columns!\n if (cols.some((c, k) => c && (cols.indexOf(c) !== k || cols.lastIndexOf(c) !== k || norm(c) === norm(t.title))))\n t.columns = cols.map(() => '')\n // No names in the labels (\"1\", \"1\", \"1\"): the header row written over the table, when there is one.\n if (t.columns!.every((c) => !c))\n t.columns =\n headerRow(\n text,\n t.parts.slice(0, t.rows![0]).map((p) => p.field),\n ) ?? t.columns\n // One named column (\"Best Practices/Safety Related Ideas Identified\"): the column's name is the table's.\n if (t.columns!.length === 1 && t.columns![0]) [t.title, t.columns] = [t.columns![0], ['']]\n const named = t.rowNames!.filter(Boolean)\n if (!t.title && named.length === 1 && t.rowNames![0]) t.title = named[0]\n if (named.length === 0 || t.title === t.rowNames![0]) delete t.rowNames\n t.title ||= t.columns!.filter(Boolean).join(' / ') || 'List'\n return\n }\n const groups = new Map<string, FieldDef[]>()\n const loose: FieldDef[] = []\n // \"LAST PSC INSPECTION: Place ____ Date ____\": the fields after a \"Question: Part\" field on its line are\n // parts of that question, until another field with its own \"…:\".\n let lead = ''\n for (const f of [...line].sort(byX)) {\n const r = rowOf(f.label)\n const stem = LEAD.exec(f.label.trim())\n if (!r && stem) lead = `\\u0001${stem[1]}`\n else if (r || f.label.includes(':') || COLUMN.test(f.label.trim())) lead = ''\n if (r) groups.set(r, [...(groups.get(r) ?? []), f])\n else if (lead) groups.set(lead, [...(groups.get(lead) ?? []), f])\n else if (COLUMN.test(f.label.trim())) loose.push(f)\n else groups.set(`\\u0000${f.id}`, [f]) // a question of its own (\"Vessel\")\n }\n // Loose column fields join the line's first \"Row – Column\" question, else make one together.\n const host = [...groups.keys()].find((k) => !k.startsWith('\\u0000') && !k.startsWith('\\u0001'))\n if (host) groups.get(host)!.push(...loose)\n else if (loose.length) groups.set(loose.map((f) => f.label).join(' / '), loose) // \"Yes / No\"\n for (const [key, group] of groups) {\n const list = [...group].sort(byX) // left to right, as on the page\n // A name made of the line's column fields (\"Yes / No\"): no question text of its own.\n const led = key.startsWith('\\u0001')\n if (led) {\n const name = (f: FieldDef) => LEAD.exec(f.label.trim())?.[2] ?? (f.label || f.key)\n out.push({\n id: list[0].id,\n title: key.slice(1),\n page,\n parts: list.map((field) => ({ field, name: name(field) })),\n })\n continue\n }\n const generic = !key.startsWith('\\u0000') && list.every((f) => !rowOf(f.label))\n let title = key.startsWith('\\u0000') ? list[0].label || list[0].key : key\n // The document's own words: in place of names made of columns (\"Yes / No\"), or where they carry on a label\n // that was cut short (\"Were the Master and senior…\" → the whole question). Never a different text.\n const written = rowText(text, list)\n const stem = norm(title).replace(/^\\d+(\\.\\d+)*[a-z]?\\s+/, '') // \"2.1.1 Were the…\": the number may sit in its own column\n if (written && (generic || (norm(written).startsWith(stem) && norm(written).length > stem.length)))\n title = written\n out.push({\n id: list[0].id,\n title,\n page,\n parts: list.map((field) => ({\n field,\n name: list.length === 1 && !rowOf(field.label) ? '' : colOf(field.label) || field.key,\n })),\n })\n }\n })\n // Boxes named only by their own label (\"Human\", \"Process\") in a row of a table whose text runs on to their\n // right: the row's text says what the box is about.\n for (const q of out) {\n if (q.rows || q.columns || !q.parts.every((p) => p.field.type === 'checkbox' || p.field.type === 'radio')) continue\n if (!q.parts.some((p) => norm(p.field.label) === norm(q.title))) continue\n const text = sideText(\n textOf(q.page) ?? [],\n q.parts.map((p) => p.field),\n sorted.filter((f) => f.position.page === q.page),\n )\n if (!text) continue\n q.title = text\n q.parts = q.parts.map((p) => ({ ...p, name: p.field.label || p.field.key }))\n }\n for (const { fields: list, title } of stacks)\n out.push({\n id: list[0].id,\n title,\n page: list[0].position.page,\n parts: list.map((field) => ({ field, name: field.label })),\n rows: [list.length],\n block: true,\n })\n const at = (q: Question) => top(q.parts.map((p) => p.field).filter((f) => f.position.page === q.page))\n out.sort((a, b) => a.page - b.page || at(a) - at(b))\n if (categoryCode) setCategories(out, sorted, textOf, categoryCode)\n setSections(out, sorted, textOf)\n setScales(out, textOf)\n return mergeBlocks(out)\n}\n\n// The text written right of boxes on their line (their own names aside), and its lines wrapped under it, until\n// the next box's line or a gap. A wrapped line may start in the boxes' column (\"(tick as appropriate) certificates\n// and…\" read as one line across both columns): the part left of the text's column is cut off, at a word break.\nfunction sideText(lines: TextLine[], boxes: FieldDef[], fields: FieldDef[]) {\n const [y0, y1, x1] = [top(boxes), bottom(boxes), right(boxes)]\n const own = new Set(boxes.map((f) => norm(f.label)))\n const first = lines\n .filter((l) => l.x >= x1 - 0.002 && l.y + l.height / 2 > y0 && l.y + l.height / 2 < y1 && !own.has(norm(l.text)))\n .sort((a, b) => a.x - b.x)[0]\n if (!first) return ''\n const x = first.x\n const others = fields.filter((f) => !boxes.includes(f))\n const out = [first.text.trim()]\n for (let cur = first, k = 0; k < 5; k++) {\n const c = cur\n const next = lines.find(\n (l) =>\n l.y > c.y + c.height / 2 &&\n l.y - (c.y + c.height) < 0.6 * c.height &&\n l.x < x + 0.02 &&\n l.x + l.width > x + 0.02 &&\n !others.some((f) => f.position.y < l.y + l.height && f.position.y + f.position.height > l.y),\n )\n if (!next) break\n let t = next.text.trim()\n if (next.x < x - 0.01) {\n // Cut at the word break nearest to where the column starts, by the share of the line's width.\n const at = Math.round(((x - next.x) / next.width) * t.length)\n const breaks = [...t.matchAll(/ /g)].map((m) => m.index!)\n if (!breaks.length) break\n t = t.slice(breaks.reduce((a, b) => (Math.abs(b - at) < Math.abs(a - at) ? b : a)) + 1)\n }\n out.push(t)\n cur = next\n }\n return out.join(' ').replace(/\\s+/g, ' ')\n}\n\nconst BIG: FieldType[] = ['textarea', 'signature', 'file']\n\n// Boxes one under another at the same x, each the only box on its line and named by its own label, with text left of\n// them: the options of the question written there. Without text beside them they are a list of options under a\n// heading (handled as an option grid).\nfunction findStacks(sorted: FieldDef[], textOf: PageText) {\n const out: { fields: FieldDef[]; title: string }[] = []\n const pages = new Map<number, FieldDef[]>()\n for (const f of sorted) pages.set(f.position.page, [...(pages.get(f.position.page) ?? []), f])\n for (const [page, fs] of pages) {\n const overlaps = (a: FieldDef, b: FieldDef) =>\n a.position.y < b.position.y + b.position.height && a.position.y + a.position.height > b.position.y\n const isBox = (f: FieldDef) => f.type === 'checkbox' || f.type === 'radio'\n // Alone among boxes on its line (a row \"☐ Y ☐ N ☐ NA\" is not a column); a text box beside it may share it.\n const boxes = fs.filter((f) => isBox(f) && f.label.trim() && !fs.some((o) => o !== f && isBox(o) && overlaps(o, f)))\n const used = new Set<FieldDef>()\n for (const f of boxes) {\n if (used.has(f)) continue\n const stack = [f]\n for (const g of boxes) {\n const p = stack[stack.length - 1].position\n if (\n g.position.y > p.y &&\n Math.abs(g.position.x - f.position.x) < 0.006 &&\n g.position.y - (p.y + p.height) < p.height\n )\n stack.push(g)\n }\n if (stack.length < 2) continue\n const title = blockText(textOf(page) ?? [], stack, fs)\n if (!title) continue\n stack.forEach((g) => used.add(g))\n out.push({ fields: stack, title })\n }\n }\n return out\n}\n\n// The text block left of a column of boxes: the lines beside it, and the lines set tight above and below them,\n// up to a category code or numbered heading above and a big answer box (a \"Finding\" textarea) below. Lines\n// carried on in lower case join the line before; the others (\"A1.\", \"A2.\", \"● …\") start their own line.\nfunction blockText(lines: TextLine[], stack: FieldDef[], fields: FieldDef[]) {\n const x = left(stack)\n const [y0, y1] = [top(stack), bottom(stack)]\n const own = new Set(stack.map((f) => norm(f.label)))\n const big = fields.filter((f) => BIG.includes(f.type))\n const stop = (l: TextLine) =>\n (CODE.test(l.text.trim()) && !COLUMN.test(l.text.trim())) ||\n NUMBERED.test(l.text.trim()) ||\n !!tagsOf(l.text) ||\n big.some((f) => f.position.y < l.y + l.height && f.position.y + f.position.height > l.y)\n const col = lines.filter((l) => l.x + l.width <= x + 0.005 && !own.has(norm(l.text))).sort((a, b) => a.y - b.y)\n const beside = (l: TextLine) => l.y + l.height / 2 > y0 && l.y + l.height / 2 < y1\n let i = col.findIndex(beside)\n let j = col.length - 1 - [...col].reverse().findIndex(beside)\n if (i < 0) return ''\n const tight = (a: TextLine, b: TextLine) => b.y - (a.y + a.height) < 1.2 * Math.max(a.height, b.height)\n // The first box may sit level with the category code (\"HF\" │ ☐ Excd. Expectation): the text starts under it.\n for (let k = j; k >= i; k--)\n if (stop(col[k])) {\n if (k === j && (k + 1 >= col.length || !tight(col[k], col[k + 1]) || stop(col[k + 1]))) return ''\n i = k + 1\n j = Math.max(j, i)\n break\n }\n while (i > 0 && !stop(col[i - 1]) && tight(col[i - 1], col[i])) i--\n while (j < col.length - 1 && !stop(col[j + 1]) && tight(col[j], col[j + 1])) j++\n return col\n .slice(i, j + 1)\n .map((l) => l.text.trim())\n .reduce((a, t) => (!a ? t : /^\\p{Ll}/u.test(t) ? `${a} ${t}` : `${a}\\n${t}`), '')\n}\n\n// With categories, a question's parts under one category heading of one numbered question are one card: the\n// column of options with its text, then the \"Finding\" box under it. Two option grids are joined only across a\n// page break (the options of one column split over two pages), into one row.\nfunction mergeBlocks(out: Question[]) {\n if (!out.some((q) => q.category)) return out\n const size = (q: Question) => q.rows?.reduce((x, y) => x + y, 0) ?? 0\n const res: Question[] = []\n for (const q of out) {\n const last = res[res.length - 1]\n const same =\n last &&\n q.category &&\n last.category === q.category &&\n last.section === q.section &&\n !q.columns &&\n !last.columns &&\n (!(q.rows && last.rows) || q.page !== last.page)\n if (!same) {\n res.push(q)\n continue\n }\n const grid = [...last.parts.slice(0, size(last)), ...q.parts.slice(0, size(q))]\n res[res.length - 1] = {\n ...last,\n title: q.block && !last.block ? q.title : last.title,\n parts: [...grid, ...last.parts.slice(size(last)), ...q.parts.slice(size(q))],\n rows: q.rows && last.rows ? [grid.length] : (last.rows ?? q.rows),\n block: last.block || q.block,\n }\n }\n return res\n}\n\n// A category code written as a heading of its own over blocks of questions (\"HW\" / \"PR\" / \"HF\").\nconst CODE = /^[A-Z]{2,4}$/\n\n// Codes first on their line, with no other code after them (a header row \"RANK NAME DATE\" is not), and not a\n// running header or footer (same text at the same height on 3+ pages). The form has categories when at\n// least two codes come back at least twice each; a question takes the last one above it, across page breaks.\nfunction setCategories(out: Question[], fields: FieldDef[], textOf: PageText, code: RegExp) {\n const last = Math.max(0, ...fields.map((f) => f.position.page))\n const found: { page: number; y: number; code: string }[] = []\n const isCode = (t: string) => code.test(t.trim()) && !COLUMN.test(t.trim())\n for (let page = 1; page <= last; page++) {\n const lines = textOf(page) ?? []\n for (const l of lines) {\n if (!isCode(l.text)) continue\n const beside = lines.filter((o) => o !== l && o.y < l.y + l.height && o.y + o.height > l.y)\n if (beside.some((o) => o.x < l.x || isCode(o.text))) continue\n found.push({ page, y: l.y, code: l.text.trim() })\n }\n }\n const marks = found.filter(\n (m) => found.filter((o) => o.page !== m.page && o.code === m.code && Math.abs(o.y - m.y) < 0.003).length < 2,\n )\n const times = new Map<string, number>()\n for (const m of marks) times.set(m.code, (times.get(m.code) ?? 0) + 1)\n if ([...times.values()].filter((t) => t >= 2).length < 2) return\n for (const q of out) q.category = lastAbove(q, marks)?.code\n}\n\n// The last mark (in document order) above a question, by its middle: a cell's answer boxes are centred in it,\n// the first one may start above the heading.\nfunction lastAbove<T extends { page: number; y: number }>(q: Question, marks: T[]) {\n const own = q.parts.map((p) => p.field).filter((f) => f.position.page === q.page)\n const y = (top(own) + bottom(own)) / 2\n return marks.filter((m) => m.page < q.page || (m.page === q.page && m.y <= y)).at(-1)\n}\n\n// A numbered heading: \"2.1.1 Maintenance of statutory Certificates\" (two levels at least: \"1. Vessel free…\" is an\n// item inside a question; \"5.9.2 / 5.10.2\" is an index).\nconst NUMBERED = /^\\d+(\\.\\d+)+\\.?\\s+\\p{L}/u\n\n// Numbered headings first on their line, with no field on it (a line with fields is a question itself): each\n// question shows the heading it answers, carried over page breaks.\nfunction setSections(out: Question[], fields: FieldDef[], textOf: PageText) {\n const last = Math.max(0, ...fields.map((f) => f.position.page))\n const marks: { page: number; y: number; text: string }[] = []\n for (let page = 1; page <= last; page++) {\n const lines = textOf(page) ?? []\n const boxes = fields.filter((f) => f.position.page === page)\n const edge = Math.max(0, ...lines.map((o) => o.x + o.width))\n for (const l of lines) {\n const text = l.text.trim().replace(/\\s+/g, ' ')\n if (!NUMBERED.test(text)) continue\n const across = (y: number, h: number) => y < l.y + l.height && y + h > l.y\n if (lines.some((o) => o !== l && o.x < l.x && across(o.y, o.height))) continue\n const free = (t: TextLine) =>\n !boxes.some((f) => f.position.y < t.y + t.height && f.position.y + f.position.height > t.y)\n if (!free(l)) continue\n // A heading wrapped onto the lines set tight under it: a line that ran to the text's right edge without\n // ending its sentence, or one the next line carries on in lower case (not a \"Note:\" after the heading).\n // Only lines in the heading's own text size: a picture's caption or watermark (\"Sampl\") is not part of it.\n // A heading cut by a picture or a box (\"…was it free of\" [photo] \"any areas for concern?\") carries on in the\n // first line of its size at its x under it, when that line starts in lower case and no field comes between.\n const parts = [text]\n const same = (o: TextLine) => Math.abs(o.height - l.height) < 0.3 * l.height\n for (let cur = l, k = 0; k < 4; k++) {\n const c = cur\n if (/[?.:!)]$/.test(c.text.trim())) break\n let next = lines.find(\n (o) =>\n o.y > c.y &&\n o.y - (c.y + c.height) < 0.5 * c.height &&\n o.x >= l.x - 0.01 &&\n o.x < l.x + l.width &&\n same(o) &&\n !NUMBERED.test(o.text.trim()) &&\n free(o),\n )\n if (next && !/^\\p{Ll}/u.test(next.text.trim()) && c.x + c.width < l.x + 0.85 * (edge - l.x)) break\n if (!next) {\n const below = lines\n .filter((o) => o.y > c.y + c.height && Math.abs(o.x - l.x) < 0.01 && same(o))\n .sort((a, b) => a.y - b.y)[0]\n const between = boxes.some((f) => f.position.y > c.y && f.position.y < (below?.y ?? 0))\n if (below && /^\\p{Ll}/u.test(below.text.trim()) && free(below) && !between) next = below\n }\n if (!next) break\n parts.push(next.text.trim())\n cur = next\n }\n marks.push({ page, y: l.y, text: parts.join(' ').replace(/\\s+/g, ' ') })\n }\n }\n // A numbered question's tags line (anywhere under its heading) applies to all of its questions. Only keys that\n // come back in two numbered questions or more are kept: a one-off \"Name: …, Date: …\" line is not a filter.\n const tagged = new Map<(typeof marks)[number], Record<string, string>>()\n for (let page = 1; page <= last; page++)\n for (const l of textOf(page) ?? []) {\n const tags = tagsOf(l.text)\n const mark = tags && marks.filter((m) => m.page < page || (m.page === page && m.y < l.y)).at(-1)\n if (mark) tagged.set(mark, { ...tagged.get(mark), ...tags })\n }\n const seen = new Map<string, number>()\n for (const t of tagged.values()) for (const k of Object.keys(t)) seen.set(k, (seen.get(k) ?? 0) + 1)\n for (const q of out) {\n const mark = lastAbove(q, marks)\n q.section = mark?.text\n if (q.section && !q.rows && !q.columns) pieceTitle(q, q.section, textOf(q.page) ?? [])\n const tags = Object.entries((mark && tagged.get(mark)) ?? {}).filter(([k]) => seen.get(k)! >= 2)\n if (tags.length) q.tags = Object.fromEntries(tags)\n }\n}\n\n// Letters that look the same in other scripts (\"Ν/S\" typed with a Greek Ν), so a choice matches its legend.\nconst LOOKALIKE: Record<string, string> = {\n Α: 'A',\n Β: 'B',\n Ε: 'E',\n Η: 'H',\n Ι: 'I',\n Κ: 'K',\n Μ: 'M',\n Ν: 'N',\n Ο: 'O',\n Ρ: 'P',\n Τ: 'T',\n Υ: 'Y',\n Χ: 'X',\n Ζ: 'Z',\n}\nconst fold = (t: string) =>\n t\n .replace(/[ΑΒΕΗΙΚΜΝΟΡΤΥΧΖ]/g, (c) => LOOKALIKE[c])\n .trim()\n .toLowerCase()\nconst escape = (t: string) => t.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n\n// Rows answered on the same scale, one under another (\"Chapter 02 … ☐1 ☐2 ☐3 ☐4 ☐5 ☐N/S\"): the text set tight\n// above the first row says what they ask (its column names aside), and a legend on the page (\"5 “excellent”\n// means…\", \"1 = Poor\") says what each choice means, written after the choice's name (\"5 – excellent\").\nfunction setScales(out: Question[], textOf: PageText) {\n for (let i = 0; i < out.length; ) {\n const choices = choicesOf(out[i]).map(fold)\n let j = i + 1\n while (\n choices.length >= 2 &&\n j < out.length &&\n out[j].page === out[i].page &&\n choicesOf(out[j]).map(fold).join('|') === choices.join('|')\n )\n j++\n if (j - i >= 2) scale(out.slice(i, j), choices, textOf)\n i = j\n }\n}\n\nfunction scale(run: Question[], choices: string[], textOf: PageText) {\n const first = run[0]\n const lines = textOf(first.page) ?? []\n const y0 = top(first.parts.map((p) => p.field))\n const isHeader = (l: TextLine) => l.text.split(/\\s+/).every((w) => choices.includes(fold(w)))\n const above = lines.filter((l) => l.y + l.height <= y0 + 0.002 && !isHeader(l)).sort((a, b) => b.y - a.y)\n const block: TextLine[] = []\n for (const l of above) {\n const below = block[block.length - 1]\n const gap = (below ? below.y : y0) - (l.y + l.height)\n if (gap > 1.2 * l.height || block.length === 3) break\n block.push(l)\n }\n const intro = block\n .reverse()\n .map((l) => l.text.trim())\n .join(' ')\n if (intro && !run.some((q) => norm(q.title) === norm(intro))) for (const q of run) q.intro = intro\n\n // The legend: lines that start with a choice's name, on this page or the next.\n const legend = new Map<string, string>()\n for (const l of [...lines, ...(textOf(first.page + 1) ?? [])]) {\n // A bullet before it may be a symbol font's private-use glyph (U+F0B7).\n const t = l.text.replace(/^[\\s\\p{Co}•●▪■◦*–-]+/u, '').trim()\n for (const c of choices) {\n if (legend.has(c)) continue\n const m = new RegExp(`^${escape(c)}\\\\s*(?:[=:–-]\\\\s*|\\\\s)(\\\\S.*)$`, 'i').exec(fold(t))\n if (!m) continue\n const rest = t.slice(t.length - m[1].length)\n const said =\n /[“\"‘]([^”\"’]{1,40})[”\"’]/.exec(rest)?.[1] ??\n rest\n .split(/\\s+means\\s+/i)[0]\n .split(/\\s+/)\n .slice(0, 6)\n .join(' ')\n legend.set(c, said.replace(/[.,;:]$/, ''))\n }\n }\n if (legend.size < Math.max(2, Math.ceil(0.6 * choices.length))) return\n for (const q of run)\n q.parts = q.parts.map((p) => {\n const said = legend.get(fold(p.name))\n return p.field.type === 'checkbox' && said ? { ...p, name: `${p.name} – ${said}` } : p\n })\n}\n\n// A card titled by a piece of its numbered question (\"any areas for concern?\", or the question cut short in a\n// label): the question is in the heading over it, so the card is named by what its box is, the \"Comments:\" written\n// on the box's line, else its part's name.\nfunction pieceTitle(q: Question, section: string, lines: TextLine[]) {\n const title = norm(q.title).replace(/[…]+$/, '')\n if (!title || !norm(section).includes(title)) return\n const f = q.parts[0].field\n const label = lines.find(\n (l) =>\n /^[^:]{1,30}:$/.test(l.text.trim()) && l.y < f.position.y + f.position.height && l.y + l.height > f.position.y,\n )\n const name = label?.text.trim().slice(0, -1) || (q.parts.length === 1 ? q.parts[0].name : '')\n if (!name) return\n q.title = name\n if (q.parts.length === 1 && norm(q.parts[0].name) === norm(name)) q.parts = [{ ...q.parts[0], name: '' }]\n}\n\n// \"Key: Value , Key: Value\": two pairs at least, short keys (up to 3 words) and values.\nconst PAIR = /^\\s*(\\p{L}[\\p{L} ]{0,24}?)\\s*:\\s*([^,:]{1,40}?)\\s*$/u\nfunction tagsOf(text: string) {\n const parts = text.split(',')\n if (parts.length < 2) return null\n const pairs = parts.map((p) => PAIR.exec(p))\n if (pairs.some((m) => !m || m[1].trim().split(/\\s+/).length > 3)) return null\n return Object.fromEntries(pairs.map((m) => [m![1].trim(), m![2].trim()]))\n}\n\nexport const isFilled = (v: AnswerValue | undefined) => v != null && v !== '' && v !== false\n\n// The boxes that are a question's answer choices: its option grid, else its boxes (\"Y / N / NA\" on one line, or\n// a lone \"☐ Human\").\nfunction choiceParts(q: Question) {\n if (q.columns) return []\n const size = q.rows?.reduce((a, b) => a + b, 0) ?? 0\n const boxes = (q.rows ? q.parts.slice(0, size) : q.parts).filter((p) => p.field.type === 'checkbox')\n return boxes\n}\nconst radioOf = (q: Question) => q.parts.find((p) => p.field.type === 'radio' && p.field.options?.length)?.field\n\n/** A question's answer choices (\"Yes\", \"No\", \"NA\"), from its boxes or its radio buttons. */\nexport function choicesOf(q: Question): string[] {\n const boxes = choiceParts(q)\n if (boxes.length) return boxes.map((p) => (p.name || p.field.label).trim())\n return radioOf(q)?.options ?? []\n}\n\n/** The choices ticked in a question's answers. */\nexport function pickedOf(q: Question, answers: Answers): string[] {\n const boxes = choiceParts(q)\n if (boxes.length)\n return boxes.filter((p) => answers[p.field.key] === true).map((p) => (p.name || p.field.label).trim())\n const radio = radioOf(q)\n const v = radio && answers[radio.key]\n return typeof v === 'string' && v ? [v] : []\n}\n","// Question-list filters as plain objects. Nothing here decides what a form \"should\" show: each filter says what\n// can be picked in this form (`options`, empty = nothing to filter on) and how a question passes (`test`). The\n// built-ins are presets; pass your own list (any order, any subset, your own filters) wherever filters are taken.\nimport type { Answers, FieldType } from './form-logic'\nimport { choicesOf, isFilled, pickedOf, type Question } from './questions'\n\nexport interface FilterOption {\n value: string\n label: string\n /** How many questions have it. */\n count?: number\n}\n\nexport interface QuestionFilterDef {\n /** Unique key: the filter's value is stored under it. */\n id: string\n title: string\n /** Where a UI may put it, e.g. a heading to group it under (\"Progress\") or \"bar\" for always visible. A hint only. */\n section?: string\n /** What can be picked in these questions. Counts may follow the answers. */\n options: (questions: Question[], answers: Answers) => FilterOption[]\n /** Whether a question passes when `value` is picked. */\n test: (q: Question, value: string, answers: Answers) => boolean\n}\n\n/** A filter, or a function making several from the questions (one per tag key, …). */\nexport type FilterSource = QuestionFilterDef | ((questions: Question[]) => QuestionFilterDef[])\n\n/** Picked value per filter id (absent / null = not filtering on it). */\nexport type FilterValues = Record<string, string | null | undefined>\n\nconst counted = (questions: Question[], values: (q: Question) => string[], label = (v: string) => v) => {\n const m = new Map<string, number>()\n for (const q of questions) for (const v of new Set(values(q))) m.set(v, (m.get(v) ?? 0) + 1)\n return [...m].map(([value, count]) => ({ value, label: label(value), count }))\n}\n\nconst filledOptions = (yes: string, no: string): FilterOption[] => [\n { value: 'filled', label: yes },\n { value: 'empty', label: no },\n]\nfunction filledTest(parts: Question['parts'], value: string, answers: Answers) {\n if (!parts.length) return false // filtering on remarks: questions without a remarks box are not shown\n const any = parts.some((p) => isFilled(answers[p.field.key]))\n return value === 'filled' ? any : !any\n}\n\n/** Answered / not answered (any part of the question). */\nexport const answeredFilter = ({\n id = 'answered',\n title = 'Answered',\n yes = 'Answered',\n no = 'Not answered',\n section = 'Progress',\n} = {}): QuestionFilterDef => ({\n id,\n title,\n section,\n options: (qs) => (qs.length ? filledOptions(yes, no) : []),\n test: (q, v, a) => filledTest(q.parts, v, a),\n})\n\n/**\n * Written / empty for the parts whose name or label matches `match` (\"Remarks\", \"Comments\", \"Finding\"…).\n * Offers nothing for a form without such parts.\n */\nexport function partFilter({\n id,\n title,\n match,\n yes = 'Written',\n no = 'Empty',\n section = 'Progress',\n}: {\n id: string\n title: string\n match: RegExp\n yes?: string\n no?: string\n section?: string\n}): QuestionFilterDef {\n const parts = (q: Question) => q.parts.filter((p) => match.test(p.name) || match.test(p.field.label))\n return {\n id,\n title,\n section,\n options: (qs) => (qs.some((q) => parts(q).length) ? filledOptions(yes, no) : []),\n test: (q, v, a) => filledTest(parts(q), v, a),\n }\n}\n\n/** Questions that offer an answer choice (\"Yes\", \"NA\", \"As Expected\"): choices offered by `min`+ questions. */\nexport const choiceFilter = ({\n id = 'choices',\n title = 'Has option',\n section = 'Answers',\n min = 2,\n max = 40,\n} = {}): QuestionFilterDef => ({\n id,\n title,\n section,\n options: (qs) =>\n counted(qs, choicesOf)\n .filter((o) => o.count >= min)\n .slice(0, max),\n test: (q, v) => choicesOf(q).includes(v),\n})\n\n/** Questions answered with a choice (counts follow the answers). */\nexport const pickedFilter = ({\n id = 'picked',\n title = 'Answered with',\n section = 'Answers',\n min = 2,\n max = 40,\n} = {}): QuestionFilterDef => ({\n id,\n title,\n section,\n options: (qs, answers) => {\n const offered = new Set(\n choiceFilter({ min, max })\n .options(qs, answers)\n .map((o) => o.value),\n )\n const picked = new Map(counted(qs, (q) => pickedOf(q, answers)).map((o) => [o.value, o.count]))\n return [...offered].map((c) => ({ value: c, label: c, count: picked.get(c) ?? 0 }))\n },\n test: (q, v, a) => pickedOf(q, a).includes(v),\n})\n\n/** By the category heading a question sits under (Question.category). */\nexport const categoryFilter = ({ id = 'category', title = 'Category', section = 'bar' } = {}): QuestionFilterDef => ({\n id,\n title,\n section,\n options: (qs) => counted(qs, (q) => (q.category ? [q.category] : [])),\n test: (q, v) => q.category === v,\n})\n\n/** By answer type (a question with any part of that type). */\nexport const typeFilter = ({\n id = 'type',\n title = 'Answer type',\n section = 'Answer type',\n label = (t: FieldType): string => t,\n} = {}): QuestionFilterDef => ({\n id,\n title,\n section,\n options: (qs) => {\n const opts = counted(\n qs,\n (q) => q.parts.map((p) => p.field.type),\n (t) => label(t as FieldType),\n )\n return opts.length > 1 ? opts : []\n },\n test: (q, v) => q.parts.some((p) => p.field.type === v),\n})\n\n/** One filter on a tag key (\"Risk\": H / M / L) of Question.tags. */\nexport const tagFilter = (key: string, { title = key, section = 'Question details' } = {}): QuestionFilterDef => ({\n id: `tag:${key}`,\n title,\n section,\n options: (qs) =>\n counted(qs, (q) => (q.tags?.[key] ? [q.tags[key]] : [])).sort((a, b) =>\n a.value.localeCompare(b.value, undefined, { numeric: true }),\n ),\n test: (q, v) => q.tags?.[key] === v,\n})\n\n/** A tagFilter for every tag key in the questions. */\nexport const tagFilters =\n ({ section = 'Question details' } = {}) =>\n (qs: Question[]): QuestionFilterDef[] =>\n [...new Set(qs.flatMap((q) => Object.keys(q.tags ?? {})))].map((k) => tagFilter(k, { section }))\n\n/** Your own filter in one line: `customFilter('deck', 'Deck', (q) => q.page <= 3 ? ['Upper'] : ['Lower'])`. */\nexport const customFilter = (\n id: string,\n title: string,\n valuesOf: (q: Question, answers: Answers) => string[],\n section?: string,\n): QuestionFilterDef => ({\n id,\n title,\n section,\n options: (qs, answers) => counted(qs, (q) => valuesOf(q, answers)),\n test: (q, v, a) => valuesOf(q, a).includes(v),\n})\n\n/** The built-in presets, in the built-in UI's order. Start from it, filter it, or ignore it. */\nexport const builtinFilters = (labels: { type?: (t: FieldType) => string } = {}): FilterSource[] => [\n answeredFilter(),\n partFilter({ id: 'remarks', title: 'Remarks', match: /remark/i }),\n partFilter({ id: 'comments', title: 'Comments', match: /comment/i }),\n choiceFilter(),\n pickedFilter(),\n tagFilters(),\n typeFilter({ label: labels.type }),\n categoryFilter(),\n]\n\n/** The filter objects for these questions (functions expanded). */\nexport const resolveFilters = (sources: FilterSource[], questions: Question[]) =>\n sources.flatMap((s) => (typeof s === 'function' ? s(questions) : [s]))\n\n/** The text search looks in: section, intro, title and the parts' labels. */\nexport const searchText = (q: Question) =>\n `${q.section ?? ''} ${q.intro ?? ''} ${q.title} ${q.parts.map((p) => p.field.label).join(' ')}`\n\n/** The questions that pass the search and every picked filter value. */\nexport function filterQuestions(\n questions: Question[],\n answers: Answers,\n filters: QuestionFilterDef[],\n values: FilterValues,\n search = '',\n) {\n const text = search.trim().toLowerCase()\n const active = filters.filter((f) => values[f.id] != null)\n return questions.filter(\n (q) =>\n (!text || searchText(q).toLowerCase().includes(text)) && active.every((f) => f.test(q, values[f.id]!, answers)),\n )\n}\n"],"mappings":"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","names":["newId","top","left","right","bottom","bottom","t"]}