document-cli 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { a as odbFormSummary, c as writeOutput, d as inferFormatFromExtension, f as isDocumentFormat, i as formatOdbReportLines, l as loadProvidedFonts, n as describeOdbReport, o as readInput, r as formatOdbFormLines, s as resolveDefaultOutputPath, t as describeOdbForm } from "./odb-structure-CX_0zL8_.js";
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-Du1w_hOU.js";
3
3
  import { Command, CommanderError, InvalidArgumentError } from "commander";
4
4
  import { writeFile } from "node:fs/promises";
5
- import { HsqldbSqlEvaluationError, HsqldbSqlParseError, HsqldbSqlUnsupportedError, OdbNoEmbeddedDataSourceError, OdbReportNotSpecifiedError, OdbTableNotFoundError, OdbTableNotSpecifiedError, OdbUnsupportedFormatError, OdmUnresolvedSectionError, PdfEncryptedError, PdfParseError, UnrecognizedDocumentSchemaError, buildDocxPackage, buildMarkdownText, buildOdgPackage, buildOdpPackage, buildOdsPackage, buildOdtPackage, buildPptxPackage, convertWordprocessingToLayout, createFontMeasurer, createFontRegistry, createLocalDocumentConverter, documentFromJson, documentPackageWithSchema, encodeMarkdownText, encodePackage, evaluateSelect, hsqldbCellDisplayText, odbToCsv, odbToXlsx, odmToPdf, parseSelect, readOdbForms, readOdbInventory, readOdbReportContent, readOdbReports, readOdbTables, readPdf, writePdf } from "documents.js";
5
+ import { HsqldbSqlEvaluationError, HsqldbSqlParseError, HsqldbSqlUnsupportedError, OdbNoEmbeddedDataSourceError, OdbReportNotSpecifiedError, OdbTableNotFoundError, OdbTableNotSpecifiedError, OdbUnsupportedFormatError, OdmUnresolvedSectionError, PdfEncryptedError, PdfParseError, UnrecognizedDocumentSchemaError, buildDocxPackage, buildMarkdownText, buildOdgPackage, buildOdpPackage, buildOdsPackage, buildOdtPackage, buildPptxPackage, convertWordprocessingToLayout, createFontMeasurer, createFontRegistry, createLocalDocumentConverter, decodeMarkdownText, decodePackage, documentFromJson, documentPackageWithSchema, encodeMarkdownText, encodePackage, evaluateSelect, extractSourceFonts, hsqldbCellDisplayText, layoutDocumentWithSchema, odbToCsv, odbToXlsx, odmToPdf, parseSelect, readDocxContent, readDocxExtras, readMarkdownContent, readOdbForms, readOdbInventory, readOdbReportContent, readOdbReports, readOdbTables, readOdfFormulaContent, readOdgContent, readOdpContent, readOdsContent, readOdtContent, readPdf, readPptxContent, writePdf, xlsxToPdf } from "documents.js";
6
6
  import { basename, dirname, extname, join } from "node:path";
7
- import { decodePackage, encodePackage as encodePackage$1 } from "odf.js";
7
+ import { decodePackage as decodePackage$1, encodePackage as encodePackage$1 } from "odf.js";
8
8
  import { existsSync, readFileSync } from "node:fs";
9
9
  //#region src/runtime/abort.ts
10
10
  function combineSignals(a, b) {
@@ -280,8 +280,100 @@ function registerConversionCommands(program) {
280
280
  });
281
281
  }
282
282
  //#endregion
