document-cli 1.3.0 → 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/cli.js +106 -12
- package/dist/index.cjs +155 -3
- package/dist/index.js +162 -10
- package/dist/{odb-structure-CX_0zL8_.js → odb-structure-DkfNyHGR.js} +59 -1
- package/dist/{tui-C8ITn1zQ.js → tui-CQCLalYe.js} +72 -5
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as odbFormSummary, c as
|
|
2
|
+
import { a as odbFormSummary, c as resolveDefaultOutputPath, f as inferFormatFromExtension, i as formatOdbReportLines, l as writeOutput, n as describeOdbReport, o as formatDocxExtrasLines, p as isDocumentFormat, r as formatOdbFormLines, s as readInput, t as describeOdbForm, u as loadProvidedFonts } from "./odb-structure-DkfNyHGR.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, decodePackage, documentFromJson, documentPackageWithSchema, encodeMarkdownText, encodePackage, evaluateSelect, extractSourceFonts, hsqldbCellDisplayText, layoutDocumentWithSchema, odbToCsv, odbToXlsx, odmToPdf, parseSelect, readDocxExtras, readOdbForms, readOdbInventory, readOdbReportContent, readOdbReports, readOdbTables, readPdf, writePdf } 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";
|
|
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();
|
|
@@ -483,7 +575,7 @@ async function runOdbTables(input, options) {
|
|
|
483
575
|
const { signal, getAbortReason } = createRuntimeSignal({});
|
|
484
576
|
try {
|
|
485
577
|
const inputBytes = await readInput(input, { signal });
|
|
486
|
-
const pkg = decodePackage(new Uint8Array(inputBytes));
|
|
578
|
+
const pkg = decodePackage$1(new Uint8Array(inputBytes));
|
|
487
579
|
const tables = readOdbTables(pkg);
|
|
488
580
|
if (options.json) {
|
|
489
581
|
const summary = tables.map((table) => ({
|
|
@@ -528,7 +620,7 @@ async function runOdbQuery(input, options) {
|
|
|
528
620
|
const { signal, getAbortReason } = createRuntimeSignal({});
|
|
529
621
|
try {
|
|
530
622
|
const inputBytes = await readInput(input, { signal });
|
|
531
|
-
const pkg = decodePackage(new Uint8Array(inputBytes));
|
|
623
|
+
const pkg = decodePackage$1(new Uint8Array(inputBytes));
|
|
532
624
|
const resolved = resolveQuerySql(pkg, options);
|
|
533
625
|
if ("errorMessage" in resolved) {
|
|
534
626
|
process.stderr.write(`[${command}] ${resolved.errorMessage}\n`);
|
|
@@ -550,7 +642,7 @@ async function runOdbForms(input, options) {
|
|
|
550
642
|
const { signal, getAbortReason } = createRuntimeSignal({});
|
|
551
643
|
try {
|
|
552
644
|
const inputBytes = await readInput(input, { signal });
|
|
553
|
-
const forms = readOdbForms(decodePackage(new Uint8Array(inputBytes)));
|
|
645
|
+
const forms = readOdbForms(decodePackage$1(new Uint8Array(inputBytes)));
|
|
554
646
|
if (options.json) {
|
|
555
647
|
process.stdout.write(`${JSON.stringify(forms.map((form) => odbFormSummary(form)))}\n`);
|
|
556
648
|
return 0;
|
|
@@ -573,7 +665,7 @@ async function runOdbReports(input, options) {
|
|
|
573
665
|
const { signal, getAbortReason } = createRuntimeSignal({});
|
|
574
666
|
try {
|
|
575
667
|
const inputBytes = await readInput(input, { signal });
|
|
576
|
-
const reports = readOdbReports(decodePackage(new Uint8Array(inputBytes)));
|
|
668
|
+
const reports = readOdbReports(decodePackage$1(new Uint8Array(inputBytes)));
|
|
577
669
|
if (options.json) {
|
|
578
670
|
process.stdout.write(`${JSON.stringify(reports)}\n`);
|
|
579
671
|
return 0;
|
|
@@ -657,7 +749,7 @@ async function runOdbRenderReport(input, output, options) {
|
|
|
657
749
|
try {
|
|
658
750
|
const inputBytes = await readInput(input, { signal });
|
|
659
751
|
const fonts = await loadProvidedFonts(options.fontFile ?? [], { signal });
|
|
660
|
-
const pkg = decodePackage(new Uint8Array(inputBytes));
|
|
752
|
+
const pkg = decodePackage$1(new Uint8Array(inputBytes));
|
|
661
753
|
const bytes = renderOdbReportBytes(readOdbReportContent(pkg, { report: options.report }), targetFormat, {
|
|
662
754
|
fonts,
|
|
663
755
|
signal,
|
|
@@ -868,7 +960,7 @@ async function runPdfInspect(input, options) {
|
|
|
868
960
|
}
|
|
869
961
|
});
|
|
870
962
|
if (options.full) {
|
|
871
|
-
process.stdout.write(`${JSON.stringify(layout, void 0, 2)}\n`);
|
|
963
|
+
process.stdout.write(`${JSON.stringify(layoutDocumentWithSchema(layout), void 0, 2)}\n`);
|
|
872
964
|
return 0;
|
|
873
965
|
}
|
|
874
966
|
const imagesByFormat = countImagesByFormat(layout.images);
|
|
@@ -923,7 +1015,7 @@ function registerPdfInspectCommand(program) {
|
|
|
923
1015
|
}
|
|
924
1016
|
//#endregion
|
|
925
1017
|
//#region package.json
|
|
926
|
-
var version = "1.
|
|
1018
|
+
var version = "1.4.0";
|
|
927
1019
|
//#endregion
|
|
928
1020
|
//#region src/program.ts
|
|
929
1021
|
function createProgram() {
|
|
@@ -940,13 +1032,15 @@ function createProgram() {
|
|
|
940
1032
|
registerOdmCommand(program);
|
|
941
1033
|
registerOdbCommands(program);
|
|
942
1034
|
registerPdfInspectCommand(program);
|
|
1035
|
+
registerFontsCommand(program);
|
|
1036
|
+
registerDocxExtrasCommand(program);
|
|
943
1037
|
return program;
|
|
944
1038
|
}
|
|
945
1039
|
//#endregion
|
|
946
1040
|
//#region src/cli.ts
|
|
947
1041
|
async function launchTui(startPath, signal) {
|
|
948
1042
|
try {
|
|
949
|
-
const { runTui } = await import("./tui-
|
|
1043
|
+
const { runTui } = await import("./tui-CQCLalYe.js");
|
|
950
1044
|
await runTui({
|
|
951
1045
|
startPath,
|
|
952
1046
|
signal
|
package/dist/index.cjs
CHANGED
|
@@ -533,8 +533,158 @@ function registerConversionCommands(program) {
|
|
|
533
533
|
});
|
|
534
534
|
}
|
|
535
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
|
|
536
686
|
//#region src/commands/formats.ts
|
|
537
|
-
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";
|
|
538
688
|
function registerFormatsCommand(program) {
|
|
539
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) => {
|
|
540
690
|
const { conversions } = (0, documents_js.createLocalDocumentConverter)();
|
|
@@ -1253,7 +1403,7 @@ async function runPdfInspect(input, options) {
|
|
|
1253
1403
|
}
|
|
1254
1404
|
});
|
|
1255
1405
|
if (options.full) {
|
|
1256
|
-
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`);
|
|
1257
1407
|
return 0;
|
|
1258
1408
|
}
|
|
1259
1409
|
const imagesByFormat = countImagesByFormat(layout.images);
|
|
@@ -1308,7 +1458,7 @@ function registerPdfInspectCommand(program) {
|
|
|
1308
1458
|
}
|
|
1309
1459
|
//#endregion
|
|
1310
1460
|
//#region package.json
|
|
1311
|
-
var version = "1.
|
|
1461
|
+
var version = "1.4.0";
|
|
1312
1462
|
//#endregion
|
|
1313
1463
|
//#region src/program.ts
|
|
1314
1464
|
function createProgram() {
|
|
@@ -1325,6 +1475,8 @@ function createProgram() {
|
|
|
1325
1475
|
registerOdmCommand(program);
|
|
1326
1476
|
registerOdbCommands(program);
|
|
1327
1477
|
registerPdfInspectCommand(program);
|
|
1478
|
+
registerFontsCommand(program);
|
|
1479
|
+
registerDocxExtrasCommand(program);
|
|
1328
1480
|
return program;
|
|
1329
1481
|
}
|
|
1330
1482
|
//#endregion
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { readFile, writeFile } from "node:fs/promises";
|
|
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, documentFromJson, documentPackageWithSchema, encodeMarkdownText, encodePackage, evaluateSelect, hsqldbCellDisplayText, odbToCsv, odbToXlsx, odmToPdf, parseSelect, readOdbForms, readOdbInventory, readOdbReportContent, 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 = {
|
|
@@ -532,8 +532,158 @@ function registerConversionCommands(program) {
|
|
|
532
532
|
});
|
|
533
533
|
}
|
|
534
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
|
|
535
685
|
//#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";
|
|
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";
|
|
537
687
|
function registerFormatsCommand(program) {
|
|
538
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) => {
|
|
539
689
|
const { conversions } = createLocalDocumentConverter();
|
|
@@ -867,7 +1017,7 @@ async function runOdbTables(input, options) {
|
|
|
867
1017
|
const { signal, getAbortReason } = createRuntimeSignal({});
|
|
868
1018
|
try {
|
|
869
1019
|
const inputBytes = await readInput(input, { signal });
|
|
870
|
-
const pkg = decodePackage(new Uint8Array(inputBytes));
|
|
1020
|
+
const pkg = decodePackage$1(new Uint8Array(inputBytes));
|
|
871
1021
|
const tables = readOdbTables(pkg);
|
|
872
1022
|
if (options.json) {
|
|
873
1023
|
const summary = tables.map((table) => ({
|
|
@@ -912,7 +1062,7 @@ async function runOdbQuery(input, options) {
|
|
|
912
1062
|
const { signal, getAbortReason } = createRuntimeSignal({});
|
|
913
1063
|
try {
|
|
914
1064
|
const inputBytes = await readInput(input, { signal });
|
|
915
|
-
const pkg = decodePackage(new Uint8Array(inputBytes));
|
|
1065
|
+
const pkg = decodePackage$1(new Uint8Array(inputBytes));
|
|
916
1066
|
const resolved = resolveQuerySql(pkg, options);
|
|
917
1067
|
if ("errorMessage" in resolved) {
|
|
918
1068
|
process.stderr.write(`[${command}] ${resolved.errorMessage}\n`);
|
|
@@ -934,7 +1084,7 @@ async function runOdbForms(input, options) {
|
|
|
934
1084
|
const { signal, getAbortReason } = createRuntimeSignal({});
|
|
935
1085
|
try {
|
|
936
1086
|
const inputBytes = await readInput(input, { signal });
|
|
937
|
-
const forms = readOdbForms(decodePackage(new Uint8Array(inputBytes)));
|
|
1087
|
+
const forms = readOdbForms(decodePackage$1(new Uint8Array(inputBytes)));
|
|
938
1088
|
if (options.json) {
|
|
939
1089
|
process.stdout.write(`${JSON.stringify(forms.map((form) => odbFormSummary(form)))}\n`);
|
|
940
1090
|
return 0;
|
|
@@ -957,7 +1107,7 @@ async function runOdbReports(input, options) {
|
|
|
957
1107
|
const { signal, getAbortReason } = createRuntimeSignal({});
|
|
958
1108
|
try {
|
|
959
1109
|
const inputBytes = await readInput(input, { signal });
|
|
960
|
-
const reports = readOdbReports(decodePackage(new Uint8Array(inputBytes)));
|
|
1110
|
+
const reports = readOdbReports(decodePackage$1(new Uint8Array(inputBytes)));
|
|
961
1111
|
if (options.json) {
|
|
962
1112
|
process.stdout.write(`${JSON.stringify(reports)}\n`);
|
|
963
1113
|
return 0;
|
|
@@ -1041,7 +1191,7 @@ async function runOdbRenderReport(input, output, options) {
|
|
|
1041
1191
|
try {
|
|
1042
1192
|
const inputBytes = await readInput(input, { signal });
|
|
1043
1193
|
const fonts = await loadProvidedFonts(options.fontFile ?? [], { signal });
|
|
1044
|
-
const pkg = decodePackage(new Uint8Array(inputBytes));
|
|
1194
|
+
const pkg = decodePackage$1(new Uint8Array(inputBytes));
|
|
1045
1195
|
const bytes = renderOdbReportBytes(readOdbReportContent(pkg, { report: options.report }), targetFormat, {
|
|
1046
1196
|
fonts,
|
|
1047
1197
|
signal,
|
|
@@ -1252,7 +1402,7 @@ async function runPdfInspect(input, options) {
|
|
|
1252
1402
|
}
|
|
1253
1403
|
});
|
|
1254
1404
|
if (options.full) {
|
|
1255
|
-
process.stdout.write(`${JSON.stringify(layout, void 0, 2)}\n`);
|
|
1405
|
+
process.stdout.write(`${JSON.stringify(layoutDocumentWithSchema(layout), void 0, 2)}\n`);
|
|
1256
1406
|
return 0;
|
|
1257
1407
|
}
|
|
1258
1408
|
const imagesByFormat = countImagesByFormat(layout.images);
|
|
@@ -1307,7 +1457,7 @@ function registerPdfInspectCommand(program) {
|
|
|
1307
1457
|
}
|
|
1308
1458
|
//#endregion
|
|
1309
1459
|
//#region package.json
|
|
1310
|
-
var version = "1.
|
|
1460
|
+
var version = "1.4.0";
|
|
1311
1461
|
//#endregion
|
|
1312
1462
|
//#region src/program.ts
|
|
1313
1463
|
function createProgram() {
|
|
@@ -1324,6 +1474,8 @@ function createProgram() {
|
|
|
1324
1474
|
registerOdmCommand(program);
|
|
1325
1475
|
registerOdbCommands(program);
|
|
1326
1476
|
registerPdfInspectCommand(program);
|
|
1477
|
+
registerFontsCommand(program);
|
|
1478
|
+
registerDocxExtrasCommand(program);
|
|
1327
1479
|
return program;
|
|
1328
1480
|
}
|
|
1329
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,
|
|
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 };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { d as
|
|
1
|
+
import { d as formatToExtension, f as inferFormatFromExtension, i as formatOdbReportLines, n as describeOdbReport, o as formatDocxExtrasLines, r as formatOdbFormLines, s as readInput, t as describeOdbForm, u as loadProvidedFonts } from "./odb-structure-DkfNyHGR.js";
|
|
2
2
|
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
-
import { buildDocxPackage, buildOdtPackage, convertWordprocessingToLayout, createDocx, createFontMeasurer, createFontRegistry, createOdg, createOdp, createOds, createOdt, createPptx, decodeMarkdownText, docxToPdf, encodeMarkdownText, encodePackage, hsqldbCellDisplayText, markdownToPdf, odgToPdf, odpToPdf, odsToPdf, odtToPdf, openDocx, openOdg, openOdp, openOds, openOdt, openPptx, pptxToPdf, readOdbForms, readOdbReportContent, readOdbReports, readOdbTables, readOdgContent, readOdsContent, readPdf, rgbHexToColor, writePdf, xlsxToPdf } from "documents.js";
|
|
3
|
+
import { buildDocxPackage, buildOdtPackage, convertWordprocessingToLayout, createDocx, createFontMeasurer, createFontRegistry, createOdg, createOdp, createOds, createOdt, createPptx, decodeMarkdownText, docxToPdf, encodeMarkdownText, encodePackage, hsqldbCellDisplayText, markdownToPdf, odgToPdf, odpToPdf, odsToPdf, odtToPdf, openDocx, openOdg, openOdp, openOds, openOdt, openPptx, pptxToPdf, readDocxExtras, readOdbForms, readOdbReportContent, readOdbReports, readOdbTables, readOdgContent, readOdsContent, readPdf, rgbHexToColor, writePdf, xlsxToPdf } from "documents.js";
|
|
4
4
|
import { basename, dirname, extname, join } from "node:path";
|
|
5
|
-
import { cellReference, columnIndexToLetters, decodePackage, encodePackage as encodePackage$1 } from "odf.js";
|
|
5
|
+
import { cellReference, columnIndexToLetters, decodePackage as decodePackage$1, encodePackage as encodePackage$1 } from "odf.js";
|
|
6
6
|
import { readdirSync } from "node:fs";
|
|
7
7
|
import { Box, Text, render, useApp, useInput, useWindowSize } from "ink";
|
|
8
8
|
import { createContext, useContext, useEffect, useReducer, useState } from "react";
|
|
@@ -78,7 +78,7 @@ const ODB_EXTENSION = ".odb";
|
|
|
78
78
|
async function openDocumentAtPath(path) {
|
|
79
79
|
const bytes = new Uint8Array(await readFile(path));
|
|
80
80
|
if (path.toLowerCase().endsWith(ODB_EXTENSION)) {
|
|
81
|
-
const pkg = decodePackage(bytes);
|
|
81
|
+
const pkg = decodePackage$1(bytes);
|
|
82
82
|
return {
|
|
83
83
|
format: "odb",
|
|
84
84
|
tables: readOdbTables(pkg),
|
|
@@ -209,6 +209,7 @@ function selectionKeyFor(screen) {
|
|
|
209
209
|
case "launcher":
|
|
210
210
|
case "newDocumentPicker":
|
|
211
211
|
case "bodyList":
|
|
212
|
+
case "docxExtras":
|
|
212
213
|
case "slideList":
|
|
213
214
|
case "sheetList":
|
|
214
215
|
case "pageList":
|
|
@@ -2261,6 +2262,12 @@ function DocxBodyListScreen() {
|
|
|
2261
2262
|
const state = useAppState();
|
|
2262
2263
|
const dispatch = useAppDispatch();
|
|
2263
2264
|
const doc = state.openDocument;
|
|
2265
|
+
useInput((input) => {
|
|
2266
|
+
if (input === "x" && doc?.format === "docx") dispatch({
|
|
2267
|
+
type: "PUSH_SCREEN",
|
|
2268
|
+
screen: { kind: "docxExtras" }
|
|
2269
|
+
});
|
|
2270
|
+
}, { isActive: doc?.format === "docx" && !anyOverlayOpen(state) });
|
|
2264
2271
|
if (doc?.format !== "docx") return /* @__PURE__ */ jsxs(Text, {
|
|
2265
2272
|
color: "red",
|
|
2266
2273
|
children: [
|
|
@@ -2278,6 +2285,65 @@ function DocxBodyListScreen() {
|
|
|
2278
2285
|
return /* @__PURE__ */ jsx(ParagraphFamilyBodyList, { adapter });
|
|
2279
2286
|
}
|
|
2280
2287
|
//#endregion
|
|
2288
|
+
//#region src/tui/screens/editors/docx/extras.tsx
|
|
2289
|
+
const DOCX_EXTRAS_RESERVED_ROWS = 5;
|
|
2290
|
+
function DocxExtrasScreen() {
|
|
2291
|
+
const state = useAppState();
|
|
2292
|
+
const dispatch = useAppDispatch();
|
|
2293
|
+
const doc = state.openDocument;
|
|
2294
|
+
const isDocx = doc?.format === "docx";
|
|
2295
|
+
const extras = doc?.format === "docx" ? readDocxExtras(doc.editor.toPackage()) : void 0;
|
|
2296
|
+
const allLines = extras === void 0 ? [] : formatDocxExtrasLines(extras);
|
|
2297
|
+
const query = state.searchQuery.trim().toLowerCase();
|
|
2298
|
+
const lines = query === "" ? allLines : allLines.filter((line) => line.toLowerCase().includes(query));
|
|
2299
|
+
const { selectedIndex } = useNavigationInput({
|
|
2300
|
+
itemCount: lines.length,
|
|
2301
|
+
onSelect: () => {},
|
|
2302
|
+
onBack: () => {
|
|
2303
|
+
dispatch({ type: "POP_SCREEN" });
|
|
2304
|
+
},
|
|
2305
|
+
isActive: isDocx && !anyOverlayOpen(state)
|
|
2306
|
+
});
|
|
2307
|
+
if (!isDocx) return /* @__PURE__ */ jsxs(Text, {
|
|
2308
|
+
color: "red",
|
|
2309
|
+
children: [
|
|
2310
|
+
"DocxExtrasScreen requires an open docx document, found ",
|
|
2311
|
+
doc === void 0 ? "no open document" : doc.format,
|
|
2312
|
+
"."
|
|
2313
|
+
]
|
|
2314
|
+
});
|
|
2315
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
2316
|
+
flexDirection: "column",
|
|
2317
|
+
children: [
|
|
2318
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
2319
|
+
bold: true,
|
|
2320
|
+
children: [
|
|
2321
|
+
"Comments, footnotes, headers, footers, numbering (",
|
|
2322
|
+
lines.length,
|
|
2323
|
+
" of ",
|
|
2324
|
+
allLines.length,
|
|
2325
|
+
" lines)"
|
|
2326
|
+
]
|
|
2327
|
+
}),
|
|
2328
|
+
/* @__PURE__ */ jsx(ListView, {
|
|
2329
|
+
items: lines,
|
|
2330
|
+
selectedIndex,
|
|
2331
|
+
reservedRows: DOCX_EXTRAS_RESERVED_ROWS,
|
|
2332
|
+
emptyMessage: query === "" ? "This document carries no comments, footnotes, headers, footers, or numbering definitions." : `No lines match "${state.searchQuery}".`,
|
|
2333
|
+
renderItem: (line, isSelected) => /* @__PURE__ */ jsx(Text, {
|
|
2334
|
+
color: isSelected ? "cyan" : void 0,
|
|
2335
|
+
inverse: isSelected,
|
|
2336
|
+
children: line
|
|
2337
|
+
})
|
|
2338
|
+
}),
|
|
2339
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2340
|
+
dimColor: true,
|
|
2341
|
+
children: "Esc to go back to the body list"
|
|
2342
|
+
})
|
|
2343
|
+
]
|
|
2344
|
+
});
|
|
2345
|
+
}
|
|
2346
|
+
//#endregion
|
|
2281
2347
|
//#region src/tui/screens/editors/markdown/shared.ts
|
|
2282
2348
|
function requireMarkdownDocument(openDocument) {
|
|
2283
2349
|
if (openDocument?.format !== "markdown") throw new Error("A markdown editing screen rendered without an open markdown document; the app router only reaches this screen group from markdownLineList, which is only ever the root screen of an open markdown document.");
|
|
@@ -2686,7 +2752,7 @@ async function renderOdbReportTo(doc, destinationPath, options) {
|
|
|
2686
2752
|
const format = detectFormat(destinationPath);
|
|
2687
2753
|
if (!isReportRenderTargetFormat(format)) throw new Error(`Cannot tell whether to render "${options.reportName}" as docx, odt, or pdf from '${destinationPath}' -- give the destination one of those three extensions`);
|
|
2688
2754
|
const fonts = await loadProvidedFonts(options.fontFiles ?? [], { signal: options.signal });
|
|
2689
|
-
const pkg = decodePackage(new Uint8Array(await readFile(doc.path)));
|
|
2755
|
+
const pkg = decodePackage$1(new Uint8Array(await readFile(doc.path)));
|
|
2690
2756
|
const bytes = renderReportBytes(readOdbReportContent(pkg, { report: options.reportName }), format, fonts, options);
|
|
2691
2757
|
await writeFile(destinationPath, bytes);
|
|
2692
2758
|
}
|
|
@@ -6188,6 +6254,7 @@ function ScreenBody({ screen }) {
|
|
|
6188
6254
|
case "filePicker": return /* @__PURE__ */ jsx(FilePickerScreen, {});
|
|
6189
6255
|
case "newDocumentPicker": return /* @__PURE__ */ jsx(NewDocumentPickerScreen, {});
|
|
6190
6256
|
case "bodyList": return format === "odt" ? /* @__PURE__ */ jsx(OdtBodyListScreen, {}) : /* @__PURE__ */ jsx(DocxBodyListScreen, {});
|
|
6257
|
+
case "docxExtras": return /* @__PURE__ */ jsx(DocxExtrasScreen, {});
|
|
6191
6258
|
case "paragraphDetail": return /* @__PURE__ */ jsx(ParagraphDetailScreen, {});
|
|
6192
6259
|
case "runEditor": return /* @__PURE__ */ jsx(RunEditorScreen, {});
|
|
6193
6260
|
case "tableView": return /* @__PURE__ */ jsx(TableViewScreen, {});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "document-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "CLI and interactive Ink TUI for documents.js: every docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/markdown conversion, bridge, and editor as a scriptable command or a terminal app.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|