Skip to content

fix: accept every PDF standard and fail on invalid combinations - #2

Closed
msallin wants to merge 1 commit into
developfrom
fix/pdf-standard-parsing
Closed

fix: accept every PDF standard and fail on invalid combinations#2
msallin wants to merge 1 commit into
developfrom
fix/pdf-standard-parsing

Conversation

@msallin

@msallin msallin commented Sep 4, 2026

Copy link
Copy Markdown
Member

Problem

Two defects in how pdfStandards is handled, both ending in a document that does not conform to what was requested.

PDF/UA-1 could not be requested. The accepted names were a hand-written match in compile_internal. It listed the PDF versions and the PDF/A levels but omitted ua-1, so the accessibility standard was rejected outright even though typst-pdf 0.15.1 supports it. Any standard added by a later Typst release would need the table updated by hand.

Invalid combinations were silently downgraded. export_pdf called PdfStandards::new(standards).unwrap_or_default(). When a combination is contradictory the validation error was discarded and export fell back to the default configuration, producing an ordinary PDF while reporting success. A pipeline could believe it was writing PDF/A until an archive validator disagreed.

Running the new tests against develop:

[Test Failure] InvalidOperationException: Invalid PDF standard: ua-1
[Test Failure] AssertionException: Expected exception message to contain "PDF/A"
[Test Failure] AssertionException: Expected exception message to contain "same time"
[Test Failure] AssertionException: Expected to throw InvalidOperationException

The last is the silent downgrade: ["a-1b", "v-2.0"] contradicts itself, and the export succeeded anyway.

Change

Standard names are parsed through PdfStandard's own serde representation instead of a table, so every variant Typst defines is accepted and future ones need no change here. PdfStandard is #[non_exhaustive], so an exhaustive match was not possible from outside the crate in any case. The v- prefix on plain PDF versions is kept as an alias because the README documents v-1.7.

export_pdf propagates the error from PdfStandards::new instead of discarding it, including the hints Typst attaches, which name the PDF versions each standard allows. The wording for an unknown name is unchanged, so InvalidPdfStandardThrowsException still passes.

Tests

Eight Rust unit tests over the parser cover every alias form, ua-1, case-insensitivity, blank entries and unknown names. Six tests in Tests.cs cover the behaviour end to end: ua-1 marks the output with pdfuaid:part, a-2b marks it with pdfaid:part where a plain export does not, and each contradictory combination throws with the upstream message.

cargo test --release   11 passed
dotnet test            51 passed

Note for reviewers: PDF/A requires the document to carry a date, and the exporter deliberately sets no timestamp, so the conformance tests set one in the template. This is worth documenting for users adopting PDF/A.

The names accepted by `pdfStandards` were a hand-written table. It omitted
`ua-1`, so PDF/UA-1 could not be requested at all even though typst-pdf
supports it, and every future standard would need the table updated.
`PdfStandard` is `#[non_exhaustive]` and derives serde, so the names are now
read from the enum itself. The `v-` prefix on plain PDF versions stays valid
as an alias because the README documents it.

Separately, `export_pdf` called `PdfStandards::new(..).unwrap_or_default()`,
which discarded the validation error and exported an ordinary PDF while
reporting success. An archival pipeline could believe it was storing PDF/A
documents that carried no conformance at all, and nothing would reveal it
until a validator rejected them. The error is now propagated with the hints
Typst attaches, which name the PDF versions each standard allows.
@msallin
msallin force-pushed the fix/pdf-standard-parsing branch from 856d09d to c8c91d7 Compare September 4, 2026 11:19
@msallin

msallin commented Sep 4, 2026

Copy link
Copy Markdown
Member Author

Superseded by evolvedlight#38; the fix belongs upstream.

@msallin msallin closed this Sep 4, 2026
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.

1 participant