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.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { readFile, writeFile } from "node:fs/promises";
2
- import { OdbNoEmbeddedDataSourceError, OdbTableNotFoundError, OdbTableNotSpecifiedError, OdbUnsupportedFormatError, OdmUnresolvedSectionError, PdfEncryptedError, PdfParseError, UnrecognizedDocumentSchemaError, buildDocxPackage, buildMarkdownText, buildOdgPackage, buildOdpPackage, buildOdsPackage, buildOdtPackage, buildPptxPackage, createLocalDocumentConverter, documentFromJson, documentPackageWithSchema, encodeMarkdownText, encodePackage, odbToCsv, odbToXlsx, odmToPdf, readOdbForms, readOdbReports, readOdbTables, readPdf, writePdf } from "documents.js";
2
+ import { HsqldbSqlEvaluationError, HsqldbSqlParseError, HsqldbSqlUnsupportedError, OdbNoEmbeddedDataSourceError, OdbReportNotSpecifiedError, OdbTableNotFoundError, OdbTableNotSpecifiedError, OdbUnsupportedFormatError, OdmUnresolvedSectionError, PdfEncryptedError, PdfParseError, UnrecognizedDocumentSchemaError, buildDocxPackage, buildMarkdownText, buildOdgPackage, buildOdpPackage, buildOdsPackage, buildOdtPackage, buildPptxPackage, convertWordprocessingToLayout, createFontMeasurer, createFontRegistry, createLocalDocumentConverter, decodePackage, documentFromJson, documentPackageWithSchema, encodeMarkdownText, encodePackage, evaluateSelect, extractSourceFonts, hsqldbCellDisplayText, layoutDocumentWithSchema, odbToCsv, odbToXlsx, odmToPdf, parseSelect, readDocxExtras, readOdbForms, readOdbInventory, readOdbReportContent, readOdbReports, readOdbTables, readPdf, writePdf } from "documents.js";
3
3
  import { basename, dirname, extname, join } from "node:path";
4
4
  import { Command, InvalidArgumentError } from "commander";
5
- import { decodePackage, encodePackage as encodePackage$1 } from "odf.js";
5
+ import { decodePackage as decodePackage$1, encodePackage as encodePackage$1 } from "odf.js";
6
6
  import { existsSync, readFileSync } from "node:fs";
7
7
  //#region src/format.ts
8
8
  const EXTENSION_TO_FORMAT = {
@@ -161,7 +161,8 @@ const EXIT_INTERRUPTED = 130;
161
161
  function mapErrorToExit(error, abortReason) {
162
162
  if (abortReason === "interrupt") return 130;
163
163
  if (abortReason === "timeout") return 124;
164
- if (error instanceof OdmUnresolvedSectionError || error instanceof OdbTableNotSpecifiedError || error instanceof OdbTableNotFoundError || error instanceof OdbNoEmbeddedDataSourceError || error instanceof OdbUnsupportedFormatError) return 3;
164
+ if (error instanceof OdmUnresolvedSectionError || error instanceof OdbTableNotSpecifiedError || error instanceof OdbTableNotFoundError || error instanceof OdbNoEmbeddedDataSourceError || error instanceof OdbUnsupportedFormatError || error instanceof OdbReportNotSpecifiedError) return 3;
165
+ if (error instanceof HsqldbSqlUnsupportedError || error instanceof HsqldbSqlParseError || error instanceof HsqldbSqlEvaluationError) return 1;
165
166
  if (error instanceof PdfEncryptedError || error instanceof PdfParseError) return 1;
166
167
  return 1;
167
168
  }
@@ -531,8 +532,158 @@ function registerConversionCommands(program) {
531
532
  });
532
533
  }
533
534
  //#endregion
