doculi 3.1.7 → 5.7.10

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/dist/index.cjs CHANGED
@@ -4,6 +4,7 @@ let node_path = require("node:path");
4
4
  let documents_js = require("documents.js");
5
5
  let node_fs = require("node:fs");
6
6
  let commander = require("commander");
7
+ let document_schema_js = require("document-schema.js");
7
8
  let document_outline_js = require("document-outline.js");
8
9
  //#region src/format.ts
9
10
  const EXTENSION_TO_FORMAT = {
@@ -30,6 +31,12 @@ const EXTENSION_TO_FORMAT = {
30
31
  svg: "svg",
31
32
  markdown: "markdown",
32
33
  md: "markdown",
34
+ rtf: "rtf",
35
+ wpd: "wpd",
36
+ doc: "doc",
37
+ xls: "xls",
38
+ ppt: "ppt",
39
+ epub: "epub",
33
40
  pdf: "pdf"
34
41
  };
35
42
  const FORMAT_TO_EXTENSION = {
@@ -44,6 +51,12 @@ const FORMAT_TO_EXTENSION = {
44
51
  csv: "csv",
45
52
  svg: "svg",
46
53
  markdown: "md",
54
+ rtf: "rtf",
55
+ wpd: "wpd",
56
+ doc: "doc",
57
+ xls: "xls",
58
+ ppt: "ppt",
59
+ epub: "epub",
47
60
  pdf: "pdf"
48
61
  };
49
62
  function isDocumentFormat(value) {
@@ -68,9 +81,13 @@ function combineSignals(a, b) {
68
81
  controller.abort(signal.reason);
69
82
  };
70
83
  if (a.aborted) forward(a);
71
- else a.addEventListener("abort", () => forward(a), { once: true });
84
+ else a.addEventListener("abort", () => {
85
+ forward(a);
86
+ }, { once: true });
72
87
  if (b.aborted) forward(b);
73
- else b.addEventListener("abort", () => forward(b), { once: true });
88
+ else b.addEventListener("abort", () => {
89
+ forward(b);
90
+ }, { once: true });
74
91
  return controller.signal;
75
92
  }
76
93
  function createRuntimeSignal(options) {
@@ -252,7 +269,7 @@ function resolveDefaultOutputPath(inputPath, targetFormat) {
252
269
  }
253
270
  //#endregion
254
271
  //#region src/commands/shared.ts
255
- const KNOWN_DOCUMENT_FORMATS = "docx, pptx, xlsx, odt, odp, ods, odg, svg, odf, csv, markdown, pdf";
272
+ const KNOWN_DOCUMENT_FORMATS = "docx, pptx, xlsx, odt, odp, ods, odg, svg, odf, csv, markdown, rtf, wpd, doc, xls, ppt, epub, pdf";
256
273
  function resolveTargetFormat(output, out, to) {
257
274
  if (to !== void 0) {
258
275
  if (!isDocumentFormat(to)) return { errorMessage: `unknown --to format '${to}'; expected one of ${KNOWN_DOCUMENT_FORMATS}` };
@@ -281,6 +298,7 @@ function buildConversionAction(source, target) {
281
298
  try {
282
299
  const inputBytes = await readInput(input, { signal });
283
300
  const fonts = await loadProvidedFonts(options.fontFiles ?? [], { signal });
301
+ const images = createFilesystemMarkdownImageResolver(input === "-" ? "." : (0, node_path.dirname)((0, node_path.resolve)(input)));
284
302
  const result = await (0, documents_js.createLocalDocumentConverter)().convert({
285
303
  source: {
286
304
  format: source,
@@ -295,7 +313,7 @@ function buildConversionAction(source, target) {
295
313
  quiet: options.quiet,
296
314
  command
297
315
  }) : void 0,
298
- images: createFilesystemMarkdownImageResolver(input === "-" ? "." : (0, node_path.dirname)((0, node_path.resolve)(input))),
316
+ images,
299
317
  delimiter: options.delimiter,
300
318
  sheet: options.sheet,
301
319
  page: options.page
@@ -307,8 +325,13 @@ function buildConversionAction(source, target) {
307
325
  command
308
326
  });
309
327
  for (const diagnostic of result.diagnostics) reporter.report(diagnostic);
310
- if (options.dumpPackage !== void 0) if (result.package === void 0) process.stderr.write(`[${command}] this conversion does not produce an intermediate DocumentPackage\n`);
311
- else await (0, node_fs_promises.writeFile)(options.dumpPackage, JSON.stringify((0, documents_js.documentPackageWithSchema)(result.package), void 0, 2));
328
+ if (options.dumpPackage !== void 0) {
329
+ const nativeTree = (0, documents_js.readNativeDocumentTree)(source, new Uint8Array(inputBytes), {
330
+ signal,
331
+ images
332
+ });
333
+ await (0, node_fs_promises.writeFile)(options.dumpPackage, JSON.stringify((0, documents_js.documentTreeWithSchema)(nativeTree), void 0, 2));
334
+ }
312
335
  reporter.summarize({
313
336
  output: resolvedOutput,
314
337
  bytes: result.document.bytes.byteLength,
@@ -339,7 +362,7 @@ function addVerboseOption(command) {
339
362
  return command.option("--verbose", "include a full stack trace when the run fails", false);
340
363
  }
341
364
  function addDumpPackageOption(command) {
342
- return command.option("--dump-package <file>", "write the intermediate DocumentPackage (the tree form: container-grouped content carrying per-node rendered frames, plus page sizes) this conversion built to a JSON file");
365
+ return command.option("--dump-package <file>", "write the intermediate DocumentTree (the tree form: container-grouped content carrying per-node rendered frames, plus page sizes) this conversion built to a JSON file");
343
366
  }
344
367
  function collectFontFile(value, previous) {
345
368
  return [...previous, value];
@@ -454,9 +477,15 @@ function footnotesSection(footnotes) {
454
477
  if (footnotes.length === 0) return [];
455
478
  return ["footnotes", ...footnotes.map((footnote, index) => footnoteLine(footnote, index + 1))];
456
479
  }
457
- function headerOrFooterSection(label, values) {
458
- if (values.length === 0) return [];
459
- return [label, ...values.map((text, index) => `${indent$1(1)}[${index + 1}] ${text}`)];
480
+ function partText(blocks) {
481
+ let text = "";
482
+ for (const block of blocks) if (block.kind === "paragraph") text += block.runs.map((run) => run.text).join("");
483
+ else if (block.kind === "table") for (const row of block.rows) for (const cell of row.cells) text += partText(cell.blocks);
484
+ return text;
485
+ }
486
+ function headerOrFooterSection(label, parts) {
487
+ if (parts.length === 0) return [];
488
+ return [label, ...parts.map((part, index) => `${indent$1(1)}[${index + 1}] ${partText(part.blocks)}`)];
460
489
  }
461
490
  function numberingLevelLine(ilvl, level) {
462
491
  const restartSuffix = level.restart === void 0 ? "" : `, restarts at level ${level.restart}`;
@@ -483,8 +512,8 @@ function formatDocxExtrasLines(extras) {
483
512
  const nonEmptySections = [
484
513
  commentsSection(extras.comments),
485
514
  footnotesSection(extras.footnotes),
486
- headerOrFooterSection("headers", extras.headers),
487
- headerOrFooterSection("footers", extras.footers),
515
+ headerOrFooterSection("headers", extras.headerFooterParts.filter((part) => part.kind === "header")),
516
+ headerOrFooterSection("footers", extras.headerFooterParts.filter((part) => part.kind === "footer")),
488
517
  numberingSection(extras.numbering)
489
518
  ].filter((section) => section.length > 0);
490
519
  if (nonEmptySections.length === 0) return ["This document carries no comments, footnotes, headers, footers, or numbering definitions."];
@@ -580,6 +609,9 @@ function isSchemaVersionMismatchError(error) {
580
609
  function isLayoutSchemaDemotedError(error) {
581
610
  return error instanceof Error && error.name === "LayoutSchemaDemotedError";
582
611
  }
612
+ function isDocumentPackageRenamedError(error) {
613
+ return error instanceof Error && error.name === "DocumentPackageRenamedError";
614
+ }
583
615
  async function runFromPackage(input, output, options) {
584
616
  const command = "from-package";
585
617
  if (output !== void 0 && options.out !== void 0 && output !== options.out) {
@@ -604,11 +636,11 @@ async function runFromPackage(input, output, options) {
604
636
  return 1;
605
637
  }
606
638
  const result = (0, documents_js.documentFromJson)(parsed);
607
- if (result.kind !== "DocumentPackage") {
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`);
639
+ if (result.kind !== "DocumentTree") {
640
+ process.stderr.write(`[${command}] '${input}' is a ${result.kind}, not a DocumentTree -- only a file written by --dump-package can be read back by this command\n`);
609
641
  return 2;
610
642
  }
611
- const content = (0, documents_js.flattenPackage)(result.value);
643
+ const content = (0, document_schema_js.flattenTree)(result.value);
612
644
  const bytes = target.format === "csv" ? (0, documents_js.encodeCsvText)((0, documents_js.buildCsvText)(content, {
613
645
  delimiter: options.delimiter,
614
646
  sheet: options.sheet
@@ -630,19 +662,23 @@ async function runFromPackage(input, output, options) {
630
662
  return 1;
631
663
  }
632
664
  if (isSchemaVersionMismatchError(error)) {
633
- process.stderr.write(`[${command}] '${input}' is a DocumentPackage dump from document-schema.js@${error.dumpVersion}, but this CLI's documents.js reads only @${error.installedVersion}-major dumps -- 4.0.0 replaced the flat { formatVersion, content, pages } shape with the tree-form DocumentPackage (ExaDev/document-schema.js#20); re-run the source conversion with --dump-package to write a current dump\n`);
665
+ process.stderr.write(`[${command}] '${input}' is a DocumentTree dump from document-schema.js@${error.dumpVersion}, but this CLI's documents.js reads only @${error.installedVersion}-major dumps -- 4.0.0 replaced the flat { formatVersion, content, pages } shape with the tree-form DocumentTree (ExaDev/document-schema.js#20); re-run the source conversion with --dump-package to write a current dump\n`);
634
666
  return 1;
635
667
  }
636
668
  if (isLayoutSchemaDemotedError(error)) {
637
669
  process.stderr.write(`[${command}] '${input}' is a LayoutDocument dump -- LayoutDocument moved to pdf-codec in document-schema.js 4.0.0 and is no longer a schema-stamped input; re-run the source conversion with --dump-package and read that package back instead\n`);
638
670
  return 1;
639
671
  }
672
+ if (isDocumentPackageRenamedError(error)) {
673
+ process.stderr.write(`[${command}] '${input}' is a document-package dump -- DocumentPackage was renamed to DocumentTree in document-schema.js 5.0.0 (ExaDev/documents.js#661); re-run the source conversion with --dump-package to write a current tree-form DocumentTree dump\n`);
674
+ return 1;
675
+ }
640
676
  process.stderr.write(`${formatError(error, options.verbose)}\n`);
641
677
  return mapErrorToExit(error, getAbortReason());
642
678
  }
643
679
  }
644
680
  function registerFromPackageCommand(program) {
645
- const command = program.command("from-package <input> [output]").description("read a DocumentPackage previously written by --dump-package and export it to a real target format");
681
+ const command = program.command("from-package <input> [output]").description("read a DocumentTree previously written by --dump-package and export it to a real target format");
646
682
  addOutOption(command);
647
683
  addTimeoutOption(command);
648
684
  addJsonOption(command);
@@ -1290,20 +1326,6 @@ function registerOdmCommand(program) {
1290
1326
  }
1291
1327
  //#endregion
1292
1328
  //#region src/commands/outline.ts
1293
- const OUTLINE_CONVERSION_TARGET = {
1294
- docx: "odt",
1295
- odt: "docx",
1296
- markdown: "docx",
1297
- pptx: "odp",
1298
- odp: "pptx",
1299
- xlsx: "ods",
1300
- ods: "xlsx",
1301
- csv: "xlsx",
1302
- odg: "odp",
1303
- svg: "odg",
1304
- pdf: "docx",
1305
- odf: "pdf"
1306
- };
1307
1329
  const INDENT = " ";
1308
1330
  function singleLineText(text) {
1309
1331
  return text.replaceAll(/\s+/g, " ").trim();
@@ -1339,7 +1361,6 @@ async function runOutline(input, options) {
1339
1361
  process.stderr.write(`[${command}] ${source.errorMessage}\n`);
1340
1362
  return 2;
1341
1363
  }
1342
- const target = OUTLINE_CONVERSION_TARGET[source.format];
1343
1364
  const { signal, getAbortReason } = createRuntimeSignal({ timeoutMs: options.timeout });
1344
1365
  const reporter = createDiagnosticReporter({
1345
1366
  json: options.json,
@@ -1348,19 +1369,14 @@ async function runOutline(input, options) {
1348
1369
  });
1349
1370
  try {
1350
1371
  const inputBytes = await readInput(input, { signal });
1351
- const result = await (0, documents_js.createLocalDocumentConverter)().convert({
1352
- source: {
1353
- format: source.format,
1354
- bytes: new Uint8Array(inputBytes)
1355
- },
1356
- targetFormat: target
1357
- }, {
1372
+ const tree = (0, documents_js.readNativeDocumentTree)(source.format, new Uint8Array(inputBytes), {
1358
1373
  signal,
1359
- images: createFilesystemMarkdownImageResolver(input === "-" ? "." : (0, node_path.dirname)((0, node_path.resolve)(input)))
1374
+ images: createFilesystemMarkdownImageResolver(input === "-" ? "." : (0, node_path.dirname)((0, node_path.resolve)(input))),
1375
+ sink: (diagnostic) => {
1376
+ reporter.report(diagnostic);
1377
+ }
1360
1378
  });
1361
- for (const diagnostic of result.diagnostics) reporter.report(diagnostic);
1362
- if (result.package === void 0) throw new Error(`the ${source.format}-to-${target} conversion produced no intermediate DocumentPackage`);
1363
- const outline = (0, document_outline_js.buildOutline)(result.package);
1379
+ const outline = (0, document_outline_js.buildOutline)(tree);
1364
1380
  if (options.json) {
1365
1381
  process.stdout.write(`${JSON.stringify(outline, void 0, 2)}\n`);
1366
1382
  return 0;
@@ -1508,11 +1524,11 @@ async function runSetMetadata(input, output, options) {
1508
1524
  function registerSetMetadataCommand(program) {
1509
1525
  const command = program.command("set-metadata <input> [output]").description("patch a document's own title/author/subject/keywords, leaving every other field and every other flag as-is").addHelpText("after", [
1510
1526
  "",
1511
- "Two write paths: a pdf source/target patches the metadata directly on the parsed PDF (writePdf), with no layout engine",
1512
- "involved at all -- genuinely lossless for everything else on the page. Every other supported format (docx, pptx, odt,",
1513
- "odp, ods, odg, markdown) rebuilds a fresh package from that format's own ContentDocument -- for docx specifically,",
1514
- "this is LOSSY: it drops anything docx-extras covers (comments, footnotes, headers/footers, numbering definitions),",
1515
- "since buildDocxPackage builds a fresh package from the ContentDocument alone, with no way to carry that data through.",
1527
+ "Three write paths: a pdf source/target patches the metadata directly on the parsed PDF (writePdf), and a docx source/target",
1528
+ "patches docProps/core.xml directly on the decoded package -- both with no layout engine or ContentDocument rebuild involved",
1529
+ "at all, so everything else on the page (pdf) or in the package (docx -- comments, footnotes, headers/footers, numbering",
1530
+ "definitions included) survives byte-faithful. Every other supported format (pptx, xlsx, odt, odp, ods, odg, markdown, rtf)",
1531
+ "rebuilds a fresh package from that format's own ContentDocument instead.",
1516
1532
  "",
1517
1533
  "set-metadata does not convert format -- source and target must match. Run convert/from-package first, then",
1518
1534
  "set-metadata on the result, if you need a different target format."
@@ -1533,12 +1549,12 @@ function registerSetMetadataCommand(program) {
1533
1549
  }
1534
1550
  //#endregion
1535
1551
  //#region package.json
1536
- var version = "3.1.7";
1552
+ var version = "5.7.10";
1537
1553
  //#endregion
1538
1554
  //#region src/program.ts
1539
1555
  function createProgram() {
1540
1556
  const program = new commander.Command("document-cli");
1541
- 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");
1557
+ program.description("every documents.js docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/csv/svg/markdown/rtf conversion, bridge, and inspector as a scriptable command");
1542
1558
  program.version(version);
1543
1559
  program.exitOverride((error) => {
1544
1560
  process.exitCode = error.exitCode === 0 ? 0 : 2;
package/dist/index.d.cts CHANGED
@@ -32,6 +32,6 @@ declare const EXIT_USAGE_ERROR = 2;
32
32
  declare const EXIT_NEEDS_INFO = 3;
33
33
  declare const EXIT_TIMEOUT = 124;
34
34
  declare const EXIT_INTERRUPTED = 130;
35
- declare function mapErrorToExit(error: unknown, abortReason: 'interrupt' | 'timeout' | undefined): number;
35
+ declare function mapErrorToExit(error: unknown, abortReason: "interrupt" | "timeout" | undefined): number;
36
36
  //#endregion
37
37
  export { type ConversionCommandOptions, EXIT_INPUT_ERROR, EXIT_INTERRUPTED, EXIT_NEEDS_INFO, EXIT_SUCCESS, EXIT_TIMEOUT, EXIT_USAGE_ERROR, buildConversionAction, createProgram, formatError, formatToExtension, inferFormatFromExtension, isDocumentFormat, mapErrorToExit };
package/dist/index.d.ts CHANGED
@@ -32,6 +32,6 @@ declare const EXIT_USAGE_ERROR = 2;
32
32
  declare const EXIT_NEEDS_INFO = 3;
33
33
  declare const EXIT_TIMEOUT = 124;
34
34
  declare const EXIT_INTERRUPTED = 130;
35
- declare function mapErrorToExit(error: unknown, abortReason: 'interrupt' | 'timeout' | undefined): number;
35
+ declare function mapErrorToExit(error: unknown, abortReason: "interrupt" | "timeout" | undefined): number;
36
36
  //#endregion
37
37
  export { type ConversionCommandOptions, EXIT_INPUT_ERROR, EXIT_INTERRUPTED, EXIT_NEEDS_INFO, EXIT_SUCCESS, EXIT_TIMEOUT, EXIT_USAGE_ERROR, buildConversionAction, createProgram, formatError, formatToExtension, inferFormatFromExtension, isDocumentFormat, mapErrorToExit };
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { readFile, writeFile } from "node:fs/promises";
2
2
  import { basename, dirname, extname, join, resolve } from "node:path";
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, encodeCsvText, encodeSvgText, evaluateSelect, extractSourceFontsForFormat, flattenPackage, hsqldbCellDisplayText, 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, documentTreeWithSchema, encodeCsvText, encodeSvgText, evaluateSelect, extractSourceFontsForFormat, hsqldbCellDisplayText, odbReportToDocx, odbReportToOdt, odbReportToPdf, odbToCsv, odbToXlsx, odmToPdf, parseSelect, readDocumentMetadata, readDocxExtras, readNativeDocumentTree, 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
+ import { flattenTree } from "document-schema.js";
6
7
  import { buildOutline, isOutlineNode, outlineLeafText } from "document-outline.js";
7
8
  //#region src/format.ts
8
9
  const EXTENSION_TO_FORMAT = {
@@ -29,6 +30,12 @@ const EXTENSION_TO_FORMAT = {
29
30
  svg: "svg",
30
31
  markdown: "markdown",
31
32
  md: "markdown",
33
+ rtf: "rtf",
34
+ wpd: "wpd",
35
+ doc: "doc",
36
+ xls: "xls",
37
+ ppt: "ppt",
38
+ epub: "epub",
32
39
  pdf: "pdf"
33
40
  };
34
41
  const FORMAT_TO_EXTENSION = {
@@ -43,6 +50,12 @@ const FORMAT_TO_EXTENSION = {
43
50
  csv: "csv",
44
51
  svg: "svg",
45
52
  markdown: "md",
53
+ rtf: "rtf",
54
+ wpd: "wpd",
55
+ doc: "doc",
56
+ xls: "xls",
57
+ ppt: "ppt",
58
+ epub: "epub",
46
59
  pdf: "pdf"
47
60
  };
48
61
  function isDocumentFormat(value) {
@@ -67,9 +80,13 @@ function combineSignals(a, b) {
67
80
  controller.abort(signal.reason);
68
81
  };
69
82
  if (a.aborted) forward(a);
70
- else a.addEventListener("abort", () => forward(a), { once: true });
83
+ else a.addEventListener("abort", () => {
84
+ forward(a);
85
+ }, { once: true });
71
86
  if (b.aborted) forward(b);
72
- else b.addEventListener("abort", () => forward(b), { once: true });
87
+ else b.addEventListener("abort", () => {
88
+ forward(b);
89
+ }, { once: true });
73
90
  return controller.signal;
74
91
  }
75
92
  function createRuntimeSignal(options) {
@@ -251,7 +268,7 @@ function resolveDefaultOutputPath(inputPath, targetFormat) {
251
268
  }
252
269
  //#endregion
253
270
  //#region src/commands/shared.ts
254
- const KNOWN_DOCUMENT_FORMATS = "docx, pptx, xlsx, odt, odp, ods, odg, svg, odf, csv, markdown, pdf";
271
+ const KNOWN_DOCUMENT_FORMATS = "docx, pptx, xlsx, odt, odp, ods, odg, svg, odf, csv, markdown, rtf, wpd, doc, xls, ppt, epub, pdf";
255
272
  function resolveTargetFormat(output, out, to) {
256
273
  if (to !== void 0) {
257
274
  if (!isDocumentFormat(to)) return { errorMessage: `unknown --to format '${to}'; expected one of ${KNOWN_DOCUMENT_FORMATS}` };
@@ -280,6 +297,7 @@ function buildConversionAction(source, target) {
280
297
  try {
281
298
  const inputBytes = await readInput(input, { signal });
282
299
  const fonts = await loadProvidedFonts(options.fontFiles ?? [], { signal });
300
+ const images = createFilesystemMarkdownImageResolver(input === "-" ? "." : dirname(resolve(input)));
283
301
  const result = await createLocalDocumentConverter().convert({
284
302
  source: {
285
303
  format: source,
@@ -294,7 +312,7 @@ function buildConversionAction(source, target) {
294
312
  quiet: options.quiet,
295
313
  command
296
314
  }) : void 0,
297
- images: createFilesystemMarkdownImageResolver(input === "-" ? "." : dirname(resolve(input))),
315
+ images,
298
316
  delimiter: options.delimiter,
299
317
  sheet: options.sheet,
300
318
  page: options.page
@@ -306,8 +324,13 @@ function buildConversionAction(source, target) {
306
324
  command
307
325
  });
308
326
  for (const diagnostic of result.diagnostics) reporter.report(diagnostic);
309
- if (options.dumpPackage !== void 0) if (result.package === void 0) process.stderr.write(`[${command}] this conversion does not produce an intermediate DocumentPackage\n`);
310
- else await writeFile(options.dumpPackage, JSON.stringify(documentPackageWithSchema(result.package), void 0, 2));
327
+ if (options.dumpPackage !== void 0) {
328
+ const nativeTree = readNativeDocumentTree(source, new Uint8Array(inputBytes), {
329
+ signal,
330
+ images
331
+ });
332
+ await writeFile(options.dumpPackage, JSON.stringify(documentTreeWithSchema(nativeTree), void 0, 2));
333
+ }
311
334
  reporter.summarize({
312
335
  output: resolvedOutput,
313
336
  bytes: result.document.bytes.byteLength,
@@ -338,7 +361,7 @@ function addVerboseOption(command) {
338
361
  return command.option("--verbose", "include a full stack trace when the run fails", false);
339
362
  }
340
363
  function addDumpPackageOption(command) {
341
- return command.option("--dump-package <file>", "write the intermediate DocumentPackage (the tree form: container-grouped content carrying per-node rendered frames, plus page sizes) this conversion built to a JSON file");
364
+ return command.option("--dump-package <file>", "write the intermediate DocumentTree (the tree form: container-grouped content carrying per-node rendered frames, plus page sizes) this conversion built to a JSON file");
342
365
  }
343
366
  function collectFontFile(value, previous) {
344
367
  return [...previous, value];
@@ -453,9 +476,15 @@ function footnotesSection(footnotes) {
453
476
  if (footnotes.length === 0) return [];
454
477
  return ["footnotes", ...footnotes.map((footnote, index) => footnoteLine(footnote, index + 1))];
455
478
  }
456
- function headerOrFooterSection(label, values) {
457
- if (values.length === 0) return [];
458
- return [label, ...values.map((text, index) => `${indent$1(1)}[${index + 1}] ${text}`)];
479
+ function partText(blocks) {
480
+ let text = "";
481
+ for (const block of blocks) if (block.kind === "paragraph") text += block.runs.map((run) => run.text).join("");
482
+ else if (block.kind === "table") for (const row of block.rows) for (const cell of row.cells) text += partText(cell.blocks);
483
+ return text;
484
+ }
485
+ function headerOrFooterSection(label, parts) {
486
+ if (parts.length === 0) return [];
487
+ return [label, ...parts.map((part, index) => `${indent$1(1)}[${index + 1}] ${partText(part.blocks)}`)];
459
488
  }
460
489
  function numberingLevelLine(ilvl, level) {
461
490
  const restartSuffix = level.restart === void 0 ? "" : `, restarts at level ${level.restart}`;
@@ -482,8 +511,8 @@ function formatDocxExtrasLines(extras) {
482
511
  const nonEmptySections = [
483
512
  commentsSection(extras.comments),
484
513
  footnotesSection(extras.footnotes),
485
- headerOrFooterSection("headers", extras.headers),
486
- headerOrFooterSection("footers", extras.footers),
514
+ headerOrFooterSection("headers", extras.headerFooterParts.filter((part) => part.kind === "header")),
515
+ headerOrFooterSection("footers", extras.headerFooterParts.filter((part) => part.kind === "footer")),
487
516
  numberingSection(extras.numbering)
488
517
  ].filter((section) => section.length > 0);
489
518
  if (nonEmptySections.length === 0) return ["This document carries no comments, footnotes, headers, footers, or numbering definitions."];
@@ -579,6 +608,9 @@ function isSchemaVersionMismatchError(error) {
579
608
  function isLayoutSchemaDemotedError(error) {
580
609
  return error instanceof Error && error.name === "LayoutSchemaDemotedError";
581
610
  }
611
+ function isDocumentPackageRenamedError(error) {
612
+ return error instanceof Error && error.name === "DocumentPackageRenamedError";
613
+ }
582
614
  async function runFromPackage(input, output, options) {
583
615
  const command = "from-package";
584
616
  if (output !== void 0 && options.out !== void 0 && output !== options.out) {
@@ -603,11 +635,11 @@ async function runFromPackage(input, output, options) {
603
635
  return 1;
604
636
  }
605
637
  const result = documentFromJson(parsed);
606
- if (result.kind !== "DocumentPackage") {
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`);
638
+ if (result.kind !== "DocumentTree") {
639
+ process.stderr.write(`[${command}] '${input}' is a ${result.kind}, not a DocumentTree -- only a file written by --dump-package can be read back by this command\n`);
608
640
  return 2;
609
641
  }
610
- const content = flattenPackage(result.value);
642
+ const content = flattenTree(result.value);
611
643
  const bytes = target.format === "csv" ? encodeCsvText(buildCsvText(content, {
612
644
  delimiter: options.delimiter,
613
645
  sheet: options.sheet
@@ -629,19 +661,23 @@ async function runFromPackage(input, output, options) {
629
661
  return 1;
630
662
  }
631
663
  if (isSchemaVersionMismatchError(error)) {
632
- process.stderr.write(`[${command}] '${input}' is a DocumentPackage dump from document-schema.js@${error.dumpVersion}, but this CLI's documents.js reads only @${error.installedVersion}-major dumps -- 4.0.0 replaced the flat { formatVersion, content, pages } shape with the tree-form DocumentPackage (ExaDev/document-schema.js#20); re-run the source conversion with --dump-package to write a current dump\n`);
664
+ process.stderr.write(`[${command}] '${input}' is a DocumentTree dump from document-schema.js@${error.dumpVersion}, but this CLI's documents.js reads only @${error.installedVersion}-major dumps -- 4.0.0 replaced the flat { formatVersion, content, pages } shape with the tree-form DocumentTree (ExaDev/document-schema.js#20); re-run the source conversion with --dump-package to write a current dump\n`);
633
665
  return 1;
634
666
  }
635
667
  if (isLayoutSchemaDemotedError(error)) {
636
668
  process.stderr.write(`[${command}] '${input}' is a LayoutDocument dump -- LayoutDocument moved to pdf-codec in document-schema.js 4.0.0 and is no longer a schema-stamped input; re-run the source conversion with --dump-package and read that package back instead\n`);
637
669
  return 1;
638
670
  }
671
+ if (isDocumentPackageRenamedError(error)) {
672
+ process.stderr.write(`[${command}] '${input}' is a document-package dump -- DocumentPackage was renamed to DocumentTree in document-schema.js 5.0.0 (ExaDev/documents.js#661); re-run the source conversion with --dump-package to write a current tree-form DocumentTree dump\n`);
673
+ return 1;
674
+ }
639
675
  process.stderr.write(`${formatError(error, options.verbose)}\n`);
640
676
  return mapErrorToExit(error, getAbortReason());
641
677
  }
642
678
  }
643
679
  function registerFromPackageCommand(program) {
644
- const command = program.command("from-package <input> [output]").description("read a DocumentPackage previously written by --dump-package and export it to a real target format");
680
+ const command = program.command("from-package <input> [output]").description("read a DocumentTree previously written by --dump-package and export it to a real target format");
645
681
  addOutOption(command);
646
682
  addTimeoutOption(command);
647
683
  addJsonOption(command);
@@ -1289,20 +1325,6 @@ function registerOdmCommand(program) {
1289
1325
  }
1290
1326
  //#endregion
1291
1327
  //#region src/commands/outline.ts
1292
- const OUTLINE_CONVERSION_TARGET = {
1293
- docx: "odt",
1294
- odt: "docx",
1295
- markdown: "docx",
1296
- pptx: "odp",
1297
- odp: "pptx",
1298
- xlsx: "ods",
1299
- ods: "xlsx",
1300
- csv: "xlsx",
1301
- odg: "odp",
1302
- svg: "odg",
1303
- pdf: "docx",
1304
- odf: "pdf"
1305
- };
1306
1328
  const INDENT = " ";
1307
1329
  function singleLineText(text) {
1308
1330
  return text.replaceAll(/\s+/g, " ").trim();
@@ -1338,7 +1360,6 @@ async function runOutline(input, options) {
1338
1360
  process.stderr.write(`[${command}] ${source.errorMessage}\n`);
1339
1361
  return 2;
1340
1362
  }
1341
- const target = OUTLINE_CONVERSION_TARGET[source.format];
1342
1363
  const { signal, getAbortReason } = createRuntimeSignal({ timeoutMs: options.timeout });
1343
1364
  const reporter = createDiagnosticReporter({
1344
1365
  json: options.json,
@@ -1347,19 +1368,14 @@ async function runOutline(input, options) {
1347
1368
  });
1348
1369
  try {
1349
1370
  const inputBytes = await readInput(input, { signal });
1350
- const result = await createLocalDocumentConverter().convert({
1351
- source: {
1352
- format: source.format,
1353
- bytes: new Uint8Array(inputBytes)
1354
- },
1355
- targetFormat: target
1356
- }, {
1371
+ const tree = readNativeDocumentTree(source.format, new Uint8Array(inputBytes), {
1357
1372
  signal,
1358
- images: createFilesystemMarkdownImageResolver(input === "-" ? "." : dirname(resolve(input)))
1373
+ images: createFilesystemMarkdownImageResolver(input === "-" ? "." : dirname(resolve(input))),
1374
+ sink: (diagnostic) => {
1375
+ reporter.report(diagnostic);
1376
+ }
1359
1377
  });
1360
- for (const diagnostic of result.diagnostics) reporter.report(diagnostic);
1361
- if (result.package === void 0) throw new Error(`the ${source.format}-to-${target} conversion produced no intermediate DocumentPackage`);
1362
- const outline = buildOutline(result.package);
1378
+ const outline = buildOutline(tree);
1363
1379
  if (options.json) {
1364
1380
  process.stdout.write(`${JSON.stringify(outline, void 0, 2)}\n`);
1365
1381
  return 0;
@@ -1507,11 +1523,11 @@ async function runSetMetadata(input, output, options) {
1507
1523
  function registerSetMetadataCommand(program) {
1508
1524
  const command = program.command("set-metadata <input> [output]").description("patch a document's own title/author/subject/keywords, leaving every other field and every other flag as-is").addHelpText("after", [
1509
1525
  "",
1510
- "Two write paths: a pdf source/target patches the metadata directly on the parsed PDF (writePdf), with no layout engine",
1511
- "involved at all -- genuinely lossless for everything else on the page. Every other supported format (docx, pptx, odt,",
1512
- "odp, ods, odg, markdown) rebuilds a fresh package from that format's own ContentDocument -- for docx specifically,",
1513
- "this is LOSSY: it drops anything docx-extras covers (comments, footnotes, headers/footers, numbering definitions),",
1514
- "since buildDocxPackage builds a fresh package from the ContentDocument alone, with no way to carry that data through.",
1526
+ "Three write paths: a pdf source/target patches the metadata directly on the parsed PDF (writePdf), and a docx source/target",
1527
+ "patches docProps/core.xml directly on the decoded package -- both with no layout engine or ContentDocument rebuild involved",
1528
+ "at all, so everything else on the page (pdf) or in the package (docx -- comments, footnotes, headers/footers, numbering",
1529
+ "definitions included) survives byte-faithful. Every other supported format (pptx, xlsx, odt, odp, ods, odg, markdown, rtf)",
1530
+ "rebuilds a fresh package from that format's own ContentDocument instead.",
1515
1531
  "",
1516
1532
  "set-metadata does not convert format -- source and target must match. Run convert/from-package first, then",
1517
1533
  "set-metadata on the result, if you need a different target format."
@@ -1532,12 +1548,12 @@ function registerSetMetadataCommand(program) {
1532
1548
  }
1533
1549
  //#endregion
1534
1550
  //#region package.json
1535
- var version = "3.1.7";
1551
+ var version = "5.7.10";
1536
1552
  //#endregion
1537
1553
  //#region src/program.ts
1538
1554
  function createProgram() {
1539
1555
  const program = new Command("document-cli");
1540
- 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");
1556
+ program.description("every documents.js docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/csv/svg/markdown/rtf conversion, bridge, and inspector as a scriptable command");
1541
1557
  program.version(version);
1542
1558
  program.exitOverride((error) => {
1543
1559
  process.exitCode = error.exitCode === 0 ? 0 : 2;
@@ -26,6 +26,12 @@ const EXTENSION_TO_FORMAT = {
26
26
  svg: "svg",
27
27
  markdown: "markdown",
28
28
  md: "markdown",
29
+ rtf: "rtf",
30
+ wpd: "wpd",
31
+ doc: "doc",
32
+ xls: "xls",
33
+ ppt: "ppt",
34
+ epub: "epub",
29
35
  pdf: "pdf"
30
36
  };
31
37
  const FORMAT_TO_EXTENSION = {
@@ -40,6 +46,12 @@ const FORMAT_TO_EXTENSION = {
40
46
  csv: "csv",
41
47
  svg: "svg",
42
48
  markdown: "md",
49
+ rtf: "rtf",
50
+ wpd: "wpd",
51
+ doc: "doc",
52
+ xls: "xls",
53
+ ppt: "ppt",
54
+ epub: "epub",
43
55
  pdf: "pdf"
44
56
  };
45
57
  function isDocumentFormat(value) {
@@ -133,9 +145,15 @@ function footnotesSection(footnotes) {
133
145
  if (footnotes.length === 0) return [];
134
146
  return ["footnotes", ...footnotes.map((footnote, index) => footnoteLine(footnote, index + 1))];
135
147
  }
136
- function headerOrFooterSection(label, values) {
137
- if (values.length === 0) return [];
138
- return [label, ...values.map((text, index) => `${indent$1(1)}[${index + 1}] ${text}`)];
148
+ function partText(blocks) {
149
+ let text = "";
150
+ for (const block of blocks) if (block.kind === "paragraph") text += block.runs.map((run) => run.text).join("");
151
+ else if (block.kind === "table") for (const row of block.rows) for (const cell of row.cells) text += partText(cell.blocks);
152
+ return text;
153
+ }
154
+ function headerOrFooterSection(label, parts) {
155
+ if (parts.length === 0) return [];
156
+ return [label, ...parts.map((part, index) => `${indent$1(1)}[${index + 1}] ${partText(part.blocks)}`)];
139
157
  }
140
158
  function numberingLevelLine(ilvl, level) {
141
159
  const restartSuffix = level.restart === void 0 ? "" : `, restarts at level ${level.restart}`;
@@ -162,8 +180,8 @@ function formatDocxExtrasLines(extras) {
162
180
  const nonEmptySections = [
163
181
  commentsSection(extras.comments),
164
182
  footnotesSection(extras.footnotes),
165
- headerOrFooterSection("headers", extras.headers),
166
- headerOrFooterSection("footers", extras.footers),
183
+ headerOrFooterSection("headers", extras.headerFooterParts.filter((part) => part.kind === "header")),
184
+ headerOrFooterSection("footers", extras.headerFooterParts.filter((part) => part.kind === "footer")),
167
185
  numberingSection(extras.numbering)
168
186
  ].filter((section) => section.length > 0);
169
187
  if (nonEmptySections.length === 0) return ["This document carries no comments, footnotes, headers, footers, or numbering definitions."];
@@ -326,4 +344,4 @@ function formatOdbReportLines(report) {
326
344
  return lines;
327
345
  }
328
346
  //#endregion
329
- export { odbFormSummary as a, formatDocxExtrasLines as c, writeOutput as d, loadProvidedFonts as f, isDocumentFormat as h, formatOdbReportLines as i, readInput as l, inferFormatFromExtension as m, describeOdbReport as n, formatMetadataLines as o, formatToExtension as p, formatOdbFormLines as r, presentMetadataEntries as s, describeOdbForm as t, resolveDefaultOutputPath as u };
347
+ export { odbFormSummary as a, presentMetadataEntries as c, resolveDefaultOutputPath as d, writeOutput as f, isDocumentFormat as g, inferFormatFromExtension as h, formatOdbReportLines as i, formatDocxExtrasLines as l, formatToExtension as m, describeOdbReport as n, formatMetadataLines as o, loadProvidedFonts as p, formatOdbFormLines as r, formatMetadataValue as s, describeOdbForm as t, readInput as u };