283
+ //#region src/commands/docx-extras.ts
284
+ async function runDocxExtras(input, options) {
285
+ const command = "docx-extras";
286
+ const { signal, getAbortReason } = createRuntimeSignal({});
287
+ try {
288
+ const inputBytes = await readInput(input, { signal });
289
+ const pkg = decodePackage(new Uint8Array(inputBytes));
290
+ const extras = readDocxExtras(pkg);
291
+ if (options.json) {
292
+ process.stdout.write(`${JSON.stringify(extras)}\n`);
293
+ return 0;
294
+ }
295
+ for (const line of formatDocxExtrasLines(extras)) process.stdout.write(`${line}\n`);
296
+ return 0;
297
+ } catch (error) {
298
+ process.stderr.write(`[${command}] ${formatError(error, false)}\n`);
299
+ return mapErrorToExit(error, getAbortReason());
300
+ }
301
+ }
302
+ function registerDocxExtrasCommand(program) {
303
+ program.command("docx-extras <input>").description("print a docx's own comments, footnotes, headers, footers, and numbering definitions -- data readDocxContent's ContentDocument cannot carry").option("--json", "emit the raw DocxExtras object as JSON instead of a human-readable report", false).action(async (input, options) => {
304
+ process.exitCode = await runDocxExtras(input, options);
305
+ });
306
+ }
307
+ //#endregion
308
+ //#region src/commands/fonts.ts
309
+ const FONT_SOURCE_FORMATS = {
310
+ docx: true,
311
+ pptx: true,
312
+ odt: true,
313
+ odp: true,
314
+ ods: true,
315
+ odg: true
316
+ };
317
+ function isFontSourceFormat(format) {
318
+ return format in FONT_SOURCE_FORMATS;
319
+ }
320
+ function resolveFontSourcePackage(format, bytes) {
321
+ if (format === "docx" || format === "pptx") return {
322
+ kind: format,
323
+ package: decodePackage(bytes)
324
+ };
325
+ return {
326
+ kind: "odf",
327
+ package: decodePackage$1(bytes)
328
+ };
329
+ }
330
+ async function runFonts(input, options) {
331
+ const command = "fonts";
332
+ const { signal, getAbortReason } = createRuntimeSignal({});
333
+ try {
334
+ const format = inferFormatFromExtension(input);
335
+ if (format === void 0) {
336
+ process.stderr.write(`[${command}] cannot infer a document format from '${input}'; expected one of docx, pptx, odt, odp, ods, odg\n`);
337
+ return 2;
338
+ }
339
+ if (!isFontSourceFormat(format)) {
340
+ process.stderr.write(`[${command}] '${format}' documents carry no source-embedded font faces this command can extract; expected one of docx, pptx, odt, odp, ods, odg\n`);
341
+ return 2;
342
+ }
343
+ const inputBytes = await readInput(input, { signal });
344
+ const source = resolveFontSourcePackage(format, new Uint8Array(inputBytes));
345
+ const summaries = extractSourceFonts(source).map((face) => ({
346
+ family: face.family,
347
+ bold: face.bold,
348
+ italic: face.italic,
349
+ byteLength: face.bytes.length
350
+ }));
351
+ if (options.json) {
352
+ process.stdout.write(`${JSON.stringify(summaries)}\n`);
353
+ return 0;
354
+ }
355
+ if (summaries.length === 0) {
356
+ process.stdout.write("This document embeds no source fonts.\n");
357
+ return 0;
358
+ }
359
+ for (const face of summaries) {
360
+ const style = [face.bold ? "bold" : void 0, face.italic ? "italic" : void 0].filter((value) => value !== void 0).join(" ");
361
+ process.stdout.write(`${face.family}${style === "" ? "" : ` (${style})`} -- ${face.byteLength} bytes\n`);
362
+ }
363
+ return 0;
364
+ } catch (error) {
365
+ process.stderr.write(`${formatError(error, false)}\n`);
366
+ return mapErrorToExit(error, getAbortReason());
367
+ }
368
+ }
369
+ function registerFontsCommand(program) {
370
+ program.command("fonts <input>").description("list every source-embedded font face a docx/pptx/odt/odp/ods/odg document carries (family, weight/style, byte length)").option("--json", "emit the face list as a JSON array instead of a human-readable report", false).action(async (input, options) => {
371
+ process.exitCode = await runFonts(input, options);
372
+ });
373
+ }
374
+ //#endregion
283
375
  //#region src/commands/formats.ts
