Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,137 @@
# Tasks — @suaveplan/pdf migration
## Chunk A — Foundation (THIS CHANGE)
Status: **SHIPPED** in this change.
- [x] Scaffold `packages/devtools/docs/pdf/` (package.json, vite, vitest,
tsconfig.lib.json, README, biome).
- [x] `src/types/` — page-size enum, dimensions table, margins, document /
page / element types, colour types, unit type. One `.md` per `.ts`.
- [x] `src/error-codes/` — `PDF_CODES` via `defineCodes`, `PdfError` class,
`asPdfError` helper.
- [x] `src/schemas/` — Zod schemas (`UnitSchema`, `HexColorSchema`,
`RgbColorSchema`, `MarginsSchema`, `PageConfigSchema`,
`DocumentMetadataSchema`) + `parseOrThrow` helper raising `PdfError`.
- [x] `src/telemetry/` — six OTel instruments + `createPdfObservability`
factory + recording helpers.
- [x] `src/units/` — `toPoints`, `fromPoints`, `convert`, `parseUnit`,
`formatUnit` raising typed errors.
- [x] `src/colors/` — `hexToRgb`, `rgbToPdfColor`, `hexToPdfColor`,
`rgbToHex`, `lighten`, `darken`, `COLORS`, `isTransparent`.
- [x] Pre-publish gate: `bunx turbo lint typecheck test build --filter=@suaveplan/pdf`
green, `bunx turbo test:coverage --filter=@suaveplan/pdf` 100 / 100 / 100 / 100.
- [x] Refresh `MANIFEST.md`.
## Chunk B — Low-level writer
Status: **SHIPPED** in this change.
- [x] `src/pdf-writer/` — hand-rolled PDF 1.4 writer with:
indirect-object table, font registry for the 14 standard fonts,
stream-object assembly (raw + FlateDecode via `node:zlib`),
xref + trailer, deterministic ordering, injectable `Clock` for
`/CreationDate`, AbortSignal-aware `generate`, `dispose()` guard.
- [x] `src/content-stream/` — encoder for `BT/ET`, `Td`/`T*`/`TL`/`Tm`,
`Tj`/`Tf`, `q/Q`, `rg/RG`, `m/l/h/S/s/f/B`, `re`, `cm`, `w`, and
image XObject `Do` placement with text-mode invariants.
- [x] Real PDF parse verification via `pdf-parse@^2.4` round-trip
(text content + page count + metadata + ProducerInfo).
## Chunk C — Elements
Status: **SHIPPED** in this change.
- [x] `src/text-element/` — `TextElement` class + `wrapText` +
`resolveStandardFont` + `measureLineWidth` with alignment,
max-lines overflow flag, kerning, `AbortSignal`.
- [x] `src/table-element/` — `TableElement<TRow>` with column-width
auto-distribution, header repeat across pages via
`renderPage(context, rowStart)`, alternating row backgrounds,
border + column dividers, `LAYOUT_OVERFLOW` typed error.
- [x] `src/image-element/` — `ImageElement` with PNG decode via
`pngjs` (RGB + optional SMask alpha plane), JPEG pass-through via
SOF-marker walk for width/height, `detectImageFormat`,
`scaleToFit`, `validateImageProps`, declared-format mismatch
detection.
- [x] `src/divider-element/` — `DividerElement` with horizontal /
vertical orientation, dash pattern, spacing above / below,
`computeDividerSpacing` flow helper.
- [x] Zod input schema per element type.
- [x] Real pdf-parse round-trip per text + table element.
- [x] Pre-publish gate: lint + typecheck + test + build green,
coverage 100 / 100 / 100 / 100.
## Chunk D — Layout, styles, document builder, renderer
Status: **SHIPPED** in this change.
- [x] `src/style-resolver/` — `StyleResolver` cascade
(`DEFAULT_STYLE` → theme → base → overrides), `mergeStyles`,
`mergeTheme` deep merge incl. `headingSizes`, `normalizeSpacing`
with `PDF.INVALID_ELEMENT` on non-finite input, `DEFAULT_THEME`
palette.
- [x] `src/layout-engine/` — `LayoutEngine` with cursor + content-area
+ header/footer slot rectangles, landscape orientation swap,
`advance(cursor, height)` returning `{ fit, remaining }`,
`nextPage`, `computeTextHeight`, `applyMargin`, AbortSignal
propagation, typed `PDF.LAYOUT_OVERFLOW` /
`PDF.INVALID_PAGE_CONFIG` errors.
- [x] `src/document-builder/` — `DocumentBuilder<TData>` fluent API
(`title` / `author` / `subject` / `keywords` / `creator` /
`creationDate` / `pageConfig` / `withData` / `addText` /
`addTable` / `addImage` / `addDivider` / `newPage` / `setHeader`
/ `setFooter` / `build`) + `createDocument<TData>()` factory.
- [x] `src/image-registry/` — `ImageRegistry` + `registerImageXObject`
that allocate per-element PDF XObjects (DCTDecode for JPEG,
FlateDecode for PNG RGB plane) and share them across logical
pages.
- [x] `src/render-pipeline/` — `placeNode` / `renderTableSlice` /
`renderSlot` / `pickFontResource` helpers operating on a
`PipelineState` bundle.
- [x] `src/renderer/` — top-level `renderDocument(doc, opts)`
returning `{ bytes, pageCount, durationMs }`. AbortSignal-aware,
emits six OTel instruments (documents-rendered counter,
pages-emitted counter, render-errors counter tagged by code,
validation-failures counter, render-duration histogram,
document-size histogram). Page-break + table-continuation loop;
raises `PDF.LAYOUT_OVERFLOW` for elements that cannot fit on a
fresh page.
- [x] Real pdf-parse round-trip tests covering text, multi-page flow,
oversize-table pagination with header repeat, header / footer
stamping across emitted pages, image XObject embedding.
- [x] Pre-publish gate: `bunx turbo lint typecheck test build
--filter=@suaveplan/pdf` green AND
`bunx turbo test:coverage --filter=@suaveplan/pdf`
100 / 100 / 100 / 100.
## Chunk E — Templates
Status: **SHIPPED** in this change.
- [x] `src/templates/invoice-template/` — `createInvoiceTemplate` +
`InvoiceDataSchema` + `computeInvoiceTotals` + `formatInvoiceAmount`.
- [x] `src/templates/receipt-template/` — `createReceiptTemplate` +
`ReceiptDataSchema` + `computeReceiptTotals` + `formatReceiptAmount`.
- [x] `src/templates/report-template/` — `createReportTemplate` +
`ReportDataSchema`.
- [x] Zod input schema per template with `PDF.INVALID_TEMPLATE_INPUT`
error path attaching the failing issue paths.
- [x] Real pdf-parse round-trip per template.
- [x] Pre-publish gate: `bunx turbo lint typecheck test build
--filter=@suaveplan/pdf` green AND
`bunx turbo test:coverage --filter=@suaveplan/pdf`
100 / 100 / 100 / 100.
React PDF preview component — deferred to a follow-up change
(`enterprise-react-pdf-preview` stub left under `openspec/changes/`).
## Cross-chunk invariants (preserved at every step)
- One `.md` per `.ts` ≥ 200 words covering Purpose, Features, Usage: Basic,
Usage: Advanced, API Reference, Implementation Notes.
- 100 / 100 / 100 / 100 Istanbul coverage on every touched module — no
`istanbul ignore` comments, no `// biome-ignore`.
- Every `it` / `test` carries `{ timeout: 5000 }` (30 000 for async).
- Tests import from `@suaveplan/testing/runner` per rule 11.
- No `export *` in non-root barrels (rule 10).