document-cli 2.0.0 → 2.1.1
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 +12 -10
- package/dist/cli.js +37 -10
- package/dist/index.cjs +38 -7
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +39 -8
- package/dist/{odb-structure-DePnGZAI.js → odb-structure-B1ygPCEa.js} +4 -0
- package/dist/{tui-Bg4JfhRZ.js → tui-tT3An-cI.js} +47 -9
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/ExaDev/document-cli) [](https://www.npmjs.com/package/document-cli) [](https://github.com/ExaDev/document-cli/releases/latest) [](https://github.com/ExaDev/document-cli/actions)
|
|
4
4
|
|
|
5
|
-
> A command-line interface and an interactive terminal (Ink) app for [`documents.js`](https://github.com/ExaDev/documents.js): every docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/markdown conversion, bridge, and editor documents.js exposes, wired up as a scriptable subcommand or a full-screen terminal editor. Installs as either `document-cli` or `doculi`.
|
|
5
|
+
> A command-line interface and an interactive terminal (Ink) app for [`documents.js`](https://github.com/ExaDev/documents.js): every docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/csv/svg/markdown conversion, bridge, and editor documents.js exposes, wired up as a scriptable subcommand or a full-screen terminal editor. Installs as either `document-cli` or `doculi`.
|
|
6
6
|
|
|
7
7
|
`document-cli` adds no conversion or editing logic of its own — it is a dispatch layer over `documents.js`'s existing conversion functions, `DocumentConverter` port, live-view editors, and `.odb`/PDF readers. What it adds is two ways to drive them without writing TypeScript: a scriptable, Unix-shaped CLI (stdin/stdout, exit codes, `--json` diagnostics) for pipelines, and a full-screen Ink terminal app for browsing and editing a document interactively.
|
|
8
8
|
|
|
@@ -79,7 +79,7 @@ cat report.docx | document-cli docx-to-pdf - - > report.pdf
|
|
|
79
79
|
|
|
80
80
|
### Commands
|
|
81
81
|
|
|
82
|
-
**The explicit `<source>-to-<target>` conversions** — one command per pair `createLocalDocumentConverter().conversions` declares in `documents.js` (confirmed by running the built CLI's own `formats` command, not assumed): the
|
|
82
|
+
**The explicit `<source>-to-<target>` conversions** — one command per pair `createLocalDocumentConverter().conversions` declares in `documents.js` (confirmed by running the built CLI's own `formats` command, not assumed): every ordered pair of the ten content formats — docx, pptx, xlsx, odt, odp, ods, odg, svg, csv, markdown — in both directions as a PDF-bypassing bridge (a pair whose formats share one `ContentDocument` variant, like `odt-to-docx` or `ods-to-xlsx`, copies content across directly; a cross-variant pair, like `docx-to-pptx`, `xlsx-to-markdown`, or `odg-to-svg`, swaps the document's content variant through a semantic transform); each of those ten plus `odf` into pdf (`docx-to-pdf`, `xlsx-to-pdf`, `csv-to-pdf`, `svg-to-pdf`, `odf-to-pdf`, ...); and pdf back into the same ten (`pdf-to-docx`, `pdf-to-xlsx`, `pdf-to-csv`, `pdf-to-svg`, ... — there is no `pdf-to-odf`; `odf-to-pdf` is one-way, see documents.js's own README). Each takes `<input> [output]`:
|
|
83
83
|
|
|
84
84
|
```sh
|
|
85
85
|
document-cli docx-to-pdf report.docx report.pdf
|
|
@@ -95,7 +95,7 @@ document-cli convert report.docx - --to pdf > report.pdf
|
|
|
95
95
|
|
|
96
96
|
**`formats`** — lists every `source -> target` pair the commands above support (`--json` for a machine-readable array), plus a pointer to the commands not on that list because they don't fit the source/target shape (`odm-to-pdf`, `odb-to-csv`, `odb-to-xlsx`, `odb-tables`, `odb-forms`, `odb-reports`, `pdf-inspect`, `from-package`, `fonts`, `docx-extras`, `metadata`, `set-metadata`).
|
|
97
97
|
|
|
98
|
-
**`from-package <input> [output]`** — reads back a `DocumentPackage` JSON file a previous conversion wrote via `--dump-package` (below) and exports it to a real target format, closing the round trip `--dump-package` otherwise has no return path for. Target resolution matches `convert`: an output path's own extension, or `--to <format>` when it doesn't have one. `pdf` rebuilds the layout from the package's own recorded positions — each content node's `frames` plus the package's `pages` geometry (`layoutDocumentFromPackage` → `writePdf`; a package no longer carries a separate `layout` half at all); every other format builds a fresh package from the `content` half through the identical `buildXPackage` function the matching `pdf-to-X`/bridge conversion already uses — `xlsx` included, via `ooxml.js`'s own `buildXlsxPackage`. `odf` is the one target rejected outright, since a standalone formula document has no write path from `ContentDocument` at all. Only a file genuinely written by a current `--dump-package` round-trips here; anything else fails with its `$schema` mismatch named, and a dump from the documents.js 1.x `formatVersion` 1 shape (content plus a separate `layout` half) is rejected with an error naming the version change rather than silently accepted:
|
|
98
|
+
**`from-package <input> [output]`** — reads back a `DocumentPackage` JSON file a previous conversion wrote via `--dump-package` (below) and exports it to a real target format, closing the round trip `--dump-package` otherwise has no return path for. Target resolution matches `convert`: an output path's own extension, or `--to <format>` when it doesn't have one. `pdf` rebuilds the layout from the package's own recorded positions — each content node's `frames` plus the package's `pages` geometry (`layoutDocumentFromPackage` → `writePdf`; a package no longer carries a separate `layout` half at all); every other format builds a fresh package from the `content` half through the identical `buildXPackage` function the matching `pdf-to-X`/bridge conversion already uses — `xlsx` included, via `ooxml.js`'s own `buildXlsxPackage`. `odf` is the one target rejected outright, since a standalone formula document has no write path from `ContentDocument` at all; a `csv` or `svg` target is written through the identical `buildCsvText`/`buildSvgText` functions the codec registry's own write wrappers call, so the `--delimiter`/`--sheet`/`--page` selection flags below reach it exactly as they do a live conversion. Only a file genuinely written by a current `--dump-package` round-trips here; anything else fails with its `$schema` mismatch named, and a dump from the documents.js 1.x `formatVersion` 1 shape (content plus a separate `layout` half) is rejected with an error naming the version change rather than silently accepted:
|
|
99
99
|
|
|
100
100
|
```sh
|
|
101
101
|
document-cli docx-to-pdf report.docx report.pdf --dump-package report.package.json
|
|
@@ -139,7 +139,7 @@ document-cli pdf-inspect report.pdf
|
|
|
139
139
|
document-cli pdf-inspect report.pdf --json
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
**`fonts <input>`** — lists every source-embedded font face a docx/pptx/odt/odp/ods/odg document carries (family, weight/style, byte length) — the same embedded faces every `<format>-to-pdf` conversion already extracts and renders through automatically (see [Real fonts](#real-fonts) below); this command just reports what's there without converting anything. Rejects a format with no source-embedded-font concept at all (xlsx, pdf, markdown, odf), naming it:
|
|
142
|
+
**`fonts <input>`** — lists every source-embedded font face a docx/pptx/odt/odp/ods/odg document carries (family, weight/style, byte length) — the same embedded faces every `<format>-to-pdf` conversion already extracts and renders through automatically (see [Real fonts](#real-fonts) below); this command just reports what's there without converting anything. Rejects a format with no source-embedded-font concept at all (xlsx, csv, svg, pdf, markdown, odf), naming it:
|
|
143
143
|
|
|
144
144
|
```sh
|
|
145
145
|
document-cli fonts report.docx
|
|
@@ -151,13 +151,13 @@ document-cli fonts report.docx
|
|
|
151
151
|
document-cli docx-extras report.docx
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
-
**`metadata <input>`** — prints a document's own title/author/subject/keywords/creator/producer/created/modified metadata, for any of the
|
|
154
|
+
**`metadata <input>`** — prints a document's own title/author/subject/keywords/creator/producer/created/modified metadata, for any of the twelve supported formats (docx, pptx, xlsx, odt, odp, ods, odg, svg, odf, csv, markdown, pdf); csv and svg carry no metadata container of their own, so they always report none. `--json` emits the raw metadata object:
|
|
155
155
|
|
|
156
156
|
```sh
|
|
157
157
|
document-cli metadata report.pdf
|
|
158
158
|
```
|
|
159
159
|
|
|
160
|
-
**`set-metadata <input> [output]`** — patches a document's own title/author/subject/keywords, leaving every other field untouched (`--set-title`, `--set-author`, `--set-subject`, `--set-keywords` — the last a comma-separated list); source and target format must match, so run `convert`/`from-package` first if a different target format is also needed. A `pdf` source/target patches the parsed PDF directly (`writePdf`) with no layout engine involved — genuinely lossless for everything else on the page; every other format rebuilds a fresh package from that format's own `ContentDocument`, which for docx specifically is lossy (it drops everything `docx-extras` covers, since `buildDocxPackage` has no way to carry that data through a `ContentDocument`-only rebuild):
|
|
160
|
+
**`set-metadata <input> [output]`** — patches a document's own title/author/subject/keywords, leaving every other field untouched (`--set-title`, `--set-author`, `--set-subject`, `--set-keywords` — the last a comma-separated list); source and target format must match, so run `convert`/`from-package` first if a different target format is also needed. A `pdf` source/target patches the parsed PDF directly (`writePdf`) with no layout engine involved — genuinely lossless for everything else on the page; every other format rebuilds a fresh package from that format's own `ContentDocument`, which for docx specifically is lossy (it drops everything `docx-extras` covers, since `buildDocxPackage` has no way to carry that data through a `ContentDocument`-only rebuild); a `csv` or `svg` source/target is rejected outright, since plain text has no metadata container and a rebuild would silently drop the override:
|
|
161
161
|
|
|
162
162
|
```sh
|
|
163
163
|
document-cli set-metadata report.docx report.docx --set-title "Q3 Report" --set-author "Finance"
|
|
@@ -178,7 +178,9 @@ The explicit conversions, `convert`, `odm-to-pdf`, `odb-to-xlsx`, `odb-to-csv`,
|
|
|
178
178
|
| `-q, --quiet` | Suppress diagnostic and summary output (the JSON result-summary line still prints in `--json` mode, so a script consuming NDJSON always gets a terminating record). |
|
|
179
179
|
| `--verbose` | Include a full stack trace in the error line when the run fails. |
|
|
180
180
|
|
|
181
|
-
|
|
181
|
+
Three further flags select what a csv or svg edge of a conversion works on, threaded straight into documents.js's own `ConversionOptions`: `--delimiter <char>` (the field delimiter a csv source reads with, or a csv target writes with — default `,`), `--sheet <name>` (the sheet a csv target writes, required when the source document has more than one), and `--page <index>` (the 0-based page an svg target draws, required when the source document has more than one). On the explicit commands they are registered only where the pair can reach the edge in question — `--delimiter` on any pair with a csv edge, `--sheet` on a csv target, `--page` on an svg target — and unconditionally on `convert` and `from-package`, whose target is only known once the output path or `--to` resolves at run time (the same registration reasoning the font flags below document). Leaving `--sheet` or `--page` unanswered on an ambiguous document fails with exit `3`, naming the sheets or page count to pick from:
|
|
182
|
+
|
|
183
|
+
`--dump-package <file>` is one flag further, registered only on the explicit conversions and `convert` — it writes the intermediate `DocumentPackage` (content carrying its own per-node rendered `frames`, plus the `pages` geometry those frames index into) that conversion built to a JSON file, tagged with its own `$schema` so `from-package` (above) can read it back in. Every conversion populates one, `odf-to-pdf` included — its dump carries a `formula`-kind content and the one A4 page it renders (the formula's glyphs travel through the PDF writer's own positioned-formula channel rather than as frame-stamped page content); every PDF-bypassing bridge (`ods-to-xlsx`, `docx-to-pptx`, `odg-to-svg`, and every other content-format pair above) populates one too, just with `pages` always absent, since a bridge never runs a layout engine. `odm-to-pdf`/`odb-*`/`set-metadata` don't expose the flag at all, since none of them goes through `DocumentConverter.convert` in the first place. `odb-tables`, `odb-forms`, `odb-reports`, `fonts`, `docx-extras`, `metadata`, `formats`, and `pdf-inspect` each take only their own `--json` (plus `pdf-inspect`'s own `--full`); `odb-query` takes `--sql <text>`/`--query <savedName>` (mutually exclusive) alongside its own `--json`, with none of the shared flags above since it only reads and writes nothing; `from-package` and `set-metadata` each take `--to <format>` alongside the shared flags in this table; `odb-render-report` takes `--report <name>` and `--to <format>` alongside the shared flags and the font flags below; `tui` takes no flags at all, only an optional positional file.
|
|
182
184
|
|
|
183
185
|
### Real fonts
|
|
184
186
|
|
|
@@ -195,7 +197,7 @@ The flag is repeatable, takes a `.ttf`/`.otf` path, and needs **no accompanying
|
|
|
195
197
|
|
|
196
198
|
`--report-font-substitutions` prints each face that resolved to something other than what the document asked for, as it happens, with its structured fields intact (`--json` makes it one more NDJSON record: `{"type":"font-substitution","requestedFamily":"Calibri",…}`). Without it, the same fallbacks are still reported — the `font/substituted` diagnostic lines every conversion already emits — just as rendered messages after the fact rather than structured events as they occur.
|
|
197
199
|
|
|
198
|
-
Both flags are registered only where they can do something: the
|
|
200
|
+
Both flags are registered only where they can do something: the `<format>-to-pdf` conversions, `convert`, `odm-to-pdf`, and `odb-render-report`. The last two register them unconditionally (like `convert`, whose target isn't known until the output path or `--to` resolves) even though a `docx`/`odt` render has nothing to resolve fonts against — the same non-pdf no-op every other command in this list already documents. A `pdf-to-<format>` reconstruction reads a PDF's own already-positioned glyphs and a format-to-format bridge runs no layout engine at all, so neither resolves a typeface and neither advertises the flags.
|
|
199
201
|
|
|
200
202
|
Diagnostics and the summary line always go to stderr; stdout is reserved for the converted bytes on any command writing to `-`.
|
|
201
203
|
|
|
@@ -206,7 +208,7 @@ Diagnostics and the summary line always go to stderr; stdout is reserved for the
|
|
|
206
208
|
| `0` | Success. |
|
|
207
209
|
| `1` | The input was unusable — a malformed or encrypted PDF, or any other conversion failure not covered by the codes below. |
|
|
208
210
|
| `2` | A usage error — bad flags, conflicting output destinations, an unrecognised format, or (for a bare/`--help`/`--version` invocation) commander's own exit path. |
|
|
209
|
-
| `3` | documents.js needs more information to finish, not a different file — an unresolved `.odm` chapter, a `.odb` table that wasn't specified (or wasn't found, or has no embedded engine at all, or uses an unsupported HSQLDB script serialisation),
|
|
211
|
+
| `3` | documents.js needs more information to finish, not a different file — an unresolved `.odm` chapter, a `.odb` table that wasn't specified (or wasn't found, or has no embedded engine at all, or uses an unsupported HSQLDB script serialisation), a `.odb` report that wasn't specified when the database declares more than one, a csv target whose source carries more than one sheet (or a `--sheet` that names one it doesn't), or an svg target whose source carries more than one page (or a `--page` that indexes past the last). |
|
|
210
212
|
| `124` | The run's own `--timeout` elapsed before it finished. |
|
|
211
213
|
| `130` | Interrupted by `SIGINT` (Ctrl+C). |
|
|
212
214
|
|
|
@@ -218,7 +220,7 @@ It supports the same seven formats documents.js's live-view editors cover — do
|
|
|
218
220
|
|
|
219
221
|
Markdown (`.md`/`.markdown`) shares the same paragraph/run/table body-list screens docx and odt already use, through documents.js's own `MarkdownEditor` (`openMarkdown`/`createMarkdownEditor`) — a genuine live view over a mutable `ContentDocument`, the same live-view contract every other editor here follows, even though there is no `XmlElement` tree underneath it the way there is for docx/odt (`MarkdownEditor.toMarkdownText()` re-serialises the whole document fresh on every call, rather than exposing a `toBytes()`). Appending a paragraph, appending a run, and toggling bold/italic all go through the identical reducer actions docx/odt use; a markdown run has no underline, colour, font family, or font size at all (CommonMark/GFM has no construct for any of the four), so those keys — along with image insertion, which `MarkdownParagraph` has no counterpart for — are simply absent from a markdown paragraph's own key hints rather than opening a prompt that could only end in a warning. A markdown table can be created and its cells edited through the same 'T' wizard and table-view screens docx/odt use, but GFM tables have no cell-merge concept, so a merge requested alongside table creation still creates the table (unmerged) and reports why the merge itself didn't happen. `:view-source` (markdown documents only) shows the literal text the document was opened with side by side with what a save would write right now — these can genuinely differ even with no edits made this session, from a heading-style, bullet-marker, or line-ending choice the writer normalises. Every save re-serialises the whole document fresh through `buildMarkdownText`, a deliberate, permanent consequence of structured editing rather than something to work around. Diagnostics from the read side (a clamped heading level, a dropped front-matter key, a fenced code block's own info string with nowhere to go, …) now surface into the same diagnostics panel a PDF export's own substitutions already populate, the moment a `.md` file is opened, not only on export. documents.js's own `createMarkdownEditor()` exists now, but this TUI does not yet wire a "new markdown document" flow into `:new`/the new-document picker, so a markdown document can still only be opened from an existing file.
|
|
220
222
|
|
|
221
|
-
Three further
|
|
223
|
+
Three further kinds of format open read-only: a `.odb` browses its tables and rows with no write path at all (documents.js's own `.odb` support has no write direction to offer), a `.pdf` browses its pages and positioned items rather than being edited in place, and a `.xlsx`, `.csv`, or `.svg` opens as a converted PDF preview — documents.js has no spreadsheet or svg editor to hold a live view into, so opening one runs `xlsxToPdf`, `csvToPdf`, or `svgToPdf` once at open time and browses the result through the identical page-list/page-items/item-detail screens a real `.pdf` uses, with the original bytes kept alongside so a later export re-runs the same conversion with the caller's own fonts and diagnostics rather than reusing the fixed preview conversion. A `.odb` additionally browses its *structure* alongside its data: `f` from the table list opens the form browser and `r` the report browser, each listing what the database declares and opening one to show it in full — a form's own data source and field-bound controls (sub-forms nested under their parent), a report's data-source command, band and group structure, and every `rpt:` formula. Both are rendered through the same `src/odb-structure.ts` the `odb-forms`/`odb-reports` commands print, so the two views cannot drift apart, and search filters by line (`/SUM` narrows a long report to its aggregate expressions). `Enter` on a report's own detail screen renders it — its data-source command resolved, its `rpt:` formulas evaluated, its bands laid out — to a real `docx`/`odt`/`pdf` file, through the same two-field destination-path-then-font-list form the PDF-export screen below uses; the TUI counterpart to the `odb-render-report` command. A standalone `.odf` formula document has no TUI editor either — nothing to edit interactively, only a PDF conversion.
|
|
222
224
|
|
|
223
225
|
The export-to-PDF screen (`e` from any editor screen) is a two-field form: a destination path, then an optional comma-separated list of local `.ttf`/`.otf` paths, which are the same `--font-file` faces the CLI takes and are derived the same way — each font's family, weight, and slope come from the file itself. `Enter` on the path field moves to the fonts field and `Enter` there exports, so leaving fonts empty is still "type a path, press Enter twice". Comma-separated rather than space-separated because a font path routinely contains spaces and almost never a comma. A face falling back to a substitute is reported into the same diagnostics panel a character substitution already is, and a bad font path fails the export with the file named, before anything is written to the destination.
|
|
224
226
|
|
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as odbFormSummary, c as formatDocxExtrasLines, d as writeOutput, f as loadProvidedFonts, h as isDocumentFormat, i as formatOdbReportLines, l as readInput, m as inferFormatFromExtension, n as describeOdbReport, o as formatMetadataLines, r as formatOdbFormLines, s as presentMetadataEntries, t as describeOdbForm, u as resolveDefaultOutputPath } from "./odb-structure-
|
|
2
|
+
import { a as odbFormSummary, c as formatDocxExtrasLines, d as writeOutput, f as loadProvidedFonts, h as isDocumentFormat, i as formatOdbReportLines, l as readInput, m as inferFormatFromExtension, n as describeOdbReport, o as formatMetadataLines, r as formatOdbFormLines, s as presentMetadataEntries, t as describeOdbForm, u as resolveDefaultOutputPath } from "./odb-structure-B1ygPCEa.js";
|
|
3
3
|
import { Command, CommanderError, InvalidArgumentError } from "commander";
|
|
4
4
|
import { writeFile } from "node:fs/promises";
|
|
5
5
|
import { basename, dirname, extname, join, resolve } from "node:path";
|
|
6
|
-
import { HsqldbSqlEvaluationError, HsqldbSqlParseError, HsqldbSqlUnsupportedError, OdbNoEmbeddedDataSourceError, OdbReportNotSpecifiedError, OdbTableNotFoundError, OdbTableNotSpecifiedError, OdbUnsupportedFormatError, OdmUnresolvedSectionError, PdfEncryptedError, PdfParseError, UnrecognizedDocumentSchemaError, UnsupportedFontSourceFormatError, buildDocumentBytes, createLocalDocumentConverter, decodeOdbPackage, decodePackage, documentFromJson, documentPackageWithSchema, documentSchemaKindOf, evaluateSelect, extractSourceFontsForFormat, hsqldbCellDisplayText, layoutDocumentWithSchema, odbReportToDocx, odbReportToOdt, odbReportToPdf, odbToCsv, odbToXlsx, odmToPdf, parseSelect, readDocumentMetadata, readDocxExtras, readOdbForms, readOdbInventory, readOdbReportContent, readOdbReports, readOdbTables, readPdf, setDocumentMetadata } from "documents.js";
|
|
6
|
+
import { CsvSheetNotFoundError, CsvSheetNotSpecifiedError, HsqldbSqlEvaluationError, HsqldbSqlParseError, HsqldbSqlUnsupportedError, OdbNoEmbeddedDataSourceError, OdbReportNotSpecifiedError, OdbTableNotFoundError, OdbTableNotSpecifiedError, OdbUnsupportedFormatError, OdmUnresolvedSectionError, PdfEncryptedError, PdfParseError, SvgMultiPageNotSpecifiedError, SvgPageNotFoundError, UnrecognizedDocumentSchemaError, UnsupportedFontSourceFormatError, buildCsvText, buildDocumentBytes, buildSvgText, createLocalDocumentConverter, decodeOdbPackage, decodePackage, documentFromJson, documentPackageWithSchema, documentSchemaKindOf, encodeCsvText, encodeSvgText, evaluateSelect, extractSourceFontsForFormat, hsqldbCellDisplayText, layoutDocumentWithSchema, odbReportToDocx, odbReportToOdt, odbReportToPdf, odbToCsv, odbToXlsx, odmToPdf, parseSelect, readDocumentMetadata, readDocxExtras, readOdbForms, readOdbInventory, readOdbReportContent, readOdbReports, readOdbTables, readPdf, setDocumentMetadata } from "documents.js";
|
|
7
7
|
import { existsSync, readFileSync } from "node:fs";
|
|
8
8
|
//#region src/runtime/abort.ts
|
|
9
9
|
function combineSignals(a, b) {
|
|
@@ -113,7 +113,7 @@ function pdfDiagnosticToDiagnostic(diagnostic) {
|
|
|
113
113
|
function mapErrorToExit(error, abortReason) {
|
|
114
114
|
if (abortReason === "interrupt") return 130;
|
|
115
115
|
if (abortReason === "timeout") return 124;
|
|
116
|
-
if (error instanceof OdmUnresolvedSectionError || error instanceof OdbTableNotSpecifiedError || error instanceof OdbTableNotFoundError || error instanceof OdbNoEmbeddedDataSourceError || error instanceof OdbUnsupportedFormatError || error instanceof OdbReportNotSpecifiedError) return 3;
|
|
116
|
+
if (error instanceof OdmUnresolvedSectionError || error instanceof OdbTableNotSpecifiedError || error instanceof OdbTableNotFoundError || error instanceof OdbNoEmbeddedDataSourceError || error instanceof OdbUnsupportedFormatError || error instanceof OdbReportNotSpecifiedError || error instanceof CsvSheetNotSpecifiedError || error instanceof CsvSheetNotFoundError || error instanceof SvgMultiPageNotSpecifiedError || error instanceof SvgPageNotFoundError) return 3;
|
|
117
117
|
if (error instanceof HsqldbSqlUnsupportedError || error instanceof HsqldbSqlParseError || error instanceof HsqldbSqlEvaluationError) return 1;
|
|
118
118
|
if (error instanceof UnsupportedFontSourceFormatError) return 2;
|
|
119
119
|
if (error instanceof PdfEncryptedError || error instanceof PdfParseError) return 1;
|
|
@@ -133,7 +133,7 @@ function createFilesystemMarkdownImageResolver(baseDir) {
|
|
|
133
133
|
}
|
|
134
134
|
//#endregion
|
|
135
135
|
//#region src/commands/shared.ts
|
|
136
|
-
const KNOWN_DOCUMENT_FORMATS = "docx, pptx, xlsx, odt, odp, ods, odg, odf, markdown, pdf";
|
|
136
|
+
const KNOWN_DOCUMENT_FORMATS = "docx, pptx, xlsx, odt, odp, ods, odg, svg, odf, csv, markdown, pdf";
|
|
137
137
|
function resolveTargetFormat(output, out, to) {
|
|
138
138
|
if (to !== void 0) {
|
|
139
139
|
if (!isDocumentFormat(to)) return { errorMessage: `unknown --to format '${to}'; expected one of ${KNOWN_DOCUMENT_FORMATS}` };
|
|
@@ -176,7 +176,10 @@ function buildConversionAction(source, target) {
|
|
|
176
176
|
quiet: options.quiet,
|
|
177
177
|
command
|
|
178
178
|
}) : void 0,
|
|
179
|
-
images: createFilesystemMarkdownImageResolver(input === "-" ? "." : dirname(resolve(input)))
|
|
179
|
+
images: createFilesystemMarkdownImageResolver(input === "-" ? "." : dirname(resolve(input))),
|
|
180
|
+
delimiter: options.delimiter,
|
|
181
|
+
sheet: options.sheet,
|
|
182
|
+
page: options.page
|
|
180
183
|
});
|
|
181
184
|
await writeOutput(resolvedOutput, result.document.bytes);
|
|
182
185
|
const reporter = createDiagnosticReporter({
|
|
@@ -235,6 +238,15 @@ function addConversionFlags(command) {
|
|
|
235
238
|
addVerboseOption(command);
|
|
236
239
|
return command;
|
|
237
240
|
}
|
|
241
|
+
function addDelimiterOption(command) {
|
|
242
|
+
return command.option("--delimiter <char>", "field delimiter a csv source reads with, or a csv target writes with (default ',')");
|
|
243
|
+
}
|
|
244
|
+
function addSheetOption(command) {
|
|
245
|
+
return command.option("--sheet <name>", "the sheet a csv target writes, when the source document has more than one");
|
|
246
|
+
}
|
|
247
|
+
function addPageOption(command) {
|
|
248
|
+
return command.option("--page <index>", "the 0-based page an svg target draws, when the source document has more than one", (value) => Number.parseInt(value, 10));
|
|
249
|
+
}
|
|
238
250
|
//#endregion
|
|
239
251
|
//#region src/commands/convert.ts
|
|
240
252
|
function toConversionCommandOptions(options) {
|
|
@@ -246,7 +258,10 @@ function toConversionCommandOptions(options) {
|
|
|
246
258
|
verbose: options.verbose,
|
|
247
259
|
dumpPackage: options.dumpPackage,
|
|
248
260
|
fontFiles: options.fontFile,
|
|
249
|
-
reportFontSubstitutions: options.reportFontSubstitutions
|
|
261
|
+
reportFontSubstitutions: options.reportFontSubstitutions,
|
|
262
|
+
delimiter: options.delimiter,
|
|
263
|
+
sheet: options.sheet,
|
|
264
|
+
page: options.page
|
|
250
265
|
};
|
|
251
266
|
}
|
|
252
267
|
async function runGenericConvert(input, output, options) {
|
|
@@ -279,6 +294,9 @@ function registerConversionCommands(program) {
|
|
|
279
294
|
addConversionFlags(command);
|
|
280
295
|
addDumpPackageOption(command);
|
|
281
296
|
if (target === "pdf") addFontOptions(command);
|
|
297
|
+
if (source === "csv" || target === "csv") addDelimiterOption(command);
|
|
298
|
+
if (target === "csv") addSheetOption(command);
|
|
299
|
+
if (target === "svg") addPageOption(command);
|
|
282
300
|
command.action(async (input, output, options) => {
|
|
283
301
|
process.exitCode = await buildConversionAction(source, target)(input, output, toConversionCommandOptions(options));
|
|
284
302
|
});
|
|
@@ -287,6 +305,9 @@ function registerConversionCommands(program) {
|
|
|
287
305
|
addConversionFlags(generic);
|
|
288
306
|
addDumpPackageOption(generic);
|
|
289
307
|
addFontOptions(generic);
|
|
308
|
+
addDelimiterOption(generic);
|
|
309
|
+
addSheetOption(generic);
|
|
310
|
+
addPageOption(generic);
|
|
290
311
|
generic.option("--to <format>", `target format when it cannot be inferred from the output path (${KNOWN_DOCUMENT_FORMATS})`);
|
|
291
312
|
generic.action(async (input, output, options) => {
|
|
292
313
|
process.exitCode = await runGenericConvert(input, output, options);
|
|
@@ -411,7 +432,10 @@ async function runFromPackage(input, output, options) {
|
|
|
411
432
|
process.stderr.write(`[${command}] '${input}' is a ${result.kind}, not a DocumentPackage -- only a file written by --dump-package can be read back by this command\n`);
|
|
412
433
|
return 2;
|
|
413
434
|
}
|
|
414
|
-
const bytes =
|
|
435
|
+
const bytes = target.format === "csv" ? encodeCsvText(buildCsvText(result.value.content, {
|
|
436
|
+
delimiter: options.delimiter,
|
|
437
|
+
sheet: options.sheet
|
|
438
|
+
})) : target.format === "svg" ? encodeSvgText(buildSvgText(result.value.content, { page: options.page })) : buildDocumentBytes(result.value, target.format);
|
|
415
439
|
await writeOutput(resolvedOutput, bytes);
|
|
416
440
|
createDiagnosticReporter({
|
|
417
441
|
json: options.json,
|
|
@@ -439,6 +463,9 @@ function registerFromPackageCommand(program) {
|
|
|
439
463
|
addJsonOption(command);
|
|
440
464
|
addQuietOption(command);
|
|
441
465
|
addVerboseOption(command);
|
|
466
|
+
addDelimiterOption(command);
|
|
467
|
+
addSheetOption(command);
|
|
468
|
+
addPageOption(command);
|
|
442
469
|
command.option("--to <format>", `target format when it cannot be inferred from the output path (${KNOWN_DOCUMENT_FORMATS})`);
|
|
443
470
|
command.action(async (input, output, options) => {
|
|
444
471
|
process.exitCode = await runFromPackage(input, output, options);
|
|
@@ -1068,12 +1095,12 @@ function registerSetMetadataCommand(program) {
|
|
|
1068
1095
|
}
|
|
1069
1096
|
//#endregion
|
|
1070
1097
|
//#region package.json
|
|
1071
|
-
var version = "2.
|
|
1098
|
+
var version = "2.1.1";
|
|
1072
1099
|
//#endregion
|
|
1073
1100
|
//#region src/program.ts
|
|
1074
1101
|
function createProgram() {
|
|
1075
1102
|
const program = new Command("document-cli");
|
|
1076
|
-
program.description("every documents.js docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/markdown conversion, bridge, and inspector as a scriptable command");
|
|
1103
|
+
program.description("every documents.js docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/csv/svg/markdown conversion, bridge, and inspector as a scriptable command");
|
|
1077
1104
|
program.version(version);
|
|
1078
1105
|
program.exitOverride((error) => {
|
|
1079
1106
|
process.exitCode = error.exitCode === 0 ? 0 : 2;
|
|
@@ -1095,7 +1122,7 @@ function createProgram() {
|
|
|
1095
1122
|
//#region src/cli.ts
|
|
1096
1123
|
async function launchTui(startPath, signal) {
|
|
1097
1124
|
try {
|
|
1098
|
-
const { runTui } = await import("./tui-
|
|
1125
|
+
const { runTui } = await import("./tui-tT3An-cI.js");
|
|
1099
1126
|
await runTui({
|
|
1100
1127
|
startPath,
|
|
1101
1128
|
signal
|
package/dist/index.cjs
CHANGED
|
@@ -25,6 +25,8 @@ const EXTENSION_TO_FORMAT = {
|
|
|
25
25
|
otg: "odg",
|
|
26
26
|
odf: "odf",
|
|
27
27
|
otf: "odf",
|
|
28
|
+
csv: "csv",
|
|
29
|
+
svg: "svg",
|
|
28
30
|
markdown: "markdown",
|
|
29
31
|
md: "markdown",
|
|
30
32
|
pdf: "pdf"
|
|
@@ -38,6 +40,8 @@ const FORMAT_TO_EXTENSION = {
|
|
|
38
40
|
ods: "ods",
|
|
39
41
|
odg: "odg",
|
|
40
42
|
odf: "odf",
|
|
43
|
+
csv: "csv",
|
|
44
|
+
svg: "svg",
|
|
41
45
|
markdown: "md",
|
|
42
46
|
pdf: "pdf"
|
|
43
47
|
};
|
|
@@ -172,7 +176,7 @@ const EXIT_INTERRUPTED = 130;
|
|
|
172
176
|
function mapErrorToExit(error, abortReason) {
|
|
173
177
|
if (abortReason === "interrupt") return 130;
|
|
174
178
|
if (abortReason === "timeout") return 124;
|
|
175
|
-
if (error instanceof documents_js.OdmUnresolvedSectionError || error instanceof documents_js.OdbTableNotSpecifiedError || error instanceof documents_js.OdbTableNotFoundError || error instanceof documents_js.OdbNoEmbeddedDataSourceError || error instanceof documents_js.OdbUnsupportedFormatError || error instanceof documents_js.OdbReportNotSpecifiedError) return 3;
|
|
179
|
+
if (error instanceof documents_js.OdmUnresolvedSectionError || error instanceof documents_js.OdbTableNotSpecifiedError || error instanceof documents_js.OdbTableNotFoundError || error instanceof documents_js.OdbNoEmbeddedDataSourceError || error instanceof documents_js.OdbUnsupportedFormatError || error instanceof documents_js.OdbReportNotSpecifiedError || error instanceof documents_js.CsvSheetNotSpecifiedError || error instanceof documents_js.CsvSheetNotFoundError || error instanceof documents_js.SvgMultiPageNotSpecifiedError || error instanceof documents_js.SvgPageNotFoundError) return 3;
|
|
176
180
|
if (error instanceof documents_js.HsqldbSqlUnsupportedError || error instanceof documents_js.HsqldbSqlParseError || error instanceof documents_js.HsqldbSqlEvaluationError) return 1;
|
|
177
181
|
if (error instanceof documents_js.UnsupportedFontSourceFormatError) return 2;
|
|
178
182
|
if (error instanceof documents_js.PdfEncryptedError || error instanceof documents_js.PdfParseError) return 1;
|
|
@@ -247,7 +251,7 @@ function resolveDefaultOutputPath(inputPath, targetFormat) {
|
|
|
247
251
|
}
|
|
248
252
|
//#endregion
|
|
249
253
|
//#region src/commands/shared.ts
|
|
250
|
-
const KNOWN_DOCUMENT_FORMATS = "docx, pptx, xlsx, odt, odp, ods, odg, odf, markdown, pdf";
|
|
254
|
+
const KNOWN_DOCUMENT_FORMATS = "docx, pptx, xlsx, odt, odp, ods, odg, svg, odf, csv, markdown, pdf";
|
|
251
255
|
function resolveTargetFormat(output, out, to) {
|
|
252
256
|
if (to !== void 0) {
|
|
253
257
|
if (!isDocumentFormat(to)) return { errorMessage: `unknown --to format '${to}'; expected one of ${KNOWN_DOCUMENT_FORMATS}` };
|
|
@@ -290,7 +294,10 @@ function buildConversionAction(source, target) {
|
|
|
290
294
|
quiet: options.quiet,
|
|
291
295
|
command
|
|
292
296
|
}) : void 0,
|
|
293
|
-
images: createFilesystemMarkdownImageResolver(input === "-" ? "." : (0, node_path.dirname)((0, node_path.resolve)(input)))
|
|
297
|
+
images: createFilesystemMarkdownImageResolver(input === "-" ? "." : (0, node_path.dirname)((0, node_path.resolve)(input))),
|
|
298
|
+
delimiter: options.delimiter,
|
|
299
|
+
sheet: options.sheet,
|
|
300
|
+
page: options.page
|
|
294
301
|
});
|
|
295
302
|
await writeOutput(resolvedOutput, result.document.bytes);
|
|
296
303
|
const reporter = createDiagnosticReporter({
|
|
@@ -349,6 +356,15 @@ function addConversionFlags(command) {
|
|
|
349
356
|
addVerboseOption(command);
|
|
350
357
|
return command;
|
|
351
358
|
}
|
|
359
|
+
function addDelimiterOption(command) {
|
|
360
|
+
return command.option("--delimiter <char>", "field delimiter a csv source reads with, or a csv target writes with (default ',')");
|
|
361
|
+
}
|
|
362
|
+
function addSheetOption(command) {
|
|
363
|
+
return command.option("--sheet <name>", "the sheet a csv target writes, when the source document has more than one");
|
|
364
|
+
}
|
|
365
|
+
function addPageOption(command) {
|
|
366
|
+
return command.option("--page <index>", "the 0-based page an svg target draws, when the source document has more than one", (value) => Number.parseInt(value, 10));
|
|
367
|
+
}
|
|
352
368
|
//#endregion
|
|
353
369
|
//#region src/commands/convert.ts
|
|
354
370
|
function toConversionCommandOptions(options) {
|
|
@@ -360,7 +376,10 @@ function toConversionCommandOptions(options) {
|
|
|
360
376
|
verbose: options.verbose,
|
|
361
377
|
dumpPackage: options.dumpPackage,
|
|
362
378
|
fontFiles: options.fontFile,
|
|
363
|
-
reportFontSubstitutions: options.reportFontSubstitutions
|
|
379
|
+
reportFontSubstitutions: options.reportFontSubstitutions,
|
|
380
|
+
delimiter: options.delimiter,
|
|
381
|
+
sheet: options.sheet,
|
|
382
|
+
page: options.page
|
|
364
383
|
};
|
|
365
384
|
}
|
|
366
385
|
async function runGenericConvert(input, output, options) {
|
|
@@ -393,6 +412,9 @@ function registerConversionCommands(program) {
|
|
|
393
412
|
addConversionFlags(command);
|
|
394
413
|
addDumpPackageOption(command);
|
|
395
414
|
if (target === "pdf") addFontOptions(command);
|
|
415
|
+
if (source === "csv" || target === "csv") addDelimiterOption(command);
|
|
416
|
+
if (target === "csv") addSheetOption(command);
|
|
417
|
+
if (target === "svg") addPageOption(command);
|
|
396
418
|
command.action(async (input, output, options) => {
|
|
397
419
|
process.exitCode = await buildConversionAction(source, target)(input, output, toConversionCommandOptions(options));
|
|
398
420
|
});
|
|
@@ -401,6 +423,9 @@ function registerConversionCommands(program) {
|
|
|
401
423
|
addConversionFlags(generic);
|
|
402
424
|
addDumpPackageOption(generic);
|
|
403
425
|
addFontOptions(generic);
|
|
426
|
+
addDelimiterOption(generic);
|
|
427
|
+
addSheetOption(generic);
|
|
428
|
+
addPageOption(generic);
|
|
404
429
|
generic.option("--to <format>", `target format when it cannot be inferred from the output path (${KNOWN_DOCUMENT_FORMATS})`);
|
|
405
430
|
generic.action(async (input, output, options) => {
|
|
406
431
|
process.exitCode = await runGenericConvert(input, output, options);
|
|
@@ -583,7 +608,10 @@ async function runFromPackage(input, output, options) {
|
|
|
583
608
|
process.stderr.write(`[${command}] '${input}' is a ${result.kind}, not a DocumentPackage -- only a file written by --dump-package can be read back by this command\n`);
|
|
584
609
|
return 2;
|
|
585
610
|
}
|
|
586
|
-
const bytes = (0, documents_js.
|
|
611
|
+
const bytes = target.format === "csv" ? (0, documents_js.encodeCsvText)((0, documents_js.buildCsvText)(result.value.content, {
|
|
612
|
+
delimiter: options.delimiter,
|
|
613
|
+
sheet: options.sheet
|
|
614
|
+
})) : target.format === "svg" ? (0, documents_js.encodeSvgText)((0, documents_js.buildSvgText)(result.value.content, { page: options.page })) : (0, documents_js.buildDocumentBytes)(result.value, target.format);
|
|
587
615
|
await writeOutput(resolvedOutput, bytes);
|
|
588
616
|
createDiagnosticReporter({
|
|
589
617
|
json: options.json,
|
|
@@ -611,6 +639,9 @@ function registerFromPackageCommand(program) {
|
|
|
611
639
|
addJsonOption(command);
|
|
612
640
|
addQuietOption(command);
|
|
613
641
|
addVerboseOption(command);
|
|
642
|
+
addDelimiterOption(command);
|
|
643
|
+
addSheetOption(command);
|
|
644
|
+
addPageOption(command);
|
|
614
645
|
command.option("--to <format>", `target format when it cannot be inferred from the output path (${KNOWN_DOCUMENT_FORMATS})`);
|
|
615
646
|
command.action(async (input, output, options) => {
|
|
616
647
|
process.exitCode = await runFromPackage(input, output, options);
|
|
@@ -1396,12 +1427,12 @@ function registerSetMetadataCommand(program) {
|
|
|
1396
1427
|
}
|
|
1397
1428
|
//#endregion
|
|
1398
1429
|
//#region package.json
|
|
1399
|
-
var version = "2.
|
|
1430
|
+
var version = "2.1.1";
|
|
1400
1431
|
//#endregion
|
|
1401
1432
|
//#region src/program.ts
|
|
1402
1433
|
function createProgram() {
|
|
1403
1434
|
const program = new commander.Command("document-cli");
|
|
1404
|
-
program.description("every documents.js docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/markdown conversion, bridge, and inspector as a scriptable command");
|
|
1435
|
+
program.description("every documents.js docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/csv/svg/markdown conversion, bridge, and inspector as a scriptable command");
|
|
1405
1436
|
program.version(version);
|
|
1406
1437
|
program.exitOverride((error) => {
|
|
1407
1438
|
process.exitCode = error.exitCode === 0 ? 0 : 2;
|
package/dist/index.d.cts
CHANGED
|
@@ -15,6 +15,9 @@ interface ConversionCommandOptions {
|
|
|
15
15
|
readonly dumpPackage?: string;
|
|
16
16
|
readonly fontFiles?: readonly string[];
|
|
17
17
|
readonly reportFontSubstitutions?: boolean;
|
|
18
|
+
readonly delimiter?: string;
|
|
19
|
+
readonly sheet?: string;
|
|
20
|
+
readonly page?: number;
|
|
18
21
|
}
|
|
19
22
|
declare function formatError(error: unknown, verbose: boolean): string;
|
|
20
23
|
declare function buildConversionAction(source: DocumentFormat, target: DocumentFormat): (input: string, output: string | undefined, options: ConversionCommandOptions) => Promise<number>;
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,9 @@ interface ConversionCommandOptions {
|
|
|
15
15
|
readonly dumpPackage?: string;
|
|
16
16
|
readonly fontFiles?: readonly string[];
|
|
17
17
|
readonly reportFontSubstitutions?: boolean;
|
|
18
|
+
readonly delimiter?: string;
|
|
19
|
+
readonly sheet?: string;
|
|
20
|
+
readonly page?: number;
|
|
18
21
|
}
|
|
19
22
|
declare function formatError(error: unknown, verbose: boolean): string;
|
|
20
23
|
declare function buildConversionAction(source: DocumentFormat, target: DocumentFormat): (input: string, output: string | undefined, options: ConversionCommandOptions) => Promise<number>;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { basename, dirname, extname, join, resolve } from "node:path";
|
|
3
|
-
import { HsqldbSqlEvaluationError, HsqldbSqlParseError, HsqldbSqlUnsupportedError, OdbNoEmbeddedDataSourceError, OdbReportNotSpecifiedError, OdbTableNotFoundError, OdbTableNotSpecifiedError, OdbUnsupportedFormatError, OdmUnresolvedSectionError, PdfEncryptedError, PdfParseError, UnrecognizedDocumentSchemaError, UnsupportedFontSourceFormatError, buildDocumentBytes, createLocalDocumentConverter, decodeOdbPackage, decodePackage, describeFontFace, documentFromJson, documentPackageWithSchema, documentSchemaKindOf, evaluateSelect, extractSourceFontsForFormat, hsqldbCellDisplayText, layoutDocumentWithSchema, odbReportToDocx, odbReportToOdt, odbReportToPdf, odbToCsv, odbToXlsx, odmToPdf, parseSelect, readDocumentMetadata, readDocxExtras, readOdbForms, readOdbInventory, readOdbReportContent, readOdbReports, readOdbTables, readPdf, setDocumentMetadata } from "documents.js";
|
|
3
|
+
import { CsvSheetNotFoundError, CsvSheetNotSpecifiedError, HsqldbSqlEvaluationError, HsqldbSqlParseError, HsqldbSqlUnsupportedError, OdbNoEmbeddedDataSourceError, OdbReportNotSpecifiedError, OdbTableNotFoundError, OdbTableNotSpecifiedError, OdbUnsupportedFormatError, OdmUnresolvedSectionError, PdfEncryptedError, PdfParseError, SvgMultiPageNotSpecifiedError, SvgPageNotFoundError, UnrecognizedDocumentSchemaError, UnsupportedFontSourceFormatError, buildCsvText, buildDocumentBytes, buildSvgText, createLocalDocumentConverter, decodeOdbPackage, decodePackage, describeFontFace, documentFromJson, documentPackageWithSchema, documentSchemaKindOf, encodeCsvText, encodeSvgText, evaluateSelect, extractSourceFontsForFormat, hsqldbCellDisplayText, layoutDocumentWithSchema, odbReportToDocx, odbReportToOdt, odbReportToPdf, odbToCsv, odbToXlsx, odmToPdf, parseSelect, readDocumentMetadata, readDocxExtras, readOdbForms, readOdbInventory, readOdbReportContent, readOdbReports, readOdbTables, readPdf, setDocumentMetadata } from "documents.js";
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
import { Command, InvalidArgumentError } from "commander";
|
|
6
6
|
//#region src/format.ts
|
|
@@ -24,6 +24,8 @@ const EXTENSION_TO_FORMAT = {
|
|
|
24
24
|
otg: "odg",
|
|
25
25
|
odf: "odf",
|
|
26
26
|
otf: "odf",
|
|
27
|
+
csv: "csv",
|
|
28
|
+
svg: "svg",
|
|
27
29
|
markdown: "markdown",
|
|
28
30
|
md: "markdown",
|
|
29
31
|
pdf: "pdf"
|
|
@@ -37,6 +39,8 @@ const FORMAT_TO_EXTENSION = {
|
|
|
37
39
|
ods: "ods",
|
|
38
40
|
odg: "odg",
|
|
39
41
|
odf: "odf",
|
|
42
|
+
csv: "csv",
|
|
43
|
+
svg: "svg",
|
|
40
44
|
markdown: "md",
|
|
41
45
|
pdf: "pdf"
|
|
42
46
|
};
|
|
@@ -171,7 +175,7 @@ const EXIT_INTERRUPTED = 130;
|
|
|
171
175
|
function mapErrorToExit(error, abortReason) {
|
|
172
176
|
if (abortReason === "interrupt") return 130;
|
|
173
177
|
if (abortReason === "timeout") return 124;
|
|
174
|
-
if (error instanceof OdmUnresolvedSectionError || error instanceof OdbTableNotSpecifiedError || error instanceof OdbTableNotFoundError || error instanceof OdbNoEmbeddedDataSourceError || error instanceof OdbUnsupportedFormatError || error instanceof OdbReportNotSpecifiedError) return 3;
|
|
178
|
+
if (error instanceof OdmUnresolvedSectionError || error instanceof OdbTableNotSpecifiedError || error instanceof OdbTableNotFoundError || error instanceof OdbNoEmbeddedDataSourceError || error instanceof OdbUnsupportedFormatError || error instanceof OdbReportNotSpecifiedError || error instanceof CsvSheetNotSpecifiedError || error instanceof CsvSheetNotFoundError || error instanceof SvgMultiPageNotSpecifiedError || error instanceof SvgPageNotFoundError) return 3;
|
|
175
179
|
if (error instanceof HsqldbSqlUnsupportedError || error instanceof HsqldbSqlParseError || error instanceof HsqldbSqlEvaluationError) return 1;
|
|
176
180
|
if (error instanceof UnsupportedFontSourceFormatError) return 2;
|
|
177
181
|
if (error instanceof PdfEncryptedError || error instanceof PdfParseError) return 1;
|
|
@@ -246,7 +250,7 @@ function resolveDefaultOutputPath(inputPath, targetFormat) {
|
|
|
246
250
|
}
|
|
247
251
|
//#endregion
|
|
248
252
|
//#region src/commands/shared.ts
|
|
249
|
-
const KNOWN_DOCUMENT_FORMATS = "docx, pptx, xlsx, odt, odp, ods, odg, odf, markdown, pdf";
|
|
253
|
+
const KNOWN_DOCUMENT_FORMATS = "docx, pptx, xlsx, odt, odp, ods, odg, svg, odf, csv, markdown, pdf";
|
|
250
254
|
function resolveTargetFormat(output, out, to) {
|
|
251
255
|
if (to !== void 0) {
|
|
252
256
|
if (!isDocumentFormat(to)) return { errorMessage: `unknown --to format '${to}'; expected one of ${KNOWN_DOCUMENT_FORMATS}` };
|
|
@@ -289,7 +293,10 @@ function buildConversionAction(source, target) {
|
|
|
289
293
|
quiet: options.quiet,
|
|
290
294
|
command
|
|
291
295
|
}) : void 0,
|
|
292
|
-
images: createFilesystemMarkdownImageResolver(input === "-" ? "." : dirname(resolve(input)))
|
|
296
|
+
images: createFilesystemMarkdownImageResolver(input === "-" ? "." : dirname(resolve(input))),
|
|
297
|
+
delimiter: options.delimiter,
|
|
298
|
+
sheet: options.sheet,
|
|
299
|
+
page: options.page
|
|
293
300
|
});
|
|
294
301
|
await writeOutput(resolvedOutput, result.document.bytes);
|
|
295
302
|
const reporter = createDiagnosticReporter({
|
|
@@ -348,6 +355,15 @@ function addConversionFlags(command) {
|
|
|
348
355
|
addVerboseOption(command);
|
|
349
356
|
return command;
|
|
350
357
|
}
|
|
358
|
+
function addDelimiterOption(command) {
|
|
359
|
+
return command.option("--delimiter <char>", "field delimiter a csv source reads with, or a csv target writes with (default ',')");
|
|
360
|
+
}
|
|
361
|
+
function addSheetOption(command) {
|
|
362
|
+
return command.option("--sheet <name>", "the sheet a csv target writes, when the source document has more than one");
|
|
363
|
+
}
|
|
364
|
+
function addPageOption(command) {
|
|
365
|
+
return command.option("--page <index>", "the 0-based page an svg target draws, when the source document has more than one", (value) => Number.parseInt(value, 10));
|
|
366
|
+
}
|
|
351
367
|
//#endregion
|
|
352
368
|
//#region src/commands/convert.ts
|
|
353
369
|
function toConversionCommandOptions(options) {
|
|
@@ -359,7 +375,10 @@ function toConversionCommandOptions(options) {
|
|
|
359
375
|
verbose: options.verbose,
|
|
360
376
|
dumpPackage: options.dumpPackage,
|
|
361
377
|
fontFiles: options.fontFile,
|
|
362
|
-
reportFontSubstitutions: options.reportFontSubstitutions
|
|
378
|
+
reportFontSubstitutions: options.reportFontSubstitutions,
|
|
379
|
+
delimiter: options.delimiter,
|
|
380
|
+
sheet: options.sheet,
|
|
381
|
+
page: options.page
|
|
363
382
|
};
|
|
364
383
|
}
|
|
365
384
|
async function runGenericConvert(input, output, options) {
|
|
@@ -392,6 +411,9 @@ function registerConversionCommands(program) {
|
|
|
392
411
|
addConversionFlags(command);
|
|
393
412
|
addDumpPackageOption(command);
|
|
394
413
|
if (target === "pdf") addFontOptions(command);
|
|
414
|
+
if (source === "csv" || target === "csv") addDelimiterOption(command);
|
|
415
|
+
if (target === "csv") addSheetOption(command);
|
|
416
|
+
if (target === "svg") addPageOption(command);
|
|
395
417
|
command.action(async (input, output, options) => {
|
|
396
418
|
process.exitCode = await buildConversionAction(source, target)(input, output, toConversionCommandOptions(options));
|
|
397
419
|
});
|
|
@@ -400,6 +422,9 @@ function registerConversionCommands(program) {
|
|
|
400
422
|
addConversionFlags(generic);
|
|
401
423
|
addDumpPackageOption(generic);
|
|
402
424
|
addFontOptions(generic);
|
|
425
|
+
addDelimiterOption(generic);
|
|
426
|
+
addSheetOption(generic);
|
|
427
|
+
addPageOption(generic);
|
|
403
428
|
generic.option("--to <format>", `target format when it cannot be inferred from the output path (${KNOWN_DOCUMENT_FORMATS})`);
|
|
404
429
|
generic.action(async (input, output, options) => {
|
|
405
430
|
process.exitCode = await runGenericConvert(input, output, options);
|
|
@@ -582,7 +607,10 @@ async function runFromPackage(input, output, options) {
|
|
|
582
607
|
process.stderr.write(`[${command}] '${input}' is a ${result.kind}, not a DocumentPackage -- only a file written by --dump-package can be read back by this command\n`);
|
|
583
608
|
return 2;
|
|
584
609
|
}
|
|
585
|
-
const bytes =
|
|
610
|
+
const bytes = target.format === "csv" ? encodeCsvText(buildCsvText(result.value.content, {
|
|
611
|
+
delimiter: options.delimiter,
|
|
612
|
+
sheet: options.sheet
|
|
613
|
+
})) : target.format === "svg" ? encodeSvgText(buildSvgText(result.value.content, { page: options.page })) : buildDocumentBytes(result.value, target.format);
|
|
586
614
|
await writeOutput(resolvedOutput, bytes);
|
|
587
615
|
createDiagnosticReporter({
|
|
588
616
|
json: options.json,
|
|
@@ -610,6 +638,9 @@ function registerFromPackageCommand(program) {
|
|
|
610
638
|
addJsonOption(command);
|
|
611
639
|
addQuietOption(command);
|
|
612
640
|
addVerboseOption(command);
|
|
641
|
+
addDelimiterOption(command);
|
|
642
|
+
addSheetOption(command);
|
|
643
|
+
addPageOption(command);
|
|
613
644
|
command.option("--to <format>", `target format when it cannot be inferred from the output path (${KNOWN_DOCUMENT_FORMATS})`);
|
|
614
645
|
command.action(async (input, output, options) => {
|
|
615
646
|
process.exitCode = await runFromPackage(input, output, options);
|
|
@@ -1395,12 +1426,12 @@ function registerSetMetadataCommand(program) {
|
|
|
1395
1426
|
}
|
|
1396
1427
|
//#endregion
|
|
1397
1428
|
//#region package.json
|
|
1398
|
-
var version = "2.
|
|
1429
|
+
var version = "2.1.1";
|
|
1399
1430
|
//#endregion
|
|
1400
1431
|
//#region src/program.ts
|
|
1401
1432
|
function createProgram() {
|
|
1402
1433
|
const program = new Command("document-cli");
|
|
1403
|
-
program.description("every documents.js docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/markdown conversion, bridge, and inspector as a scriptable command");
|
|
1434
|
+
program.description("every documents.js docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/csv/svg/markdown conversion, bridge, and inspector as a scriptable command");
|
|
1404
1435
|
program.version(version);
|
|
1405
1436
|
program.exitOverride((error) => {
|
|
1406
1437
|
process.exitCode = error.exitCode === 0 ? 0 : 2;
|
|
@@ -22,6 +22,8 @@ const EXTENSION_TO_FORMAT = {
|
|
|
22
22
|
otg: "odg",
|
|
23
23
|
odf: "odf",
|
|
24
24
|
otf: "odf",
|
|
25
|
+
csv: "csv",
|
|
26
|
+
svg: "svg",
|
|
25
27
|
markdown: "markdown",
|
|
26
28
|
md: "markdown",
|
|
27
29
|
pdf: "pdf"
|
|
@@ -35,6 +37,8 @@ const FORMAT_TO_EXTENSION = {
|
|
|
35
37
|
ods: "ods",
|
|
36
38
|
odg: "odg",
|
|
37
39
|
odf: "odf",
|
|
40
|
+
csv: "csv",
|
|
41
|
+
svg: "svg",
|
|
38
42
|
markdown: "md",
|
|
39
43
|
pdf: "pdf"
|
|
40
44
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { c as formatDocxExtrasLines, f as loadProvidedFonts, i as formatOdbReportLines, l as readInput, m as inferFormatFromExtension, n as describeOdbReport, o as formatMetadataLines, p as formatToExtension, r as formatOdbFormLines, t as describeOdbForm } from "./odb-structure-
|
|
1
|
+
import { c as formatDocxExtrasLines, f as loadProvidedFonts, i as formatOdbReportLines, l as readInput, m as inferFormatFromExtension, n as describeOdbReport, o as formatMetadataLines, p as formatToExtension, r as formatOdbFormLines, t as describeOdbForm } from "./odb-structure-B1ygPCEa.js";
|
|
2
2
|
import { readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { basename, dirname, extname, join } from "node:path";
|
|
4
|
-
import { bytesToBase64, cellReference, columnIndexToLetters, createDocx, createOdg, createOdp, createOds, createOdt, createPdf, createPptx, decodeMarkdownText, decodeOdbPackage, docxToPdf, encodeMarkdownText, hsqldbCellDisplayText, markdownToPdf, odbReportToDocx, odbReportToOdt, odbReportToPdf, odgToPdf, odpToPdf, odsToPdf, odtToPdf, openDocx, openMarkdown, openOdg, openOdp, openOds, openOdt, openPdf, openPptx, parseXml, pptxToPdf, readDocxContent, readDocxExtras, readMarkdownContent, readOdbForms, readOdbReportContent, readOdbReports, readOdbTables, readOdgContent, readOdpContent, readOdsContent, readOdtContent, readPdf, readPptxContent, rgbHexToColor, xlsxToPdf } from "documents.js";
|
|
4
|
+
import { bytesToBase64, cellReference, columnIndexToLetters, createDocx, createOdg, createOdp, createOds, createOdt, createPdf, createPptx, csvToPdf, decodeMarkdownText, decodeOdbPackage, docxToPdf, encodeMarkdownText, hsqldbCellDisplayText, markdownToPdf, odbReportToDocx, odbReportToOdt, odbReportToPdf, odgToPdf, odpToPdf, odsToPdf, odtToPdf, openDocx, openMarkdown, openOdg, openOdp, openOds, openOdt, openPdf, openPptx, parseXml, pptxToPdf, readDocxContent, readDocxExtras, readMarkdownContent, readOdbForms, readOdbReportContent, readOdbReports, readOdbTables, readOdgContent, readOdpContent, readOdsContent, readOdtContent, readPdf, readPptxContent, rgbHexToColor, svgToPdf, xlsxToPdf } from "documents.js";
|
|
5
5
|
import { readdirSync } from "node:fs";
|
|
6
6
|
import { Box, Text, render, useApp, useInput, useWindowSize } from "ink";
|
|
7
7
|
import { createContext, useContext, useEffect, useReducer, useState } from "react";
|
|
@@ -47,6 +47,16 @@ async function exportToPdf(openDocument, destinationPath, options) {
|
|
|
47
47
|
await writeFile(destinationPath, pdfBytes);
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
|
+
if (openDocument.format === "csv") {
|
|
51
|
+
const pdfBytes = csvToPdf(openDocument.bytes, pdfOptions);
|
|
52
|
+
await writeFile(destinationPath, pdfBytes);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (openDocument.format === "svg") {
|
|
56
|
+
const pdfBytes = svgToPdf(openDocument.bytes, pdfOptions);
|
|
57
|
+
await writeFile(destinationPath, pdfBytes);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
50
60
|
const bytes = openDocument.editor.toBytes();
|
|
51
61
|
const pdfBytes = convert(openDocument.format, bytes, pdfOptions);
|
|
52
62
|
await writeFile(destinationPath, pdfBytes);
|
|
@@ -148,6 +158,18 @@ async function openDocumentAtPath(path, options = {}) {
|
|
|
148
158
|
bytes,
|
|
149
159
|
path
|
|
150
160
|
};
|
|
161
|
+
case "csv": return {
|
|
162
|
+
format,
|
|
163
|
+
layout: readPdf(csvToPdf(bytes)),
|
|
164
|
+
bytes,
|
|
165
|
+
path
|
|
166
|
+
};
|
|
167
|
+
case "svg": return {
|
|
168
|
+
format,
|
|
169
|
+
layout: readPdf(svgToPdf(bytes)),
|
|
170
|
+
bytes,
|
|
171
|
+
path
|
|
172
|
+
};
|
|
151
173
|
case "odf": throw new Error("A standalone .odf formula document has no editor; convert it to PDF (odfToPdf) instead");
|
|
152
174
|
}
|
|
153
175
|
}
|
|
@@ -195,7 +217,7 @@ function createNewDocument(format) {
|
|
|
195
217
|
}
|
|
196
218
|
}
|
|
197
219
|
async function saveDocumentTo(openDocument, path) {
|
|
198
|
-
if (openDocument.format === "odb" || openDocument.format === "xlsx") throw new Error(`A ${openDocument.format} document is opened read-only and cannot be written back`);
|
|
220
|
+
if (openDocument.format === "odb" || openDocument.format === "xlsx" || openDocument.format === "csv" || openDocument.format === "svg") throw new Error(`A ${openDocument.format} document is opened read-only and cannot be written back`);
|
|
199
221
|
if (openDocument.format === "markdown") {
|
|
200
222
|
await writeFile(path, encodeMarkdownText(openDocument.editor.toMarkdownText()));
|
|
201
223
|
return;
|
|
@@ -277,7 +299,9 @@ function rootScreenForFormat(format) {
|
|
|
277
299
|
case "odg": return { kind: "pageList" };
|
|
278
300
|
case "odb": return { kind: "odbTableList" };
|
|
279
301
|
case "pdf":
|
|
280
|
-
case "xlsx":
|
|
302
|
+
case "xlsx":
|
|
303
|
+
case "csv":
|
|
304
|
+
case "svg": return { kind: "pdfPageList" };
|
|
281
305
|
}
|
|
282
306
|
}
|
|
283
307
|
function currentScreen(state) {
|
|
@@ -414,6 +438,18 @@ function documentWithPath(doc, path) {
|
|
|
414
438
|
bytes: doc.bytes,
|
|
415
439
|
path
|
|
416
440
|
};
|
|
441
|
+
case "csv": return {
|
|
442
|
+
format: "csv",
|
|
443
|
+
layout: doc.layout,
|
|
444
|
+
bytes: doc.bytes,
|
|
445
|
+
path
|
|
446
|
+
};
|
|
447
|
+
case "svg": return {
|
|
448
|
+
format: "svg",
|
|
449
|
+
layout: doc.layout,
|
|
450
|
+
bytes: doc.bytes,
|
|
451
|
+
path
|
|
452
|
+
};
|
|
417
453
|
}
|
|
418
454
|
}
|
|
419
455
|
function reopenEditable(doc, bytes) {
|
|
@@ -731,7 +767,7 @@ function appReducer(state, action) {
|
|
|
731
767
|
selection: {},
|
|
732
768
|
errorDetail: void 0,
|
|
733
769
|
stack: [rootScreenForFormat(action.doc.format)]
|
|
734
|
-
}, "info", action.doc.format === "xlsx" ? `Opened ${action.path} as a read-only PDF preview -- press ':' then 'export pdf' to save it as a real PDF` : `Opened ${action.path}`);
|
|
770
|
+
}, "info", action.doc.format === "xlsx" || action.doc.format === "csv" || action.doc.format === "svg" ? `Opened ${action.path} as a read-only PDF preview -- press ':' then 'export pdf' to save it as a real PDF` : `Opened ${action.path}`);
|
|
735
771
|
case "OPEN_FILE_ERROR": return withStatus({
|
|
736
772
|
...state,
|
|
737
773
|
errorDetail: {
|
|
@@ -1317,7 +1353,7 @@ function appReducer(state, action) {
|
|
|
1317
1353
|
case "UNDO": {
|
|
1318
1354
|
const doc = state.openDocument;
|
|
1319
1355
|
if (doc === void 0) return withStatus(state, "info", "There is nothing to undo");
|
|
1320
|
-
if (doc.format === "odb" || doc.format === "xlsx") return withStatus(state, "warning", `A ${doc.format} document is read-only, so it has no history to undo`);
|
|
1356
|
+
if (doc.format === "odb" || doc.format === "xlsx" || doc.format === "csv" || doc.format === "svg") return withStatus(state, "warning", `A ${doc.format} document is read-only, so it has no history to undo`);
|
|
1321
1357
|
const snapshot = state.undoStack.at(-1);
|
|
1322
1358
|
if (snapshot === void 0) return withStatus(state, "info", "There is nothing to undo");
|
|
1323
1359
|
const restored = doc.format === "markdown" ? {
|
|
@@ -7149,7 +7185,7 @@ function OdtBodyListScreen() {
|
|
|
7149
7185
|
//#endregion
|
|
7150
7186
|
//#region src/tui/screens/editors/pdf/shared.ts
|
|
7151
7187
|
function requirePdfDocument(openDocument) {
|
|
7152
|
-
if (openDocument?.format !== "pdf" && openDocument?.format !== "xlsx") throw new Error("A PDF inspection screen rendered without an open PDF or
|
|
7188
|
+
if (openDocument?.format !== "pdf" && openDocument?.format !== "xlsx" && openDocument?.format !== "csv" && openDocument?.format !== "svg") throw new Error("A PDF inspection screen rendered without an open PDF, xlsx, csv, or svg document; the app router only reaches this screen group from pdfPageList, which is only ever the root screen of one of those four formats.");
|
|
7153
7189
|
return openDocument;
|
|
7154
7190
|
}
|
|
7155
7191
|
function isEditablePdfDocument(doc) {
|
|
@@ -8712,7 +8748,7 @@ function LauncherScreen() {
|
|
|
8712
8748
|
}),
|
|
8713
8749
|
/* @__PURE__ */ jsx(Text, {
|
|
8714
8750
|
dimColor: true,
|
|
8715
|
-
children: "A terminal editor for docx, pptx, odt, odp, ods, odg, markdown, odb and pdf -- xlsx
|
|
8751
|
+
children: "A terminal editor for docx, pptx, odt, odp, ods, odg, markdown, odb and pdf -- xlsx, csv and svg open as read-only PDF previews."
|
|
8716
8752
|
}),
|
|
8717
8753
|
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
8718
8754
|
/* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
|
|
@@ -8877,7 +8913,9 @@ function metadataFor(doc) {
|
|
|
8877
8913
|
case "odg": return readOdgContent(doc.editor.toPackage()).metadata;
|
|
8878
8914
|
case "markdown": return readMarkdownContent(doc.editor.toMarkdownText()).metadata;
|
|
8879
8915
|
case "pdf":
|
|
8880
|
-
case "xlsx":
|
|
8916
|
+
case "xlsx":
|
|
8917
|
+
case "csv":
|
|
8918
|
+
case "svg": return doc.layout.metadata;
|
|
8881
8919
|
case "odb": throw new Error("A .odb database has no document-level metadata -- it is a table/form/report container, not a single document with its own title/author/etc.");
|
|
8882
8920
|
}
|
|
8883
8921
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "document-cli",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "CLI and interactive Ink TUI for documents.js: every docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/markdown conversion, bridge, and editor as a scriptable command or a terminal app.",
|
|
3
|
+
"version": "2.1.1",
|
|
4
|
+
"description": "CLI and interactive Ink TUI for documents.js: every docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/csv/svg/markdown conversion, bridge, and editor as a scriptable command or a terminal app.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"packageManager": "pnpm@11.6.0",
|
|
89
89
|
"dependencies": {
|
|
90
90
|
"commander": "^15.0.0",
|
|
91
|
-
"documents.js": "^2.
|
|
91
|
+
"documents.js": "^2.3.0",
|
|
92
92
|
"ink": "^7.1.1",
|
|
93
93
|
"ink-text-input": "^6.0.0",
|
|
94
94
|
"react": "^19.2.8"
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"husky": "^9.1.7",
|
|
111
111
|
"ink-testing-library": "^4.0.0",
|
|
112
112
|
"lint-staged": "^17.3.0",
|
|
113
|
-
"odf.js": "^3.0.
|
|
113
|
+
"odf.js": "^3.0.2",
|
|
114
114
|
"pdf-codec": "^2.2.20",
|
|
115
115
|
"publint": "^0.3.22",
|
|
116
116
|
"semantic-release": "^25.0.8",
|