284
- const COMMANDS_NOT_LISTED = "odm-to-pdf, odb-to-csv, odb-to-xlsx, odb-tables, odb-forms, odb-reports, pdf-inspect, from-package";
376
+ const COMMANDS_NOT_LISTED = "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";
285
377
  function registerFormatsCommand(program) {
286
378
  program.command("formats").description("list every source -> target conversion this CLI supports via a <source>-to-<target> command").option("--json", "emit the conversion list as a JSON array instead of a human-readable table", false).action((options) => {
287
379
  const { conversions } = createLocalDocumentConverter();
@@ -374,6 +466,54 @@ function registerFromPackageCommand(program) {
374
466
  });
375
467
  }
376
468
  //#endregion
469
+ //#region src/commands/metadata.ts
470
+ function readMetadataForFormat(format, bytes, signal) {
471
+ switch (format) {
472
+ case "docx": return readDocxContent(decodePackage(bytes)).metadata;
473
+ case "pptx": return readPptxContent(decodePackage(bytes)).metadata;
474
+ case "odt": return readOdtContent(decodePackage$1(bytes)).metadata;
475
+ case "odp": return readOdpContent(decodePackage$1(bytes)).metadata;
476
+ case "ods": return readOdsContent(decodePackage$1(bytes)).metadata;
477
+ case "odg": return readOdgContent(decodePackage$1(bytes)).metadata;
478
+ case "odf": return readOdfFormulaContent(decodePackage$1(bytes)).metadata;
479
+ case "markdown": return readMarkdownContent(decodeMarkdownText(bytes)).metadata;
480
+ case "pdf": return readPdf(bytes, { signal }).metadata;
481
+ case "xlsx": return readPdf(xlsxToPdf(bytes, { signal }), { signal }).metadata;
482
+ }
483
+ }
484
+ async function runMetadata(input, options) {
485
+ const command = "metadata";
486
+ const source = inferFormatFromExtension(input);
487
+ if (source === void 0) {
488
+ process.stderr.write(`[${command}] cannot infer a source format from '${input}'; rename the file with a recognised extension (${KNOWN_DOCUMENT_FORMATS})\n`);
489
+ return 2;
490
+ }
491
+ const { signal, getAbortReason } = createRuntimeSignal({});
492
+ try {
493
+ const inputBytes = await readInput(input, { signal });
494
+ const metadata = readMetadataForFormat(source, new Uint8Array(inputBytes), signal);
495
+ if (options.json) {
496
+ process.stdout.write(`${JSON.stringify(metadata)}\n`);
497
+ return 0;
498
+ }
499
+ const lines = formatMetadataLines(metadata);
500
+ if (lines.length === 0) {
501
+ process.stdout.write("This document carries no metadata.\n");
502
+ return 0;
503
+ }
504
+ for (const line of lines) process.stdout.write(`${line}\n`);
505
+ return 0;
506
+ } catch (error) {
507
+ process.stderr.write(`[${command}] ${formatError(error, false)}\n`);
508
+ return mapErrorToExit(error, getAbortReason());
509
+ }
510
+ }
511
+ function registerMetadataCommand(program) {
512
+ program.command("metadata <input>").description(`print a document's own title/author/subject/keywords/creator/producer/created/modified metadata (${KNOWN_DOCUMENT_FORMATS})`).option("--json", "emit the metadata as a JSON object instead of a human-readable report", false).action(async (input, options) => {
513
+ process.exitCode = await runMetadata(input, options);
514
+ });
515
+ }
516
+ //#endregion
377
517
  //#region src/sql-result-format.ts
378
518
  const COLUMN_GAP = " ";
379
519
  function columnWidths(columns, cells) {
@@ -483,7 +623,7 @@ async function runOdbTables(input, options) {
483
623
  const { signal, getAbortReason } = createRuntimeSignal({});
484
624
  try {
485
625
  const inputBytes = await readInput(input, { signal });
486
- const pkg = decodePackage(new Uint8Array(inputBytes));
626
+ const pkg = decodePackage$1(new Uint8Array(inputBytes));
487
627
  const tables = readOdbTables(pkg);
488
628
  if (options.json) {
489
629
  const summary = tables.map((table) => ({
@@ -528,7 +668,7 @@ async function runOdbQuery(input, options) {
528
668
  const { signal, getAbortReason } = createRuntimeSignal({});
529
669
  try {
530
670
  const inputBytes = await readInput(input, { signal });
531
- const pkg = decodePackage(new Uint8Array(inputBytes));
671
+ const pkg = decodePackage$1(new Uint8Array(inputBytes));
532
672
  const resolved = resolveQuerySql(pkg, options);
533
673
  if ("errorMessage" in resolved) {
534
674
  process.stderr.write(`[${command}] ${resolved.errorMessage}\n`);
@@ -550,7 +690,7 @@ async function runOdbForms(input, options) {
550
690
  const { signal, getAbortReason } = createRuntimeSignal({});
551
691
  try {
552
692
  const inputBytes = await readInput(input, { signal });
553
- const forms = readOdbForms(decodePackage(new Uint8Array(inputBytes)));
693
+ const forms = readOdbForms(decodePackage$1(new Uint8Array(inputBytes)));
554
694
  if (options.json) {
555
695
  process.stdout.write(`${JSON.stringify(forms.map((form) => odbFormSummary(form)))}\n`);
556
696
  return 0;
@@ -573,7 +713,7 @@ async function runOdbReports(input, options) {
573
713
  const { signal, getAbortReason } = createRuntimeSignal({});
574
714
  try {
575
715
  const inputBytes = await readInput(input, { signal });
576
- const reports = readOdbReports(decodePackage(new Uint8Array(inputBytes)));
716
+ const reports = readOdbReports(decodePackage$1(new Uint8Array(inputBytes)));
577
717
  if (options.json) {
578
718
  process.stdout.write(`${JSON.stringify(reports)}\n`);
579
719
  return 0;
@@ -657,7 +797,7 @@ async function runOdbRenderReport(input, output, options) {
657
797
  try {
658
798
  const inputBytes = await readInput(input, { signal });
659
799
  const fonts = await loadProvidedFonts(options.fontFile ?? [], { signal });
660
- const pkg = decodePackage(new Uint8Array(inputBytes));
800
+ const pkg = decodePackage$1(new Uint8Array(inputBytes));
661
801
  const bytes = renderOdbReportBytes(readOdbReportContent(pkg, { report: options.report }), targetFormat, {
662
802
  fonts,
663
803
  signal,
@@ -845,12 +985,6 @@ function countImagesByFormat(images) {
845
985
  for (const asset of Object.values(images)) counts.set(asset.format, (counts.get(asset.format) ?? 0) + 1);
846
986
  return counts;
847
987
  }
848
- function isPresent(entry) {
849
- return entry[1] !== void 0;
850
- }
851
- function formatMetadataValue(value) {
852
- return typeof value === "string" ? value : value.join(", ");
853
- }
854
988
  async function runPdfInspect(input, options) {
855
989
  const command = "pdf-inspect";
856
990
  const { signal, getAbortReason } = createRuntimeSignal({});
@@ -868,7 +1002,7 @@ async function runPdfInspect(input, options) {
868
1002
  }
869
1003
  });
870
1004
  if (options.full) {
871
- process.stdout.write(`${JSON.stringify(layout, void 0, 2)}\n`);
1005
+ process.stdout.write(`${JSON.stringify(layoutDocumentWithSchema(layout), void 0, 2)}\n`);
872
1006
  return 0;
873
1007
  }
874
1008
  const imagesByFormat = countImagesByFormat(layout.images);
@@ -892,19 +1026,9 @@ async function runPdfInspect(input, options) {
892
1026
  const histogramText = Array.from(histogram.entries()).map(([kind, count]) => `${kind}=${count}`).join(", ");
893
1027
  process.stdout.write(` page ${index + 1}: ${page.widthPt}pt x ${page.heightPt}pt${histogramText === "" ? "" : ` (${histogramText})`}\n`);
894
1028
  });
895
- const presentMetadata = [
896
- ["title", layout.metadata.title],
897
- ["author", layout.metadata.author],
898
- ["subject", layout.metadata.subject],
899
- ["keywords", layout.metadata.keywords],
900
- ["creator", layout.metadata.creator],
901
- ["producer", layout.metadata.producer],
902
- ["createdIso", layout.metadata.createdIso],
903
- ["modifiedIso", layout.metadata.modifiedIso]
904
- ].filter(isPresent);
905
- if (presentMetadata.length > 0) {
1029
+ if (presentMetadataEntries(layout.metadata).length > 0) {
906
1030
  process.stdout.write("metadata:\n");
907
- for (const [key, value] of presentMetadata) process.stdout.write(` ${key}: ${formatMetadataValue(value)}\n`);
1031
+ for (const line of formatMetadataLines(layout.metadata)) process.stdout.write(` ${line}\n`);
908
1032
  }
909
1033
  if (imagesByFormat.size > 0) {
910
1034
  process.stdout.write("images:\n");
@@ -922,8 +1046,155 @@ function registerPdfInspectCommand(program) {
922
1046
  });
923
1047
  }
924
1048
  //#endregion
1049
+ //#region src/commands/set-metadata.ts
1050
+ const REBUILD_FORMATS = {
1051
+ docx: true,
1052
+ pptx: true,
1053
+ odt: true,
1054
+ odp: true,
1055
+ ods: true,
1056
+ odg: true,
1057
+ markdown: true
1058
+ };
1059
+ function isRebuildFormat(format) {
1060
+ return format in REBUILD_FORMATS;
1061
+ }
1062
+ function readContentForFormat(format, bytes) {
1063
+ switch (format) {
1064
+ case "docx": return readDocxContent(decodePackage(bytes));
1065
+ case "pptx": return readPptxContent(decodePackage(bytes));
1066
+ case "odt": return readOdtContent(decodePackage$1(bytes));
1067
+ case "odp": return readOdpContent(decodePackage$1(bytes));
1068
+ case "ods": return readOdsContent(decodePackage$1(bytes));
1069
+ case "odg": return readOdgContent(decodePackage$1(bytes));
1070
+ case "markdown": return readMarkdownContent(decodeMarkdownText(bytes));
1071
+ }
1072
+ }
1073
+ function buildBytesForRebuildFormat(format, content) {
1074
+ switch (format) {
1075
+ case "docx": return encodePackage(buildDocxPackage(content));
1076
+ case "pptx": return encodePackage(buildPptxPackage(content));
1077
+ case "odt": return encodePackage$1(buildOdtPackage(content));
1078
+ case "odp": return encodePackage$1(buildOdpPackage(content));
1079
+ case "ods": return encodePackage$1(buildOdsPackage(content));
1080
+ case "odg": return encodePackage$1(buildOdgPackage(content));
1081
+ case "markdown": return encodeMarkdownText(buildMarkdownText(content));
1082
+ }
1083
+ }
1084
+ function mergeMetadata(current, overrides) {
1085
+ return {
1086
+ ...current,
1087
+ ...overrides.title !== void 0 ? { title: overrides.title } : {},
1088
+ ...overrides.author !== void 0 ? { author: overrides.author } : {},
1089
+ ...overrides.subject !== void 0 ? { subject: overrides.subject } : {},
1090
+ ...overrides.keywords !== void 0 ? { keywords: overrides.keywords } : {}
1091
+ };
1092
+ }
1093
+ function parseKeywords(csv) {
1094
+ return csv.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
1095
+ }
1096
+ function classifyWritePath(source, target) {
1097
+ if (source === "pdf" && target === "pdf") return { kind: "pdf" };
1098
+ if (target === "xlsx" || source === "xlsx") return { errorMessage: "'xlsx' is not a supported set-metadata source or target -- documents.js does not re-export a ContentDocument-to-xlsx builder or a readXlsxContent from its own public surface (see that package's own README, Architecture section); convert with 'xlsx-to-ods'/'ods-to-xlsx' first, then set metadata on the ods" };
1099
+ if (target === "odf" || source === "odf") return { errorMessage: "'odf' (a standalone formula document) is not a supported set-metadata source or target -- it has no write path back out at all" };
1100
+ if (!isRebuildFormat(source) || !isRebuildFormat(target)) return { errorMessage: `set-metadata only patches metadata in place; it does not convert format -- source ('${source}') and target ('${target}') must be the same format (or both 'pdf'). Run 'convert'/'from-package' first if you need a different target format.` };
1101
+ if (source !== target) return { errorMessage: `set-metadata only patches metadata in place; it does not convert format -- source ('${source}') and target ('${target}') must be the same format. Run 'convert'/'from-package' first if you need a different target format.` };
1102
+ return {
1103
+ kind: "rebuild",
1104
+ format: source
1105
+ };
1106
+ }
1107
+ async function runSetMetadata(input, output, options) {
1108
+ const command = "set-metadata";
1109
+ if (output !== void 0 && options.out !== void 0 && output !== options.out) {
1110
+ process.stderr.write(`[${command}] conflicting output destinations: positional '${output}' and --out '${options.out}'\n`);
1111
+ return 2;
1112
+ }
1113
+ const target = resolveTargetFormat(output, options.out, options.to);
1114
+ if ("errorMessage" in target) {
1115
+ process.stderr.write(`[${command}] ${target.errorMessage}\n`);
1116
+ return 2;
1117
+ }
1118
+ const source = inferFormatFromExtension(input);
1119
+ if (source === void 0) {
1120
+ process.stderr.write(`[${command}] cannot infer a source format from '${input}'; rename the file with a recognised extension (${KNOWN_DOCUMENT_FORMATS})\n`);
1121
+ return 2;
1122
+ }
1123
+ const writePath = classifyWritePath(source, target.format);
1124
+ if ("errorMessage" in writePath) {
1125
+ process.stderr.write(`[${command}] ${writePath.errorMessage}\n`);
1126
+ return 2;
1127
+ }
1128
+ const overrides = {
1129
+ title: options.setTitle,
1130
+ author: options.setAuthor,
1131
+ subject: options.setSubject,
1132
+ keywords: options.setKeywords === void 0 ? void 0 : parseKeywords(options.setKeywords)
1133
+ };
1134
+ const resolvedOutput = output ?? options.out ?? (input === "-" ? "-" : resolveDefaultOutputPath(input, target.format));
1135
+ const { signal, getAbortReason } = createRuntimeSignal({ timeoutMs: options.timeout });
1136
+ try {
1137
+ const inputBytes = await readInput(input, { signal });
1138
+ const bytes = writePath.kind === "pdf" ? (() => {
1139
+ const layout = readPdf(new Uint8Array(inputBytes), { signal });
1140
+ const patched = {
1141
+ ...layout,
1142
+ metadata: mergeMetadata(layout.metadata, overrides)
1143
+ };
1144
+ return writePdf(patched, { signal });
1145
+ })() : (() => {
1146
+ const content = readContentForFormat(writePath.format, new Uint8Array(inputBytes));
1147
+ const nextContent = {
1148
+ ...content,
1149
+ metadata: mergeMetadata(content.metadata, overrides)
1150
+ };
1151
+ return buildBytesForRebuildFormat(writePath.format, nextContent);
1152
+ })();
1153
+ await writeOutput(resolvedOutput, bytes);
1154
+ createDiagnosticReporter({
1155
+ json: options.json,
1156
+ quiet: options.quiet,
1157
+ command
1158
+ }).summarize({
1159
+ output: resolvedOutput,
1160
+ bytes: bytes.byteLength,
1161
+ diagnosticCount: 0
1162
+ });
1163
+ return 0;
1164
+ } catch (error) {
1165
+ process.stderr.write(`${formatError(error, options.verbose)}\n`);
1166
+ return mapErrorToExit(error, getAbortReason());
1167
+ }
1168
+ }
1169
+ function registerSetMetadataCommand(program) {
1170
+ 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", [
1171
+ "",
1172
+ "Two write paths: a pdf source/target patches the metadata directly on the parsed PDF (writePdf), with no layout engine",
1173
+ "involved at all -- genuinely lossless for everything else on the page. Every other supported format (docx, pptx, odt,",
1174
+ "odp, ods, odg, markdown) rebuilds a fresh package from that format's own ContentDocument -- for docx specifically,",
1175
+ "this is LOSSY: it drops anything docx-extras covers (comments, footnotes, headers/footers, numbering definitions),",
1176
+ "since buildDocxPackage builds a fresh package from the ContentDocument alone, with no way to carry that data through.",
1177
+ "",
1178
+ "set-metadata does not convert format -- source and target must match. Run convert/from-package first, then",
1179
+ "set-metadata on the result, if you need a different target format."
1180
+ ].join("\n"));
1181
+ addOutOption(command);
1182
+ addTimeoutOption(command);
1183
+ addJsonOption(command);
1184
+ addQuietOption(command);
1185
+ addVerboseOption(command);
1186
+ command.option("--to <format>", `target format when it cannot be inferred from the output path (${KNOWN_DOCUMENT_FORMATS})`);
1187
+ command.option("--set-title <text>", "set the title field");
1188
+ command.option("--set-author <text>", "set the author field");
1189
+ command.option("--set-subject <text>", "set the subject field");
1190
+ command.option("--set-keywords <csv>", "set the keywords field, comma-separated (trimmed, empty entries dropped)");
1191
+ command.action(async (input, output, options) => {
1192
+ process.exitCode = await runSetMetadata(input, output, options);
1193
+ });
1194
+ }
1195
+ //#endregion
925
1196
  //#region package.json
926
- var version = "1.3.0";
1197
+ var version = "1.5.0";
927
1198
  //#endregion
928
1199
  //#region src/program.ts
929
1200
  function createProgram() {
@@ -940,13 +1211,17 @@ function createProgram() {
940
1211
  registerOdmCommand(program);
941
1212
  registerOdbCommands(program);
942
1213
  registerPdfInspectCommand(program);
1214
+ registerFontsCommand(program);
1215
+ registerDocxExtrasCommand(program);
1216
+ registerMetadataCommand(program);
1217
+ registerSetMetadataCommand(program);
943
1218
  return program;
944
1219
  }
945
1220
  //#endregion
946
1221
  //#region src/cli.ts
947
1222
  async function launchTui(startPath, signal) {
948
1223
  try {
949
- const { runTui } = await import("./tui-C8ITn1zQ.js");
1224
+ const { runTui } = await import("./tui-B-o3iI9a.js");
950
1225
  await runTui({
951
1226
  startPath,
952
1227
  signal