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/cli.js +284 -11
- package/dist/index.cjs +335 -4
- package/dist/index.js +340 -9
- package/dist/{odb-structure-CX_0zL8_.js → odb-structure-DkfNyHGR.js} +59 -1
- package/dist/{tui-DD4bQp39.js → tui-CQCLalYe.js} +223 -6
- package/package.json +1 -1
|
@@ -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 { createDocx, createOdg, createOdp, createOds, createOdt, createPptx, decodeMarkdownText, docxToPdf, encodeMarkdownText, hsqldbCellDisplayText, markdownToPdf, odgToPdf, odpToPdf, odsToPdf, odtToPdf, openDocx, openOdg, openOdp, openOds, openOdt, openPptx, pptxToPdf, readOdbForms, readOdbReports, readOdbTables, readOdgContent, readOdsContent, readPdf, rgbHexToColor, 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 } 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":
|
|
@@ -238,6 +239,7 @@ function selectionKeyFor(screen) {
|
|
|
238
239
|
case "odbTableRows": return `odbTableRows:${screen.tableName}`;
|
|
239
240
|
case "odbFormDetail": return `odbFormDetail:${screen.formName}`;
|
|
240
241
|
case "odbReportDetail": return `odbReportDetail:${screen.reportName}`;
|
|
242
|
+
case "odbReportRender": return `odbReportRender:${screen.reportName}`;
|
|
241
243
|
case "markdownLineEditor": return `markdownLineEditor:${screen.lineIndex}`;
|
|
242
244
|
}
|
|
243
245
|
}
|
|
@@ -2260,6 +2262,12 @@ function DocxBodyListScreen() {
|
|
|
2260
2262
|
const state = useAppState();
|
|
2261
2263
|
const dispatch = useAppDispatch();
|
|
2262
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) });
|
|
2263
2271
|
if (doc?.format !== "docx") return /* @__PURE__ */ jsxs(Text, {
|
|
2264
2272
|
color: "red",
|
|
2265
2273
|
children: [
|
|
@@ -2277,6 +2285,65 @@ function DocxBodyListScreen() {
|
|
|
2277
2285
|
return /* @__PURE__ */ jsx(ParagraphFamilyBodyList, { adapter });
|
|
2278
2286
|
}
|
|
2279
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
|
|
2280
2347
|
//#region src/tui/screens/editors/markdown/shared.ts
|
|
2281
2348
|
function requireMarkdownDocument(openDocument) {
|
|
2282
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.");
|
|
@@ -2537,7 +2604,15 @@ function OdbReportDetailScreen() {
|
|
|
2537
2604
|
const lines = query === "" ? allLines : allLines.filter((line) => line.toLowerCase().includes(query));
|
|
2538
2605
|
const { selectedIndex } = useNavigationInput({
|
|
2539
2606
|
itemCount: lines.length,
|
|
2540
|
-
onSelect: () => {
|
|
2607
|
+
onSelect: () => {
|
|
2608
|
+
dispatch({
|
|
2609
|
+
type: "PUSH_SCREEN",
|
|
2610
|
+
screen: {
|
|
2611
|
+
kind: "odbReportRender",
|
|
2612
|
+
reportName: report.name
|
|
2613
|
+
}
|
|
2614
|
+
});
|
|
2615
|
+
},
|
|
2541
2616
|
onBack: () => {
|
|
2542
2617
|
dispatch({ type: "POP_SCREEN" });
|
|
2543
2618
|
},
|
|
@@ -2574,7 +2649,7 @@ function OdbReportDetailScreen() {
|
|
|
2574
2649
|
}),
|
|
2575
2650
|
/* @__PURE__ */ jsx(Text, {
|
|
2576
2651
|
dimColor: true,
|
|
2577
|
-
children: "Esc to go back to the report list"
|
|
2652
|
+
children: "Enter to render this report, Esc to go back to the report list"
|
|
2578
2653
|
})
|
|
2579
2654
|
]
|
|
2580
2655
|
});
|
|
@@ -2636,6 +2711,146 @@ function OdbReportListScreen() {
|
|
|
2636
2711
|
});
|
|
2637
2712
|
}
|
|
2638
2713
|
//#endregion
|
|
2714
|
+
//#region src/tui/format/render-odb-report.ts
|
|
2715
|
+
const REPORT_RENDER_TARGET_FORMATS = {
|
|
2716
|
+
docx: true,
|
|
2717
|
+
odt: true,
|
|
2718
|
+
pdf: true
|
|
2719
|
+
};
|
|
2720
|
+
function isReportRenderTargetFormat(format) {
|
|
2721
|
+
return format !== void 0 && format in REPORT_RENDER_TARGET_FORMATS;
|
|
2722
|
+
}
|
|
2723
|
+
function renderReportBytes(content, format, fonts, options) {
|
|
2724
|
+
if (format === "docx") return encodePackage(buildDocxPackage(content));
|
|
2725
|
+
if (format === "odt") return encodePackage$1(buildOdtPackage(content));
|
|
2726
|
+
if (content.kind !== "wordprocessing") throw new Error("readOdbReportContent returned a non-wordprocessing ContentDocument");
|
|
2727
|
+
const registry = createFontRegistry({
|
|
2728
|
+
fonts,
|
|
2729
|
+
onSubstitution: (substitution) => {
|
|
2730
|
+
const requested = `${substitution.requestedFamily}${substitution.requestedBold ? " bold" : ""}${substitution.requestedItalic ? " italic" : ""}`;
|
|
2731
|
+
options.onDiagnostic({
|
|
2732
|
+
severity: "info",
|
|
2733
|
+
message: `No "${requested}" face available; drew it in "${substitution.resolvedFamily}"`
|
|
2734
|
+
});
|
|
2735
|
+
}
|
|
2736
|
+
});
|
|
2737
|
+
const { document: layout, formulas } = convertWordprocessingToLayout(content, { measurer: createFontMeasurer(registry) });
|
|
2738
|
+
return writePdf(layout, {
|
|
2739
|
+
signal: options.signal,
|
|
2740
|
+
onSubstitution: (substitution, context) => {
|
|
2741
|
+
options.onDiagnostic({
|
|
2742
|
+
severity: "info",
|
|
2743
|
+
message: `Substituted "${substitution.to}" for "${substitution.from}"`,
|
|
2744
|
+
pageIndex: context.pageIndex
|
|
2745
|
+
});
|
|
2746
|
+
},
|
|
2747
|
+
formulas,
|
|
2748
|
+
fonts: registry
|
|
2749
|
+
});
|
|
2750
|
+
}
|
|
2751
|
+
async function renderOdbReportTo(doc, destinationPath, options) {
|
|
2752
|
+
const format = detectFormat(destinationPath);
|
|
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`);
|
|
2754
|
+
const fonts = await loadProvidedFonts(options.fontFiles ?? [], { signal: options.signal });
|
|
2755
|
+
const pkg = decodePackage$1(new Uint8Array(await readFile(doc.path)));
|
|
2756
|
+
const bytes = renderReportBytes(readOdbReportContent(pkg, { report: options.reportName }), format, fonts, options);
|
|
2757
|
+
await writeFile(destinationPath, bytes);
|
|
2758
|
+
}
|
|
2759
|
+
//#endregion
|
|
2760
|
+
//#region src/tui/screens/editors/odb/report-render.tsx
|
|
2761
|
+
function defaultReportRenderDestination(odbPath, reportName) {
|
|
2762
|
+
return join(dirname(odbPath), `${reportName}.pdf`);
|
|
2763
|
+
}
|
|
2764
|
+
function parseFontFileField$1(value) {
|
|
2765
|
+
return value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
2766
|
+
}
|
|
2767
|
+
function OdbReportRenderScreen() {
|
|
2768
|
+
const state = useAppState();
|
|
2769
|
+
const dispatch = useAppDispatch();
|
|
2770
|
+
const isActive = !anyOverlayOpen(state);
|
|
2771
|
+
const doc = requireOdbDocument(state.openDocument);
|
|
2772
|
+
const screen = currentScreen(state);
|
|
2773
|
+
if (screen.kind !== "odbReportRender") throw new Error(`OdbReportRenderScreen rendered while the current screen is "${screen.kind}", not "odbReportRender".`);
|
|
2774
|
+
const reportName = screen.reportName;
|
|
2775
|
+
const [destination, setDestination] = useState(() => defaultReportRenderDestination(doc.path, reportName));
|
|
2776
|
+
const [fontFiles, setFontFiles] = useState("");
|
|
2777
|
+
const [field, setField] = useState("destination");
|
|
2778
|
+
const cancel = () => {
|
|
2779
|
+
dispatch({ type: "POP_SCREEN" });
|
|
2780
|
+
};
|
|
2781
|
+
const submit = () => {
|
|
2782
|
+
(async () => {
|
|
2783
|
+
let diagnosticCount = 0;
|
|
2784
|
+
try {
|
|
2785
|
+
await renderOdbReportTo(doc, destination, {
|
|
2786
|
+
reportName,
|
|
2787
|
+
fontFiles: parseFontFileField$1(fontFiles),
|
|
2788
|
+
onDiagnostic: (diagnostic) => {
|
|
2789
|
+
diagnosticCount += 1;
|
|
2790
|
+
dispatch({
|
|
2791
|
+
type: "APPEND_DIAGNOSTIC",
|
|
2792
|
+
diagnostic
|
|
2793
|
+
});
|
|
2794
|
+
}
|
|
2795
|
+
});
|
|
2796
|
+
dispatch({
|
|
2797
|
+
type: "SET_STATUS",
|
|
2798
|
+
severity: "info",
|
|
2799
|
+
text: `Rendered "${reportName}" to ${destination}`
|
|
2800
|
+
});
|
|
2801
|
+
if (diagnosticCount > 0) dispatch({
|
|
2802
|
+
type: "OPEN_OVERLAY",
|
|
2803
|
+
overlay: "diagnosticsPanel"
|
|
2804
|
+
});
|
|
2805
|
+
dispatch({ type: "POP_SCREEN" });
|
|
2806
|
+
} catch (error) {
|
|
2807
|
+
dispatch({
|
|
2808
|
+
type: "OPEN_FILE_ERROR",
|
|
2809
|
+
message: `Could not render "${reportName}" to ${destination}`,
|
|
2810
|
+
detail: describeError(error)
|
|
2811
|
+
});
|
|
2812
|
+
}
|
|
2813
|
+
})();
|
|
2814
|
+
};
|
|
2815
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
2816
|
+
flexDirection: "column",
|
|
2817
|
+
children: [
|
|
2818
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
2819
|
+
bold: true,
|
|
2820
|
+
children: ["Render report: ", reportName]
|
|
2821
|
+
}),
|
|
2822
|
+
/* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
|
|
2823
|
+
color: "cyan",
|
|
2824
|
+
children: "Path: "
|
|
2825
|
+
}), /* @__PURE__ */ jsx(TextField, {
|
|
2826
|
+
value: destination,
|
|
2827
|
+
isFocused: isActive && field === "destination",
|
|
2828
|
+
placeholder: "destination path (.docx, .odt, or .pdf)",
|
|
2829
|
+
onChange: setDestination,
|
|
2830
|
+
onSubmit: () => {
|
|
2831
|
+
setField("fonts");
|
|
2832
|
+
},
|
|
2833
|
+
onCancel: cancel
|
|
2834
|
+
})] }),
|
|
2835
|
+
/* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
|
|
2836
|
+
color: "cyan",
|
|
2837
|
+
children: "Fonts: "
|
|
2838
|
+
}), /* @__PURE__ */ jsx(TextField, {
|
|
2839
|
+
value: fontFiles,
|
|
2840
|
+
isFocused: isActive && field === "fonts",
|
|
2841
|
+
placeholder: "optional .ttf/.otf paths, comma-separated -- pdf only",
|
|
2842
|
+
onChange: setFontFiles,
|
|
2843
|
+
onSubmit: submit,
|
|
2844
|
+
onCancel: cancel
|
|
2845
|
+
})] }),
|
|
2846
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2847
|
+
dimColor: true,
|
|
2848
|
+
children: field === "destination" ? "Enter for fonts, Esc to cancel" : "Enter to render, Esc to cancel. The destination's own extension picks docx/odt/pdf"
|
|
2849
|
+
})
|
|
2850
|
+
]
|
|
2851
|
+
});
|
|
2852
|
+
}
|
|
2853
|
+
//#endregion
|
|
2639
2854
|
//#region src/tui/screens/editors/odb/table-list.tsx
|
|
2640
2855
|
const TABLE_LIST_RESERVED_ROWS = 5;
|
|
2641
2856
|
function OdbTableListScreen() {
|
|
@@ -6039,6 +6254,7 @@ function ScreenBody({ screen }) {
|
|
|
6039
6254
|
case "filePicker": return /* @__PURE__ */ jsx(FilePickerScreen, {});
|
|
6040
6255
|
case "newDocumentPicker": return /* @__PURE__ */ jsx(NewDocumentPickerScreen, {});
|
|
6041
6256
|
case "bodyList": return format === "odt" ? /* @__PURE__ */ jsx(OdtBodyListScreen, {}) : /* @__PURE__ */ jsx(DocxBodyListScreen, {});
|
|
6257
|
+
case "docxExtras": return /* @__PURE__ */ jsx(DocxExtrasScreen, {});
|
|
6042
6258
|
case "paragraphDetail": return /* @__PURE__ */ jsx(ParagraphDetailScreen, {});
|
|
6043
6259
|
case "runEditor": return /* @__PURE__ */ jsx(RunEditorScreen, {});
|
|
6044
6260
|
case "tableView": return /* @__PURE__ */ jsx(TableViewScreen, {});
|
|
@@ -6061,6 +6277,7 @@ function ScreenBody({ screen }) {
|
|
|
6061
6277
|
case "odbFormDetail": return /* @__PURE__ */ jsx(OdbFormDetailScreen, {});
|
|
6062
6278
|
case "odbReportList": return /* @__PURE__ */ jsx(OdbReportListScreen, {});
|
|
6063
6279
|
case "odbReportDetail": return /* @__PURE__ */ jsx(OdbReportDetailScreen, {});
|
|
6280
|
+
case "odbReportRender": return /* @__PURE__ */ jsx(OdbReportRenderScreen, {});
|
|
6064
6281
|
case "markdownLineList": return /* @__PURE__ */ jsx(MarkdownLineListScreen, {});
|
|
6065
6282
|
case "markdownLineEditor": return /* @__PURE__ */ jsx(MarkdownLineEditorScreen, {});
|
|
6066
6283
|
case "pdfPageList": return /* @__PURE__ */ jsx(PdfPageListScreen, {});
|
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": {
|