document-cli 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
- import { d as inferFormatFromExtension, i as formatOdbReportLines, l as loadProvidedFonts, n as describeOdbReport, o as readInput, r as formatOdbFormLines, t as describeOdbForm, u as formatToExtension } from "./odb-structure-CX_0zL8_.js";
1
+ import { c as formatDocxExtrasLines, f as loadProvidedFonts, i as formatOdbReportLines, l as readInput, m as inferFormatFromExtension, n as describeOdbReport, o as formatMetadataLines, p as formatToExtension, r as formatOdbFormLines, t as describeOdbForm } from "./odb-structure-Du1w_hOU.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, readDocxContent, readDocxExtras, readMarkdownContent, readOdbForms, readOdbReportContent, readOdbReports, readOdbTables, readOdgContent, readOdpContent, readOdsContent, readOdtContent, readPdf, readPptxContent, 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":
@@ -218,7 +219,8 @@ function selectionKeyFor(screen) {
218
219
  case "pdfPageList":
219
220
  case "exportOptions":
220
221
  case "saveAsPrompt":
221
- case "markdownLineList": return screen.kind;
222
+ case "markdownLineList":
223
+ case "metadata": return screen.kind;
222
224
  case "filePicker": return `filePicker:${screen.purpose}:${screen.cwd}`;
223
225
  case "paragraphDetail":
224
226
  case "tableView":
@@ -1416,6 +1418,10 @@ const GLOBAL_KEYS = [
1416
1418
  keys: "a",
1417
1419
  description: "Append a new item to the current list"
1418
1420
  },
1421
+ {
1422
+ keys: "m",
1423
+ description: "Show the open document's metadata (read-only)"
1424
+ },
1419
1425
  {
1420
1426
  keys: "Ctrl+S",
1421
1427
  description: "Save the open document"
@@ -2261,6 +2267,12 @@ function DocxBodyListScreen() {
2261
2267
  const state = useAppState();
2262
2268
  const dispatch = useAppDispatch();
2263
2269
  const doc = state.openDocument;
2270
+ useInput((input) => {
2271
+ if (input === "x" && doc?.format === "docx") dispatch({
2272
+ type: "PUSH_SCREEN",
2273
+ screen: { kind: "docxExtras" }
2274
+ });
2275
+ }, { isActive: doc?.format === "docx" && !anyOverlayOpen(state) });
2264
2276
  if (doc?.format !== "docx") return /* @__PURE__ */ jsxs(Text, {
2265
2277
  color: "red",
2266
2278
  children: [
@@ -2278,6 +2290,65 @@ function DocxBodyListScreen() {
2278
2290
  return /* @__PURE__ */ jsx(ParagraphFamilyBodyList, { adapter });
2279
2291
  }
2280
2292
  //#endregion
2293
+ //#region src/tui/screens/editors/docx/extras.tsx
2294
+ const DOCX_EXTRAS_RESERVED_ROWS = 5;
2295
+ function DocxExtrasScreen() {
2296
+ const state = useAppState();
2297
+ const dispatch = useAppDispatch();
2298
+ const doc = state.openDocument;
2299
+ const isDocx = doc?.format === "docx";
2300
+ const extras = doc?.format === "docx" ? readDocxExtras(doc.editor.toPackage()) : void 0;
2301
+ const allLines = extras === void 0 ? [] : formatDocxExtrasLines(extras);
2302
+ const query = state.searchQuery.trim().toLowerCase();
2303
+ const lines = query === "" ? allLines : allLines.filter((line) => line.toLowerCase().includes(query));
2304
+ const { selectedIndex } = useNavigationInput({
2305
+ itemCount: lines.length,
2306
+ onSelect: () => {},
2307
+ onBack: () => {
2308
+ dispatch({ type: "POP_SCREEN" });
2309
+ },
2310
+ isActive: isDocx && !anyOverlayOpen(state)
2311
+ });
2312
+ if (!isDocx) return /* @__PURE__ */ jsxs(Text, {
2313
+ color: "red",
2314
+ children: [
2315
+ "DocxExtrasScreen requires an open docx document, found ",
2316
+ doc === void 0 ? "no open document" : doc.format,
2317
+ "."
2318
+ ]
2319
+ });
2320
+ return /* @__PURE__ */ jsxs(Box, {
2321
+ flexDirection: "column",
2322
+ children: [
2323
+ /* @__PURE__ */ jsxs(Text, {
2324
+ bold: true,
2325
+ children: [
2326
+ "Comments, footnotes, headers, footers, numbering (",
2327
+ lines.length,
2328
+ " of ",
2329
+ allLines.length,
2330
+ " lines)"
2331
+ ]
2332
+ }),
2333
+ /* @__PURE__ */ jsx(ListView, {
2334
+ items: lines,
2335
+ selectedIndex,
2336
+ reservedRows: DOCX_EXTRAS_RESERVED_ROWS,
2337
+ emptyMessage: query === "" ? "This document carries no comments, footnotes, headers, footers, or numbering definitions." : `No lines match "${state.searchQuery}".`,
2338
+ renderItem: (line, isSelected) => /* @__PURE__ */ jsx(Text, {
2339
+ color: isSelected ? "cyan" : void 0,
2340
+ inverse: isSelected,
2341
+ children: line
2342
+ })
2343
+ }),
2344
+ /* @__PURE__ */ jsx(Text, {
2345
+ dimColor: true,
2346
+ children: "Esc to go back to the body list"
2347
+ })
2348
+ ]
2349
+ });
2350
+ }
2351
+ //#endregion
2281
2352
  //#region src/tui/screens/editors/markdown/shared.ts
2282
2353
  function requireMarkdownDocument(openDocument) {
2283
2354
  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 +2757,7 @@ async function renderOdbReportTo(doc, destinationPath, options) {
2686
2757
  const format = detectFormat(destinationPath);
2687
2758
  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
2759
  const fonts = await loadProvidedFonts(options.fontFiles ?? [], { signal: options.signal });
2689
- const pkg = decodePackage(new Uint8Array(await readFile(doc.path)));
2760
+ const pkg = decodePackage$1(new Uint8Array(await readFile(doc.path)));
2690
2761
  const bytes = renderReportBytes(readOdbReportContent(pkg, { report: options.reportName }), format, fonts, options);
2691
2762
  await writeFile(destinationPath, bytes);
2692
2763
  }
@@ -6174,6 +6245,67 @@ function SaveAsPromptScreen() {
6174
6245
  });
6175
6246
  }
6176
6247
  //#endregion
6248
+ //#region src/tui/format/read-metadata.ts
6249
+ function metadataFor(doc) {
6250
+ switch (doc.format) {
6251
+ case "docx": return readDocxContent(doc.editor.toPackage()).metadata;
6252
+ case "pptx": return readPptxContent(doc.editor.toPackage()).metadata;
6253
+ case "odt": return readOdtContent(doc.editor.toPackage()).metadata;
6254
+ case "odp": return readOdpContent(doc.editor.toPackage()).metadata;
6255
+ case "ods": return readOdsContent(doc.editor.toPackage()).metadata;
6256
+ case "odg": return readOdgContent(doc.editor.toPackage()).metadata;
6257
+ case "markdown": return readMarkdownContent(doc.source).metadata;
6258
+ case "pdf":
6259
+ case "xlsx": return doc.layout.metadata;
6260
+ case "odb": throw new Error("A .odb database has no document-level metadata -- it is a table/form/report container, not a single document with its own title/author/etc.");
6261
+ }
6262
+ }
6263
+ //#endregion
6264
+ //#region src/tui/screens/shared/metadata.tsx
6265
+ function MetadataScreen() {
6266
+ const state = useAppState();
6267
+ const dispatch = useAppDispatch();
6268
+ const doc = state.openDocument;
6269
+ useInput((input, key) => {
6270
+ if (key.escape || key.leftArrow || input === "h") dispatch({ type: "POP_SCREEN" });
6271
+ }, { isActive: doc !== void 0 && !anyOverlayOpen(state) });
6272
+ if (doc === void 0) return /* @__PURE__ */ jsx(Text, {
6273
+ color: "red",
6274
+ children: "MetadataScreen requires an open document."
6275
+ });
6276
+ let lines;
6277
+ let errorMessage;
6278
+ try {
6279
+ lines = formatMetadataLines(metadataFor(doc));
6280
+ } catch (error) {
6281
+ errorMessage = error instanceof Error ? error.message : String(error);
6282
+ }
6283
+ return /* @__PURE__ */ jsxs(Box, {
6284
+ flexDirection: "column",
6285
+ children: [
6286
+ /* @__PURE__ */ jsxs(Text, {
6287
+ bold: true,
6288
+ children: [
6289
+ "Document metadata (",
6290
+ doc.format,
6291
+ ")"
6292
+ ]
6293
+ }),
6294
+ errorMessage !== void 0 ? /* @__PURE__ */ jsx(Text, {
6295
+ color: "yellow",
6296
+ children: errorMessage
6297
+ }) : lines !== void 0 && lines.length > 0 ? lines.map((line) => /* @__PURE__ */ jsx(Text, { children: line }, line)) : /* @__PURE__ */ jsx(Text, {
6298
+ dimColor: true,
6299
+ children: "This document carries no metadata."
6300
+ }),
6301
+ /* @__PURE__ */ jsx(Text, {
6302
+ dimColor: true,
6303
+ children: "Esc / ← / h to go back"
6304
+ })
6305
+ ]
6306
+ });
6307
+ }
6308
+ //#endregion
6177
6309
  //#region src/tui/app.tsx
6178
6310
  function App(props) {
6179
6311
  return /* @__PURE__ */ jsx(AppStateProvider, {
@@ -6188,6 +6320,7 @@ function ScreenBody({ screen }) {
6188
6320
  case "filePicker": return /* @__PURE__ */ jsx(FilePickerScreen, {});
6189
6321
  case "newDocumentPicker": return /* @__PURE__ */ jsx(NewDocumentPickerScreen, {});
6190
6322
  case "bodyList": return format === "odt" ? /* @__PURE__ */ jsx(OdtBodyListScreen, {}) : /* @__PURE__ */ jsx(DocxBodyListScreen, {});
6323
+ case "docxExtras": return /* @__PURE__ */ jsx(DocxExtrasScreen, {});
6191
6324
  case "paragraphDetail": return /* @__PURE__ */ jsx(ParagraphDetailScreen, {});
6192
6325
  case "runEditor": return /* @__PURE__ */ jsx(RunEditorScreen, {});
6193
6326
  case "tableView": return /* @__PURE__ */ jsx(TableViewScreen, {});
@@ -6218,6 +6351,7 @@ function ScreenBody({ screen }) {
6218
6351
  case "pdfItemDetail": return /* @__PURE__ */ jsx(PdfItemDetailScreen, {});
6219
6352
  case "exportOptions": return /* @__PURE__ */ jsx(ExportOptionsScreen, {});
6220
6353
  case "saveAsPrompt": return /* @__PURE__ */ jsx(SaveAsPromptScreen, {});
6354
+ case "metadata": return /* @__PURE__ */ jsx(MetadataScreen, {});
6221
6355
  }
6222
6356
  }
6223
6357
  function Overlay({ state }) {
@@ -6328,10 +6462,27 @@ function AppShell({ startPath }) {
6328
6462
  });
6329
6463
  return;
6330
6464
  }
6331
- if (key.ctrl && input === "d") dispatch({
6332
- type: "OPEN_OVERLAY",
6333
- overlay: "diagnosticsPanel"
6334
- });
6465
+ if (key.ctrl && input === "d") {
6466
+ dispatch({
6467
+ type: "OPEN_OVERLAY",
6468
+ overlay: "diagnosticsPanel"
6469
+ });
6470
+ return;
6471
+ }
6472
+ if (input === "m") {
6473
+ if (state.openDocument === void 0) {
6474
+ dispatch({
6475
+ type: "SET_STATUS",
6476
+ severity: "warning",
6477
+ text: "There is no open document to show metadata for"
6478
+ });
6479
+ return;
6480
+ }
6481
+ dispatch({
6482
+ type: "PUSH_SCREEN",
6483
+ screen: { kind: "metadata" }
6484
+ });
6485
+ }
6335
6486
  }, { isActive: !overlayOpen });
6336
6487
  return /* @__PURE__ */ jsxs(Box, {
6337
6488
  flexDirection: "column",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "document-cli",
3
- "version": "1.3.0",
3
+ "version": "1.5.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": {