document-cli 5.11.51 → 5.12.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/README.md +2 -2
- package/dist/cli.js +23 -23
- package/dist/index.cjs +22 -22
- package/dist/index.js +22 -22
- package/dist/{odb-structure-yc8OHoC0.js → odb-structure-Crz3Yzzb.js} +2 -2
- package/dist/{tui-CogHEvyJ.js → tui-y8MLtP8W.js} +60 -60
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -277,8 +277,8 @@ pnpm typecheck # turbo run _typecheck -> tsc --noEmit
|
|
|
277
277
|
pnpm lint # turbo run _lint -> eslint . --fix --cache --max-warnings 0
|
|
278
278
|
pnpm test # turbo run _test -> vitest run --project unit
|
|
279
279
|
pnpm test:watch # vitest --project unit
|
|
280
|
-
pnpm test:smoke # turbo run _test:smoke -> tsdown, then vitest run --project smoke
|
|
281
|
-
pnpm test:workers # turbo run _test:workers -> vitest run --config vitest.workers.config.ts
|
|
280
|
+
pnpm test:smoke # turbo run _test:smoke -> tsdown, then vitest run --project smoke — spawns the built dist/cli.js as a real child process
|
|
281
|
+
pnpm test:workers # turbo run _test:workers -> vitest run --config vitest.workers.config.ts — runs the thin isomorphic slice (src/sql-result-format.ts, src/runtime/exit-codes.ts) under the real Cloudflare Workers runtime (workerd), proving the wrapped documents.js paths execute inside a workerd isolate with no Node-only API usage
|
|
282
282
|
```
|
|
283
283
|
|
|
284
284
|
## Gotchas
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as odbFormSummary, c as presentMetadataEntries, d as resolveDefaultOutputPath, f as writeOutput, g as isDocumentFormat, h as inferFormatFromExtension, i as formatOdbReportLines, l as formatDocxExtrasLines, n as describeOdbReport, o as formatMetadataLines, p as loadProvidedFonts, r as formatOdbFormLines, t as describeOdbForm, u as readInput } from "./odb-structure-
|
|
2
|
+
import { a as odbFormSummary, c as presentMetadataEntries, d as resolveDefaultOutputPath, f as writeOutput, g as isDocumentFormat, h as inferFormatFromExtension, i as formatOdbReportLines, l as formatDocxExtrasLines, n as describeOdbReport, o as formatMetadataLines, p as loadProvidedFonts, r as formatOdbFormLines, t as describeOdbForm, u as readInput } from "./odb-structure-Crz3Yzzb.js";
|
|
3
3
|
import { Command, CommanderError, InvalidArgumentError } from "commander";
|
|
4
4
|
import { writeFile } from "node:fs/promises";
|
|
5
5
|
import { basename, dirname, extname, join, resolve } from "node:path";
|
|
@@ -142,7 +142,7 @@ function resolveTargetFormat(output, out, to) {
|
|
|
142
142
|
return { format: to };
|
|
143
143
|
}
|
|
144
144
|
const destination = output ?? out;
|
|
145
|
-
if (destination === void 0) return { errorMessage: "cannot infer a target format
|
|
145
|
+
if (destination === void 0) return { errorMessage: "cannot infer a target format — pass an output path with a recognised extension, --out with one, or --to <format>" };
|
|
146
146
|
const inferred = inferFormatFromExtension(destination);
|
|
147
147
|
if (inferred === void 0) return { errorMessage: `cannot infer a target format from '${destination}'; pass --to <format> instead` };
|
|
148
148
|
return { format: inferred };
|
|
@@ -275,11 +275,11 @@ function toConversionCommandOptions(options) {
|
|
|
275
275
|
async function runGenericConvert(input, output, options) {
|
|
276
276
|
const extension = extname(input).toLowerCase();
|
|
277
277
|
if (extension === ".odm") {
|
|
278
|
-
process.stderr.write("convert: '.odm' master documents are not supported by the generic convert command
|
|
278
|
+
process.stderr.write("convert: '.odm' master documents are not supported by the generic convert command — use 'odm-to-pdf' instead\n");
|
|
279
279
|
return 2;
|
|
280
280
|
}
|
|
281
281
|
if (extension === ".odb") {
|
|
282
|
-
process.stderr.write("convert: '.odb' embedded databases are not supported by the generic convert command
|
|
282
|
+
process.stderr.write("convert: '.odb' embedded databases are not supported by the generic convert command — use 'odb-to-csv', 'odb-to-xlsx', or 'odb-tables' instead\n");
|
|
283
283
|
return 2;
|
|
284
284
|
}
|
|
285
285
|
const source = inferFormatFromExtension(input);
|
|
@@ -342,7 +342,7 @@ async function runDocxExtras(input, options) {
|
|
|
342
342
|
}
|
|
343
343
|
}
|
|
344
344
|
function registerDocxExtrasCommand(program) {
|
|
345
|
-
program.command("docx-extras <input>").description("print a docx's own comments, footnotes, headers, footers, and numbering definitions
|
|
345
|
+
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) => {
|
|
346
346
|
process.exitCode = await runDocxExtras(input, options);
|
|
347
347
|
});
|
|
348
348
|
}
|
|
@@ -374,7 +374,7 @@ async function runFonts(input, options) {
|
|
|
374
374
|
}
|
|
375
375
|
for (const face of summaries) {
|
|
376
376
|
const style = [face.bold ? "bold" : void 0, face.italic ? "italic" : void 0].filter((value) => value !== void 0).join(" ");
|
|
377
|
-
process.stdout.write(`${face.family}${style === "" ? "" : ` (${style})`}
|
|
377
|
+
process.stdout.write(`${face.family}${style === "" ? "" : ` (${style})`} — ${face.byteLength} bytes\n`);
|
|
378
378
|
}
|
|
379
379
|
return 0;
|
|
380
380
|
} catch (error) {
|
|
@@ -439,7 +439,7 @@ async function runFromPackage(input, output, options) {
|
|
|
439
439
|
}
|
|
440
440
|
const result = documentFromJson(parsed);
|
|
441
441
|
if (result.kind !== "DocumentTree") {
|
|
442
|
-
process.stderr.write(`[${command}] '${input}' is a ${result.kind}, not a DocumentTree
|
|
442
|
+
process.stderr.write(`[${command}] '${input}' is a ${result.kind}, not a DocumentTree — only a file written by --dump-package can be read back by this command\n`);
|
|
443
443
|
return 2;
|
|
444
444
|
}
|
|
445
445
|
const content = flattenTree(result.value);
|
|
@@ -460,19 +460,19 @@ async function runFromPackage(input, output, options) {
|
|
|
460
460
|
return 0;
|
|
461
461
|
} catch (error) {
|
|
462
462
|
if (error instanceof UnrecognizedDocumentSchemaError) {
|
|
463
|
-
process.stderr.write(`[${command}] '${input}' has no recognised $schema
|
|
463
|
+
process.stderr.write(`[${command}] '${input}' has no recognised $schema — only a file written by --dump-package can be read back by this command\n`);
|
|
464
464
|
return 1;
|
|
465
465
|
}
|
|
466
466
|
if (isSchemaVersionMismatchError(error)) {
|
|
467
|
-
process.stderr.write(`[${command}] '${input}' is a DocumentTree dump from document-schema.js@${error.dumpVersion}, but this CLI's documents.js reads only @${error.installedVersion}-major dumps
|
|
467
|
+
process.stderr.write(`[${command}] '${input}' is a DocumentTree dump from document-schema.js@${error.dumpVersion}, but this CLI's documents.js reads only @${error.installedVersion}-major dumps — 4.0.0 replaced the flat { formatVersion, content, pages } shape with the tree-form DocumentTree (ExaDev/document-schema.js#20); re-run the source conversion with --dump-package to write a current dump\n`);
|
|
468
468
|
return 1;
|
|
469
469
|
}
|
|
470
470
|
if (isLayoutSchemaDemotedError(error)) {
|
|
471
|
-
process.stderr.write(`[${command}] '${input}' is a LayoutDocument dump
|
|
471
|
+
process.stderr.write(`[${command}] '${input}' is a LayoutDocument dump — LayoutDocument moved to pdf-codec in document-schema.js 4.0.0 and is no longer a schema-stamped input; re-run the source conversion with --dump-package and read that package back instead\n`);
|
|
472
472
|
return 1;
|
|
473
473
|
}
|
|
474
474
|
if (isDocumentPackageRenamedError(error)) {
|
|
475
|
-
process.stderr.write(`[${command}] '${input}' is a document-package dump
|
|
475
|
+
process.stderr.write(`[${command}] '${input}' is a document-package dump — DocumentPackage was renamed to DocumentTree in document-schema.js 5.0.0 (ExaDev/documents.js#661); re-run the source conversion with --dump-package to write a current tree-form DocumentTree dump\n`);
|
|
476
476
|
return 1;
|
|
477
477
|
}
|
|
478
478
|
process.stderr.write(`${formatError(error, options.verbose)}\n`);
|
|
@@ -666,7 +666,7 @@ function resolveQuerySql(pkg, options) {
|
|
|
666
666
|
const saved = inventory.queries.find((candidate) => candidate.name === queryName);
|
|
667
667
|
if (saved === void 0) {
|
|
668
668
|
const available = inventory.queries.map((candidate) => candidate.name);
|
|
669
|
-
return { errorMessage: `this .odb declares no saved query named '${queryName}'${available.length === 0 ? "" : `
|
|
669
|
+
return { errorMessage: `this .odb declares no saved query named '${queryName}'${available.length === 0 ? "" : ` — available: ${available.join(", ")}`}` };
|
|
670
670
|
}
|
|
671
671
|
return { sql: saved.command };
|
|
672
672
|
}
|
|
@@ -833,7 +833,7 @@ function registerOdbToCsvCommand(program) {
|
|
|
833
833
|
addJsonOption(command);
|
|
834
834
|
addQuietOption(command);
|
|
835
835
|
addVerboseOption(command);
|
|
836
|
-
command.option("--table <name>", "the table to export
|
|
836
|
+
command.option("--table <name>", "the table to export — required when the .odb declares more than one table");
|
|
837
837
|
command.action(async (input, output, options) => {
|
|
838
838
|
process.exitCode = await runOdbToCsv(input, output, options);
|
|
839
839
|
});
|
|
@@ -854,19 +854,19 @@ function registerOdbReportsCommand(program) {
|
|
|
854
854
|
});
|
|
855
855
|
}
|
|
856
856
|
function registerOdbQueryCommand(program) {
|
|
857
|
-
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
|
|
857
|
+
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) => {
|
|
858
858
|
process.exitCode = await runOdbQuery(input, options);
|
|
859
859
|
});
|
|
860
860
|
}
|
|
861
861
|
function registerOdbRenderReportCommand(program) {
|
|
862
|
-
const command = program.command("odb-render-report <input> [output]").description("render one of an .odb's own reports
|
|
862
|
+
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");
|
|
863
863
|
addOutOption(command);
|
|
864
864
|
addTimeoutOption(command);
|
|
865
865
|
addJsonOption(command);
|
|
866
866
|
addQuietOption(command);
|
|
867
867
|
addVerboseOption(command);
|
|
868
868
|
addFontOptions(command);
|
|
869
|
-
command.option("--report <name>", "the report to render
|
|
869
|
+
command.option("--report <name>", "the report to render — required only when the .odb declares more than one report");
|
|
870
870
|
command.option("--to <format>", "target format when it cannot be inferred from the output path (docx, odt, pdf)");
|
|
871
871
|
command.action(async (input, output, options) => {
|
|
872
872
|
process.exitCode = await runOdbRenderReport(input, output, options);
|
|
@@ -1037,7 +1037,7 @@ async function runOutline(input, options) {
|
|
|
1037
1037
|
}
|
|
1038
1038
|
}
|
|
1039
1039
|
function registerOutlineCommand(program) {
|
|
1040
|
-
const command = program.command("outline <input>").description(`print a document's outline
|
|
1040
|
+
const command = program.command("outline <input>").description(`print a document's outline — headings, list items, and slide/sheet/page groups as indented text (${KNOWN_DOCUMENT_FORMATS})`);
|
|
1041
1041
|
addTimeoutOption(command);
|
|
1042
1042
|
command.option("--json", "emit the outline tree as JSON instead of indented text (diagnostics as NDJSON on stderr)", false);
|
|
1043
1043
|
addQuietOption(command);
|
|
@@ -1171,12 +1171,12 @@ function registerSetMetadataCommand(program) {
|
|
|
1171
1171
|
const command = program.command("set-metadata <input> [output]").description("patch a document's own title/author/subject/keywords, leaving every other field and every other flag as-is").addHelpText("after", [
|
|
1172
1172
|
"",
|
|
1173
1173
|
"Three write paths: a pdf source/target patches the metadata directly on the parsed PDF (writePdf), and a docx source/target",
|
|
1174
|
-
"patches docProps/core.xml directly on the decoded package
|
|
1175
|
-
"at all, so everything else on the page (pdf) or in the package (docx
|
|
1174
|
+
"patches docProps/core.xml directly on the decoded package — both with no layout engine or ContentDocument rebuild involved",
|
|
1175
|
+
"at all, so everything else on the page (pdf) or in the package (docx — comments, footnotes, headers/footers, numbering",
|
|
1176
1176
|
"definitions included) survives byte-faithful. Every other supported format (pptx, xlsx, odt, odp, ods, odg, markdown, rtf)",
|
|
1177
1177
|
"rebuilds a fresh package from that format's own ContentDocument instead.",
|
|
1178
1178
|
"",
|
|
1179
|
-
"set-metadata does not convert format
|
|
1179
|
+
"set-metadata does not convert format — source and target must match. Run convert/from-package first, then",
|
|
1180
1180
|
"set-metadata on the result, if you need a different target format."
|
|
1181
1181
|
].join("\n"));
|
|
1182
1182
|
addOutOption(command);
|
|
@@ -1195,7 +1195,7 @@ function registerSetMetadataCommand(program) {
|
|
|
1195
1195
|
}
|
|
1196
1196
|
//#endregion
|
|
1197
1197
|
//#region package.json
|
|
1198
|
-
var version = "5.
|
|
1198
|
+
var version = "5.12.0";
|
|
1199
1199
|
//#endregion
|
|
1200
1200
|
//#region src/program.ts
|
|
1201
1201
|
function createProgram() {
|
|
@@ -1223,7 +1223,7 @@ function createProgram() {
|
|
|
1223
1223
|
//#region src/cli-main.ts
|
|
1224
1224
|
async function launchTui(startPath, signal) {
|
|
1225
1225
|
try {
|
|
1226
|
-
const { runTui } = await import("./tui-
|
|
1226
|
+
const { runTui } = await import("./tui-y8MLtP8W.js");
|
|
1227
1227
|
await runTui({
|
|
1228
1228
|
startPath,
|
|
1229
1229
|
signal
|
|
@@ -1238,7 +1238,7 @@ function findStartPath(args) {
|
|
|
1238
1238
|
return args.find((arg) => !arg.startsWith("-"));
|
|
1239
1239
|
}
|
|
1240
1240
|
/**
|
|
1241
|
-
* The real, full-featured CLI entry logic
|
|
1241
|
+
* The real, full-featured CLI entry logic — `src/cli.ts` (the published npm `bin`, run under a real Node.js install) awaits this at its own top level. The SEA build (`src/sea-entry.ts`) does NOT use this function; it uses `src/cli-main-sea.ts`'s own TUI-free equivalent instead, so that Ink's module graph is never reachable from the SEA bundle's own entry at all — see this file's own top comment.
|
|
1242
1242
|
*/
|
|
1243
1243
|
async function main() {
|
|
1244
1244
|
const { signal } = createRuntimeSignal({});
|
package/dist/index.cjs
CHANGED
|
@@ -273,7 +273,7 @@ function resolveTargetFormat(output, out, to) {
|
|
|
273
273
|
return { format: to };
|
|
274
274
|
}
|
|
275
275
|
const destination = output ?? out;
|
|
276
|
-
if (destination === void 0) return { errorMessage: "cannot infer a target format
|
|
276
|
+
if (destination === void 0) return { errorMessage: "cannot infer a target format — pass an output path with a recognised extension, --out with one, or --to <format>" };
|
|
277
277
|
const inferred = inferFormatFromExtension(destination);
|
|
278
278
|
if (inferred === void 0) return { errorMessage: `cannot infer a target format from '${destination}'; pass --to <format> instead` };
|
|
279
279
|
return { format: inferred };
|
|
@@ -406,11 +406,11 @@ function toConversionCommandOptions(options) {
|
|
|
406
406
|
async function runGenericConvert(input, output, options) {
|
|
407
407
|
const extension = (0, node_path.extname)(input).toLowerCase();
|
|
408
408
|
if (extension === ".odm") {
|
|
409
|
-
process.stderr.write("convert: '.odm' master documents are not supported by the generic convert command
|
|
409
|
+
process.stderr.write("convert: '.odm' master documents are not supported by the generic convert command — use 'odm-to-pdf' instead\n");
|
|
410
410
|
return 2;
|
|
411
411
|
}
|
|
412
412
|
if (extension === ".odb") {
|
|
413
|
-
process.stderr.write("convert: '.odb' embedded databases are not supported by the generic convert command
|
|
413
|
+
process.stderr.write("convert: '.odb' embedded databases are not supported by the generic convert command — use 'odb-to-csv', 'odb-to-xlsx', or 'odb-tables' instead\n");
|
|
414
414
|
return 2;
|
|
415
415
|
}
|
|
416
416
|
const source = inferFormatFromExtension(input);
|
|
@@ -537,7 +537,7 @@ async function runDocxExtras(input, options) {
|
|
|
537
537
|
}
|
|
538
538
|
}
|
|
539
539
|
function registerDocxExtrasCommand(program) {
|
|
540
|
-
program.command("docx-extras <input>").description("print a docx's own comments, footnotes, headers, footers, and numbering definitions
|
|
540
|
+
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) => {
|
|
541
541
|
process.exitCode = await runDocxExtras(input, options);
|
|
542
542
|
});
|
|
543
543
|
}
|
|
@@ -569,7 +569,7 @@ async function runFonts(input, options) {
|
|
|
569
569
|
}
|
|
570
570
|
for (const face of summaries) {
|
|
571
571
|
const style = [face.bold ? "bold" : void 0, face.italic ? "italic" : void 0].filter((value) => value !== void 0).join(" ");
|
|
572
|
-
process.stdout.write(`${face.family}${style === "" ? "" : ` (${style})`}
|
|
572
|
+
process.stdout.write(`${face.family}${style === "" ? "" : ` (${style})`} — ${face.byteLength} bytes\n`);
|
|
573
573
|
}
|
|
574
574
|
return 0;
|
|
575
575
|
} catch (error) {
|
|
@@ -634,7 +634,7 @@ async function runFromPackage(input, output, options) {
|
|
|
634
634
|
}
|
|
635
635
|
const result = (0, documents_js.documentFromJson)(parsed);
|
|
636
636
|
if (result.kind !== "DocumentTree") {
|
|
637
|
-
process.stderr.write(`[${command}] '${input}' is a ${result.kind}, not a DocumentTree
|
|
637
|
+
process.stderr.write(`[${command}] '${input}' is a ${result.kind}, not a DocumentTree — only a file written by --dump-package can be read back by this command\n`);
|
|
638
638
|
return 2;
|
|
639
639
|
}
|
|
640
640
|
const content = (0, document_schema_js.flattenTree)(result.value);
|
|
@@ -655,19 +655,19 @@ async function runFromPackage(input, output, options) {
|
|
|
655
655
|
return 0;
|
|
656
656
|
} catch (error) {
|
|
657
657
|
if (error instanceof documents_js.UnrecognizedDocumentSchemaError) {
|
|
658
|
-
process.stderr.write(`[${command}] '${input}' has no recognised $schema
|
|
658
|
+
process.stderr.write(`[${command}] '${input}' has no recognised $schema — only a file written by --dump-package can be read back by this command\n`);
|
|
659
659
|
return 1;
|
|
660
660
|
}
|
|
661
661
|
if (isSchemaVersionMismatchError(error)) {
|
|
662
|
-
process.stderr.write(`[${command}] '${input}' is a DocumentTree dump from document-schema.js@${error.dumpVersion}, but this CLI's documents.js reads only @${error.installedVersion}-major dumps
|
|
662
|
+
process.stderr.write(`[${command}] '${input}' is a DocumentTree dump from document-schema.js@${error.dumpVersion}, but this CLI's documents.js reads only @${error.installedVersion}-major dumps — 4.0.0 replaced the flat { formatVersion, content, pages } shape with the tree-form DocumentTree (ExaDev/document-schema.js#20); re-run the source conversion with --dump-package to write a current dump\n`);
|
|
663
663
|
return 1;
|
|
664
664
|
}
|
|
665
665
|
if (isLayoutSchemaDemotedError(error)) {
|
|
666
|
-
process.stderr.write(`[${command}] '${input}' is a LayoutDocument dump
|
|
666
|
+
process.stderr.write(`[${command}] '${input}' is a LayoutDocument dump — LayoutDocument moved to pdf-codec in document-schema.js 4.0.0 and is no longer a schema-stamped input; re-run the source conversion with --dump-package and read that package back instead\n`);
|
|
667
667
|
return 1;
|
|
668
668
|
}
|
|
669
669
|
if (isDocumentPackageRenamedError(error)) {
|
|
670
|
-
process.stderr.write(`[${command}] '${input}' is a document-package dump
|
|
670
|
+
process.stderr.write(`[${command}] '${input}' is a document-package dump — DocumentPackage was renamed to DocumentTree in document-schema.js 5.0.0 (ExaDev/documents.js#661); re-run the source conversion with --dump-package to write a current tree-form DocumentTree dump\n`);
|
|
671
671
|
return 1;
|
|
672
672
|
}
|
|
673
673
|
process.stderr.write(`${formatError(error, options.verbose)}\n`);
|
|
@@ -775,7 +775,7 @@ function countOdbFormDefinitionBoundControls(definition) {
|
|
|
775
775
|
function describeOdbForm(form) {
|
|
776
776
|
const controlCount = form.forms.reduce((total, definition) => total + countOdbFormDefinitionControls(definition), 0);
|
|
777
777
|
const boundCount = form.forms.reduce((total, definition) => total + countOdbFormDefinitionBoundControls(definition), 0);
|
|
778
|
-
return `${form.name} [${form.href}]
|
|
778
|
+
return `${form.name} [${form.href}] — ${form.forms.length} form${form.forms.length === 1 ? "" : "s"}, ${controlCount} control${controlCount === 1 ? "" : "s"} (${boundCount} bound)`;
|
|
779
779
|
}
|
|
780
780
|
function formControlLines(control, depth) {
|
|
781
781
|
const parts = [control.tag];
|
|
@@ -825,7 +825,7 @@ function describeOdbReport(report) {
|
|
|
825
825
|
const groupCount = countReportGroups(report.groups);
|
|
826
826
|
const elementCount = countReportBandElements(report.reportHeader) + countReportBandElements(report.pageHeader) + countReportBandElements(report.detail) + countReportBandElements(report.pageFooter) + countReportBandElements(report.reportFooter) + report.groups.reduce((total, group) => total + countReportGroupElements(group), 0);
|
|
827
827
|
const source = dataSource === void 0 ? "no data source" : `on ${dataSource}`;
|
|
828
|
-
return `${report.name} [${report.href}]
|
|
828
|
+
return `${report.name} [${report.href}] — ${source}, ${groupCount} group${groupCount === 1 ? "" : "s"}, ${elementCount} element${elementCount === 1 ? "" : "s"}`;
|
|
829
829
|
}
|
|
830
830
|
function reportElementLine(element, depth) {
|
|
831
831
|
const parts = [element.tag];
|
|
@@ -1017,7 +1017,7 @@ function resolveQuerySql(pkg, options) {
|
|
|
1017
1017
|
const saved = inventory.queries.find((candidate) => candidate.name === queryName);
|
|
1018
1018
|
if (saved === void 0) {
|
|
1019
1019
|
const available = inventory.queries.map((candidate) => candidate.name);
|
|
1020
|
-
return { errorMessage: `this .odb declares no saved query named '${queryName}'${available.length === 0 ? "" : `
|
|
1020
|
+
return { errorMessage: `this .odb declares no saved query named '${queryName}'${available.length === 0 ? "" : ` — available: ${available.join(", ")}`}` };
|
|
1021
1021
|
}
|
|
1022
1022
|
return { sql: saved.command };
|
|
1023
1023
|
}
|
|
@@ -1184,7 +1184,7 @@ function registerOdbToCsvCommand(program) {
|
|
|
1184
1184
|
addJsonOption(command);
|
|
1185
1185
|
addQuietOption(command);
|
|
1186
1186
|
addVerboseOption(command);
|
|
1187
|
-
command.option("--table <name>", "the table to export
|
|
1187
|
+
command.option("--table <name>", "the table to export — required when the .odb declares more than one table");
|
|
1188
1188
|
command.action(async (input, output, options) => {
|
|
1189
1189
|
process.exitCode = await runOdbToCsv(input, output, options);
|
|
1190
1190
|
});
|
|
@@ -1205,19 +1205,19 @@ function registerOdbReportsCommand(program) {
|
|
|
1205
1205
|
});
|
|
1206
1206
|
}
|
|
1207
1207
|
function registerOdbQueryCommand(program) {
|
|
1208
|
-
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
|
|
1208
|
+
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) => {
|
|
1209
1209
|
process.exitCode = await runOdbQuery(input, options);
|
|
1210
1210
|
});
|
|
1211
1211
|
}
|
|
1212
1212
|
function registerOdbRenderReportCommand(program) {
|
|
1213
|
-
const command = program.command("odb-render-report <input> [output]").description("render one of an .odb's own reports
|
|
1213
|
+
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");
|
|
1214
1214
|
addOutOption(command);
|
|
1215
1215
|
addTimeoutOption(command);
|
|
1216
1216
|
addJsonOption(command);
|
|
1217
1217
|
addQuietOption(command);
|
|
1218
1218
|
addVerboseOption(command);
|
|
1219
1219
|
addFontOptions(command);
|
|
1220
|
-
command.option("--report <name>", "the report to render
|
|
1220
|
+
command.option("--report <name>", "the report to render — required only when the .odb declares more than one report");
|
|
1221
1221
|
command.option("--to <format>", "target format when it cannot be inferred from the output path (docx, odt, pdf)");
|
|
1222
1222
|
command.action(async (input, output, options) => {
|
|
1223
1223
|
process.exitCode = await runOdbRenderReport(input, output, options);
|
|
@@ -1388,7 +1388,7 @@ async function runOutline(input, options) {
|
|
|
1388
1388
|
}
|
|
1389
1389
|
}
|
|
1390
1390
|
function registerOutlineCommand(program) {
|
|
1391
|
-
const command = program.command("outline <input>").description(`print a document's outline
|
|
1391
|
+
const command = program.command("outline <input>").description(`print a document's outline — headings, list items, and slide/sheet/page groups as indented text (${KNOWN_DOCUMENT_FORMATS})`);
|
|
1392
1392
|
addTimeoutOption(command);
|
|
1393
1393
|
command.option("--json", "emit the outline tree as JSON instead of indented text (diagnostics as NDJSON on stderr)", false);
|
|
1394
1394
|
addQuietOption(command);
|
|
@@ -1522,12 +1522,12 @@ function registerSetMetadataCommand(program) {
|
|
|
1522
1522
|
const command = program.command("set-metadata <input> [output]").description("patch a document's own title/author/subject/keywords, leaving every other field and every other flag as-is").addHelpText("after", [
|
|
1523
1523
|
"",
|
|
1524
1524
|
"Three write paths: a pdf source/target patches the metadata directly on the parsed PDF (writePdf), and a docx source/target",
|
|
1525
|
-
"patches docProps/core.xml directly on the decoded package
|
|
1526
|
-
"at all, so everything else on the page (pdf) or in the package (docx
|
|
1525
|
+
"patches docProps/core.xml directly on the decoded package — both with no layout engine or ContentDocument rebuild involved",
|
|
1526
|
+
"at all, so everything else on the page (pdf) or in the package (docx — comments, footnotes, headers/footers, numbering",
|
|
1527
1527
|
"definitions included) survives byte-faithful. Every other supported format (pptx, xlsx, odt, odp, ods, odg, markdown, rtf)",
|
|
1528
1528
|
"rebuilds a fresh package from that format's own ContentDocument instead.",
|
|
1529
1529
|
"",
|
|
1530
|
-
"set-metadata does not convert format
|
|
1530
|
+
"set-metadata does not convert format — source and target must match. Run convert/from-package first, then",
|
|
1531
1531
|
"set-metadata on the result, if you need a different target format."
|
|
1532
1532
|
].join("\n"));
|
|
1533
1533
|
addOutOption(command);
|
|
@@ -1546,7 +1546,7 @@ function registerSetMetadataCommand(program) {
|
|
|
1546
1546
|
}
|
|
1547
1547
|
//#endregion
|
|
1548
1548
|
//#region package.json
|
|
1549
|
-
var version = "5.
|
|
1549
|
+
var version = "5.12.0";
|
|
1550
1550
|
//#endregion
|
|
1551
1551
|
//#region src/program.ts
|
|
1552
1552
|
function createProgram() {
|
package/dist/index.js
CHANGED
|
@@ -272,7 +272,7 @@ function resolveTargetFormat(output, out, to) {
|
|
|
272
272
|
return { format: to };
|
|
273
273
|
}
|
|
274
274
|
const destination = output ?? out;
|
|
275
|
-
if (destination === void 0) return { errorMessage: "cannot infer a target format
|
|
275
|
+
if (destination === void 0) return { errorMessage: "cannot infer a target format — pass an output path with a recognised extension, --out with one, or --to <format>" };
|
|
276
276
|
const inferred = inferFormatFromExtension(destination);
|
|
277
277
|
if (inferred === void 0) return { errorMessage: `cannot infer a target format from '${destination}'; pass --to <format> instead` };
|
|
278
278
|
return { format: inferred };
|
|
@@ -405,11 +405,11 @@ function toConversionCommandOptions(options) {
|
|
|
405
405
|
async function runGenericConvert(input, output, options) {
|
|
406
406
|
const extension = extname(input).toLowerCase();
|
|
407
407
|
if (extension === ".odm") {
|
|
408
|
-
process.stderr.write("convert: '.odm' master documents are not supported by the generic convert command
|
|
408
|
+
process.stderr.write("convert: '.odm' master documents are not supported by the generic convert command — use 'odm-to-pdf' instead\n");
|
|
409
409
|
return 2;
|
|
410
410
|
}
|
|
411
411
|
if (extension === ".odb") {
|
|
412
|
-
process.stderr.write("convert: '.odb' embedded databases are not supported by the generic convert command
|
|
412
|
+
process.stderr.write("convert: '.odb' embedded databases are not supported by the generic convert command — use 'odb-to-csv', 'odb-to-xlsx', or 'odb-tables' instead\n");
|
|
413
413
|
return 2;
|
|
414
414
|
}
|
|
415
415
|
const source = inferFormatFromExtension(input);
|
|
@@ -536,7 +536,7 @@ async function runDocxExtras(input, options) {
|
|
|
536
536
|
}
|
|
537
537
|
}
|
|
538
538
|
function registerDocxExtrasCommand(program) {
|
|
539
|
-
program.command("docx-extras <input>").description("print a docx's own comments, footnotes, headers, footers, and numbering definitions
|
|
539
|
+
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) => {
|
|
540
540
|
process.exitCode = await runDocxExtras(input, options);
|
|
541
541
|
});
|
|
542
542
|
}
|
|
@@ -568,7 +568,7 @@ async function runFonts(input, options) {
|
|
|
568
568
|
}
|
|
569
569
|
for (const face of summaries) {
|
|
570
570
|
const style = [face.bold ? "bold" : void 0, face.italic ? "italic" : void 0].filter((value) => value !== void 0).join(" ");
|
|
571
|
-
process.stdout.write(`${face.family}${style === "" ? "" : ` (${style})`}
|
|
571
|
+
process.stdout.write(`${face.family}${style === "" ? "" : ` (${style})`} — ${face.byteLength} bytes\n`);
|
|
572
572
|
}
|
|
573
573
|
return 0;
|
|
574
574
|
} catch (error) {
|
|
@@ -633,7 +633,7 @@ async function runFromPackage(input, output, options) {
|
|
|
633
633
|
}
|
|
634
634
|
const result = documentFromJson(parsed);
|
|
635
635
|
if (result.kind !== "DocumentTree") {
|
|
636
|
-
process.stderr.write(`[${command}] '${input}' is a ${result.kind}, not a DocumentTree
|
|
636
|
+
process.stderr.write(`[${command}] '${input}' is a ${result.kind}, not a DocumentTree — only a file written by --dump-package can be read back by this command\n`);
|
|
637
637
|
return 2;
|
|
638
638
|
}
|
|
639
639
|
const content = flattenTree(result.value);
|
|
@@ -654,19 +654,19 @@ async function runFromPackage(input, output, options) {
|
|
|
654
654
|
return 0;
|
|
655
655
|
} catch (error) {
|
|
656
656
|
if (error instanceof UnrecognizedDocumentSchemaError) {
|
|
657
|
-
process.stderr.write(`[${command}] '${input}' has no recognised $schema
|
|
657
|
+
process.stderr.write(`[${command}] '${input}' has no recognised $schema — only a file written by --dump-package can be read back by this command\n`);
|
|
658
658
|
return 1;
|
|
659
659
|
}
|
|
660
660
|
if (isSchemaVersionMismatchError(error)) {
|
|
661
|
-
process.stderr.write(`[${command}] '${input}' is a DocumentTree dump from document-schema.js@${error.dumpVersion}, but this CLI's documents.js reads only @${error.installedVersion}-major dumps
|
|
661
|
+
process.stderr.write(`[${command}] '${input}' is a DocumentTree dump from document-schema.js@${error.dumpVersion}, but this CLI's documents.js reads only @${error.installedVersion}-major dumps — 4.0.0 replaced the flat { formatVersion, content, pages } shape with the tree-form DocumentTree (ExaDev/document-schema.js#20); re-run the source conversion with --dump-package to write a current dump\n`);
|
|
662
662
|
return 1;
|
|
663
663
|
}
|
|
664
664
|
if (isLayoutSchemaDemotedError(error)) {
|
|
665
|
-
process.stderr.write(`[${command}] '${input}' is a LayoutDocument dump
|
|
665
|
+
process.stderr.write(`[${command}] '${input}' is a LayoutDocument dump — LayoutDocument moved to pdf-codec in document-schema.js 4.0.0 and is no longer a schema-stamped input; re-run the source conversion with --dump-package and read that package back instead\n`);
|
|
666
666
|
return 1;
|
|
667
667
|
}
|
|
668
668
|
if (isDocumentPackageRenamedError(error)) {
|
|
669
|
-
process.stderr.write(`[${command}] '${input}' is a document-package dump
|
|
669
|
+
process.stderr.write(`[${command}] '${input}' is a document-package dump — DocumentPackage was renamed to DocumentTree in document-schema.js 5.0.0 (ExaDev/documents.js#661); re-run the source conversion with --dump-package to write a current tree-form DocumentTree dump\n`);
|
|
670
670
|
return 1;
|
|
671
671
|
}
|
|
672
672
|
process.stderr.write(`${formatError(error, options.verbose)}\n`);
|
|
@@ -774,7 +774,7 @@ function countOdbFormDefinitionBoundControls(definition) {
|
|
|
774
774
|
function describeOdbForm(form) {
|
|
775
775
|
const controlCount = form.forms.reduce((total, definition) => total + countOdbFormDefinitionControls(definition), 0);
|
|
776
776
|
const boundCount = form.forms.reduce((total, definition) => total + countOdbFormDefinitionBoundControls(definition), 0);
|
|
777
|
-
return `${form.name} [${form.href}]
|
|
777
|
+
return `${form.name} [${form.href}] — ${form.forms.length} form${form.forms.length === 1 ? "" : "s"}, ${controlCount} control${controlCount === 1 ? "" : "s"} (${boundCount} bound)`;
|
|
778
778
|
}
|
|
779
779
|
function formControlLines(control, depth) {
|
|
780
780
|
const parts = [control.tag];
|
|
@@ -824,7 +824,7 @@ function describeOdbReport(report) {
|
|
|
824
824
|
const groupCount = countReportGroups(report.groups);
|
|
825
825
|
const elementCount = countReportBandElements(report.reportHeader) + countReportBandElements(report.pageHeader) + countReportBandElements(report.detail) + countReportBandElements(report.pageFooter) + countReportBandElements(report.reportFooter) + report.groups.reduce((total, group) => total + countReportGroupElements(group), 0);
|
|
826
826
|
const source = dataSource === void 0 ? "no data source" : `on ${dataSource}`;
|
|
827
|
-
return `${report.name} [${report.href}]
|
|
827
|
+
return `${report.name} [${report.href}] — ${source}, ${groupCount} group${groupCount === 1 ? "" : "s"}, ${elementCount} element${elementCount === 1 ? "" : "s"}`;
|
|
828
828
|
}
|
|
829
829
|
function reportElementLine(element, depth) {
|
|
830
830
|
const parts = [element.tag];
|
|
@@ -1016,7 +1016,7 @@ function resolveQuerySql(pkg, options) {
|
|
|
1016
1016
|
const saved = inventory.queries.find((candidate) => candidate.name === queryName);
|
|
1017
1017
|
if (saved === void 0) {
|
|
1018
1018
|
const available = inventory.queries.map((candidate) => candidate.name);
|
|
1019
|
-
return { errorMessage: `this .odb declares no saved query named '${queryName}'${available.length === 0 ? "" : `
|
|
1019
|
+
return { errorMessage: `this .odb declares no saved query named '${queryName}'${available.length === 0 ? "" : ` — available: ${available.join(", ")}`}` };
|
|
1020
1020
|
}
|
|
1021
1021
|
return { sql: saved.command };
|
|
1022
1022
|
}
|
|
@@ -1183,7 +1183,7 @@ function registerOdbToCsvCommand(program) {
|
|
|
1183
1183
|
addJsonOption(command);
|
|
1184
1184
|
addQuietOption(command);
|
|
1185
1185
|
addVerboseOption(command);
|
|
1186
|
-
command.option("--table <name>", "the table to export
|
|
1186
|
+
command.option("--table <name>", "the table to export — required when the .odb declares more than one table");
|
|
1187
1187
|
command.action(async (input, output, options) => {
|
|
1188
1188
|
process.exitCode = await runOdbToCsv(input, output, options);
|
|
1189
1189
|
});
|
|
@@ -1204,19 +1204,19 @@ function registerOdbReportsCommand(program) {
|
|
|
1204
1204
|
});
|
|
1205
1205
|
}
|
|
1206
1206
|
function registerOdbQueryCommand(program) {
|
|
1207
|
-
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
|
|
1207
|
+
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) => {
|
|
1208
1208
|
process.exitCode = await runOdbQuery(input, options);
|
|
1209
1209
|
});
|
|
1210
1210
|
}
|
|
1211
1211
|
function registerOdbRenderReportCommand(program) {
|
|
1212
|
-
const command = program.command("odb-render-report <input> [output]").description("render one of an .odb's own reports
|
|
1212
|
+
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");
|
|
1213
1213
|
addOutOption(command);
|
|
1214
1214
|
addTimeoutOption(command);
|
|
1215
1215
|
addJsonOption(command);
|
|
1216
1216
|
addQuietOption(command);
|
|
1217
1217
|
addVerboseOption(command);
|
|
1218
1218
|
addFontOptions(command);
|
|
1219
|
-
command.option("--report <name>", "the report to render
|
|
1219
|
+
command.option("--report <name>", "the report to render — required only when the .odb declares more than one report");
|
|
1220
1220
|
command.option("--to <format>", "target format when it cannot be inferred from the output path (docx, odt, pdf)");
|
|
1221
1221
|
command.action(async (input, output, options) => {
|
|
1222
1222
|
process.exitCode = await runOdbRenderReport(input, output, options);
|
|
@@ -1387,7 +1387,7 @@ async function runOutline(input, options) {
|
|
|
1387
1387
|
}
|
|
1388
1388
|
}
|
|
1389
1389
|
function registerOutlineCommand(program) {
|
|
1390
|
-
const command = program.command("outline <input>").description(`print a document's outline
|
|
1390
|
+
const command = program.command("outline <input>").description(`print a document's outline — headings, list items, and slide/sheet/page groups as indented text (${KNOWN_DOCUMENT_FORMATS})`);
|
|
1391
1391
|
addTimeoutOption(command);
|
|
1392
1392
|
command.option("--json", "emit the outline tree as JSON instead of indented text (diagnostics as NDJSON on stderr)", false);
|
|
1393
1393
|
addQuietOption(command);
|
|
@@ -1521,12 +1521,12 @@ function registerSetMetadataCommand(program) {
|
|
|
1521
1521
|
const command = program.command("set-metadata <input> [output]").description("patch a document's own title/author/subject/keywords, leaving every other field and every other flag as-is").addHelpText("after", [
|
|
1522
1522
|
"",
|
|
1523
1523
|
"Three write paths: a pdf source/target patches the metadata directly on the parsed PDF (writePdf), and a docx source/target",
|
|
1524
|
-
"patches docProps/core.xml directly on the decoded package
|
|
1525
|
-
"at all, so everything else on the page (pdf) or in the package (docx
|
|
1524
|
+
"patches docProps/core.xml directly on the decoded package — both with no layout engine or ContentDocument rebuild involved",
|
|
1525
|
+
"at all, so everything else on the page (pdf) or in the package (docx — comments, footnotes, headers/footers, numbering",
|
|
1526
1526
|
"definitions included) survives byte-faithful. Every other supported format (pptx, xlsx, odt, odp, ods, odg, markdown, rtf)",
|
|
1527
1527
|
"rebuilds a fresh package from that format's own ContentDocument instead.",
|
|
1528
1528
|
"",
|
|
1529
|
-
"set-metadata does not convert format
|
|
1529
|
+
"set-metadata does not convert format — source and target must match. Run convert/from-package first, then",
|
|
1530
1530
|
"set-metadata on the result, if you need a different target format."
|
|
1531
1531
|
].join("\n"));
|
|
1532
1532
|
addOutOption(command);
|
|
@@ -1545,7 +1545,7 @@ function registerSetMetadataCommand(program) {
|
|
|
1545
1545
|
}
|
|
1546
1546
|
//#endregion
|
|
1547
1547
|
//#region package.json
|
|
1548
|
-
var version = "5.
|
|
1548
|
+
var version = "5.12.0";
|
|
1549
1549
|
//#endregion
|
|
1550
1550
|
//#region src/program.ts
|
|
1551
1551
|
function createProgram() {
|
|
@@ -240,7 +240,7 @@ function countOdbFormDefinitionBoundControls(definition) {
|
|
|
240
240
|
function describeOdbForm(form) {
|
|
241
241
|
const controlCount = form.forms.reduce((total, definition) => total + countOdbFormDefinitionControls(definition), 0);
|
|
242
242
|
const boundCount = form.forms.reduce((total, definition) => total + countOdbFormDefinitionBoundControls(definition), 0);
|
|
243
|
-
return `${form.name} [${form.href}]
|
|
243
|
+
return `${form.name} [${form.href}] — ${form.forms.length} form${form.forms.length === 1 ? "" : "s"}, ${controlCount} control${controlCount === 1 ? "" : "s"} (${boundCount} bound)`;
|
|
244
244
|
}
|
|
245
245
|
function formControlLines(control, depth) {
|
|
246
246
|
const parts = [control.tag];
|
|
@@ -290,7 +290,7 @@ function describeOdbReport(report) {
|
|
|
290
290
|
const groupCount = countReportGroups(report.groups);
|
|
291
291
|
const elementCount = countReportBandElements(report.reportHeader) + countReportBandElements(report.pageHeader) + countReportBandElements(report.detail) + countReportBandElements(report.pageFooter) + countReportBandElements(report.reportFooter) + report.groups.reduce((total, group) => total + countReportGroupElements(group), 0);
|
|
292
292
|
const source = dataSource === void 0 ? "no data source" : `on ${dataSource}`;
|
|
293
|
-
return `${report.name} [${report.href}]
|
|
293
|
+
return `${report.name} [${report.href}] — ${source}, ${groupCount} group${groupCount === 1 ? "" : "s"}, ${elementCount} element${elementCount === 1 ? "" : "s"}`;
|
|
294
294
|
}
|
|
295
295
|
function reportElementLine(element, depth) {
|
|
296
296
|
const parts = [element.tag];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h as inferFormatFromExtension, i as formatOdbReportLines, l as formatDocxExtrasLines, m as formatToExtension, n as describeOdbReport, o as formatMetadataLines, p as loadProvidedFonts, r as formatOdbFormLines, s as formatMetadataValue, t as describeOdbForm, u as readInput } from "./odb-structure-
|
|
1
|
+
import { h as inferFormatFromExtension, i as formatOdbReportLines, l as formatDocxExtrasLines, m as formatToExtension, n as describeOdbReport, o as formatMetadataLines, p as loadProvidedFonts, r as formatOdbFormLines, s as formatMetadataValue, t as describeOdbForm, u as readInput } from "./odb-structure-Crz3Yzzb.js";
|
|
2
2
|
import { readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { basename, dirname, extname, join } from "node:path";
|
|
4
4
|
import { bytesToBase64, cellReference, columnIndexToLetters, convertDocument, createDoc, createDocx, createMarkdownEditor, createOdg, createOdp, createOds, createOdt, createPdf, createPpt, createPptx, createXls, csvToPdf, decodeMarkdownText, decodeOdbPackage, docToPdf, docxToPdf, encodeMarkdownText, epubToPdf, hsqldbCellDisplayText, markdownToPdf, odbReportToDocx, odbReportToOdt, odbReportToPdf, odgToPdf, odpToPdf, odsToPdf, odtToPdf, openDoc, openDocx, openMarkdown, openOdg, openOdp, openOds, openOdt, openPdf, openPpt, openPptx, openXls, parseXml, pptToPdf, pptxToPdf, readDocxContent, readDocxExtras, readMarkdownContent, readOdbForms, readOdbReportContent, readOdbReports, readOdbTables, readOdgContent, readOdpContent, readOdsContent, readOdtContent, readPdf, readPptxContent, rgbHexToColor, rtfToPdf, svgToPdf, xlsToPdf, xlsxToPdf } from "documents.js";
|
|
@@ -36,7 +36,7 @@ function toPdfOptions(options, fonts) {
|
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
async function exportToPdf(openDocument, destinationPath, options) {
|
|
39
|
-
if (openDocument.format === "odb" || openDocument.format === "pdf") throw new Error(`A ${openDocument.format} document has no export-to-PDF path
|
|
39
|
+
if (openDocument.format === "odb" || openDocument.format === "pdf") throw new Error(`A ${openDocument.format} document has no export-to-PDF path — ${openDocument.format === "pdf" ? "save it directly instead" : "it is a read-only source with nothing to convert"}`);
|
|
40
40
|
const pdfOptions = toPdfOptions(options, await loadProvidedFonts(options.fontFiles ?? [], { signal: options.signal }));
|
|
41
41
|
if (openDocument.format === "markdown") {
|
|
42
42
|
const pdfBytes = markdownToPdf(encodeMarkdownText(openDocument.editor.toMarkdownText()), pdfOptions);
|
|
@@ -950,7 +950,7 @@ function appReducer(state, action) {
|
|
|
950
950
|
selection: {},
|
|
951
951
|
errorDetail: void 0,
|
|
952
952
|
stack: [rootScreenForFormat(action.doc.format)]
|
|
953
|
-
}, "info", action.doc.format === "xlsx" || action.doc.format === "csv" || action.doc.format === "svg" || action.doc.format === "rtf" || action.doc.format === "wpd" || action.doc.format === "doc" || action.doc.format === "xls" || action.doc.format === "ppt" || action.doc.format === "epub" ? `Opened ${action.path} as a read-only PDF preview
|
|
953
|
+
}, "info", action.doc.format === "xlsx" || action.doc.format === "csv" || action.doc.format === "svg" || action.doc.format === "rtf" || action.doc.format === "wpd" || action.doc.format === "doc" || action.doc.format === "xls" || action.doc.format === "ppt" || action.doc.format === "epub" ? `Opened ${action.path} as a read-only PDF preview — press ':' then 'export pdf' to save it as a real PDF` : `Opened ${action.path}`);
|
|
954
954
|
case "OPEN_FILE_ERROR": return withStatus({
|
|
955
955
|
...state,
|
|
956
956
|
errorDetail: {
|
|
@@ -1057,7 +1057,7 @@ function appReducer(state, action) {
|
|
|
1057
1057
|
}
|
|
1058
1058
|
table.mergeCells(action.merge.startRow, action.merge.startColumn, action.merge.rowSpan, action.merge.colSpan);
|
|
1059
1059
|
});
|
|
1060
|
-
return merge.unsupported ? withStatus(nextState, "warning", "Markdown tables do not support merged cells
|
|
1060
|
+
return merge.unsupported ? withStatus(nextState, "warning", "Markdown tables do not support merged cells — the table was created without merging") : nextState;
|
|
1061
1061
|
}
|
|
1062
1062
|
case "MERGE_TABLE_CELLS": {
|
|
1063
1063
|
const doc = wordprocessingDocument(state);
|
|
@@ -2279,7 +2279,7 @@ function StatusLine() {
|
|
|
2279
2279
|
" ",
|
|
2280
2280
|
"⚠ ",
|
|
2281
2281
|
state.diagnostics.length,
|
|
2282
|
-
" diagnostics
|
|
2282
|
+
" diagnostics — Ctrl+D"
|
|
2283
2283
|
]
|
|
2284
2284
|
}) : void 0
|
|
2285
2285
|
] });
|
|
@@ -2294,7 +2294,7 @@ function requireFieldValue(values, key) {
|
|
|
2294
2294
|
function FieldWizard(props) {
|
|
2295
2295
|
const [stepIndex, setStepIndex] = useState(0);
|
|
2296
2296
|
const field = props.fields[stepIndex];
|
|
2297
|
-
if (field === void 0) throw new Error(`FieldWizard stepIndex ${stepIndex} is out of range for ${props.fields.length} fields
|
|
2297
|
+
if (field === void 0) throw new Error(`FieldWizard stepIndex ${stepIndex} is out of range for ${props.fields.length} fields — onComplete always fires before stepIndex can advance past the last field, so this indicates a bug in that advance.`);
|
|
2298
2298
|
const [collected, setCollected] = useState({});
|
|
2299
2299
|
const [draft, setDraft] = useState(field.defaultValue);
|
|
2300
2300
|
return /* @__PURE__ */ jsxs(Box, {
|
|
@@ -2334,7 +2334,7 @@ function FieldWizard(props) {
|
|
|
2334
2334
|
stepIndex + 1,
|
|
2335
2335
|
" of ",
|
|
2336
2336
|
props.fields.length,
|
|
2337
|
-
"
|
|
2337
|
+
" — Enter to continue, Esc to cancel"
|
|
2338
2338
|
]
|
|
2339
2339
|
})
|
|
2340
2340
|
]
|
|
@@ -2481,7 +2481,7 @@ function FormulaPicker(props) {
|
|
|
2481
2481
|
children: [
|
|
2482
2482
|
/* @__PURE__ */ jsx(Text, {
|
|
2483
2483
|
bold: true,
|
|
2484
|
-
children: "Insert formula
|
|
2484
|
+
children: "Insert formula — choose a preset or write raw MathML"
|
|
2485
2485
|
}),
|
|
2486
2486
|
/* @__PURE__ */ jsx(ListView, {
|
|
2487
2487
|
items: PICKER_ROWS,
|
|
@@ -2819,7 +2819,7 @@ function ParagraphFamilyBodyList(props) {
|
|
|
2819
2819
|
/* @__PURE__ */ jsx(ListView, {
|
|
2820
2820
|
items: rows,
|
|
2821
2821
|
selectedIndex: listSelectedIndex,
|
|
2822
|
-
emptyMessage: "No paragraphs or tables yet
|
|
2822
|
+
emptyMessage: "No paragraphs or tables yet — press 'a' to append a paragraph.",
|
|
2823
2823
|
renderItem: (row, isSelected) => {
|
|
2824
2824
|
if (row.kind === "header") return /* @__PURE__ */ jsx(Text, {
|
|
2825
2825
|
bold: true,
|
|
@@ -3022,7 +3022,7 @@ async function applyInsertImage(blockIndex, values, dispatch) {
|
|
|
3022
3022
|
dispatch({
|
|
3023
3023
|
type: "SET_STATUS",
|
|
3024
3024
|
severity: "warning",
|
|
3025
|
-
text: `${path} is not a .png or .jpg/.jpeg file
|
|
3025
|
+
text: `${path} is not a .png or .jpg/.jpeg file — image not inserted`
|
|
3026
3026
|
});
|
|
3027
3027
|
return;
|
|
3028
3028
|
}
|
|
@@ -3051,7 +3051,7 @@ async function applyInsertImage(blockIndex, values, dispatch) {
|
|
|
3051
3051
|
function ParagraphRunsView(props) {
|
|
3052
3052
|
if (props.runs.length === 0) return /* @__PURE__ */ jsx(Text, {
|
|
3053
3053
|
dimColor: true,
|
|
3054
|
-
children: "(no runs
|
|
3054
|
+
children: "(no runs — press 'a' to append one)"
|
|
3055
3055
|
});
|
|
3056
3056
|
return /* @__PURE__ */ jsx(Box, { children: props.runs.map((run, index) => {
|
|
3057
3057
|
const styled = supportsRunStyleExtras(run);
|
|
@@ -4072,7 +4072,7 @@ function isReportRenderTargetFormat(format) {
|
|
|
4072
4072
|
}
|
|
4073
4073
|
async function renderOdbReportTo(doc, destinationPath, options) {
|
|
4074
4074
|
const format = detectFormat(destinationPath);
|
|
4075
|
-
if (!isReportRenderTargetFormat(format)) throw new Error(`Cannot tell whether to render "${options.reportName}" as docx, odt, or pdf from '${destinationPath}'
|
|
4075
|
+
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`);
|
|
4076
4076
|
const fonts = await loadProvidedFonts(options.fontFiles ?? [], { signal: options.signal });
|
|
4077
4077
|
const pkg = decodeOdbPackage(new Uint8Array(await readFile(doc.path)));
|
|
4078
4078
|
const content = readOdbReportContent(pkg, { report: options.reportName });
|
|
@@ -4161,7 +4161,7 @@ function OdbReportRenderScreen() {
|
|
|
4161
4161
|
}), /* @__PURE__ */ jsx(TextField, {
|
|
4162
4162
|
value: fontFiles,
|
|
4163
4163
|
isFocused: isActive && field === "fonts",
|
|
4164
|
-
placeholder: "optional .ttf/.otf paths, comma-separated
|
|
4164
|
+
placeholder: "optional .ttf/.otf paths, comma-separated — pdf only",
|
|
4165
4165
|
onChange: setFontFiles,
|
|
4166
4166
|
onSubmit: submit,
|
|
4167
4167
|
onCancel: cancel
|
|
@@ -4383,17 +4383,17 @@ function defaultTriangleSubpaths(widthPt, heightPt) {
|
|
|
4383
4383
|
//#region src/tui/screens/editors/odg/shared.ts
|
|
4384
4384
|
function requireOdgDocument(state) {
|
|
4385
4385
|
const doc = state.openDocument;
|
|
4386
|
-
if (doc?.format !== "odg") throw new Error(`An odg screen rendered with the open document being ${doc === void 0 ? "no document" : `a '${doc.format}' document`}
|
|
4386
|
+
if (doc?.format !== "odg") throw new Error(`An odg screen rendered with the open document being ${doc === void 0 ? "no document" : `a '${doc.format}' document`} — pageList/pageDetail/shapeOrVectorDetail only ever get pushed from odg-routed navigation (rootScreenForFormat maps 'odg' to 'pageList', and every deeper push originates from that screen or its own descendants), so this indicates a routing bug elsewhere, not a state this screen should render around.`);
|
|
4387
4387
|
return doc;
|
|
4388
4388
|
}
|
|
4389
4389
|
function requirePageDetailScreen(state) {
|
|
4390
4390
|
const screen = currentScreen(state);
|
|
4391
|
-
if (screen.kind !== "pageDetail") throw new Error(`OdgPageDetailScreen rendered while the top of the stack is '${screen.kind}', not 'pageDetail'
|
|
4391
|
+
if (screen.kind !== "pageDetail") throw new Error(`OdgPageDetailScreen rendered while the top of the stack is '${screen.kind}', not 'pageDetail' — app.tsx's ScreenBody switch only mounts this component for that screen kind, so this cannot happen without a routing bug.`);
|
|
4392
4392
|
return screen;
|
|
4393
4393
|
}
|
|
4394
4394
|
function requireShapeOrVectorDetailScreen(state) {
|
|
4395
4395
|
const screen = currentScreen(state);
|
|
4396
|
-
if (screen.kind !== "shapeOrVectorDetail") throw new Error(`OdgShapeOrVectorDetailScreen rendered while the top of the stack is '${screen.kind}', not 'shapeOrVectorDetail'
|
|
4396
|
+
if (screen.kind !== "shapeOrVectorDetail") throw new Error(`OdgShapeOrVectorDetailScreen rendered while the top of the stack is '${screen.kind}', not 'shapeOrVectorDetail' — app.tsx's ScreenBody switch only mounts this component for that screen kind, so this cannot happen without a routing bug.`);
|
|
4397
4397
|
return screen;
|
|
4398
4398
|
}
|
|
4399
4399
|
function vectorsParityMatch(liveVectors, contentVectors) {
|
|
@@ -4404,9 +4404,9 @@ function buildPageItems(doc, pageIndex) {
|
|
|
4404
4404
|
const page = doc.editor.pages()[pageIndex];
|
|
4405
4405
|
if (page === void 0) return [];
|
|
4406
4406
|
const content = readOdgContent(doc.editor.toPackage());
|
|
4407
|
-
if (content.kind !== "drawing") throw new Error(`readOdgContent(doc.editor.toPackage()) returned a '${content.kind}' ContentDocument for an odg-format open document
|
|
4407
|
+
if (content.kind !== "drawing") throw new Error(`readOdgContent(doc.editor.toPackage()) returned a '${content.kind}' ContentDocument for an odg-format open document — an odg package should always read back as the 'drawing' variant, so this indicates a real inconsistency in documents.js's own reader, not a state this screen should paper over.`);
|
|
4408
4408
|
const contentPage = content.pages[pageIndex];
|
|
4409
|
-
if (contentPage === void 0) throw new Error(`readOdgContent found no page at index ${pageIndex}, but doc.editor.pages() has a page there
|
|
4409
|
+
if (contentPage === void 0) throw new Error(`readOdgContent found no page at index ${pageIndex}, but doc.editor.pages() has a page there — the two read the same live package, so they should always agree on page count.`);
|
|
4410
4410
|
const liveVectors = page.vectors();
|
|
4411
4411
|
const parityOk = vectorsParityMatch(liveVectors, contentPage.vectors);
|
|
4412
4412
|
const vectorItems = contentPage.vectors.map((vector, index) => ({
|
|
@@ -4494,7 +4494,7 @@ function OdgPageListScreen() {
|
|
|
4494
4494
|
}), /* @__PURE__ */ jsx(ListView, {
|
|
4495
4495
|
items: pageIndices,
|
|
4496
4496
|
selectedIndex,
|
|
4497
|
-
emptyMessage: "No pages yet
|
|
4497
|
+
emptyMessage: "No pages yet — press 'a' to add one",
|
|
4498
4498
|
renderItem: (pageIndex, isSelected) => {
|
|
4499
4499
|
const page = pages[pageIndex];
|
|
4500
4500
|
const shapeCount = page === void 0 ? 0 : page.shapes().length;
|
|
@@ -4639,7 +4639,7 @@ function warnVectorIsViewOnly(dispatch, label) {
|
|
|
4639
4639
|
dispatch({
|
|
4640
4640
|
type: "SET_STATUS",
|
|
4641
4641
|
severity: "info",
|
|
4642
|
-
text: `${label} added
|
|
4642
|
+
text: `${label} added — but this page also has a vector element documents.js's OdgPage.vectors() cannot wrap, so every vector on it (including this one) shows read-only in this list rather than risk pairing the wrong live handle to the wrong row.`
|
|
4643
4643
|
});
|
|
4644
4644
|
}
|
|
4645
4645
|
function warnIfVectorAddedReadOnly(doc, pageIndex, dispatch, label) {
|
|
@@ -4733,7 +4733,7 @@ async function applyAddKind$1(kind, pageIndex, doc, values, dispatch) {
|
|
|
4733
4733
|
dispatch({
|
|
4734
4734
|
type: "SET_STATUS",
|
|
4735
4735
|
severity: "warning",
|
|
4736
|
-
text: `${path} is not a .png or .jpg/.jpeg file
|
|
4736
|
+
text: `${path} is not a .png or .jpg/.jpeg file — image not added`
|
|
4737
4737
|
});
|
|
4738
4738
|
return;
|
|
4739
4739
|
}
|
|
@@ -4778,7 +4778,7 @@ function AddItemFlow$1(props) {
|
|
|
4778
4778
|
paddingX: 1,
|
|
4779
4779
|
children: [/* @__PURE__ */ jsx(Text, {
|
|
4780
4780
|
bold: true,
|
|
4781
|
-
children: "Add item
|
|
4781
|
+
children: "Add item — choose a kind"
|
|
4782
4782
|
}), /* @__PURE__ */ jsx(ListView, {
|
|
4783
4783
|
items: ADD_KIND_OPTIONS$1,
|
|
4784
4784
|
selectedIndex,
|
|
@@ -4863,7 +4863,7 @@ function OdgPageDetailScreen() {
|
|
|
4863
4863
|
children: [
|
|
4864
4864
|
"Page ",
|
|
4865
4865
|
pageIndex + 1,
|
|
4866
|
-
"
|
|
4866
|
+
" — ",
|
|
4867
4867
|
items.length,
|
|
4868
4868
|
" item",
|
|
4869
4869
|
items.length === 1 ? "" : "s"
|
|
@@ -4871,7 +4871,7 @@ function OdgPageDetailScreen() {
|
|
|
4871
4871
|
}), /* @__PURE__ */ jsx(ListView, {
|
|
4872
4872
|
items: rows,
|
|
4873
4873
|
selectedIndex,
|
|
4874
|
-
emptyMessage: "No items yet
|
|
4874
|
+
emptyMessage: "No items yet — press 'a' to add one",
|
|
4875
4875
|
renderItem: (row, isSelected) => /* @__PURE__ */ jsxs(Text, {
|
|
4876
4876
|
color: selectedColor(isSelected),
|
|
4877
4877
|
children: [isSelected ? "> " : " ", describeItem(row.item)]
|
|
@@ -4903,7 +4903,7 @@ function buildVectorRows(vector, liveVector, dispatch) {
|
|
|
4903
4903
|
dispatch({
|
|
4904
4904
|
type: "SET_STATUS",
|
|
4905
4905
|
severity: "warning",
|
|
4906
|
-
text: "A vector stroke cannot be cleared to none through this editor
|
|
4906
|
+
text: "A vector stroke cannot be cleared to none through this editor — enter \"r g b widthPt\" (0-1 colour, pt width) instead"
|
|
4907
4907
|
});
|
|
4908
4908
|
return;
|
|
4909
4909
|
}
|
|
@@ -4946,7 +4946,7 @@ function VectorDetail(props) {
|
|
|
4946
4946
|
/* @__PURE__ */ jsx(Text, { children: describeFillStroke(vector) }),
|
|
4947
4947
|
/* @__PURE__ */ jsx(Text, {
|
|
4948
4948
|
color: "yellow",
|
|
4949
|
-
children: "This page's live vectors (documents.js's `OdgPage.vectors()`) don't line up one-to-one with what odf.js's own reader found here
|
|
4949
|
+
children: "This page's live vectors (documents.js's `OdgPage.vectors()`) don't line up one-to-one with what odf.js's own reader found here — likely a `draw:circle`/`polygon`/`polyline`/`custom-shape` element the live accessor has no wrapper for, sitting alongside a plain rect/ellipse/line/path it does. Rather than risk pairing the wrong live handle to this row, every vector on this page is shown read-only until that mismatch is resolved outside this TUI. Open the file in a real ODF editor to change it."
|
|
4950
4950
|
}),
|
|
4951
4951
|
/* @__PURE__ */ jsx(Text, {
|
|
4952
4952
|
dimColor: true,
|
|
@@ -4956,7 +4956,7 @@ function VectorDetail(props) {
|
|
|
4956
4956
|
});
|
|
4957
4957
|
if (editingField !== void 0) {
|
|
4958
4958
|
const row = rows[editingField];
|
|
4959
|
-
if (row === void 0) throw new Error(`VectorDetail is editing field index ${editingField}, but there are only ${rows.length} rows
|
|
4959
|
+
if (row === void 0) throw new Error(`VectorDetail is editing field index ${editingField}, but there are only ${rows.length} rows — selecting a row always sets editingField to a valid index from that same rows array, so this indicates a bug in that selection.`);
|
|
4960
4960
|
return /* @__PURE__ */ jsxs(Box, {
|
|
4961
4961
|
flexDirection: "column",
|
|
4962
4962
|
borderStyle: "round",
|
|
@@ -5115,7 +5115,7 @@ function ShapeDetail(props) {
|
|
|
5115
5115
|
});
|
|
5116
5116
|
if (editingField !== void 0) {
|
|
5117
5117
|
const row = rows[editingField];
|
|
5118
|
-
if (row === void 0) throw new Error(`ShapeDetail is editing field index ${editingField}, but there are only ${rows.length} rows
|
|
5118
|
+
if (row === void 0) throw new Error(`ShapeDetail is editing field index ${editingField}, but there are only ${rows.length} rows — selecting a row always sets editingField to a valid index from that same rows array, so this indicates a bug in that selection.`);
|
|
5119
5119
|
return /* @__PURE__ */ jsxs(Box, {
|
|
5120
5120
|
flexDirection: "column",
|
|
5121
5121
|
borderStyle: "round",
|
|
@@ -5228,7 +5228,7 @@ function assertPresentationDocument(doc) {
|
|
|
5228
5228
|
return doc;
|
|
5229
5229
|
}
|
|
5230
5230
|
function assertRichPresentationDocument(doc) {
|
|
5231
|
-
if (doc === void 0 || doc.format !== "pptx" && doc.format !== "odp") throw new Error("Expected an open pptx or odp document here; the screen router in app.tsx should only reach this rich slide-family screen for one of those formats
|
|
5231
|
+
if (doc === void 0 || doc.format !== "pptx" && doc.format !== "odp") throw new Error("Expected an open pptx or odp document here; the screen router in app.tsx should only reach this rich slide-family screen for one of those formats — a ppt document routes to its own narrower detail screen.");
|
|
5232
5232
|
return doc;
|
|
5233
5233
|
}
|
|
5234
5234
|
const DEFAULT_FRAME_MARGIN_FRACTION = .1;
|
|
@@ -5321,7 +5321,7 @@ function SlideFamilySlideList(props) {
|
|
|
5321
5321
|
/* @__PURE__ */ jsx(ListView, {
|
|
5322
5322
|
items: rows,
|
|
5323
5323
|
selectedIndex,
|
|
5324
|
-
emptyMessage: "No slides yet
|
|
5324
|
+
emptyMessage: "No slides yet — press 'a' to add one",
|
|
5325
5325
|
renderItem: (row, isSelected) => /* @__PURE__ */ jsx(SlideRowView, {
|
|
5326
5326
|
row,
|
|
5327
5327
|
isSelected
|
|
@@ -5581,7 +5581,7 @@ function ShapeEditorScreen(props) {
|
|
|
5581
5581
|
]
|
|
5582
5582
|
}), /* @__PURE__ */ jsx(Text, {
|
|
5583
5583
|
color: "yellow",
|
|
5584
|
-
children: "This shape no longer exists
|
|
5584
|
+
children: "This shape no longer exists — press Esc to go back"
|
|
5585
5585
|
})]
|
|
5586
5586
|
});
|
|
5587
5587
|
return /* @__PURE__ */ jsxs(Box, {
|
|
@@ -5847,7 +5847,7 @@ function imageFormatFromPath(path) {
|
|
|
5847
5847
|
}
|
|
5848
5848
|
async function readImageForShape(path) {
|
|
5849
5849
|
const format = imageFormatFromPath(path);
|
|
5850
|
-
if (format === void 0) throw new Error(`${path} does not look like a .png or .jpg/.jpeg file
|
|
5850
|
+
if (format === void 0) throw new Error(`${path} does not look like a .png or .jpg/.jpeg file — ADD_IMAGE only accepts those two formats`);
|
|
5851
5851
|
return {
|
|
5852
5852
|
format,
|
|
5853
5853
|
bytes: new Uint8Array(await readFile(path))
|
|
@@ -6028,7 +6028,7 @@ function SlideDetailScreen(props) {
|
|
|
6028
6028
|
children: [
|
|
6029
6029
|
"Slide ",
|
|
6030
6030
|
slideIndex + 1,
|
|
6031
|
-
"
|
|
6031
|
+
" — ",
|
|
6032
6032
|
shapes.length,
|
|
6033
6033
|
" shape",
|
|
6034
6034
|
shapes.length === 1 ? "" : "s"
|
|
@@ -6036,11 +6036,11 @@ function SlideDetailScreen(props) {
|
|
|
6036
6036
|
}),
|
|
6037
6037
|
slide === void 0 ? /* @__PURE__ */ jsx(Text, {
|
|
6038
6038
|
color: "yellow",
|
|
6039
|
-
children: "This slide no longer exists
|
|
6039
|
+
children: "This slide no longer exists — press Esc to go back"
|
|
6040
6040
|
}) : /* @__PURE__ */ jsx(ListView, {
|
|
6041
6041
|
items: rows,
|
|
6042
6042
|
selectedIndex: listSelectedIndex,
|
|
6043
|
-
emptyMessage: "No shapes yet
|
|
6043
|
+
emptyMessage: "No shapes yet — press 'a' to add one",
|
|
6044
6044
|
renderItem: (row, isSelected) => {
|
|
6045
6045
|
if (row.kind === "tablesHeader") return /* @__PURE__ */ jsxs(Text, {
|
|
6046
6046
|
bold: true,
|
|
@@ -6261,7 +6261,7 @@ function SlideTableDetailScreen(props) {
|
|
|
6261
6261
|
]
|
|
6262
6262
|
}), /* @__PURE__ */ jsx(Text, {
|
|
6263
6263
|
color: "yellow",
|
|
6264
|
-
children: "This table no longer exists
|
|
6264
|
+
children: "This table no longer exists — press Esc to go back"
|
|
6265
6265
|
})]
|
|
6266
6266
|
});
|
|
6267
6267
|
return /* @__PURE__ */ jsxs(Box, {
|
|
@@ -6342,7 +6342,7 @@ function NotesEditorScreen(props) {
|
|
|
6342
6342
|
]
|
|
6343
6343
|
}), /* @__PURE__ */ jsx(Text, {
|
|
6344
6344
|
color: "yellow",
|
|
6345
|
-
children: "This slide no longer exists
|
|
6345
|
+
children: "This slide no longer exists — press Esc to go back"
|
|
6346
6346
|
})]
|
|
6347
6347
|
});
|
|
6348
6348
|
return /* @__PURE__ */ jsxs(Box, {
|
|
@@ -6622,7 +6622,7 @@ function OdsSheetListScreen() {
|
|
|
6622
6622
|
/* @__PURE__ */ jsx(ListView, {
|
|
6623
6623
|
items: rows,
|
|
6624
6624
|
selectedIndex,
|
|
6625
|
-
emptyMessage: "This workbook has no sheets yet
|
|
6625
|
+
emptyMessage: "This workbook has no sheets yet — press 'a' to add one.",
|
|
6626
6626
|
renderItem: (row, isSelected) => /* @__PURE__ */ jsx(Text, {
|
|
6627
6627
|
color: selectedColor(isSelected),
|
|
6628
6628
|
inverse: isSelected,
|
|
@@ -6826,7 +6826,7 @@ function OdsPrintSettingsEditorScreen() {
|
|
|
6826
6826
|
children: [
|
|
6827
6827
|
/* @__PURE__ */ jsxs(Text, {
|
|
6828
6828
|
bold: true,
|
|
6829
|
-
children: ["Print settings
|
|
6829
|
+
children: ["Print settings — ", sheet.name]
|
|
6830
6830
|
}),
|
|
6831
6831
|
/* @__PURE__ */ jsx(ListView, {
|
|
6832
6832
|
items: FIELD_ROWS,
|
|
@@ -6913,7 +6913,7 @@ function OdsCellEditor(props) {
|
|
|
6913
6913
|
dispatch({
|
|
6914
6914
|
type: "SET_STATUS",
|
|
6915
6915
|
severity: "warning",
|
|
6916
|
-
text: `"${text}" is not a valid ${kind} value
|
|
6916
|
+
text: `"${text}" is not a valid ${kind} value — Tab to change kind`
|
|
6917
6917
|
});
|
|
6918
6918
|
return;
|
|
6919
6919
|
}
|
|
@@ -7003,7 +7003,7 @@ async function applyAddSheetImage(sheetIndex, anchorRow, anchorColumn, values, d
|
|
|
7003
7003
|
dispatch({
|
|
7004
7004
|
type: "SET_STATUS",
|
|
7005
7005
|
severity: "warning",
|
|
7006
|
-
text: `${path} is not a .png or .jpg/.jpeg file
|
|
7006
|
+
text: `${path} is not a .png or .jpg/.jpeg file — image not added`
|
|
7007
7007
|
});
|
|
7008
7008
|
return;
|
|
7009
7009
|
}
|
|
@@ -7228,7 +7228,7 @@ function OdsSpreadsheetGridScreen() {
|
|
|
7228
7228
|
items: filteredCompactRows,
|
|
7229
7229
|
selectedIndex: compactSelectedIndex,
|
|
7230
7230
|
reservedRows: GRID_CHROME_ROWS,
|
|
7231
|
-
emptyMessage: "No populated cells yet
|
|
7231
|
+
emptyMessage: "No populated cells yet — press 't' to go back to the grid and start typing.",
|
|
7232
7232
|
renderItem: (row, isSelected) => /* @__PURE__ */ jsxs(Text, {
|
|
7233
7233
|
color: selectedColor(isSelected),
|
|
7234
7234
|
inverse: isSelected,
|
|
@@ -7586,7 +7586,7 @@ function XlsSheetListScreen() {
|
|
|
7586
7586
|
/* @__PURE__ */ jsx(ListView, {
|
|
7587
7587
|
items: rows,
|
|
7588
7588
|
selectedIndex,
|
|
7589
|
-
emptyMessage: "This workbook has no sheets yet
|
|
7589
|
+
emptyMessage: "This workbook has no sheets yet — press 'a' to add one.",
|
|
7590
7590
|
renderItem: (row, isSelected) => /* @__PURE__ */ jsx(Text, {
|
|
7591
7591
|
color: selectedColor(isSelected),
|
|
7592
7592
|
inverse: isSelected,
|
|
@@ -7698,9 +7698,9 @@ function XlsSpreadsheetGridScreen(props) {
|
|
|
7698
7698
|
bold: true,
|
|
7699
7699
|
children: [
|
|
7700
7700
|
sheet.name,
|
|
7701
|
-
"
|
|
7701
|
+
" — non-empty cells (",
|
|
7702
7702
|
entries.length,
|
|
7703
|
-
")
|
|
7703
|
+
") — 't' back to grid"
|
|
7704
7704
|
]
|
|
7705
7705
|
}),
|
|
7706
7706
|
entries.length === 0 ? /* @__PURE__ */ jsx(Text, {
|
|
@@ -7813,7 +7813,7 @@ function ListEditorScreen() {
|
|
|
7813
7813
|
} else if (input === "<") dispatch({
|
|
7814
7814
|
type: "SET_STATUS",
|
|
7815
7815
|
severity: "warning",
|
|
7816
|
-
text: "Outdenting isn't reachable from this screen yet
|
|
7816
|
+
text: "Outdenting isn't reachable from this screen yet — it only browses top-level lists, with no route into an item's own nested list"
|
|
7817
7817
|
});
|
|
7818
7818
|
}, { isActive: isNavigationActive });
|
|
7819
7819
|
if (screen.kind !== "listEditor") return /* @__PURE__ */ jsx(Text, {
|
|
@@ -7834,7 +7834,7 @@ function ListEditorScreen() {
|
|
|
7834
7834
|
});
|
|
7835
7835
|
if (editingIndex !== void 0) {
|
|
7836
7836
|
const item = items[editingIndex];
|
|
7837
|
-
if (item === void 0) throw new Error(`ListEditorScreen is editing item index ${editingIndex}, but list ${screen.blockIndex} only has ${items.length} items
|
|
7837
|
+
if (item === void 0) throw new Error(`ListEditorScreen is editing item index ${editingIndex}, but list ${screen.blockIndex} only has ${items.length} items — selecting a row always sets editingIndex to a valid index from that same items array, so this indicates a bug in that selection.`);
|
|
7838
7838
|
return /* @__PURE__ */ jsxs(Box, {
|
|
7839
7839
|
flexDirection: "column",
|
|
7840
7840
|
children: [/* @__PURE__ */ jsxs(Text, {
|
|
@@ -7880,7 +7880,7 @@ function ListEditorScreen() {
|
|
|
7880
7880
|
/* @__PURE__ */ jsx(ListView, {
|
|
7881
7881
|
items: rows,
|
|
7882
7882
|
selectedIndex,
|
|
7883
|
-
emptyMessage: "This list has no items yet
|
|
7883
|
+
emptyMessage: "This list has no items yet — press 'a' to add one.",
|
|
7884
7884
|
renderItem: (row, isSelected) => {
|
|
7885
7885
|
const trimmed = row.item.text.trim();
|
|
7886
7886
|
return /* @__PURE__ */ jsxs(Text, {
|
|
@@ -8079,7 +8079,7 @@ function PdfPageListScreen() {
|
|
|
8079
8079
|
children: [
|
|
8080
8080
|
"Page ",
|
|
8081
8081
|
pageIndex + 1,
|
|
8082
|
-
"
|
|
8082
|
+
" — ",
|
|
8083
8083
|
pageSummaryText(page)
|
|
8084
8084
|
]
|
|
8085
8085
|
})
|
|
@@ -8623,7 +8623,7 @@ function buildRowsFor(item, pageIndex, itemIndex, dispatch, onReplaceImage) {
|
|
|
8623
8623
|
}
|
|
8624
8624
|
function pathSummary(item) {
|
|
8625
8625
|
const segmentCount = item.subpaths.reduce((total, subpath) => total + subpath.segments.length, 0);
|
|
8626
|
-
return `${item.subpaths.length} subpath${item.subpaths.length === 1 ? "" : "s"}, ${segmentCount} segment${segmentCount === 1 ? "" : "s"} (not editable here
|
|
8626
|
+
return `${item.subpaths.length} subpath${item.subpaths.length === 1 ? "" : "s"}, ${segmentCount} segment${segmentCount === 1 ? "" : "s"} (not editable here — see documents.js's own PdfPathItem doc comment)`;
|
|
8627
8627
|
}
|
|
8628
8628
|
async function applyImageReplace(pageIndex, itemIndex, path, dispatch) {
|
|
8629
8629
|
const format = inferImageFormat(path);
|
|
@@ -8631,7 +8631,7 @@ async function applyImageReplace(pageIndex, itemIndex, path, dispatch) {
|
|
|
8631
8631
|
dispatch({
|
|
8632
8632
|
type: "SET_STATUS",
|
|
8633
8633
|
severity: "warning",
|
|
8634
|
-
text: `${path} is not a .png or .jpg/.jpeg file
|
|
8634
|
+
text: `${path} is not a .png or .jpg/.jpeg file — image not replaced`
|
|
8635
8635
|
});
|
|
8636
8636
|
return;
|
|
8637
8637
|
}
|
|
@@ -8711,7 +8711,7 @@ function EditableItemDetail(props) {
|
|
|
8711
8711
|
});
|
|
8712
8712
|
if (editingField !== void 0) {
|
|
8713
8713
|
const row = rows[editingField];
|
|
8714
|
-
if (row === void 0) throw new Error(`EditableItemDetail is editing field index ${editingField}, but there are only ${rows.length} rows
|
|
8714
|
+
if (row === void 0) throw new Error(`EditableItemDetail is editing field index ${editingField}, but there are only ${rows.length} rows — selecting a row always sets editingField to a valid index from that same rows array, so this indicates a bug in that selection.`);
|
|
8715
8715
|
return /* @__PURE__ */ jsxs(Box, {
|
|
8716
8716
|
flexDirection: "column",
|
|
8717
8717
|
borderStyle: "round",
|
|
@@ -8743,7 +8743,7 @@ function EditableItemDetail(props) {
|
|
|
8743
8743
|
pageIndex + 1,
|
|
8744
8744
|
", item ",
|
|
8745
8745
|
itemIndex + 1,
|
|
8746
|
-
"
|
|
8746
|
+
" — ",
|
|
8747
8747
|
item.kind
|
|
8748
8748
|
]
|
|
8749
8749
|
}),
|
|
@@ -9090,7 +9090,7 @@ async function applyAddKind(kind, pageIndex, values, dispatch) {
|
|
|
9090
9090
|
dispatch({
|
|
9091
9091
|
type: "SET_STATUS",
|
|
9092
9092
|
severity: "warning",
|
|
9093
|
-
text: `${path} is not a .png or .jpg/.jpeg file
|
|
9093
|
+
text: `${path} is not a .png or .jpg/.jpeg file — image not added`
|
|
9094
9094
|
});
|
|
9095
9095
|
return;
|
|
9096
9096
|
}
|
|
@@ -9147,7 +9147,7 @@ function AddItemFlow(props) {
|
|
|
9147
9147
|
paddingX: 1,
|
|
9148
9148
|
children: [/* @__PURE__ */ jsx(Text, {
|
|
9149
9149
|
bold: true,
|
|
9150
|
-
children: "Add item
|
|
9150
|
+
children: "Add item — choose a kind"
|
|
9151
9151
|
}), /* @__PURE__ */ jsx(ListView, {
|
|
9152
9152
|
items: ADD_KIND_OPTIONS,
|
|
9153
9153
|
selectedIndex,
|
|
@@ -9243,7 +9243,7 @@ function PdfPageItemsScreen() {
|
|
|
9243
9243
|
/* @__PURE__ */ jsx(ListView, {
|
|
9244
9244
|
items,
|
|
9245
9245
|
selectedIndex,
|
|
9246
|
-
emptyMessage: query === "" ? editable ? "This page has no items
|
|
9246
|
+
emptyMessage: query === "" ? editable ? "This page has no items — press 'a' to add one" : "This page has no items." : `No items match "${state.searchQuery}".`,
|
|
9247
9247
|
renderItem: ({ item, itemIndex }, isSelected) => /* @__PURE__ */ jsxs(Text, {
|
|
9248
9248
|
color: selectedColor(isSelected),
|
|
9249
9249
|
inverse: isSelected,
|
|
@@ -9251,7 +9251,7 @@ function PdfPageItemsScreen() {
|
|
|
9251
9251
|
itemIndex + 1,
|
|
9252
9252
|
". ",
|
|
9253
9253
|
item.kind,
|
|
9254
|
-
"
|
|
9254
|
+
" — ",
|
|
9255
9255
|
previewFor(item)
|
|
9256
9256
|
]
|
|
9257
9257
|
})
|
|
@@ -9543,7 +9543,7 @@ function FilePickerScreen() {
|
|
|
9543
9543
|
bold: true,
|
|
9544
9544
|
children: [
|
|
9545
9545
|
titleFor(purpose),
|
|
9546
|
-
"
|
|
9546
|
+
" — ",
|
|
9547
9547
|
currentDir
|
|
9548
9548
|
]
|
|
9549
9549
|
}),
|
|
@@ -9612,7 +9612,7 @@ function LauncherScreen() {
|
|
|
9612
9612
|
}),
|
|
9613
9613
|
/* @__PURE__ */ jsx(Text, {
|
|
9614
9614
|
dimColor: true,
|
|
9615
|
-
children: "A terminal editor for docx, pptx, odt, odp, ods, odg, doc, xls, ppt, markdown, odb and pdf
|
|
9615
|
+
children: "A terminal editor for docx, pptx, odt, odp, ods, odg, doc, xls, ppt, markdown, odb and pdf — xlsx, csv, svg, rtf, wpd and epub open as read-only PDF previews."
|
|
9616
9616
|
}),
|
|
9617
9617
|
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
9618
9618
|
/* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
|
|
@@ -9802,7 +9802,7 @@ function metadataFor(doc) {
|
|
|
9802
9802
|
case "rtf":
|
|
9803
9803
|
case "wpd":
|
|
9804
9804
|
case "epub": return doc.layout.metadata;
|
|
9805
|
-
case "odb": throw new Error("A .odb database has no document-level metadata
|
|
9805
|
+
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.");
|
|
9806
9806
|
}
|
|
9807
9807
|
}
|
|
9808
9808
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "document-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.12.0",
|
|
4
4
|
"description": "CLI and interactive Ink TUI for documents.js: every docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/csv/svg/markdown/rtf conversion, bridge, and editor as a scriptable command or a terminal app.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -92,9 +92,9 @@
|
|
|
92
92
|
"packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c",
|
|
93
93
|
"dependencies": {
|
|
94
94
|
"commander": "15.0.0",
|
|
95
|
-
"document-outline.js": "3.
|
|
96
|
-
"document-schema.js": "7.
|
|
97
|
-
"documents.js": "14.
|
|
95
|
+
"document-outline.js": "3.10.0",
|
|
96
|
+
"document-schema.js": "7.15.0",
|
|
97
|
+
"documents.js": "14.2.0",
|
|
98
98
|
"ink": "7.1.1",
|
|
99
99
|
"ink-text-input": "6.0.0",
|
|
100
100
|
"react": "19.2.8"
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"eslint": "10.8.1",
|
|
112
112
|
"husky": "9.1.7",
|
|
113
113
|
"ink-testing-library": "4.0.0",
|
|
114
|
-
"odf.js": "11.
|
|
114
|
+
"odf.js": "11.1.0",
|
|
115
115
|
"publint": "0.3.22",
|
|
116
116
|
"semantic-release": "25.0.9",
|
|
117
117
|
"tsdown": "0.22.14",
|