535
+ //#region src/docx-extras-format.ts
536
+ const INDENT$1 = " ";
537
+ function indent$1(depth) {
538
+ return INDENT$1.repeat(depth);
539
+ }
540
+ function commentLine(comment, position) {
541
+ const author = comment.author ?? "(no author)";
542
+ return `${indent$1(1)}[${position}] ${author}: ${comment.text}`;
543
+ }
544
+ function footnoteLine(footnote, position) {
545
+ const typeSuffix = footnote.type === void 0 ? "" : ` (${footnote.type})`;
546
+ return `${indent$1(1)}[${position}]${typeSuffix} ${footnote.text}`;
547
+ }
548
+ function commentsSection(comments) {
549
+ if (comments.length === 0) return [];
550
+ return ["comments", ...comments.map((comment, index) => commentLine(comment, index + 1))];
551
+ }
552
+ function footnotesSection(footnotes) {
553
+ if (footnotes.length === 0) return [];
554
+ return ["footnotes", ...footnotes.map((footnote, index) => footnoteLine(footnote, index + 1))];
555
+ }
556
+ function headerOrFooterSection(label, values) {
557
+ if (values.length === 0) return [];
558
+ return [label, ...values.map((text, index) => `${indent$1(1)}[${index + 1}] ${text}`)];
559
+ }
560
+ function numberingLevelLine(ilvl, level) {
561
+ const restartSuffix = level.restart === void 0 ? "" : `, restarts at level ${level.restart}`;
562
+ return `${indent$1(2)}level ${ilvl}: ${level.format} ${JSON.stringify(level.text)} starting at ${level.startAt}${restartSuffix}`;
563
+ }
564
+ function numberingSection(numbering) {
565
+ const numIds = Object.keys(numbering);
566
+ if (numIds.length === 0) return [];
567
+ const lines = ["numbering"];
568
+ for (const numId of numIds) {
569
+ const definition = numbering[numId];
570
+ if (definition === void 0) continue;
571
+ lines.push(`${indent$1(1)}numId ${numId}`);
572
+ const ilvls = Object.keys(definition.levels).sort((a, b) => Number(a) - Number(b));
573
+ for (const ilvl of ilvls) {
574
+ const level = definition.levels[ilvl];
575
+ if (level === void 0) continue;
576
+ lines.push(numberingLevelLine(ilvl, level));
577
+ }
578
+ }
579
+ return lines;
580
+ }
581
+ function formatDocxExtrasLines(extras) {
582
+ const nonEmptySections = [
583
+ commentsSection(extras.comments),
584
+ footnotesSection(extras.footnotes),
585
+ headerOrFooterSection("headers", extras.headers),
586
+ headerOrFooterSection("footers", extras.footers),
587
+ numberingSection(extras.numbering)
588
+ ].filter((section) => section.length > 0);
589
+ if (nonEmptySections.length === 0) return ["This document carries no comments, footnotes, headers, footers, or numbering definitions."];
590
+ return nonEmptySections.flatMap((section, index) => index === 0 ? section : ["", ...section]);
591
+ }
592
+ //#endregion
593
+ //#region src/commands/docx-extras.ts
594
+ async function runDocxExtras(input, options) {
595
+ const command = "docx-extras";
596
+ const { signal, getAbortReason } = createRuntimeSignal({});
597
+ try {
598
+ const inputBytes = await readInput(input, { signal });
599
+ const pkg = decodePackage(new Uint8Array(inputBytes));
600
+ const extras = readDocxExtras(pkg);
601
+ if (options.json) {
602
+ process.stdout.write(`${JSON.stringify(extras)}\n`);
603
+ return 0;
604
+ }
605
+ for (const line of formatDocxExtrasLines(extras)) process.stdout.write(`${line}\n`);
606
+ return 0;
607
+ } catch (error) {
608
+ process.stderr.write(`[${command}] ${formatError(error, false)}\n`);
609
+ return mapErrorToExit(error, getAbortReason());
610
+ }
611
+ }
612
+ function registerDocxExtrasCommand(program) {
613
+ 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) => {
614
+ process.exitCode = await runDocxExtras(input, options);
615
+ });
616
+ }
617
+ //#endregion
618
+ //#region src/commands/fonts.ts
619
+ const FONT_SOURCE_FORMATS = {
620
+ docx: true,
621
+ pptx: true,
622
+ odt: true,
623
+ odp: true,
624
+ ods: true,
625
+ odg: true
626
+ };
627
+ function isFontSourceFormat(format) {
628
+ return format in FONT_SOURCE_FORMATS;
629
+ }
630
+ function resolveFontSourcePackage(format, bytes) {
631
+ if (format === "docx" || format === "pptx") return {
632
+ kind: format,
633
+ package: decodePackage(bytes)
634
+ };
635
+ return {
636
+ kind: "odf",
637
+ package: decodePackage$1(bytes)
638
+ };
639
+ }
640
+ async function runFonts(input, options) {
641
+ const command = "fonts";
642
+ const { signal, getAbortReason } = createRuntimeSignal({});
643
+ try {
644
+ const format = inferFormatFromExtension(input);
645
+ if (format === void 0) {
646
+ process.stderr.write(`[${command}] cannot infer a document format from '${input}'; expected one of docx, pptx, odt, odp, ods, odg\n`);
647
+ return 2;
648
+ }
649
+ if (!isFontSourceFormat(format)) {
650
+ 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`);
651
+ return 2;
652
+ }
653
+ const inputBytes = await readInput(input, { signal });
654
+ const source = resolveFontSourcePackage(format, new Uint8Array(inputBytes));
655
+ const summaries = extractSourceFonts(source).map((face) => ({
656
+ family: face.family,
657
+ bold: face.bold,
658
+ italic: face.italic,
659
+ byteLength: face.bytes.length
660
+ }));
661
+ if (options.json) {
662
+ process.stdout.write(`${JSON.stringify(summaries)}\n`);
663
+ return 0;
664
+ }
665
+ if (summaries.length === 0) {
666
+ process.stdout.write("This document embeds no source fonts.\n");
667
+ return 0;
668
+ }
669
+ for (const face of summaries) {
670
+ const style = [face.bold ? "bold" : void 0, face.italic ? "italic" : void 0].filter((value) => value !== void 0).join(" ");
671
+ process.stdout.write(`${face.family}${style === "" ? "" : ` (${style})`} -- ${face.byteLength} bytes\n`);
672
+ }
673
+ return 0;
674
+ } catch (error) {
675
+ process.stderr.write(`${formatError(error, false)}\n`);
676
+ return mapErrorToExit(error, getAbortReason());
677
+ }
678
+ }
679
+ function registerFontsCommand(program) {
680
+ 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) => {
681
+ process.exitCode = await runFonts(input, options);
682
+ });
683
+ }
684
+ //#endregion
534
685
  //#region src/commands/formats.ts
535
- const COMMANDS_NOT_LISTED = "odm-to-pdf, odb-to-csv, odb-to-xlsx, odb-tables, odb-forms, odb-reports, pdf-inspect, from-package";
686
+ 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";
536
687
  function registerFormatsCommand(program) {
537
688
  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) => {
538
689
  const { conversions } = createLocalDocumentConverter();
@@ -757,6 +908,27 @@ function formatOdbReportLines(report) {
757
908
  return lines;
758
909
  }
759
910
  //#endregion
911
+ //#region src/sql-result-format.ts
912
+ const COLUMN_GAP = " ";
913
+ function columnWidths(columns, cells) {
914
+ return columns.map((column, index) => {
915
+ const cellWidths = cells.map((row) => row[index]?.length ?? 0);
916
+ return Math.max(column.length, ...cellWidths);
917
+ });
918
+ }
919
+ function formatRow(values, widths) {
920
+ return values.map((value, index) => value.padEnd(widths[index] ?? value.length)).join(COLUMN_GAP).trimEnd();
921
+ }
922
+ function formatSqlResultSetTable(result) {
923
+ const { columns, rows } = result;
924
+ const cells = rows.map((row) => row.map((value) => hsqldbCellDisplayText(value)));
925
+ const widths = columnWidths(columns, cells);
926
+ const lines = [formatRow(columns, widths), formatRow(widths.map((width) => "-".repeat(width)), widths)];
927
+ for (const row of cells) lines.push(formatRow(row, widths));
928
+ lines.push(`${rows.length} row${rows.length === 1 ? "" : "s"}`);
929
+ return lines;
930
+ }
931
+ //#endregion
760
932
  //#region src/commands/odb.ts
761
933
  function reportOdbError(command, error, verbose, abortReason) {
762
934
  if (error instanceof OdbNoEmbeddedDataSourceError || error instanceof OdbUnsupportedFormatError) {
@@ -773,6 +945,13 @@ function reportOdbCsvError(command, error, verbose, abortReason) {
773
945
  }
774
946
  return reportOdbError(command, error, verbose, abortReason);
775
947
  }
948
+ function reportOdbReportError(command, error, verbose, abortReason) {
949
+ if (error instanceof OdbReportNotSpecifiedError) {
950
+ process.stderr.write(`[${command}] ${error.message}\nrun 'odb-reports' first to see the available reports\n`);
951
+ return mapErrorToExit(error, abortReason);
952
+ }
953
+ return reportOdbError(command, error, verbose, abortReason);
954
+ }
776
955
  function resolveDefaultCsvOutputPath(inputPath) {
777
956
  const directory = dirname(inputPath);
778
957
  const stem = basename(inputPath, extname(inputPath));
@@ -838,7 +1017,7 @@ async function runOdbTables(input, options) {
838
1017
  const { signal, getAbortReason } = createRuntimeSignal({});
839
1018
  try {
840
1019
  const inputBytes = await readInput(input, { signal });
841
- const pkg = decodePackage(new Uint8Array(inputBytes));
1020
+ const pkg = decodePackage$1(new Uint8Array(inputBytes));
842
1021
  const tables = readOdbTables(pkg);
843
1022
  if (options.json) {
844
1023
  const summary = tables.map((table) => ({
@@ -858,12 +1037,54 @@ async function runOdbTables(input, options) {
858
1037
  return reportOdbError(command, error, false, getAbortReason());
859
1038
  }
860
1039
  }
1040
+ function resolveQuerySql(pkg, options) {
1041
+ if (options.sql !== void 0) return { sql: options.sql };
1042
+ const queryName = options.query;
1043
+ if (queryName === void 0) return { errorMessage: "pass --sql <text> or --query <savedName>" };
1044
+ const inventory = readOdbInventory(pkg);
1045
+ const saved = inventory.queries.find((candidate) => candidate.name === queryName);
1046
+ if (saved === void 0) {
1047
+ const available = inventory.queries.map((candidate) => candidate.name);
1048
+ return { errorMessage: `this .odb declares no saved query named '${queryName}'${available.length === 0 ? "" : ` -- available: ${available.join(", ")}`}` };
1049
+ }
1050
+ return { sql: saved.command };
1051
+ }
1052
+ async function runOdbQuery(input, options) {
1053
+ const command = "odb-query";
1054
+ if (options.sql !== void 0 && options.query !== void 0) {
1055
+ process.stderr.write(`[${command}] pass --sql or --query, not both\n`);
1056
+ return 2;
1057
+ }
1058
+ if (options.sql === void 0 && options.query === void 0) {
1059
+ process.stderr.write(`[${command}] pass --sql <text> or --query <savedName>\n`);
1060
+ return 2;
1061
+ }
1062
+ const { signal, getAbortReason } = createRuntimeSignal({});
1063
+ try {
1064
+ const inputBytes = await readInput(input, { signal });
1065
+ const pkg = decodePackage$1(new Uint8Array(inputBytes));
1066
+ const resolved = resolveQuerySql(pkg, options);
1067
+ if ("errorMessage" in resolved) {
1068
+ process.stderr.write(`[${command}] ${resolved.errorMessage}\n`);
1069
+ return 2;
1070
+ }
1071
+ const result = evaluateSelect(parseSelect(resolved.sql), readOdbTables(pkg));
1072
+ if (options.json) {
1073
+ process.stdout.write(`${JSON.stringify(result)}\n`);
1074
+ return 0;
1075
+ }
1076
+ for (const line of formatSqlResultSetTable(result)) process.stdout.write(`${line}\n`);
1077
+ return 0;
1078
+ } catch (error) {
1079
+ return reportOdbError(command, error, false, getAbortReason());
1080
+ }
1081
+ }
861
1082
  async function runOdbForms(input, options) {
862
1083
  const command = "odb-forms";
863
1084
  const { signal, getAbortReason } = createRuntimeSignal({});
864
1085
  try {
865
1086
  const inputBytes = await readInput(input, { signal });
866
- const forms = readOdbForms(decodePackage(new Uint8Array(inputBytes)));
1087
+ const forms = readOdbForms(decodePackage$1(new Uint8Array(inputBytes)));
867
1088
  if (options.json) {
868
1089
  process.stdout.write(`${JSON.stringify(forms.map((form) => odbFormSummary(form)))}\n`);
869
1090
  return 0;
@@ -886,7 +1107,7 @@ async function runOdbReports(input, options) {
886
1107
  const { signal, getAbortReason } = createRuntimeSignal({});
887
1108
  try {
888
1109
  const inputBytes = await readInput(input, { signal });
889
- const reports = readOdbReports(decodePackage(new Uint8Array(inputBytes)));
1110
+ const reports = readOdbReports(decodePackage$1(new Uint8Array(inputBytes)));
890
1111
  if (options.json) {
891
1112
  process.stdout.write(`${JSON.stringify(reports)}\n`);
892
1113
  return 0;
@@ -904,6 +1125,93 @@ async function runOdbReports(input, options) {
904
1125
  return reportOdbError(command, error, false, getAbortReason());
905
1126
  }
906
1127
  }
1128
+ const ODB_REPORT_TARGET_FORMATS = {
1129
+ docx: true,
1130
+ odt: true,
1131
+ pdf: true
1132
+ };
1133
+ function isOdbReportTargetFormat(format) {
1134
+ return format in ODB_REPORT_TARGET_FORMATS;
1135
+ }
1136
+ function renderOdbReportBytes(content, target, options) {
1137
+ if (target === "docx") return encodePackage(buildDocxPackage(content));
1138
+ if (target === "odt") return encodePackage$1(buildOdtPackage(content));
1139
+ if (content.kind !== "wordprocessing") throw new Error("readOdbReportContent returned a non-wordprocessing ContentDocument");
1140
+ const fonts = createFontRegistry({
1141
+ fonts: options.fonts,
1142
+ onSubstitution: (substitution) => {
1143
+ if (options.reportFontSubstitution !== void 0) {
1144
+ options.reportFontSubstitution(substitution);
1145
+ return;
1146
+ }
1147
+ options.onDiagnosticCounted();
1148
+ options.reporter.report(fontSubstitutionToDiagnostic(substitution));
1149
+ }
1150
+ });
1151
+ const { document: layout, formulas } = convertWordprocessingToLayout(content, { measurer: createFontMeasurer(fonts) });
1152
+ return writePdf(layout, {
1153
+ signal: options.signal,
1154
+ onSubstitution: (substitution, context) => {
1155
+ options.onDiagnosticCounted();
1156
+ options.reporter.report(substitutionToDiagnostic(substitution, context.pageIndex));
1157
+ },
1158
+ formulas,
1159
+ fonts
1160
+ });
1161
+ }
1162
+ async function runOdbRenderReport(input, output, options) {
1163
+ const command = "odb-render-report";
1164
+ if (output !== void 0 && options.out !== void 0 && output !== options.out) {
1165
+ process.stderr.write(`[${command}] conflicting output destinations: positional '${output}' and --out '${options.out}'\n`);
1166
+ return 2;
1167
+ }
1168
+ const target = resolveTargetFormat(output, options.out, options.to);
1169
+ if ("errorMessage" in target) {
1170
+ process.stderr.write(`[${command}] ${target.errorMessage}\n`);
1171
+ return 2;
1172
+ }
1173
+ if (!isOdbReportTargetFormat(target.format)) {
1174
+ process.stderr.write(`[${command}] '${target.format}' is not a supported report render target; expected one of docx, odt, pdf\n`);
1175
+ return 2;
1176
+ }
1177
+ const targetFormat = target.format;
1178
+ const resolvedOutput = output ?? options.out ?? (input === "-" ? "-" : resolveDefaultOutputPath(input, targetFormat));
1179
+ const { signal, getAbortReason } = createRuntimeSignal({ timeoutMs: options.timeout });
1180
+ const reporter = createDiagnosticReporter({
1181
+ json: options.json,
1182
+ quiet: options.quiet,
1183
+ command
1184
+ });
1185
+ let diagnosticCount = 0;
1186
+ const reportFontSubstitution = options.reportFontSubstitutions === true ? createFontSubstitutionReporter({
1187
+ json: options.json,
1188
+ quiet: options.quiet,
1189
+ command
1190
+ }) : void 0;
1191
+ try {
1192
+ const inputBytes = await readInput(input, { signal });
1193
+ const fonts = await loadProvidedFonts(options.fontFile ?? [], { signal });
1194
+ const pkg = decodePackage$1(new Uint8Array(inputBytes));
1195
+ const bytes = renderOdbReportBytes(readOdbReportContent(pkg, { report: options.report }), targetFormat, {
1196
+ fonts,
1197
+ signal,
1198
+ reporter,
1199
+ reportFontSubstitution,
1200
+ onDiagnosticCounted: () => {
1201
+ diagnosticCount += 1;
1202
+ }
1203
+ });
1204
+ await writeOutput(resolvedOutput, bytes);
1205
+ reporter.summarize({
1206
+ output: resolvedOutput,
1207
+ bytes: bytes.byteLength,
1208
+ diagnosticCount
1209
+ });
1210
+ return 0;
1211
+ } catch (error) {
1212
+ return reportOdbReportError(command, error, options.verbose, getAbortReason());
1213
+ }
1214
+ }
907
1215
  function registerOdbToXlsxCommand(program) {
908
1216
  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");
909
1217
  addOutOption(command);
@@ -942,12 +1250,33 @@ function registerOdbReportsCommand(program) {
942
1250
  process.exitCode = await runOdbReports(input, options);
943
1251
  });
944
1252
  }
1253
+ function registerOdbQueryCommand(program) {
1254
+ 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) => {
1255
+ process.exitCode = await runOdbQuery(input, options);
1256
+ });
1257
+ }
1258
+ function registerOdbRenderReportCommand(program) {
1259
+ 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");
1260
+ addOutOption(command);
1261
+ addTimeoutOption(command);
1262
+ addJsonOption(command);
1263
+ addQuietOption(command);
1264
+ addVerboseOption(command);
1265
+ addFontOptions(command);
1266
+ command.option("--report <name>", "the report to render -- required only when the .odb declares more than one report");
1267
+ command.option("--to <format>", "target format when it cannot be inferred from the output path (docx, odt, pdf)");
1268
+ command.action(async (input, output, options) => {
1269
+ process.exitCode = await runOdbRenderReport(input, output, options);
1270
+ });
1271
+ }
945
1272
  function registerOdbCommands(program) {
946
1273
  registerOdbToXlsxCommand(program);
947
1274
  registerOdbToCsvCommand(program);
948
1275
  registerOdbTablesCommand(program);
949
1276
  registerOdbFormsCommand(program);
950
1277
  registerOdbReportsCommand(program);
1278
+ registerOdbQueryCommand(program);
1279
+ registerOdbRenderReportCommand(program);
951
1280
  }
952
1281
  //#endregion
953
1282
  //#region src/commands/odm.ts
@@ -1073,7 +1402,7 @@ async function runPdfInspect(input, options) {
1073
1402
  }
1074
1403
  });
1075
1404
  if (options.full) {
1076
- process.stdout.write(`${JSON.stringify(layout, void 0, 2)}\n`);
1405
+ process.stdout.write(`${JSON.stringify(layoutDocumentWithSchema(layout), void 0, 2)}\n`);
1077
1406
  return 0;
1078
1407
  }
1079
1408
  const imagesByFormat = countImagesByFormat(layout.images);
@@ -1128,7 +1457,7 @@ function registerPdfInspectCommand(program) {
1128
1457
  }
1129
1458
  //#endregion
1130
1459
  //#region package.json
1131
- var version = "1.2.11";
1460
+ var version = "1.4.0";
1132
1461
  //#endregion
1133
1462
  //#region src/program.ts
1134
1463
  function createProgram() {
@@ -1145,6 +1474,8 @@ function createProgram() {
1145
1474
  registerOdmCommand(program);
1146
1475
  registerOdbCommands(program);
1147
1476
  registerPdfInspectCommand(program);
1477
+ registerFontsCommand(program);
1478
+ registerDocxExtrasCommand(program);
1148
1479
  return program;
1149
1480
  }
1150
1481
  //#endregion
@@ -247,6 +247,64 @@ function resolveDefaultOutputPath(inputPath, targetFormat) {
247
247
  return join(directory, `${stem}.${formatToExtension(targetFormat)}`);
248
248
  }
249
249
  //#endregion
250
+ //#region src/docx-extras-format.ts
251
+ const INDENT$1 = " ";
252
+ function indent$1(depth) {
253
+ return INDENT$1.repeat(depth);
254
+ }
255
+ function commentLine(comment, position) {
256
+ const author = comment.author ?? "(no author)";
257
+ return `${indent$1(1)}[${position}] ${author}: ${comment.text}`;
258
+ }
259
+ function footnoteLine(footnote, position) {
260
+ const typeSuffix = footnote.type === void 0 ? "" : ` (${footnote.type})`;
261
+ return `${indent$1(1)}[${position}]${typeSuffix} ${footnote.text}`;
262
+ }
263
+ function commentsSection(comments) {
264
+ if (comments.length === 0) return [];
265
+ return ["comments", ...comments.map((comment, index) => commentLine(comment, index + 1))];
266
+ }
267
+ function footnotesSection(footnotes) {
268
+ if (footnotes.length === 0) return [];
269
+ return ["footnotes", ...footnotes.map((footnote, index) => footnoteLine(footnote, index + 1))];
270
+ }
271
+ function headerOrFooterSection(label, values) {
272
+ if (values.length === 0) return [];
273
+ return [label, ...values.map((text, index) => `${indent$1(1)}[${index + 1}] ${text}`)];
274
+ }
275
+ function numberingLevelLine(ilvl, level) {
276
+ const restartSuffix = level.restart === void 0 ? "" : `, restarts at level ${level.restart}`;
277
+ return `${indent$1(2)}level ${ilvl}: ${level.format} ${JSON.stringify(level.text)} starting at ${level.startAt}${restartSuffix}`;
278
+ }
279
+ function numberingSection(numbering) {
280
+ const numIds = Object.keys(numbering);
281
+ if (numIds.length === 0) return [];
282
+ const lines = ["numbering"];
283
+ for (const numId of numIds) {
284
+ const definition = numbering[numId];
285
+ if (definition === void 0) continue;
286
+ lines.push(`${indent$1(1)}numId ${numId}`);
287
+ const ilvls = Object.keys(definition.levels).sort((a, b) => Number(a) - Number(b));
288
+ for (const ilvl of ilvls) {
289
+ const level = definition.levels[ilvl];
290
+ if (level === void 0) continue;
291
+ lines.push(numberingLevelLine(ilvl, level));
292
+ }
293
+ }
294
+ return lines;
295
+ }
296
+ function formatDocxExtrasLines(extras) {
297
+ const nonEmptySections = [
298
+ commentsSection(extras.comments),
299
+ footnotesSection(extras.footnotes),
300
+ headerOrFooterSection("headers", extras.headers),
301
+ headerOrFooterSection("footers", extras.footers),
302
+ numberingSection(extras.numbering)
303
+ ].filter((section) => section.length > 0);
304
+ if (nonEmptySections.length === 0) return ["This document carries no comments, footnotes, headers, footers, or numbering definitions."];
305
+ return nonEmptySections.flatMap((section, index) => index === 0 ? section : ["", ...section]);
306
+ }
307
+ //#endregion
250
308
  //#region src/odb-structure.ts
251
309
  const INDENT = " ";
252
310
  function indent(depth) {
@@ -379,4 +437,4 @@ function formatOdbReportLines(report) {
379
437
  return lines;
380
438
  }
381
439
  //#endregion
382
- export { odbFormSummary as a, writeOutput as c, inferFormatFromExtension as d, isDocumentFormat as f, formatOdbReportLines as i, loadProvidedFonts as l, describeOdbReport as n, readInput as o, formatOdbFormLines as r, resolveDefaultOutputPath as s, describeOdbForm as t, formatToExtension as u };
440
+ export { odbFormSummary as a, resolveDefaultOutputPath as c, formatToExtension as d, inferFormatFromExtension as f, formatOdbReportLines as i, writeOutput as l, describeOdbReport as n, formatDocxExtrasLines as o, isDocumentFormat as p, formatOdbFormLines as r, readInput as s, describeOdbForm as t, loadProvidedFonts as u };