document-cli 1.2.11 → 1.4.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/index.cjs CHANGED
@@ -162,7 +162,8 @@ const EXIT_INTERRUPTED = 130;
162
162
  function mapErrorToExit(error, abortReason) {
163
163
  if (abortReason === "interrupt") return 130;
164
164
  if (abortReason === "timeout") return 124;
165
- 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) return 3;
165
+ 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;
166
+ if (error instanceof documents_js.HsqldbSqlUnsupportedError || error instanceof documents_js.HsqldbSqlParseError || error instanceof documents_js.HsqldbSqlEvaluationError) return 1;
166
167
  if (error instanceof documents_js.PdfEncryptedError || error instanceof documents_js.PdfParseError) return 1;
167
168
  return 1;
168
169
  }
@@ -532,8 +533,158 @@ function registerConversionCommands(program) {
532
533
  });
533
534
  }
534
535
  //#endregion
536
+ //#region src/docx-extras-format.ts
537
+ const INDENT$1 = " ";
538
+ function indent$1(depth) {
539
+ return INDENT$1.repeat(depth);
540
+ }
541
+ function commentLine(comment, position) {
542
+ const author = comment.author ?? "(no author)";
543
+ return `${indent$1(1)}[${position}] ${author}: ${comment.text}`;
544
+ }
545
+ function footnoteLine(footnote, position) {
546
+ const typeSuffix = footnote.type === void 0 ? "" : ` (${footnote.type})`;
547
+ return `${indent$1(1)}[${position}]${typeSuffix} ${footnote.text}`;
548
+ }
549
+ function commentsSection(comments) {
550
+ if (comments.length === 0) return [];
551
+ return ["comments", ...comments.map((comment, index) => commentLine(comment, index + 1))];
552
+ }
553
+ function footnotesSection(footnotes) {
554
+ if (footnotes.length === 0) return [];
555
+ return ["footnotes", ...footnotes.map((footnote, index) => footnoteLine(footnote, index + 1))];
556
+ }
557
+ function headerOrFooterSection(label, values) {
558
+ if (values.length === 0) return [];
559
+ return [label, ...values.map((text, index) => `${indent$1(1)}[${index + 1}] ${text}`)];
560
+ }
561
+ function numberingLevelLine(ilvl, level) {
562
+ const restartSuffix = level.restart === void 0 ? "" : `, restarts at level ${level.restart}`;
563
+ return `${indent$1(2)}level ${ilvl}: ${level.format} ${JSON.stringify(level.text)} starting at ${level.startAt}${restartSuffix}`;
564
+ }
565
+ function numberingSection(numbering) {
566
+ const numIds = Object.keys(numbering);
567
+ if (numIds.length === 0) return [];
568
+ const lines = ["numbering"];
569
+ for (const numId of numIds) {
570
+ const definition = numbering[numId];
571
+ if (definition === void 0) continue;
572
+ lines.push(`${indent$1(1)}numId ${numId}`);
573
+ const ilvls = Object.keys(definition.levels).sort((a, b) => Number(a) - Number(b));
574
+ for (const ilvl of ilvls) {
575
+ const level = definition.levels[ilvl];
576
+ if (level === void 0) continue;
577
+ lines.push(numberingLevelLine(ilvl, level));
578
+ }
579
+ }
580
+ return lines;
581
+ }
582
+ function formatDocxExtrasLines(extras) {
583
+ const nonEmptySections = [
584
+ commentsSection(extras.comments),
585
+ footnotesSection(extras.footnotes),
586
+ headerOrFooterSection("headers", extras.headers),
587
+ headerOrFooterSection("footers", extras.footers),
588
+ numberingSection(extras.numbering)
589
+ ].filter((section) => section.length > 0);
590
+ if (nonEmptySections.length === 0) return ["This document carries no comments, footnotes, headers, footers, or numbering definitions."];
591
+ return nonEmptySections.flatMap((section, index) => index === 0 ? section : ["", ...section]);
592
+ }
593
+ //#endregion
594
+ //#region src/commands/docx-extras.ts
595
+ async function runDocxExtras(input, options) {
596
+ const command = "docx-extras";
597
+ const { signal, getAbortReason } = createRuntimeSignal({});
598
+ try {
599
+ const inputBytes = await readInput(input, { signal });
600
+ const pkg = (0, documents_js.decodePackage)(new Uint8Array(inputBytes));
601
+ const extras = (0, documents_js.readDocxExtras)(pkg);
602
+ if (options.json) {
603
+ process.stdout.write(`${JSON.stringify(extras)}\n`);
604
+ return 0;
605
+ }
606
+ for (const line of formatDocxExtrasLines(extras)) process.stdout.write(`${line}\n`);
607
+ return 0;
608
+ } catch (error) {
609
+ process.stderr.write(`[${command}] ${formatError(error, false)}\n`);
610
+ return mapErrorToExit(error, getAbortReason());
611
+ }
612
+ }
613
+ function registerDocxExtrasCommand(program) {
614
+ 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) => {
615
+ process.exitCode = await runDocxExtras(input, options);
616
+ });
617
+ }
618
+ //#endregion
619
+ //#region src/commands/fonts.ts
620
+ const FONT_SOURCE_FORMATS = {
621
+ docx: true,
622
+ pptx: true,
623
+ odt: true,
624
+ odp: true,
625
+ ods: true,
626
+ odg: true
627
+ };
628
+ function isFontSourceFormat(format) {
629
+ return format in FONT_SOURCE_FORMATS;
630
+ }
631
+ function resolveFontSourcePackage(format, bytes) {
632
+ if (format === "docx" || format === "pptx") return {
633
+ kind: format,
634
+ package: (0, documents_js.decodePackage)(bytes)
635
+ };
636
+ return {
637
+ kind: "odf",
638
+ package: (0, odf_js.decodePackage)(bytes)
639
+ };
640
+ }
641
+ async function runFonts(input, options) {
642
+ const command = "fonts";
643
+ const { signal, getAbortReason } = createRuntimeSignal({});
644
+ try {
645
+ const format = inferFormatFromExtension(input);
646
+ if (format === void 0) {
647
+ process.stderr.write(`[${command}] cannot infer a document format from '${input}'; expected one of docx, pptx, odt, odp, ods, odg\n`);
648
+ return 2;
649
+ }
650
+ if (!isFontSourceFormat(format)) {
651
+ 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`);
652
+ return 2;
653
+ }
654
+ const inputBytes = await readInput(input, { signal });
655
+ const source = resolveFontSourcePackage(format, new Uint8Array(inputBytes));
656
+ const summaries = (0, documents_js.extractSourceFonts)(source).map((face) => ({
657
+ family: face.family,
658
+ bold: face.bold,
659
+ italic: face.italic,
660
+ byteLength: face.bytes.length
661
+ }));
662
+ if (options.json) {
663
+ process.stdout.write(`${JSON.stringify(summaries)}\n`);
664
+ return 0;
665
+ }
666
+ if (summaries.length === 0) {
667
+ process.stdout.write("This document embeds no source fonts.\n");
668
+ return 0;
669
+ }
670
+ for (const face of summaries) {
671
+ const style = [face.bold ? "bold" : void 0, face.italic ? "italic" : void 0].filter((value) => value !== void 0).join(" ");
672
+ process.stdout.write(`${face.family}${style === "" ? "" : ` (${style})`} -- ${face.byteLength} bytes\n`);
673
+ }
674
+ return 0;
675
+ } catch (error) {
676
+ process.stderr.write(`${formatError(error, false)}\n`);
677
+ return mapErrorToExit(error, getAbortReason());
678
+ }
679
+ }
680
+ function registerFontsCommand(program) {
681
+ 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) => {
682
+ process.exitCode = await runFonts(input, options);
683
+ });
684
+ }
685
+ //#endregion
535
686
  //#region src/commands/formats.ts
536
- const COMMANDS_NOT_LISTED = "odm-to-pdf, odb-to-csv, odb-to-xlsx, odb-tables, odb-forms, odb-reports, pdf-inspect, from-package";
687
+ 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";
537
688
  function registerFormatsCommand(program) {
538
689
  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) => {
539
690
  const { conversions } = (0, documents_js.createLocalDocumentConverter)();
@@ -758,6 +909,27 @@ function formatOdbReportLines(report) {
758
909
  return lines;
759
910
  }
760
911
  //#endregion
912
+ //#region src/sql-result-format.ts
913
+ const COLUMN_GAP = " ";
914
+ function columnWidths(columns, cells) {
915
+ return columns.map((column, index) => {
916
+ const cellWidths = cells.map((row) => row[index]?.length ?? 0);
917
+ return Math.max(column.length, ...cellWidths);
918
+ });
919
+ }
920
+ function formatRow(values, widths) {
921
+ return values.map((value, index) => value.padEnd(widths[index] ?? value.length)).join(COLUMN_GAP).trimEnd();
922
+ }
923
+ function formatSqlResultSetTable(result) {
924
+ const { columns, rows } = result;
925
+ const cells = rows.map((row) => row.map((value) => (0, documents_js.hsqldbCellDisplayText)(value)));
926
+ const widths = columnWidths(columns, cells);
927
+ const lines = [formatRow(columns, widths), formatRow(widths.map((width) => "-".repeat(width)), widths)];
928
+ for (const row of cells) lines.push(formatRow(row, widths));
929
+ lines.push(`${rows.length} row${rows.length === 1 ? "" : "s"}`);
930
+ return lines;
931
+ }
932
+ //#endregion
761
933
  //#region src/commands/odb.ts
762
934
  function reportOdbError(command, error, verbose, abortReason) {
763
935
  if (error instanceof documents_js.OdbNoEmbeddedDataSourceError || error instanceof documents_js.OdbUnsupportedFormatError) {
@@ -774,6 +946,13 @@ function reportOdbCsvError(command, error, verbose, abortReason) {
774
946
  }
775
947
  return reportOdbError(command, error, verbose, abortReason);
776
948
  }
949
+ function reportOdbReportError(command, error, verbose, abortReason) {
950
+ if (error instanceof documents_js.OdbReportNotSpecifiedError) {
951
+ process.stderr.write(`[${command}] ${error.message}\nrun 'odb-reports' first to see the available reports\n`);
952
+ return mapErrorToExit(error, abortReason);
953
+ }
954
+ return reportOdbError(command, error, verbose, abortReason);
955
+ }
777
956
  function resolveDefaultCsvOutputPath(inputPath) {
778
957
  const directory = (0, node_path.dirname)(inputPath);
779
958
  const stem = (0, node_path.basename)(inputPath, (0, node_path.extname)(inputPath));
@@ -859,6 +1038,48 @@ async function runOdbTables(input, options) {
859
1038
  return reportOdbError(command, error, false, getAbortReason());
860
1039
  }
861
1040
  }
1041
+ function resolveQuerySql(pkg, options) {
1042
+ if (options.sql !== void 0) return { sql: options.sql };
1043
+ const queryName = options.query;
1044
+ if (queryName === void 0) return { errorMessage: "pass --sql <text> or --query <savedName>" };
1045
+ const inventory = (0, documents_js.readOdbInventory)(pkg);
1046
+ const saved = inventory.queries.find((candidate) => candidate.name === queryName);
1047
+ if (saved === void 0) {
1048
+ const available = inventory.queries.map((candidate) => candidate.name);
1049
+ return { errorMessage: `this .odb declares no saved query named '${queryName}'${available.length === 0 ? "" : ` -- available: ${available.join(", ")}`}` };
1050
+ }
1051
+ return { sql: saved.command };
1052
+ }
1053
+ async function runOdbQuery(input, options) {
1054
+ const command = "odb-query";
1055
+ if (options.sql !== void 0 && options.query !== void 0) {
1056
+ process.stderr.write(`[${command}] pass --sql or --query, not both\n`);
1057
+ return 2;
1058
+ }
1059
+ if (options.sql === void 0 && options.query === void 0) {
1060
+ process.stderr.write(`[${command}] pass --sql <text> or --query <savedName>\n`);
1061
+ return 2;
1062
+ }
1063
+ const { signal, getAbortReason } = createRuntimeSignal({});
1064
+ try {
1065
+ const inputBytes = await readInput(input, { signal });
1066
+ const pkg = (0, odf_js.decodePackage)(new Uint8Array(inputBytes));
1067
+ const resolved = resolveQuerySql(pkg, options);
1068
+ if ("errorMessage" in resolved) {
1069
+ process.stderr.write(`[${command}] ${resolved.errorMessage}\n`);
1070
+ return 2;
1071
+ }
1072
+ const result = (0, documents_js.evaluateSelect)((0, documents_js.parseSelect)(resolved.sql), (0, documents_js.readOdbTables)(pkg));
1073
+ if (options.json) {
1074
+ process.stdout.write(`${JSON.stringify(result)}\n`);
1075
+ return 0;
1076
+ }
1077
+ for (const line of formatSqlResultSetTable(result)) process.stdout.write(`${line}\n`);
1078
+ return 0;
1079
+ } catch (error) {
1080
+ return reportOdbError(command, error, false, getAbortReason());
1081
+ }
1082
+ }
862
1083
  async function runOdbForms(input, options) {
863
1084
  const command = "odb-forms";
864
1085
  const { signal, getAbortReason } = createRuntimeSignal({});
@@ -905,6 +1126,93 @@ async function runOdbReports(input, options) {
905
1126
  return reportOdbError(command, error, false, getAbortReason());
906
1127
  }
907
1128
  }
1129
+ const ODB_REPORT_TARGET_FORMATS = {
1130
+ docx: true,
1131
+ odt: true,
1132
+ pdf: true
1133
+ };
1134
+ function isOdbReportTargetFormat(format) {
1135
+ return format in ODB_REPORT_TARGET_FORMATS;
1136
+ }
1137
+ function renderOdbReportBytes(content, target, options) {
1138
+ if (target === "docx") return (0, documents_js.encodePackage)((0, documents_js.buildDocxPackage)(content));
1139
+ if (target === "odt") return (0, odf_js.encodePackage)((0, documents_js.buildOdtPackage)(content));
1140
+ if (content.kind !== "wordprocessing") throw new Error("readOdbReportContent returned a non-wordprocessing ContentDocument");
1141
+ const fonts = (0, documents_js.createFontRegistry)({
1142
+ fonts: options.fonts,
1143
+ onSubstitution: (substitution) => {
1144
+ if (options.reportFontSubstitution !== void 0) {
1145
+ options.reportFontSubstitution(substitution);
1146
+ return;
1147
+ }
1148
+ options.onDiagnosticCounted();
1149
+ options.reporter.report(fontSubstitutionToDiagnostic(substitution));
1150
+ }
1151
+ });
1152
+ const { document: layout, formulas } = (0, documents_js.convertWordprocessingToLayout)(content, { measurer: (0, documents_js.createFontMeasurer)(fonts) });
1153
+ return (0, documents_js.writePdf)(layout, {
1154
+ signal: options.signal,
1155
+ onSubstitution: (substitution, context) => {
1156
+ options.onDiagnosticCounted();
1157
+ options.reporter.report(substitutionToDiagnostic(substitution, context.pageIndex));
1158
+ },
1159
+ formulas,
1160
+ fonts
1161
+ });
1162
+ }
1163
+ async function runOdbRenderReport(input, output, options) {
1164
+ const command = "odb-render-report";
1165
+ if (output !== void 0 && options.out !== void 0 && output !== options.out) {
1166
+ process.stderr.write(`[${command}] conflicting output destinations: positional '${output}' and --out '${options.out}'\n`);
1167
+ return 2;
1168
+ }
1169
+ const target = resolveTargetFormat(output, options.out, options.to);
1170
+ if ("errorMessage" in target) {
1171
+ process.stderr.write(`[${command}] ${target.errorMessage}\n`);
1172
+ return 2;
1173
+ }
1174
+ if (!isOdbReportTargetFormat(target.format)) {
1175
+ process.stderr.write(`[${command}] '${target.format}' is not a supported report render target; expected one of docx, odt, pdf\n`);
1176
+ return 2;
1177
+ }
1178
+ const targetFormat = target.format;
1179
+ const resolvedOutput = output ?? options.out ?? (input === "-" ? "-" : resolveDefaultOutputPath(input, targetFormat));
1180
+ const { signal, getAbortReason } = createRuntimeSignal({ timeoutMs: options.timeout });
1181
+ const reporter = createDiagnosticReporter({
1182
+ json: options.json,
1183
+ quiet: options.quiet,
1184
+ command
1185
+ });
1186
+ let diagnosticCount = 0;
1187
+ const reportFontSubstitution = options.reportFontSubstitutions === true ? createFontSubstitutionReporter({
1188
+ json: options.json,
1189
+ quiet: options.quiet,
1190
+ command
1191
+ }) : void 0;
1192
+ try {
1193
+ const inputBytes = await readInput(input, { signal });
1194
+ const fonts = await loadProvidedFonts(options.fontFile ?? [], { signal });
1195
+ const pkg = (0, odf_js.decodePackage)(new Uint8Array(inputBytes));
1196
+ const bytes = renderOdbReportBytes((0, documents_js.readOdbReportContent)(pkg, { report: options.report }), targetFormat, {
1197
+ fonts,
1198
+ signal,
1199
+ reporter,
1200
+ reportFontSubstitution,
1201
+ onDiagnosticCounted: () => {
1202
+ diagnosticCount += 1;
1203
+ }
1204
+ });
1205
+ await writeOutput(resolvedOutput, bytes);
1206
+ reporter.summarize({
1207
+ output: resolvedOutput,
1208
+ bytes: bytes.byteLength,
1209
+ diagnosticCount
1210
+ });
1211
+ return 0;
1212
+ } catch (error) {
1213
+ return reportOdbReportError(command, error, options.verbose, getAbortReason());
1214
+ }
1215
+ }
908
1216
  function registerOdbToXlsxCommand(program) {
909
1217
  const command = program.command("odb-to-xlsx <input> [output]").description("extract every table an embedded .odb database declares into one xlsx workbook, one sheet per table");
910
1218
  addOutOption(command);
@@ -943,12 +1251,33 @@ function registerOdbReportsCommand(program) {
943
1251
  process.exitCode = await runOdbReports(input, options);
944
1252
  });
945
1253
  }
1254
+ function registerOdbQueryCommand(program) {
1255
+ program.command("odb-query <input>").description("run a bounded SELECT over an embedded .odb database's own extracted tables, given directly or by naming one of its saved queries").option("--sql <text>", "the SELECT statement to run -- mutually exclusive with --query").option("--query <savedName>", "the name of one of the .odb's own saved queries to run -- mutually exclusive with --sql").option("--json", "emit the result set as JSON ({ columns, rows }) instead of a plain-text table", false).action(async (input, options) => {
1256
+ process.exitCode = await runOdbQuery(input, options);
1257
+ });
1258
+ }
1259
+ function registerOdbRenderReportCommand(program) {
1260
+ const command = program.command("odb-render-report <input> [output]").description("render one of an .odb's own reports -- its query resolved, its rpt: formulas evaluated, its bands laid out -- to docx, odt, or pdf");
1261
+ addOutOption(command);
1262
+ addTimeoutOption(command);
1263
+ addJsonOption(command);
1264
+ addQuietOption(command);
1265
+ addVerboseOption(command);
1266
+ addFontOptions(command);
1267
+ command.option("--report <name>", "the report to render -- required only when the .odb declares more than one report");
1268
+ command.option("--to <format>", "target format when it cannot be inferred from the output path (docx, odt, pdf)");
1269
+ command.action(async (input, output, options) => {
1270
+ process.exitCode = await runOdbRenderReport(input, output, options);
1271
+ });
1272
+ }
946
1273
  function registerOdbCommands(program) {
947
1274
  registerOdbToXlsxCommand(program);
948
1275
  registerOdbToCsvCommand(program);
949
1276
  registerOdbTablesCommand(program);
950
1277
  registerOdbFormsCommand(program);
951
1278
  registerOdbReportsCommand(program);
1279
+ registerOdbQueryCommand(program);
1280
+ registerOdbRenderReportCommand(program);
952
1281
  }
953
1282
  //#endregion
954
1283
  //#region src/commands/odm.ts
@@ -1074,7 +1403,7 @@ async function runPdfInspect(input, options) {
1074
1403
  }
1075
1404
  });
1076
1405
  if (options.full) {
1077
- process.stdout.write(`${JSON.stringify(layout, void 0, 2)}\n`);
1406
+ process.stdout.write(`${JSON.stringify((0, documents_js.layoutDocumentWithSchema)(layout), void 0, 2)}\n`);
1078
1407
  return 0;
1079
1408
  }
1080
1409
  const imagesByFormat = countImagesByFormat(layout.images);
@@ -1129,7 +1458,7 @@ function registerPdfInspectCommand(program) {
1129
1458
  }
1130
1459
  //#endregion
1131
1460
  //#region package.json
1132
- var version = "1.2.11";
1461
+ var version = "1.4.0";
1133
1462
  //#endregion
1134
1463
  //#region src/program.ts
1135
1464
  function createProgram() {
@@ -1146,6 +1475,8 @@ function createProgram() {
1146
1475
  registerOdmCommand(program);
1147
1476
  registerOdbCommands(program);
1148
1477
  registerPdfInspectCommand(program);
1478
+ registerFontsCommand(program);
1479
+ registerDocxExtrasCommand(program);
1149
1480
  return program;
1150
1481
  }
1151
1482
  //#endregion