From ea03336fb92968a0f492e5cc2480a2416de0ea26 Mon Sep 17 00:00:00 2001 From: yousefed Date: Thu, 27 Aug 2026 14:03:47 +0200 Subject: [PATCH 1/9] feat(pdf): own Typst wasm compiler (@blocknote/xl-typst-compiler), replacing typst.ts Compiles the official typst crates to wasm behind a minimal TypeScript API and moves the whole PDF pipeline onto it: native, validated PDF/UA-1 (tryDeclarePdfUA with typed violations), compile failures as values (compileErrors/compileWarnings), no CDN or network access anywhere, no page-level compiler singleton, and no @myriaddreamin/* or @cantoo/pdf-lib runtime dependencies. The wasm builds from rust/ via a self-provisioning build step (scripts/ensure-wasm.mjs) that covers CI and Vercel. --- .github/workflows/build.yml | 13 +- .github/workflows/fresh-install-tests.yml | 3 - .github/workflows/publish.yaml | 4 + docs/app/demo/_components/DemoEditor.tsx | 16 +- docs/components/typstCompilerWasmUrl.ts | 4 +- docs/components/typstRendererStub.ts | 4 - docs/content/docs/features/export/pdf.mdx | 122 +- docs/next.config.ts | 9 +- docs/package.json | 5 +- .../.bnexample.json | 3 +- .../package.json | 3 +- .../src/App.tsx | 32 +- packages/diagram-block/package.json | 2 +- .../withDiagramMappings/diagramDocument.typ | 4 +- packages/math-block/package.json | 2 +- .../withMathMappings/mathDocument.typ | 4 +- packages/xl-pdf-exporter/package.json | 8 +- packages/xl-pdf-exporter/src/index.ts | 187 +- .../xl-pdf-exporter/src/pdfExporter.test.ts | 189 +- packages/xl-pdf-exporter/src/pdfExporter.ts | 300 ++ .../src/pdfua/__fixtures__/tagged.pdf | Bin 25729 -> 0 bytes .../src/pdfua/__snapshots__/render/.gitignore | 2 - .../__snapshots__/render/testDocument-1.png | Bin 66445 -> 0 bytes .../__snapshots__/render/testDocument-2.png | Bin 120977 -> 0 bytes .../__snapshots__/render/testDocument-3.png | Bin 30748 -> 0 bytes .../__snapshots__/render/testDocument-4.png | Bin 76202 -> 0 bytes .../src/pdfua/compileBrowser.browser.test.ts | 85 - .../src/pdfua/compileBrowser.ts | 200 -- .../src/pdfua/compileTypst.browser.test.ts | 112 + .../xl-pdf-exporter/src/pdfua/compileTypst.ts | 88 + .../xl-pdf-exporter/src/pdfua/pdfua.test.ts | 168 +- .../src/pdfua/postProcess.test.ts | 110 - .../xl-pdf-exporter/src/pdfua/postProcess.ts | 174 - packages/xl-pdf-exporter/vite.config.ts | 3 + packages/xl-typst-compiler/.gitignore | 2 + packages/xl-typst-compiler/README.md | 66 + packages/xl-typst-compiler/package.json | 67 + packages/xl-typst-compiler/rust/Cargo.lock | 3128 +++++++++++++++++ packages/xl-typst-compiler/rust/Cargo.toml | 32 + .../rust/rust-toolchain.toml | 3 + packages/xl-typst-compiler/rust/src/lib.rs | 353 ++ .../xl-typst-compiler/scripts/ensure-wasm.mjs | 140 + packages/xl-typst-compiler/src/index.ts | 8 + .../src/typstCompiler.test.ts | 262 ++ .../xl-typst-compiler/src/typstCompiler.ts | 183 + packages/xl-typst-compiler/tsconfig.json | 25 + packages/xl-typst-compiler/vite.config.ts | 60 + packages/xl-typst-exporter/package.json | 4 +- .../src/typstExporter.test.ts | 12 +- .../xl-typst-exporter/src/typstExporter.ts | 40 +- playground/package.json | 4 +- playground/src/examples.gen.tsx | 3 +- pnpm-lock.yaml | 291 +- pnpm-workspace.yaml | 2 + shared/package.json | 6 +- shared/util/binaryFileSnapshotUtil.ts | 94 - shared/util/typstTestUtil.ts | 113 +- tests/docker-run.sh | 13 + tests/package.json | 6 +- tests/scripts/install-pdf-tooling.sh | 69 - .../exporters/exporterImages.test.tsx | 160 +- tests/vite.config.browser.ts | 7 +- 62 files changed, 5575 insertions(+), 1434 deletions(-) delete mode 100644 docs/components/typstRendererStub.ts create mode 100644 packages/xl-pdf-exporter/src/pdfExporter.ts delete mode 100644 packages/xl-pdf-exporter/src/pdfua/__fixtures__/tagged.pdf delete mode 100644 packages/xl-pdf-exporter/src/pdfua/__snapshots__/render/.gitignore delete mode 100644 packages/xl-pdf-exporter/src/pdfua/__snapshots__/render/testDocument-1.png delete mode 100644 packages/xl-pdf-exporter/src/pdfua/__snapshots__/render/testDocument-2.png delete mode 100644 packages/xl-pdf-exporter/src/pdfua/__snapshots__/render/testDocument-3.png delete mode 100644 packages/xl-pdf-exporter/src/pdfua/__snapshots__/render/testDocument-4.png delete mode 100644 packages/xl-pdf-exporter/src/pdfua/compileBrowser.browser.test.ts delete mode 100644 packages/xl-pdf-exporter/src/pdfua/compileBrowser.ts create mode 100644 packages/xl-pdf-exporter/src/pdfua/compileTypst.browser.test.ts create mode 100644 packages/xl-pdf-exporter/src/pdfua/compileTypst.ts delete mode 100644 packages/xl-pdf-exporter/src/pdfua/postProcess.test.ts delete mode 100644 packages/xl-pdf-exporter/src/pdfua/postProcess.ts create mode 100644 packages/xl-typst-compiler/.gitignore create mode 100644 packages/xl-typst-compiler/README.md create mode 100644 packages/xl-typst-compiler/package.json create mode 100644 packages/xl-typst-compiler/rust/Cargo.lock create mode 100644 packages/xl-typst-compiler/rust/Cargo.toml create mode 100644 packages/xl-typst-compiler/rust/rust-toolchain.toml create mode 100644 packages/xl-typst-compiler/rust/src/lib.rs create mode 100644 packages/xl-typst-compiler/scripts/ensure-wasm.mjs create mode 100644 packages/xl-typst-compiler/src/index.ts create mode 100644 packages/xl-typst-compiler/src/typstCompiler.test.ts create mode 100644 packages/xl-typst-compiler/src/typstCompiler.ts create mode 100644 packages/xl-typst-compiler/tsconfig.json create mode 100644 packages/xl-typst-compiler/vite.config.ts delete mode 100644 shared/util/binaryFileSnapshotUtil.ts delete mode 100755 tests/scripts/install-pdf-tooling.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d6a941508b..1a86990c37 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,15 +31,16 @@ jobs: - name: Install Dependencies run: vp install + # `vp run -r build` includes @blocknote/xl-typst-compiler, whose build + # task compiles its Rust wasm when missing or stale (rustup is + # preinstalled on the runners; the pinned toolchain + wasm32 target + # auto-provision from rust/rust-toolchain.toml). - name: Build packages run: vp run -r build - name: Lint packages run: vp lint - - name: Install PDF tooling (veraPDF conformance gate + poppler visual snapshots) - run: bash tests/scripts/install-pdf-tooling.sh - - name: Run unit tests run: vp run test @@ -89,6 +90,12 @@ jobs: - name: Install dependencies run: vp install + # The e2e suite consumes xl-typst-compiler through its build outputs + # (see tests/vite.config.browser.ts). Its build task also compiles the + # Rust wasm when missing (rustup is preinstalled on the runners). + - name: Build Typst compiler package + run: vp run --filter @blocknote/xl-typst-compiler build + # No preview server: Vitest Browser Mode serves the tests + mounted example # apps itself. `--browser` selects this matrix job's browser and # `--shard=/` splits that browser's test files across two diff --git a/.github/workflows/fresh-install-tests.yml b/.github/workflows/fresh-install-tests.yml index b713b4a785..edf45382d0 100644 --- a/.github/workflows/fresh-install-tests.yml +++ b/.github/workflows/fresh-install-tests.yml @@ -82,9 +82,6 @@ jobs: name: Build packages run: vp run -r build - - name: Install PDF tooling (veraPDF conformance gate + poppler visual snapshots) - run: bash tests/scripts/install-pdf-tooling.sh - - id: run_unit_tests name: Run unit tests run: vp run test diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 01bb86785f..59e58c459d 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -42,6 +42,10 @@ jobs: - name: Prebuild run: cp README.md packages/core/README.md && cp README.md packages/react/README.md + # `vp run -r build` includes @blocknote/xl-typst-compiler, whose build + # task compiles its Rust wasm (published inside the package as pkg/); + # rustup auto-provisions the pinned toolchain from + # rust/rust-toolchain.toml. - name: Build packages run: vp run -r build diff --git a/docs/app/demo/_components/DemoEditor.tsx b/docs/app/demo/_components/DemoEditor.tsx index 724b2760fb..2f8733da4d 100644 --- a/docs/app/demo/_components/DemoEditor.tsx +++ b/docs/app/demo/_components/DemoEditor.tsx @@ -50,7 +50,7 @@ import { } from "@blocknote/xl-pdf-exporter"; // Bundle the Typst compiler wasm (resolved to a local asset in // next.config.ts) instead of loading it from a CDN. -import compilerWasmUrl from "@myriaddreamin/typst-ts-web-compiler/wasm?url"; +import compilerWasmUrl from "@blocknote/xl-typst-compiler/wasm?url"; import { DefaultChatTransport } from "ai"; import { useTheme } from "next-themes"; import { useEffect, useMemo, useState } from "react"; @@ -344,11 +344,19 @@ function DemoEditorInner({ editor.schema, typstDefaultSchemaMappings, ); - blob = await exporter.toBlob( + const result = await exporter.toBlob( editor.document, - { getModule: () => compilerWasmUrl }, - { title: "BlockNote demo document" }, + { wasm: compilerWasmUrl }, + { title: "BlockNote demo document", lang: "en" }, ); + if (result.error) { + throw new Error( + `PDF export failed: ${result.compileErrors + .map((d) => d.message) + .join("; ")}`, + ); + } + blob = result.blob; } else if (format === "docx") { const exporter = new DOCXExporter( editor.schema, diff --git a/docs/components/typstCompilerWasmUrl.ts b/docs/components/typstCompilerWasmUrl.ts index dc3ec24e6e..8d8a113291 100644 --- a/docs/components/typstCompilerWasmUrl.ts +++ b/docs/components/typstCompilerWasmUrl.ts @@ -1,11 +1,11 @@ // The Typst compiler wasm for the docs build (see next.config.ts): the // pdf-ua example bundles it via Vite's `?url`; under the docs site the // import is aliased here. `new URL(..., import.meta.url)` is Turbopack's -// static-asset reference: the ~29MB wasm is emitted as a hashed static +// static-asset reference: the ~25MB wasm is emitted as a hashed static // file and served by the site itself - no CDN involved, and the version // can't skew from the installed package because it IS the installed file. const url = new URL( - "../node_modules/@myriaddreamin/typst-ts-web-compiler/pkg/typst_ts_web_compiler_bg.wasm", + "../node_modules/@blocknote/xl-typst-compiler/pkg/blocknote_typst_wasm_bg.wasm", import.meta.url, ).href; export default url; diff --git a/docs/components/typstRendererStub.ts b/docs/components/typstRendererStub.ts deleted file mode 100644 index a0a636f2d6..0000000000 --- a/docs/components/typstRendererStub.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Stub for @myriaddreamin/typst-ts-renderer (see next.config.ts): the -// pdf-ua demo only compiles Typst, never canvas-renders, so the optional -// renderer peer is not installed. -export {}; diff --git a/docs/content/docs/features/export/pdf.mdx b/docs/content/docs/features/export/pdf.mdx index 3d0dec3328..77afcc9e74 100644 --- a/docs/content/docs/features/export/pdf.mdx +++ b/docs/content/docs/features/export/pdf.mdx @@ -38,19 +38,22 @@ import { const exporter = new PDFExporter(editor.schema, typstDefaultSchemaMappings); // Export the document to a PDF Blob (there's also `toBytes` for a Uint8Array) -const blob = await exporter.toBlob( +const { blob, pdfUA } = await exporter.toBlob( editor.document, {}, { title: "My document", lang: "en" }, ); ``` -This works out of the box: the export matches the editor's look (Inter body -text, Geist Mono code) and handles math blocks and emoji — the default fonts -ship inside the package and load lazily on the first export, with no CDN -involved. The Typst compiler itself (a ~30MB wasm file) is the one thing -loaded from a CDN by default; for production you'll want to bundle it: see -[Fonts & offline use](#fonts--offline-use). +This works out of the box, fully offline: the export matches the editor's +look (Inter body text, Geist Mono code) and handles math blocks and emoji — +the default fonts ship inside the package and load lazily on the first +export, and the compiler (a ~25MB wasm file from +`@blocknote/xl-typst-compiler`) loads from the package's own files, emitted +as an asset by your bundler. Nothing is ever fetched from a CDN. + +The result's `pdfUA` field reports whether the document earned the PDF/UA-1 +conformance claim — see [PDF/UA conformance](#pdfua-conformance). When repeatedly exporting changing content (e.g. a live preview), create a fresh exporter per export — construction is cheap, and an exporter instance @@ -68,7 +71,7 @@ The second parameter of `toBlob` / `toBytes` takes the compile options per-document options: ```typescript -const blob = await exporter.toBlob(editor.document, {}, { +const { blob } = await exporter.toBlob(editor.document, {}, { // Document title - required for PDF/UA (also shown in the viewer's title bar) title: "My document", // Document author, written to the PDF metadata @@ -155,20 +158,23 @@ new PDFExporter(editor.schema, { By default, exports use a font set matching the editor — Inter (body), Geist Mono (code), New Computer Modern Math (math blocks) and Noto Color Emoji (emoji, [required for PDF/UA](#pdfua-conformance)) — embedded in the package -and loaded lazily on the first export. Fonts never touch a CDN; the compiler -wasm is the only CDN default, and bundling it makes the export fully -offline. The compile options (the second parameter of `toBlob` / `toBytes`) -control all of it: +and loaded lazily on the first export, and the compiler wasm loads from +`@blocknote/xl-typst-compiler`'s own package files. Neither touches a CDN. +The compile options (the second parameter of `toBlob` / `toBytes`) control +all of it; to take explicit control of where the wasm is served from (e.g. +self-hosting with caching headers), pass its URL or bytes: ```typescript -import compilerWasmUrl from "@myriaddreamin/typst-ts-web-compiler/wasm?url"; +import compilerWasmUrl from "@blocknote/xl-typst-compiler/wasm?url"; -const blob = await exporter.toBlob(editor.document, { - // The compiler wasm, bundled by your bundler (Vite shown here) instead - // of loaded from a CDN. Install @myriaddreamin/typst-ts-web-compiler to - // import it. - getModule: () => compilerWasmUrl, -}); +const { blob } = await exporter.toBlob( + editor.document, + { + // The compiler wasm as an explicitly bundled asset (Vite shown here). + wasm: compilerWasmUrl, + }, + { title: "My document", lang: "en" }, +); ``` To take full control of fonts (e.g. a different look, or trimming the lazily @@ -178,22 +184,24 @@ keeps the default emoji font (and vice versa), and an explicit empty array disables one entirely: ```typescript -const blob = await exporter.toBlob(editor.document, { - // Font bytes (Uint8Array) to load into the compiler. - fonts: [myBodyFont, myMonoFont], - // An emoji-capable font. Browsers give the compiler no access to OS - // fonts, so without one emoji render as missing glyphs (and fail PDF/UA). - emojiFont: myEmojiFont, - // Optionally also preload Typst's stock fonts (from its CDN) as - // fallback faces for glyphs your fonts don't cover. - preloadDefaultFonts: true, -}); +const { blob } = await exporter.toBlob( + editor.document, + { + // Font bytes (Uint8Array) to load into the compiler. + fonts: [myBodyFont, myMonoFont], + // An emoji-capable font. Browsers give the compiler no access to OS + // fonts, so without one emoji render as missing glyphs (and fail PDF/UA). + emojiFont: myEmojiFont, + }, + { title: "My document", lang: "en" }, +); ``` -The wasm and fonts are loaded once, on the page's first export, and reused -afterwards — pass every font the page will need on that first call. The -[example](/examples/interoperability/converting-blocks-to-pdf-ua) bundles -everything explicitly and works fully offline. +The compiler ships no fonts of its own and never falls back silently: text +that no supplied font covers fails the export loudly rather than rendering +substituted glyphs. The wasm module is loaded once per page; fonts are +per-export options, so different exports on the same page can freely use +different font sets. When passing custom fonts, set the exporter's font families to match (defaults: `"Inter 18pt"` body, `"Geist Mono"` code, `"Noto Color Emoji"` @@ -208,19 +216,45 @@ const exporter = new PDFExporter(editor.schema, typstDefaultSchemaMappings, { ### PDF/UA conformance -The produced PDF is tagged and **declares** PDF/UA-1 conformance. Two things -to know: +The produced PDF always carries the tagged (accessible) structure tree. On +top of that, the exporter **declares PDF/UA-1 conformance when — and only +when — the document earns it**: Typst validates conformance during the +compile, and a nonconforming document is automatically exported as +tagged-but-unclaimed instead (an honest output rather than a false claim), +with the violations reported in the result: -- **Alt text**: every image needs it. BlockNote's image block has no dedicated - alt field yet, so the caption (or file name) is used — give images captions. -- **Headings**: PDF/UA requires the document's first heading to be level 1 — - start documents with an H1. +```typescript +const { blob, pdfUA } = await exporter.toBlob(editor.document, {}, { + title: "My document", + lang: "en", +}); +if (!pdfUA.declared && pdfUA.reason === "nonconforming") { + // e.g. "PDF/UA-1 error: the first heading must be of level 1" + console.info(pdfUA.violations.map((v) => v.message)); +} +``` -The declaration doesn't itself guarantee conformance of arbitrary input, so -validate exports with [veraPDF](https://verapdf.org) (`--flavour ua1`) if -conformance matters to you. For a document known not to conform, pass -`declarePdfUA: false` in the compile options to produce an honest -tagged-but-unclaimed PDF instead of a false claim. +What conformance requires of the document: + +- **Title and language**: pass `title` and `lang` in the document options. + Without a title, Typst's validation withholds the claim. The language is + required to attempt the claim at all — exporting without `lang` throws + (pass `tryDeclarePdfUA: false` to skip the claim instead), because the + PDF would otherwise declare Typst's default language (English), and a + wrong language declaration is an accessibility defect no validator can + catch. +- **Headings**: the first heading must be level 1, and levels must be + consecutive (no jumping from H1 to H3). +- **Alt text**: every image needs it. BlockNote's image block has no + dedicated alt field yet, so the caption (or file name) is used — give + images captions. + +Pass `tryDeclarePdfUA: false` in the compile options to skip the validation +and claim entirely (e.g. for a live preview, where the validation compile +would be wasted work). Conformance of the claim is enforced at compile +time by the Typst engine itself — a declared export has also been verified +against [veraPDF](https://verapdf.org)'s `--flavour ua1` checks (0 failed +checks) if you need independent validation. ### Exporter options diff --git a/docs/next.config.ts b/docs/next.config.ts index 02981ea446..e5b5773b4b 100644 --- a/docs/next.config.ts +++ b/docs/next.config.ts @@ -19,19 +19,16 @@ const config = { redirects, // `next build` runs Turbopack; the demo examples are written for Vite, so // give their `?url` asset imports (fonts, the Typst compiler wasm) the - // same URL-string semantics here, and stub the compiler's optional - // canvas-renderer peer (the pdf-ua demo only compiles, never renders to - // canvas, so the peer isn't installed). + // same URL-string semantics here. turbopack: { resolveAlias: { - "@myriaddreamin/typst-ts-renderer": "./components/typstRendererStub.ts", // Both key forms on purpose: Turbopack matches the alias key against // the request with its query in some resolution paths and without it // in others, so covering `/wasm` and `/wasm?url` makes the demo's // `?url` import resolve in both. - "@myriaddreamin/typst-ts-web-compiler/wasm": + "@blocknote/xl-typst-compiler/wasm": "./components/typstCompilerWasmUrl.ts", - "@myriaddreamin/typst-ts-web-compiler/wasm?url": + "@blocknote/xl-typst-compiler/wasm?url": "./components/typstCompilerWasmUrl.ts", }, }, diff --git a/docs/package.json b/docs/package.json index b3d3cd7313..9e4e282da9 100644 --- a/docs/package.json +++ b/docs/package.json @@ -47,8 +47,6 @@ "@marsidev/react-turnstile": "^1.4.2", "@mui/icons-material": "^5.16.1", "@mui/material": "^5.16.1", - "@myriaddreamin/typst-ts-web-compiler": "^0.8.0-rc3", - "@myriaddreamin/typst.ts": "^0.8.0-rc3", "@orama/orama": "^3.1.18", "@polar-sh/better-auth": "^1.6.4", "@polar-sh/sdk": "^0.42.2", @@ -115,7 +113,8 @@ "y-websocket": "^2.1.0", "yjs": "^13.6.27", "zod": "^4.3.5", - "@blocknote/xl-typst-exporter": "workspace:*" + "@blocknote/xl-typst-exporter": "workspace:*", + "@blocknote/xl-typst-compiler": "workspace:*" }, "devDependencies": { "@blocknote/code-block": "workspace:*", diff --git a/examples/05-interoperability/11-converting-blocks-to-pdf-ua/.bnexample.json b/examples/05-interoperability/11-converting-blocks-to-pdf-ua/.bnexample.json index 596cc792ba..0a39b03402 100644 --- a/examples/05-interoperability/11-converting-blocks-to-pdf-ua/.bnexample.json +++ b/examples/05-interoperability/11-converting-blocks-to-pdf-ua/.bnexample.json @@ -9,8 +9,7 @@ "@blocknote/xl-multi-column": "latest", "@blocknote/math-block": "latest", "@blocknote/diagram-block": "latest", - "@myriaddreamin/typst.ts": "^0.8.0-rc3", - "@myriaddreamin/typst-ts-web-compiler": "^0.8.0-rc3" + "@blocknote/xl-typst-compiler": "latest" }, "pro": true } diff --git a/examples/05-interoperability/11-converting-blocks-to-pdf-ua/package.json b/examples/05-interoperability/11-converting-blocks-to-pdf-ua/package.json index a81fc36580..515f5b808e 100644 --- a/examples/05-interoperability/11-converting-blocks-to-pdf-ua/package.json +++ b/examples/05-interoperability/11-converting-blocks-to-pdf-ua/package.json @@ -24,8 +24,7 @@ "@blocknote/xl-multi-column": "latest", "@blocknote/math-block": "latest", "@blocknote/diagram-block": "latest", - "@myriaddreamin/typst.ts": "^0.8.0-rc3", - "@myriaddreamin/typst-ts-web-compiler": "^0.8.0-rc3" + "@blocknote/xl-typst-compiler": "latest" }, "devDependencies": { "@types/react": "^19.2.3", diff --git a/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx b/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx index 7632d1b559..2a835d7c6a 100644 --- a/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx +++ b/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx @@ -36,10 +36,12 @@ import { multiColumnDropCursor, withMultiColumn, } from "@blocknote/xl-multi-column"; -// Bundle the Typst compiler wasm so it resolves locally (no CDN / importer). +// Bundle the Typst compiler wasm explicitly (it would otherwise load from +// the package's own files - also CDN-free - but an explicit URL keeps the +// bundling visible in this example). // Fonts need no setup: the exporter's bundled defaults (Inter, Geist Mono, // math, emoji - matching the editor) load lazily from the package. -import compilerWasmUrl from "@myriaddreamin/typst-ts-web-compiler/wasm?url"; +import compilerWasmUrl from "@blocknote/xl-typst-compiler/wasm?url"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import "./styles.css"; @@ -69,15 +71,35 @@ function usePdfUA( setStatus("loading"); void (async () => { try { - const blob = await makeExporter().toBlob( + const result = await makeExporter().toBlob( blocks, - { getModule: () => compilerWasmUrl }, + { wasm: compilerWasmUrl }, { title: "BlockNote document", lang: "en" }, ); if (stale) { return; } - setPdfUrl(URL.createObjectURL(blob)); + // A document that fails to compile (e.g. text no supplied font + // covers) is an expected outcome, reported in the result. + if (result.error) { + // eslint-disable-next-line no-console + console.error( + "PDF export failed:", + result.compileErrors.map((d) => d.message).join("; "), + ); + setStatus("error"); + return; + } + // A nonconforming document (e.g. one not starting with an H1) still + // exports - tagged but without the PDF/UA-1 claim; surface why. + if (!result.pdfUA.declared && result.pdfUA.reason === "nonconforming") { + // eslint-disable-next-line no-console + console.info( + "Exported without PDF/UA-1 declaration:", + result.pdfUA.violations.map((v) => v.message).join("; "), + ); + } + setPdfUrl(URL.createObjectURL(result.blob)); setStatus("ready"); } catch (e) { if (stale) { diff --git a/packages/diagram-block/package.json b/packages/diagram-block/package.json index 9f3bff700a..ae7bb72a2e 100644 --- a/packages/diagram-block/package.json +++ b/packages/diagram-block/package.json @@ -104,7 +104,7 @@ "typescript": "^7.0.2", "vite-plus": "catalog:", "@blocknote/xl-typst-exporter": "workspace:^", - "@myriaddreamin/typst-ts-node-compiler": "^0.8.0-rc3" + "@blocknote/xl-typst-compiler": "workspace:^" }, "peerDependencies": { "@blocknote/xl-docx-exporter": "workspace:^", diff --git a/packages/diagram-block/src/typst-exporter/__snapshots__/withDiagramMappings/diagramDocument.typ b/packages/diagram-block/src/typst-exporter/__snapshots__/withDiagramMappings/diagramDocument.typ index 9fa48da25a..49a19cac1e 100644 --- a/packages/diagram-block/src/typst-exporter/__snapshots__/withDiagramMappings/diagramDocument.typ +++ b/packages/diagram-block/src/typst-exporter/__snapshots__/withDiagramMappings/diagramDocument.typ @@ -1,5 +1,5 @@ -#set document(title: "Diagram", author: "") -#set text(font: "Inter 18pt", size: 12pt, lang: "en") +#set document(title: "Diagram") +#set text(font: "Inter 18pt", size: 12pt) #set page(paper: "a4", margin: 48pt) #set par(leading: 0.78em, spacing: 0pt, justify: false) #set block(spacing: 0pt) diff --git a/packages/math-block/package.json b/packages/math-block/package.json index 9099b586f3..5bea233906 100644 --- a/packages/math-block/package.json +++ b/packages/math-block/package.json @@ -113,7 +113,7 @@ "xml-formatter": "^3.6.7", "@blocknote/xl-typst-exporter": "workspace:^", "tex2typst": "^0.6.2", - "@myriaddreamin/typst-ts-node-compiler": "^0.8.0-rc3" + "@blocknote/xl-typst-compiler": "workspace:^" }, "peerDependencies": { "@blocknote/xl-docx-exporter": "workspace:^", diff --git a/packages/math-block/src/typst-exporter/__snapshots__/withMathMappings/mathDocument.typ b/packages/math-block/src/typst-exporter/__snapshots__/withMathMappings/mathDocument.typ index 1bad6f9a44..942f236cf8 100644 --- a/packages/math-block/src/typst-exporter/__snapshots__/withMathMappings/mathDocument.typ +++ b/packages/math-block/src/typst-exporter/__snapshots__/withMathMappings/mathDocument.typ @@ -1,5 +1,5 @@ -#set document(title: "Math", author: "") -#set text(font: "Inter 18pt", size: 12pt, lang: "en") +#set document(title: "Math") +#set text(font: "Inter 18pt", size: 12pt) #set page(paper: "a4", margin: 48pt) #set par(leading: 0.78em, spacing: 0pt, justify: false) #set block(spacing: 0pt) diff --git a/packages/xl-pdf-exporter/package.json b/packages/xl-pdf-exporter/package.json index 015da3cfa5..4099963cf4 100644 --- a/packages/xl-pdf-exporter/package.json +++ b/packages/xl-pdf-exporter/package.json @@ -56,9 +56,7 @@ "@blocknote/core": "workspace:^", "@blocknote/xl-multi-column": "workspace:^", "@blocknote/xl-typst-exporter": "workspace:^", - "@myriaddreamin/typst.ts": "^0.8.0-rc3", - "@myriaddreamin/typst-ts-web-compiler": "^0.8.0-rc3", - "@cantoo/pdf-lib": "^2.9.1" + "@blocknote/xl-typst-compiler": "workspace:^" }, "devDependencies": { "@blocknote/shared": "workspace:^", @@ -72,9 +70,9 @@ "rollup-plugin-webpack-stats": "^0.2.6", "typescript": "^7.0.2", "vite-plus": "catalog:", - "@myriaddreamin/typst-ts-node-compiler": "^0.8.0-rc3", "@types/node": "22.13.13", - "@react-pdf/renderer": "^4.5.1" + "@react-pdf/renderer": "^4.5.1", + "@cantoo/pdf-lib": "^2.9.1" }, "peerDependencies": { "react": "^18.0 || ^19.0 || >= 19.0.0-rc", diff --git a/packages/xl-pdf-exporter/src/index.ts b/packages/xl-pdf-exporter/src/index.ts index 063eb48e5b..cbeaa0b1ec 100644 --- a/packages/xl-pdf-exporter/src/index.ts +++ b/packages/xl-pdf-exporter/src/index.ts @@ -1,179 +1,22 @@ -import { - Block, - BlockNoteSchema, - BlockSchema, - Exporter, - InlineContentSchema, - StyleSchema, -} from "@blocknote/core"; -import { - TypstDocumentOptions, - TypstExporter, - TypstExporterOptions, -} from "@blocknote/xl-typst-exporter"; -import { - compileTypstToTaggedPdf, - TypstCompileOptions, -} from "./pdfua/compileBrowser.js"; -import { - DEFAULT_EMOJI_FONT_FAMILY, - loadDefaultBodyFonts, - loadDefaultEmojiFont, -} from "./pdfua/defaultFonts.js"; -import { declarePdfUA } from "./pdfua/postProcess.js"; - // The Typst layer is re-exported so PDF consumers need only this package. // The mappings passed to `PDFExporter` ARE Typst mappings - a custom block's // single Typst mapping serves both the standalone `.typ` export // (@blocknote/xl-typst-exporter) and the PDF export. export * from "@blocknote/xl-typst-exporter"; -export { declarePdfUA } from "./pdfua/postProcess.js"; export { - compileTypstToTaggedPdf, + PDFExporter, + type PdfBlobExportResult, + type PdfExportOptions, + type PdfExportResult, + type PdfUAResult, + type PdfUAViolation, +} from "./pdfExporter.js"; +export { + compileTypstToPdf, type TypstCompileOptions, -} from "./pdfua/compileBrowser.js"; - -/** Options for {@link PDFExporter}'s export methods. */ -export type PdfExportOptions = TypstCompileOptions & { - /** - * Declare PDF/UA-1 conformance on the produced document (the - * `pdfuaid:part` XMP identifier plus `/ViewerPreferences/DisplayDocTitle`; - * see {@link declarePdfUA}). - * - * The tagged structure tree is always emitted either way - this controls - * only the conformance *claim*. Opt out when a document is known not to - * conform (e.g. its first heading isn't level 1, or an image lacks any - * caption/name to use as alt text): a tagged-but-unclaimed PDF is honest, - * while a false claim fails validation. Either way, verify output with - * veraPDF (`--flavour ua1`) in CI - the declaration does not itself - * guarantee conformance of arbitrary input. - * - * @default true - */ - declarePdfUA?: boolean; -}; - -/** - * Exports BlockNote documents to accessible, tagged PDF/UA-1 files, powered - * by Typst (compiled to wasm - the whole pipeline runs client-side). - * - * The mappings are *Typst* mappings ({@link typstDefaultSchemaMappings}); - * this class is a {@link TypstExporter} plus the PDF compile step, so - * everything documented there applies - including that an exporter instance - * accumulates assets for its lifetime: create a fresh exporter per export - * when repeatedly exporting changing content (construction is cheap). - * - * Zero-config exports match the editor: the compile options' `fonts` and - * `emojiFont` each default (independently) to the bundled set - Inter, - * Geist Mono, New Computer Modern Math resp. Noto Color Emoji - loaded - * lazily from the package. Pass a value (or an explicit `[]` for none) to - * take over either. - * - * Concurrency: the shared compile stage is serialized internally (see - * `compileTypstToTaggedPdf`) and the asset registry is append-only, so - * overlapping exports are *safe* - but like any async calls, independent - * exports may complete out of call order. Callers that only want the newest - * result (e.g. a live preview exporting on every change) should guard for - * that themselves, as the pdf-ua example does. - * - * (The previous react-pdf based exporter is still available from - * `@blocknote/xl-pdf-exporter/react-pdf` during its deprecation window.) - */ -export class PDFExporter< - B extends BlockSchema, - S extends StyleSchema, - I extends InlineContentSchema, -> extends TypstExporter { - public constructor( - schema: BlockNoteSchema, - mappings: Exporter< - NoInfer, - NoInfer, - NoInfer, - string, - string, - (inner: string) => string, - string - >["mappings"], - options?: Partial, - ) { - super(schema, mappings, { - // The bundled default fonts (see `defaultFonts.ts`) include Noto - // Color Emoji; declaring the family by default lets multi-codepoint - // emoji shape correctly with zero config. Callers supplying their own - // fonts can override (or unset) it. - emojiFontFamily: DEFAULT_EMOJI_FONT_FAMILY, - ...options, - }); - } - - /** - * Export a document to PDF bytes: BlockNote document -> Typst -> tagged - * PDF (wasm) -> declared PDF/UA-1 (unless opted out via - * {@link PdfExportOptions.declarePdfUA}). - */ - public async toBytes( - blocks: Block[], - options: PdfExportOptions = {}, - documentOptions?: TypstDocumentOptions, - ): Promise { - const { declarePdfUA: withDeclaration = true, ...compileOptions } = options; - const typst = await this.toTypst(blocks, documentOptions); - // The images collected during the export are mapped into the compiler - // alongside (not instead of) any assets the caller supplied - e.g. an - // image referenced from the header/footer markup. A caller asset under - // the exporter's own key space would be silently shadowed by the merge, - // so that's rejected loudly instead. - for (const key of compileOptions.assets?.keys() ?? []) { - if (this.assetFiles.has(key)) { - throw new Error( - `PDFExporter: the caller-supplied asset "${key}" collides with an ` + - `asset registered by the exporter - use a path outside /assets/`, - ); - } - } - // Zero-config fonts: each option defaults independently to the bundled - // set matching the editor - `undefined` means "use the default", a - // supplied value (including an explicit `[]` for none) takes over. The - // independence keeps the bytes consistent with the constructor's - // independent `emojiFontFamily` default: custom body fonts don't - // silently drop emoji support, and vice versa. - const [fonts, emojiFont] = await Promise.all([ - compileOptions.fonts === undefined - ? loadDefaultBodyFonts() - : compileOptions.fonts, - compileOptions.emojiFont === undefined - ? loadDefaultEmojiFont() - : compileOptions.emojiFont, - ]); - const taggedPdf = await compileTypstToTaggedPdf(typst, { - ...compileOptions, - fonts, - emojiFont, - assets: new Map([...(compileOptions.assets ?? []), ...this.assetFiles]), - }); - // TODO: collapse this into one step once the web compiler supports native - // PDF/UA-1 export. typst's node compiler already accepts - // `pdfStandard: "ua-1"`, which emits a veraPDF-conformant PDF/UA-1 - // directly (verified: 0 failed checks) and validates accessibility at - // compile time (errors on missing alt text) — making `declarePdfUA` (and - // the `@cantoo/pdf-lib` dependency) unnecessary. `@myriaddreamin/ - // typst.ts`'s browser `pdf()` does not yet expose a PDF standard option, - // so the post-process is still required for the wasm path. - return withDeclaration ? declarePdfUA(taggedPdf) : taggedPdf; - } - - /** Export a document to a PDF Blob (e.g. for downloads / object URLs). */ - public async toBlob( - blocks: Block[], - options: PdfExportOptions = {}, - documentOptions?: TypstDocumentOptions, - ): Promise { - const bytes = await this.toBytes(blocks, options, documentOptions); - // The pipeline always returns a view over a plain (non-shared) buffer; - // the cast narrows `ArrayBufferLike` for `BlobPart`. - return new Blob([bytes as Uint8Array], { - type: "application/pdf", - }); - } -} +} from "./pdfua/compileTypst.js"; +export { + isPdfStandardViolation, + type CompilePdfResult, + type TypstDiagnostic, +} from "@blocknote/xl-typst-compiler"; diff --git a/packages/xl-pdf-exporter/src/pdfExporter.test.ts b/packages/xl-pdf-exporter/src/pdfExporter.test.ts index ff3ad25d6e..3ab3b9e5c4 100644 --- a/packages/xl-pdf-exporter/src/pdfExporter.test.ts +++ b/packages/xl-pdf-exporter/src/pdfExporter.test.ts @@ -6,8 +6,14 @@ import { import { typstDefaultSchemaMappings } from "@blocknote/xl-typst-exporter"; import { partialBlocksToBlocksForTesting } from "@shared/formatConversionTestUtil.js"; import { testResolveFileUrl } from "@shared/util/testFileResolver.js"; +import { readFileSync } from "node:fs"; +import { join, resolve } from "node:path"; import { describe, expect, it } from "vite-plus/test"; -import { PDFExporter } from "./index.js"; +import { + PDFExporter, + type PdfExportOptions, + type PdfExportResult, +} from "./index.js"; const schema = BlockNoteSchema.create({ blockSpecs: { @@ -38,3 +44,184 @@ describe("PDFExporter", () => { ).rejects.toThrow('the caller-supplied asset "/assets/asset-0" collides'); }); }); + +// Node has no URL-relative wasm loading, so the module bytes and fonts are +// passed explicitly (the zero-config defaults - bundled fonts, wasm from +// package files - are browser paths, covered by the browser/e2e suites). +function wasmAndFonts(): Pick< + PdfExportOptions, + "wasm" | "fonts" | "emojiFont" +> { + const read = (p: string) => + new Uint8Array(readFileSync(resolve(process.cwd(), p))); + const fontDir = "../../shared/assets/fonts"; + return { + wasm: read("../xl-typst-compiler/pkg/blocknote_typst_wasm_bg.wasm"), + fonts: [ + read(join(fontDir, "inter/Inter_18pt-Regular.ttf")), + read(join(fontDir, "inter/Inter_18pt-Bold.ttf")), + ], + emojiFont: [], + }; +} + +const latin1 = (bytes: Uint8Array) => new TextDecoder("latin1").decode(bytes); + +function expectExported( + result: PdfExportResult, +): Extract { + if (result.error) { + throw new Error( + `expected an export, got: ${result.compileErrors + .map((d) => d.message) + .join(" | ")}`, + ); + } + return result; +} + +describe("PDFExporter PDF/UA declaration", () => { + function exporter() { + return new PDFExporter(schema, typstDefaultSchemaMappings, { + resolveFileUrl: testResolveFileUrl, + }); + } + const conforming = () => + partialBlocksToBlocksForTesting(schema, [ + { type: "heading", props: { level: 1 }, content: "Title" }, + { type: "paragraph", content: "Body" }, + ]); + + it("declares PDF/UA-1 for a conforming document", async () => { + const { bytes, pdfUA } = expectExported( + await exporter().toBytes(conforming(), wasmAndFonts(), { + title: "Doc", + lang: "en", + }), + ); + expect(pdfUA).toEqual({ declared: true }); + expect(latin1(bytes)).toContain("pdfuaid"); + expect(latin1(bytes)).toContain("StructTreeRoot"); + }); + + it("falls back to an unclaimed export for a nonconforming document", async () => { + // First heading is level 2: a PDF/UA-1 violation Typst catches at + // compile time. The export still succeeds - tagged, but without the + // conformance claim - and reports why. + const blocks = partialBlocksToBlocksForTesting(schema, [ + { type: "heading", props: { level: 2 }, content: "Not level one" }, + ]); + const { bytes, pdfUA } = expectExported( + await exporter().toBytes(blocks, wasmAndFonts(), { + title: "Doc", + lang: "en", + }), + ); + expect(pdfUA.declared).toBe(false); + if (!pdfUA.declared && pdfUA.reason === "nonconforming") { + expect(pdfUA.violations.length).toBeGreaterThan(0); + expect(pdfUA.violations[0].message).toContain( + "first heading must be of level 1", + ); + } else { + throw new Error(`unexpected pdfUA result: ${JSON.stringify(pdfUA)}`); + } + expect(latin1(bytes)).not.toContain("pdfuaid"); + expect(latin1(bytes)).toContain("StructTreeRoot"); + }); + + it("rejects declaring without a document language (caller-args error)", async () => { + // A no-lang export would still carry Typst's silently defaulted + // language (English) in the PDF - a wrong `/Lang` no validator can + // catch. Unlike content violations, the language is an integration + // decision only the caller can make, so this fails loudly instead of + // quietly producing forever-unclaimed exports. + await expect( + exporter().toBytes(conforming(), wasmAndFonts(), { title: "Doc" }), + ).rejects.toThrow("requires the document's language"); + // Opting out of the claim makes the language optional again. + const { pdfUA } = expectExported( + await exporter().toBytes( + conforming(), + { ...wasmAndFonts(), tryDeclarePdfUA: false }, + { title: "Doc" }, + ), + ); + expect(pdfUA).toEqual({ + declared: false, + reason: "tryDeclarePdfUA-disabled", + }); + }); + + it("skips validation and claim with tryDeclarePdfUA: false", async () => { + const { bytes, pdfUA } = expectExported( + await exporter().toBytes( + conforming(), + { ...wasmAndFonts(), tryDeclarePdfUA: false }, + { title: "Doc", lang: "en" }, + ), + ); + expect(pdfUA).toEqual({ + declared: false, + reason: "tryDeclarePdfUA-disabled", + }); + expect(latin1(bytes)).not.toContain("pdfuaid"); + expect(latin1(bytes)).toContain("StructTreeRoot"); + }); + + it("forwards compile warnings alongside a successful export", async () => { + // An unknown font family is a warning, not an error - the export + // succeeds (Typst falls back across the loaded fonts), and the result + // surfaces what an integrator would want to know. + const warned = new PDFExporter(schema, typstDefaultSchemaMappings, { + resolveFileUrl: testResolveFileUrl, + fontFamily: "No Such Family", + }); + const result = expectExported( + await warned.toBytes(conforming(), wasmAndFonts(), { + title: "Doc", + lang: "en", + }), + ); + expect( + result.compileWarnings.some((w) => + w.message.includes("unknown font family"), + ), + ).toBe(true); + }); + + it("exports a Blob with the same result reporting", async () => { + const result = await exporter().toBlob(conforming(), wasmAndFonts(), { + title: "Doc", + lang: "en", + }); + if (result.error) { + throw new Error(result.compileErrors.map((d) => d.message).join(" | ")); + } + expect(result.blob.type).toBe("application/pdf"); + expect(result.blob.size).toBeGreaterThan(1000); + expect(result.pdfUA).toEqual({ declared: true }); + // The minimal test font set omits the preamble's code/emoji families, + // which surfaces as unknown-font-family warnings - nothing else. + expect( + result.compileWarnings.every((w) => + w.message.includes("unknown font family"), + ), + ).toBe(true); + }); + + it("reports compile failures as a typed error, not as violations", async () => { + // Broken raw markup (here via the caller-supplied header) is a compile + // failure - an expected outcome carried in the result, distinct from + // conformance violations (it must not degrade to an unclaimed export). + const result = await exporter().toBytes(conforming(), wasmAndFonts(), { + title: "Doc", + lang: "en", + header: "#thisFunctionDoesNotExist()", + }); + expect(result.error).toBe("compile-failed"); + if (result.error) { + expect(result.compileErrors.length).toBeGreaterThan(0); + } + }); +}); diff --git a/packages/xl-pdf-exporter/src/pdfExporter.ts b/packages/xl-pdf-exporter/src/pdfExporter.ts new file mode 100644 index 0000000000..057067f11d --- /dev/null +++ b/packages/xl-pdf-exporter/src/pdfExporter.ts @@ -0,0 +1,300 @@ +import { + Block, + BlockNoteSchema, + BlockSchema, + Exporter, + InlineContentSchema, + StyleSchema, +} from "@blocknote/core"; +import { + isPdfStandardViolation, + type TypstDiagnostic, +} from "@blocknote/xl-typst-compiler"; +import { + TypstDocumentOptions, + TypstExporter, + TypstExporterOptions, +} from "@blocknote/xl-typst-exporter"; +import { + compileTypstToPdf, + TypstCompileOptions, +} from "./pdfua/compileTypst.js"; +import { + DEFAULT_EMOJI_FONT_FAMILY, + loadDefaultBodyFonts, + loadDefaultEmojiFont, +} from "./pdfua/defaultFonts.js"; + +/** Options for {@link PDFExporter}'s export methods. */ +export type PdfExportOptions = TypstCompileOptions & { + /** + * Try to produce a *declared* PDF/UA-1 document - the claim is made only + * when the document earns it. Typst + * validates conformance at compile time (document title present, first + * heading level 1, consecutive heading levels, alt text on images and + * equations, ...); a conforming document gets the `pdfuaid` conformance + * claim, a nonconforming one is automatically re-exported as + * tagged-but-unclaimed - an honest output rather than a false claim - + * with the violations reported in the result's {@link PdfUAResult}. + * + * The tagged (accessible) structure tree is always emitted either way. + * Set `false` to skip the claim and its validation entirely (e.g. for a + * live preview, where the validation compile would be wasted work). + * + * Attempting the claim requires the document's language + * (`documentOptions.lang`) - the one conformance input only the caller + * can provide - and throws without it. + * + * @default true + */ + tryDeclarePdfUA?: boolean; +}; + +/** One PDF/UA-1 conformance violation, safe to surface in an app's UI. */ +export type PdfUAViolation = { + /** Typst's diagnostic message, e.g. "PDF/UA-1 error: missing alt text". */ + message: string; + /** Remediation hints accompanying the message. */ + hints: string[]; +}; + +/** Whether (and why not) the produced PDF declares PDF/UA-1 conformance. */ +export type PdfUAResult = + | { declared: true } + | { declared: false; reason: "tryDeclarePdfUA-disabled" } + | { + declared: false; + reason: "nonconforming"; + violations: PdfUAViolation[]; + }; + +/** + * The outcome of {@link PDFExporter.toBytes}. A document that fails to + * compile is an expected outcome (the source is generated from user + * content: text no supplied font covers, broken caller-supplied + * header/footer markup, ...), so it's a value carrying the compiler's + * diagnostics - not an exception. + */ +export type PdfExportResult = + | { + error?: undefined; + bytes: Uint8Array; + pdfUA: PdfUAResult; + compileWarnings: TypstDiagnostic[]; + } + | { + error: "compile-failed"; + compileErrors: TypstDiagnostic[]; + compileWarnings: TypstDiagnostic[]; + }; + +/** The outcome of {@link PDFExporter.toBlob}. See {@link PdfExportResult}. */ +export type PdfBlobExportResult = + | { + error?: undefined; + blob: Blob; + pdfUA: PdfUAResult; + compileWarnings: TypstDiagnostic[]; + } + | { + error: "compile-failed"; + compileErrors: TypstDiagnostic[]; + compileWarnings: TypstDiagnostic[]; + }; + +/** + * Exports BlockNote documents to accessible, tagged PDF files - PDF/UA-1 + * when the document conforms (see {@link PdfExportOptions.tryDeclarePdfUA}) - + * powered by Typst compiled to WebAssembly + * (`@blocknote/xl-typst-compiler`): the whole pipeline runs client-side, + * with no network access. + * + * The mappings are *Typst* mappings ({@link typstDefaultSchemaMappings}); + * this class is a {@link TypstExporter} plus the PDF compile step, so + * everything documented there applies - including that an exporter instance + * accumulates assets for its lifetime: create a fresh exporter per export + * when repeatedly exporting changing content (construction is cheap). + * + * Zero-config exports match the editor: the compile options' `fonts` and + * `emojiFont` each default (independently) to the bundled set - Inter, + * Geist Mono, New Computer Modern Math resp. Noto Color Emoji - loaded + * lazily from the package, and the compiler wasm loads from its own + * package's files. Pass a value (or an explicit `[]` for no fonts) to take + * over either. + * + * (The previous react-pdf based exporter is still available from + * `@blocknote/xl-pdf-exporter/react-pdf` during its deprecation window.) + */ +export class PDFExporter< + B extends BlockSchema, + S extends StyleSchema, + I extends InlineContentSchema, +> extends TypstExporter { + public constructor( + schema: BlockNoteSchema, + mappings: Exporter< + NoInfer, + NoInfer, + NoInfer, + string, + string, + (inner: string) => string, + string + >["mappings"], + options?: Partial, + ) { + super(schema, mappings, { + // The bundled default fonts (see `defaultFonts.ts`) include Noto + // Color Emoji; declaring the family by default lets multi-codepoint + // emoji shape correctly with zero config. Callers supplying their own + // fonts can override (or unset) it. + emojiFontFamily: DEFAULT_EMOJI_FONT_FAMILY, + ...options, + }); + } + + /** + * Export a document to PDF bytes: BlockNote document -> Typst -> tagged + * PDF (wasm), declared PDF/UA-1 when the document conforms (see + * {@link PdfExportOptions.tryDeclarePdfUA}). The result reports whether the + * claim was made and the conformance violations when it wasn't - or, for + * a document that fails to compile at all, the compiler's diagnostics + * (see {@link PdfExportResult}). + */ + public async toBytes( + blocks: Block[], + options: PdfExportOptions = {}, + documentOptions?: TypstDocumentOptions, + ): Promise { + const { tryDeclarePdfUA = true, ...compileOptions } = options; + const typst = await this.toTypst(blocks, documentOptions); + // The images collected during the export are mapped into the compiler + // alongside (not instead of) any assets the caller supplied - e.g. an + // image referenced from the header/footer markup. A caller asset under + // the exporter's own key space would be silently shadowed by the merge, + // so that's rejected loudly instead (a programmer error, not an + // expected outcome - hence a throw, unlike compile failures). + for (const key of compileOptions.assets?.keys() ?? []) { + if (this.assetFiles.has(key)) { + throw new Error( + `PDFExporter: the caller-supplied asset "${key}" collides with an ` + + `asset registered by the exporter - use a path outside /assets/`, + ); + } + } + // Zero-config fonts: each option defaults independently to the bundled + // set matching the editor - `undefined` means "use the default", a + // supplied value (including an explicit `[]` for none) takes over. The + // independence keeps the bytes consistent with the constructor's + // independent `emojiFontFamily` default: custom body fonts don't + // silently drop emoji support, and vice versa. + const [fonts, emojiFont] = await Promise.all([ + compileOptions.fonts === undefined + ? loadDefaultBodyFonts() + : compileOptions.fonts, + compileOptions.emojiFont === undefined + ? loadDefaultEmojiFont() + : compileOptions.emojiFont, + ]); + const resolved: TypstCompileOptions = { + ...compileOptions, + fonts, + emojiFont, + assets: new Map([...(compileOptions.assets ?? []), ...this.assetFiles]), + }; + + if (!tryDeclarePdfUA) { + return withPdfUA(await compileTypstToPdf(typst, resolved), { + declared: false, + reason: "tryDeclarePdfUA-disabled", + }); + } + + // Attempting the claim without a document language is a caller-args + // error (like the asset collision above), not a document + // nonconformity: the PDF would otherwise carry Typst's silently + // defaulted language (English), and a wrong `/Lang` (e.g. "en" on a + // German document) is an accessibility defect no validator can catch. + // Unlike heading structure or alt text - content the end user can fix - + // the language is an integration-time decision only the caller can + // make, so it fails loudly at development time instead of quietly + // producing forever-unclaimed exports. + if (!documentOptions?.lang) { + throw new Error( + "PDFExporter: declaring PDF/UA-1 (tryDeclarePdfUA, the default) " + + "requires the document's language - pass its BCP-47 tag in the " + + 'document options (e.g. { lang: "en" }), or opt out of the ' + + "claim with tryDeclarePdfUA: false.", + ); + } + + const declared = await compileTypstToPdf(typst, { + ...resolved, + pdfStandard: "ua-1", + }); + if (!declared.error) { + return { + bytes: declared.pdf, + pdfUA: { declared: true }, + compileWarnings: declared.compileWarnings, + }; + } + // Only conformance violations fall back to an unclaimed export; any + // other failure (broken markup, missing font) would fail the fallback + // compile too, so it surfaces as the compile failure it is. (Violations + // are always *errors* - Typst emits every validator finding as an + // error, never a warning - so classifying compileErrors alone is + // complete. The declared attempt's compileWarnings are dropped here, + // but nothing is lost: the fallback compiles the same document with + // the same fonts, so the result below carries the identical warnings.) + if (!declared.compileErrors.every(isPdfStandardViolation)) { + return declared; + } + return withPdfUA(await compileTypstToPdf(typst, resolved), { + declared: false, + reason: "nonconforming", + violations: declared.compileErrors.map(({ message, hints }) => ({ + message, + hints, + })), + }); + } + + /** + * Export a document to a PDF Blob (e.g. for downloads / object URLs), + * with the same result reporting as {@link toBytes}. + */ + public async toBlob( + blocks: Block[], + options: PdfExportOptions = {}, + documentOptions?: TypstDocumentOptions, + ): Promise { + const result = await this.toBytes(blocks, options, documentOptions); + if (result.error) { + return result; + } + // The pipeline always returns a view over a plain (non-shared) buffer; + // the cast narrows `ArrayBufferLike` for `BlobPart`. + return { + blob: new Blob([result.bytes as Uint8Array], { + type: "application/pdf", + }), + pdfUA: result.pdfUA, + compileWarnings: result.compileWarnings, + }; + } +} + +function withPdfUA( + compiled: Awaited>, + pdfUA: PdfUAResult, +): PdfExportResult { + if (compiled.error) { + return compiled; + } + return { + bytes: compiled.pdf, + pdfUA, + compileWarnings: compiled.compileWarnings, + }; +} diff --git a/packages/xl-pdf-exporter/src/pdfua/__fixtures__/tagged.pdf b/packages/xl-pdf-exporter/src/pdfua/__fixtures__/tagged.pdf deleted file mode 100644 index 9a68ad240f6c8d9f92ccaa2f31c2021fd995609a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25729 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 K!`Jti>HjYq>OUj^ diff --git a/packages/xl-pdf-exporter/src/pdfua/__snapshots__/render/.gitignore b/packages/xl-pdf-exporter/src/pdfua/__snapshots__/render/.gitignore deleted file mode 100644 index a458bdff29..0000000000 --- a/packages/xl-pdf-exporter/src/pdfua/__snapshots__/render/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Debug output written when a page differs from its baseline. -*.actual.png diff --git a/packages/xl-pdf-exporter/src/pdfua/__snapshots__/render/testDocument-1.png b/packages/xl-pdf-exporter/src/pdfua/__snapshots__/render/testDocument-1.png deleted file mode 100644 index 2b24b12393d776b87e81de2f239adf4f99c5c364..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66445 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

agmXbi~y0-2O%6`erQu?Sw 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%0A7YWXf#Q_-oB8ffO!;O!ge&iSZ<#)*G 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 CStB0+ diff --git a/packages/xl-pdf-exporter/src/pdfua/__snapshots__/render/testDocument-2.png b/packages/xl-pdf-exporter/src/pdfua/__snapshots__/render/testDocument-2.png deleted file mode 100644 index f0cf22fb10318ee0341aa4035e298152a33d6b02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120977 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 diff --git a/packages/xl-pdf-exporter/src/pdfua/__snapshots__/render/testDocument-3.png b/packages/xl-pdf-exporter/src/pdfua/__snapshots__/render/testDocument-3.png deleted file mode 100644 index 9bd412441728751d64f787050e15e3d4f7bbb9ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30748 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

gTNIfX84*7UpTpUuzK_VSzkh$Q;S&;~ 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 new URL(..., import.meta.url)`). The compiler compares - // getModule results across compiles to detect configuration changes, so - // every later test in this suite doubles as a regression test that - // equivalent-but-fresh URL objects are compared by value, not identity - // (identity comparison would reject each compile after the first as - // "already initialized with different options"). - getModule: () => new URL(compilerWasmUrl, document.baseURI), - preloadDefaultFonts: false, -} as const; - -describe("compileTypstToTaggedPdf", () => { - test("compiles markup with mapped assets", { timeout: 60000 }, async () => { - const pdf = await compileTypstToTaggedPdf( - `#set document(title: "t")\nHello #image("/assets/a.png", width: 10pt)`, - { ...OPTIONS, assets: new Map([["/assets/a.png", TEST_PNG_BYTES]]) }, - ); - expect(isPdf(pdf)).toBe(true); - }); - - test( - "serializes concurrent compiles with different assets", - { timeout: 60000 }, - async () => { - // Shadow files are global compiler state; without serialization one - // compile's resetShadow lands mid-flight in the other and it fails - // with file-not-found (the debounced re-export scenario). - function compile(path: string) { - return compileTypstToTaggedPdf( - `#set document(title: "t")\n#image("${path}", width: 10pt)`, - { ...OPTIONS, assets: new Map([[path, TEST_PNG_BYTES]]) }, - ); - } - const [a, b] = await Promise.all([ - compile("/assets/one.png"), - compile("/assets/two.png"), - ]); - expect(isPdf(a)).toBe(true); - expect(isPdf(b)).toBe(true); - }, - ); - - test( - "rejects a later compile that changes the init-time options", - { timeout: 60000 }, - async () => { - // The wasm module and fonts load once, on the first compile; silently - // ignoring different options would leave e.g. new fonts unloaded. - await compileTypstToTaggedPdf("ok", OPTIONS); - await expect( - compileTypstToTaggedPdf("ok", { - ...OPTIONS, - fonts: [new Uint8Array([1, 2, 3])], - }), - ).rejects.toThrow("already initialized"); - }, - ); - - test( - "surfaces compile errors instead of returning output", - { timeout: 60000 }, - async () => { - await expect( - compileTypstToTaggedPdf("#image(unknownvariable)", OPTIONS), - ).rejects.toThrow(); - }, - ); -}); diff --git a/packages/xl-pdf-exporter/src/pdfua/compileBrowser.ts b/packages/xl-pdf-exporter/src/pdfua/compileBrowser.ts deleted file mode 100644 index 2b4bb5c3df..0000000000 --- a/packages/xl-pdf-exporter/src/pdfua/compileBrowser.ts +++ /dev/null @@ -1,200 +0,0 @@ -import type { TypstSnippet } from "@myriaddreamin/typst.ts/contrib/snippet"; -import type { InitOptions } from "@myriaddreamin/typst.ts/options.init"; - -export interface TypstCompileOptions { - /** - * Returns the wasm module for the Typst compiler. In a browser bundler this - * is typically the imported `.wasm` URL/bytes from - * `@myriaddreamin/typst-ts-web-compiler`, e.g. - * `getModule: () => new URL("...", import.meta.url)`. - * - * If omitted, Typst.ts loads its matching compiler wasm from its CDN — handy - * for demos, but bundle/self-host it for production. - */ - getModule?: InitOptions["getModule"]; - /** - * Extra fonts (as bytes) to load into the compiler — typically the body fonts - * the exporter references (e.g. Inter, Geist Mono). - */ - fonts?: Uint8Array[]; - /** - * The emoji source: an emoji-capable font (or fonts) as bytes. Unlike - * react-pdf's image-based `emojiSource`, Typst renders emoji from a font, so - * this is how you supply one. Required for *fully* PDF/UA-1 conformant output - * that contains emoji — the browser has no OS font access, so without it emoji - * render as `.notdef` and fail ISO 14289-1 clauses 7.21.7 / 7.21.8. Loaded - * alongside {@link fonts} (this is just a clearer, dedicated channel for it). - */ - emojiFont?: Uint8Array | Uint8Array[]; - /** - * Additionally fetch Typst's stock font assets (Libertinus Serif, DejaVu - * Sans Mono, etc.) from the jsdelivr CDN, as fallback faces for glyphs - * the supplied fonts don't cover. Off by default: `PDFExporter` already - * loads a bundled default font set (body, code, math, emoji), so - * zero-config exports make no font CDN requests at all. - * @default false - */ - preloadDefaultFonts?: boolean; - /** - * Image/asset files to map into the compiler's virtual filesystem, keyed by - * the Typst path referenced in the source (e.g. `/assets/asset-0`). - * Populate from `TypstExporter.assetFiles`. - */ - assets?: ReadonlyMap; -} - -function fontList(options: TypstCompileOptions): Uint8Array[] { - const emojiFonts = - options.emojiFont === undefined - ? [] - : Array.isArray(options.emojiFont) - ? options.emojiFont - : [options.emojiFont]; - return [...(options.fonts ?? []), ...emojiFonts]; -} - -// A cheap content fingerprint for font byte arrays, so byte-identical fonts -// pass the compatibility check even as fresh Uint8Array instances (a caller -// refetching the same files per export, test retries, HMR) - reference -// identity would spuriously reject them. Length plus the first bytes is -// discriminating enough: a font file's table directory (offsets, checksums) -// sits at the start, so different fonts diverge immediately. -function fontFingerprint(bytes: Uint8Array): string { - let hash = 0; - const end = Math.min(bytes.length, 256); - for (let i = 0; i < end; i++) { - hash = (hash * 31 + bytes[i]) | 0; - } - return `${bytes.length}:${hash}`; -} - -// Canonicalizes a getModule result for the compatibility check below. -// Strings compare by value on their own, but the equally-documented -// `getModule: () => new URL(..., import.meta.url)` pattern returns a fresh -// `URL` instance per call - comparing those by identity would spuriously -// reject every compile after the first. URLs therefore compare by href; -// other module forms (bytes, WebAssembly.Module, Response) keep reference -// identity, as callers hold onto those. -function moduleSourceKey(source: unknown): unknown { - return source instanceof URL ? source.href : source; -} - -// The wasm compiler is a page-level singleton (typst.ts's own `$typst` is -// module-global), so its init-time inputs — wasm module, font set, default -// font preloading — are fixed by the first compile. A later compile that -// tries to CHANGE them throws a descriptive error instead of silently -// compiling with the first call's configuration: pass every font the page -// will need on the first call. (These constraints — and that a failed wasm -// load can only be recovered by a page reload — are inherent to the -// `$typst` snippet singleton; lifting them means moving to typst.ts's -// per-instance compiler API.) -let configured: - | { - snippet: TypstSnippet; - fonts: Set; - moduleSource: unknown; - preloadDefaultFonts: boolean; - } - | undefined; - -// Compiles are serialized: shadow files (the per-document image assets) are -// state on the shared compiler, so overlapping compiles would reset or read -// each other's assets mid-flight. The chain also covers initialization, so -// two concurrent first compiles cannot double-initialize. A failed compile -// must not break the chain for the next caller, hence the swallow-and-await -// structure below (the failure still rejects that caller's own promise). -let queue: Promise = Promise.resolve(); - -async function getSnippet(options: TypstCompileOptions): Promise { - if (configured) { - const newFonts = fontList(options).filter( - (f) => !configured!.fonts.has(fontFingerprint(f)), - ); - // getModule is compared by its *resolved* source (the URL/module it - // returns, canonicalized via `moduleSourceKey`), not by function - // identity - callers typically pass a fresh closure per call around the - // same URL. Omitting it after a first call that had one means "reuse - // what's loaded" and is fine. - const moduleChanged = - options.getModule !== undefined && - moduleSourceKey(options.getModule()) !== configured.moduleSource; - if ( - newFonts.length > 0 || - moduleChanged || - (options.preloadDefaultFonts === true) !== configured.preloadDefaultFonts - ) { - throw new Error( - "The Typst compiler is already initialized with different options. " + - "Its wasm module and fonts are loaded once, on the first compile - " + - "pass every font (and the getModule/preloadDefaultFonts settings) " + - "the page will need on the first compileTypstToTaggedPdf call.", - ); - } - return configured.snippet; - } - - const { $typst, TypstSnippet } = - await import("@myriaddreamin/typst.ts/contrib/snippet"); - if (options.getModule) { - $typst.setCompilerInitOptions({ getModule: options.getModule }); - } - const providers = []; - if (options.preloadDefaultFonts === true) { - providers.push(TypstSnippet.preloadFontAssets()); - } else { - // The explicit opt-out marker matters: without a provider whose options - // say `assets: false`, the compiler driver force-loads its stock 'text' - // font assets (Libertinus, New CM Math, ...) from the jsdelivr CDN even - // when no preload provider was given - which would silently reintroduce - // a CDN dependency behind this off-by-default option. - providers.push(TypstSnippet.disableDefaultFontAssets()); - } - const fonts = fontList(options); - for (const font of fonts) { - providers.push(TypstSnippet.preloadFontData(font)); - } - if (providers.length) { - $typst.use(...providers); - } - configured = { - snippet: $typst, - fonts: new Set(fonts.map(fontFingerprint)), - moduleSource: moduleSourceKey(options.getModule?.()), - preloadDefaultFonts: options.preloadDefaultFonts === true, - }; - return configured.snippet; -} - -/** - * Compile Typst source to a *tagged* PDF using the browser (wasm) engine. - * The compiler is initialized once and reused; concurrent calls are - * serialized (see above). - */ -export async function compileTypstToTaggedPdf( - typst: string, - options: TypstCompileOptions, -): Promise { - const run = queue.then(async () => { - const $typst = await getSnippet(options); - // Shadow files are per-compile; reset so a previous document's assets - // don't leak into this one. - await $typst.resetShadow(); - for (const [path, bytes] of options.assets ?? []) { - await $typst.mapShadow(path, bytes); - } - const pdf = await $typst.pdf({ mainContent: typst }); - if (!pdf) { - throw new Error("Typst wasm compilation produced no output"); - } - return pdf; - }); - // Keep the chain alive whether this compile succeeds or fails (the failure - // still propagates through `run` to this caller) - and resolve it to - // undefined either way, so the module-global chain doesn't pin the last - // compile's multi-MB PDF bytes in memory for the page's lifetime. - queue = run.then( - () => undefined, - () => undefined, - ); - return run; -} diff --git a/packages/xl-pdf-exporter/src/pdfua/compileTypst.browser.test.ts b/packages/xl-pdf-exporter/src/pdfua/compileTypst.browser.test.ts new file mode 100644 index 0000000000..b95072ba26 --- /dev/null +++ b/packages/xl-pdf-exporter/src/pdfua/compileTypst.browser.test.ts @@ -0,0 +1,112 @@ +import { isPdf, TEST_PNG_BYTES } from "@shared/util/testBytesUtil.js"; +import { describe, expect, test } from "vite-plus/test"; + +import { compileTypstToPdf } from "./compileTypst.js"; + +// Bundled wasm so the compiler initializes fully offline. +// eslint-disable-next-line import/no-unresolved +import compilerWasmUrl from "@blocknote/xl-typst-compiler/wasm?url"; + +// Browser unit tests for the actual production compile path - the wasm +// compiler the exporters ship to the browser, loaded through the bundler +// like an app would. The node suites drive the same wasm from bytes, so +// what only this suite can catch is URL-based module loading and +// browser-side glue. Font-less on purpose: glyphs don't matter here, and +// it keeps the suite fast. +const OPTIONS = { + wasm: new URL(compilerWasmUrl, document.baseURI), +} as const; + +function expectPdf( + result: Awaited>, +): Uint8Array { + if (result.error) { + throw new Error(result.compileErrors.map((d) => d.message).join(" | ")); + } + return result.pdf; +} + +describe("compileTypstToPdf", () => { + test("compiles markup with mapped assets", { timeout: 60000 }, async () => { + const pdf = expectPdf( + await compileTypstToPdf( + `#set document(title: "t")\nHello #image("/assets/a.png", width: 10pt, alt: "a")`, + { ...OPTIONS, assets: new Map([["/assets/a.png", TEST_PNG_BYTES]]) }, + ), + ); + expect(isPdf(pdf)).toBe(true); + }); + + test( + "keeps concurrent compiles with different assets independent", + { timeout: 60000 }, + async () => { + // Assets are per-compile inputs (not shared compiler state), so + // overlapping exports - the debounced re-export scenario - cannot + // read each other's files. + async function compile(path: string) { + return expectPdf( + await compileTypstToPdf( + `#set document(title: "t")\n#image("${path}", width: 10pt, alt: "a")`, + { ...OPTIONS, assets: new Map([[path, TEST_PNG_BYTES]]) }, + ), + ); + } + const [a, b] = await Promise.all([ + compile("/assets/one.png"), + compile("/assets/two.png"), + ]); + expect(isPdf(a)).toBe(true); + expect(isPdf(b)).toBe(true); + }, + ); + + test( + "accepts different fonts on later compiles", + { timeout: 60000 }, + async () => { + // A per-compile font set was impossible under the previous + // page-singleton engine (fonts were fixed by the first compile); + // compilers are now per-font-set instances, so this must just work. + // Invalid font bytes are ignored (0 faces), not fatal. + const first = expectPdf(await compileTypstToPdf("one", OPTIONS)); + const second = expectPdf( + await compileTypstToPdf("two", { + ...OPTIONS, + fonts: [new Uint8Array([1, 2, 3])], + }), + ); + expect(isPdf(first)).toBe(true); + expect(isPdf(second)).toBe(true); + }, + ); + + test( + "returns typed diagnostics instead of output for broken markup", + { timeout: 60000 }, + async () => { + const result = await compileTypstToPdf( + "#image(unknownvariable)", + OPTIONS, + ); + expect(result.error).toBe("compile-failed"); + if (result.error) { + expect(result.compileErrors[0].message).toContain("unknown variable"); + } + }, + ); + + test( + "produces declared PDF/UA-1 with the ua-1 standard", + { timeout: 60000 }, + async () => { + const pdf = expectPdf( + await compileTypstToPdf(`#set document(title: "t")\nHello`, { + ...OPTIONS, + pdfStandard: "ua-1", + }), + ); + expect(new TextDecoder("latin1").decode(pdf)).toContain("pdfuaid"); + }, + ); +}); diff --git a/packages/xl-pdf-exporter/src/pdfua/compileTypst.ts b/packages/xl-pdf-exporter/src/pdfua/compileTypst.ts new file mode 100644 index 0000000000..ff3a1e0ac6 --- /dev/null +++ b/packages/xl-pdf-exporter/src/pdfua/compileTypst.ts @@ -0,0 +1,88 @@ +import { + TypstCompiler, + type CompilePdfResult, + type TypstCompilerOptions, +} from "@blocknote/xl-typst-compiler"; + +export interface TypstCompileOptions { + /** + * The compiler wasm module: a URL (string or `URL`) or the module bytes. + * Omitted, it loads from `@blocknote/xl-typst-compiler`'s own package + * files - bundlers emit it as an asset, so zero-config exports involve no + * CDN. The module is loaded once per page; only the first compile's value + * is used. + */ + wasm?: TypstCompilerOptions["wasm"]; + /** + * Fonts (as bytes) to load into the compiler - the body fonts the + * exporter references (e.g. Inter, Geist Mono). The compiler ships no + * fonts of its own: text renders only with supplied fonts, and a + * document needing a missing one fails to compile (loudly, not with + * substituted glyphs). + */ + fonts?: Uint8Array[]; + /** + * The emoji source: an emoji-capable font (or fonts) as bytes. Unlike + * react-pdf's image-based `emojiSource`, Typst renders emoji from a font, + * so this is how you supply one. Required for PDF/UA-1 conformant output + * that contains emoji - the browser has no OS font access, so without it + * emoji render as `.notdef` and fail ISO 14289-1 clauses 7.21.7 / 7.21.8. + * Loaded alongside {@link fonts} (this is just a clearer, dedicated + * channel for it). + */ + emojiFont?: Uint8Array | Uint8Array[]; + /** + * Image/asset files to map into the compiler's virtual filesystem, keyed + * by the Typst path referenced in the source (e.g. `/assets/asset-0`). + * Populate from `TypstExporter.assetFiles`. + */ + assets?: ReadonlyMap; + /** + * PDF creation timestamp in seconds since the Unix epoch (UTC). Pass a + * fixed value for byte-reproducible output; omitted means no timestamp. + */ + creationTimestamp?: number; +} + +function fontList(options: TypstCompileOptions): Uint8Array[] { + const emojiFonts = + options.emojiFont === undefined + ? [] + : Array.isArray(options.emojiFont) + ? options.emojiFont + : [options.emojiFont]; + return [...(options.fonts ?? []), ...emojiFonts]; +} + +/** + * Compile Typst source to PDF with the wasm engine + * (`@blocknote/xl-typst-compiler`). Compilation failure - invalid markup, + * a missing font, or PDF-standard validation - is part of the contract and + * comes back as a typed result, not an exception. + * + * Pass `pdfStandard: "ua-1"` for a *validated*, declared PDF/UA-1; without + * it the output is tagged (accessible structure tree) but carries no + * conformance claim. + */ +export async function compileTypstToPdf( + typst: string, + options: TypstCompileOptions & { + pdfStandard?: string; + tagged?: boolean; + } = {}, +): Promise { + // A fresh instance per compile: the wasm module is loaded once globally + // and Typst's caches are module-wide, so instance creation (including + // parsing the fonts) costs single-digit milliseconds - not worth any + // reuse scheme, and it keeps compiles fully independent. + const compiler = await TypstCompiler.create({ + wasm: options.wasm, + fonts: fontList(options), + }); + return compiler.compilePdf(typst, { + assets: options.assets, + pdfStandard: options.pdfStandard, + tagged: options.tagged, + creationTimestamp: options.creationTimestamp, + }); +} diff --git a/packages/xl-pdf-exporter/src/pdfua/pdfua.test.ts b/packages/xl-pdf-exporter/src/pdfua/pdfua.test.ts index 31dc70f432..053dcd8440 100644 --- a/packages/xl-pdf-exporter/src/pdfua/pdfua.test.ts +++ b/packages/xl-pdf-exporter/src/pdfua/pdfua.test.ts @@ -6,24 +6,20 @@ import { import { PDFDict, PDFDocument, PDFName } from "@cantoo/pdf-lib"; import { ColumnBlock, ColumnListBlock } from "@blocknote/xl-multi-column"; import { testDocument } from "@shared/testDocument.js"; -import { toMatchBinaryFileSnapshot } from "@shared/util/binaryFileSnapshotUtil.js"; import { testResolveFileUrl } from "@shared/util/testFileResolver.js"; import { compileTypstForTesting } from "@shared/util/typstTestUtil.js"; -import { execFileSync } from "node:child_process"; -import { mkdtempSync, readdirSync, readFileSync, writeFileSync } from "node:fs"; -import { tmpdir } from "node:os"; -import { join, resolve } from "node:path"; +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; import { beforeAll, describe, expect, it } from "vite-plus/test"; import { TypstExporter, typstDefaultSchemaMappings, } from "@blocknote/xl-typst-exporter"; -import { declarePdfUA } from "./postProcess.js"; // The fonts the exporter references (Inter 18pt + Geist Mono), from the shared // assets, plus a color emoji font (Noto Color Emoji, pure-COLRv1) so emoji // render in color rather than as `.notdef` — matching the example. -function fontBlobs(): Buffer[] { +function fontBlobs(): Uint8Array[] { const shared = "../../shared/assets/fonts"; const paths = [ `${shared}/inter/Inter_18pt-Regular.ttf`, @@ -33,91 +29,26 @@ function fontBlobs(): Buffer[] { `${shared}/GeistMono-Regular.ttf`, `${shared}/noto/Noto-COLRv1.ttf`, ]; - return paths.map((p) => Buffer.from(readFileSync(resolve(process.cwd(), p)))); -} - -// These tests are gates, and a gate whose tooling is missing must fail -// loudly - a silent pass would report conformance/visual coverage that was -// never checked. -function requireTool(command: string, args: string[], installHint: string) { - try { - execFileSync(command, args, { stdio: "ignore" }); - } catch { - throw new Error( - `\`${command} ${args.join(" ")}\` failed - it is required by this test. ${installHint}`, - ); - } -} - -// The rasterizer for the visual snapshots, as a digest-pinned container -// (mirroring the veraPDF image in tests/scripts/install-pdf-tooling.sh): -// the PNG baselines are compared byte-exactly, so every environment - a -// macOS laptop, CI, next year's CI - must run the *identical* poppler -// build. `--platform linux/amd64` below keeps even the binary the same on -// Apple Silicon (via Rosetta). Repoint deliberately, regenerating the -// baselines (`vp test --run src/pdfua/pdfua.test.ts -u`) in the same -// change. install-pdf-tooling.sh greps this constant to pre-pull the image -// on CI. -const POPPLER_IMAGE = - "minidocks/poppler@sha256:0817047a6d6078f1af9931860646e8c21234c0c1777d2f05b79df8434cb194de"; // :latest as of 2026-08-20 - -/** Rasterizes each page to `page-N.png` in `dir`, returning the file names. */ -function rasterizePdf(pdf: Buffer, dir: string): string[] { - writeFileSync(join(dir, "doc.pdf"), pdf); - // The host user's uid/gid, so the container-written PNGs are readable and - // cleanable by the test process on Linux bind mounts. - const user = process.getuid - ? ["--user", `${process.getuid()}:${process.getgid!()}`] - : []; - execFileSync( - "docker", - [ - "run", - "--rm", - "--platform", - "linux/amd64", - ...user, - "-v", - `${dir}:/data`, - POPPLER_IMAGE, - "pdftoppm", - "-png", - "-r", - "96", - "/data/doc.pdf", - "/data/page", - ], - { stdio: "ignore" }, + return paths.map( + (p) => new Uint8Array(readFileSync(resolve(process.cwd(), p))), ); - return readdirSync(dir) - .filter((f) => f.endsWith(".png")) - .sort(); } -function veraPdfVerdict(pdf: Uint8Array): string { - requireTool( - "verapdf", - ["--version"], - "Install veraPDF (https://verapdf.org) - it is the PDF/UA conformance gate.", - ); - const dir = mkdtempSync(join(tmpdir(), "pdfua-")); - const file = join(dir, "out.pdf"); - writeFileSync(file, pdf); - try { - return execFileSync("verapdf", ["--flavour", "ua1", file], { - encoding: "utf8", - maxBuffer: 1e8, - }); - } catch (e: any) { - return e.stdout?.toString() ?? ""; // non-zero exit on non-conformance - } -} - -// Compiles the shared test document once (with the network-free test image -// resolver), then asserts both PDF/UA-1 conformance and a per-page visual -// snapshot off the same render. -describe("pdf/ua-1: BlockNote -> Typst -> PDF (conformance + visual)", () => { - let tagged: Buffer; +// Compiles the shared test document (with the network-free test image +// resolver) natively as PDF/UA-1 and asserts the structural essentials. +// +// Conformance itself is validated *during* the compile: requesting the +// `ua-1` standard makes Typst/krilla check the document (heading structure, +// alt text, title, ...) and refuse to emit a nonconforming PDF — so a +// successful compile IS the conformance statement, guaranteed by the +// engine rather than re-verified here. (Independent verification with +// veraPDF — `verapdf --flavour ua1` — remains a manual option; the +// declared output has been validated against it: 0 failed checks.) +// +// Visual regression of the rendered pages lives in the browser e2e suite +// (tests/src/end-to-end/exporters/exporterImages.test.tsx), which +// rasterizes the produced PDF with pdf.js and screenshots each page. +describe("pdf/ua-1: BlockNote -> Typst -> PDF", () => { let ua: Uint8Array; beforeAll(async () => { @@ -145,56 +76,29 @@ describe("pdf/ua-1: BlockNote -> Typst -> PDF (conformance + visual)", () => { author: "BlockNote", }); - // Compile to a *tagged* PDF (no UA flag), mirroring the browser path. - tagged = Buffer.from( - await compileTypstForTesting(typ, { - assets: exporter.assetFiles, - fontBlobs: fontBlobs(), - creationTimestamp: 1_700_000_000, - }), - ); - // Declare PDF/UA-1 via our post-process. - ua = await declarePdfUA(new Uint8Array(tagged)); + ua = await compileTypstForTesting(typ, { + assets: exporter.assetFiles, + fontBlobs: fontBlobs(), + creationTimestamp: 1_700_000_000, + pdfStandard: "ua-1", + }); }, 30000); - it("produces a declared, structurally-tagged, veraPDF-conformant document", async () => { - // Deterministic structural assertions (no external tooling). + it("produces a declared, structurally-tagged document", async () => { + // The conformance claim in the XMP metadata. + expect(new TextDecoder("latin1").decode(ua)).toContain("pdfuaid"); + + // Structure that lives in compressed objects, via a real PDF parser: + // the tag tree root and the DisplayDocTitle viewer preference PDF/UA + // requires. const doc = await PDFDocument.load(ua, { updateMetadata: false }); expect(doc.catalog.get(PDFName.of("StructTreeRoot"))).toBeDefined(); const vp = doc.catalog.lookup(PDFName.of("ViewerPreferences"), PDFDict); expect(String(vp!.get(PDFName.of("DisplayDocTitle")))).toBe("true"); - - // Full conformance gate. - const verdict = veraPdfVerdict(ua); - expect(verdict).toContain('isCompliant="true"'); - expect(verdict).toContain('failedChecks="0"'); }); - it("matches the per-page visual snapshot", async () => { - requireTool( - "docker", - ["info"], - "Start Docker - the visual snapshot rasterizes through a digest-pinned poppler container so the PNG baselines are byte-stable across environments.", - ); - const dir = mkdtempSync(join(tmpdir(), "bn-visual-")); - // Rasterize the *final* PDF/UA artifact (post `declarePdfUA`), not the - // intermediate tagged PDF - the post-process is metadata-only, so the - // raster is identical, and this way a post-process regression that did - // alter page content would fail the visual snapshot too. - const pages = rasterizePdf(Buffer.from(ua), dir); - expect(pages.length).toBeGreaterThan(0); - - // Compare each page against its committed baseline PNG; on mismatch the - // received render is dumped next to the baseline for inspection. - for (let i = 0; i < pages.length; i++) { - await toMatchBinaryFileSnapshot( - readFileSync(join(dir, pages[i])), - resolve( - process.cwd(), - `src/pdfua/__snapshots__/render/testDocument-${i + 1}.png`, - ), - { writeActualOnMismatch: true }, - ); - } + it("carries the fixed creation timestamp (deterministic output)", () => { + // Byte-reproducible output is what the e2e visual baselines rely on. + expect(new TextDecoder("latin1").decode(ua)).toContain("2023-11-14"); }); }); diff --git a/packages/xl-pdf-exporter/src/pdfua/postProcess.test.ts b/packages/xl-pdf-exporter/src/pdfua/postProcess.test.ts deleted file mode 100644 index c90c5229fd..0000000000 --- a/packages/xl-pdf-exporter/src/pdfua/postProcess.test.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { existsSync, readFileSync } from "node:fs"; -import { resolve } from "node:path"; -import { PDFDict, PDFDocument, PDFName, PDFRawStream } from "@cantoo/pdf-lib"; -import { describe, expect, it } from "vite-plus/test"; -import { declarePdfUA } from "./postProcess.js"; - -// `tagged.pdf` is a Typst-generated, tagged-but-NOT-declared PDF/UA document -// (the same kind the wasm browser engine emits). -function loadFixture(): Uint8Array { - const candidates = [ - resolve(process.cwd(), "src/pdfua/__fixtures__/tagged.pdf"), - resolve(process.cwd(), "__fixtures__/tagged.pdf"), - ]; - const path = candidates.find((p) => existsSync(p)); - if (!path) { - throw new Error("tagged.pdf fixture not found; cwd=" + process.cwd()); - } - return new Uint8Array(readFileSync(path)); -} - -// A minimal one-page PDF whose /Metadata stream holds the given XMP packet, -// for exercising declarePdfUA against XMP shapes the Typst fixture cannot -// produce (e.g. a pre-existing pdfuaid:part claim). -async function pdfWithXmp(xmp: string): Promise { - const doc = await PDFDocument.create(); - doc.addPage(); - const bytes = new TextEncoder().encode(xmp); - doc.catalog.set( - PDFName.of("Metadata"), - doc.context.register( - PDFRawStream.of( - doc.context.obj({ - Type: "Metadata", - Subtype: "XML", - Length: bytes.length, - }), - bytes, - ), - ), - ); - return doc.save({ useObjectStreams: false }); -} - -function xmpWithDescription(content: string): string { - return `${content}`; -} - -describe("declarePdfUA", () => { - it("adds DisplayDocTitle + pdfuaid:part=1 to a tagged PDF", async () => { - const out = await declarePdfUA(loadFixture()); - - const doc = await PDFDocument.load(out, { updateMetadata: false }); - - // 1) ViewerPreferences / DisplayDocTitle = true - const vp = doc.catalog.lookup(PDFName.of("ViewerPreferences"), PDFDict); - expect(vp).toBeDefined(); - expect(String(vp!.get(PDFName.of("DisplayDocTitle")))).toBe("true"); - - // 2) PDF/UA identification in XMP - const meta = doc.context.lookup( - doc.catalog.get(PDFName.of("Metadata")), - ) as PDFRawStream; - const xmp = new TextDecoder().decode(meta.getContents()); - expect(xmp).toContain("pdfuaid"); - expect(xmp).toMatch(/1<\/pdfuaid:part>/); - - // structure is preserved (still a tagged PDF) - expect(doc.catalog.get(PDFName.of("StructTreeRoot"))).toBeDefined(); - }); - - it("is idempotent", async () => { - const once = await declarePdfUA(loadFixture()); - const twice = await declarePdfUA(once); - const doc = await PDFDocument.load(twice, { updateMetadata: false }); - const meta = doc.context.lookup( - doc.catalog.get(PDFName.of("Metadata")), - ) as PDFRawStream; - const xmp = new TextDecoder().decode(meta.getContents()); - // not doubled - expect(xmp.match(//g)?.length).toBe(1); - }); - - it("keeps an existing PDF/UA-1 claim without doubling it", async () => { - const out = await declarePdfUA( - await pdfWithXmp(xmpWithDescription("1")), - ); - const doc = await PDFDocument.load(out, { updateMetadata: false }); - const meta = doc.context.lookup( - doc.catalog.get(PDFName.of("Metadata")), - ) as PDFRawStream; - const xmp = new TextDecoder().decode(meta.getContents()); - expect(xmp.match(//g)?.length).toBe(1); - }); - - it("rejects an existing claim of a different PDF/UA part", async () => { - await expect( - declarePdfUA( - await pdfWithXmp(xmpWithDescription("2")), - ), - ).rejects.toThrow("pdfuaid:part"); - }); - - it("rejects an existing empty pdfuaid:part element", async () => { - await expect( - declarePdfUA( - await pdfWithXmp(xmpWithDescription("")), - ), - ).rejects.toThrow("pdfuaid:part"); - }); -}); diff --git a/packages/xl-pdf-exporter/src/pdfua/postProcess.ts b/packages/xl-pdf-exporter/src/pdfua/postProcess.ts deleted file mode 100644 index 45d8548590..0000000000 --- a/packages/xl-pdf-exporter/src/pdfua/postProcess.ts +++ /dev/null @@ -1,174 +0,0 @@ -import { - decodePDFRawStream, - PDFDocument, - PDFName, - PDFRawStream, -} from "@cantoo/pdf-lib"; - -// The XMP namespace of the PDF/UA identification schema (ISO 14289-1, -// clause 5). Its one required property, `pdfuaid:part`, holds the part -// number of the ISO standard the file claims conformance with - `1` for -// PDF/UA-1. This is the analogue of PDF/A's `pdfaid:part`. -const PDFUA_NS = "http://www.aiim.org/pdfua/ns/id/"; - -/** - * Promote a *tagged* PDF (as produced by the Typst engine) to a declared - * PDF/UA-1 document. - * - * Typst 0.15 already emits the hard part - a UA-conformant tag tree - by - * default. What its `--pdf-standard ua-1` export flag *additionally* writes, - * and what the published wasm binding does not expose, are two declarations: - * - * 1. `/ViewerPreferences << /DisplayDocTitle true >>` in the catalog: - * viewers must show the document title, not the filename - * (ISO 14289-1, 7.1). - * 2. The conformance claim in the document's XMP metadata - the XML - * packet in the catalog's `/Metadata` stream where title/producer - * etc. live (clause 5): - * - * ```xml - * - * 1 - * - * ``` - * - * Validators check the claim first: veraPDF's `ua1` flavour fails a file - * without the identifier no matter how well-tagged it is. Both declarations - * are added here in pure JS (@cantoo/pdf-lib runs in the browser), so the - * whole pipeline stays client-side. - * - * A document whose XMP cannot be safely rewritten makes this function throw - * rather than return an undeclared (or corrupted) PDF as success. - * - * NOTE: this *declares* conformance; it does not create it. Garbage in (an - * untagged PDF, a figure missing alt text, ...) stays non-conformant - and - * now falsely claims otherwise - which is why veraPDF is the gate, not this - * function. To produce a tagged-but-unclaimed PDF instead, compile with - * `compileTypstToTaggedPdf` and skip this step. - */ -export async function declarePdfUA(pdfBytes: Uint8Array): Promise { - const doc = await PDFDocument.load(pdfBytes, { updateMetadata: false }); - - // Declaration 1: DisplayDocTitle. - doc.catalog.getOrCreateViewerPreferences().setDisplayDocTitle(true); - - // Declaration 2: `pdfuaid:part` in the XMP packet. The existing packet is - // edited rather than replaced, preserving the metadata Typst wrote - // (title, producer, ...), then written back as a fresh /Metadata stream. - const xmp = withPdfUaIdentifier(readMetadataXmp(doc)); - const xmpBytes = new TextEncoder().encode(xmp); - doc.catalog.set( - PDFName.of("Metadata"), - doc.context.register( - PDFRawStream.of( - doc.context.obj({ - Type: "Metadata", - Subtype: "XML", - Length: xmpBytes.length, - }), - xmpBytes, - ), - ), - ); - - return doc.save({ useObjectStreams: false }); -} - -/** - * The document's XMP packet as a string - or, for a document without one, a - * minimal empty packet (one blank `rdf:Description`) to inject into. - */ -function readMetadataXmp(doc: PDFDocument): string { - const ref = doc.catalog.get(PDFName.of("Metadata")); - if (!ref) { - return ``; - } - const stream = doc.context.lookup(ref); - if (!(stream instanceof PDFRawStream)) { - throw new Error( - "declarePdfUA: the document's /Metadata is not a stream object", - ); - } - // Run the stream through its declared filters. XMP is usually stored - // uncompressed, but a Flate-compressed packet is legal - decoding raw - // contents as text would silently corrupt it. - const bytes = - stream.dict.get(PDFName.of("Filter")) === undefined - ? stream.getContents() - : decodePDFRawStream(stream).decode(); - return new TextDecoder().decode(bytes); -} - -/** - * Splices `1` (plus its namespace declaration) - * into the packet's first `rdf:Description` element: - * - * before: ... - * after: - * 1... - * - * Regex-based on purpose: a DOM round-trip isn't available in node and - * re-serializing the whole packet risks perturbing metadata this code - * doesn't understand. A packet without any description throws (as does one - * already claiming a pdfuaid:part other than 1); the - * long-term replacement is the compiler's own `--pdf-standard ua-1` flag - * once the wasm binding exposes it (see the TODO in index.ts). - */ -function withPdfUaIdentifier(xmp: string): string { - // Already identified as PDF/UA-1 (element or attribute form) - nothing to - // do. Matched as the actual element/attribute form, not as a bare - // substring (document text merely *mentioning* "pdfuaid:part" must not - // skip the declaration). - if ( - /\s*1\s*<\/pdfuaid:part>|pdfuaid:part\s*=\s*["']\s*1\s*["']/.test( - xmp, - ) - ) { - return xmp; - } - - // Any other existing identifier - a different part, or an empty or - // otherwise unreadable value - is a conflicting claim. Keeping it would - // return a document that does not declare PDF/UA-1 as success, and - // rewriting a foreign value in place is exactly the kind of splice the - // regex approach must not attempt (see above) - so throw, per this - // module's contract. - if (/]|pdfuaid:part\s*=/.test(xmp)) { - throw new Error( - "declarePdfUA: the document's XMP metadata already contains a " + - "pdfuaid:part identifier that does not declare PDF/UA-1", - ); - } - - // Find the first (outermost) description's open tag. Group 1 = its - // attributes, group 2 = "/" when the element is self-closing - // (attribute-only XMP, common from non-Typst producers). - const openTag = /]*?)(\/?)>/.exec(xmp); - if (!openTag) { - throw new Error( - "declarePdfUA: no found in the document's XMP metadata", - ); - } - const [match, attrs, selfClosing] = openTag; - - // Bind the `pdfuaid` prefix on the element, then rebuild it with the - // identifier as its FIRST child (property order in RDF is insignificant, - // and inserting at the open tag keeps this a single replace - appending - // before a closing tag could land inside a *nested* description, e.g. an - // XMP struct value). A self-closing element is expanded so the property - // has somewhere to live. The replacement goes through a function because - // the spliced text is document-derived - as a replacement *string*, - // `$`-patterns in it (e.g. `$&`) would be expanded by String.replace. - const attrsWithNs = /pdfuaid/.test(attrs) - ? attrs - : `${attrs} xmlns:pdfuaid="${PDFUA_NS}"`; - const part = `1`; - return xmp.replace( - match, - () => - `${part}${ - selfClosing ? "" : "" - }`, - ); -} diff --git a/packages/xl-pdf-exporter/vite.config.ts b/packages/xl-pdf-exporter/vite.config.ts index 14be012e7f..3c3a7ad2f8 100644 --- a/packages/xl-pdf-exporter/vite.config.ts +++ b/packages/xl-pdf-exporter/vite.config.ts @@ -20,6 +20,9 @@ export default defineConfig( // dist/ leaves consumers without declarations (tsc is skipped). // Entries stored before this spec carried types/** replay stale // declarations; editing this config invalidates them. + // (Invalidated again 2026-08: the Typst-compiler migration + // replaced pdfua/compileBrowser with pdfua/compileTypst and the + // export surface, and cached pre-migration types resurfaced.) output: ["dist/**", "types/**", "!dist/*.tsbuildinfo"], }, }, diff --git a/packages/xl-typst-compiler/.gitignore b/packages/xl-typst-compiler/.gitignore new file mode 100644 index 0000000000..34aa146b52 --- /dev/null +++ b/packages/xl-typst-compiler/.gitignore @@ -0,0 +1,2 @@ +target/ +pkg/ diff --git a/packages/xl-typst-compiler/README.md b/packages/xl-typst-compiler/README.md new file mode 100644 index 0000000000..9812099d8a --- /dev/null +++ b/packages/xl-typst-compiler/README.md @@ -0,0 +1,66 @@ +# @blocknote/xl-typst-compiler + +The [Typst](https://typst.app) compiler - the official `typst` Rust crates, +compiled to WebAssembly - behind a minimal TypeScript API: Typst markup + +assets + fonts in, PDF bytes (or typed diagnostics) out. This is the engine +of BlockNote's [PDF export](https://www.blocknotejs.org/docs/features/export/pdf); +it also works standalone, in browsers and Node alike. + +Design points: + +- **No network access, ever.** The wasm embeds no fonts and downloads + nothing; text renders only with fonts you supply (`fonts` / + `addFont`), and a document needing a missing font fails loudly instead + of rendering substituted glyphs. +- **No singleton.** Create as many compiler instances as you like; each + owns only its font set. The wasm module loads once per page. +- **Native PDF standards.** `pdfStandard: "ua-1"` produces a _validated_, + declared, accessible PDF/UA-1 - typst checks conformance at compile time + (heading structure, alt text, document title, ...) and nonconforming + documents fail with recognizable diagnostics + (`isPdfStandardViolation`), never with a false conformance claim. +- **Failures are values.** `compilePdf` returns a result union; compile + errors (including standard violations) carry structured diagnostics with + messages, hints, and source byte ranges. + +```ts +import { TypstCompiler } from "@blocknote/xl-typst-compiler"; + +const compiler = await TypstCompiler.create({ fonts: [interBytes] }); +const result = compiler.compilePdf(source, { + assets: new Map([["/assets/img.png", pngBytes]]), + pdfStandard: "ua-1", +}); +if (result.error) { + console.log(result.diagnostics); +} else { + download(result.pdf); +} +``` + +## Building the wasm + +The wasm module (`pkg/`) is built from `rust/` (toolchain pinned in +`rust/rust-toolchain.toml`, `wasm32-unknown-unknown` target, +[wasm-pack](https://rustwasm.github.io/wasm-pack/)): + +```bash +pnpm exec vp run --filter @blocknote/xl-typst-compiler build +``` + +The build task self-provisions: `scripts/ensure-wasm.mjs` compiles `pkg/` +from `rust/` when it is missing or stale (content-hashed), before the +TypeScript build. It needs rustup locally (the pinned toolchain and wasm32 +target auto-install); on Vercel it bootstraps rustup itself and keeps the +cargo caches under `node_modules/.cache`, so only the first build on a +fresh cache pays the full compile. `npm run build:wasm` forces a rebuild. +`pkg/` is a build output (not checked in); the published npm package +includes it. + +## Loading the wasm + +By default the module loads from this package's own files, relative to the +wasm-bindgen glue - no CDN involved; bundlers (Vite, webpack) emit it as an +asset automatically. To control loading (self-hosting, caching, Node), pass +`wasm` to `TypstCompiler.create` - a URL or the module bytes. The module is +loaded once; later `create()` calls reuse it. diff --git a/packages/xl-typst-compiler/package.json b/packages/xl-typst-compiler/package.json new file mode 100644 index 0000000000..b5e8b0ae2c --- /dev/null +++ b/packages/xl-typst-compiler/package.json @@ -0,0 +1,67 @@ +{ + "name": "@blocknote/xl-typst-compiler", + "homepage": "https://github.com/TypeCellOS/BlockNote", + "private": false, + "sideEffects": false, + "repository": { + "type": "git", + "url": "git+https://github.com/TypeCellOS/BlockNote.git", + "directory": "packages/xl-typst-compiler" + }, + "license": "GPL-3.0 OR PROPRIETARY", + "version": "0.54.0", + "files": [ + "dist", + "types", + "src", + "pkg", + "rust", + "README.md", + "scripts" + ], + "keywords": [ + "typst", + "pdf", + "wasm", + "compiler", + "javascript", + "typescript" + ], + "description": "The Typst compiler (official typst crates) compiled to WebAssembly, with a minimal TypeScript API - the engine behind BlockNote's PDF export.", + "type": "module", + "source": "src/index.ts", + "types": "./types/src/index.d.ts", + "main": "./dist/blocknote-xl-typst-compiler.cjs", + "module": "./dist/blocknote-xl-typst-compiler.js", + "exports": { + ".": { + "types": "./types/src/index.d.ts", + "import": "./dist/blocknote-xl-typst-compiler.js", + "require": "./dist/blocknote-xl-typst-compiler.cjs" + }, + "./pkg": { + "types": "./pkg/blocknote_typst_wasm.d.ts", + "default": "./pkg/blocknote_typst_wasm.js" + }, + "./wasm": { + "default": "./pkg/blocknote_typst_wasm_bg.wasm" + } + }, + "scripts": { + "dev": "vp dev", + "build:wasm": "node scripts/ensure-wasm.mjs --force", + "lint": "vp lint src", + "test": "vp test --run", + "test-watch": "vp test watch", + "clean": "rimraf dist && rimraf types" + }, + "devDependencies": { + "@types/node": "22.13.13", + "rimraf": "^5.0.10", + "rollup-plugin-webpack-stats": "^0.2.6", + "typescript": "^7.0.2", + "vite-plus": "catalog:", + "wasm-pack": "^0.15.0" + }, + "gitHead": "37614ab348dcc7faa830a9a88437b37197a2162d" +} diff --git a/packages/xl-typst-compiler/rust/Cargo.lock b/packages/xl-typst-compiler/rust/Cargo.lock new file mode 100644 index 0000000000..e467ae52fb --- /dev/null +++ b/packages/xl-typst-compiler/rust/Cargo.lock @@ -0,0 +1,3128 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ar_archive_writer" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73cd58deff2140a0a8eae87e417bd01db68a33e148aa93d1e8cd837e55e312b6" +dependencies = [ + "object", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "az" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "biblatex" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "591eba69b7c085632e22ca03606f0bbea68d53bbe26c8962e2d549af20c6a561" +dependencies = [ + "paste", + "roman-numerals-rs", + "strum", + "unic-langid", + "unicode-normalization", + "unscanny", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +dependencies = [ + "serde_core", +] + +[[package]] +name = "blocknote-typst-wasm" +version = "0.1.0" +dependencies = [ + "comemo 0.4.0", + "console_error_panic_hook", + "js-sys", + "serde", + "serde-wasm-bindgen", + "typst", + "typst-layout", + "typst-pdf", + "wasm-bindgen", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0e56a716f1e132ff6bf4bdac1c944a3fcdc1cae65f70a4a2a1ac3b401d2d1f" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "cc" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chinese-number" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e964125508474a83c95eb935697abbeb446ff4e9d62c71ce880e3986d1c606b" +dependencies = [ + "chinese-variant", + "enum-ordinalize", + "num-bigint", + "num-traits", +] + +[[package]] +name = "chinese-variant" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d1275808335c5583ea45a4141d631dafcb36b79fa8a5e10b00e356b6af3e08a" + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "citationberg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756ff1e3d43a9ecc8183932fb4d9fd3971236f3ce4acb62fe51d1cd43297547d" +dependencies = [ + "quick-xml 0.38.4", + "serde", + "serde_path_to_error", +] + +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror", +] + +[[package]] +name = "codex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0732ab1a27b4ea05e6f9f60a5122c9924dd5123defde0d8e907f58cf643d40e6" +dependencies = [ + "chinese-number", +] + +[[package]] +name = "color" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ec7c5eb7a16992b1904d76c517d170ab353b0e0b3d5a0c81a8a0cd1037893cf" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "comemo" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df6916408a724339aa77b18214233355f3eb04c42eb895e5f8909215bd8a7a91" +dependencies = [ + "comemo-macros 0.4.0", + "once_cell", + "parking_lot", + "siphasher", +] + +[[package]] +name = "comemo" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c963350b2b08aa4b725d7802593245380ab53dacfedcaa971385fc33306c0d4" +dependencies = [ + "comemo-macros 0.5.1", + "parking_lot", + "rustc-hash", + "siphasher", + "slab", +] + +[[package]] +name = "comemo-macros" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8936e42f9b4f5bdfaf23700609ac1f11cb03ad4c1ec128a4ee4fd0903e228db" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "comemo-macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3c400139ba1389ef9e20ad2d87cda68b437a66483aa0da616bdf2cea7413853" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "core_maths" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" +dependencies = [ + "libm", +] + +[[package]] +name = "crc32fast" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8498c871161e1742aaa9d52551b2d6ebdd4c3d45a3be423e3728f33b955be550" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "csv" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde_core", +] + +[[package]] +name = "csv-core" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +dependencies = [ + "memchr", +] + +[[package]] +name = "data-url" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "ecow" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78e4f79b296fbaab6ce2e22d52cb4c7f010fe0ebe7a32e34fa25885fd797bd02" +dependencies = [ + "serde", +] + +[[package]] +name = "either" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" + +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "euclid" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fancy-regex" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f" +dependencies = [ + "bit-set", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "fearless_simd" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97b65636e5b9ef369943878ac74335ba1c55c1cb6adbf1e2c293c624248d693" + +[[package]] +name = "find-msvc-tools" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "font-types" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b38ad915f6dadd993ced50848a8291a543bd41ca62bc10740d5e64e2ab4cfd7" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "fontconfig-parser" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646" +dependencies = [ + "roxmltree 0.20.0", +] + +[[package]] +name = "fontdb" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2", + "slotmap", + "tinyvec", + "ttf-parser", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "gif" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "glidesort" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2e102e6eb644d3e0b186fc161e4460417880a0a0b87d235f2e5b8fb30f2e9e0" + +[[package]] +name = "glifo" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d99fc21d493812643aae86d53b7bbd02f376434a90317e8a790bc209fdd6605e" +dependencies = [ + "bytemuck", + "foldhash", + "hashbrown", + "log", + "peniko", + "png", + "skrifa", + "smallvec", + "vello_common 0.0.9", +] + +[[package]] +name = "guillotiere" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b17e70c989c36bad147b27a58d148c0741c51448aa5653436547323e524d0ab" +dependencies = [ + "euclid", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hayagriva" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b6c185c5c72546d50b25b70187f01ab9a1a2fa21c4db8691e2426fa5fce805c" +dependencies = [ + "biblatex", + "ciborium", + "citationberg", + "icu_collator", + "icu_locale", + "indexmap", + "paste", + "roman-numerals-rs", + "serde", + "serde_yaml", + "thiserror", + "unic-langid", + "unicode-segmentation", + "unscanny", + "url", +] + +[[package]] +name = "hayro" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4caa128ab87fd48ffb7490617cf93f77f606820dffbc9fd9ef6ab0ed077f56d" +dependencies = [ + "bytemuck", + "hayro-interpret", + "image", + "kurbo", + "pic-scale", + "vello_cpu", +] + +[[package]] +name = "hayro-ccitt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f4d0e94ddd48749f06bbe4e5389fb9799a0c45bcaf00495042076ef05e3241a" + +[[package]] +name = "hayro-cmap" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d285dc30731c8485de5fa732fbdf2b3affdf01e4da7c2135022ca6fa664bf6" +dependencies = [ + "hayro-postscript", +] + +[[package]] +name = "hayro-interpret" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2613d0406898995042d0794c4245b2f2fba1246490c8ac593769bba6551129d" +dependencies = [ + "bitflags", + "hayro-cmap", + "hayro-syntax", + "kurbo", + "moxcms", + "phf", + "rustc-hash", + "siphasher", + "skrifa", + "smallvec", + "yoke", +] + +[[package]] +name = "hayro-jbig2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69374b3668dd45aeb3d3145cda68f2c7b4f223aaa2511e67d076f1c7d741388d" +dependencies = [ + "fearless_simd", + "hayro-ccitt", +] + +[[package]] +name = "hayro-jpeg2000" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ab947623ef4ccaa7acf0579edf7cbb5a73838e3839a7be73335e522f433a1" +dependencies = [ + "fearless_simd", +] + +[[package]] +name = "hayro-postscript" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "885c5ef0654933139a9b9546fc2c69e18d37f38aa2520f079092b1be18f1fcaa" + +[[package]] +name = "hayro-svg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7434c89e920d84e077214a29e69b462a6518754610f732f1124af3948410cb8c" +dependencies = [ + "base64", + "hayro-interpret", + "image", + "kurbo", + "siphasher", + "xmlwriter", +] + +[[package]] +name = "hayro-syntax" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0edeafd70aa2db743de8ede8637d07ec87db05efe69cde371d03f1b185fcef27" +dependencies = [ + "flate2", + "hayro-ccitt", + "hayro-jbig2", + "hayro-jpeg2000", + "memchr", + "rustc-hash", + "smallvec", + "zune-jpeg", +] + +[[package]] +name = "hayro-write" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0b3db92c4917aad24ff30d61413a9a7509ae88b27aee1ae34eff881e1d2723a" +dependencies = [ + "flate2", + "hayro-syntax", + "pdf-writer", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hypher" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef68590049bab63a464eee1a1158ac04c6f6613a546d8d90f78636b8b94f171" + +[[package]] +name = "icu_collator" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08984ed58ac439ebf3e13d2cf26b0c46a60afcd21721c1d14087c0b240344dda" +dependencies = [ + "icu_collator_data", + "icu_collections", + "icu_locale_core", + "icu_locale_fallback", + "icu_normalizer", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "zerovec", +] + +[[package]] +name = "icu_collator_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d7e54efdddeb1208c08dd5d32b53a879ac00d2d3d051b2255fd26821d16368" + +[[package]] +name = "icu_collections" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" +dependencies = [ + "displaydoc", + "potential_utf", + "serde", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "785f595c61ef57169a467eeed7b4b6936a66f6cacbb116a96ee86da983251bf4" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_locale_data", + "icu_locale_fallback", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +dependencies = [ + "displaydoc", + "litemap", + "serde", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locale_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37d91460e362a5cf58907cd7ce871411775ee6294e49a5cc8e6cec16dfa75ea" + +[[package]] +name = "icu_locale_fallback" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "251af8e57c9400e3eb58242fe5b8b1152b2a64fdf4cf632f923c38ccee6f2fa9" +dependencies = [ + "icu_locale_core", + "icu_locale_fallback_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locale_fallback_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "decf2a22ec8fa68f1a0c1129a3f8583f8f8bc24e8b9ccbe98ead99f62a4dc3a8" + +[[package]] +name = "icu_normalizer" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" + +[[package]] +name = "icu_properties" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "serde", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" + +[[package]] +name = "icu_provider" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" +dependencies = [ + "displaydoc", + "icu_locale_core", + "postcard", + "serde", + "stable_deref_trait", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_provider_blob" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5916b44fac319d3f58e4d8d805a627df19e27937b582cd99fcde3bb6b7ce1b0e" +dependencies = [ + "icu_provider", + "postcard", + "serde", + "writeable", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_segmenter" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d07aafccd67af15d02512a6adf5896fbc5ed00f2e99b471d2efa14016db3db" +dependencies = [ + "core_maths", + "icu_collections", + "icu_locale_fallback", + "icu_provider", + "icu_segmenter_data", + "potential_utf", + "serde", + "smallvec", + "utf8_iter", + "zerovec", +] + +[[package]] +name = "icu_segmenter_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae293c039020f9ec10710af98d29ce6aa2051486638b49c9a6409f3b4a9e98ad" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "gif", + "image-webp", + "moxcms", + "num-traits", + "png", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imagesize" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", + "rayon", + "serde", + "serde_core", +] + +[[package]] +name = "infer" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "js-sys" +version = "0.3.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "kamadak-exif" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1130d80c7374efad55a117d715a3af9368f0fa7a2c54573afc15a188cd984837" +dependencies = [ + "mutate_once", +] + +[[package]] +name = "krilla" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27da593198b20eeba65caeb73c2bbeec3e53ab08fa549898312ce81c4fce5e33" +dependencies = [ + "base64", + "bumpalo", + "comemo 0.5.1", + "flate2", + "float-cmp", + "gif", + "hayro-write", + "image-webp", + "imagesize", + "indexmap", + "pdf-writer", + "png", + "rayon", + "rustc-hash", + "rustybuzz", + "siphasher", + "skrifa", + "smallvec", + "subsetter", + "tiny-skia-path", + "xmp-writer", + "yoke", + "zune-jpeg", +] + +[[package]] +name = "krilla-svg" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1237d7c37b16ca9fbc2e72dde13a10d321f9a44aceee35c062bc0a43bfc7ce16" +dependencies = [ + "flate2", + "fontdb", + "krilla", + "resvg", + "skrifa", + "smallvec", + "tiny-skia", + "usvg", +] + +[[package]] +name = "kurbo" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b60dfc32f652b926df6192e55525b16d186c69d47876c3ead4da5cc9f8450e2" +dependencies = [ + "arrayvec", + "euclid", + "polycool", + "smallvec", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "linebender_resource_handle" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "lipsum" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "636860251af8963cc40f6b4baadee105f02e21b28131d76eba8e40ce84ab8064" +dependencies = [ + "rand", + "rand_chacha", +] + +[[package]] +name = "litemap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" +dependencies = [ + "serde_core", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memmap2" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +dependencies = [ + "libc", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "mutate_once" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d2233c9842d08cfe13f9eac96e207ca6a2ea10b80259ebe8ad0268be27d2af" + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-integer" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "palette" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddeed8580d347d2abf3dcf06a5f0b3dc020258338526b277847cd4248a70fc64" +dependencies = [ + "approx", + "libm", + "palette_derive", + "palette_math", +] + +[[package]] +name = "palette_derive" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88537020289b719d81be994ccf1bbf4990f477e2f69ee52fe3e45f43a02e56be" +dependencies = [ + "by_address", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "palette_math" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e6eb142958d64335fb0e345c5b9ead2ecd6fc438c307e9d7d3c4fd428dbaf12" +dependencies = [ + "libm", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pdf-writer" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e456864a7a304047bff84977dc6fb162bd956475d40ba50b2dcecaada7f753" +dependencies = [ + "bitflags", + "itoa", + "memchr", + "ryu", +] + +[[package]] +name = "peniko" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "839c8299360d2e998bdb106dc0a6cd71dcc5f4df51df1b620361bf50e283cca6" +dependencies = [ + "bytemuck", + "color", + "kurbo", + "linebender_resource_handle", + "smallvec", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pic-scale" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c80d88d5c31215ceec2862abb2504860c715b8e2545a5ab15b62a3d097f30d" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "plist" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da1d65da6dd5d1e44199ac0f58712d241c0f439f80adea8924d832384087f85" +dependencies = [ + "base64", + "indexmap", + "quick-xml 0.41.0", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polycool" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50596ddc09eb5ad5f75cacd40209568e66df71baf86e1499a0e99c4cff12a5a6" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "portable-atomic" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" + +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "serde", +] + +[[package]] +name = "potential_utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" +dependencies = [ + "serde_core", + "writeable", + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd034599e63b970727f70d79e02d62390a4a84f7c6b827c27c46d5ac3fa622" +dependencies = [ + "ar_archive_writer", + "cc", +] + +[[package]] +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quick-xml" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "read-fonts" +version = "0.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4ed38b89c2c77ff968c524145ad65fb010f38af5c7a224b53b81d47ac2daa81" +dependencies = [ + "bytemuck", + "font-types", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "resvg" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be183ad6a216aa96f33e4c8033b0988b8b3ea6fd2359d19af5bac4643fd8e81" +dependencies = [ + "gif", + "image-webp", + "log", + "pico-args", + "rgb", + "svgtypes", + "tiny-skia", + "usvg", + "zune-jpeg", +] + +[[package]] +name = "rgb" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "roman-numerals-rs" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85cd47a33a4510b1424fe796498e174c6a9cf94e606460ef022a19f3e4ff85e" + +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + +[[package]] +name = "roxmltree" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb" +dependencies = [ + "memchr", +] + +[[package]] +name = "rust_decimal" +version = "1.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be2a24f50780bc85f09cc6ac299bdf1424302742d77221106859c9d8b102126a" +dependencies = [ + "arrayvec", + "num-traits", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "rustybuzz" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" +dependencies = [ + "bitflags", + "bytemuck", + "core_maths", + "log", + "smallvec", + "ttf-parser", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "simplecss" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" +dependencies = [ + "log", +] + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "skrifa" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c34617370ae968efb7161bb2beb517d9084659aae19e24b89e3db25b46e4564" +dependencies = [ + "bytemuck", + "read-fonts", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stacker" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707f49d46706bacf8a2b00d51dace3f9de527c13eec3778f570c411f89e69967" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys", +] + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "subsetter" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38803281d1c23166c5ebcb455439a5d2afe711cc909cf88af72448c297756ad6" +dependencies = [ + "kurbo", + "rustc-hash", + "skrifa", + "write-fonts", +] + +[[package]] +name = "svgtypes" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "695b5790b3131dafa99b3bbfd25a216edb3d216dad9ca208d4657bfb8f2abc3d" +dependencies = [ + "kurbo", + "siphasher", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "syntect" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "656b45c05d95a5704399aeef6bd0ddec7b2b3531b7c9e900abbf7c4d2190c925" +dependencies = [ + "bincode", + "fancy-regex", + "flate2", + "fnv", + "once_cell", + "plist", + "regex-syntax", + "serde", + "serde_derive", + "serde_json", + "thiserror", + "walkdir", + "yaml-rust", +] + +[[package]] +name = "thin-vec" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79def32ffcd477db1ff26f76dab9e3a91f0bd42a85ca96577089b24623056f9d" + +[[package]] +name = "thiserror" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-skia" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47ffee5eaaf5527f630fb0e356b90ebdec84d5d18d937c5e440350f88c5a91ea" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "png", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca365c3faccca67d06593c5980fa6c57687de727a03131735bb85f01fdeeb9" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinystr" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +dependencies = [ + "displaydoc", + "serde_core", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +dependencies = [ + "core_maths", +] + +[[package]] +name = "two-face" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e51b6e60e545cfdae5a4639ff423818f52372211a8d9a3e892b4b0761f76b2" +dependencies = [ + "serde", + "serde_derive", + "syntect", +] + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typst" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cb79435d128de5d5443a058a983f6dcc16738760fa55ed703762bc278b1fd3" +dependencies = [ + "arrayvec", + "comemo 0.5.1", + "ecow", + "rustc-hash", + "typst-eval", + "typst-html", + "typst-layout", + "typst-library", + "typst-macros", + "typst-realize", + "typst-syntax", + "typst-timing", + "typst-utils", +] + +[[package]] +name = "typst-assets" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcee505dac6702dd1c5e65aa2e94a6179d19ee09e2e5637d7313db91765dc4e0" +dependencies = [ + "bitflags", +] + +[[package]] +name = "typst-eval" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8823e1822bd181d8bee47b05632d16bf3a0a8ab042e01d815826350d7ae16c3" +dependencies = [ + "comemo 0.5.1", + "ecow", + "indexmap", + "rustc-hash", + "stacker", + "toml", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-segmentation", +] + +[[package]] +name = "typst-html" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f41bcfbe480b640c4447d8bf9bb59020da610f239aa032d53328651a03572c09" +dependencies = [ + "az", + "bumpalo", + "comemo 0.5.1", + "ecow", + "palette", + "rustc-hash", + "time", + "typst-assets", + "typst-library", + "typst-macros", + "typst-svg", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-math-class", +] + +[[package]] +name = "typst-layout" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1916c407baf8f8815e5d50030eed6d5ac6a0702d927b3c156e38db7a618499e2" +dependencies = [ + "az", + "bumpalo", + "codex", + "comemo 0.5.1", + "ecow", + "either", + "hypher", + "icu_properties", + "icu_provider", + "icu_provider_blob", + "icu_segmenter", + "kurbo", + "libm", + "memchr", + "rustc-hash", + "rustybuzz", + "smallvec", + "ttf-parser", + "typst-assets", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-bidi", + "unicode-math-class", + "unicode-script", + "unicode-segmentation", +] + +[[package]] +name = "typst-library" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12becd02464849f1507f3c4ef3f401a4d28d5938cc74b6acc6f1d703458bf393" +dependencies = [ + "arrayvec", + "az", + "bitflags", + "bumpalo", + "ciborium", + "codex", + "comemo 0.5.1", + "csv", + "ecow", + "either", + "flate2", + "fontdb", + "glidesort", + "hayagriva", + "hayro-syntax", + "icu_properties", + "image", + "indexmap", + "kamadak-exif", + "kurbo", + "libm", + "lipsum", + "memchr", + "moxcms", + "palette", + "percent-encoding", + "phf", + "png", + "rayon", + "regex", + "regex-syntax", + "roxmltree 0.21.1", + "rust_decimal", + "rustc-hash", + "rustybuzz", + "serde", + "serde_json", + "serde_yaml", + "siphasher", + "smallvec", + "syntect", + "time", + "toml", + "ttf-parser", + "two-face", + "typed-arena", + "typst-assets", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-math-class", + "unicode-normalization", + "unicode-segmentation", + "unscanny", + "usvg", + "utf8_iter", + "wasmi", + "xmlwriter", +] + +[[package]] +name = "typst-macros" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "033626e6fd43dc09170a9237c55a4dd308005fd751456a0c81b5864f822a97df" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "typst-pdf" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aef841ff3e606542f3057ce5dd0ff264d53a439e00ed4a91ec00ec8568b3b7f" +dependencies = [ + "az", + "bytemuck", + "codex", + "comemo 0.5.1", + "ecow", + "flate2", + "image", + "indexmap", + "infer", + "krilla", + "krilla-svg", + "rustc-hash", + "serde", + "smallvec", + "typst-assets", + "typst-layout", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", +] + +[[package]] +name = "typst-realize" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f2eb73ab25add88cab03b26effabc657977fe850ff81556b28c6b137ff4bf1" +dependencies = [ + "arrayvec", + "bumpalo", + "comemo 0.5.1", + "ecow", + "regex", + "typst-html", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", +] + +[[package]] +name = "typst-svg" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5df6dc785695aae085678bd6657aa04a1d26058a76ed042e738658078bca681e" +dependencies = [ + "base64", + "comemo 0.5.1", + "ecow", + "flate2", + "hayro", + "hayro-svg", + "image", + "indexmap", + "itoa", + "rustc-hash", + "ryu", + "ttf-parser", + "typst-assets", + "typst-layout", + "typst-library", + "typst-macros", + "typst-timing", + "typst-utils", + "xmlwriter", +] + +[[package]] +name = "typst-syntax" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92a20d79df5d10c7fb0b4f7c18e4b2671edfc21e5ed9ad9894e18cccefd1c70f" +dependencies = [ + "ecow", + "rustc-hash", + "serde", + "toml", + "typst-timing", + "typst-utils", + "unicode-ident", + "unicode-math-class", + "unicode-script", + "unicode-segmentation", + "unscanny", +] + +[[package]] +name = "typst-timing" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab6ee5110f671a23164c61caa85dbc476043d503103dedd36f16d93f970f3f59" +dependencies = [ + "parking_lot", + "serde", + "serde_json", +] + +[[package]] +name = "typst-utils" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33ad1675497b45ae9d960a16e95207c35c2c46330d1a6249a9a977670c8c160" +dependencies = [ + "libm", + "once_cell", + "portable-atomic", + "rayon", + "rustc-hash", + "semver", + "siphasher", + "smallvec", + "thin-vec", + "unicode-math-class", +] + +[[package]] +name = "unic-langid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05" +dependencies = [ + "unic-langid-impl", + "unic-langid-macros", +] + +[[package]] +name = "unic-langid-impl" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658" +dependencies = [ + "serde", + "tinystr", +] + +[[package]] +name = "unic-langid-macros" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5957eb82e346d7add14182a3315a7e298f04e1ba4baac36f7f0dbfedba5fc25" +dependencies = [ + "proc-macro-hack", + "tinystr", + "unic-langid-impl", + "unic-langid-macros-impl", +] + +[[package]] +name = "unic-langid-macros-impl" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1249a628de3ad34b821ecb1001355bca3940bcb2f88558f1a8bd82e977f75b5" +dependencies = [ + "proc-macro-hack", + "quote", + "syn 2.0.119", + "unic-langid-impl", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-bidi-mirroring" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe" + +[[package]] +name = "unicode-ccc" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-math-class" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d246cf599d5fae3c8d56e04b20eb519adb89a8af8d0b0fbcded369aa3647d65" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unicode-script" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "unscanny" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9df2af067a7953e9c3831320f35c1cc0600c30d44d9f7a12b01db1cd88d6b47" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "usvg" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d46cf96c5f498d36b7a9693bc6a7075c0bb9303189d61b2249b0dc3d309c07de" +dependencies = [ + "base64", + "data-url", + "flate2", + "fontdb", + "imagesize", + "kurbo", + "log", + "pico-args", + "roxmltree 0.21.1", + "rustybuzz", + "simplecss", + "siphasher", + "strict-num", + "svgtypes", + "tiny-skia-path", + "ttf-parser", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "xmlwriter", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "vello_common" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3361bff7f7d82c0c496b92048db83846691f0e844cc28dee92b1c824291b55ee" +dependencies = [ + "bytemuck", + "fearless_simd", + "guillotiere", + "hashbrown", + "log", + "peniko", + "png", + "smallvec", + "thiserror", +] + +[[package]] +name = "vello_common" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d672facaa2d697285a786cd9d44d614cd2ce54cdc022504bf339f8fff3b750" +dependencies = [ + "bytemuck", + "fearless_simd", + "guillotiere", + "hashbrown", + "log", + "peniko", + "png", + "smallvec", + "thiserror", +] + +[[package]] +name = "vello_cpu" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d8ded630e8316bb94a55881256506d1f3b9947b5f66db8a7d32ca7ba02decd0" +dependencies = [ + "bytemuck", + "glifo", + "hashbrown", + "png", + "vello_common 0.0.8", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.119", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasmi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2300d0f78cba12f14e29e8dd157ea64050c0a688179aefdb2050105805594a0c" +dependencies = [ + "spin", + "wasmi_collections", + "wasmi_core", + "wasmi_ir", + "wasmparser", +] + +[[package]] +name = "wasmi_collections" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a8c42a2a76148d43097b1d7cc2a5bf33d5c23bd4dd69015fc887e311767884" + +[[package]] +name = "wasmi_core" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9013136083d988725953390bf668b64b7a218fabf26f8b913bbc59546b97ee27" +dependencies = [ + "libm", +] + +[[package]] +name = "wasmi_ir" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1fa003f79156f406d62ef0e1464dc03e11ace37170e9fa7524299a75ad8f68" +dependencies = [ + "wasmi_core", +] + +[[package]] +name = "wasmparser" +version = "0.239.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" +dependencies = [ + "bitflags", +] + +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "write-fonts" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb731d4c4d93eacc69a1ad2f270f905788a98e4a3438267bcafbe08d3431c8d8" +dependencies = [ + "font-types", + "indexmap", + "kurbo", + "log", + "read-fonts", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" + +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + +[[package]] +name = "xmp-writer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9440ea3e5aeabb0ac63af70daf835274065238cdd0cec83418f417eae38bacee" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +dependencies = [ + "displaydoc", + "litemap", + "serde_core", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "zerovec" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" +dependencies = [ + "serde", + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "zlib-rs" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b31d188d9d685a4f9c7b46d6e36631b07058d2cfe190267adce54dc230bf12" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zune-core" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b" + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] diff --git a/packages/xl-typst-compiler/rust/Cargo.toml b/packages/xl-typst-compiler/rust/Cargo.toml new file mode 100644 index 0000000000..c9011d428f --- /dev/null +++ b/packages/xl-typst-compiler/rust/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "blocknote-typst-wasm" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +typst = "0.15.1" +typst-pdf = "0.15.1" +comemo = "0.4" +wasm-bindgen = "0.2" +js-sys = "0.3" +serde = { version = "1", features = ["derive"] } +serde-wasm-bindgen = "0.6" +console_error_panic_hook = "0.1.7" +typst-layout = "0.15.1" + +# Size-focused release profile: the wasm is a shipped web asset. +[profile.release] +opt-level = "s" +lto = true +strip = true +codegen-units = 1 + +# wasm-pack's bundled wasm-opt (an old binaryen) fails validating modern +# rustc output; ship the direct rustc artifact. A current binaryen pass is +# a known size optimization to add later (see README). +[package.metadata.wasm-pack.profile.release] +wasm-opt = false diff --git a/packages/xl-typst-compiler/rust/rust-toolchain.toml b/packages/xl-typst-compiler/rust/rust-toolchain.toml new file mode 100644 index 0000000000..128dbd4e77 --- /dev/null +++ b/packages/xl-typst-compiler/rust/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.92.0" +targets = ["wasm32-unknown-unknown"] diff --git a/packages/xl-typst-compiler/rust/src/lib.rs b/packages/xl-typst-compiler/rust/src/lib.rs new file mode 100644 index 0000000000..b8275c7dd6 --- /dev/null +++ b/packages/xl-typst-compiler/rust/src/lib.rs @@ -0,0 +1,353 @@ +//! Minimal wasm binding over the official `typst` crates for BlockNote's PDF +//! export: an in-memory `World` (main source + asset files), fonts supplied as +//! bytes, and native PDF-standards support (`ua-1`) via `typst-pdf`. +//! +//! Deliberately excluded: package registry (BlockNote's generated markup +//! imports no packages), incremental rendering, SVG/vector output, system +//! font access, network access of any kind. + +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; +use typst::diag::{FileError, FileResult, SourceDiagnostic}; +use typst::foundations::{Bytes, Datetime, Duration}; +use typst::syntax::{DiagSpanKind, FileId, RootedPath, Source, VirtualPath, VirtualRoot}; +use typst::text::{Font, FontBook}; +use typst::utils::LazyHash; +use typst::{Library, LibraryExt, World}; +use typst_layout::PagedDocument; +use typst_pdf::{PdfOptions, PdfStandard, PdfStandards}; +use wasm_bindgen::prelude::*; + +/// An immutable in-memory world for a single compilation. +struct BnWorld { + library: LazyHash, + book: LazyHash, + fonts: Vec, + main: Source, + /// Additional `.typ` sources (imports), interned by path. + sources: HashMap, + files: HashMap, +} + +impl World for BnWorld { + fn library(&self) -> &LazyHash { + &self.library + } + + fn book(&self) -> &LazyHash { + &self.book + } + + fn main(&self) -> FileId { + self.main.id() + } + + fn source(&self, id: FileId) -> FileResult { + if id == self.main.id() { + Ok(self.main.clone()) + } else { + self.sources + .get(&id) + .cloned() + .ok_or_else(|| FileError::NotFound(id.vpath().as_rooted_path().into())) + } + } + + fn file(&self, id: FileId) -> FileResult { + self.files + .get(&id) + .cloned() + .ok_or_else(|| FileError::NotFound(id.vpath().as_rooted_path().into())) + } + + fn font(&self, index: usize) -> Option { + self.fonts.get(index).cloned() + } + + fn today(&self, _offset: Option) -> Option { + // Deterministic output: no wall clock in the sandbox. Documents using + // `datetime.today()` get no date rather than a nondeterministic one. + None + } +} + +/// Options for a single PDF compilation, mirroring `typst-pdf`'s knobs that +/// BlockNote needs. camelCase to match the JS caller. +#[derive(Deserialize, Default)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct CompileOptions { + /// A PDF standard to enforce, e.g. "ua-1". Enforcement includes typst's + /// compile-time validation; failures come back as diagnostics. + #[serde(default)] + pdf_standard: Option, + /// Emit the tagged (accessible) structure tree. typst's default is true. + #[serde(default)] + tagged: Option, + /// PDF creation timestamp in seconds since the Unix epoch (UTC). Pass a + /// fixed value for byte-reproducible output; omitted means no timestamp. + #[serde(default)] + creation_timestamp: Option, +} + +/// One diagnostic, serialized to JS. Whether it is an error or a warning +/// is expressed by which list it arrives in (`compileErrors` / +/// `compileWarnings`), not by a field. `message` keeps typst's original +/// text, including the "PDF/UA-1 error:" prefix on validation errors, so +/// callers can distinguish conformance failures from genuine compile +/// errors. +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct JsDiagnostic { + message: String, + hints: Vec, + /// Byte range in the main source, when the span points there. + range: Option<(usize, usize)>, +} + +fn to_js_diags(main: &Source, diags: &[SourceDiagnostic]) -> Vec { + diags + .iter() + .map(|d| JsDiagnostic { + message: d.message.to_string(), + hints: d.hints.iter().map(|h| h.v.to_string()).collect(), + range: diag_range(main, d.span), + }) + .collect() +} + +/// Resolve a diagnostic's span to a byte range in the main source. +fn diag_range(main: &Source, span: typst::syntax::DiagSpan) -> Option<(usize, usize)> { + match span.get() { + DiagSpanKind::Number { id, num, sub_range } if id == main.id() => { + main.range(num, sub_range).map(|r| (r.start, r.end)) + } + DiagSpanKind::Range { id, range } if id == main.id() => { + Some((range.start, range.end)) + } + _ => None, + } +} + +/// The uniform result payload: `pdf` present on success, and both +/// diagnostic lists always present (empty when there is nothing to say). +/// Compile failure is an expected outcome, so it is *returned*, never +/// thrown - `Err` is reserved for caller mistakes (invalid options). +fn compile_result( + main: &Source, + pdf: Option<&[u8]>, + errors: &[SourceDiagnostic], + warnings: &[SourceDiagnostic], +) -> JsValue { + let result = js_sys::Object::new(); + if let Some(pdf) = pdf { + js_sys::Reflect::set( + &result, + &"pdf".into(), + &js_sys::Uint8Array::from(pdf).into(), + ) + .expect("plain object set"); + } + for (key, diags) in [("compileErrors", errors), ("compileWarnings", warnings)] { + js_sys::Reflect::set( + &result, + &key.into(), + &serde_wasm_bindgen::to_value(&to_js_diags(main, diags)) + .expect("diagnostics serialize"), + ) + .expect("plain object set"); + } + result.into() +} + +/// The compiler: owns the loaded fonts (the expensive, reusable part). +/// Each `compile_pdf` call builds a fresh world, so instances are cheap to +/// keep and there is no page-level singleton. +#[wasm_bindgen] +pub struct TypstCompiler { + fonts: Vec, + font_hashes: std::collections::HashSet, + library: LazyHash, +} + +#[wasm_bindgen] +impl TypstCompiler { + #[wasm_bindgen(constructor)] + pub fn new() -> TypstCompiler { + console_error_panic_hook::set_once(); + TypstCompiler { + fonts: Vec::new(), + font_hashes: std::collections::HashSet::new(), + library: LazyHash::new(Library::default()), + } + } + + /// Load every face of a font file (TTF/OTF/TTC). Byte-identical files + /// are deduplicated (repeat loads are no-ops). + /// Returns the number of faces added; 0 means the bytes were not a font + /// (or were already loaded). + pub fn add_font(&mut self, data: &[u8]) -> u32 { + use std::hash::{Hash, Hasher}; + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + data.hash(&mut hasher); + if !self.font_hashes.insert(hasher.finish()) { + return 0; + } + let bytes = Bytes::new(data.to_vec()); + let mut added = 0u32; + // Collections hold multiple faces; probe indices until one fails. + for index in 0..64 { + match Font::new(bytes.clone(), index) { + Some(font) => { + self.fonts.push(font); + added += 1; + } + None => break, + } + } + added + } + + /// The family names of the loaded fonts, in load order (deduplicated) - + /// what the Typst source can reference in `#set text(font: ...)`. + pub fn font_families(&self) -> Vec { + let mut seen = std::collections::HashSet::new(); + self.fonts + .iter() + .map(|f| f.info().family.to_string()) + .filter(|name| seen.insert(name.clone())) + .collect() + } + + /// Compile Typst markup to PDF bytes. + /// + /// `asset_paths[i]` (an absolute virtual path like "/assets/img0.png") + /// names the file whose bytes are `asset_data[i]`. + /// + /// On failure the error is `{ diagnostics: [...] }`; PDF-standard + /// validation failures are diagnostics whose message starts with the + /// validator prefix (e.g. "PDF/UA-1 error:"). + pub fn compile_pdf( + &self, + main_source: &str, + asset_paths: Vec, + asset_data: Vec, + options: JsValue, + ) -> Result { + let options: CompileOptions = if options.is_undefined() || options.is_null() { + CompileOptions::default() + } else { + serde_wasm_bindgen::from_value(options) + .map_err(|e| JsValue::from_str(&format!("invalid options: {e}")))? + }; + + if asset_paths.len() != asset_data.len() { + return Err(JsValue::from_str("asset_paths/asset_data length mismatch")); + } + let mut files = HashMap::new(); + let mut sources = HashMap::new(); + for (path, data) in asset_paths.into_iter().zip(asset_data) { + let id = project_file(&path)?; + if path.ends_with(".typ") { + // Importable source files must be registered as sources, not + // raw bytes, so `#import` finds them. + let text = String::from_utf8(data.to_vec()).map_err(|_| { + JsValue::from_str(&format!("{path}: .typ files must be UTF-8")) + })?; + sources.insert(id, Source::new(id, text)); + } else { + files.insert(id, Bytes::new(data.to_vec())); + } + } + + let world = BnWorld { + library: self.library.clone(), + book: LazyHash::new(FontBook::from_fonts(&self.fonts)), + fonts: self.fonts.clone(), + main: Source::new( + project_file("/main.typ").expect("static path is valid"), + main_source.to_string(), + ), + sources, + files, + }; + + let compiled = typst::compile::(&world); + let document = match compiled.output { + Ok(document) => document, + Err(errors) => { + return Ok(compile_result( + &world.main, + None, + &errors, + &compiled.warnings, + )); + } + }; + + let standards = match options.pdf_standard { + Some(standard) => PdfStandards::new(&[standard]) + .map_err(|e| JsValue::from_str(&format!("invalid PDF standard: {}", e.message())))?, + None => PdfStandards::default(), + }; + let pdf_options = PdfOptions { + standards, + tagged: options.tagged.unwrap_or(true), + timestamp: options + .creation_timestamp + .and_then(unix_seconds_to_datetime) + .map(typst_pdf::Timestamp::new_utc), + ..Default::default() + }; + let pdf = match typst_pdf::pdf(&document, &pdf_options) { + Ok(pdf) => pdf, + Err(errors) => { + return Ok(compile_result( + &world.main, + None, + &errors, + &compiled.warnings, + )); + } + }; + Ok(compile_result( + &world.main, + Some(&pdf), + &[], + &compiled.warnings, + )) + } +} + +/// Civil-from-days (Howard Hinnant's algorithm): Unix seconds -> Datetime. +/// Deterministic and dependency-free; returns `None` outside Datetime's +/// supported range. +fn unix_seconds_to_datetime(seconds: i64) -> Option { + let days = seconds.div_euclid(86_400); + let secs_of_day = seconds.rem_euclid(86_400); + let z = days + 719_468; + let era = z.div_euclid(146_097); + let doe = z.rem_euclid(146_097); + let yoe = (doe - doe / 1460 + doe / 36_524 - doe / 146_096) / 365; + let y = yoe + era * 400; + let doy = doe - (365 * yoe + yoe / 4 - yoe / 100); + let mp = (5 * doy + 2) / 153; + let d = doy - (153 * mp + 2) / 5 + 1; + let m = if mp < 10 { mp + 3 } else { mp - 9 }; + let y = if m <= 2 { y + 1 } else { y }; + Datetime::from_ymd_hms( + i32::try_from(y).ok()?, + u8::try_from(m).ok()?, + u8::try_from(d).ok()?, + u8::try_from(secs_of_day / 3600).ok()?, + u8::try_from((secs_of_day % 3600) / 60).ok()?, + u8::try_from(secs_of_day % 60).ok()?, + ) +} + +/// Interns an absolute virtual path in the project root. +fn project_file(path: &str) -> Result { + let vpath = VirtualPath::new(path) + .map_err(|e| JsValue::from_str(&format!("invalid path {path:?}: {e}")))?; + Ok(FileId::new(RootedPath::new(VirtualRoot::Project, vpath))) +} diff --git a/packages/xl-typst-compiler/scripts/ensure-wasm.mjs b/packages/xl-typst-compiler/scripts/ensure-wasm.mjs new file mode 100644 index 0000000000..232e5f4896 --- /dev/null +++ b/packages/xl-typst-compiler/scripts/ensure-wasm.mjs @@ -0,0 +1,140 @@ +// Ensures pkg/ (the wasm-pack build output) exists and matches the Rust +// sources, building it when it doesn't. Runs as the first step of this +// package's build task, so every consumer - `vp run -r build`, CI, the +// Vercel builds (whose `--filter '...'` graphs include this package) - +// gets a correct wasm without a separate step. +// +// - Fresh (pkg/.build-hash matches the hashed Rust inputs): exits silently. +// - Stale/missing: builds with the wasm-pack devDependency. Needs a Rust +// toolchain; rustup auto-provisions the pinned version + wasm32 target +// from rust/rust-toolchain.toml. +// - No rustup: on Vercel it is bootstrapped automatically (installed under +// node_modules/.cache, which Vercel persists between builds - as are the +// cargo registry and target dirs, so warm builds take seconds). On a dev +// machine it fails with instructions instead of installing things. +// +// `--force` skips the freshness check (the `build:wasm` script). +import { execFileSync } from "node:child_process"; +import { createHash } from "node:crypto"; +import { + existsSync, + mkdirSync, + readdirSync, + readFileSync, + writeFileSync, +} from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const packageDir = dirname(dirname(fileURLToPath(import.meta.url))); +const rustDir = join(packageDir, "rust"); +const pkgDir = join(packageDir, "pkg"); +const hashFile = join(pkgDir, ".build-hash"); + +function listRustInputs() { + const files = [ + join(rustDir, "Cargo.toml"), + join(rustDir, "Cargo.lock"), + join(rustDir, "rust-toolchain.toml"), + ]; + function walk(dir) { + for (const entry of readdirSync(dir, { withFileTypes: true })) { + const path = join(dir, entry.name); + if (entry.isDirectory()) { + walk(path); + } else { + files.push(path); + } + } + } + walk(join(rustDir, "src")); + return files.sort(); +} + +function inputHash() { + const hash = createHash("sha256"); + // The wasm-pack version participates: it drives the generated JS glue. + hash.update( + JSON.parse(readFileSync(join(packageDir, "package.json"), "utf8")) + .devDependencies["wasm-pack"], + ); + for (const file of listRustInputs()) { + hash.update(file); + hash.update(readFileSync(file)); + } + return hash.digest("hex"); +} + +function commandExists(command, env) { + try { + execFileSync(command, ["--version"], { stdio: "ignore", env }); + return true; + } catch { + return false; + } +} + +const force = process.argv.includes("--force"); +const currentHash = inputHash(); +if ( + !force && + existsSync(join(pkgDir, "blocknote_typst_wasm_bg.wasm")) && + existsSync(hashFile) && + readFileSync(hashFile, "utf8") === currentHash +) { + process.exit(0); +} + +const env = { ...process.env }; + +// On Vercel, keep every Rust artifact under node_modules/.cache: it is +// persisted between builds, so only the first build on a fresh cache pays +// the full compile. +if (process.env.VERCEL) { + const cacheDir = join(packageDir, "node_modules", ".cache", "rust"); + mkdirSync(cacheDir, { recursive: true }); + env.CARGO_HOME = join(cacheDir, "cargo"); + env.RUSTUP_HOME = join(cacheDir, "rustup"); + env.CARGO_TARGET_DIR = join(cacheDir, "target"); + env.PATH = `${join(env.CARGO_HOME, "bin")}:${env.PATH}`; + + if (!commandExists("cargo", env)) { + console.log("[ensure-wasm] installing rustup (Vercel build container)…"); + execFileSync( + "sh", + [ + "-c", + "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain none --no-modify-path", + ], + { stdio: "inherit", env }, + ); + } +} else if (!commandExists("rustup", env)) { + console.error( + "[ensure-wasm] pkg/ is missing or stale and no Rust toolchain was " + + "found. Install rustup (https://rustup.rs) - the pinned toolchain " + + "and wasm32 target auto-install from rust/rust-toolchain.toml - " + + "then re-run the build (or `npm run build:wasm` in " + + "packages/xl-typst-compiler).", + ); + process.exit(1); +} + +console.log("[ensure-wasm] building the Typst compiler wasm (rust/ -> pkg/)…"); +execFileSync( + join(packageDir, "node_modules", ".bin", "wasm-pack"), + [ + "build", + "rust", + "--target", + "web", + "--release", + "--out-dir", + "../pkg", + "--out-name", + "blocknote_typst_wasm", + ], + { stdio: "inherit", cwd: packageDir, env }, +); +writeFileSync(hashFile, currentHash); +console.log("[ensure-wasm] done."); diff --git a/packages/xl-typst-compiler/src/index.ts b/packages/xl-typst-compiler/src/index.ts new file mode 100644 index 0000000000..71b33ad69e --- /dev/null +++ b/packages/xl-typst-compiler/src/index.ts @@ -0,0 +1,8 @@ +export { + TypstCompiler, + isPdfStandardViolation, + type CompilePdfOptions, + type CompilePdfResult, + type TypstCompilerOptions, + type TypstDiagnostic, +} from "./typstCompiler.js"; diff --git a/packages/xl-typst-compiler/src/typstCompiler.test.ts b/packages/xl-typst-compiler/src/typstCompiler.test.ts new file mode 100644 index 0000000000..c01fe5a5b9 --- /dev/null +++ b/packages/xl-typst-compiler/src/typstCompiler.test.ts @@ -0,0 +1,262 @@ +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import { beforeAll, describe, expect, it } from "vite-plus/test"; +import { + TypstCompiler, + isPdfStandardViolation, + type CompilePdfResult, +} from "./index.js"; + +const pkgDir = join(__dirname, ".."); +const fontDir = join(pkgDir, "..", "..", "shared", "assets", "fonts"); + +function font(rel: string): Uint8Array { + return new Uint8Array(readFileSync(join(fontDir, rel))); +} + +// Node has no URL-relative wasm loading from the test runner, so the module +// bytes are passed explicitly (the browser path is covered by the tests +// package's e2e suite, which exercises URL loading through a bundler). +const wasmBytes = new Uint8Array( + readFileSync(join(pkgDir, "pkg", "blocknote_typst_wasm_bg.wasm")), +); + +const latin1 = (bytes: Uint8Array) => new TextDecoder("latin1").decode(bytes); +const isPdf = (bytes: Uint8Array) => latin1(bytes.slice(0, 5)) === "%PDF-"; + +// A 1x1 red PNG. +const png = Uint8Array.from( + atob( + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==", + ), + (c) => c.charCodeAt(0), +); + +function expectPdf( + result: CompilePdfResult, +): Extract { + if (result.error) { + throw new Error( + `expected a PDF, got errors: ${result.compileErrors + .map((d) => d.message) + .join(" | ")}`, + ); + } + return result; +} + +let compiler: TypstCompiler; + +beforeAll(async () => { + compiler = await TypstCompiler.create({ + wasm: wasmBytes, + fonts: [ + font("inter/Inter_18pt-Regular.ttf"), + font("inter/Inter_18pt-Bold.ttf"), + font("newcm/NewCMMath-Regular.otf"), + font("newcm/NewCMMath-Book.otf"), + ], + }); +}); + +const preamble = `#set document(title: [Test])\n#set text(font: "Inter 18pt", lang: "en")\n`; +const conforming = `${preamble}= Heading +Body with math #math.equation(alt: "a squared", $a^2$). +#figure(image("/assets/dot.png", width: 10pt, alt: "A red dot"), caption: [A dot]) +`; +const assets = new Map([["/assets/dot.png", png]]); + +describe("compilePdf", () => { + it("compiles markup with fonts, math, and image assets to a PDF", () => { + const { pdf, compileWarnings } = expectPdf( + compiler.compilePdf(conforming, { assets }), + ); + expect(isPdf(pdf)).toBe(true); + expect(compileWarnings).toEqual([]); + // Tagged by default, but no conformance claim without a standard. + expect(latin1(pdf)).toContain("StructTreeRoot"); + expect(latin1(pdf)).not.toContain("pdfuaid"); + }); + + it("can disable tagging", () => { + const { pdf } = expectPdf( + compiler.compilePdf(conforming, { assets, tagged: false }), + ); + expect(latin1(pdf)).not.toContain("StructTreeRoot"); + }); + + it("returns typed diagnostics for invalid markup", () => { + const result = compiler.compilePdf(`${preamble}#broken(`); + expect(result.error).toBe("compile-failed"); + if (result.error) { + expect(result.compileErrors.length).toBeGreaterThan(0); + expect(result.compileErrors.some((d) => isPdfStandardViolation(d))).toBe( + false, + ); + } + }); + + it("fails loudly when a needed font is missing (no embedded fonts)", async () => { + const fontless = await TypstCompiler.create(); + const result = fontless.compilePdf(`$x$`); + expect(result.error).toBe("compile-failed"); + if (result.error) { + expect(result.compileErrors[0].message).toContain( + "no font could be found", + ); + } + }); + + it("surfaces compile warnings alongside the produced PDF", () => { + const { pdf, compileWarnings } = expectPdf( + compiler.compilePdf( + `${preamble}#set text(font: "No Such Family")\nHello`, + ), + ); + expect(isPdf(pdf)).toBe(true); + expect( + compileWarnings.some((w) => w.message.includes("unknown font family")), + ).toBe(true); + }); + + it("carries warnings on the failure branch too", () => { + // A document can accumulate warnings before hitting a hard error; the + // failure result keeps both, so callers don't lose context. (The error + // must occur past parsing - a parse error aborts before the stages + // that produce warnings.) + const result = compiler.compilePdf( + `${preamble}#set text(font: "No Such Family")\nHello\n#image("/nope.png")`, + ); + expect(result.error).toBe("compile-failed"); + if (result.error) { + expect(result.compileErrors.length).toBeGreaterThan(0); + expect( + result.compileWarnings.some((w) => + w.message.includes("unknown font family"), + ), + ).toBe(true); + } + }); + + it("throws (not a typed failure) for invalid caller options", () => { + // An unknown PDF standard is a caller mistake, not an expected + // document-driven outcome - it must not masquerade as a compile + // failure. + expect(() => + compiler.compilePdf(`${preamble}Hello`, { pdfStandard: "bogus" }), + ).toThrow(); + }); + + it("supports importable .typ assets", () => { + const result = expectPdf( + compiler.compilePdf(`${preamble}#import "/lib.typ": shout\n#shout[hi]`, { + assets: new Map([ + [ + "/lib.typ", + new TextEncoder().encode(`#let shout(body) = [#upper(body)!]`), + ], + ]), + }), + ); + expect(isPdf(result.pdf)).toBe(true); + }); + + it("produces byte-identical output for a fixed creationTimestamp", () => { + const opts = { assets, creationTimestamp: 0 }; + const first = expectPdf(compiler.compilePdf(conforming, opts)); + const second = expectPdf(compiler.compilePdf(conforming, opts)); + expect(latin1(first.pdf)).toContain("1970-01-01T00:00:00"); + expect(Buffer.from(first.pdf).equals(Buffer.from(second.pdf))).toBe(true); + }); +}); + +describe("PDF standards (ua-1)", () => { + it("declares validated PDF/UA-1 conformance", () => { + const { pdf } = expectPdf( + compiler.compilePdf(conforming, { assets, pdfStandard: "ua-1" }), + ); + expect(latin1(pdf)).toContain("pdfuaid"); + expect(latin1(pdf)).toContain("StructTreeRoot"); + }); + + it("fails nonconforming documents with recognizable violations", () => { + const nonconforming = `${preamble}== Not level one\nBody.\n`; + const result = compiler.compilePdf(nonconforming, { + pdfStandard: "ua-1", + }); + expect(result.error).toBe("compile-failed"); + if (result.error) { + expect(result.compileErrors.length).toBeGreaterThan(0); + // Every failure is a conformance violation (with a source range), so + // callers can distinguish "doesn't conform" from "broken document" + // and fall back to an unclaimed export. + expect(result.compileErrors.every(isPdfStandardViolation)).toBe(true); + expect(result.compileErrors.some((d) => d.range)).toBe(true); + } + const fallback = expectPdf(compiler.compilePdf(nonconforming, {})); + expect(latin1(fallback.pdf)).not.toContain("pdfuaid"); + expect(latin1(fallback.pdf)).toContain("StructTreeRoot"); + }); + + it("rejects violations for missing alt text", () => { + const noAlt = `${preamble}#figure(image("/assets/dot.png", width: 10pt), caption: [No alt])\n`; + const result = compiler.compilePdf(noAlt, { assets, pdfStandard: "ua-1" }); + expect(result.error).toBe("compile-failed"); + if (result.error) { + expect( + result.compileErrors.some((d) => + d.message.includes("missing alt text"), + ), + ).toBe(true); + } + }); +}); + +describe("fonts", () => { + it("lists loaded font families and deduplicates repeated files", async () => { + const own = await TypstCompiler.create({ wasm: wasmBytes }); + const inter = font("inter/Inter_18pt-Regular.ttf"); + expect(own.addFont(inter)).toBe(1); + expect(own.addFont(font("GeistMono-Regular.ttf"))).toBe(1); + // Byte-identical repeat is a no-op. + expect(own.addFont(font("inter/Inter_18pt-Regular.ttf"))).toBe(0); + expect(own.fontFamilies()).toEqual(["Inter 18pt", "Geist Mono"]); + }); +}); + +describe("the real exporter document", () => { + it("compiles the shared test document snapshot as declared ua-1", async () => { + const full = await TypstCompiler.create({ + wasm: wasmBytes, + fonts: [ + font("inter/Inter_18pt-Regular.ttf"), + font("inter/Inter_18pt-Italic.ttf"), + font("inter/Inter_18pt-Bold.ttf"), + font("inter/Inter_18pt-BoldItalic.ttf"), + font("GeistMono-Regular.ttf"), + font("newcm/NewCMMath-Regular.otf"), + font("newcm/NewCMMath-Book.otf"), + font("noto/Noto-COLRv1.ttf"), + ], + }); + const source = readFileSync( + join( + pkgDir, + "..", + "xl-typst-exporter", + "src", + "__snapshots__", + "testDocument.typ", + ), + "utf8", + ); + const { pdf } = expectPdf( + full.compilePdf(source, { + assets: new Map([["/assets/asset-0", png]]), + pdfStandard: "ua-1", + }), + ); + expect(isPdf(pdf)).toBe(true); + expect(latin1(pdf)).toContain("pdfuaid"); + }); +}); diff --git a/packages/xl-typst-compiler/src/typstCompiler.ts b/packages/xl-typst-compiler/src/typstCompiler.ts new file mode 100644 index 0000000000..243782ef7f --- /dev/null +++ b/packages/xl-typst-compiler/src/typstCompiler.ts @@ -0,0 +1,183 @@ +/** + * A minimal TypeScript API over the Typst compiler (the official `typst` + * crates, compiled to WebAssembly - see `rust/`): Typst markup + assets + + * fonts in, PDF bytes (or typed diagnostics) out. + * + * Runs anywhere WebAssembly runs - browsers, Node, workers. There is no + * page-level singleton: create as many compilers as needed; each owns only + * its font set. The wasm module itself is loaded once per page/process. + */ +import initWasm, { + TypstCompiler as WasmCompiler, +} from "@blocknote/xl-typst-compiler/pkg"; + +/** + * One compiler diagnostic. Whether it is an error or a warning is expressed + * by which result list it arrives in (`compileErrors` / `compileWarnings`), + * so there is no severity field to cross-check. + */ +export type TypstDiagnostic = { + message: string; + hints: string[]; + /** Byte range in the compiled source, when the span points there. */ + range?: [number, number]; +}; + +/** + * Compilation failure is part of the contract (the source is generated from + * user content, and PDF-standard validation is expected to fail for + * nonconforming documents), so it's a value, not an exception. + */ +export type CompilePdfResult = + | { + error?: undefined; + pdf: Uint8Array; + compileWarnings: TypstDiagnostic[]; + } + | { + error: "compile-failed"; + compileErrors: TypstDiagnostic[]; + compileWarnings: TypstDiagnostic[]; + }; + +export type CompilePdfOptions = { + /** + * Files referenced from the markup, keyed by absolute virtual path (e.g. + * `/assets/asset-0`). `.typ` entries become importable sources; everything + * else raw bytes (images etc.). + */ + assets?: ReadonlyMap; + /** + * A PDF standard to enforce, e.g. `"ua-1"` for accessible, tagged + * PDF/UA-1. Typst validates conformance at compile time: a nonconforming + * document fails with diagnostics recognizable via + * {@link isPdfStandardViolation} (e.g. "the first heading must be of + * level 1"), rather than producing a false conformance claim. + */ + pdfStandard?: "ua-1" | "a-2b" | "a-3b" | (string & {}); + /** + * Emit the tagged (accessible) structure tree. + * @default true + */ + tagged?: boolean; + /** + * PDF creation timestamp in seconds since the Unix epoch (UTC). Pass a + * fixed value for byte-reproducible output; omitted means no timestamp. + */ + creationTimestamp?: number; +}; + +/** + * Whether a diagnostic is a PDF-standard conformance violation - an + * expected outcome for nonconforming documents - rather than a genuine + * compile error. Typst prefixes these with the validator name(s), e.g. + * `PDF/UA-1 error: missing alt text`. + */ +export function isPdfStandardViolation(diagnostic: TypstDiagnostic): boolean { + return /^PDF\/[A-Za-z0-9.-]+(?:, ?PDF\/[A-Za-z0-9.-]+)* error:/.test( + diagnostic.message, + ); +} + +let wasmReady: Promise | undefined; + +export type TypstCompilerOptions = { + /** + * The wasm module source: a URL (string or `URL`) or the module bytes. + * Omitted, the module loads from this package's own files - bundlers + * (and plain browsers) resolve it next to the wasm-bindgen glue, so + * zero-config use involves no CDN. In runtimes without URL-relative + * loading (or to control caching), pass bytes or an explicit URL. Only + * the first `create()` call's value is used; the module is loaded once. + */ + wasm?: string | URL | Uint8Array; + /** Font files to load (every face of each TTF/OTF/TTC). */ + fonts?: readonly Uint8Array[]; +}; + +/** + * A Typst-to-PDF compiler instance owning a font set. + * + * The wasm module embeds no fonts and never touches the network: text + * renders only with the supplied fonts (a document needing a missing font + * fails to compile - loudly, not with substituted glyphs). + */ +export class TypstCompiler { + private readonly inner: WasmCompiler; + + private constructor(inner: WasmCompiler) { + this.inner = inner; + } + + static async create( + options: TypstCompilerOptions = {}, + ): Promise { + wasmReady ??= initWasm( + options.wasm === undefined ? undefined : { module_or_path: options.wasm }, + ); + await wasmReady; + const compiler = new TypstCompiler(new WasmCompiler()); + for (const font of options.fonts ?? []) { + compiler.addFont(font); + } + return compiler; + } + + /** + * Load a font file; every face of a collection is added, byte-identical + * repeats are no-ops. Returns the number of faces added. + */ + addFont(data: Uint8Array): number { + return this.inner.add_font(data); + } + + /** + * The family names of the loaded fonts (deduplicated, in load order) - + * what Typst's `#set text(font: ...)` can reference. Useful to verify a + * supplied font carries the family name the document asks for. + */ + fontFamilies(): string[] { + return this.inner.font_families(); + } + + compilePdf( + source: string, + options: CompilePdfOptions = {}, + ): CompilePdfResult { + const paths = [...(options.assets?.keys() ?? [])]; + const data = [...(options.assets?.values() ?? [])]; + // Compile failure is an expected outcome, so the wasm layer *returns* + // it - one uniform payload for both outcomes. It only throws for + // caller mistakes (invalid options), which propagate as the genuine + // errors they are. + const { pdf, compileErrors, compileWarnings } = this.inner.compile_pdf( + source, + paths, + data, + { + pdfStandard: options.pdfStandard, + tagged: options.tagged, + creationTimestamp: options.creationTimestamp, + }, + ) as { + pdf?: Uint8Array; + compileErrors: TypstDiagnostic[]; + compileWarnings: TypstDiagnostic[]; + }; + if (pdf !== undefined && compileErrors.length === 0) { + return { pdf, compileWarnings }; + } + if (pdf === undefined && compileErrors.length > 0) { + return { error: "compile-failed", compileErrors, compileWarnings }; + } + // Output and errors must be mutually exclusive; anything else means + // the compiler misreported its outcome - a bug to fail loudly on. + throw new Error( + `TypstCompiler invariant violated: ${ + pdf !== undefined + ? "produced a PDF alongside errors" + : "produced neither a PDF nor errors" + }`, + ); + } +} diff --git a/packages/xl-typst-compiler/tsconfig.json b/packages/xl-typst-compiler/tsconfig.json new file mode 100644 index 0000000000..cee556c3db --- /dev/null +++ b/packages/xl-typst-compiler/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "moduleResolution": "Bundler", + "types": ["node"], + "strict": true, + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "noEmit": false, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "outDir": "dist", + "declaration": true, + "declarationDir": "types", + "composite": true, + "skipLibCheck": true, + "emitDeclarationOnly": true + }, + "include": ["src"] +} diff --git a/packages/xl-typst-compiler/vite.config.ts b/packages/xl-typst-compiler/vite.config.ts new file mode 100644 index 0000000000..d33b1657f1 --- /dev/null +++ b/packages/xl-typst-compiler/vite.config.ts @@ -0,0 +1,60 @@ +import * as path from "path"; +import { webpackStats } from "rollup-plugin-webpack-stats"; +import { defineConfig, type UserConfig } from "vite-plus"; + +// https://vitejs.dev/config/ +export default defineConfig( + () => + ({ + run: { + tasks: { + build: { + // ensure-wasm builds pkg/ from rust/ when missing or stale + // (content-hashed; see scripts/ensure-wasm.mjs) - so every + // consumer of this task, including the Vercel builds, gets the + // wasm without a separate step. Requires a Rust toolchain + // locally (pinned in rust/rust-toolchain.toml). + command: "node scripts/ensure-wasm.mjs && tsc && vp build", + input: [ + { auto: true }, + { pattern: "!**/*.tsbuildinfo", base: "workspace" }, + { pattern: "rust/**", base: "workspace" }, + { pattern: "!rust/target/**", base: "workspace" }, + ], + // `types/**` must be declared too: a cache replay that restores + // only dist/ leaves consumers without declarations. pkg/** is + // produced by ensure-wasm and replayed with the rest. + output: ["dist/**", "types/**", "pkg/**", "!dist/*.tsbuildinfo"], + }, + }, + }, + test: { + environment: "node", + testTimeout: 30000, + }, + plugins: [webpackStats() as any], + build: { + sourcemap: true, + lib: { + entry: { + "blocknote-xl-typst-compiler": path.resolve( + __dirname, + "src/index.ts", + ), + }, + name: "blocknote-xl-typst-compiler", + formats: ["es", "cjs"], + fileName: (format, entryName) => + format === "es" ? `${entryName}.js` : `${entryName}.cjs`, + }, + rollupOptions: { + // The wasm-bindgen glue (self-referenced as .../pkg) ships as + // files next to dist/, not bundled: the glue locates the .wasm + // relative to its own URL, which bundling would break. + external: (source) => + source.startsWith("@blocknote/") || source.startsWith("node:"), + output: { globals: {} }, + }, + }, + }) as UserConfig, +); diff --git a/packages/xl-typst-exporter/package.json b/packages/xl-typst-exporter/package.json index e3d6fd56df..717b3c456f 100644 --- a/packages/xl-typst-exporter/package.json +++ b/packages/xl-typst-exporter/package.json @@ -50,13 +50,13 @@ }, "devDependencies": { "@blocknote/shared": "workspace:^", - "@myriaddreamin/typst-ts-node-compiler": "^0.8.0-rc3", "@types/jsdom": "^21.1.7", "@types/node": "22.13.13", "rimraf": "^5.0.10", "rollup-plugin-webpack-stats": "^0.2.6", "typescript": "^7.0.2", - "vite-plus": "catalog:" + "vite-plus": "catalog:", + "@blocknote/xl-typst-compiler": "workspace:^" }, "gitHead": "37614ab348dcc7faa830a9a88437b37197a2162d" } diff --git a/packages/xl-typst-exporter/src/typstExporter.test.ts b/packages/xl-typst-exporter/src/typstExporter.test.ts index 3f97b79bc0..7f001ab82d 100644 --- a/packages/xl-typst-exporter/src/typstExporter.test.ts +++ b/packages/xl-typst-exporter/src/typstExporter.test.ts @@ -68,7 +68,7 @@ describe("TypstExporter", () => { await expect(typ).toMatchFileSnapshot("__snapshots__/testDocument.typ"); }); - it("applies default document options when none are given", async () => { + it("fabricates no document metadata when none is given", async () => { const exporter = new TypstExporter(schema, typstDefaultSchemaMappings); const typ = await exporter.toTypst( @@ -77,10 +77,12 @@ describe("TypstExporter", () => { ]), ); - expect(typ).toContain('#set document(title: "Document", author: "")'); - expect(typ).toContain( - '#set text(font: "Inter 18pt", size: 12pt, lang: "en")', - ); + // No invented title/author/language - PDF/UA metadata requirements are + // enforced (and reported) by the PDF exporter's conformance gating, not + // papered over with defaults. + expect(typ).not.toContain("#set document("); + expect(typ).not.toContain("lang:"); + expect(typ).toContain('#set text(font: "Inter 18pt", size: 12pt)'); expect(typ).toContain('#show raw: set text(font: "Geist Mono")'); }); diff --git a/packages/xl-typst-exporter/src/typstExporter.ts b/packages/xl-typst-exporter/src/typstExporter.ts index ca38de9c1d..7b7b7c7edc 100644 --- a/packages/xl-typst-exporter/src/typstExporter.ts +++ b/packages/xl-typst-exporter/src/typstExporter.ts @@ -56,18 +56,22 @@ export type TypstExporterOptions = ExporterOptions & { */ export type TypstDocumentOptions = { /** - * Document title — required for PDF/UA (also sets `DisplayDocTitle`). - * @default "Document" + * Document title, written to the PDF metadata (and shown in the viewer's + * title bar). PDF/UA-1 requires one — without it the PDF exporter + * produces a tagged but unclaimed document. No default: absent means no + * title is written. */ title?: string; /** - * Document author, written to PDF metadata. - * @default "" + * Document author, written to PDF metadata. No default. */ author?: string; /** - * BCP-47 language tag, e.g. "en". Sets the document's natural language. - * @default "en" + * BCP-47 language tag of the document's natural language, e.g. "en". + * The PDF exporter requires it when declaring PDF/UA-1 (the default) — + * a wrong language declaration is an accessibility defect no validator + * can catch, so it must be stated rather than defaulted. No default + * here: absent means the markup declares no language. */ lang?: string; /** @@ -439,9 +443,21 @@ export class TypstExporter< families.length === 1 ? strLit(families[0]) : `(${families.map(strLit).join(", ")})`; - const title = doc.title ?? "Document"; - const author = doc.author ?? ""; - const lang = doc.lang ?? "en"; + // No fabricated metadata: title, author, and language appear only when + // supplied. (PDF/UA requires a title and language - the PDF exporter + // gates its conformance claim on Typst's validation resp. the language + // check, rather than inventing values here.) + const documentArgs: string[] = []; + if (doc.title !== undefined) { + documentArgs.push(`title: ${strLit(doc.title)}`); + } + if (doc.author !== undefined) { + documentArgs.push(`author: ${strLit(doc.author)}`); + } + const textArgs = [`font: ${fontArg}`, `size: ${fontSize}pt`]; + if (doc.lang !== undefined) { + textArgs.push(`lang: ${strLit(doc.lang)}`); + } const { header, footer } = doc; // Default margins ≈ the editor's 8% horizontal padding (54px / 670px) // applied to A4. @@ -456,8 +472,10 @@ export class TypstExporter< pageArgs.push(`footer: [${footer}]`); } return [ - `#set document(title: ${strLit(title)}, author: ${strLit(author)})`, - `#set text(font: ${fontArg}, size: ${fontSize}pt, lang: ${strLit(lang)})`, + ...(documentArgs.length + ? [`#set document(${documentArgs.join(", ")})`] + : []), + `#set text(${textArgs.join(", ")})`, `#set page(${pageArgs.join(", ")})`, // Line height ≈ the editor's 1.5 (≈18pt at 12pt). Block spacing is applied // as *padding* on each block (see applyBlockProps), not margin — so a diff --git a/playground/package.json b/playground/package.json index 90177d990f..eb8b7400ed 100644 --- a/playground/package.json +++ b/playground/package.json @@ -63,8 +63,8 @@ "react-router-dom": "^6.30.1", "y-partykit": "^0.0.25", "@blocknote/xl-typst-exporter": "workspace:^", - "@myriaddreamin/typst-ts-web-compiler": "^0.8.0-rc3", - "tex2typst": "^0.6.2" + "tex2typst": "^0.6.2", + "@blocknote/xl-typst-compiler": "workspace:^" }, "devDependencies": { "@tailwindcss/vite": "^4.1.14", diff --git a/playground/src/examples.gen.tsx b/playground/src/examples.gen.tsx index cc73e95877..0c00672583 100644 --- a/playground/src/examples.gen.tsx +++ b/playground/src/examples.gen.tsx @@ -1283,8 +1283,7 @@ export const examples = { "@blocknote/xl-multi-column": "latest", "@blocknote/math-block": "latest", "@blocknote/diagram-block": "latest", - "@myriaddreamin/typst.ts": "^0.8.0-rc3", - "@myriaddreamin/typst-ts-web-compiler": "^0.8.0-rc3", + "@blocknote/xl-typst-compiler": "latest", } as any, pro: true, }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 038f24d9b8..d4bb3206da 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -126,6 +126,9 @@ importers: '@blocknote/xl-pdf-exporter': specifier: workspace:* version: link:../packages/xl-pdf-exporter + '@blocknote/xl-typst-compiler': + specifier: workspace:* + version: link:../packages/xl-typst-compiler '@blocknote/xl-typst-exporter': specifier: workspace:* version: link:../packages/xl-typst-exporter @@ -165,12 +168,6 @@ importers: '@mui/material': specifier: ^5.16.1 version: 5.18.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@myriaddreamin/typst-ts-web-compiler': - specifier: ^0.8.0-rc3 - version: 0.8.0-rc3 - '@myriaddreamin/typst.ts': - specifier: ^0.8.0-rc3 - version: 0.8.0-rc3(@myriaddreamin/typst-ts-web-compiler@0.8.0-rc3) '@orama/orama': specifier: ^3.1.18 version: 3.1.18 @@ -3144,18 +3141,15 @@ importers: '@blocknote/xl-pdf-exporter': specifier: latest version: link:../../../packages/xl-pdf-exporter + '@blocknote/xl-typst-compiler': + specifier: latest + version: link:../../../packages/xl-typst-compiler '@mantine/core': specifier: ^9.0.2 version: 9.1.1(@mantine/hooks@9.1.1(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@mantine/hooks': specifier: ^9.0.2 version: 9.1.1(react@19.2.5) - '@myriaddreamin/typst-ts-web-compiler': - specifier: ^0.8.0-rc3 - version: 0.8.0-rc3 - '@myriaddreamin/typst.ts': - specifier: ^0.8.0-rc3 - version: 0.8.0-rc3(@myriaddreamin/typst-ts-web-compiler@0.8.0-rc3) react: specifier: ^19.2.3 version: 19.2.5 @@ -5430,12 +5424,12 @@ importers: '@blocknote/xl-pdf-exporter': specifier: workspace:^ version: link:../xl-pdf-exporter + '@blocknote/xl-typst-compiler': + specifier: workspace:^ + version: link:../xl-typst-compiler '@blocknote/xl-typst-exporter': specifier: workspace:^ version: link:../xl-typst-exporter - '@myriaddreamin/typst-ts-node-compiler': - specifier: ^0.8.0-rc3 - version: 0.8.0-rc3 '@react-email/components': specifier: ^1.0.12 version: 1.0.12(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -5564,12 +5558,12 @@ importers: '@blocknote/xl-pdf-exporter': specifier: workspace:^ version: link:../xl-pdf-exporter + '@blocknote/xl-typst-compiler': + specifier: workspace:^ + version: link:../xl-typst-compiler '@blocknote/xl-typst-exporter': specifier: workspace:^ version: link:../xl-typst-exporter - '@myriaddreamin/typst-ts-node-compiler': - specifier: ^0.8.0-rc3 - version: 0.8.0-rc3 '@react-email/components': specifier: ^1.0.12 version: 1.0.12(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -6240,25 +6234,19 @@ importers: '@blocknote/xl-multi-column': specifier: workspace:^ version: link:../xl-multi-column + '@blocknote/xl-typst-compiler': + specifier: workspace:^ + version: link:../xl-typst-compiler '@blocknote/xl-typst-exporter': specifier: workspace:^ version: link:../xl-typst-exporter - '@cantoo/pdf-lib': - specifier: ^2.9.1 - version: 2.9.1(html-entities@2.6.0) - '@myriaddreamin/typst-ts-web-compiler': - specifier: ^0.8.0-rc3 - version: 0.8.0-rc3 - '@myriaddreamin/typst.ts': - specifier: ^0.8.0-rc3 - version: 0.8.0-rc3(@myriaddreamin/typst-ts-web-compiler@0.8.0-rc3) devDependencies: '@blocknote/shared': specifier: workspace:^ version: link:../../shared - '@myriaddreamin/typst-ts-node-compiler': - specifier: ^0.8.0-rc3 - version: 0.8.0-rc3 + '@cantoo/pdf-lib': + specifier: ^2.9.1 + version: 2.9.1(html-entities@2.6.0) '@react-pdf/renderer': specifier: ^4.5.1 version: 4.5.1(react@19.2.5) @@ -6296,6 +6284,27 @@ importers: specifier: 'catalog:' version: 0.2.9(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/browser-playwright@4.1.10)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@25.6.0)(typescript@7.0.2))(terser@5.46.2)(tsx@4.21.0)(typescript@7.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) + packages/xl-typst-compiler: + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + rimraf: + specifier: ^5.0.10 + version: 5.0.10 + rollup-plugin-webpack-stats: + specifier: ^0.2.6 + version: 0.2.6(rollup@4.60.1) + typescript: + specifier: ^7.0.2 + version: 7.0.2 + vite-plus: + specifier: 'catalog:' + version: 0.2.9(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(@vitest/browser-playwright@4.1.10)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@25.6.0)(typescript@7.0.2))(terser@5.46.2)(tsx@4.21.0)(typescript@7.0.2)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) + wasm-pack: + specifier: ^0.15.0 + version: 0.15.0 + packages/xl-typst-exporter: dependencies: '@blocknote/core': @@ -6308,9 +6317,9 @@ importers: '@blocknote/shared': specifier: workspace:^ version: link:../../shared - '@myriaddreamin/typst-ts-node-compiler': - specifier: ^0.8.0-rc3 - version: 0.8.0-rc3 + '@blocknote/xl-typst-compiler': + specifier: workspace:^ + version: link:../xl-typst-compiler '@types/jsdom': specifier: ^21.1.7 version: 21.1.7 @@ -6386,6 +6395,9 @@ importers: '@blocknote/xl-pdf-exporter': specifier: workspace:^ version: link:../packages/xl-pdf-exporter + '@blocknote/xl-typst-compiler': + specifier: workspace:^ + version: link:../packages/xl-typst-compiler '@blocknote/xl-typst-exporter': specifier: workspace:^ version: link:../packages/xl-typst-exporter @@ -6422,9 +6434,6 @@ importers: '@mui/material': specifier: ^5.18.0 version: 5.18.0(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@myriaddreamin/typst-ts-web-compiler': - specifier: ^0.8.0-rc3 - version: 0.8.0-rc3 '@react-pdf/math': specifier: ^2.0.1 version: 2.0.1(@react-pdf/renderer@4.5.1(react@19.2.5))(react@19.2.5) @@ -6538,9 +6547,9 @@ importers: specifier: ^0.2.1 version: 0.2.2 devDependencies: - '@myriaddreamin/typst-ts-node-compiler': - specifier: ^0.8.0-rc3 - version: 0.8.0-rc3 + '@blocknote/xl-typst-compiler': + specifier: workspace:^ + version: link:../packages/xl-typst-compiler '@types/node': specifier: ^25.6.0 version: 25.6.0 @@ -6559,6 +6568,9 @@ importers: tests: dependencies: + '@blocknote/xl-typst-compiler': + specifier: workspace:^ + version: link:../packages/xl-typst-compiler get-port-please: specifier: 3.2.0 version: 3.2.0 @@ -6596,9 +6608,6 @@ importers: '@blocknote/xl-typst-exporter': specifier: workspace:^ version: link:../packages/xl-typst-exporter - '@myriaddreamin/typst-ts-web-compiler': - specifier: ^0.8.0-rc3 - version: 0.8.0-rc3 '@playwright/test': specifier: 1.60.0 version: 1.60.0 @@ -7874,6 +7883,10 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -8088,94 +8101,6 @@ packages: '@types/react': optional: true - '@myriaddreamin/typst-ts-node-compiler-android-arm-eabi@0.8.0-rc3': - resolution: {integrity: sha512-HNqXX1Pyt4BI7WetnrcCX+Yfz+K0L9I/Eklhko22+XSVz+OchPD4To8E2dOkIV1H3lC302OrnAoNcXWZpQc9Pw==} - engines: {node: '>= 10'} - cpu: [arm] - os: [android] - - '@myriaddreamin/typst-ts-node-compiler-android-arm64@0.8.0-rc3': - resolution: {integrity: sha512-PS1jRRGWxZ6Fuv8BgppgENdpQX1AfZaBwQq+81onkE53CoDpMTuD41UFjqdKrOos/BnCjrie/jjBWRVCt4NNNg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] - - '@myriaddreamin/typst-ts-node-compiler-darwin-arm64@0.8.0-rc3': - resolution: {integrity: sha512-PmJ11x/pYvg2pF8y3wVV92Tk3fjiGdxWk2sXuUXcwsebH4wr3UDb2bsPyVUE6deNJ6SrUafglKm1nnXf4QMe8w==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@myriaddreamin/typst-ts-node-compiler-darwin-x64@0.8.0-rc3': - resolution: {integrity: sha512-DoYzkayAnad/x5I5eXW8YTkZVTpthzMKn1HtbwSFP87QCEecFFQFgSKGYpSfWPedNAc8ZMnTzk1XsuuE7s6SUA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@myriaddreamin/typst-ts-node-compiler-linux-arm-gnueabihf@0.8.0-rc3': - resolution: {integrity: sha512-6mNiQ5S+pTAJA6xiHtMMYjJWBa+YnpnawK2To3Y9UpzNkhgIipi1Nd0m+E6lQsqFFwjlYR/0EPlgcpQQOzP+Fg==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - - '@myriaddreamin/typst-ts-node-compiler-linux-arm64-gnu@0.8.0-rc3': - resolution: {integrity: sha512-+c8a+W+mcLH6SGFh99HKiiNUEIQB7pZ3CyyFsl94IIuq+MqOAI9uEYPzauKsIsbDc9ZsWC9rie2wSYQHLvmNSg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@myriaddreamin/typst-ts-node-compiler-linux-arm64-musl@0.8.0-rc3': - resolution: {integrity: sha512-bEYNf4eiyJqOo1AO/WRacRoXiKvJ60KHb3zItETR50GwV9bck+rhSwzLfWO9VsckKMPdWeovSVLcHkl9IHvMJA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@myriaddreamin/typst-ts-node-compiler-linux-x64-gnu@0.8.0-rc3': - resolution: {integrity: sha512-bqqb2NCCytrrI4GD6LST7FIM3jsyBPRqZ9LtPFi7IGLEHPokWN1PkuZtbwJ4mxb3/eD7ovd5G6Qyv2WDqesW2Q==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@myriaddreamin/typst-ts-node-compiler-linux-x64-musl@0.8.0-rc3': - resolution: {integrity: sha512-uqjicMMq+ePQxsmjwQyGXYv7WK6DvGMfCSKzuv1jHLVFxD8BQFJ5UXWgMaOopCdRkFL1SdUzzipGaeo/8GQkpw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@myriaddreamin/typst-ts-node-compiler-win32-arm64-msvc@0.8.0-rc3': - resolution: {integrity: sha512-O2pAiIAKMMV+lRGSE1a+EqCJUWc+Gfi4zyo9OXTXeCnpzICp4P4vIUrjU6R784gJjuG+p4tQP+n3PRw81mkbIA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@myriaddreamin/typst-ts-node-compiler-win32-x64-msvc@0.8.0-rc3': - resolution: {integrity: sha512-G/uP+tlOZLx0OXXO4CEqo2D/ewHc8uBqmGD5p6f+LX3SBbRSqB6CosDS7PCfh2tehfdC7HNXyLtey9s2g4Xg9w==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@myriaddreamin/typst-ts-node-compiler@0.8.0-rc3': - resolution: {integrity: sha512-UV/LynOjsoXvbPigusm7IGusu22cENI5UDGdMFWK6B6E0F74r9S+TnY/TAGN3S6PvJvpgMTo9Y/MvmqDlgzB8w==} - engines: {node: '>= 10'} - - '@myriaddreamin/typst-ts-web-compiler@0.8.0-rc3': - resolution: {integrity: sha512-akc8TlhBzldlU1DtbDvR/6ufzgJmQrZMqfYY2fCFbH7y/+h3YdmnyF+twtVqwv+g6YuFXm/Oc1wwa6cYQX4/aw==} - - '@myriaddreamin/typst.ts@0.8.0-rc3': - resolution: {integrity: sha512-Z5SzwBRNV3a8Zz6BCdUBnAKRQj2khNM90dhwFpGkefIYiFJ5AUj/F02uoyDZmY2TvziDKEsJn0800BeF7J8mAw==} - peerDependencies: - '@myriaddreamin/typst-ts-renderer': ^0.8.0-rc3 - '@myriaddreamin/typst-ts-web-compiler': ^0.8.0-rc3 - peerDependenciesMeta: - '@myriaddreamin/typst-ts-renderer': - optional: true - '@myriaddreamin/typst-ts-web-compiler': - optional: true - '@napi-rs/wasm-runtime@1.1.4': resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} peerDependencies: @@ -12309,6 +12234,10 @@ packages: chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} @@ -13030,6 +12959,7 @@ packages: eslint@9.39.4: resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true peerDependencies: jiti: '*' @@ -13578,9 +13508,6 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} - idb@7.1.1: - resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} - ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -14545,6 +14472,10 @@ packages: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + mj-context-menu@0.6.1: resolution: {integrity: sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==} @@ -15989,6 +15920,10 @@ packages: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} + tar@7.5.22: + resolution: {integrity: sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==} + engines: {node: '>=18'} + terser-webpack-plugin@5.5.0: resolution: {integrity: sha512-UYhptBwhWvfIjKd/UuFo6D8uq9xpGLDK+z8EDsj/zWhrTaH34cKEbrkMKfV5YWqGBvAYA3tlzZbs2R+qYrbQJA==} engines: {node: '>= 10.13.0'} @@ -16452,6 +16387,11 @@ packages: engines: {node: '>=20.0.0'} hasBin: true + wasm-pack@0.15.0: + resolution: {integrity: sha512-DdqtGWc3+iFx+7lL7QU5LBWs7qMnwQSWxF0htSfE15sNa3roVwHjAkTm2JXgueU2GGfSwNqbq2EzyC2b/biKDA==} + engines: {node: '>=16'} + hasBin: true + watchpack@2.5.1: resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} engines: {node: '>=10.13.0'} @@ -16663,6 +16603,10 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + yaml@1.10.3: resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} engines: {node: '>= 6'} @@ -18092,6 +18036,10 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.3 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -18385,61 +18333,6 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - '@myriaddreamin/typst-ts-node-compiler-android-arm-eabi@0.8.0-rc3': - optional: true - - '@myriaddreamin/typst-ts-node-compiler-android-arm64@0.8.0-rc3': - optional: true - - '@myriaddreamin/typst-ts-node-compiler-darwin-arm64@0.8.0-rc3': - optional: true - - '@myriaddreamin/typst-ts-node-compiler-darwin-x64@0.8.0-rc3': - optional: true - - '@myriaddreamin/typst-ts-node-compiler-linux-arm-gnueabihf@0.8.0-rc3': - optional: true - - '@myriaddreamin/typst-ts-node-compiler-linux-arm64-gnu@0.8.0-rc3': - optional: true - - '@myriaddreamin/typst-ts-node-compiler-linux-arm64-musl@0.8.0-rc3': - optional: true - - '@myriaddreamin/typst-ts-node-compiler-linux-x64-gnu@0.8.0-rc3': - optional: true - - '@myriaddreamin/typst-ts-node-compiler-linux-x64-musl@0.8.0-rc3': - optional: true - - '@myriaddreamin/typst-ts-node-compiler-win32-arm64-msvc@0.8.0-rc3': - optional: true - - '@myriaddreamin/typst-ts-node-compiler-win32-x64-msvc@0.8.0-rc3': - optional: true - - '@myriaddreamin/typst-ts-node-compiler@0.8.0-rc3': - optionalDependencies: - '@myriaddreamin/typst-ts-node-compiler-android-arm-eabi': 0.8.0-rc3 - '@myriaddreamin/typst-ts-node-compiler-android-arm64': 0.8.0-rc3 - '@myriaddreamin/typst-ts-node-compiler-darwin-arm64': 0.8.0-rc3 - '@myriaddreamin/typst-ts-node-compiler-darwin-x64': 0.8.0-rc3 - '@myriaddreamin/typst-ts-node-compiler-linux-arm-gnueabihf': 0.8.0-rc3 - '@myriaddreamin/typst-ts-node-compiler-linux-arm64-gnu': 0.8.0-rc3 - '@myriaddreamin/typst-ts-node-compiler-linux-arm64-musl': 0.8.0-rc3 - '@myriaddreamin/typst-ts-node-compiler-linux-x64-gnu': 0.8.0-rc3 - '@myriaddreamin/typst-ts-node-compiler-linux-x64-musl': 0.8.0-rc3 - '@myriaddreamin/typst-ts-node-compiler-win32-arm64-msvc': 0.8.0-rc3 - '@myriaddreamin/typst-ts-node-compiler-win32-x64-msvc': 0.8.0-rc3 - - '@myriaddreamin/typst-ts-web-compiler@0.8.0-rc3': {} - - '@myriaddreamin/typst.ts@0.8.0-rc3(@myriaddreamin/typst-ts-web-compiler@0.8.0-rc3)': - dependencies: - idb: 7.1.1 - optionalDependencies: - '@myriaddreamin/typst-ts-web-compiler': 0.8.0-rc3 - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': dependencies: '@emnapi/core': 1.9.2 @@ -22559,6 +22452,8 @@ snapshots: chownr@1.1.4: {} + chownr@3.0.0: {} + chrome-trace-event@1.0.4: {} citty@0.1.6: @@ -24007,8 +23902,6 @@ snapshots: dependencies: safer-buffer: 2.1.2 - idb@7.1.1: {} - ieee754@1.2.1: {} ignore@5.3.2: {} @@ -25152,6 +25045,10 @@ snapshots: minipass@7.1.3: {} + minizlib@3.1.0: + dependencies: + minipass: 7.1.3 + mj-context-menu@0.6.1: {} mkdirp-classic@0.5.3: {} @@ -26878,6 +26775,14 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + tar@7.5.22: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.3 + minizlib: 3.1.0 + yallist: 5.0.0 + terser-webpack-plugin@5.5.0(esbuild@0.27.5)(webpack@5.105.4(esbuild@0.27.5)): dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -27412,6 +27317,10 @@ snapshots: transitivePeerDependencies: - debug + wasm-pack@0.15.0: + dependencies: + tar: 7.5.22 + watchpack@2.5.1: dependencies: glob-to-regexp: 0.4.1 @@ -27641,6 +27550,8 @@ snapshots: yallist@3.1.1: {} + yallist@5.0.0: {} + yaml@1.10.3: {} yaml@2.9.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index ea1d7dca67..b88fc33bb0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -67,6 +67,8 @@ allowBuilds: sharp: false workerd: false leveldown: false + # wasm-pack's binary shim self-installs on first run; no install script. + wasm-pack: false patchedDependencies: { "@y/prosemirror@2.0.0-6": patches/@y__prosemirror@2.0.0-6.patch, diff --git a/shared/package.json b/shared/package.json index d437720690..e85a8d23ca 100644 --- a/shared/package.json +++ b/shared/package.json @@ -20,13 +20,13 @@ "typescript": "^7.0.2", "vite-plus": "catalog:", "xml-formatter": "^3.6.7", - "@myriaddreamin/typst-ts-node-compiler": "^0.8.0-rc3" + "@blocknote/xl-typst-compiler": "workspace:^" }, "peerDependencies": { "@zip.js/zip.js": "^2.8.8", "image-meta": "^0.2.1", "xml-formatter": "^3.6.7", - "@myriaddreamin/typst-ts-node-compiler": "^0.8.0-rc3" + "@blocknote/xl-typst-compiler": "workspace:^" }, "peerDependenciesMeta": { "@zip.js/zip.js": { @@ -38,7 +38,7 @@ "xml-formatter": { "optional": true }, - "@myriaddreamin/typst-ts-node-compiler": { + "@blocknote/xl-typst-compiler": { "optional": true } } diff --git a/shared/util/binaryFileSnapshotUtil.ts b/shared/util/binaryFileSnapshotUtil.ts deleted file mode 100644 index 2e252a50d4..0000000000 --- a/shared/util/binaryFileSnapshotUtil.ts +++ /dev/null @@ -1,94 +0,0 @@ -import fs from "fs"; -import path from "path"; -const NAME_WORKER_STATE = "__vitest_worker__"; - -// from https://github.com/vitest-dev/vitest/blob/main/packages/vitest/src/runtime/utils.ts#L8 -export function getWorkerState(): any { - // @ts-expect-error untyped global - const workerState = globalThis[NAME_WORKER_STATE]; - if (!workerState) { - const errorMsg = - "Vitest failed to access its internal state." + - "\n\nOne of the following is possible:" + - '\n- "vitest" is imported directly without running "vitest" command' + - '\n- "vitest" is imported inside "globalSetup" (to fix this, use "setupFiles" instead, because "globalSetup" runs in a different context)' + - "\n- Otherwise, it might be a Vitest bug. Please report it to https://github.com/vitest-dev/vitest/issues\n"; - throw new Error(errorMsg); - } - return workerState; -} - -function getSnapshotOptions() { - const option: "new" | "all" | "none" = - getWorkerState().ctx.config.snapshotOptions.updateSnapshot; - return option; -} - -// async function createMD5FromBuffer(buffer: Buffer) { -// const hash = crypto.createHash("md5"); -// hash.update(buffer); -// return hash.digest("hex"); -// } - -// async function createMD5FromFile(filePath: string) { -// const hash = crypto.createHash("md5"); - -// if (!fs.existsSync(filePath)) { -// return undefined; -// } - -// await pipeline(fs.createReadStream(filePath), async function (source) { -// for await (const chunk of source) { -// hash.update(chunk); -// } -// }); - -// return hash.digest("hex"); -// } - -export async function toMatchBinaryFileSnapshot( - buffer: Buffer, - filepath: string, - options: { - /** - * On a mismatch that fails the test, also write the received bytes next - * to the baseline (as `.actual.`) so they can be inspected / - * diffed - useful for image snapshots. - */ - writeActualOnMismatch?: boolean; - } = {}, -) { - const fileBuffer = fs.existsSync(filepath) - ? fs.readFileSync(filepath) - : undefined; - - const same = fileBuffer && buffer.equals(fileBuffer); // && bufferMD5 === fileMD5; - - const option = getSnapshotOptions(); - - if (same) { - return; - } - - if (option === "none" || (option === "new" && fileBuffer !== undefined)) { - if (options.writeActualOnMismatch) { - // `name.ext` -> `name.actual.ext`; an extension-less path gets a plain - // `.actual` suffix (the no-match case must never fall through to the - // baseline path itself). - const actualPath = /\.[^./]+$/.test(filepath) - ? filepath.replace(/(\.[^./]+)$/, ".actual$1") - : `${filepath}.actual`; - // A missing baseline may mean its directory is missing too - the - // diagnostic write must not itself throw ENOENT and mask the snapshot - // mismatch below. - fs.mkdirSync(path.dirname(actualPath), { recursive: true }); - fs.writeFileSync(actualPath, buffer); - } - throw new Error(`${filepath} not matching `); - } - - // create dir if not exists - fs.mkdirSync(path.dirname(filepath), { recursive: true }); - - fs.writeFileSync(filepath, buffer); -} diff --git a/shared/util/typstTestUtil.ts b/shared/util/typstTestUtil.ts index a8acdb165b..946be8b481 100644 --- a/shared/util/typstTestUtil.ts +++ b/shared/util/typstTestUtil.ts @@ -1,27 +1,59 @@ -import { resolve } from "node:path"; +import { readFileSync } from "node:fs"; +import { join, resolve } from "node:path"; -type NodeCompilerInstance = - import("@myriaddreamin/typst-ts-node-compiler").NodeCompiler; +type TypstCompilerInstance = + import("@blocknote/xl-typst-compiler").TypstCompiler; -// One shared compiler for the common (default-font) case - creating a -// NodeCompiler scans system fonts, which would dominate test time if every -// compile created its own. Its shadow files are reset per call; a call with -// custom `fontBlobs` gets a throwaway compiler instead, since fonts are -// fixed at creation. -let defaultCompiler: NodeCompilerInstance | undefined; +// The compiler wasm, loaded from the workspace package's build output. Tests +// need `pnpm --filter @blocknote/xl-typst-compiler run build:wasm` to have +// run; failing loudly beats a cryptic resolve error. +function wasmBytes(): Uint8Array { + const path = resolve( + __dirname, + "../../packages/xl-typst-compiler/pkg/blocknote_typst_wasm_bg.wasm", + ); + try { + return new Uint8Array(readFileSync(path)); + } catch { + throw new Error( + `Missing compiler wasm at ${path} - build it first: ` + + "pnpm --filter @blocknote/xl-typst-compiler run build:wasm", + ); + } +} + +// The default font set for tests: the shared assets the exporters reference. +// Unlike the previous node-compiler setup (which scanned *system* fonts), +// this is deterministic across machines - a test render can only use fonts +// that are checked into the repo. +function defaultFontBlobs(): Uint8Array[] { + const fontDir = resolve(__dirname, "../assets/fonts"); + return [ + "inter/Inter_18pt-Regular.ttf", + "inter/Inter_18pt-Italic.ttf", + "inter/Inter_18pt-Bold.ttf", + "inter/Inter_18pt-BoldItalic.ttf", + "GeistMono-Regular.ttf", + "newcm/NewCMMath-Regular.otf", + "newcm/NewCMMath-Book.otf", + "noto/Noto-COLRv1.ttf", + ].map((f) => new Uint8Array(readFileSync(join(fontDir, f)))); +} + +// One shared compiler for the common (default-font) case - font parsing +// would otherwise repeat per compile. A call with custom `fontBlobs` gets +// its own compiler, since an instance's font set only grows. +let defaultCompiler: TypstCompilerInstance | undefined; /** - * Compiles Typst source with the node compiler for tests, mapping an - * exporter's collected `assetFiles` into the compiler first. - * - * The node compiler resolves a project-absolute Typst path (`/assets/..`) - * against the cwd, so each shadow file is keyed by that resolved absolute - * path (the browser pipeline in `compileBrowser.ts` uses the virtual path - * directly). + * Compiles Typst source for tests, mapping an exporter's collected + * `assetFiles` into the compiler first. Fonts default to the shared test + * font set (Inter, Geist Mono, New CM Math, Noto Color Emoji). * - * Pass `pdfStandard: "ua-1"` to run Typst's own PDF/UA-1 validation - it - * errors on accessibility violations (e.g. images or equations without alt - * text), making the compile itself a conformance gate. + * Pass `pdfStandard: "ua-1"` to produce a *declared* PDF/UA-1 - Typst + * validates conformance at compile time and this helper throws on + * violations (e.g. images or equations without alt text), making the + * compile itself a conformance gate. */ export async function compileTypstForTesting( typst: string, @@ -29,32 +61,35 @@ export async function compileTypstForTesting( assets?: ReadonlyMap; pdfStandard?: string; creationTimestamp?: number; - fontBlobs?: Buffer[]; + fontBlobs?: Uint8Array[]; } = {}, -): Promise { - const { NodeCompiler } = - await import("@myriaddreamin/typst-ts-node-compiler"); - let compiler: NodeCompilerInstance; +): Promise { + const { TypstCompiler } = await import("@blocknote/xl-typst-compiler"); + let compiler: TypstCompilerInstance; if (options.fontBlobs?.length) { - compiler = NodeCompiler.create({ - fontArgs: [{ fontBlobs: options.fontBlobs }], + compiler = await TypstCompiler.create({ + wasm: wasmBytes(), + fonts: options.fontBlobs, }); } else { - defaultCompiler ??= NodeCompiler.create(); + defaultCompiler ??= await TypstCompiler.create({ + wasm: wasmBytes(), + fonts: defaultFontBlobs(), + }); compiler = defaultCompiler; - compiler.resetShadow(); } - for (const [path, bytes] of options.assets ?? []) { - compiler.mapShadow( - resolve(process.cwd(), path.replace(/^\/+/, "")), - Buffer.from(bytes), + const result = compiler.compilePdf(typst, { + assets: options.assets, + pdfStandard: options.pdfStandard, + creationTimestamp: options.creationTimestamp, + }); + if (result.error) { + // Tests want failures loud; production code uses the typed result. + throw new Error( + `Typst compile failed:\n${result.compileErrors + .map((d) => d.message) + .join("\n")}`, ); } - return compiler.pdf( - { mainFileContent: typst }, - { - pdfStandard: options.pdfStandard, - creationTimestamp: options.creationTimestamp, - }, - ); + return result.pdf; } diff --git a/tests/docker-run.sh b/tests/docker-run.sh index 4cc2fd708b..8748043482 100755 --- a/tests/docker-run.sh +++ b/tests/docker-run.sh @@ -65,6 +65,19 @@ mounts=() for src in packages/*/src; do mounts+=(-v "$PWD/$src:/work/$src") done +# xl-typst-compiler is consumed through its build outputs (see +# vite.config.browser.ts): the wasm + glue in pkg/ and the built TS wrapper. +# Build them first (build:wasm + build) - they are gitignored, so the image +# cannot contain them. +for out in pkg dist types; do + if [ ! -d "packages/xl-typst-compiler/$out" ]; then + echo "packages/xl-typst-compiler/$out is missing - build it first:" >&2 + echo " pnpm exec vp run --filter @blocknote/xl-typst-compiler build" >&2 + echo "(compiles the Rust wasm too when needed - requires rustup)" >&2 + exit 1 + fi + mounts+=(-v "$PWD/packages/xl-typst-compiler/$out:/work/packages/xl-typst-compiler/$out") +done # The test files and browser config (callers iterate on these too). mounts+=( -v "$PWD/tests/src:/work/tests/src" diff --git a/tests/package.json b/tests/package.json index 31599a2dff..7a9ef2573b 100644 --- a/tests/package.json +++ b/tests/package.json @@ -38,10 +38,10 @@ "rimraf": "^5.0.10", "vite-plus": "catalog:", "vitest-browser-react": "^2.2.0", - "@blocknote/xl-typst-exporter": "workspace:^", - "@myriaddreamin/typst-ts-web-compiler": "^0.8.0-rc3" + "@blocknote/xl-typst-exporter": "workspace:^" }, "dependencies": { - "get-port-please": "3.2.0" + "get-port-please": "3.2.0", + "@blocknote/xl-typst-compiler": "workspace:^" } } diff --git a/tests/scripts/install-pdf-tooling.sh b/tests/scripts/install-pdf-tooling.sh deleted file mode 100755 index 3b4582e60c..0000000000 --- a/tests/scripts/install-pdf-tooling.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env bash -# Installs the tooling the xl-pdf-exporter unit tests gate on: -# - pdftoppm (poppler) rasterizes the per-page visual snapshots; the test -# itself runs it through a digest-pinned container (see pdfua.test.ts) so -# the byte-exact PNG baselines can't drift with the host's poppler - this -# script only pre-pulls that image so the pull cost isn't paid mid-test. -# - veraPDF validates PDF/UA-1 conformance; it comes from its official -# container image behind a PATH shim, so tests invoke plain `verapdf` -# (locally, `brew install verapdf` provides the same tool natively). -# Used by CI (see .github/workflows). -# -# Both images are PINNED by digest: rasterizer upgrades change the rendered -# bytes and validator upgrades can change conformance verdicts, so either -# should land as a deliberate diff, not ambient CI drift. The veraPDF image -# currently publishes only dev-line tags (no stable releases) - the digest -# below is v1.31.156; when veraPDF starts tagging stable releases, repoint -# to one. -set -euo pipefail - -VERAPDF_IMAGE="ghcr.io/verapdf/cli@sha256:65583906f9abb4683242cd605c4317e821e60f3e1ee418d00db87b83f11f54e7" # v1.31.156 - -# The poppler image is defined in pdfua.test.ts (single source of truth, next -# to the baselines it renders); grep it out rather than duplicating the digest. -ROOT="$(cd "$(dirname "$0")/../.." && pwd)" -POPPLER_IMAGE="$(grep -o 'minidocks/poppler@sha256:[0-9a-f]*' \ - "$ROOT/packages/xl-pdf-exporter/src/pdfua/pdfua.test.ts" | head -1)" -test -n "$POPPLER_IMAGE" - -docker pull -q "$VERAPDF_IMAGE" -docker pull -q --platform linux/amd64 "$POPPLER_IMAGE" - -# A PATH shim so tests can invoke plain `verapdf `. The image's -# entrypoint is the verapdf CLI (workdir /data, non-root user), so a trailing -# file argument is copied into a world-readable temp dir and mounted there - -# the container's uid can't read the caller's 0700 temp dirs directly. -sudo tee /usr/local/bin/verapdf >/dev/null < \`; only that shape gets the -# copy-and-mount treatment. Requiring the .pdf suffix (not just an existing -# file) keeps a trailing file-valued option (e.g. \`--policyfile x.sch\`) -# from being mounted as the input, and the \$# guard keeps a zero-argument -# call (e.g. bare \`verapdf\`) from tripping over an empty array subscript. -last="" -if [ "\$#" -gt 0 ]; then - last="\${args[\$# - 1]}" -fi -if [[ "\$last" == *.pdf && -f "\$last" ]]; then - tmp="\$(mktemp -d)" - trap 'rm -rf "\$tmp"' EXIT - chmod 755 "\$tmp" - cp "\$last" "\$tmp/input.pdf" - chmod 644 "\$tmp/input.pdf" - unset "args[\$# - 1]" - # No exec: the EXIT trap must still run to clean up the temp dir; set -e - # exits with docker's status code, so non-conformance still propagates. - docker run --rm -v "\$tmp":/data:ro "\$IMAGE" \${args[@]+"\${args[@]}"} /data/input.pdf - exit 0 -fi -# \${args[@]+...} keeps an empty array from tripping set -u on old bash. -exec docker run --rm "\$IMAGE" \${args[@]+"\${args[@]}"} -SHIM -sudo chmod +x /usr/local/bin/verapdf - -# Smoke-check both tools so a broken install fails here, not inside a test. -verapdf --version -docker run --rm --platform linux/amd64 "$POPPLER_IMAGE" pdftoppm -v diff --git a/tests/src/end-to-end/exporters/exporterImages.test.tsx b/tests/src/end-to-end/exporters/exporterImages.test.tsx index 7534326311..b9dd39a9ca 100644 --- a/tests/src/end-to-end/exporters/exporterImages.test.tsx +++ b/tests/src/end-to-end/exporters/exporterImages.test.tsx @@ -19,20 +19,21 @@ import { reactEmailDefaultSchemaMappings, } from "@blocknote/xl-email-exporter"; import { - compileTypstToTaggedPdf, - declarePdfUA, + compileTypstToPdf, TypstExporter, typstDefaultSchemaMappings, } from "@blocknote/xl-pdf-exporter"; -// Bundled wasm + a body font so the Typst compile below runs fully offline. +// Bundled wasm + fonts so the Typst compile below runs fully offline. // eslint-disable-next-line import/no-unresolved -import compilerWasmUrl from "@myriaddreamin/typst-ts-web-compiler/wasm?url"; +import compilerWasmUrl from "@blocknote/xl-typst-compiler/wasm?url"; // eslint-disable-next-line import/no-unresolved import interRegularUrl from "@shared/assets/fonts/inter/Inter_18pt-Regular.ttf?url"; -// Typst needs a math-capable font for equations; with `preloadDefaultFonts: -// false` (no CDN fonts) it must be bundled like the body font. +// Typst needs a math-capable font for equations and an emoji font for the +// document's emoji (the compiler ships no fonts; missing glyphs would fail +// PDF/UA-1 validation as `.notdef`). import newCMMathBookUrl from "@shared/assets/fonts/newcm/NewCMMath-Book.otf?url"; import newCMMathRegularUrl from "@shared/assets/fonts/newcm/NewCMMath-Regular.otf?url"; +import notoEmojiUrl from "@shared/assets/fonts/noto/Noto-COLRv1.ttf?url"; import { PDFExporter, pdfDefaultSchemaMappings, @@ -160,37 +161,70 @@ describe("email export through a complete exporter in the browser", () => { }); }); +// Builds the exporter, converts the shared document (plus invalid math / +// diagram placeholders), and compiles it natively as PDF/UA-1 through the +// real wasm pipeline. Shared by the assertion test and the visual test. +async function compileTypstUaPdf() { + const typstDocument = [ + ...testDocumentWithSourceBlocks, + invalidDiagramBlock, + invalidMathBlock, + ]; + + const exporter = new TypstExporter( + schema(), + { + ...typstDefaultSchemaMappings, + blockMapping: { + ...typstDefaultSchemaMappings.blockMapping, + mathBlock: typstMathBlockMapping, + diagram: typstDiagramBlockMapping, + }, + inlineContentMapping: { + ...typstDefaultSchemaMappings.inlineContentMapping, + math: typstInlineMathMapping, + }, + } as any, + { resolveFileUrl: testResolveFileUrl }, + ); + + const typ = await exporter.toTypst( + typstDocument as any, + { + title: "BlockNote Export", + lang: "en", + // Fixed timestamp: the visual baselines rely on deterministic bytes. + creationTimestamp: 1_700_000_000, + } as any, + ); + + const fonts = await Promise.all( + [interRegularUrl, newCMMathRegularUrl, newCMMathBookUrl, notoEmojiUrl].map( + async (url) => new Uint8Array(await (await fetch(url)).arrayBuffer()), + ), + ); + const result = await compileTypstToPdf(typ, { + wasm: new URL(compilerWasmUrl, document.baseURI), + fonts, + assets: exporter.assetFiles, + pdfStandard: "ua-1", + creationTimestamp: 1_700_000_000, + }); + if (result.error) { + throw new Error(result.compileErrors.map((d) => d.message).join(" | ")); + } + return { typ, exporter, pdf: result.pdf }; +} + describe("pdf/ua export through the complete typst pipeline in the browser", () => { test( "exports the shared document with math and diagrams", { timeout: 60000 }, async () => { - const typstDocument = [ - ...testDocumentWithSourceBlocks, - invalidDiagramBlock, - invalidMathBlock, - ]; - - const exporter = new TypstExporter( - schema(), - { - ...typstDefaultSchemaMappings, - blockMapping: { - ...typstDefaultSchemaMappings.blockMapping, - mathBlock: typstMathBlockMapping, - diagram: typstDiagramBlockMapping, - }, - inlineContentMapping: { - ...typstDefaultSchemaMappings.inlineContentMapping, - math: typstInlineMathMapping, - }, - } as any, - { resolveFileUrl: testResolveFileUrl }, - ); - - const typ = await exporter.toTypst(typstDocument as any, { - title: "BlockNote Export", - }); + // Compiling through the real wasm pipeline is what only the browser + // suite covers: bundler-served wasm loading (the node unit suites + // drive the same wasm from bytes). + const { typ, exporter, pdf } = await compileTypstUaPdf(); // Native equations with the LaTeX source as alt text, the diagram as a // figure with the Mermaid source as alt text - and the invalid sources @@ -211,23 +245,53 @@ describe("pdf/ua export through the complete typst pipeline in the browser", () ).toBe(true); expect(assetBytes.some((b) => b[0] === 0xff && b[1] === 0xd8)).toBe(true); - // Compile through the real wasm pipeline (the node unit suites - // substitute the node compiler; only this covers what browsers run), - // then declare PDF/UA - the same steps PDFExporter.toBytes composes. - const fonts = await Promise.all( - [interRegularUrl, newCMMathRegularUrl, newCMMathBookUrl].map( - async (url) => new Uint8Array(await (await fetch(url)).arrayBuffer()), - ), + expect(isPdf(pdf)).toBe(true); + expect(pdf.byteLength).toBeGreaterThan(10_000); + // Natively declared and validated by the compile itself. + expect(new TextDecoder("latin1").decode(pdf).includes("pdfuaid")).toBe( + true, ); - const tagged = await compileTypstToTaggedPdf(typ, { - getModule: () => compilerWasmUrl, - fonts, - preloadDefaultFonts: false, - assets: exporter.assetFiles, - }); - const ua = await declarePdfUA(tagged); - expect(isPdf(ua)).toBe(true); - expect(ua.byteLength).toBeGreaterThan(10_000); + }, + ); + + // Chromium only, like the react-pdf visual test below: the PDF is the + // same bytes everywhere (Typst lays it out from the supplied fonts, not + // browser rendering), so per-browser runs would only re-test pdf.js's + // rasterizer at 3x the suite cost. + test.skipIf(browserName !== "chromium")( + "matches the per-page visual snapshot", + { timeout: 60000 }, + async () => { + const { pdf } = await compileTypstUaPdf(); + + // Render the produced PDF's pages with pdf.js and screenshot each + // page as a visual regression of the actual export (the same + // approach as the react-pdf test below). + const pdfjs = await import("pdfjs-dist"); + const workerUrl = ( + await import("pdfjs-dist/build/pdf.worker.min.mjs?url" as string) + ).default; + pdfjs.GlobalWorkerOptions.workerSrc = workerUrl; + + const parsed = await pdfjs.getDocument({ data: pdf.slice() }).promise; + // The test document contains a page break. + expect(parsed.numPages).toBeGreaterThanOrEqual(2); + + const frame = createExportFrame("fit-content"); + for (let n = 1; n <= parsed.numPages; n++) { + const pdfPage = await parsed.getPage(n); + const viewport = pdfPage.getViewport({ scale: 1 }); + const canvas = document.createElement("canvas"); + canvas.width = viewport.width; + canvas.height = viewport.height; + canvas.style.display = "block"; + await pdfPage.render({ + canvasContext: canvas.getContext("2d")!, + viewport, + } as any).promise; + frame.replaceChildren(canvas); + await screenshotFull(frame, `typst-pdf-page-${n}`); + } }, ); }); diff --git a/tests/vite.config.browser.ts b/tests/vite.config.browser.ts index 21fb2a1e1b..b030d2f8fe 100644 --- a/tests/vite.config.browser.ts +++ b/tests/vite.config.browser.ts @@ -40,7 +40,12 @@ const blockNoteSrcAliases = Object.fromEntries( path.join(dir, "src"), ] as const, ) - .filter(([name]) => name?.startsWith("@blocknote/")), + .filter(([name]) => name?.startsWith("@blocknote/")) + // xl-typst-compiler resolves via its package exports instead: its `/pkg` + // and `/wasm` subpaths point at wasm build outputs that live next to + // (not under) src/, which the prefix-replace alias would misdirect. + // docker-run.sh mounts its dist/types/pkg alongside src for this. + .filter(([name]) => name !== "@blocknote/xl-typst-compiler"), ); // The e2e suite is designed to run in a fixed Linux environment (the Playwright From 7b702822757384bd9c4387613f3a1667a74b27a3 Mon Sep 17 00:00:00 2001 From: yousefed Date: Thu, 27 Aug 2026 14:10:38 +0200 Subject: [PATCH 2/9] fix(ci): bootstrap rustup on CI runners; merge toBytes/toBlob into toPDF GitHub's ubuntu-24.04 images no longer ship Rust, so ensure-wasm now bootstraps rustup on CI like it does on Vercel (dev machines still get instructions instead of an install). PDFExporter.toPDF replaces toBytes/toBlob - one method, one result union, with the success branch carrying the PDF as both bytes and a Blob - mirroring toTypst and the other exporters' to naming. --- docs/app/demo/_components/DemoEditor.tsx | 2 +- docs/content/docs/features/export/pdf.mdx | 16 ++-- .../src/App.tsx | 2 +- packages/xl-pdf-exporter/src/index.ts | 1 - .../xl-pdf-exporter/src/pdfExporter.test.ts | 22 ++--- packages/xl-pdf-exporter/src/pdfExporter.ts | 85 +++++++------------ .../xl-typst-compiler/scripts/ensure-wasm.mjs | 54 +++++++----- 7 files changed, 86 insertions(+), 96 deletions(-) diff --git a/docs/app/demo/_components/DemoEditor.tsx b/docs/app/demo/_components/DemoEditor.tsx index 2f8733da4d..3e98122e66 100644 --- a/docs/app/demo/_components/DemoEditor.tsx +++ b/docs/app/demo/_components/DemoEditor.tsx @@ -344,7 +344,7 @@ function DemoEditorInner({ editor.schema, typstDefaultSchemaMappings, ); - const result = await exporter.toBlob( + const result = await exporter.toPDF( editor.document, { wasm: compilerWasmUrl }, { title: "BlockNote demo document", lang: "en" }, diff --git a/docs/content/docs/features/export/pdf.mdx b/docs/content/docs/features/export/pdf.mdx index 77afcc9e74..ee1f1e8628 100644 --- a/docs/content/docs/features/export/pdf.mdx +++ b/docs/content/docs/features/export/pdf.mdx @@ -37,8 +37,8 @@ import { // Create the exporter const exporter = new PDFExporter(editor.schema, typstDefaultSchemaMappings); -// Export the document to a PDF Blob (there's also `toBytes` for a Uint8Array) -const { blob, pdfUA } = await exporter.toBlob( +// Export the document - the result carries the PDF as bytes and as a Blob +const { blob, pdfUA } = await exporter.toPDF( editor.document, {}, { title: "My document", lang: "en" }, @@ -66,12 +66,12 @@ with a live PDF preview below: ### Customizing the PDF -The second parameter of `toBlob` / `toBytes` takes the compile options +The second parameter of `toPDF` takes the compile options (covered in [Fonts & offline use](#fonts--offline-use)); the third takes per-document options: ```typescript -const { blob } = await exporter.toBlob(editor.document, {}, { +const { blob } = await exporter.toPDF(editor.document, {}, { // Document title - required for PDF/UA (also shown in the viewer's title bar) title: "My document", // Document author, written to the PDF metadata @@ -160,14 +160,14 @@ Mono (code), New Computer Modern Math (math blocks) and Noto Color Emoji (emoji, [required for PDF/UA](#pdfua-conformance)) — embedded in the package and loaded lazily on the first export, and the compiler wasm loads from `@blocknote/xl-typst-compiler`'s own package files. Neither touches a CDN. -The compile options (the second parameter of `toBlob` / `toBytes`) control +The compile options (the second parameter of `toPDF`) control all of it; to take explicit control of where the wasm is served from (e.g. self-hosting with caching headers), pass its URL or bytes: ```typescript import compilerWasmUrl from "@blocknote/xl-typst-compiler/wasm?url"; -const { blob } = await exporter.toBlob( +const { blob } = await exporter.toPDF( editor.document, { // The compiler wasm as an explicitly bundled asset (Vite shown here). @@ -184,7 +184,7 @@ keeps the default emoji font (and vice versa), and an explicit empty array disables one entirely: ```typescript -const { blob } = await exporter.toBlob( +const { blob } = await exporter.toPDF( editor.document, { // Font bytes (Uint8Array) to load into the compiler. @@ -224,7 +224,7 @@ tagged-but-unclaimed instead (an honest output rather than a false claim), with the violations reported in the result: ```typescript -const { blob, pdfUA } = await exporter.toBlob(editor.document, {}, { +const { blob, pdfUA } = await exporter.toPDF(editor.document, {}, { title: "My document", lang: "en", }); diff --git a/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx b/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx index 2a835d7c6a..a8507eb83c 100644 --- a/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx +++ b/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx @@ -71,7 +71,7 @@ function usePdfUA( setStatus("loading"); void (async () => { try { - const result = await makeExporter().toBlob( + const result = await makeExporter().toPDF( blocks, { wasm: compilerWasmUrl }, { title: "BlockNote document", lang: "en" }, diff --git a/packages/xl-pdf-exporter/src/index.ts b/packages/xl-pdf-exporter/src/index.ts index cbeaa0b1ec..b0ddefea43 100644 --- a/packages/xl-pdf-exporter/src/index.ts +++ b/packages/xl-pdf-exporter/src/index.ts @@ -5,7 +5,6 @@ export * from "@blocknote/xl-typst-exporter"; export { PDFExporter, - type PdfBlobExportResult, type PdfExportOptions, type PdfExportResult, type PdfUAResult, diff --git a/packages/xl-pdf-exporter/src/pdfExporter.test.ts b/packages/xl-pdf-exporter/src/pdfExporter.test.ts index 3ab3b9e5c4..dfaac80253 100644 --- a/packages/xl-pdf-exporter/src/pdfExporter.test.ts +++ b/packages/xl-pdf-exporter/src/pdfExporter.test.ts @@ -32,7 +32,7 @@ describe("PDFExporter", () => { // the same key would be silently shadowed by the merge, so the export // must fail loudly instead (before ever reaching the compiler). await expect( - exporter.toBytes( + exporter.toPDF( partialBlocksToBlocksForTesting(schema, [ { type: "image", @@ -94,7 +94,7 @@ describe("PDFExporter PDF/UA declaration", () => { it("declares PDF/UA-1 for a conforming document", async () => { const { bytes, pdfUA } = expectExported( - await exporter().toBytes(conforming(), wasmAndFonts(), { + await exporter().toPDF(conforming(), wasmAndFonts(), { title: "Doc", lang: "en", }), @@ -112,7 +112,7 @@ describe("PDFExporter PDF/UA declaration", () => { { type: "heading", props: { level: 2 }, content: "Not level one" }, ]); const { bytes, pdfUA } = expectExported( - await exporter().toBytes(blocks, wasmAndFonts(), { + await exporter().toPDF(blocks, wasmAndFonts(), { title: "Doc", lang: "en", }), @@ -137,11 +137,11 @@ describe("PDFExporter PDF/UA declaration", () => { // decision only the caller can make, so this fails loudly instead of // quietly producing forever-unclaimed exports. await expect( - exporter().toBytes(conforming(), wasmAndFonts(), { title: "Doc" }), + exporter().toPDF(conforming(), wasmAndFonts(), { title: "Doc" }), ).rejects.toThrow("requires the document's language"); // Opting out of the claim makes the language optional again. const { pdfUA } = expectExported( - await exporter().toBytes( + await exporter().toPDF( conforming(), { ...wasmAndFonts(), tryDeclarePdfUA: false }, { title: "Doc" }, @@ -155,7 +155,7 @@ describe("PDFExporter PDF/UA declaration", () => { it("skips validation and claim with tryDeclarePdfUA: false", async () => { const { bytes, pdfUA } = expectExported( - await exporter().toBytes( + await exporter().toPDF( conforming(), { ...wasmAndFonts(), tryDeclarePdfUA: false }, { title: "Doc", lang: "en" }, @@ -178,7 +178,7 @@ describe("PDFExporter PDF/UA declaration", () => { fontFamily: "No Such Family", }); const result = expectExported( - await warned.toBytes(conforming(), wasmAndFonts(), { + await warned.toPDF(conforming(), wasmAndFonts(), { title: "Doc", lang: "en", }), @@ -190,8 +190,8 @@ describe("PDFExporter PDF/UA declaration", () => { ).toBe(true); }); - it("exports a Blob with the same result reporting", async () => { - const result = await exporter().toBlob(conforming(), wasmAndFonts(), { + it("carries the PDF as a Blob alongside the bytes", async () => { + const result = await exporter().toPDF(conforming(), wasmAndFonts(), { title: "Doc", lang: "en", }); @@ -199,7 +199,7 @@ describe("PDFExporter PDF/UA declaration", () => { throw new Error(result.compileErrors.map((d) => d.message).join(" | ")); } expect(result.blob.type).toBe("application/pdf"); - expect(result.blob.size).toBeGreaterThan(1000); + expect(result.blob.size).toBe(result.bytes.byteLength); expect(result.pdfUA).toEqual({ declared: true }); // The minimal test font set omits the preamble's code/emoji families, // which surfaces as unknown-font-family warnings - nothing else. @@ -214,7 +214,7 @@ describe("PDFExporter PDF/UA declaration", () => { // Broken raw markup (here via the caller-supplied header) is a compile // failure - an expected outcome carried in the result, distinct from // conformance violations (it must not degrade to an unclaimed export). - const result = await exporter().toBytes(conforming(), wasmAndFonts(), { + const result = await exporter().toPDF(conforming(), wasmAndFonts(), { title: "Doc", lang: "en", header: "#thisFunctionDoesNotExist()", diff --git a/packages/xl-pdf-exporter/src/pdfExporter.ts b/packages/xl-pdf-exporter/src/pdfExporter.ts index 057067f11d..e83952bfc9 100644 --- a/packages/xl-pdf-exporter/src/pdfExporter.ts +++ b/packages/xl-pdf-exporter/src/pdfExporter.ts @@ -69,7 +69,7 @@ export type PdfUAResult = }; /** - * The outcome of {@link PDFExporter.toBytes}. A document that fails to + * The outcome of {@link PDFExporter.toPDF}. A document that fails to * compile is an expected outcome (the source is generated from user * content: text no supplied font covers, broken caller-supplied * header/footer markup, ...), so it's a value carrying the compiler's @@ -78,20 +78,9 @@ export type PdfUAResult = export type PdfExportResult = | { error?: undefined; + /** The PDF bytes. */ bytes: Uint8Array; - pdfUA: PdfUAResult; - compileWarnings: TypstDiagnostic[]; - } - | { - error: "compile-failed"; - compileErrors: TypstDiagnostic[]; - compileWarnings: TypstDiagnostic[]; - }; - -/** The outcome of {@link PDFExporter.toBlob}. See {@link PdfExportResult}. */ -export type PdfBlobExportResult = - | { - error?: undefined; + /** The same PDF as a Blob (e.g. for downloads / object URLs). */ blob: Blob; pdfUA: PdfUAResult; compileWarnings: TypstDiagnostic[]; @@ -154,14 +143,17 @@ export class PDFExporter< } /** - * Export a document to PDF bytes: BlockNote document -> Typst -> tagged - * PDF (wasm), declared PDF/UA-1 when the document conforms (see - * {@link PdfExportOptions.tryDeclarePdfUA}). The result reports whether the - * claim was made and the conformance violations when it wasn't - or, for - * a document that fails to compile at all, the compiler's diagnostics - * (see {@link PdfExportResult}). + * Export a document to PDF: BlockNote document -> Typst -> tagged PDF + * (wasm), declared PDF/UA-1 when the document conforms (see + * {@link PdfExportOptions.tryDeclarePdfUA}). The counterpart of the + * inherited {@link TypstExporter.toTypst}. + * + * The result carries the PDF as both bytes and a Blob, and reports + * whether the conformance claim was made (and the violations when it + * wasn't) - or, for a document that fails to compile at all, the + * compiler's diagnostics (see {@link PdfExportResult}). */ - public async toBytes( + public async toPDF( blocks: Block[], options: PdfExportOptions = {}, documentOptions?: TypstDocumentOptions, @@ -233,11 +225,11 @@ export class PDFExporter< pdfStandard: "ua-1", }); if (!declared.error) { - return { - bytes: declared.pdf, - pdfUA: { declared: true }, - compileWarnings: declared.compileWarnings, - }; + return exported( + declared.pdf, + { declared: true }, + declared.compileWarnings, + ); } // Only conformance violations fall back to an unclaimed export; any // other failure (broken markup, missing font) would fail the fallback @@ -259,30 +251,6 @@ export class PDFExporter< })), }); } - - /** - * Export a document to a PDF Blob (e.g. for downloads / object URLs), - * with the same result reporting as {@link toBytes}. - */ - public async toBlob( - blocks: Block[], - options: PdfExportOptions = {}, - documentOptions?: TypstDocumentOptions, - ): Promise { - const result = await this.toBytes(blocks, options, documentOptions); - if (result.error) { - return result; - } - // The pipeline always returns a view over a plain (non-shared) buffer; - // the cast narrows `ArrayBufferLike` for `BlobPart`. - return { - blob: new Blob([result.bytes as Uint8Array], { - type: "application/pdf", - }), - pdfUA: result.pdfUA, - compileWarnings: result.compileWarnings, - }; - } } function withPdfUA( @@ -292,9 +260,22 @@ function withPdfUA( if (compiled.error) { return compiled; } + return exported(compiled.pdf, pdfUA, compiled.compileWarnings); +} + +function exported( + bytes: Uint8Array, + pdfUA: PdfUAResult, + compileWarnings: TypstDiagnostic[], +): PdfExportResult { return { - bytes: compiled.pdf, + bytes, + // The pipeline always returns a view over a plain (non-shared) buffer; + // the cast narrows `ArrayBufferLike` for `BlobPart`. + blob: new Blob([bytes as Uint8Array], { + type: "application/pdf", + }), pdfUA, - compileWarnings: compiled.compileWarnings, + compileWarnings, }; } diff --git a/packages/xl-typst-compiler/scripts/ensure-wasm.mjs b/packages/xl-typst-compiler/scripts/ensure-wasm.mjs index 232e5f4896..965cb4450f 100644 --- a/packages/xl-typst-compiler/scripts/ensure-wasm.mjs +++ b/packages/xl-typst-compiler/scripts/ensure-wasm.mjs @@ -8,10 +8,12 @@ // - Stale/missing: builds with the wasm-pack devDependency. Needs a Rust // toolchain; rustup auto-provisions the pinned version + wasm32 target // from rust/rust-toolchain.toml. -// - No rustup: on Vercel it is bootstrapped automatically (installed under -// node_modules/.cache, which Vercel persists between builds - as are the -// cargo registry and target dirs, so warm builds take seconds). On a dev -// machine it fails with instructions instead of installing things. +// - No toolchain: on CI and Vercel, rustup is bootstrapped automatically +// (GitHub's ubuntu-24.04 runner images no longer ship Rust). On Vercel it +// installs under node_modules/.cache, which Vercel persists between +// builds - as are the cargo registry and target dirs, so warm builds take +// seconds. On a dev machine it fails with instructions instead of +// installing things. // // `--force` skips the freshness check (the `build:wasm` script). import { execFileSync } from "node:child_process"; @@ -23,6 +25,7 @@ import { readFileSync, writeFileSync, } from "node:fs"; +import { homedir } from "node:os"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; @@ -89,7 +92,8 @@ const env = { ...process.env }; // On Vercel, keep every Rust artifact under node_modules/.cache: it is // persisted between builds, so only the first build on a fresh cache pays -// the full compile. +// the full compile. Elsewhere rustup's default home is fine (and gets on +// PATH explicitly, since a fresh install can't modify the current shell). if (process.env.VERCEL) { const cacheDir = join(packageDir, "node_modules", ".cache", "rust"); mkdirSync(cacheDir, { recursive: true }); @@ -97,27 +101,33 @@ if (process.env.VERCEL) { env.RUSTUP_HOME = join(cacheDir, "rustup"); env.CARGO_TARGET_DIR = join(cacheDir, "target"); env.PATH = `${join(env.CARGO_HOME, "bin")}:${env.PATH}`; +} else { + env.PATH = `${join(homedir(), ".cargo", "bin")}:${env.PATH}`; +} - if (!commandExists("cargo", env)) { - console.log("[ensure-wasm] installing rustup (Vercel build container)…"); - execFileSync( - "sh", - [ - "-c", - "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain none --no-modify-path", - ], - { stdio: "inherit", env }, +if (!commandExists("cargo", env)) { + // CI covers GitHub Actions (whose ubuntu-24.04 images ship no Rust) and + // most other build services; only interactive dev machines get the + // do-it-yourself error. + if (!process.env.VERCEL && !process.env.CI) { + console.error( + "[ensure-wasm] pkg/ is missing or stale and no Rust toolchain was " + + "found. Install rustup (https://rustup.rs) - the pinned toolchain " + + "and wasm32 target auto-install from rust/rust-toolchain.toml - " + + "then re-run the build (or `npm run build:wasm` in " + + "packages/xl-typst-compiler).", ); + process.exit(1); } -} else if (!commandExists("rustup", env)) { - console.error( - "[ensure-wasm] pkg/ is missing or stale and no Rust toolchain was " + - "found. Install rustup (https://rustup.rs) - the pinned toolchain " + - "and wasm32 target auto-install from rust/rust-toolchain.toml - " + - "then re-run the build (or `npm run build:wasm` in " + - "packages/xl-typst-compiler).", + console.log("[ensure-wasm] installing rustup (CI/Vercel build)…"); + execFileSync( + "sh", + [ + "-c", + "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain none --no-modify-path", + ], + { stdio: "inherit", env }, ); - process.exit(1); } console.log("[ensure-wasm] building the Typst compiler wasm (rust/ -> pkg/)…"); From f26d19b290e43230a8ee3c56c29976c097049609 Mon Sep 17 00:00:00 2001 From: yousefed Date: Thu, 27 Aug 2026 14:15:23 +0200 Subject: [PATCH 3/9] perf(pdf): create the result Blob lazily (constructing a Blob copies the bytes) --- .../xl-pdf-exporter/src/pdfExporter.test.ts | 2 ++ packages/xl-pdf-exporter/src/pdfExporter.ts | 23 +++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/xl-pdf-exporter/src/pdfExporter.test.ts b/packages/xl-pdf-exporter/src/pdfExporter.test.ts index dfaac80253..dabc4be21f 100644 --- a/packages/xl-pdf-exporter/src/pdfExporter.test.ts +++ b/packages/xl-pdf-exporter/src/pdfExporter.test.ts @@ -200,6 +200,8 @@ describe("PDFExporter PDF/UA declaration", () => { } expect(result.blob.type).toBe("application/pdf"); expect(result.blob.size).toBe(result.bytes.byteLength); + // Lazily created, memoized: repeated access yields the same instance. + expect(result.blob).toBe(result.blob); expect(result.pdfUA).toEqual({ declared: true }); // The minimal test font set omits the preamble's code/emoji families, // which surfaces as unknown-font-family warnings - nothing else. diff --git a/packages/xl-pdf-exporter/src/pdfExporter.ts b/packages/xl-pdf-exporter/src/pdfExporter.ts index e83952bfc9..87d49a84ef 100644 --- a/packages/xl-pdf-exporter/src/pdfExporter.ts +++ b/packages/xl-pdf-exporter/src/pdfExporter.ts @@ -80,8 +80,12 @@ export type PdfExportResult = error?: undefined; /** The PDF bytes. */ bytes: Uint8Array; - /** The same PDF as a Blob (e.g. for downloads / object URLs). */ - blob: Blob; + /** + * The same PDF as a Blob (e.g. for downloads / object URLs). + * Created lazily on first access - constructing a Blob copies the + * bytes, so results that only use `bytes` never pay for it. + */ + readonly blob: Blob; pdfUA: PdfUAResult; compileWarnings: TypstDiagnostic[]; } @@ -268,13 +272,18 @@ function exported( pdfUA: PdfUAResult, compileWarnings: TypstDiagnostic[], ): PdfExportResult { + let blob: Blob | undefined; return { bytes, - // The pipeline always returns a view over a plain (non-shared) buffer; - // the cast narrows `ArrayBufferLike` for `BlobPart`. - blob: new Blob([bytes as Uint8Array], { - type: "application/pdf", - }), + // Constructing a Blob copies the bytes, so it's deferred to first + // access (and memoized for a stable identity). + get blob() { + // The pipeline always returns a view over a plain (non-shared) + // buffer; the cast narrows `ArrayBufferLike` for `BlobPart`. + return (blob ??= new Blob([bytes as Uint8Array], { + type: "application/pdf", + })); + }, pdfUA, compileWarnings, }; From c1304bbc17b158abc3614ad810155cfdc1f694ba Mon Sep 17 00:00:00 2001 From: yousefed Date: Thu, 27 Aug 2026 15:06:55 +0200 Subject: [PATCH 4/9] refactor(pdf): exporter-level font/wasm config, family-consistent toPDF options Fonts (bytes, value-or-promise) and the compiler wasm move to the PDFExporter constructor - names and bytes side by side, matching how the other exporters put all configuration in the constructor - while toPDF takes a single per-export bag of document facts (plus tryDeclarePdfUA, assets, creationTimestamp), like every other exporter's export method. Also: exported spreadable default-font loaders (replacing the short-lived extraFonts), lazy result Blob, a font-name/file sync invariant test, the lang requirement failing fast, PdfExporterOptions as the full options shape with Partial at the constructor, and a leaner e2e docker context (rust/target excluded). --- .dockerignore | 4 + docs/app/demo/_components/DemoEditor.tsx | 8 +- docs/content/docs/features/export/pdf.mdx | 93 ++++++---- .../src/App.tsx | 41 ++-- packages/xl-pdf-exporter/src/index.ts | 5 + .../xl-pdf-exporter/src/pdfExporter.test.ts | 175 +++++++++++------- packages/xl-pdf-exporter/src/pdfExporter.ts | 173 ++++++++++++----- .../xl-pdf-exporter/src/pdfua/compileTypst.ts | 10 +- .../xl-pdf-exporter/src/pdfua/defaultFonts.ts | 10 +- .../xl-typst-compiler/src/typstCompiler.ts | 10 +- .../xl-typst-exporter/src/typstExporter.ts | 5 + 11 files changed, 364 insertions(+), 170 deletions(-) diff --git a/.dockerignore b/.dockerignore index 87697e5b29..87239fb0a2 100644 --- a/.dockerignore +++ b/.dockerignore @@ -13,5 +13,9 @@ .git **/test-results **/blob-report +# The Typst compiler's Rust build tree (GBs) and wasm output: never image +# content - docker-run.sh bind-mounts pkg/ at run time. +**/rust/target +packages/xl-typst-compiler/pkg **/playwright-report tests/.vitest-attachments diff --git a/docs/app/demo/_components/DemoEditor.tsx b/docs/app/demo/_components/DemoEditor.tsx index 3e98122e66..b4a0899cad 100644 --- a/docs/app/demo/_components/DemoEditor.tsx +++ b/docs/app/demo/_components/DemoEditor.tsx @@ -343,12 +343,12 @@ function DemoEditorInner({ const exporter = new PDFExporter( editor.schema, typstDefaultSchemaMappings, - ); - const result = await exporter.toPDF( - editor.document, { wasm: compilerWasmUrl }, - { title: "BlockNote demo document", lang: "en" }, ); + const result = await exporter.toPDF(editor.document, { + title: "BlockNote demo document", + lang: "en", + }); if (result.error) { throw new Error( `PDF export failed: ${result.compileErrors diff --git a/docs/content/docs/features/export/pdf.mdx b/docs/content/docs/features/export/pdf.mdx index ee1f1e8628..7680041064 100644 --- a/docs/content/docs/features/export/pdf.mdx +++ b/docs/content/docs/features/export/pdf.mdx @@ -38,11 +38,10 @@ import { const exporter = new PDFExporter(editor.schema, typstDefaultSchemaMappings); // Export the document - the result carries the PDF as bytes and as a Blob -const { blob, pdfUA } = await exporter.toPDF( - editor.document, - {}, - { title: "My document", lang: "en" }, -); +const { blob, pdfUA } = await exporter.toPDF(editor.document, { + title: "My document", + lang: "en", +}); ``` This works out of the box, fully offline: the export matches the editor's @@ -66,12 +65,12 @@ with a live PDF preview below: ### Customizing the PDF -The second parameter of `toPDF` takes the compile options -(covered in [Fonts & offline use](#fonts--offline-use)); the third takes -per-document options: +The second parameter of `toPDF` is a single per-export options bag: the +per-document options below, plus `tryDeclarePdfUA`, extra `assets` for +caller-supplied markup, and a `creationTimestamp`: ```typescript -const { blob } = await exporter.toPDF(editor.document, {}, { +const { blob } = await exporter.toPDF(editor.document, { // Document title - required for PDF/UA (also shown in the viewer's title bar) title: "My document", // Document author, written to the PDF metadata @@ -160,21 +159,17 @@ Mono (code), New Computer Modern Math (math blocks) and Noto Color Emoji (emoji, [required for PDF/UA](#pdfua-conformance)) — embedded in the package and loaded lazily on the first export, and the compiler wasm loads from `@blocknote/xl-typst-compiler`'s own package files. Neither touches a CDN. -The compile options (the second parameter of `toPDF`) control +The exporter's constructor options control all of it; to take explicit control of where the wasm is served from (e.g. self-hosting with caching headers), pass its URL or bytes: ```typescript import compilerWasmUrl from "@blocknote/xl-typst-compiler/wasm?url"; -const { blob } = await exporter.toPDF( - editor.document, - { - // The compiler wasm as an explicitly bundled asset (Vite shown here). - wasm: compilerWasmUrl, - }, - { title: "My document", lang: "en" }, -); +const exporter = new PDFExporter(editor.schema, typstDefaultSchemaMappings, { + // The compiler wasm as an explicitly bundled asset (Vite shown here). + wasm: compilerWasmUrl, +}); ``` To take full control of fonts (e.g. a different look, or trimming the lazily @@ -184,17 +179,14 @@ keeps the default emoji font (and vice versa), and an explicit empty array disables one entirely: ```typescript -const { blob } = await exporter.toPDF( - editor.document, - { - // Font bytes (Uint8Array) to load into the compiler. - fonts: [myBodyFont, myMonoFont], - // An emoji-capable font. Browsers give the compiler no access to OS - // fonts, so without one emoji render as missing glyphs (and fail PDF/UA). - emojiFont: myEmojiFont, - }, - { title: "My document", lang: "en" }, -); +const exporter = new PDFExporter(editor.schema, typstDefaultSchemaMappings, { + // Font bytes (Uint8Array) to load into the compiler - or a promise of + // them, so lazy loading fits the sync constructor. + fonts: [myBodyFont, myMonoFont], + // An emoji-capable font. Browsers give the compiler no access to OS + // fonts, so without one emoji render as missing glyphs (and fail PDF/UA). + emojiFont: myEmojiFont, +}); ``` The compiler ships no fonts of its own and never falls back silently: text @@ -203,17 +195,43 @@ substituted glyphs. The wasm module is loaded once per page; fonts are per-export options, so different exports on the same page can freely use different font sets. -When passing custom fonts, set the exporter's font families to match +When passing custom fonts, set the exporter's font families to match — +Typst selects fonts by the family name embedded in the font file itself (defaults: `"Inter 18pt"` body, `"Geist Mono"` code, `"Noto Color Emoji"` -emoji). This is also how you cover scripts the primary font doesn't, e.g. -CJK — load the extra font's bytes and declare a fallback list: +emoji). A mismatch shows up as an `unknown font family` entry in the +result's `compileWarnings`, naming exactly what didn't resolve. To cover scripts the default fonts don't (e.g. CJK), extend rather than +replace: the bundled defaults are exported as loaders, so spreading them +plus your addition is plain composition, and a `fontFamily` list makes +Typst fall back per glyph — Latin stays Inter, CJK comes from the added +font: ```typescript +import { + loadDefaultBodyFonts, + PDFExporter, + typstDefaultSchemaMappings, +} from "@blocknote/xl-pdf-exporter"; +import notoSansSCUrl from "./NotoSansSC-Regular.ttf?url"; + +// Family names and font bytes side by side - the whole font setup is +// constructor configuration. const exporter = new PDFExporter(editor.schema, typstDefaultSchemaMappings, { fontFamily: ["Inter 18pt", "Noto Sans SC"], + fonts: loadDefaultBodyFonts().then(async (fonts) => [ + ...fonts, + new Uint8Array(await (await fetch(notoSansSCUrl)).arrayBuffer()), + ]), +}); + +const result = await exporter.toPDF(editor.document, { + title: "文档", + lang: "zh", }); ``` +(The family name in `fontFamily` must match what the font file itself +declares — "Noto Sans SC" here; a mismatch shows up in `compileWarnings`.) + ### PDF/UA conformance The produced PDF always carries the tagged (accessible) structure tree. On @@ -224,7 +242,7 @@ tagged-but-unclaimed instead (an honest output rather than a false claim), with the violations reported in the result: ```typescript -const { blob, pdfUA } = await exporter.toPDF(editor.document, {}, { +const { blob, pdfUA } = await exporter.toPDF(editor.document, { title: "My document", lang: "en", }); @@ -249,7 +267,7 @@ What conformance requires of the document: dedicated alt field yet, so the caption (or file name) is used — give images captions. -Pass `tryDeclarePdfUA: false` in the compile options to skip the validation +Pass `tryDeclarePdfUA: false` in the export options to skip the validation and claim entirely (e.g. for a live preview, where the validation compile would be wasted work). Conformance of the claim is enforced at compile time by the Typst engine itself — a declared export has also been verified @@ -258,6 +276,13 @@ checks) if you need independent validation. ### Exporter options +The split between the two option surfaces matches the other exporters: +the **constructor** configures everything the exporter *is* — styling, the +font family names **and** the font bytes they resolve against, the +compiler wasm — while `toPDF`'s **options** carry the facts of the +individual export: the document metadata and page setup, plus the +conformance policy (`tryDeclarePdfUA`). + The `PDFExporter` constructor takes an optional third `options` parameter: ```typescript diff --git a/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx b/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx index a8507eb83c..bf4fcc539a 100644 --- a/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx +++ b/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx @@ -71,11 +71,10 @@ function usePdfUA( setStatus("loading"); void (async () => { try { - const result = await makeExporter().toPDF( - blocks, - { wasm: compilerWasmUrl }, - { title: "BlockNote document", lang: "en" }, - ); + const result = await makeExporter().toPDF(blocks, { + title: "BlockNote document", + lang: "en", + }); if (stale) { return; } @@ -204,20 +203,28 @@ export default function App() { // every image/diagram variant it has ever rendered. const makeExporter = useCallback( () => - new PDFExporter(editor.schema, { - ...typstDefaultSchemaMappings, - blockMapping: { - ...typstDefaultSchemaMappings.blockMapping, - // Renders math blocks as native Typst equations, and diagrams as - // embedded images - both carrying alt text for PDF/UA. - mathBlock: mathBlockMapping, - diagram: diagramBlockMapping, + new PDFExporter( + editor.schema, + { + ...typstDefaultSchemaMappings, + blockMapping: { + ...typstDefaultSchemaMappings.blockMapping, + // Renders math blocks as native Typst equations, and diagrams as + // embedded images - both carrying alt text for PDF/UA. + mathBlock: mathBlockMapping, + diagram: diagramBlockMapping, + }, + inlineContentMapping: { + ...typstDefaultSchemaMappings.inlineContentMapping, + math: inlineMathMapping, + }, }, - inlineContentMapping: { - ...typstDefaultSchemaMappings.inlineContentMapping, - math: inlineMathMapping, + { + // The bundled compiler wasm (see the import above) - engine setup + // belongs to the exporter, per-document facts go to toPDF. + wasm: compilerWasmUrl, }, - }), + ), [editor], ); diff --git a/packages/xl-pdf-exporter/src/index.ts b/packages/xl-pdf-exporter/src/index.ts index b0ddefea43..987e657e20 100644 --- a/packages/xl-pdf-exporter/src/index.ts +++ b/packages/xl-pdf-exporter/src/index.ts @@ -5,6 +5,7 @@ export * from "@blocknote/xl-typst-exporter"; export { PDFExporter, + type PdfExporterOptions, type PdfExportOptions, type PdfExportResult, type PdfUAResult, @@ -14,6 +15,10 @@ export { compileTypstToPdf, type TypstCompileOptions, } from "./pdfua/compileTypst.js"; +export { + loadDefaultBodyFonts, + loadDefaultEmojiFont, +} from "./pdfua/defaultFonts.js"; export { isPdfStandardViolation, type CompilePdfResult, diff --git a/packages/xl-pdf-exporter/src/pdfExporter.test.ts b/packages/xl-pdf-exporter/src/pdfExporter.test.ts index dabc4be21f..fe5421bc01 100644 --- a/packages/xl-pdf-exporter/src/pdfExporter.test.ts +++ b/packages/xl-pdf-exporter/src/pdfExporter.test.ts @@ -10,8 +10,9 @@ import { readFileSync } from "node:fs"; import { join, resolve } from "node:path"; import { describe, expect, it } from "vite-plus/test"; import { + loadDefaultBodyFonts, PDFExporter, - type PdfExportOptions, + type PdfExporterOptions, type PdfExportResult, } from "./index.js"; @@ -22,39 +23,18 @@ const schema = BlockNoteSchema.create({ }, }); -describe("PDFExporter", () => { - it("rejects caller assets that collide with exporter-registered ones", async () => { - const exporter = new PDFExporter(schema, typstDefaultSchemaMappings, { - resolveFileUrl: testResolveFileUrl, - }); - - // The document's image registers `/assets/asset-0`; a caller asset under - // the same key would be silently shadowed by the merge, so the export - // must fail loudly instead (before ever reaching the compiler). - await expect( - exporter.toPDF( - partialBlocksToBlocksForTesting(schema, [ - { - type: "image", - props: { url: "https://placehold.co/60x60.png", caption: "Cap" }, - }, - ]), - { assets: new Map([["/assets/asset-0", new Uint8Array([1])]]) }, - ), - ).rejects.toThrow('the caller-supplied asset "/assets/asset-0" collides'); - }); -}); +function read(p: string) { + return new Uint8Array(readFileSync(resolve(process.cwd(), p))); +} -// Node has no URL-relative wasm loading, so the module bytes and fonts are -// passed explicitly (the zero-config defaults - bundled fonts, wasm from -// package files - are browser paths, covered by the browser/e2e suites). +// Node has no URL-relative wasm loading, so the module bytes are passed +// explicitly. A minimal font set keeps the compiles fast; tests about the +// bundled defaults leave `fonts`/`emojiFont` unset instead. +const fontDir = "../../shared/assets/fonts"; function wasmAndFonts(): Pick< - PdfExportOptions, + Partial, "wasm" | "fonts" | "emojiFont" > { - const read = (p: string) => - new Uint8Array(readFileSync(resolve(process.cwd(), p))); - const fontDir = "../../shared/assets/fonts"; return { wasm: read("../xl-typst-compiler/pkg/blocknote_typst_wasm_bg.wasm"), fonts: [ @@ -65,6 +45,14 @@ function wasmAndFonts(): Pick< }; } +function exporter(options?: Partial) { + return new PDFExporter(schema, typstDefaultSchemaMappings, { + resolveFileUrl: testResolveFileUrl, + ...wasmAndFonts(), + ...options, + }); +} + const latin1 = (bytes: Uint8Array) => new TextDecoder("latin1").decode(bytes); function expectExported( @@ -80,12 +68,29 @@ function expectExported( return result; } +describe("PDFExporter", () => { + it("rejects caller assets that collide with exporter-registered ones", async () => { + // The document's image registers `/assets/asset-0`; a caller asset under + // the same key would be silently shadowed by the merge, so the export + // must fail loudly instead (before ever reaching the compiler). + await expect( + exporter().toPDF( + partialBlocksToBlocksForTesting(schema, [ + { + type: "image", + props: { url: "https://placehold.co/60x60.png", caption: "Cap" }, + }, + ]), + { + assets: new Map([["/assets/asset-0", new Uint8Array([1])]]), + lang: "en", + }, + ), + ).rejects.toThrow('the caller-supplied asset "/assets/asset-0" collides'); + }); +}); + describe("PDFExporter PDF/UA declaration", () => { - function exporter() { - return new PDFExporter(schema, typstDefaultSchemaMappings, { - resolveFileUrl: testResolveFileUrl, - }); - } const conforming = () => partialBlocksToBlocksForTesting(schema, [ { type: "heading", props: { level: 1 }, content: "Title" }, @@ -94,10 +99,7 @@ describe("PDFExporter PDF/UA declaration", () => { it("declares PDF/UA-1 for a conforming document", async () => { const { bytes, pdfUA } = expectExported( - await exporter().toPDF(conforming(), wasmAndFonts(), { - title: "Doc", - lang: "en", - }), + await exporter().toPDF(conforming(), { title: "Doc", lang: "en" }), ); expect(pdfUA).toEqual({ declared: true }); expect(latin1(bytes)).toContain("pdfuaid"); @@ -112,10 +114,7 @@ describe("PDFExporter PDF/UA declaration", () => { { type: "heading", props: { level: 2 }, content: "Not level one" }, ]); const { bytes, pdfUA } = expectExported( - await exporter().toPDF(blocks, wasmAndFonts(), { - title: "Doc", - lang: "en", - }), + await exporter().toPDF(blocks, { title: "Doc", lang: "en" }), ); expect(pdfUA.declared).toBe(false); if (!pdfUA.declared && pdfUA.reason === "nonconforming") { @@ -137,15 +136,14 @@ describe("PDFExporter PDF/UA declaration", () => { // decision only the caller can make, so this fails loudly instead of // quietly producing forever-unclaimed exports. await expect( - exporter().toPDF(conforming(), wasmAndFonts(), { title: "Doc" }), + exporter().toPDF(conforming(), { title: "Doc" }), ).rejects.toThrow("requires the document's language"); // Opting out of the claim makes the language optional again. const { pdfUA } = expectExported( - await exporter().toPDF( - conforming(), - { ...wasmAndFonts(), tryDeclarePdfUA: false }, - { title: "Doc" }, - ), + await exporter().toPDF(conforming(), { + tryDeclarePdfUA: false, + title: "Doc", + }), ); expect(pdfUA).toEqual({ declared: false, @@ -155,11 +153,11 @@ describe("PDFExporter PDF/UA declaration", () => { it("skips validation and claim with tryDeclarePdfUA: false", async () => { const { bytes, pdfUA } = expectExported( - await exporter().toPDF( - conforming(), - { ...wasmAndFonts(), tryDeclarePdfUA: false }, - { title: "Doc", lang: "en" }, - ), + await exporter().toPDF(conforming(), { + tryDeclarePdfUA: false, + title: "Doc", + lang: "en", + }), ); expect(pdfUA).toEqual({ declared: false, @@ -173,15 +171,9 @@ describe("PDFExporter PDF/UA declaration", () => { // An unknown font family is a warning, not an error - the export // succeeds (Typst falls back across the loaded fonts), and the result // surfaces what an integrator would want to know. - const warned = new PDFExporter(schema, typstDefaultSchemaMappings, { - resolveFileUrl: testResolveFileUrl, - fontFamily: "No Such Family", - }); + const warned = exporter({ fontFamily: "No Such Family" }); const result = expectExported( - await warned.toPDF(conforming(), wasmAndFonts(), { - title: "Doc", - lang: "en", - }), + await warned.toPDF(conforming(), { title: "Doc", lang: "en" }), ); expect( result.compileWarnings.some((w) => @@ -190,8 +182,63 @@ describe("PDFExporter PDF/UA declaration", () => { ).toBe(true); }); + it("keeps the bundled default fonts in sync with the referenced families", async () => { + // Two things can drift independently: the family-name defaults + // (TypstExporter's fontFamily/monoFontFamily, PDFExporter's + // emojiFontFamily) and the bundled font files in defaultFonts.ts. + // Either drift - a renamed default or a swapped file - surfaces as an + // `unknown font family` compile warning, so a zero-config export of a + // document exercising body (regular/bold/italic), code, and emoji must + // warn about nothing. (The math pairing is pinned the same way by + // math-block's typst-exporter test.) + const blocks = partialBlocksToBlocksForTesting(schema, [ + { type: "heading", props: { level: 1 }, content: "Title" }, + { + type: "paragraph", + content: [ + { type: "text", text: "plain ", styles: {} }, + { type: "text", text: "bold ", styles: { bold: true } }, + { type: "text", text: "italic ", styles: { italic: true } }, + { type: "text", text: "emoji 😀🧑‍💻", styles: {} }, + ], + }, + { type: "codeBlock", content: "const mono = true;" }, + ]); + // Only the wasm is supplied (node can't URL-load it); fonts and + // emojiFont stay unset so the real bundled defaults load. + const zeroConfig = new PDFExporter(schema, typstDefaultSchemaMappings, { + resolveFileUrl: testResolveFileUrl, + wasm: wasmAndFonts().wasm, + }); + const result = expectExported( + await zeroConfig.toPDF(blocks, { title: "Doc", lang: "en" }), + ); + expect(result.compileWarnings).toEqual([]); + expect(result.pdfUA).toEqual({ declared: true }); + }); + + it("extends the defaults by spreading the exported loaders", async () => { + // `fonts` replaces the bundled default set; extension is composition, + // not API: spread the exported defaults and append - names and bytes + // configured side by side in the constructor. (The appended bytes here + // are already part of the defaults, so the compiler's dedup makes this + // a pure wiring test.) + const extended = exporter({ + fonts: loadDefaultBodyFonts().then((fonts) => [ + ...fonts, + read(join(fontDir, "inter/Inter_18pt-Regular.ttf")), + ]), + emojiFont: undefined, + }); + const result = expectExported( + await extended.toPDF(conforming(), { title: "Doc", lang: "en" }), + ); + expect(latin1(result.bytes)).toContain("pdfuaid"); + expect(result.compileWarnings).toEqual([]); + }); + it("carries the PDF as a Blob alongside the bytes", async () => { - const result = await exporter().toPDF(conforming(), wasmAndFonts(), { + const result = await exporter().toPDF(conforming(), { title: "Doc", lang: "en", }); @@ -216,7 +263,7 @@ describe("PDFExporter PDF/UA declaration", () => { // Broken raw markup (here via the caller-supplied header) is a compile // failure - an expected outcome carried in the result, distinct from // conformance violations (it must not degrade to an unclaimed export). - const result = await exporter().toPDF(conforming(), wasmAndFonts(), { + const result = await exporter().toPDF(conforming(), { title: "Doc", lang: "en", header: "#thisFunctionDoesNotExist()", diff --git a/packages/xl-pdf-exporter/src/pdfExporter.ts b/packages/xl-pdf-exporter/src/pdfExporter.ts index 87d49a84ef..a5057400f7 100644 --- a/packages/xl-pdf-exporter/src/pdfExporter.ts +++ b/packages/xl-pdf-exporter/src/pdfExporter.ts @@ -25,8 +25,67 @@ import { loadDefaultEmojiFont, } from "./pdfua/defaultFonts.js"; -/** Options for {@link PDFExporter}'s export methods. */ -export type PdfExportOptions = TypstCompileOptions & { +/** + * {@link PDFExporter}'s options: everything the *exporter* is (like the + * other exporters' option types) - the Typst styling options including the + * font *family names*, plus the engine inputs those names resolve against: + * the font *bytes* and the compiler wasm. Names and bytes side by side, so + * a custom font setup lives in one place. + * + * Like the other exporters, this is the full options shape; the + * constructor takes a `Partial` of it and fills the defaults. + */ +export type PdfExporterOptions = TypstExporterOptions & { + /** + * The compiler wasm module: a URL (string or `URL`) or the module bytes. + * Omitted, it loads from `@blocknote/xl-typst-compiler`'s own package + * files (no CDN). Loaded once per page; the first exporter's value wins. + * + * Optional even in this full options shape: absence is not an unfilled + * default but a complete configuration - resolution is delegated to the + * wasm-bindgen glue's own module-relative URL, the one pattern bundlers + * reliably detect and rewrite (a value computed here couldn't be). + */ + wasm?: TypstCompileOptions["wasm"]; + /** + * The body fonts (as bytes, or a promise of them) the exporter's + * `fontFamily` / `monoFontFamily` names resolve against. Defaults to the + * bundled set matching the editor; to *extend* it, spread the exported + * loader: `loadDefaultBodyFonts().then((f) => [...f, myCjkFont])`. + * Typst selects fonts by the family name embedded in each file's own + * name table; a referenced-but-missing family surfaces as an + * `unknown font family` entry in the result's `compileWarnings`. + */ + fonts: Uint8Array[] | Promise; + /** + * An emoji-capable font (or fonts) as bytes, or a promise of them - + * what {@link TypstExporterOptions.emojiFontFamily} resolves against. + * Defaults (independently of {@link fonts}) to the bundled Noto Color + * Emoji. Browsers give the compiler no access to OS fonts, so without + * one emoji render as missing glyphs (and fail PDF/UA). + */ + emojiFont: Uint8Array | Uint8Array[] | Promise; +}; + +/** + * Per-export options for {@link PDFExporter.toPDF} - one bag, like the + * other exporters' export methods: the per-document options (title, + * language, page setup - {@link TypstDocumentOptions}) plus the per-export + * compile inputs. + */ +export type PdfExportOptions = TypstDocumentOptions & { + /** + * Extra files to map into the compiler's virtual filesystem, keyed by + * the Typst path referenced in the source - e.g. an image used by a + * caller-supplied {@link TypstDocumentOptions.header}. The exporter's + * own collected assets are merged in automatically. + */ + assets?: TypstCompileOptions["assets"]; + /** + * PDF creation timestamp in seconds since the Unix epoch (UTC). Pass a + * fixed value for byte-reproducible output; omitted means no timestamp. + */ + creationTimestamp?: number; /** * Try to produce a *declared* PDF/UA-1 document - the claim is made only * when the document earns it. Typst @@ -41,9 +100,9 @@ export type PdfExportOptions = TypstCompileOptions & { * Set `false` to skip the claim and its validation entirely (e.g. for a * live preview, where the validation compile would be wasted work). * - * Attempting the claim requires the document's language - * (`documentOptions.lang`) - the one conformance input only the caller - * can provide - and throws without it. + * Attempting the claim requires the document's language (the export + * options' `lang`) - the one conformance input only the caller can + * provide - and throws without it. * * @default true */ @@ -108,12 +167,12 @@ export type PdfExportResult = * accumulates assets for its lifetime: create a fresh exporter per export * when repeatedly exporting changing content (construction is cheap). * - * Zero-config exports match the editor: the compile options' `fonts` and + * Zero-config exports match the editor: the constructor's `fonts` and * `emojiFont` each default (independently) to the bundled set - Inter, * Geist Mono, New Computer Modern Math resp. Noto Color Emoji - loaded * lazily from the package, and the compiler wasm loads from its own * package's files. Pass a value (or an explicit `[]` for no fonts) to take - * over either. + * over either; see {@link PdfExporterOptions}. * * (The previous react-pdf based exporter is still available from * `@blocknote/xl-pdf-exporter/react-pdf` during its deprecation window.) @@ -123,6 +182,10 @@ export class PDFExporter< S extends StyleSchema, I extends InlineContentSchema, > extends TypstExporter { + private readonly wasm: TypstCompileOptions["wasm"]; + private readonly fonts: Promise; + private readonly emojiFont: Promise; + public constructor( schema: BlockNoteSchema, mappings: Exporter< @@ -134,16 +197,39 @@ export class PDFExporter< (inner: string) => string, string >["mappings"], - options?: Partial, + options?: Partial, ) { + const { wasm, fonts, emojiFont, ...typstOptions } = options ?? {}; super(schema, mappings, { // The bundled default fonts (see `defaultFonts.ts`) include Noto // Color Emoji; declaring the family by default lets multi-codepoint - // emoji shape correctly with zero config. Callers supplying their own - // fonts can override (or unset) it. + // emoji shape correctly with zero config. Spread-defaulting is + // deliberate here (unlike the base's per-key defaults): an explicit + // `emojiFontFamily: undefined` *unsets* the family - a legitimate + // state when supplying custom fonts without an emoji face, where a + // dangling default reference would only produce warning noise. emojiFontFamily: DEFAULT_EMOJI_FONT_FAMILY, - ...options, + ...typstOptions, }); + this.wasm = wasm; + // Zero-config fonts: each option defaults independently to the bundled + // set matching the editor - `undefined` means "use the default", a + // supplied value (including an explicit `[]` for none) takes over. The + // independence keeps the bytes consistent with the constructor's + // independent `emojiFontFamily` default: custom body fonts don't + // silently drop emoji support, and vice versa. Values may be promises + // (the constructor stays sync); they resolve on first export. + this.fonts = + fonts === undefined ? loadDefaultBodyFonts() : Promise.resolve(fonts); + this.emojiFont = + emojiFont === undefined + ? loadDefaultEmojiFont() + : Promise.resolve(emojiFont); + // A caller-supplied promise may reject before the first export awaits + // it; these no-op handlers keep that from surfacing as an unhandled + // rejection (the export still rejects with the real error). + this.fonts.catch(() => {}); + this.emojiFont.catch(() => {}); } /** @@ -160,9 +246,30 @@ export class PDFExporter< public async toPDF( blocks: Block[], options: PdfExportOptions = {}, - documentOptions?: TypstDocumentOptions, ): Promise { - const { tryDeclarePdfUA = true, ...compileOptions } = options; + const { + tryDeclarePdfUA = true, + assets, + creationTimestamp, + ...documentOptions + } = options; + // Attempting the claim without a document language is a caller-args + // error (like the asset collision below), not a document + // nonconformity: the PDF would otherwise carry Typst's silently + // defaulted language (English), and a wrong `/Lang` (e.g. "en" on a + // German document) is an accessibility defect no validator can catch. + // Unlike heading structure or alt text - content the end user can fix - + // the language is an integration-time decision only the caller can + // make, so it fails loudly (and first) at development time instead of + // quietly producing forever-unclaimed exports. + if (tryDeclarePdfUA && !options.lang) { + throw new Error( + "PDFExporter: declaring PDF/UA-1 (tryDeclarePdfUA, the default) " + + "requires the document's language - pass its BCP-47 tag in the " + + 'export options (e.g. { lang: "en" }), or opt out of the ' + + "claim with tryDeclarePdfUA: false.", + ); + } const typst = await this.toTypst(blocks, documentOptions); // The images collected during the export are mapped into the compiler // alongside (not instead of) any assets the caller supplied - e.g. an @@ -170,7 +277,7 @@ export class PDFExporter< // the exporter's own key space would be silently shadowed by the merge, // so that's rejected loudly instead (a programmer error, not an // expected outcome - hence a throw, unlike compile failures). - for (const key of compileOptions.assets?.keys() ?? []) { + for (const key of assets?.keys() ?? []) { if (this.assetFiles.has(key)) { throw new Error( `PDFExporter: the caller-supplied asset "${key}" collides with an ` + @@ -178,25 +285,13 @@ export class PDFExporter< ); } } - // Zero-config fonts: each option defaults independently to the bundled - // set matching the editor - `undefined` means "use the default", a - // supplied value (including an explicit `[]` for none) takes over. The - // independence keeps the bytes consistent with the constructor's - // independent `emojiFontFamily` default: custom body fonts don't - // silently drop emoji support, and vice versa. - const [fonts, emojiFont] = await Promise.all([ - compileOptions.fonts === undefined - ? loadDefaultBodyFonts() - : compileOptions.fonts, - compileOptions.emojiFont === undefined - ? loadDefaultEmojiFont() - : compileOptions.emojiFont, - ]); + const [fonts, emojiFont] = await Promise.all([this.fonts, this.emojiFont]); const resolved: TypstCompileOptions = { - ...compileOptions, + wasm: this.wasm, fonts, emojiFont, - assets: new Map([...(compileOptions.assets ?? []), ...this.assetFiles]), + creationTimestamp, + assets: new Map([...(assets ?? []), ...this.assetFiles]), }; if (!tryDeclarePdfUA) { @@ -206,24 +301,6 @@ export class PDFExporter< }); } - // Attempting the claim without a document language is a caller-args - // error (like the asset collision above), not a document - // nonconformity: the PDF would otherwise carry Typst's silently - // defaulted language (English), and a wrong `/Lang` (e.g. "en" on a - // German document) is an accessibility defect no validator can catch. - // Unlike heading structure or alt text - content the end user can fix - - // the language is an integration-time decision only the caller can - // make, so it fails loudly at development time instead of quietly - // producing forever-unclaimed exports. - if (!documentOptions?.lang) { - throw new Error( - "PDFExporter: declaring PDF/UA-1 (tryDeclarePdfUA, the default) " + - "requires the document's language - pass its BCP-47 tag in the " + - 'document options (e.g. { lang: "en" }), or opt out of the ' + - "claim with tryDeclarePdfUA: false.", - ); - } - const declared = await compileTypstToPdf(typst, { ...resolved, pdfStandard: "ua-1", diff --git a/packages/xl-pdf-exporter/src/pdfua/compileTypst.ts b/packages/xl-pdf-exporter/src/pdfua/compileTypst.ts index ff3a1e0ac6..cf982c60d4 100644 --- a/packages/xl-pdf-exporter/src/pdfua/compileTypst.ts +++ b/packages/xl-pdf-exporter/src/pdfua/compileTypst.ts @@ -15,10 +15,18 @@ export interface TypstCompileOptions { wasm?: TypstCompilerOptions["wasm"]; /** * Fonts (as bytes) to load into the compiler - the body fonts the - * exporter references (e.g. Inter, Geist Mono). The compiler ships no + * source references (e.g. Inter, Geist Mono). This low-level function + * has no defaults (`PDFExporter` adds those); the compiler ships no * fonts of its own: text renders only with supplied fonts, and a * document needing a missing one fails to compile (loudly, not with * substituted glyphs). + * + * Fonts are selected by the family name embedded in each file's name + * table (array order and file names play no role) - the exporter's + * `fontFamily` options must match it exactly. A mismatch surfaces as an + * `unknown font family` entry in the result's `compileWarnings`; + * `TypstCompiler.fontFamilies` (from `@blocknote/xl-typst-compiler`) + * lists what a font file actually declares. */ fonts?: Uint8Array[]; /** diff --git a/packages/xl-pdf-exporter/src/pdfua/defaultFonts.ts b/packages/xl-pdf-exporter/src/pdfua/defaultFonts.ts index b93d01eeb4..e0c1db1a9b 100644 --- a/packages/xl-pdf-exporter/src/pdfua/defaultFonts.ts +++ b/packages/xl-pdf-exporter/src/pdfua/defaultFonts.ts @@ -35,13 +35,21 @@ function cached(load: () => Promise): () => Promise { /** * The default body font set for zero-config exports, matching the editor: + * these files must declare (in their name tables) exactly the family names + * the exporters reference by default - TypstExporter's fontFamily / + * monoFontFamily and {@link DEFAULT_EMOJI_FONT_FAMILY}. The pairing is + * pinned by pdfExporter.test.ts's "keeps the bundled default fonts in + * sync" test: swapping a file (or renaming a default) fails it. + * * Inter (body, 4 faces), Geist Mono (code), and New Computer Modern Math * (Typst's math family - the compiler wasm embeds no fonts, so without it * a document with math blocks fails to compile). Embedded in the package * as lazily-imported chunks (the same mechanism the react-pdf exporter * uses), so nothing loads until a zero-config export runs, and exports * work offline. Used when the compile options' `fonts` is undefined - pass - * your own (or an explicit `[]` for none) to skip it. + * your own (or an explicit `[]` for none) to skip it, or spread this + * loader's result to *extend* it (e.g. `[...(await loadDefaultBodyFonts()), + * myCjkFont]`). */ export const loadDefaultBodyFonts: () => Promise = cached(() => Promise.all([ diff --git a/packages/xl-typst-compiler/src/typstCompiler.ts b/packages/xl-typst-compiler/src/typstCompiler.ts index 243782ef7f..474cba4c30 100644 --- a/packages/xl-typst-compiler/src/typstCompiler.ts +++ b/packages/xl-typst-compiler/src/typstCompiler.ts @@ -91,7 +91,15 @@ export type TypstCompilerOptions = { * the first `create()` call's value is used; the module is loaded once. */ wasm?: string | URL | Uint8Array; - /** Font files to load (every face of each TTF/OTF/TTC). */ + /** + * Font files to load (every face of each TTF/OTF/TTC). Typst selects + * fonts by the family name embedded in each file's own name table - + * array order and file names play no role - so a document must reference + * the family exactly as the font declares it. {@link + * TypstCompiler.fontFamilies} lists the loaded names for verification, + * and a referenced-but-missing family surfaces as an + * `unknown font family` entry in the result's `compileWarnings`. + */ fonts?: readonly Uint8Array[]; }; diff --git a/packages/xl-typst-exporter/src/typstExporter.ts b/packages/xl-typst-exporter/src/typstExporter.ts index 7b7b7c7edc..f15f2f6dfa 100644 --- a/packages/xl-typst-exporter/src/typstExporter.ts +++ b/packages/xl-typst-exporter/src/typstExporter.ts @@ -161,6 +161,11 @@ export class TypstExporter< // `options.colors[name]` whose types promise a value. const newOptions = { ...options, + // These family names must match what the PDF exporter's bundled + // default font files declare in their name tables (defaultFonts.ts). + // The pairing is pinned by pdfExporter.test.ts's "keeps the bundled + // default fonts in sync" test - changing a default here without the + // matching font file fails it. fontFamily: options?.fontFamily ?? "Inter 18pt", monoFontFamily: options?.monoFontFamily ?? "Geist Mono", fontSize: options?.fontSize ?? 12, From b9c69b2048396f12a1909e99ee3a2e0167a5ccb5 Mon Sep 17 00:00:00 2001 From: yousefed Date: Thu, 27 Aug 2026 15:31:05 +0200 Subject: [PATCH 5/9] fix(ci): resolve the Rust toolchain from the crate dir; build wasm outside the e2e container wasm-pack now runs with the crate directory as cwd so rustup discovers rust-toolchain.toml (a bootstrapped rustup with no default toolchain found nothing to run - masked locally by an existing default). The e2e shards can't build the wasm at all (the Playwright container has no C toolchain for proc-macros), so a bare-runner job builds it once and shares pkg/dist/types as an artifact. --- .github/workflows/build.yml | 53 ++++++++++++++++--- .../xl-typst-compiler/scripts/ensure-wasm.mjs | 8 ++- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1a86990c37..1a8cbe517c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -58,16 +58,57 @@ jobs: id: soft-release run: vp dlx pkg-pr-new publish './packages/*' # TODO disabled only for AI branch--compact + build-typst-compiler: + # The one package the e2e suite consumes through build outputs instead of + # src/ aliases: @blocknote/xl-typst-compiler (its /pkg and /wasm subpaths + # are wasm build artifacts - see tests/vite.config.browser.ts). Built once + # on a bare runner - the Playwright container has no C toolchain for the + # Rust build - and shared with the shards as an artifact. + name: Build Typst compiler + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 100 + persist-credentials: false + + - uses: voidzero-dev/setup-vp@313600b80b104eadebb9111787d37a2e83e014ca # v1.17.0 + with: + node-version-file: ".node-version" + cache: true + + - name: Install dependencies + run: vp install + + # Compiles the Rust wasm when missing/stale (rustup is bootstrapped by + # the build task itself) plus the TS wrapper's dist/types. + - name: Build Typst compiler package + run: vp run --filter @blocknote/xl-typst-compiler build + + - name: Upload compiler build outputs + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: typst-compiler-build + path: | + packages/xl-typst-compiler/pkg + packages/xl-typst-compiler/dist + packages/xl-typst-compiler/types + include-hidden-files: true + e2e: # Vitest Browser Mode runs in the Playwright Linux container — the same # environment as the local Docker run — so behaviour matches local dev. # The suite resolves every `@blocknote/*` import to its `src/` via the # aliases in `tests/vite.config.browser.ts` (vite transpiles the package # sources on the fly), so the packages do NOT need to be built to `dist` - # first — `vp install` + the checked-out sources are enough. + # first — `vp install` + the checked-out sources are enough (the one + # exception, xl-typst-compiler, arrives prebuilt from the + # build-typst-compiler job). name: "E2E - ${{ matrix.browser }} (${{ matrix.shardIndex }}/${{ matrix.shardTotal }})" runs-on: ubuntu-latest timeout-minutes: 30 + needs: build-typst-compiler container: image: mcr.microsoft.com/playwright:v1.60.0-noble strategy: @@ -90,11 +131,11 @@ jobs: - name: Install dependencies run: vp install - # The e2e suite consumes xl-typst-compiler through its build outputs - # (see tests/vite.config.browser.ts). Its build task also compiles the - # Rust wasm when missing (rustup is preinstalled on the runners). - - name: Build Typst compiler package - run: vp run --filter @blocknote/xl-typst-compiler build + - name: Download Typst compiler build outputs + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: typst-compiler-build + path: packages/xl-typst-compiler # No preview server: Vitest Browser Mode serves the tests + mounted example # apps itself. `--browser` selects this matrix job's browser and diff --git a/packages/xl-typst-compiler/scripts/ensure-wasm.mjs b/packages/xl-typst-compiler/scripts/ensure-wasm.mjs index 965cb4450f..666b993d9d 100644 --- a/packages/xl-typst-compiler/scripts/ensure-wasm.mjs +++ b/packages/xl-typst-compiler/scripts/ensure-wasm.mjs @@ -135,7 +135,7 @@ execFileSync( join(packageDir, "node_modules", ".bin", "wasm-pack"), [ "build", - "rust", + ".", "--target", "web", "--release", @@ -144,7 +144,11 @@ execFileSync( "--out-name", "blocknote_typst_wasm", ], - { stdio: "inherit", cwd: packageDir, env }, + // cwd must be the crate directory: rustup resolves rust-toolchain.toml + // (the pinned toolchain + wasm32 target, auto-installed on first use) by + // walking up from the *working directory* - from packageDir a freshly + // bootstrapped rustup with no default toolchain finds nothing to run. + { stdio: "inherit", cwd: rustDir, env }, ); writeFileSync(hashFile, currentHash); console.log("[ensure-wasm] done."); From 0b1cf5feca52ad6348fe852ebca119314e9a6151 Mon Sep 17 00:00:00 2001 From: yousefed Date: Thu, 27 Aug 2026 15:42:22 +0200 Subject: [PATCH 6/9] docs(pdf): rewrite the PDF page against the exporter-docs conventions Simple-first flow matching the DOCX template: PDF/UA confined to its own section, CDN/offline said once, internals cut, fonts split into short sections, custom mappings owned by the Typst page (the base layer never points up; the PDF page keeps its own option surfaces explicit). Typst page gains its own Customizing/assets/math-diagram/options sections; math's export section renamed Typst / PDF. DEFAULT_FONT_FAMILY / DEFAULT_MONO_FONT_FAMILY are exported so fallback lists need no hardcoded names. --- docs/content/docs/features/blocks/math.mdx | 11 +- docs/content/docs/features/export/pdf.mdx | 286 +++++++----------- docs/content/docs/features/export/typst.mdx | 121 +++++++- .../xl-typst-exporter/src/typstExporter.ts | 14 +- 4 files changed, 229 insertions(+), 203 deletions(-) diff --git a/docs/content/docs/features/blocks/math.mdx b/docs/content/docs/features/blocks/math.mdx index 3bf753c1da..83378c6aa6 100644 --- a/docs/content/docs/features/blocks/math.mdx +++ b/docs/content/docs/features/blocks/math.mdx @@ -119,12 +119,13 @@ import { // Spread into the ODTExporter's mappings exactly as for DOCX above. ``` -### PDF +### Typst / PDF -With the [PDF exporter](/docs/features/export/pdf) (or the standalone -[Typst exporter](/docs/features/export/typst) — they share mappings), math -blocks and inline math export as **native Typst equations**: real, selectable -text, no rasterization, so they also work server-side out of the box: +With the [Typst exporter](/docs/features/export/typst) and the +[PDF exporter](/docs/features/export/pdf) built on it (they share mappings), +math blocks and inline math export as **native Typst equations**: real, +selectable text, no rasterization, so they also work server-side out of the +box: ```typescript import { diff --git a/docs/content/docs/features/export/pdf.mdx b/docs/content/docs/features/export/pdf.mdx index 7680041064..1d096961da 100644 --- a/docs/content/docs/features/export/pdf.mdx +++ b/docs/content/docs/features/export/pdf.mdx @@ -9,9 +9,8 @@ path: /docs/export-to-pdf It's possible to export BlockNote documents to PDF, completely client-side. The exporter is powered by the [Typst](https://typst.app) typesetting engine -(compiled to WebAssembly) and produces **accessible, tagged PDF/UA-1** -documents: the PDF carries a logical structure tree (headings, paragraphs, -lists, tables, figures with alt text, links) that screen readers can navigate. +(compiled to WebAssembly) and produces accessible, tagged documents; see +[PDF/UA conformance](#pdfua-conformance). This feature is provided by the `@blocknote/xl-pdf-exporter`. `xl-` packages @@ -37,26 +36,20 @@ import { // Create the exporter const exporter = new PDFExporter(editor.schema, typstDefaultSchemaMappings); -// Export the document - the result carries the PDF as bytes and as a Blob -const { blob, pdfUA } = await exporter.toPDF(editor.document, { +// Export the document; the result carries the PDF as bytes and as a Blob +const result = await exporter.toPDF(editor.document, { title: "My document", lang: "en", }); +if (!result.error) { + const url = URL.createObjectURL(result.blob); + // e.g. open or download `url` +} ``` -This works out of the box, fully offline: the export matches the editor's -look (Inter body text, Geist Mono code) and handles math blocks and emoji — -the default fonts ship inside the package and load lazily on the first -export, and the compiler (a ~25MB wasm file from -`@blocknote/xl-typst-compiler`) loads from the package's own files, emitted -as an asset by your bundler. Nothing is ever fetched from a CDN. - -The result's `pdfUA` field reports whether the document earned the PDF/UA-1 -conformance claim — see [PDF/UA conformance](#pdfua-conformance). - -When repeatedly exporting changing content (e.g. a live preview), create a -fresh exporter per export — construction is cheap, and an exporter instance -accumulates the image assets it has resolved for as long as it lives. +This works out of the box, fully offline: exports match the editor's look, +and everything needed (the default fonts and the compiler itself) ships +inside the package. Nothing is fetched from a CDN. See the [full example](/examples/interoperability/converting-blocks-to-pdf-ua) with a live PDF preview below: @@ -65,13 +58,11 @@ with a live PDF preview below: ### Customizing the PDF -The second parameter of `toPDF` is a single per-export options bag: the -per-document options below, plus `tryDeclarePdfUA`, extra `assets` for -caller-supplied markup, and a `creationTimestamp`: +`toPDF` takes per-export options: the document metadata and page setup. ```typescript -const { blob } = await exporter.toPDF(editor.document, { - // Document title - required for PDF/UA (also shown in the viewer's title bar) +const result = await exporter.toPDF(editor.document, { + // Document title, shown in the viewer's title bar title: "My document", // Document author, written to the PDF metadata author: "John Doe", @@ -88,201 +79,131 @@ const { blob } = await exporter.toPDF(editor.document, { }); ``` -### Custom mappings / custom schemas +The remaining export options are +[`tryDeclarePdfUA`](#pdfua-conformance), `assets` (extra files for +caller-supplied header/footer markup), and `creationTimestamp` (a fixed +Unix timestamp for byte-reproducible output). -The `PDFExporter` constructor takes a `schema` and `mappings` parameter. A -_mapping_ defines how to convert a BlockNote schema element (a Block, Inline -Content, or Style) — for this exporter, into a **Typst markup string**. The -same mappings drive the standalone [Typst export](/docs/features/export/typst), -so one custom-block mapping serves both formats. +A document that fails to compile (e.g. text in a script the loaded fonts +don't cover) is reported in the result as `{ error: "compile-failed" }` +with the compiler's diagnostics, rather than thrown. + +### PDF/UA conformance -If you're using a [custom schema](/docs/features/custom-schemas) in your -editor, or if you want to overwrite how default BlockNote elements are -converted, you can pass your own `mappings`: +The produced PDF is always _tagged_: it carries a logical structure tree +(headings, paragraphs, lists, tables, figures with alt text, links) that +screen readers can navigate. On top of that, the exporter **declares +PDF/UA-1 conformance when, and only when, the document earns it**: Typst +validates conformance during the compile, and a nonconforming document is +exported as tagged-but-unclaimed instead, with the violations reported in +the result: ```typescript -import { - PDFExporter, - typstDefaultSchemaMappings, - strLit, -} from "@blocknote/xl-pdf-exporter"; - -new PDFExporter(schema, { - ...typstDefaultSchemaMappings, - blockMapping: { - ...typstDefaultSchemaMappings.blockMapping, - myCustomBlock: (block, exporter) => { - // Return Typst markup; `strLit` safely embeds user text as a - // Typst string literal. - return `#${strLit("My custom block")}`; - }, - }, +const result = await exporter.toPDF(editor.document, { + title: "My document", + lang: "en", }); +if ( + !result.error && + !result.pdfUA.declared && + result.pdfUA.reason === "nonconforming" +) { + // e.g. "PDF/UA-1 error: the first heading must be of level 1" + console.info(result.pdfUA.violations.map((v) => v.message)); +} ``` -For a block with inline content, render it the way the default mappings do: -`exporter.transformInlineContent(block.content).join("")` (inline results are -markup strings, so plain concatenation composes them). +What conformance requires of the document: -### Math & diagram blocks +- **Title and language**: pass `title` and `lang` in the export options. + `lang` is required to attempt the claim at all: a wrong language + declaration is an accessibility defect no validator can catch, so + exporting without it throws. +- **Headings**: the first heading must be level 1, and levels must be + consecutive (no jumping from H1 to H3). -The [math](/docs/features/blocks/math) and -[diagram](/docs/features/blocks/diagrams) blocks ship Typst mappings — math -exports as native Typst equations (real text, not images), diagrams as -embedded vector SVG — both carrying alt text, as PDF/UA requires: +Images always get the alt text PDF/UA requires, derived from the caption +with the file name as fallback. Captions make far better alt text, so +encourage them. -```typescript -import { diagramBlockMapping } from "@blocknote/diagram-block/typst-exporter"; -import { - inlineMathMapping, - mathBlockMapping, -} from "@blocknote/math-block/typst-exporter"; - -new PDFExporter(editor.schema, { - ...typstDefaultSchemaMappings, - blockMapping: { - ...typstDefaultSchemaMappings.blockMapping, - mathBlock: mathBlockMapping, - diagram: diagramBlockMapping, - }, - inlineContentMapping: { - ...typstDefaultSchemaMappings.inlineContentMapping, - math: inlineMathMapping, - }, -}); -``` +Pass `tryDeclarePdfUA: false` in the export options to skip the validation +and claim entirely, e.g. for a live preview, where the validation compile +would be wasted work. For live previews, also create a fresh exporter per +export, since an instance accumulates the image assets it resolves. + +### Custom mappings / custom schemas -### Fonts & offline use +The `PDFExporter` constructor takes a `schema` and `mappings` parameter. A +_mapping_ converts a BlockNote schema element into a **Typst markup +string**, and the mappings are shared with the standalone Typst export. See +[custom mappings](/docs/features/export/typst#custom-mappings--custom-schemas) +there; everything on writing them applies to this exporter unchanged. -By default, exports use a font set matching the editor — Inter (body), Geist -Mono (code), New Computer Modern Math (math blocks) and Noto Color Emoji -(emoji, [required for PDF/UA](#pdfua-conformance)) — embedded in the package -and loaded lazily on the first export, and the compiler wasm loads from -`@blocknote/xl-typst-compiler`'s own package files. Neither touches a CDN. -The exporter's constructor options control -all of it; to take explicit control of where the wasm is served from (e.g. -self-hosting with caching headers), pass its URL or bytes: +### Math & diagram blocks -```typescript -import compilerWasmUrl from "@blocknote/xl-typst-compiler/wasm?url"; +The [math](/docs/features/blocks/math) and +[diagram](/docs/features/blocks/diagrams) blocks ship their own Typst +mappings: math exports as native Typst equations (real text, not images), +diagrams as embedded vector graphics. See +[exporting math](/docs/features/blocks/math#typst--pdf) and +[exporting diagrams](/docs/features/blocks/diagrams#exporting) for the setup. -const exporter = new PDFExporter(editor.schema, typstDefaultSchemaMappings, { - // The compiler wasm as an explicitly bundled asset (Vite shown here). - wasm: compilerWasmUrl, -}); -``` +### Fonts -To take full control of fonts (e.g. a different look, or trimming the lazily -loaded defaults — the emoji font alone is ~5MB), pass your own font bytes. -Each option independently replaces its bundled default: supplying `fonts` -keeps the default emoji font (and vice versa), and an explicit empty array -disables one entirely: +By default, exports use a bundled font set matching the editor: Inter +(body), Geist Mono (code), New Computer Modern Math (math), and Noto Color +Emoji. To use your own fonts instead, pass the font bytes and the matching +family names to the constructor: ```typescript const exporter = new PDFExporter(editor.schema, typstDefaultSchemaMappings, { - // Font bytes (Uint8Array) to load into the compiler - or a promise of - // them, so lazy loading fits the sync constructor. - fonts: [myBodyFont, myMonoFont], - // An emoji-capable font. Browsers give the compiler no access to OS - // fonts, so without one emoji render as missing glyphs (and fail PDF/UA). - emojiFont: myEmojiFont, + fontFamily: "My Font", + monoFontFamily: "My Mono Font", + // Uint8Array[], or a promise of them + fonts: [myFontBytes, myMonoFontBytes], + // An emoji-capable font; replaces the default independently of `fonts` + emojiFont: myEmojiFontBytes, }); ``` -The compiler ships no fonts of its own and never falls back silently: text -that no supplied font covers fails the export loudly rather than rendering -substituted glyphs. The wasm module is loaded once per page; fonts are -per-export options, so different exports on the same page can freely use -different font sets. - -When passing custom fonts, set the exporter's font families to match — -Typst selects fonts by the family name embedded in the font file itself -(defaults: `"Inter 18pt"` body, `"Geist Mono"` code, `"Noto Color Emoji"` -emoji). A mismatch shows up as an `unknown font family` entry in the -result's `compileWarnings`, naming exactly what didn't resolve. To cover scripts the default fonts don't (e.g. CJK), extend rather than -replace: the bundled defaults are exported as loaders, so spreading them -plus your addition is plain composition, and a `fontFamily` list makes -Typst fall back per glyph — Latin stays Inter, CJK comes from the added -font: +Typst selects fonts by the family name embedded in the font file itself, so +the `fontFamily` options must match what your files declare. A mismatch +shows up as an `unknown font family` entry in the result's +`compileWarnings`. + +To extend the defaults rather than replace them (e.g. adding a CJK font as +a per-glyph fallback), spread the exported default loaders: ```typescript import { + DEFAULT_FONT_FAMILY, loadDefaultBodyFonts, PDFExporter, typstDefaultSchemaMappings, } from "@blocknote/xl-pdf-exporter"; -import notoSansSCUrl from "./NotoSansSC-Regular.ttf?url"; -// Family names and font bytes side by side - the whole font setup is -// constructor configuration. const exporter = new PDFExporter(editor.schema, typstDefaultSchemaMappings, { - fontFamily: ["Inter 18pt", "Noto Sans SC"], - fonts: loadDefaultBodyFonts().then(async (fonts) => [ - ...fonts, - new Uint8Array(await (await fetch(notoSansSCUrl)).arrayBuffer()), - ]), -}); - -const result = await exporter.toPDF(editor.document, { - title: "文档", - lang: "zh", + fontFamily: [DEFAULT_FONT_FAMILY, "Noto Sans SC"], + fonts: loadDefaultBodyFonts().then((fonts) => [...fonts, notoSansSCBytes]), }); ``` -(The family name in `fontFamily` must match what the font file itself -declares — "Noto Sans SC" here; a mismatch shows up in `compileWarnings`.) - -### PDF/UA conformance +### Self-hosting the compiler -The produced PDF always carries the tagged (accessible) structure tree. On -top of that, the exporter **declares PDF/UA-1 conformance when — and only -when — the document earns it**: Typst validates conformance during the -compile, and a nonconforming document is automatically exported as -tagged-but-unclaimed instead (an honest output rather than a false claim), -with the violations reported in the result: +The Typst compiler is a ~25MB wasm file from `@blocknote/xl-typst-compiler`, +by default emitted as an asset by your bundler. To control where it is +served from (e.g. with caching headers), pass its URL or bytes: ```typescript -const { blob, pdfUA } = await exporter.toPDF(editor.document, { - title: "My document", - lang: "en", +import compilerWasmUrl from "@blocknote/xl-typst-compiler/wasm?url"; + +const exporter = new PDFExporter(editor.schema, typstDefaultSchemaMappings, { + wasm: compilerWasmUrl, }); -if (!pdfUA.declared && pdfUA.reason === "nonconforming") { - // e.g. "PDF/UA-1 error: the first heading must be of level 1" - console.info(pdfUA.violations.map((v) => v.message)); -} ``` -What conformance requires of the document: - -- **Title and language**: pass `title` and `lang` in the document options. - Without a title, Typst's validation withholds the claim. The language is - required to attempt the claim at all — exporting without `lang` throws - (pass `tryDeclarePdfUA: false` to skip the claim instead), because the - PDF would otherwise declare Typst's default language (English), and a - wrong language declaration is an accessibility defect no validator can - catch. -- **Headings**: the first heading must be level 1, and levels must be - consecutive (no jumping from H1 to H3). -- **Alt text**: every image needs it. BlockNote's image block has no - dedicated alt field yet, so the caption (or file name) is used — give - images captions. - -Pass `tryDeclarePdfUA: false` in the export options to skip the validation -and claim entirely (e.g. for a live preview, where the validation compile -would be wasted work). Conformance of the claim is enforced at compile -time by the Typst engine itself — a declared export has also been verified -against [veraPDF](https://verapdf.org)'s `--flavour ua1` checks (0 failed -checks) if you need independent validation. - ### Exporter options -The split between the two option surfaces matches the other exporters: -the **constructor** configures everything the exporter *is* — styling, the -font family names **and** the font bytes they resolve against, the -compiler wasm — while `toPDF`'s **options** carry the facts of the -individual export: the document metadata and page setup, plus the -conformance policy (`tryDeclarePdfUA`). - The `PDFExporter` constructor takes an optional third `options` parameter: ```typescript @@ -296,18 +217,23 @@ const defaultOptions = { dictionary: locales.en, // the colors used for highlighting, background colors and font colors colors: COLORS_DEFAULT, // defaults from @blocknote/core - // font families, see "Fonts & offline use" above + // font families (DEFAULT_FONT_FAMILY / DEFAULT_MONO_FONT_FAMILY) and the + // font bytes they resolve against - see "Fonts" above fontFamily: "Inter 18pt", monoFontFamily: "Geist Mono", + fonts: loadDefaultBodyFonts(), + emojiFont: loadDefaultEmojiFont(), // base font size in points fontSize: 12, + // where the compiler wasm loads from - see "Self-hosting the compiler" + wasm: undefined, // the packaged wasm }; ``` ### Exporting Typst markup The underlying Typst source export is available standalone (e.g. to compile -with your own Typst toolchain, including server-side) — see +with your own Typst toolchain, including server-side); see [Typst export](/docs/features/export/typst). ### Deprecated: the react-pdf exporter @@ -325,6 +251,6 @@ import { } from "@blocknote/xl-pdf-exporter/react-pdf"; ``` -Note that its mappings are react-pdf mappings — when migrating to the new +Note that its mappings are react-pdf mappings; when migrating to the new exporter, custom blocks need a [Typst mapping](#custom-mappings--custom-schemas) instead. diff --git a/docs/content/docs/features/export/typst.mdx b/docs/content/docs/features/export/typst.mdx index b498e25194..1f545fc38a 100644 --- a/docs/content/docs/features/export/typst.mdx +++ b/docs/content/docs/features/export/typst.mdx @@ -8,7 +8,7 @@ path: /docs/export-to-typst # Typst Export It's possible to export BlockNote documents to [Typst](https://typst.app) -markup — for example to post-process documents in a Typst workflow, or to +markup, for example to post-process documents in a Typst workflow, or to compile them to PDF with your own Typst toolchain (including server-side). This exporter is also the foundation of the [PDF exporter](/docs/features/export/pdf), which compiles its output to @@ -43,23 +43,112 @@ const typst = await exporter.toTypst(editor.document, { title: "My document", lang: "en", }); +``` + +### Images & assets + +The markup references the document's images by virtual paths like +`/assets/asset-0`. After `toTypst`, the exporter's `assetFiles` map holds +the bytes for those paths. Map them into your Typst compiler's filesystem +before compiling: -// The document's images, keyed by the virtual path referenced in the markup - -// map these into your Typst compiler's filesystem before compiling -const assets = exporter.assetFiles; +```typescript +const assets = exporter.assetFiles; // Map ``` -`toTypst` takes the same per-document options as the PDF exporter's export -methods (title, author, language, paper size, margins, page header/footer) — -see [customizing the PDF](/docs/features/export/pdf#customizing-the-pdf) — -and the constructor takes the same -[exporter options](/docs/features/export/pdf#exporter-options). +(The [PDF exporter](/docs/features/export/pdf) does this automatically.) + +### Customizing the output -### Custom mappings +`toTypst` takes per-export options: the document metadata and page setup. -Mappings convert schema elements into Typst markup strings, and they are -shared with the PDF exporter — one custom-block mapping serves both formats. -See [custom mappings](/docs/features/export/pdf#custom-mappings--custom-schemas) -on the PDF page; the [math](/docs/features/blocks/math#pdf) and -[diagram](/docs/features/blocks/diagrams) blocks ship ready-made Typst -mappings from their `typst-exporter` subpaths. +```typescript +const typst = await exporter.toTypst(editor.document, { + // Document title, written to the document metadata + title: "My document", + // Document author + author: "John Doe", + // BCP-47 language tag of the document's natural language + lang: "en", + // Typst paper name, e.g. "a4" (default) or "us-letter" + paper: "a4", + // Page margin as a Typst length + margin: "48pt", + // Raw Typst markup for the running page header / footer, e.g. a + // page counter: "#context counter(page).display()" + header: "My document", + footer: "#context counter(page).display()", +}); +``` + +Only the options you pass are emitted; the markup declares no title, +author, or language on its own. + +### Custom mappings / custom schemas + +A _mapping_ defines how to convert a BlockNote schema element (a Block, +Inline Content, or Style) into a **Typst markup string**. The same mappings +drive the [PDF exporter](/docs/features/export/pdf), so one custom-block +mapping serves both formats. + +If you're using a [custom schema](/docs/features/custom-schemas) in your +editor, or if you want to overwrite how default BlockNote elements are +converted, you can pass your own `mappings`: + +```typescript +import { + TypstExporter, + typstDefaultSchemaMappings, + strLit, +} from "@blocknote/xl-typst-exporter"; + +new TypstExporter(schema, { + ...typstDefaultSchemaMappings, + blockMapping: { + ...typstDefaultSchemaMappings.blockMapping, + myCustomBlock: (block, exporter) => { + // Return Typst markup; `strLit` safely embeds user text as a + // Typst string literal. + return `#${strLit("My custom block")}`; + }, + }, +}); +``` + +For a block with inline content, render it the way the default mappings do: +`exporter.transformInlineContent(block.content).join("")` (inline results are +markup strings, so plain concatenation composes them). + + +### Math & diagram blocks + +The [math](/docs/features/blocks/math) and +[diagram](/docs/features/blocks/diagrams) blocks ship their own Typst +mappings. See [exporting math](/docs/features/blocks/math#typst--pdf) and +[exporting diagrams](/docs/features/blocks/diagrams#exporting) for the +setup. + +### Exporter options + +The `TypstExporter` constructor takes an optional third `options` parameter: + +```typescript +const defaultOptions = { + // a function to resolve external resources (e.g. images) in order to avoid + // CORS issues; by default, this calls a BlockNote hosted server-side proxy + resolveFileUrl: corsProxyResolveFileUrl, + // the strings rendered into the exported document (file link texts, error + // placeholders); pass a locale from @blocknote/core/locales (or your + // editor's dictionary) to export in another language + dictionary: locales.en, + // the colors used for highlighting, background colors and font colors + colors: COLORS_DEFAULT, // defaults from @blocknote/core + // the font families the markup references - they must match fonts loaded + // into whichever Typst compiler you use (exported as DEFAULT_FONT_FAMILY + // and DEFAULT_MONO_FONT_FAMILY) + fontFamily: "Inter 18pt", + monoFontFamily: "Geist Mono", + // base font size in points + fontSize: 12, +}; +``` diff --git a/packages/xl-typst-exporter/src/typstExporter.ts b/packages/xl-typst-exporter/src/typstExporter.ts index f15f2f6dfa..f289055ef5 100644 --- a/packages/xl-typst-exporter/src/typstExporter.ts +++ b/packages/xl-typst-exporter/src/typstExporter.ts @@ -49,6 +49,16 @@ export type TypstExporterOptions = ExporterOptions & { emojiFontFamily?: string; }; +/** + * The default body font family — what the bundled default fonts declare and + * the editor uses. Exported so a custom `fontFamily` fallback list can + * reference it without hardcoding, e.g. `[DEFAULT_FONT_FAMILY, "Noto Sans SC"]`. + */ +export const DEFAULT_FONT_FAMILY = "Inter 18pt"; + +/** The default code font family. See {@link DEFAULT_FONT_FAMILY}. */ +export const DEFAULT_MONO_FONT_FAMILY = "Geist Mono"; + /** * Per-document options applied at export time, passed to `toTypst(blocks, ...)`. * Mirrors how the other exporters take title/author/header/footer at the export @@ -166,8 +176,8 @@ export class TypstExporter< // The pairing is pinned by pdfExporter.test.ts's "keeps the bundled // default fonts in sync" test - changing a default here without the // matching font file fails it. - fontFamily: options?.fontFamily ?? "Inter 18pt", - monoFontFamily: options?.monoFontFamily ?? "Geist Mono", + fontFamily: options?.fontFamily ?? DEFAULT_FONT_FAMILY, + monoFontFamily: options?.monoFontFamily ?? DEFAULT_MONO_FONT_FAMILY, fontSize: options?.fontSize ?? 12, colors: options?.colors ?? COLORS_DEFAULT, // Proxy cross-origin image fetches so any host works in the browser, not From 5c372a4428b2742a91f6d1b4e81549bc169e1d09 Mon Sep 17 00:00:00 2001 From: yousefed Date: Thu, 27 Aug 2026 15:47:22 +0200 Subject: [PATCH 7/9] docs(skill): dependency-direction, concept containment, hero-snippet, and prose-style rules from the PDF page review --- .claude/skills/docs-skill/SKILL.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.claude/skills/docs-skill/SKILL.md b/.claude/skills/docs-skill/SKILL.md index ad44bea9c5..e0791f408f 100644 --- a/.claude/skills/docs-skill/SKILL.md +++ b/.claude/skills/docs-skill/SKILL.md @@ -18,8 +18,16 @@ The documentation site lives in `docs/content/docs` (fumadocs + Next.js). These - **Live examples cap the setup they demonstrate.** Place an `` embed after the prose has introduced everything the example's code uses — an embed whose `App.tsx` shows APIs the page never mentions teaches by confusion. Introduced means named, given a purpose, and linked — the example itself (and the linked component pages) can carry the full wiring; expanding every integration inline pushes the example too far down the page. Not at the top (a demo without context motivates but doesn't teach) and not at the bottom (readers rarely reach it); at the end of the "getting it working" narrative, before advanced/optional topics. If an example uses more API than the page should cover, simplify the example rather than the rule. - **Signature snippets tell the truth for one API.** A snippet formatted as a type signature documents exactly that export — never fold variant differences ("only for the X subpath…") into a doc-comment inside it. Show the signature that is true everywhere, and describe variant-specific options as prose in the variant's own section. +- **Docs follow the dependency direction.** When a package builds on another, the base layer's page owns the shared mechanisms (mappings, formats, behaviors) and never points "up" to a consumer page for its own concepts; consumer pages link down. Consumer pages still document their own API surfaces (option lists, signatures) explicitly rather than delegating them, per the signature rule below. Name sections for every layer they serve ("Typst / PDF", not just "PDF") so the base layer isn't erased. +- **Confine a cross-cutting concept to one designated section per page.** A page's headline concept (a conformance standard, an offline guarantee) gets one owning section; the intro may link to it once, and other sections mention it only where the reader must act on it there. Sprinkled re-mentions read as emphasis when written but age as duplication. +- **The hero snippet is the happy path only.** The first usage snippet shows the shortest end-to-end flow and nothing else; auxiliary mechanisms (asset maps, secondary outputs, tuning knobs) move to their own short sections even when genuinely relevant. Same for prose caveats aimed at a niche audience (a live-preview memory note): put them where that audience looks, not in the getting-started flow. - **Caveats must be actionable.** Only note a limitation if the reader can do something with it (install a package, avoid a pattern, pass an option). Speculative hedges ("rare X may behave differently") and defensive implementation details (what a function guards against internally) erode trust without helping anyone act — cut them. +## Prose style + +- Avoid em-dash-heavy prose; prefer commas, colons, semicolons, periods, or parentheses, choosing per sentence rather than substituting mechanically. An em-dash is fine occasionally; several per section reads as filler. +- Before listing something as a _requirement_, verify the reader can actually fail it. A "requirement" the implementation always satisfies automatically (e.g. auto-derived alt text) is at most a quality tip, phrased as one. + ## Verifying content - **Verify snippets against the actual package exports, not memory or existing docs.** APIs drift; grep the package source for every symbol a snippet imports (`export function X` / `export const X`) and check option names and shapes. Content copied forward without this check stays wrong after refactors. From 063bfc4b55126f416f9c3ff371d96e9cef4431e1 Mon Sep 17 00:00:00 2001 From: yousefed Date: Thu, 27 Aug 2026 20:18:19 +0200 Subject: [PATCH 8/9] test(e2e): typst PDF visual baselines; faster and reliable e2e image builds Adds the four typst-pdf-page chromium baselines (visually verified, pixel-exact via pdf.js rasterization) and gives the visual test cold-start headroom on shared runners. The e2e image install no longer re-verifies minimumReleaseAge (2000+ live registry checks - the frozen lockfile was already policy-verified by the install that produced it and by CI) and caches the pnpm store/metadata across rebuilds, taking the step from 70+ flaky minutes to ~4 (sub-minute warm). The pkg-pr-new soft release excludes xl-typst-compiler: its ~25MB wasm exceeds the service's non-whitelisted upload limit. --- .github/workflows/build.yml | 7 ++++++- tests/Dockerfile | 18 +++++++++++++++++- .../typst-pdf-page-1-chromium-linux.png | Bin 0 -> 63960 bytes .../typst-pdf-page-2-chromium-linux.png | Bin 0 -> 130821 bytes .../typst-pdf-page-3-chromium-linux.png | Bin 0 -> 27485 bytes .../typst-pdf-page-4-chromium-linux.png | Bin 0 -> 78965 bytes .../exporters/exporterImages.test.tsx | 4 +++- ...atic-rendering-equality-chromium-linux.png | Bin 27436 -> 27636 bytes 8 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 tests/src/end-to-end/exporters/__screenshots__/exporterImages.test.tsx/typst-pdf-page-1-chromium-linux.png create mode 100644 tests/src/end-to-end/exporters/__screenshots__/exporterImages.test.tsx/typst-pdf-page-2-chromium-linux.png create mode 100644 tests/src/end-to-end/exporters/__screenshots__/exporterImages.test.tsx/typst-pdf-page-3-chromium-linux.png create mode 100644 tests/src/end-to-end/exporters/__screenshots__/exporterImages.test.tsx/typst-pdf-page-4-chromium-linux.png diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1a8cbe517c..5e129945a1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -56,7 +56,12 @@ jobs: - name: Soft release id: soft-release - run: vp dlx pkg-pr-new publish './packages/*' # TODO disabled only for AI branch--compact + # xl-typst-compiler is excluded: its wasm makes the package ~25MB, + # which pkg.pr.new rejects (413; multipart uploads are whitelisted - + # https://github.com/stackblitz-labs/pkg.pr.new/blob/main/.whitelist). + # Preview installs of the PDF exporter therefore lack the compiler + # until the repo is whitelisted or the wasm ships separately. + run: vp dlx pkg-pr-new publish $(ls -d ./packages/* | grep -v xl-typst-compiler) # TODO disabled only for AI branch--compact build-typst-compiler: # The one package the e2e suite consumes through build outputs instead of diff --git a/tests/Dockerfile b/tests/Dockerfile index f19e9428c4..6805569494 100644 --- a/tests/Dockerfile +++ b/tests/Dockerfile @@ -41,7 +41,23 @@ COPY patches ./patches # enough — pnpm still runs the docs `postinstall` lifecycle script, which fails # in fumadocs-mdx. SKIP_DOCS_POSTINSTALL makes that script a no-op (see # docs/package.json) without disabling the native build scripts other deps need. -RUN SKIP_DOCS_POSTINSTALL=1 pnpm install --frozen-lockfile --filter '!docs' +# BuildKit cache mounts persist the pnpm store (package tarballs) and cache +# (registry metadata, which the supply-chain policy checks hit per package) +# across image rebuilds: after a dependency change, the reinstall only +# fetches what actually changed instead of the whole workspace store. The +# store lives on a separate mount, so pnpm copies instead of hardlinking - +# still far cheaper than downloading. The first build after adding this +# seeds the caches at full cost. +# minimumReleaseAge is disabled here: the policy re-verifies every package +# against live registry metadata (2000+ requests), which is both the slow +# part of this step and flaky under Docker Desktop's NAT - and the frozen +# lockfile being installed was already verified against the policy by the +# local install that produced it (and by CI). A throwaway test image +# re-checking it buys nothing. +RUN --mount=type=cache,id=pnpm-store,target=/pnpm-store \ + --mount=type=cache,id=pnpm-cache,target=/root/.cache/pnpm \ + SKIP_DOCS_POSTINSTALL=1 pnpm install --frozen-lockfile --filter '!docs' \ + --store-dir /pnpm-store --config.minimumReleaseAge=0 # Bake in the example apps: the tests import them and vite transpiles them from # source at run time. They sit after the install layer, so editing an example diff --git a/tests/src/end-to-end/exporters/__screenshots__/exporterImages.test.tsx/typst-pdf-page-1-chromium-linux.png b/tests/src/end-to-end/exporters/__screenshots__/exporterImages.test.tsx/typst-pdf-page-1-chromium-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..c52ab39088d459860d33e5d32cb6aa4c6e1f75fa GIT binary patch literal 63960 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

  • l-&ZHO{ise9ohsX34nL>#wuWQXb^lPC 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 W9Nx6}3y;_M$G)GV;p;wQ7XBxYYdk;z literal 0 HcmV?d00001 diff --git a/tests/src/end-to-end/exporters/__screenshots__/exporterImages.test.tsx/typst-pdf-page-3-chromium-linux.png b/tests/src/end-to-end/exporters/__screenshots__/exporterImages.test.tsx/typst-pdf-page-3-chromium-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..cb737d35b7217d8ac483b1c6834d83fe88433eed GIT binary patch literal 27485 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 UXAu9}tlwlL7563VIezhf0SxYBP5=M^ literal 0 HcmV?d00001 diff --git a/tests/src/end-to-end/exporters/__screenshots__/exporterImages.test.tsx/typst-pdf-page-4-chromium-linux.png b/tests/src/end-to-end/exporters/__screenshots__/exporterImages.test.tsx/typst-pdf-page-4-chromium-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..10c511a3d3dd46e5693c50c71464c9c7c5721216 GIT binary patch literal 78965 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ù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 literal 0 HcmV?d00001 diff --git a/tests/src/end-to-end/exporters/exporterImages.test.tsx b/tests/src/end-to-end/exporters/exporterImages.test.tsx index b9dd39a9ca..4bf711b2f3 100644 --- a/tests/src/end-to-end/exporters/exporterImages.test.tsx +++ b/tests/src/end-to-end/exporters/exporterImages.test.tsx @@ -260,7 +260,9 @@ describe("pdf/ua export through the complete typst pipeline in the browser", () // rasterizer at 3x the suite cost. test.skipIf(browserName !== "chromium")( "matches the per-page visual snapshot", - { timeout: 60000 }, + // Cold wasm load + compile + rasterizing every page needs more headroom + // than the other tests on shared CI runners. + { timeout: 120000 }, async () => { const { pdf } = await compileTypstUaPdf(); diff --git a/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-equality-chromium-linux.png b/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-equality-chromium-linux.png index bb98426953f0468911850c43c28c6a7a5f7742dc..544a0c0d372d0f1b7c5c3fd23717ea3bd626b599 100644 GIT binary patch literal 27636 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 literal 27436 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 From 50dffc63d170f5b41f5a645d5159a154d704c796 Mon Sep 17 00:00:00 2001 From: yousefed Date: Fri, 28 Aug 2026 08:07:01 +0200 Subject: [PATCH 9/9] fix: address review quick wins (pdf-ua example status, font-less test compiler, workflow quoting) - the pdf-ua example shows a distinct status when the export is tagged but unclaimed, instead of displaying the UA-1 checkmark for a nonconforming document - compileTypstForTesting treats an explicit fontBlobs: [] as a font-less compiler rather than falling through to the bundled defaults - the pkg-pr-new publish line builds a quoted package array (SC2010/SC2046) --- .github/workflows/build.yml | 10 +++++++++- .../11-converting-blocks-to-pdf-ua/src/App.tsx | 15 +++++++++------ shared/util/typstTestUtil.ts | 4 +++- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5e129945a1..cc5b7941bc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -61,7 +61,15 @@ jobs: # https://github.com/stackblitz-labs/pkg.pr.new/blob/main/.whitelist). # Preview installs of the PDF exporter therefore lack the compiler # until the repo is whitelisted or the wasm ships separately. - run: vp dlx pkg-pr-new publish $(ls -d ./packages/* | grep -v xl-typst-compiler) # TODO disabled only for AI branch--compact + # TODO disabled only for AI branch--compact + run: | + packages=() + for dir in ./packages/*/; do + if [[ "$dir" != *"/xl-typst-compiler/"* ]]; then + packages+=("${dir%/}") + fi + done + vp dlx pkg-pr-new publish "${packages[@]}" build-typst-compiler: # The one package the e2e suite consumes through build outputs instead of diff --git a/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx b/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx index bf4fcc539a..bfce34f37a 100644 --- a/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx +++ b/examples/05-interoperability/11-converting-blocks-to-pdf-ua/src/App.tsx @@ -62,9 +62,9 @@ function usePdfUA( blocks: Block[], ) { const [pdfUrl, setPdfUrl] = useState(); - const [status, setStatus] = useState<"loading" | "ready" | "error">( - "loading", - ); + const [status, setStatus] = useState< + "loading" | "ready" | "unclaimed" | "error" + >("loading"); useEffect(() => { let stale = false; @@ -90,7 +90,8 @@ function usePdfUA( return; } // A nonconforming document (e.g. one not starting with an H1) still - // exports - tagged but without the PDF/UA-1 claim; surface why. + // exports - tagged but without the PDF/UA-1 claim; surface why, and + // show a distinct status instead of claiming conformance. if (!result.pdfUA.declared && result.pdfUA.reason === "nonconforming") { // eslint-disable-next-line no-console console.info( @@ -99,7 +100,7 @@ function usePdfUA( ); } setPdfUrl(URL.createObjectURL(result.blob)); - setStatus("ready"); + setStatus(result.pdfUA.declared ? "ready" : "unclaimed"); } catch (e) { if (stale) { return; @@ -259,7 +260,9 @@ export default function App() { ? "Generating…" : status === "error" ? "Export failed (see console)" - : "✓ Tagged PDF/UA-1"; + : status === "unclaimed" + ? "Tagged PDF, no UA-1 claim (see console)" + : "✓ Tagged PDF/UA-1"; return (

    diff --git a/shared/util/typstTestUtil.ts b/shared/util/typstTestUtil.ts index 946be8b481..78e04fc585 100644 --- a/shared/util/typstTestUtil.ts +++ b/shared/util/typstTestUtil.ts @@ -66,7 +66,9 @@ export async function compileTypstForTesting( ): Promise { const { TypstCompiler } = await import("@blocknote/xl-typst-compiler"); let compiler: TypstCompilerInstance; - if (options.fontBlobs?.length) { + // Truthiness on the array (not its length): an explicit `[]` means "a + // font-less compiler", not "the defaults". + if (options.fontBlobs) { compiler = await TypstCompiler.create({ wasm: wasmBytes(), fonts: options.fontBlobs,