@openpresentation/cli 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @openpresentation/cli
2
2
 
3
- A local CLI for agents and people working with `.opf.json` presentations. Create documents, validate them, apply precise edits, paginate content, bundle catalog references for offline use, inspect the bundled schemas and catalogs, and render, export (PPTX, PDF, PNG, SVG) and import (PPTX) files. Node 22 or later on macOS, Linux, or Windows is required (`engines.node` `>=22` from the release after 0.10.0; 0.10.0 and earlier 24.x-only releases make npm on Node 22 or 26 silently install the 0.7.0 CLI, which has no `export` or `render` command).
3
+ A local CLI for agents and people working with `.opf.json` presentations, and the library API `@openpresentation/cli/api` for applications that read, write, export and import them. Create documents, validate them, apply precise edits, paginate content, embed the catalog records a deck uses for offline use (`opf embed`), inspect the bundled schemas and the default catalog, and render, export (PPTX, PDF, PNG, SVG) and import (PPTX) files. Node 22 or later on macOS, Linux, or Windows is required (`engines.node` `>=22` from the release after 0.10.0; 0.10.0 and earlier 24.x-only releases make npm on Node 22 or 26 silently install the 0.7.0 CLI, which has no `export` or `render` command).
4
4
 
5
- The CLI bundles its OPF schema, catalogs, and validator. It needs no separate core package, API key, or network connection at runtime. `opf --version` reports the CLI and bundled core versions. Validation and editing never render; successful validation is not visual verification. `opf render`, `opf export` and `opf import` use the optional peers `@openpresentation/opf-render` and `@openpresentation/opf-pptx` (see [Render, export and import](#render-export-and-import)).
5
+ The CLI depends on `@openpresentation/opf` (core), which holds the OPF schema, catalogs and validator and reads and writes the text formats; the CLI adds files. It needs no API key or network connection at runtime. `opf --version` reports the CLI and the installed core versions. Validation and editing never render; successful validation is not visual verification. `opf render`, `opf export` and `opf import` use the optional peers `@openpresentation/opf-render` and `@openpresentation/opf-pptx` (see [Render, export and import](#render-export-and-import)).
6
6
 
7
7
  ## Install
8
8
 
@@ -13,9 +13,9 @@ npm install -g @openpresentation/cli
13
13
  opf --version
14
14
  ```
15
15
 
16
- Or install it as a development dependency and use `npx --no-install opf`. CLI 0.11.0 bundles OPF 0.13.0 (chart and table data: number formats, datasets and `chart.mapping`; plus templates and variables, numbered lists, footnotes and captions, chart options, the 0.01 pt font grid, the design fields, the 100-layout catalog and the pinned gallery default catalog), including the reference layer (`variables`, ColorRef, payload ids, `opf bundle`), complete code and quote composition, source-preserving pagination and readability floors, styled/merged table cells, shared headers/footers, `opf lint`, and the six OPF agent skills. Browser rendering and editable PowerPoint export require the coordinated library releases documented in [the compatibility matrix](../../docs/compatibility-matrix.md).
16
+ Or install it as a development dependency and use `npx --no-install opf`. The command covers creating, validating, editing, paginating, embedding, linting, filling, rendering, exporting and importing; `opf --help` lists it, and [the compatibility matrix](../../docs/compatibility-matrix.md) names the library releases that go with each CLI. To use it from code, see [Library API](#library-api).
17
17
 
18
- To verify the standalone package from source, run `pnpm install` and `pnpm test:cli:packed`. This creates `artifacts/cli/openpresentation-cli-0.11.0.tgz`, which can be installed using its absolute path. For source development, run `pnpm --filter @openpresentation/cli build` and `node packages/cli/dist/index.js --help`.
18
+ To verify the standalone package from source, run `pnpm install` and `pnpm test:cli:packed`. This creates `artifacts/cli/openpresentation-cli-<version>.tgz` (with the core tarball it depends on), which can be installed using its absolute path. For source development, run `pnpm --filter @openpresentation/cli build` and `node packages/cli/dist/index.js --help`.
19
19
 
20
20
  ## Install agent skills
21
21
 
@@ -48,7 +48,7 @@ opf create - --title "Launch decision" | opf validate -
48
48
  opf create imported.opf.json --from - < authored.opf.json
49
49
  ```
50
50
 
51
- `opf validate` is the one checker: it reads the file as strict JSON text (or as YAML, for a name ending `.yaml`/`.yml` or `--input-format yaml`) and prints the report (`valid`, `schemaValid`, `findings`, `counts`, `checks`), the input's SHA-256 digest and the bundled core version. Each finding has a stable `opf/<rule>` id, a severity, a category (`format`, `references`, `policy`, `accessibility`, `layout`, `content`), a JSON Pointer path, the source line and column, a hint and sometimes suggested fixes. Only format, references and policy findings are errors by default, so `valid` keeps meaning "correct OPF"; accessibility, layout and content findings are warnings and info. Reference warnings do not cover every possible unresolved reference: free-form layout IDs can pass without warnings.
51
+ `opf validate` is the one checker: it reads the file as strict JSON text (or as YAML for a name ending `.yaml`/`.yml` or `--input-format yaml`, or as a Markdown deck for a name ending `.opf.md` or `--input-format markdown`) and prints the report (`valid`, `schemaValid`, `findings`, `counts`, `checks`), the input's SHA-256 digest and the core version. Each finding has a stable `opf/<rule>` id, a severity, a category (`format`, `references`, `policy`, `accessibility`, `layout`, `content`), a JSON Pointer path, the source line and column, a hint and sometimes suggested fixes. Only format, references and policy findings are errors by default, so `valid` keeps meaning "correct OPF"; accessibility, layout and content findings are warnings and info. A content reference that resolves nowhere is the warning `opf/unresolved-reference`; a `name:id` prefix that names no catalog group is the error `opf/undeclared-catalog`.
52
52
 
53
53
  ```sh
54
54
  opf validate deck.opf.json # everything, JSON report
@@ -152,7 +152,7 @@ opf catalog layouts
152
152
  opf catalog fontSchemes roboto
153
153
  ```
154
154
 
155
- `schemas` and `catalogs` list available names/kinds. `schema` returns the whole schema or a branch addressed by a pointer into the schema. `catalog` returns the records in a kind, or one exact ID. Deprecated records (for example chart types outside the Aspose.Slides-supported set, which carry a `deprecation.replacedBy` id) are left out of listings and counts unless you pass `--all`, but an exact ID still returns them; `catalogs` reports how many each kind has as `deprecated`. These commands inspect the bundled version and do not fetch galleries.
155
+ `schemas` and `catalogs` list available names/kinds. `schema` returns the whole schema or a branch addressed by a pointer into the schema. `catalog` returns the records in a kind, keyed by id, or one exact ID. They inspect the default catalog of the core it runs on (the full pptx.gallery catalog) and do not fetch galleries.
156
156
 
157
157
  ```sh
158
158
  opf paginate decision.opf.json paginated.opf.json
@@ -161,10 +161,10 @@ opf paginate decision.opf.json paginated.opf.json
161
161
  Pagination emits ordinary OPF slides and a page mapping. Preview the result with the renderer to assess wrapping and visual fidelity.
162
162
 
163
163
  ```sh
164
- opf bundle decision.opf.json bundled.opf.json
164
+ opf embed decision.opf.json embedded.opf.json
165
165
  ```
166
166
 
167
- Bundle inlines every bundled catalog record the document references — including transitive references such as a theme's color and font schemes — into `catalogs.<kind>.records`, so the file resolves every catalog reference offline. Kinds that declare a custom `source` are left untouched, and the report lists added, already-inline, and unresolved ids. Remote media and data assets (`https:` images, chart `data.src` URLs) are not inlined. Bundling twice is a no-op.
167
+ Embed copies every catalog record the document references — including transitive references such as a theme's color and font schemes — into the document, once, in the group it resolves in (`catalogs.default` for the default catalog, with its `source`), so the file renders the same with no catalog registered. Records already embedded are kept, and the report lists the added records and the references that resolve nowhere. Remote media and data assets (`https:` images, chart `data.src` URLs) are not inlined. Embedding twice is a no-op. Every CLI command registers the default catalog (the pinned pptx.gallery snapshot); a validate configuration's `catalogs` registers more, first.
168
168
 
169
169
  ## Agent output contract
170
170
 
@@ -179,16 +179,56 @@ Bundle inlines every bundled catalog record the document references — includin
179
179
  ## Markdown and outlines
180
180
 
181
181
  `opf from-md <deck.md|-> [output.opf.json|output.opf.yaml|-] [--split <rules|headings>] [--title <text>] [--force] [--fail-on <level>]` converts Markdown in the OPF dialect (YAML front matter, `---` between slides, `#` title, lists, quotes, tables, `chart`, `metric` and `timeline` fences, `Note:` notes, `<!-- slide: ... -->` options) to a validated deck, and `opf to-md <deck.opf.json|-> [output.md|-] [--drop-unsupported] [--force] [--fail-on <level>]` writes a deck as that Markdown, which `from-md` reads back unchanged. Both print JSON reports and follow the exit codes above; Markdown findings carry `line` and `column`. Not in releases before the one that lists it in the changelog. See the [Markdown guide](../../docs/markdown.md).
182
+
183
+ ### Markdown decks in every command
184
+
185
+ JSON stays the canonical form of a deck; YAML and Markdown are authoring forms of the same data, and every command that reads or writes a deck reads and writes all three. A file ending `.opf.md` (any case) is a Markdown deck: `opf validate deck.opf.md`, `opf render deck.opf.md`, `opf export deck.opf.md --format pptx`, `opf edit deck.opf.md --patch changes.json --in-place`, `opf format deck.opf.md` (canonical Markdown; `--check` works), `opf paginate`, `opf fill`, `opf merge`, `opf diff`, `opf stats`. Only `.opf.md` counts: a plain `.md` file is never taken for a deck. Stdin and other names are JSON unless `--input-format markdown` (alias `md`) says otherwise. A Markdown syntax error exits 2 with `line:column` in the message and located findings under `markdown` in the error report, except in `opf validate`, which reports it as a `markdown/<rule>` finding (exit 1); `validate`, `render` and `export` report their findings at Markdown lines. A deck is written as Markdown when the output name ends `.opf.md` or with `--format markdown` (`md`); without either, a command writes the format it read (`create`, `import` and `from-md` have no deck input and default to JSON), and a rewrite that has to put content into an `opf-slide`/`opf-block` fence prints a warning on stderr. `from-md` and `to-md` stay explicit conversions with any file names. See [Markdown decks in every command](../../docs/markdown.md#markdown-decks-in-every-command).
182
186
  ## OPF as YAML
183
187
 
184
- A deck can be written as YAML (`deck.opf.yaml`) and every command that reads a deck or a JSON Patch reads it: a file ending `.yaml` or `.yml` is YAML (strict JSON-compatible YAML 1.2, no anchors, tags or duplicate keys); stdin and other names are JSON unless `--input-format yaml` says otherwise. A YAML syntax error exits 2 with the line and column in the message, like invalid JSON, except in `opf validate`, which reports it as a `yaml/<rule>` finding (exit 1); `validate`, `render` and `export` report their findings at YAML lines. A deck is written as YAML when the output name ends `.yaml`/`.yml` or with `--format yaml` (`create`, `edit`, `merge`, `format`, `paginate`, `bundle`, `fill`, `import-data`, `from-md`, `import`); without either, a command writes the format it read, and JSON when it read none.
188
+ A deck can be written as YAML (`deck.opf.yaml`) and every command that reads a deck or a JSON Patch reads it: a file ending `.yaml` or `.yml` is YAML (strict JSON-compatible YAML 1.2, no anchors, tags or duplicate keys); stdin and other names are JSON unless `--input-format yaml` (or `markdown`) says otherwise. A YAML syntax error exits 2 with the line and column in the message, like invalid JSON, except in `opf validate`, which reports it as a `yaml/<rule>` finding (exit 1); `validate`, `render` and `export` report their findings at YAML lines. A deck is written as YAML when the output name ends `.yaml`/`.yml` or with `--format yaml` (`create`, `edit`, `merge`, `format`, `paginate`, `embed`, `fill`, `import-data`, `from-md`, `import`); without either, a command writes the format it read, and JSON when it read none.
185
189
 
186
190
  `opf from-yaml <deck.yaml|-> [output.opf.json|-] [--aliases] [--force] [--fail-on <level>]` converts YAML to a validated JSON deck (`--aliases` expands anchors, aliases and merge keys, capped at 100 aliases), and `opf to-yaml <deck.opf.json|-> [output.opf.yaml|-] [--schema-comment] [--force]` writes canonical YAML that `from-yaml` reads back unchanged; `--schema-comment` adds the `# yaml-language-server: $schema=...` line that gives editors validation and completion. Both print JSON reports and follow the exit codes above; YAML findings carry `line` and `column`. Commands that rewrite a YAML file do not preserve its comments and print a warning on stderr. Settings files (`--config`), `fill --data` and `import-data` sources stay JSON, CSV or TSV. See the [YAML guide](../../docs/yaml.md).
187
191
 
192
+ ## Library API
193
+
194
+ `@openpresentation/cli/api` is the CLI's code as a library: the format-oriented functions an application calls instead of spawning `opf`. Core reads and writes the text formats; this entry reads and writes files. It is one package with the command, so the command and the API give the same bytes.
195
+
196
+ ```sh
197
+ npm install @openpresentation/cli @openpresentation/opf-render @openpresentation/opf-pptx @resvg/resvg-js sharp pdf-lib @expo-google-fonts/roboto@0.4.3 @expo-google-fonts/roboto-mono@0.4.2 @expo-google-fonts/caladea@0.4.2 @expo-google-fonts/arimo@0.4.3 @expo-google-fonts/tinos@0.4.2 @expo-google-fonts/cousine@0.4.3 @expo-google-fonts/gelasio@0.4.1 @expo-google-fonts/noto-sans@0.4.2
198
+ ```
199
+
200
+ ```ts
201
+ import { readDeck, exportDeck, importDeck } from "@openpresentation/cli/api";
202
+
203
+ const { presentation, findings } = readDeck(text, { filename: "deck.opf.md" }); // JSON, YAML or .opf.md
204
+ const pdf = await exportDeck(presentation, { format: "pdf" }); // { files: [{ name, type, bytes }], findings }
205
+ const slides = await exportDeck(presentation, { format: "png", scale: 2, slides: "1,3-5" });
206
+ const pptx = await exportDeck(presentation, { format: "pptx" });
207
+ const { presentation: back } = await importDeck(pptx.files[0].bytes); // PPTX to OPF
208
+ ```
209
+
210
+ | Function | Does |
211
+ | --- | --- |
212
+ | `readDeck(text, { format?, filename?, catalogs?, validate? })`, `writeDeck(presentation, { format? \| filename? })`, `validate`, `assertValid`, `OPFValidationError`, `defaultCatalog` | Core's own functions, re-exported: one import for an application that only has this package. They are the same functions and classes as `@openpresentation/opf` exports. |
213
+ | `exportDeck(presentation, options)` | Draws a presentation as `pdf`, `png`, `svg` or `pptx`. `png` and `svg` give one file per slide (named `<name>-001.png`), or one zip with `zip: true`; `pdf` and `pptx` give one file. Returns `{ files, findings, fonts, skippedHidden, renderer, pptx? }`. |
214
+ | `importDeck(bytes, { catalogs?, signals? })` | Reads a PowerPoint file into `{ presentation, findings, pptx, signals? }`. Import is a conversion, not a lossless round trip: what it cannot keep is in `findings`. |
215
+
216
+ `exportDeck` options: `format` (required), `slides` (`"1,3-5"` or `[1, 3]`; not for `pptx`), `includeHidden`, `paginate`, `scale` (`png`, raster `pdf`), `pdfMode` (`vector` or `raster`), `svgFonts` (`used` or `none`), `chartex`, `provenance`, `imageFormat` (`pptx`), `date` (`YYYY-MM-DD`), `zip`, `filename` (the source name, for naming files), `catalogs`, `fonts`, `fontDirs` and `assetDir`. They are the options of `opf export` and `opf render` in camel case.
217
+
218
+ - **Deterministic.** No network, no system fonts, no clock: a date field draws only the `date` you pass, and the same presentation gives the same bytes on every machine.
219
+ - **Fonts.** The renderer's bundled open pack plus the `.ttf` and `.otf` files in `fontDirs`. To reuse one prepared set across many calls, pass `fonts`: the handle `loadFonts()` of `@openpresentation/opf-render/fonts-node` returns.
220
+ - **Catalogs.** `catalogs` defaults to core's default catalog, as the command does. Pass your own list (for example `[defaultCatalog, myCatalog]`) to change how references resolve.
221
+ - **Images.** Local image paths are read only from `assetDir`; without it no local file is read. Data URIs work as they are, and URLs are never fetched.
222
+ - **The engines are peers.** `@openpresentation/opf-render` (PDF, PNG, SVG) and `@openpresentation/opf-pptx` (PPTX, import) are optional peer dependencies, loaded the first time a function needs them. Install what you call: from opf-render 0.16 its converters (`@resvg/resvg-js` and `sharp` for PNG, `pdf-lib` for raster PDF, `sharp` for pictures in a PDF) and font packages are optional peers too, listed per output in [docs/cli.md](https://github.com/OpenPresentation/opf/blob/main/docs/cli.md#install); a missing one throws the same `peer-not-installed` error with `details.package` (or `details.packages`) and the install command.
223
+ - **Errors.** `exportDeck` throws `OPFExportError` and `importDeck` `OPFImportError` (both extend `OPFApiError`), with a `code`, `details` and the located `findings`: `peer-not-installed` (the message carries the install command; `details` the package and its range), `peer-too-old`, `peer-load-failed`, `invalid-option`, `invalid-presentation`, `no-slides`, `all-slides-hidden`, `export-failed` and `import-failed`. A presentation that fails the format and references check is rejected with `invalid-presentation`; warnings come back in `findings`.
224
+ - **One core.** The package depends on `@openpresentation/opf` as a regular dependency and does not bundle a copy, so an application that also imports core runs a single core: `error instanceof OPFValidationError` holds across both imports.
225
+
226
+ The same engine runs `opf render`, `opf export` and `opf import`, whose reports are described in [docs/cli.md](https://github.com/OpenPresentation/opf/blob/main/docs/cli.md).
227
+
188
228
  ## Render, export and import
189
229
 
190
230
  ```sh
191
- npm install -g @openpresentation/cli @openpresentation/opf-render @openpresentation/opf-pptx
231
+ npm install -g @openpresentation/cli @openpresentation/opf-render @openpresentation/opf-pptx @resvg/resvg-js sharp pdf-lib @expo-google-fonts/roboto@0.4.3 @expo-google-fonts/roboto-mono@0.4.2 @expo-google-fonts/caladea@0.4.2 @expo-google-fonts/arimo@0.4.3 @expo-google-fonts/tinos@0.4.2 @expo-google-fonts/cousine@0.4.3 @expo-google-fonts/gelasio@0.4.1 @expo-google-fonts/noto-sans@0.4.2
192
232
  opf render deck.opf.json --slides 1,3-5 --format png --scale 2 --out slides
193
233
  opf export deck.opf.json --format pptx # deck.pptx
194
234
  opf export deck.opf.json --format pdf --pdf-mode vector
@@ -198,8 +238,8 @@ opf import deck.pptx --out deck.opf.json --signals signals.json
198
238
 
199
239
  These commands write files; every other command only prints JSON. They check the document's format and references first and print the `opf validate` report (`findings`, `counts`, exit 1 on errors, or on findings at or above `--fail-on`, in which case nothing is written) plus an `outputs` list with each file's SHA-256. Output is deterministic: no network, no system fonts, no clock (`--date` supplies the date for `date: true` fields). Fonts are the renderer's bundled open pack plus the `.ttf`/`.otf` files in each `--font-dir`; relative images are read only from the document's folder (`--asset-dir`); URLs are never fetched. Existing outputs need `--force`.
200
240
 
201
- opf-render and opf-pptx are **optional peer dependencies**, loaded the first time a command needs them (beside the CLI first, then in the working directory), so the CLI stays small and dependency-free; a missing peer, or one older than the `^0.14.0` range (it lacks `loadFonts`, `renderSlideSvg` or the other 0.14 names), exits 2 with the install command. Scripts beyond Latin, Greek and Cyrillic need the renderer's optional Noto script packages (the report names them). The full reference, the report fields and the decisions are in [docs/cli.md](https://github.com/OpenPresentation/opf/blob/main/docs/cli.md).
241
+ opf-render and opf-pptx are **optional peer dependencies**, loaded the first time a command needs them (beside the CLI first, then in the working directory), so the CLI stays small and dependency-free; a missing peer, or one that lacks `loadFonts`, `renderSlideSvg` or the other names of its API, exits 2 (the declared range is `^0.15.0`) with the install command. Scripts beyond Latin, Greek and Cyrillic need the renderer's optional Noto script packages (the report names them). From code, the same engines are `exportDeck` and `importDeck` ([Library API](#library-api)). The full reference, the report fields and the decisions are in [docs/cli.md](https://github.com/OpenPresentation/opf/blob/main/docs/cli.md).
202
242
 
203
243
  ## Development checks
204
244
 
205
- `pnpm test:cli` runs command-level regression checks, including `test/files.mjs` for render, export and import against the workspace's pinned opf-render and opf-pptx (set `UPDATE_GOLDEN=1` to refresh the pinned SVG digests after a renderer or core bump). `pnpm test:cli:packed:peers` installs the packed CLI with both peers from the npm registry and repeats those checks against the installed binary and through `npm exec`. `pnpm test:cli:packed` builds and packs the CLI, installs the tarball offline into an isolated global prefix, exercises the actual executable, and reruns the same checks against the installation. It does not change your global installation. Package builds bundle their current core dependency; rebuild after schema/catalog changes.
245
+ `pnpm test:cli` runs command-level regression checks, including `test/files.mjs` for render, export and import against the workspace's pinned opf-render and opf-pptx (set `UPDATE_GOLDEN=1` to refresh the pinned SVG digests after a renderer or core bump). `pnpm test:cli:packed:peers` installs the packed CLI with both peers from the npm registry and repeats those checks against the installed binary and through `npm exec`. `pnpm test:cli:packed` builds and packs the CLI, installs the tarball and the core tarball it depends on into an isolated global prefix, exercises the actual executable, asserts that the installation holds one core, and reruns the same checks against the installation. It does not change your global installation. `test/api.test.mjs` covers the library API. Rebuild the CLI after a core change; the workspace links the CLI to the core in `packages/javascript`.
package/dist/api.d.ts ADDED
@@ -0,0 +1,191 @@
1
+ import { Finding, Catalog, Presentation } from '@openpresentation/opf';
2
+ export { Catalog, DeckFormat, Finding, OPFValidationError, Presentation, ReadDeckOptions, ReadDeckResult, ValidateOptions, ValidationReport, WriteDeckOptions, assertValid, readDeck, validate, writeDeck } from '@openpresentation/opf';
3
+ export { defaultCatalog } from '@openpresentation/opf/catalog';
4
+
5
+ declare class OPFApiError extends Error {
6
+ readonly code: string;
7
+ readonly details: Record<string, unknown>;
8
+ readonly findings: Finding[];
9
+ constructor(message: string, code: string, extra?: {
10
+ details?: Record<string, unknown>;
11
+ findings?: Finding[];
12
+ cause?: unknown;
13
+ });
14
+ }
15
+ /** Thrown by `exportDeck`: `peer-not-installed`, `peer-too-old`, `peer-load-failed`, `invalid-option`, `invalid-presentation`, `no-slides`, `all-slides-hidden`, `font-failed`, `export-failed`. */
16
+ declare class OPFExportError extends OPFApiError {
17
+ }
18
+ /** Thrown by `importDeck`: `peer-not-installed`, `peer-too-old`, `peer-load-failed`, `invalid-option`, `invalid-presentation`, `import-failed`. */
19
+ declare class OPFImportError extends OPFApiError {
20
+ }
21
+
22
+ interface EmbeddedFace {
23
+ family: string;
24
+ weight: number;
25
+ italic?: boolean;
26
+ dataUrl: string;
27
+ }
28
+ /** What the renderer's deck-level functions read from `{ fonts }` (opf-render `RenderFonts`). */
29
+ interface RenderFonts {
30
+ textMeasurement?: unknown;
31
+ embeddedFonts?: readonly EmbeddedFace[];
32
+ fontFiles?: readonly string[];
33
+ useBundledFonts?: boolean;
34
+ loadSystemFonts?: boolean;
35
+ }
36
+ interface FontRegistry {
37
+ scriptSelection?: {
38
+ detected: string[];
39
+ scripts: string[];
40
+ unavailable: string[];
41
+ packages?: string[];
42
+ notInstalled?: string[];
43
+ uncovered?: string[];
44
+ };
45
+ }
46
+ /** The handle `loadFonts()` of opf-render `/fonts-node` returns: pass it as `{ fonts }` to every deck-level call. */
47
+ interface FontsHandle extends RenderFonts {
48
+ textMeasurement: unknown;
49
+ embeddedFonts: EmbeddedFace[];
50
+ fontFiles: string[];
51
+ useBundledFonts: false;
52
+ loadSystemFonts: false;
53
+ registry: FontRegistry;
54
+ substitutions: {
55
+ requestedFamily: string;
56
+ resolvedFamily: string;
57
+ compatibility: string;
58
+ substitute: boolean;
59
+ }[];
60
+ }
61
+
62
+ type ExportFormat = "svg" | "png" | "pdf" | "pptx";
63
+ interface ExportOptions {
64
+ /** What to write. `svg` and `png` give one file per slide (or one zip), `pdf` and `pptx` one file. */
65
+ format: ExportFormat;
66
+ /** A prepared fonts handle (`loadFonts()` of `@openpresentation/opf-render/fonts-node`), reused across calls. Omitted: the bundled open font pack plus `fontDirs`. */
67
+ fonts?: FontsHandle;
68
+ /** Directories of `.ttf` and `.otf` files to load before the bundled pack (not recursive). Ignored when `fonts` is given. */
69
+ fontDirs?: readonly string[];
70
+ /** The catalogs the presentation's references resolve in. Omitted: core's default catalog. */
71
+ catalogs?: readonly Catalog[];
72
+ /** The slides to write, one-based: numbers or a selection such as `"1,3-5"`. Omitted: every slide that is not hidden. Not for `pptx`. */
73
+ slides?: readonly number[] | string;
74
+ /** Write hidden slides too (`svg`, `png`, `pdf`). */
75
+ includeHidden?: boolean;
76
+ /** Split overflowing slides with the same fonts before drawing, as `opf paginate` does. */
77
+ paginate?: boolean;
78
+ /** Pixel scale of `png` and of a raster `pdf` (0.1 to 8; 1 draws the 1280 x 720 reference slide at 1280 x 720 pixels). */
79
+ scale?: number;
80
+ /** `pdf`: `vector` (selectable text, the default) or `raster`. */
81
+ pdfMode?: "vector" | "raster";
82
+ /** `svg`: embed the faces the slide's text uses (`used`, the default) or none (`none`). */
83
+ svgFonts?: "used" | "none";
84
+ /** `pptx`: native charts (`native`), picture fallbacks (`fallback`) or opf-pptx's choice (`auto`). */
85
+ chartex?: "auto" | "native" | "fallback";
86
+ /** `pptx`: what the file records about where media came from. */
87
+ provenance?: "full" | "references-only" | "none";
88
+ /** `pptx`: keep images as they are (`preserve`) or convert them for older PowerPoint (`compatible`). */
89
+ imageFormat?: "compatible" | "preserve";
90
+ /** `YYYY-MM-DD`, for date fields that show today's date. Nothing reads a clock: without it such a field reports `date-needs-value`. */
91
+ date?: string;
92
+ /** The directory a presentation's relative image paths resolve against. Omitted: no local file is read (data URIs and remote references work as the engines handle them). */
93
+ assetDir?: string;
94
+ /** `svg` and `png`: one zip of the slides instead of one file per slide. */
95
+ zip?: boolean;
96
+ /** The source file name, for naming the output when the presentation has no `filename` or `name`. */
97
+ filename?: string;
98
+ }
99
+ interface ExportFile {
100
+ /** The file name: the presentation's `filename`, else its slugified `name`, else the source name, then `-001.png` for slide 1 and so on. */
101
+ name: string;
102
+ /** The media type. */
103
+ type: string;
104
+ bytes: Uint8Array;
105
+ /** `svg` and `png`: the slide number (one-based) and its id. */
106
+ slide?: number;
107
+ id?: string;
108
+ /** `svg` and `png`: the picture's size in pixels. */
109
+ width?: number;
110
+ height?: number;
111
+ /** `pdf`: the number of pages and the slide numbers they show. */
112
+ pages?: number;
113
+ slides?: number[];
114
+ /** `zip`: the names of the entries. */
115
+ entries?: string[];
116
+ }
117
+ interface ExportFontSummary {
118
+ pack: "office";
119
+ substitutionPolicy: "visual";
120
+ /** The `fontDirs` files, in load order. */
121
+ userFonts: string[];
122
+ substitutions: {
123
+ requested: string;
124
+ resolved: string;
125
+ compatibility: string;
126
+ }[];
127
+ scripts?: unknown;
128
+ }
129
+
130
+ interface ExportResult {
131
+ /** The files, in slide order: one per slide for `svg` and `png`, otherwise one. */
132
+ files: ExportFile[];
133
+ /** The findings of the format and references check (warnings and notes; errors throw) and the diagnostics of the engines: fonts, layout, SVG, PDF and PPTX, each with a `render/`, `pptx/`, `pdf/`, `fonts/` or `cli/` rule prefix. */
134
+ findings: Finding[];
135
+ /** The bundled fonts and font files used, and the substitutions made. */
136
+ fonts: ExportFontSummary;
137
+ /** Slide numbers left out because they are hidden (`svg`, `png`, `pdf` without `includeHidden` or `slides`). */
138
+ skippedHidden: number[];
139
+ /** With `paginate`: the pages the slides were split into. */
140
+ pagination?: {
141
+ pages: unknown;
142
+ };
143
+ /** `pdf`: the mode used. */
144
+ pdf?: {
145
+ mode: "vector" | "raster";
146
+ };
147
+ /** The engines that drew the files. */
148
+ renderer: {
149
+ package: string;
150
+ version: string;
151
+ };
152
+ pptx?: {
153
+ package: string;
154
+ version: string;
155
+ };
156
+ }
157
+ /**
158
+ * Draw a presentation as PDF, PNG, SVG or PPTX with the bundled open fonts. Throws `OPFExportError`: `peer-not-installed`,
159
+ * `peer-too-old` or `peer-load-failed` for the engines, `invalid-option`, `invalid-presentation` (its `findings` are the
160
+ * errors of the check), `no-slides`, `all-slides-hidden`, `export-failed` (a drawing error; `findings` hold it) or a font code.
161
+ */
162
+ declare function exportDeck(presentation: Presentation, options: ExportOptions): Promise<ExportResult>;
163
+ interface ImportOptions {
164
+ /** The catalogs the imported presentation's references resolve in. Omitted: core's default catalog. */
165
+ catalogs?: readonly Catalog[];
166
+ /** Also return the raw per-shape layout and style signals of the file (`signals`). */
167
+ signals?: boolean;
168
+ }
169
+ interface ImportResult {
170
+ /** The presentation. It passed the format and references check. */
171
+ presentation: Presentation;
172
+ /** What the conversion could not keep or had to change, and the findings of the check. */
173
+ findings: Finding[];
174
+ /** With `signals: true`. */
175
+ signals?: {
176
+ version?: number;
177
+ };
178
+ /** The importer that read the file. */
179
+ pptx: {
180
+ package: string;
181
+ version: string;
182
+ };
183
+ }
184
+ /**
185
+ * Read a PowerPoint file into an OPF presentation. Import is a conversion, not a lossless round trip for arbitrary decks:
186
+ * what it cannot keep is reported in `findings`. Throws `OPFImportError`: `peer-not-installed`, `peer-too-old`,
187
+ * `peer-load-failed`, `import-failed` (opf-pptx could not read the file; `findings` hold the error) or `invalid-presentation`.
188
+ */
189
+ declare function importDeck(input: Uint8Array | ArrayBuffer, options?: ImportOptions): Promise<ImportResult>;
190
+
191
+ export { type ExportFile, type ExportFontSummary, type ExportFormat, type ExportOptions, type ExportResult, type FontsHandle, type ImportOptions, type ImportResult, OPFApiError, OPFExportError, OPFImportError, exportDeck, importDeck };
package/dist/api.js ADDED
@@ -0,0 +1,80 @@
1
+ import {
2
+ CLI_CATALOGS,
3
+ OPFApiError,
4
+ OPFExportError,
5
+ OPFImportError,
6
+ PPTX_PACKAGE,
7
+ Reporter,
8
+ VERSIONS,
9
+ asApiError,
10
+ listFontDirectories,
11
+ loadPptx,
12
+ loadRenderer,
13
+ resolveExportOptions,
14
+ runExport,
15
+ runImport
16
+ } from "./chunk-Z2XWARO7.js";
17
+
18
+ // src/api.ts
19
+ import { validate } from "@openpresentation/opf";
20
+ import { OPFValidationError, assertValid, readDeck, validate as validate2, writeDeck } from "@openpresentation/opf";
21
+ import { defaultCatalog } from "@openpresentation/opf/catalog";
22
+ var checkOptions = (catalogs) => ({ only: ["format", "references"], catalogs });
23
+ async function exportDeck(presentation, options) {
24
+ try {
25
+ const resolved = resolveExportOptions(options);
26
+ if (!presentation || typeof presentation !== "object" || Array.isArray(presentation)) throw new OPFApiError("exportDeck takes a presentation object; read JSON, YAML or Markdown text with readDeck first.", "invalid-option");
27
+ const renderer = await loadRenderer();
28
+ const pptx = resolved.format === "pptx" ? await loadPptx() : void 0;
29
+ const userFonts = resolved.fonts ? [] : await listFontDirectories([...resolved.fontDirs ?? []], "fontDirs");
30
+ const check = validate(presentation, checkOptions(resolved.catalogs ?? CLI_CATALOGS));
31
+ if (!check.valid) throw new OPFApiError(`The presentation is not valid OPF: ${firstError(check.findings)}`, "invalid-presentation", { findings: check.findings });
32
+ const reporter = new Reporter(check.findings);
33
+ const run = await runExport(presentation, resolved, { reporter, renderer, ...pptx ? { pptx } : {}, userFonts });
34
+ if (run.failure) throw new OPFApiError(run.failure.message, "export-failed", { details: { reason: run.failure.code }, findings: reporter.findings });
35
+ return {
36
+ files: run.files,
37
+ findings: reporter.findings,
38
+ fonts: run.fonts,
39
+ skippedHidden: run.skippedHidden,
40
+ ...run.pagination ? { pagination: run.pagination } : {},
41
+ ...run.pdf ? { pdf: run.pdf } : {},
42
+ ...VERSIONS(renderer, pptx)
43
+ };
44
+ } catch (error) {
45
+ throw asApiError(OPFExportError, error, "export-failed");
46
+ }
47
+ }
48
+ async function importDeck(input, options = {}) {
49
+ try {
50
+ if (!(input instanceof Uint8Array) && !(input instanceof ArrayBuffer)) throw new OPFApiError("importDeck takes the bytes of a .pptx file (a Uint8Array, a Buffer or an ArrayBuffer).", "invalid-option");
51
+ const pptx = await loadPptx();
52
+ const reporter = new Reporter();
53
+ const run = await runImport(input instanceof Uint8Array ? input : new Uint8Array(input), { signals: options.signals === true }, reporter, pptx);
54
+ if (run.failure || !run.presentation) throw new OPFApiError(run.failure?.message ?? "The file could not be read.", "import-failed", { details: { reason: run.failure?.code }, findings: reporter.findings });
55
+ const check = validate(run.presentation, checkOptions(options.catalogs ?? CLI_CATALOGS));
56
+ for (const found of check.findings) reporter.addFinding(found);
57
+ if (!check.valid) throw new OPFApiError(`The imported presentation is not valid OPF: ${firstError(check.findings)}`, "invalid-presentation", { findings: reporter.findings });
58
+ return { presentation: run.presentation, findings: reporter.findings, ...run.signals ? { signals: run.signals } : {}, pptx: { package: PPTX_PACKAGE, version: pptx.version } };
59
+ } catch (error) {
60
+ throw asApiError(OPFImportError, error, "import-failed");
61
+ }
62
+ }
63
+ var firstError = (findings) => {
64
+ const first = findings.find((found) => found.severity === "error");
65
+ return first ? `${first.message} [${first.ruleId}]` : "see findings.";
66
+ };
67
+ export {
68
+ OPFApiError,
69
+ OPFExportError,
70
+ OPFImportError,
71
+ OPFValidationError,
72
+ assertValid,
73
+ defaultCatalog,
74
+ exportDeck,
75
+ importDeck,
76
+ readDeck,
77
+ validate2 as validate,
78
+ writeDeck
79
+ };
80
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api.ts"],"sourcesContent":["// `@openpresentation/cli/api`: the format-oriented library API of the CLI package. Core reads and writes the text formats\n// (`readDeck`, `writeDeck`, `validate`, re-exported here from the one core this package depends on); this entry reads and\n// writes files (`exportDeck`: PDF, PNG, SVG and PPTX; `importDeck`: PPTX to a presentation). The two engines behind them,\n// `@openpresentation/opf-render` and `@openpresentation/opf-pptx`, are optional peers, loaded the first time a function needs\n// them; a missing one throws a typed error that carries the install command. The `opf render`, `opf export` and\n// `opf import` commands run the same code (export.ts, convert.ts).\n//\n// Output is deterministic: no network, no system fonts, no clock unless `date` is passed.\nimport { type Catalog, type Finding, type Presentation, type ValidateOptions, validate } from \"@openpresentation/opf\";\nimport { CLI_CATALOGS } from \"./catalogs.js\";\nimport { runImport } from \"./convert.js\";\nimport { OPFApiError, OPFExportError, OPFImportError, asApiError } from \"./errors.js\";\nimport { type ExportFile, type ExportFontSummary, type ExportOptions, VERSIONS, resolveExportOptions, runExport } from \"./export.js\";\nimport { listFontDirectories } from \"./fonts.js\";\nimport { PPTX_PACKAGE, loadPptx, loadRenderer } from \"./peers.js\";\nimport { Reporter } from \"./reporter.js\";\n\nexport { OPFValidationError, assertValid, readDeck, validate, writeDeck } from \"@openpresentation/opf\";\nexport type { DeckFormat, Finding, Presentation, ReadDeckOptions, ReadDeckResult, ValidateOptions, ValidationReport, WriteDeckOptions } from \"@openpresentation/opf\";\nexport { defaultCatalog } from \"@openpresentation/opf/catalog\";\nexport type { Catalog } from \"@openpresentation/opf\";\nexport { OPFApiError, OPFExportError, OPFImportError } from \"./errors.js\";\nexport type { ExportFile, ExportFontSummary, ExportFormat, ExportOptions } from \"./export.js\";\nexport type { FontsHandle } from \"./peers.js\";\n\n/** The check a presentation passes before it is exported or after it is imported: format and references, so a contrast warning never blocks a write. */\nconst checkOptions = (catalogs: readonly Catalog[]): ValidateOptions => ({ only: [\"format\", \"references\"], catalogs });\n\nexport interface ExportResult {\n\t/** The files, in slide order: one per slide for `svg` and `png`, otherwise one. */\n\tfiles: ExportFile[];\n\t/** The findings of the format and references check (warnings and notes; errors throw) and the diagnostics of the engines: fonts, layout, SVG, PDF and PPTX, each with a `render/`, `pptx/`, `pdf/`, `fonts/` or `cli/` rule prefix. */\n\tfindings: Finding[];\n\t/** The bundled fonts and font files used, and the substitutions made. */\n\tfonts: ExportFontSummary;\n\t/** Slide numbers left out because they are hidden (`svg`, `png`, `pdf` without `includeHidden` or `slides`). */\n\tskippedHidden: number[];\n\t/** With `paginate`: the pages the slides were split into. */\n\tpagination?: { pages: unknown };\n\t/** `pdf`: the mode used. */\n\tpdf?: { mode: \"vector\" | \"raster\" };\n\t/** The engines that drew the files. */\n\trenderer: { package: string; version: string };\n\tpptx?: { package: string; version: string };\n}\n\n/**\n * Draw a presentation as PDF, PNG, SVG or PPTX with the bundled open fonts. Throws `OPFExportError`: `peer-not-installed`,\n * `peer-too-old` or `peer-load-failed` for the engines, `invalid-option`, `invalid-presentation` (its `findings` are the\n * errors of the check), `no-slides`, `all-slides-hidden`, `export-failed` (a drawing error; `findings` hold it) or a font code.\n */\nexport async function exportDeck(presentation: Presentation, options: ExportOptions): Promise<ExportResult> {\n\ttry {\n\t\tconst resolved = resolveExportOptions(options);\n\t\tif (!presentation || typeof presentation !== \"object\" || Array.isArray(presentation)) throw new OPFApiError(\"exportDeck takes a presentation object; read JSON, YAML or Markdown text with readDeck first.\", \"invalid-option\");\n\t\t// Engines and font directories first, so a missing install is reported before the document is looked at.\n\t\tconst renderer = await loadRenderer();\n\t\tconst pptx = resolved.format === \"pptx\" ? await loadPptx() : undefined;\n\t\tconst userFonts = resolved.fonts ? [] : await listFontDirectories([...(resolved.fontDirs ?? [])], \"fontDirs\");\n\t\tconst check = validate(presentation, checkOptions(resolved.catalogs ?? CLI_CATALOGS));\n\t\tif (!check.valid) throw new OPFApiError(`The presentation is not valid OPF: ${firstError(check.findings)}`, \"invalid-presentation\", { findings: check.findings });\n\t\tconst reporter = new Reporter(check.findings);\n\t\tconst run = await runExport(presentation, resolved, { reporter, renderer, ...(pptx ? { pptx } : {}), userFonts });\n\t\tif (run.failure) throw new OPFApiError(run.failure.message, \"export-failed\", { details: { reason: run.failure.code }, findings: reporter.findings });\n\t\treturn {\n\t\t\tfiles: run.files,\n\t\t\tfindings: reporter.findings,\n\t\t\tfonts: run.fonts as ExportFontSummary,\n\t\t\tskippedHidden: run.skippedHidden,\n\t\t\t...(run.pagination ? { pagination: run.pagination } : {}),\n\t\t\t...(run.pdf ? { pdf: run.pdf } : {}),\n\t\t\t...VERSIONS(renderer, pptx),\n\t\t};\n\t} catch (error) {\n\t\tthrow asApiError(OPFExportError, error, \"export-failed\");\n\t}\n}\n\nexport interface ImportOptions {\n\t/** The catalogs the imported presentation's references resolve in. Omitted: core's default catalog. */\n\tcatalogs?: readonly Catalog[];\n\t/** Also return the raw per-shape layout and style signals of the file (`signals`). */\n\tsignals?: boolean;\n}\n\nexport interface ImportResult {\n\t/** The presentation. It passed the format and references check. */\n\tpresentation: Presentation;\n\t/** What the conversion could not keep or had to change, and the findings of the check. */\n\tfindings: Finding[];\n\t/** With `signals: true`. */\n\tsignals?: { version?: number };\n\t/** The importer that read the file. */\n\tpptx: { package: string; version: string };\n}\n\n/**\n * Read a PowerPoint file into an OPF presentation. Import is a conversion, not a lossless round trip for arbitrary decks:\n * what it cannot keep is reported in `findings`. Throws `OPFImportError`: `peer-not-installed`, `peer-too-old`,\n * `peer-load-failed`, `import-failed` (opf-pptx could not read the file; `findings` hold the error) or `invalid-presentation`.\n */\nexport async function importDeck(input: Uint8Array | ArrayBuffer, options: ImportOptions = {}): Promise<ImportResult> {\n\ttry {\n\t\tif (!(input instanceof Uint8Array) && !(input instanceof ArrayBuffer)) throw new OPFApiError(\"importDeck takes the bytes of a .pptx file (a Uint8Array, a Buffer or an ArrayBuffer).\", \"invalid-option\");\n\t\tconst pptx = await loadPptx();\n\t\tconst reporter = new Reporter();\n\t\tconst run = await runImport(input instanceof Uint8Array ? input : new Uint8Array(input), { signals: options.signals === true }, reporter, pptx);\n\t\tif (run.failure || !run.presentation) throw new OPFApiError(run.failure?.message ?? \"The file could not be read.\", \"import-failed\", { details: { reason: run.failure?.code }, findings: reporter.findings });\n\t\t// The deck is checked in its JSON form, so a located finding points into the document that would be written.\n\t\tconst check = validate(run.presentation, checkOptions(options.catalogs ?? CLI_CATALOGS));\n\t\tfor (const found of check.findings) reporter.addFinding(found);\n\t\tif (!check.valid) throw new OPFApiError(`The imported presentation is not valid OPF: ${firstError(check.findings)}`, \"invalid-presentation\", { findings: reporter.findings });\n\t\treturn { presentation: run.presentation as unknown as Presentation, findings: reporter.findings, ...(run.signals ? { signals: run.signals } : {}), pptx: { package: PPTX_PACKAGE, version: pptx.version } };\n\t} catch (error) {\n\t\tthrow asApiError(OPFImportError, error, \"import-failed\");\n\t}\n}\n\nconst firstError = (findings: readonly Finding[]) => {\n\tconst first = findings.find((found) => found.severity === \"error\");\n\treturn first ? `${first.message} [${first.ruleId}]` : \"see findings.\";\n};\n"],"mappings":"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","names":["validate"]}