Skip to content

feat(pipeline): IDML parser and intermediate representation#77

Merged
PAMulligan merged 1 commit into
mainfrom
62-indesign-pipeline-idml-parser-and-intermediate-representation
May 21, 2026
Merged

feat(pipeline): IDML parser and intermediate representation#77
PAMulligan merged 1 commit into
mainfrom
62-indesign-pipeline-idml-parser-and-intermediate-representation

Conversation

@PAMulligan
Copy link
Copy Markdown
Collaborator

Closes #62. Foundational sub-issue for the InDesign-to-WordPress pipeline (#61).

Summary

  • New @flavian/pipeline workspace package (this PR creates the packages/* workspace; it's the first occupant)
  • parseIdml(path) / parseIdmlBuffer(bytes) — unzip via fflate, parse XML via fast-xml-parser, resolve Self/ParentStory cross-references, validate the final shape with zod
  • IR covers Document, Spread, Page, Frame (discriminated union of TextFrame + ImageFrame), Story, Style, Swatch, Font, MasterSpread
  • Unit normalizer: pt / pc / mm / cm / in / px → px at configurable DPI (default 96)
  • Warning collector — missing optional resources, dangling refs, unknown color spaces, empty stories surface on the IR rather than throwing
  • CLI: flavian-parse-idml <file.idml> (JSON on stdout, warnings on stderr)
  • 20 tests via Node's built-in node:test: happy path + the three malformed cases the issue calls out (missing manifest throws; unknown style refs warn; empty stories give empty run lists) + unit-conversion coverage

Decisions worth flagging

  1. Language: issue text says packages/pipeline/src/indesign/ir.ts, but the repo has zero TypeScript today (everything is .mjs ESM + JSDoc + node:test). I used .js + JSDoc + zod so the new package matches the rest of the repo. z.infer<typeof Document> gives any future TS consumer the types for free. Happy to migrate to TS if you'd rather.
  2. Fixtures: built programmatically by tests/indesign/helpers/build-idml.js — no binary blobs in git, no InDesign required to maintain them. The epic's "commit .idml fixtures" AC lives on Add InDesign-to-WordPress conversion pipeline #61, not here.

Acceptance criteria (from #62)

  • Given a fixture .idml, the parser produces a valid IR object that passes schema validation (zod)
  • All swatches, paragraph styles, character styles, and fonts are enumerated in the IR
  • Image frames reference resolvable asset paths inside the IDML package (href + embedded flag)
  • Unit tests cover happy path + at least three malformed/edge-case IDMLs (missing manifest, unknown style refs, empty stories; also bonus: malformed zip, missing optional resources, unknown color space)
  • Parse warnings are collected on the IR and surfaced by the CLI (process.stderr.write for each)

CI

pipeline-tests.yml got a new path filter (packages/pipeline/** and pnpm-workspace.yaml) and a new job that runs pnpm --filter @flavian/pipeline test via pnpm + Node 20. Existing bats jobs unchanged.

Test plan

  • pnpm install from a clean clone succeeds (workspace resolution)
  • pnpm --filter @flavian/pipeline test reports 20/20 passing
  • node packages/pipeline/bin/parse-idml.mjs <real-exported.idml> against a real IDML produces JSON with non-empty swatches, styles, and spreads
  • CI Pipeline Tests workflow is green on this PR

🤖 Generated with Claude Code

Closes #62. Foundational sub-issue for the InDesign-to-WordPress pipeline
(#61). Ships:

- `@flavian/pipeline` workspace package (new `packages/*` workspace; this
  is the first occupant)
- `parseIdml(path)` / `parseIdmlBuffer(bytes)` — unzip via fflate, parse
  XML via fast-xml-parser, resolve Self/ParentStory cross-refs, validate
  the final shape with zod
- IR covering Document, Spread, Page, Frame (discriminated union of
  TextFrame + ImageFrame), Story, Style, Swatch, Font, MasterSpread
- Unit normalizer (pt/pc/mm/cm/in/px → px at configurable DPI, default 96)
- Warning collector — non-fatal issues (missing optional resources,
  dangling style refs, unknown color spaces, empty stories) surface on
  the IR rather than throwing
- CLI: `flavian-parse-idml <file.idml>` (JSON on stdout, warnings on stderr)
- 20 tests via `node --test`: happy path (parses full IDML with swatches,
  fonts, styles, story, spread, master), three malformed cases called
  out in the issue (missing manifest throws; unknown style refs warn;
  empty stories produce empty run lists), plus unit conversion coverage

Notes on language choice: the issue spec says `ir.ts` but the repo has
zero TypeScript today. Used `.js` + JSDoc + zod instead to match the
existing `.mjs` + node:test stack. `z.infer` gives any future TS
consumer the types for free.

Notes on fixtures: built programmatically by
`tests/indesign/helpers/build-idml.js` — no binary blobs in git, no
InDesign required to maintain or evolve them. The epic's AC for
committed `.idml` files lives on #61, not here.

CI: extended `pipeline-tests.yml` with a `packages/pipeline/**` path
filter and a new job that runs `pnpm --filter @flavian/pipeline test`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@PAMulligan PAMulligan linked an issue May 21, 2026 that may be closed by this pull request
@PAMulligan PAMulligan merged commit f970fc5 into main May 21, 2026
4 checks passed
@PAMulligan PAMulligan deleted the 62-indesign-pipeline-idml-parser-and-intermediate-representation branch May 21, 2026 14:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[InDesign pipeline] IDML parser and intermediate representation

1 participant