politty 0.4.4 → 0.4.6
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/{arg-registry-BUUhZ7JR.d.ts → arg-registry-2m40k1Et.d.ts} +1 -1
- package/dist/{arg-registry-BUUhZ7JR.d.ts.map → arg-registry-2m40k1Et.d.ts.map} +1 -1
- package/dist/augment.d.ts +1 -1
- package/dist/completion/index.cjs +16 -168
- package/dist/completion/index.d.cts +2 -77
- package/dist/completion/index.d.ts +2 -77
- package/dist/completion/index.js +3 -154
- package/dist/{zsh-DR47Ccac.cjs → completion-Df0eZ70u.cjs} +230 -18
- package/dist/completion-Df0eZ70u.cjs.map +1 -0
- package/dist/{zsh-XbRzR8FW.js → completion-_AnQsWh9.js} +202 -8
- package/dist/completion-_AnQsWh9.js.map +1 -0
- package/dist/docs/index.cjs +274 -28
- package/dist/docs/index.cjs.map +1 -1
- package/dist/docs/index.d.cts +62 -7
- package/dist/docs/index.d.cts.map +1 -1
- package/dist/docs/index.d.ts +62 -7
- package/dist/docs/index.d.ts.map +1 -1
- package/dist/docs/index.js +269 -29
- package/dist/docs/index.js.map +1 -1
- package/dist/{value-completion-resolver-BQgHsX7b.d.cts → index-BZalbMeu.d.ts} +83 -4
- package/dist/index-BZalbMeu.d.ts.map +1 -0
- package/dist/{value-completion-resolver-C9LTGr0O.d.ts → index-C5-0RXiH.d.cts} +83 -4
- package/dist/index-C5-0RXiH.d.cts.map +1 -0
- package/dist/index.cjs +8 -7
- package/dist/index.d.cts +67 -13
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +68 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -5
- package/dist/{lazy-BEDnSR0m.cjs → lazy-DHlvJiQQ.cjs} +44 -8
- package/dist/lazy-DHlvJiQQ.cjs.map +1 -0
- package/dist/{lazy-BrEg8SgI.js → lazy-DSyfzR-F.js} +38 -8
- package/dist/lazy-DSyfzR-F.js.map +1 -0
- package/dist/{runner-C4fSHJMe.cjs → runner-C1Aah5c5.cjs} +365 -23
- package/dist/runner-C1Aah5c5.cjs.map +1 -0
- package/dist/{runner-D6k4BgB4.js → runner-DjG0uBxQ.js} +365 -23
- package/dist/runner-DjG0uBxQ.js.map +1 -0
- package/dist/{schema-extractor-n9288WJ6.d.ts → schema-extractor-C9APqeSL.d.ts} +30 -3
- package/dist/schema-extractor-C9APqeSL.d.ts.map +1 -0
- package/dist/{schema-extractor-DFaAZzaY.d.cts → schema-extractor-CVf0J4An.d.cts} +29 -2
- package/dist/schema-extractor-CVf0J4An.d.cts.map +1 -0
- package/dist/{subcommand-router-CAzBsLSI.js → subcommand-router-CKuy6D2b.js} +2 -2
- package/dist/{subcommand-router-CAzBsLSI.js.map → subcommand-router-CKuy6D2b.js.map} +1 -1
- package/dist/{subcommand-router-ZjNjFaUL.cjs → subcommand-router-sZHhUP7b.cjs} +2 -2
- package/dist/{subcommand-router-ZjNjFaUL.cjs.map → subcommand-router-sZHhUP7b.cjs.map} +1 -1
- package/package.json +9 -9
- package/dist/completion/index.cjs.map +0 -1
- package/dist/completion/index.d.cts.map +0 -1
- package/dist/completion/index.d.ts.map +0 -1
- package/dist/completion/index.js.map +0 -1
- package/dist/lazy-BEDnSR0m.cjs.map +0 -1
- package/dist/lazy-BrEg8SgI.js.map +0 -1
- package/dist/runner-C4fSHJMe.cjs.map +0 -1
- package/dist/runner-D6k4BgB4.js.map +0 -1
- package/dist/schema-extractor-DFaAZzaY.d.cts.map +0 -1
- package/dist/schema-extractor-n9288WJ6.d.ts.map +0 -1
- package/dist/value-completion-resolver-BQgHsX7b.d.cts.map +0 -1
- package/dist/value-completion-resolver-C9LTGr0O.d.ts.map +0 -1
- package/dist/zsh-DR47Ccac.cjs.map +0 -1
- package/dist/zsh-XbRzR8FW.js.map +0 -1
package/dist/docs/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const require_subcommand_router = require('../subcommand-router-
|
|
3
|
-
const require_lazy = require('../lazy-
|
|
2
|
+
const require_subcommand_router = require('../subcommand-router-sZHhUP7b.cjs');
|
|
3
|
+
const require_lazy = require('../lazy-DHlvJiQQ.cjs');
|
|
4
4
|
let zod = require("zod");
|
|
5
5
|
let node_util = require("node:util");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
@@ -61,6 +61,26 @@ function globalOptionsEndMarker() {
|
|
|
61
61
|
return `<!-- ${GLOBAL_OPTIONS_MARKER_PREFIX}:end -->`;
|
|
62
62
|
}
|
|
63
63
|
/**
|
|
64
|
+
* Marker prefix for root header sections in generated documentation
|
|
65
|
+
*/
|
|
66
|
+
const ROOT_HEADER_MARKER_PREFIX = "politty:root-header";
|
|
67
|
+
function rootHeaderStartMarker() {
|
|
68
|
+
return `<!-- ${ROOT_HEADER_MARKER_PREFIX}:start -->`;
|
|
69
|
+
}
|
|
70
|
+
function rootHeaderEndMarker() {
|
|
71
|
+
return `<!-- ${ROOT_HEADER_MARKER_PREFIX}:end -->`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Marker prefix for root footer sections in generated documentation
|
|
75
|
+
*/
|
|
76
|
+
const ROOT_FOOTER_MARKER_PREFIX = "politty:root-footer";
|
|
77
|
+
function rootFooterStartMarker() {
|
|
78
|
+
return `<!-- ${ROOT_FOOTER_MARKER_PREFIX}:start -->`;
|
|
79
|
+
}
|
|
80
|
+
function rootFooterEndMarker() {
|
|
81
|
+
return `<!-- ${ROOT_FOOTER_MARKER_PREFIX}:end -->`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
64
84
|
* Marker prefix for index sections in generated documentation
|
|
65
85
|
* Format: <!-- politty:index:<scope>:start --> ... <!-- politty:index:<scope>:end -->
|
|
66
86
|
*/
|
|
@@ -301,6 +321,68 @@ function renderOptionsTableFromArray(options) {
|
|
|
301
321
|
return lines.join("\n");
|
|
302
322
|
}
|
|
303
323
|
/**
|
|
324
|
+
* Render union/xor options as markdown with variant grouping
|
|
325
|
+
*/
|
|
326
|
+
function renderUnionOptionsMarkdown(extracted, style = "table") {
|
|
327
|
+
const unionOptions = extracted.unionOptions ?? [];
|
|
328
|
+
if (unionOptions.length === 0) return "";
|
|
329
|
+
const sections = [];
|
|
330
|
+
const allFieldNames = /* @__PURE__ */ new Set();
|
|
331
|
+
for (const option of unionOptions) for (const field of option.fields) allFieldNames.add(field.name);
|
|
332
|
+
const commonFieldNames = /* @__PURE__ */ new Set();
|
|
333
|
+
for (const fieldName of allFieldNames) if (unionOptions.every((o) => o.fields.some((f) => f.name === fieldName))) commonFieldNames.add(fieldName);
|
|
334
|
+
const commonFields = extracted.fields.filter((f) => commonFieldNames.has(f.name) && !f.positional);
|
|
335
|
+
if (commonFields.length > 0) sections.push(style === "table" ? renderOptionsTableFromArray(commonFields) : renderOptionsListFromArray(commonFields));
|
|
336
|
+
sections.push("> One of the following option groups is required:");
|
|
337
|
+
for (let i = 0; i < unionOptions.length; i++) {
|
|
338
|
+
const option = unionOptions[i];
|
|
339
|
+
if (!option) continue;
|
|
340
|
+
const uniqueFields = option.fields.filter((f) => !commonFieldNames.has(f.name) && !f.positional);
|
|
341
|
+
if (uniqueFields.length === 0) continue;
|
|
342
|
+
const label = option.description ?? `Variant ${i + 1}`;
|
|
343
|
+
const rendered = style === "table" ? renderOptionsTableFromArray(uniqueFields) : renderOptionsListFromArray(uniqueFields);
|
|
344
|
+
sections.push(`**${label}:**\n\n${rendered}`);
|
|
345
|
+
}
|
|
346
|
+
return sections.join("\n\n");
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Render discriminatedUnion options as markdown with variant grouping
|
|
350
|
+
*/
|
|
351
|
+
function renderDiscriminatedUnionOptionsMarkdown(extracted, style = "table") {
|
|
352
|
+
const discriminator = extracted.discriminator;
|
|
353
|
+
const variants = extracted.variants ?? [];
|
|
354
|
+
if (!discriminator || variants.length === 0) return "";
|
|
355
|
+
const sections = [];
|
|
356
|
+
const allFieldNames = /* @__PURE__ */ new Set();
|
|
357
|
+
for (const variant of variants) for (const field of variant.fields) allFieldNames.add(field.name);
|
|
358
|
+
const commonFieldNames = /* @__PURE__ */ new Set();
|
|
359
|
+
for (const fieldName of allFieldNames) {
|
|
360
|
+
if (fieldName === discriminator) continue;
|
|
361
|
+
if (variants.every((v) => v.fields.some((f) => f.name === fieldName))) commonFieldNames.add(fieldName);
|
|
362
|
+
}
|
|
363
|
+
const discriminatorField = extracted.fields.find((f) => f.name === discriminator);
|
|
364
|
+
const variantValues = variants.map((v) => v.discriminatorValue).join("\\|");
|
|
365
|
+
const topFields = [];
|
|
366
|
+
if (discriminatorField) topFields.push({
|
|
367
|
+
...discriminatorField,
|
|
368
|
+
placeholder: variantValues
|
|
369
|
+
});
|
|
370
|
+
for (const fieldName of commonFieldNames) {
|
|
371
|
+
const field = extracted.fields.find((f) => f.name === fieldName);
|
|
372
|
+
if (field && !field.positional) topFields.push(field);
|
|
373
|
+
}
|
|
374
|
+
if (topFields.length > 0) sections.push(style === "table" ? renderOptionsTableFromArray(topFields) : renderOptionsListFromArray(topFields));
|
|
375
|
+
for (const variant of variants) {
|
|
376
|
+
const uniqueFields = variant.fields.filter((f) => f.name !== discriminator && !commonFieldNames.has(f.name) && !f.positional);
|
|
377
|
+
if (uniqueFields.length === 0) continue;
|
|
378
|
+
const descSuffix = variant.description ? ` ${variant.description}` : "";
|
|
379
|
+
const label = `**When \`${discriminator}\` = \`${variant.discriminatorValue}\`:**${descSuffix}`;
|
|
380
|
+
const rendered = style === "table" ? renderOptionsTableFromArray(uniqueFields) : renderOptionsListFromArray(uniqueFields);
|
|
381
|
+
sections.push(`${label}\n\n${rendered}`);
|
|
382
|
+
}
|
|
383
|
+
return sections.join("\n\n");
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
304
386
|
* Render options from array as list
|
|
305
387
|
*/
|
|
306
388
|
function renderOptionsListFromArray(options) {
|
|
@@ -416,8 +498,13 @@ function wrapWithMarker(type, scope, content) {
|
|
|
416
498
|
return `${sectionStartMarker(type, scope)}\n${content}\n${sectionEndMarker(type, scope)}`;
|
|
417
499
|
}
|
|
418
500
|
/**
|
|
419
|
-
*
|
|
501
|
+
* Generate a "See Global Options" link for subcommand documentation.
|
|
502
|
+
* Returns null for root command or when no global options exist.
|
|
420
503
|
*/
|
|
504
|
+
function getGlobalOptionsLink(info) {
|
|
505
|
+
if (!info.hasGlobalOptions || info.commandPath === "") return null;
|
|
506
|
+
return `See [Global Options](${info.rootDocPath && info.filePath && info.filePath !== info.rootDocPath ? `${getRelativePath(info.filePath, info.rootDocPath)}#global-options` : "#global-options"}) for options available to all commands.`;
|
|
507
|
+
}
|
|
421
508
|
function createCommandRenderer(options = {}) {
|
|
422
509
|
const { headingLevel = 1, optionStyle = "table", generateAnchors = true, includeSubcommandDetails = true, renderDescription: customRenderDescription, renderUsage: customRenderUsage, renderArguments: customRenderArguments, renderOptions: customRenderOptions, renderSubcommands: customRenderSubcommands, renderNotes: customRenderNotes, renderFooter: customRenderFooter, renderExamples: customRenderExamples } = options;
|
|
423
510
|
return (info) => {
|
|
@@ -465,7 +552,11 @@ function createCommandRenderer(options = {}) {
|
|
|
465
552
|
const renderOpts = (opts, renderOpts) => {
|
|
466
553
|
const style = renderOpts?.style ?? optionStyle;
|
|
467
554
|
const withHeading = renderOpts?.withHeading ?? true;
|
|
468
|
-
const
|
|
555
|
+
const extracted = info.extracted;
|
|
556
|
+
let content;
|
|
557
|
+
if (extracted && (extracted.schemaType === "union" || extracted.schemaType === "xor") && extracted.unionOptions) content = renderUnionOptionsMarkdown(extracted, style);
|
|
558
|
+
else if (extracted && extracted.schemaType === "discriminatedUnion" && extracted.discriminator) content = renderDiscriminatedUnionOptionsMarkdown(extracted, style);
|
|
559
|
+
else content = style === "table" ? renderOptionsTableFromArray(opts) : renderOptionsListFromArray(opts);
|
|
469
560
|
return withHeading ? `**Options**\n\n${content}` : content;
|
|
470
561
|
};
|
|
471
562
|
const context = {
|
|
@@ -477,6 +568,10 @@ function createCommandRenderer(options = {}) {
|
|
|
477
568
|
const content = customRenderOptions ? customRenderOptions(context) : renderOpts(context.options);
|
|
478
569
|
if (content) sections.push(wrapWithMarker("options", scope, content));
|
|
479
570
|
}
|
|
571
|
+
{
|
|
572
|
+
const globalLink = getGlobalOptionsLink(info);
|
|
573
|
+
if (globalLink) sections.push(globalLink);
|
|
574
|
+
}
|
|
480
575
|
if (info.subCommands.length > 0) {
|
|
481
576
|
const effectiveAnchors = generateAnchors && includeSubcommandDetails;
|
|
482
577
|
const renderSubs = (subs, opts) => {
|
|
@@ -723,7 +818,7 @@ async function executeSingleExample(example, rootCommand, commandPath) {
|
|
|
723
818
|
collector.start();
|
|
724
819
|
let success = true;
|
|
725
820
|
try {
|
|
726
|
-
const { runCommand } = await Promise.resolve().then(() => require("../runner-
|
|
821
|
+
const { runCommand } = await Promise.resolve().then(() => require("../runner-C1Aah5c5.cjs")).then((n) => n.runner_exports);
|
|
727
822
|
const result = await runCommand(rootCommand, argv);
|
|
728
823
|
success = result.success;
|
|
729
824
|
if (!result.success && result.error) console.error(result.error.message);
|
|
@@ -1127,7 +1222,7 @@ function resolveConfiguredCommandPaths(fileConfigRaw, allCommands, ignores) {
|
|
|
1127
1222
|
return {
|
|
1128
1223
|
fileConfig,
|
|
1129
1224
|
specifiedCommands,
|
|
1130
|
-
commandPaths: filterIgnoredCommands(expandCommandPaths(specifiedCommands, allCommands), ignores),
|
|
1225
|
+
commandPaths: filterIgnoredCommands(fileConfig.noExpand ? specifiedCommands.filter((p) => allCommands.has(p)) : expandCommandPaths(specifiedCommands, allCommands), ignores),
|
|
1131
1226
|
topLevelCommands: filterIgnoredCommands(resolveTopLevelCommands(specifiedCommands, allCommands), ignores)
|
|
1132
1227
|
};
|
|
1133
1228
|
}
|
|
@@ -1447,6 +1542,7 @@ function generateGlobalOptionsSection(config) {
|
|
|
1447
1542
|
const endMarker = globalOptionsEndMarker();
|
|
1448
1543
|
return [
|
|
1449
1544
|
startMarker,
|
|
1545
|
+
"<a id=\"global-options\"></a>",
|
|
1450
1546
|
renderArgsTable(config.args, config.options),
|
|
1451
1547
|
endMarker
|
|
1452
1548
|
].join("\n");
|
|
@@ -1473,7 +1569,7 @@ function normalizeDocPathForComparison(filePath) {
|
|
|
1473
1569
|
* Process global options marker in file content
|
|
1474
1570
|
* Returns result with updated content and any diffs
|
|
1475
1571
|
*/
|
|
1476
|
-
async function processGlobalOptionsMarker(existingContent, globalOptionsConfig, updateMode, formatter) {
|
|
1572
|
+
async function processGlobalOptionsMarker(existingContent, globalOptionsConfig, updateMode, formatter, autoInsertIfMissing) {
|
|
1477
1573
|
let content = existingContent;
|
|
1478
1574
|
const diffs = [];
|
|
1479
1575
|
let hasError = false;
|
|
@@ -1483,6 +1579,16 @@ async function processGlobalOptionsMarker(existingContent, globalOptionsConfig,
|
|
|
1483
1579
|
const generatedSection = await applyFormatter(generateGlobalOptionsSection(globalOptionsConfig), formatter);
|
|
1484
1580
|
const existingSection = extractMarkerSection(content, startMarker, endMarker);
|
|
1485
1581
|
if (!existingSection) {
|
|
1582
|
+
if (updateMode && autoInsertIfMissing) {
|
|
1583
|
+
content = content.trimEnd() + "\n\n" + generatedSection + "\n";
|
|
1584
|
+
wasUpdated = true;
|
|
1585
|
+
return {
|
|
1586
|
+
content,
|
|
1587
|
+
diffs,
|
|
1588
|
+
hasError,
|
|
1589
|
+
wasUpdated
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1486
1592
|
hasError = true;
|
|
1487
1593
|
diffs.push(`Global options marker not found in file. Expected markers:\n${startMarker}\n...\n${endMarker}`);
|
|
1488
1594
|
return {
|
|
@@ -1513,6 +1619,61 @@ async function processGlobalOptionsMarker(existingContent, globalOptionsConfig,
|
|
|
1513
1619
|
};
|
|
1514
1620
|
}
|
|
1515
1621
|
/**
|
|
1622
|
+
* Process a static content marker (root-header or root-footer).
|
|
1623
|
+
* Inserts/updates the marker section with the given content.
|
|
1624
|
+
*/
|
|
1625
|
+
async function processStaticMarker(existingContent, markerLabel, startMarker, endMarker, rawContent, updateMode, formatter, autoInsertIfMissing) {
|
|
1626
|
+
let content = existingContent;
|
|
1627
|
+
const diffs = [];
|
|
1628
|
+
let hasError = false;
|
|
1629
|
+
let wasUpdated = false;
|
|
1630
|
+
const generatedSection = [
|
|
1631
|
+
startMarker,
|
|
1632
|
+
await applyFormatter(rawContent, formatter),
|
|
1633
|
+
endMarker
|
|
1634
|
+
].join("\n");
|
|
1635
|
+
const existingSection = extractMarkerSection(content, startMarker, endMarker);
|
|
1636
|
+
if (!existingSection) {
|
|
1637
|
+
if (updateMode && autoInsertIfMissing) {
|
|
1638
|
+
content = content.trimEnd() + "\n\n" + generatedSection + "\n";
|
|
1639
|
+
wasUpdated = true;
|
|
1640
|
+
return {
|
|
1641
|
+
content,
|
|
1642
|
+
diffs,
|
|
1643
|
+
hasError,
|
|
1644
|
+
wasUpdated
|
|
1645
|
+
};
|
|
1646
|
+
}
|
|
1647
|
+
hasError = true;
|
|
1648
|
+
diffs.push(`${markerLabel} marker not found in file. Expected markers:\n${startMarker}\n...\n${endMarker}`);
|
|
1649
|
+
return {
|
|
1650
|
+
content,
|
|
1651
|
+
diffs,
|
|
1652
|
+
hasError,
|
|
1653
|
+
wasUpdated
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1656
|
+
if (existingSection !== generatedSection) if (updateMode) {
|
|
1657
|
+
const updated = replaceMarkerSection(content, startMarker, endMarker, generatedSection);
|
|
1658
|
+
if (updated) {
|
|
1659
|
+
content = updated;
|
|
1660
|
+
wasUpdated = true;
|
|
1661
|
+
} else {
|
|
1662
|
+
hasError = true;
|
|
1663
|
+
diffs.push(`Failed to replace ${markerLabel} section`);
|
|
1664
|
+
}
|
|
1665
|
+
} else {
|
|
1666
|
+
hasError = true;
|
|
1667
|
+
diffs.push(formatDiff(existingSection, generatedSection));
|
|
1668
|
+
}
|
|
1669
|
+
return {
|
|
1670
|
+
content,
|
|
1671
|
+
diffs,
|
|
1672
|
+
hasError,
|
|
1673
|
+
wasUpdated
|
|
1674
|
+
};
|
|
1675
|
+
}
|
|
1676
|
+
/**
|
|
1516
1677
|
* Process index marker in file content
|
|
1517
1678
|
* Returns result with updated content and any diffs.
|
|
1518
1679
|
* If the marker is not present in the file, the section is silently skipped.
|
|
@@ -1603,26 +1764,29 @@ function findTargetCommandsInFile(targetCommands, filePath, files, allCommands,
|
|
|
1603
1764
|
/**
|
|
1604
1765
|
* Generate a single command section (already contains section markers from renderer)
|
|
1605
1766
|
*/
|
|
1606
|
-
function generateCommandSection(cmdPath, allCommands, render, filePath, fileMap) {
|
|
1767
|
+
function generateCommandSection(cmdPath, allCommands, render, filePath, fileMap, rootDocPath, hasGlobalOptions) {
|
|
1607
1768
|
const info = allCommands.get(cmdPath);
|
|
1608
1769
|
if (!info) return null;
|
|
1609
|
-
|
|
1770
|
+
const enriched = {
|
|
1610
1771
|
...info,
|
|
1611
1772
|
filePath,
|
|
1612
|
-
fileMap
|
|
1613
|
-
|
|
1773
|
+
fileMap,
|
|
1774
|
+
rootDocPath
|
|
1775
|
+
};
|
|
1776
|
+
if (hasGlobalOptions !== void 0) enriched.hasGlobalOptions = hasGlobalOptions;
|
|
1777
|
+
return render(enriched);
|
|
1614
1778
|
}
|
|
1615
1779
|
/**
|
|
1616
1780
|
* Generate markdown for a file containing multiple commands
|
|
1617
1781
|
* Each command section is wrapped with markers for partial validation
|
|
1618
1782
|
*/
|
|
1619
|
-
function generateFileMarkdown(commandPaths, allCommands, render, filePath, fileMap, specifiedOrder, fileConfig) {
|
|
1783
|
+
function generateFileMarkdown(commandPaths, allCommands, render, filePath, fileMap, specifiedOrder, fileConfig, rootDocPath, hasGlobalOptions) {
|
|
1620
1784
|
const sections = [];
|
|
1621
1785
|
const header = fileConfig ? generateFileHeader(fileConfig) : null;
|
|
1622
1786
|
if (header) sections.push(header);
|
|
1623
1787
|
const sortedPaths = sortDepthFirst(commandPaths, specifiedOrder ?? []);
|
|
1624
1788
|
for (const cmdPath of sortedPaths) {
|
|
1625
|
-
const section = generateCommandSection(cmdPath, allCommands, render, filePath, fileMap);
|
|
1789
|
+
const section = generateCommandSection(cmdPath, allCommands, render, filePath, fileMap, rootDocPath, hasGlobalOptions);
|
|
1626
1790
|
if (section) sections.push(section);
|
|
1627
1791
|
}
|
|
1628
1792
|
return `${sections.join("\n")}\n`;
|
|
@@ -1651,16 +1815,72 @@ async function executeConfiguredExamples(allCommands, examplesConfig, rootComman
|
|
|
1651
1815
|
}
|
|
1652
1816
|
}
|
|
1653
1817
|
/**
|
|
1818
|
+
* Convert PathConfig to FileMapping with explicit command paths.
|
|
1819
|
+
* Uses noExpand to prevent subcommand expansion since paths are pre-resolved.
|
|
1820
|
+
*/
|
|
1821
|
+
function pathToFiles(pathConfig, allCommands) {
|
|
1822
|
+
if (typeof pathConfig === "string") return {
|
|
1823
|
+
files: { [pathConfig]: Array.from(allCommands.keys()) },
|
|
1824
|
+
rootDocPath: pathConfig
|
|
1825
|
+
};
|
|
1826
|
+
const { root, commands = {} } = pathConfig;
|
|
1827
|
+
const files = {};
|
|
1828
|
+
const assignedToOtherFiles = /* @__PURE__ */ new Set();
|
|
1829
|
+
const sortedEntries = Object.entries(commands).sort(([a], [b]) => b.split(" ").length - a.split(" ").length);
|
|
1830
|
+
for (const [cmdPath, filePath] of sortedEntries) {
|
|
1831
|
+
if (!files[filePath]) files[filePath] = {
|
|
1832
|
+
commands: [],
|
|
1833
|
+
noExpand: true
|
|
1834
|
+
};
|
|
1835
|
+
const fc = files[filePath];
|
|
1836
|
+
for (const existingPath of allCommands.keys()) if ((existingPath === cmdPath || existingPath.startsWith(cmdPath + " ")) && !assignedToOtherFiles.has(existingPath)) {
|
|
1837
|
+
fc.commands.push(existingPath);
|
|
1838
|
+
assignedToOtherFiles.add(existingPath);
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
files[root] = {
|
|
1842
|
+
commands: Array.from(allCommands.keys()).filter((p) => !assignedToOtherFiles.has(p)),
|
|
1843
|
+
noExpand: true
|
|
1844
|
+
};
|
|
1845
|
+
return {
|
|
1846
|
+
files,
|
|
1847
|
+
rootDocPath: root
|
|
1848
|
+
};
|
|
1849
|
+
}
|
|
1850
|
+
/**
|
|
1654
1851
|
* Generate documentation from command definition
|
|
1655
1852
|
*/
|
|
1656
1853
|
async function generateDoc(config) {
|
|
1657
|
-
const { command,
|
|
1854
|
+
const { command, ignores = [], format = {}, formatter, examples: examplesConfig, targetCommands, globalArgs } = config;
|
|
1855
|
+
const allCommands = await collectAllCommands(command);
|
|
1856
|
+
let files;
|
|
1857
|
+
let usingPathConfig = false;
|
|
1858
|
+
let resolvedRootDocPath;
|
|
1859
|
+
if (config.path !== void 0) {
|
|
1860
|
+
if (config.files !== void 0) throw new Error("Cannot specify both \"path\" and \"files\". Use one or the other.");
|
|
1861
|
+
const converted = pathToFiles(config.path, allCommands);
|
|
1862
|
+
files = converted.files;
|
|
1863
|
+
resolvedRootDocPath = converted.rootDocPath;
|
|
1864
|
+
usingPathConfig = true;
|
|
1865
|
+
} else if (config.files !== void 0) files = config.files;
|
|
1866
|
+
else throw new Error("Either \"path\" or \"files\" must be specified.");
|
|
1867
|
+
let rootDoc = config.rootDoc;
|
|
1868
|
+
if (!rootDoc && usingPathConfig && (globalArgs || config.rootInfo)) rootDoc = { path: resolvedRootDocPath };
|
|
1869
|
+
if (globalArgs && rootDoc && !rootDoc.globalOptions) {
|
|
1870
|
+
const optionFields = require_lazy.extractFields(globalArgs).fields.filter((f) => !f.positional);
|
|
1871
|
+
if (optionFields.length > 0) {
|
|
1872
|
+
const globalShape = Object.fromEntries(optionFields.map((f) => [f.name, f.schema]));
|
|
1873
|
+
rootDoc = {
|
|
1874
|
+
...rootDoc,
|
|
1875
|
+
globalOptions: globalShape
|
|
1876
|
+
};
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1658
1879
|
const updateMode = isUpdateMode();
|
|
1659
|
-
if (rootDoc) {
|
|
1880
|
+
if (rootDoc && !usingPathConfig) {
|
|
1660
1881
|
const normalizedRootDocPath = normalizeDocPathForComparison(rootDoc.path);
|
|
1661
1882
|
if (Object.keys(files).some((filePath) => normalizeDocPathForComparison(filePath) === normalizedRootDocPath)) throw new Error(`rootDoc.path "${rootDoc.path}" must not also appear as a key in files.`);
|
|
1662
1883
|
}
|
|
1663
|
-
const allCommands = await collectAllCommands(command);
|
|
1664
1884
|
if (examplesConfig) await executeConfiguredExamples(allCommands, examplesConfig, command);
|
|
1665
1885
|
const hasTargetCommands = targetCommands !== void 0 && targetCommands.length > 0;
|
|
1666
1886
|
if (hasTargetCommands) {
|
|
@@ -1694,11 +1914,13 @@ async function generateDoc(config) {
|
|
|
1694
1914
|
headingLevel: adjustedHeadingLevel
|
|
1695
1915
|
});
|
|
1696
1916
|
const render = fileConfig.render ?? fileRenderer;
|
|
1697
|
-
|
|
1917
|
+
const isRootDocFile = usingPathConfig && rootDoc && normalizeDocPathForComparison(filePath) === normalizeDocPathForComparison(rootDoc.path);
|
|
1918
|
+
if (hasTargetCommands || isRootDocFile) {
|
|
1698
1919
|
let existingContent = readFile(filePath);
|
|
1699
1920
|
const sortedCommandPaths = sortDepthFirst(commandPaths, specifiedCommands);
|
|
1700
|
-
|
|
1701
|
-
|
|
1921
|
+
const effectiveTargetCommands = hasTargetCommands ? fileTargetCommands : commandPaths;
|
|
1922
|
+
for (const targetCommand of effectiveTargetCommands) {
|
|
1923
|
+
const rawSection = generateCommandSection(targetCommand, allCommands, render, filePath, fileMap, rootDoc?.path, globalOptionDefinitions.size > 0);
|
|
1702
1924
|
if (!rawSection) throw new Error(`Target command "${targetCommand}" not found in commands`);
|
|
1703
1925
|
const generatedSection = await applyFormatter(rawSection, formatter);
|
|
1704
1926
|
if (!existingContent) {
|
|
@@ -1747,7 +1969,7 @@ async function generateDoc(config) {
|
|
|
1747
1969
|
}
|
|
1748
1970
|
}
|
|
1749
1971
|
} else {
|
|
1750
|
-
const generatedMarkdown = await applyFormatter(generateFileMarkdown(commandPaths, allCommands, render, filePath, fileMap, specifiedCommands, fileConfig), formatter);
|
|
1972
|
+
const generatedMarkdown = await applyFormatter(generateFileMarkdown(commandPaths, allCommands, render, filePath, fileMap, specifiedCommands, fileConfig, rootDoc?.path, globalOptionDefinitions.size > 0), formatter);
|
|
1751
1973
|
const comparison = compareWithExisting(generatedMarkdown, filePath);
|
|
1752
1974
|
if (comparison.match) {} else if (updateMode) {
|
|
1753
1975
|
writeFile(filePath, generatedMarkdown);
|
|
@@ -1777,22 +1999,33 @@ async function generateDoc(config) {
|
|
|
1777
1999
|
} else {
|
|
1778
2000
|
let content = existingContent;
|
|
1779
2001
|
let markerUpdated = false;
|
|
1780
|
-
const
|
|
2002
|
+
const rootInfo = config.rootInfo;
|
|
2003
|
+
const rootDocFileConfig = { title: rootInfo?.title ?? command.name };
|
|
1781
2004
|
if (rootDoc.headingLevel !== void 0) rootDocFileConfig.headingLevel = rootDoc.headingLevel;
|
|
1782
|
-
|
|
2005
|
+
const rootDescription = rootInfo?.description ?? command.description;
|
|
2006
|
+
if (rootDescription !== void 0) rootDocFileConfig.description = rootDescription;
|
|
1783
2007
|
const headerResult = processFileHeader(content, rootDocFileConfig, updateMode);
|
|
1784
2008
|
content = headerResult.content;
|
|
1785
2009
|
if (headerResult.diff) rootDocDiffs.push(headerResult.diff);
|
|
1786
2010
|
if (headerResult.hasError) hasError = true;
|
|
1787
2011
|
if (headerResult.wasUpdated) markerUpdated = true;
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
rootDocDiffs.push(
|
|
2012
|
+
if (rootInfo?.header) {
|
|
2013
|
+
const headerMarkerResult = await processStaticMarker(content, "Root header", rootHeaderStartMarker(), rootHeaderEndMarker(), rootInfo.header, updateMode, formatter, usingPathConfig);
|
|
2014
|
+
content = headerMarkerResult.content;
|
|
2015
|
+
rootDocDiffs.push(...headerMarkerResult.diffs);
|
|
2016
|
+
if (headerMarkerResult.hasError) hasError = true;
|
|
2017
|
+
if (headerMarkerResult.wasUpdated) markerUpdated = true;
|
|
2018
|
+
}
|
|
2019
|
+
if (!usingPathConfig) {
|
|
2020
|
+
const unexpectedSectionPaths = Array.from(new Set(collectSectionMarkerPaths(content)));
|
|
2021
|
+
if (unexpectedSectionPaths.length > 0) {
|
|
2022
|
+
hasError = true;
|
|
2023
|
+
rootDocDiffs.push(`Found unexpected section markers in rootDoc: ${unexpectedSectionPaths.map((commandPath) => `"${formatCommandPath(commandPath)}"`).join(", ")}.`);
|
|
2024
|
+
}
|
|
1792
2025
|
}
|
|
1793
2026
|
const normalizedGlobalOptions = normalizeGlobalOptions(rootDoc.globalOptions);
|
|
1794
2027
|
if (normalizedGlobalOptions) {
|
|
1795
|
-
const globalOptionsResult = await processGlobalOptionsMarker(content, normalizedGlobalOptions, updateMode, formatter);
|
|
2028
|
+
const globalOptionsResult = await processGlobalOptionsMarker(content, normalizedGlobalOptions, updateMode, formatter, usingPathConfig);
|
|
1796
2029
|
content = globalOptionsResult.content;
|
|
1797
2030
|
rootDocDiffs.push(...globalOptionsResult.diffs);
|
|
1798
2031
|
if (globalOptionsResult.hasError) hasError = true;
|
|
@@ -1805,6 +2038,13 @@ async function generateDoc(config) {
|
|
|
1805
2038
|
rootDocDiffs.push(...indexResult.diffs);
|
|
1806
2039
|
if (indexResult.hasError) hasError = true;
|
|
1807
2040
|
if (indexResult.wasUpdated) markerUpdated = true;
|
|
2041
|
+
if (rootInfo?.footer) {
|
|
2042
|
+
const footerMarkerResult = await processStaticMarker(content, "Root footer", rootFooterStartMarker(), rootFooterEndMarker(), rootInfo.footer, updateMode, formatter, usingPathConfig);
|
|
2043
|
+
content = footerMarkerResult.content;
|
|
2044
|
+
rootDocDiffs.push(...footerMarkerResult.diffs);
|
|
2045
|
+
if (footerMarkerResult.hasError) hasError = true;
|
|
2046
|
+
if (footerMarkerResult.wasUpdated) markerUpdated = true;
|
|
2047
|
+
}
|
|
1808
2048
|
if (updateMode && markerUpdated) {
|
|
1809
2049
|
writeFile(rootDocFilePath, content);
|
|
1810
2050
|
if (rootDocStatus === "match") rootDocStatus = "updated";
|
|
@@ -1848,12 +2088,14 @@ async function assertDocMatch(config) {
|
|
|
1848
2088
|
function initDocFile(config, fileSystem) {
|
|
1849
2089
|
if (!isUpdateMode()) return;
|
|
1850
2090
|
if (typeof config === "string") deleteFile(config, fileSystem);
|
|
1851
|
-
else for (const filePath of Object.keys(config.files)) deleteFile(filePath, fileSystem);
|
|
2091
|
+
else if (config.files) for (const filePath of Object.keys(config.files)) deleteFile(filePath, fileSystem);
|
|
1852
2092
|
}
|
|
1853
2093
|
|
|
1854
2094
|
//#endregion
|
|
1855
2095
|
exports.GLOBAL_OPTIONS_MARKER_PREFIX = GLOBAL_OPTIONS_MARKER_PREFIX;
|
|
1856
2096
|
exports.INDEX_MARKER_PREFIX = INDEX_MARKER_PREFIX;
|
|
2097
|
+
exports.ROOT_FOOTER_MARKER_PREFIX = ROOT_FOOTER_MARKER_PREFIX;
|
|
2098
|
+
exports.ROOT_HEADER_MARKER_PREFIX = ROOT_HEADER_MARKER_PREFIX;
|
|
1857
2099
|
exports.SECTION_MARKER_PREFIX = SECTION_MARKER_PREFIX;
|
|
1858
2100
|
exports.SECTION_TYPES = SECTION_TYPES;
|
|
1859
2101
|
exports.UPDATE_GOLDEN_ENV = UPDATE_GOLDEN_ENV;
|
|
@@ -1886,6 +2128,10 @@ exports.renderSubcommandsTable = renderSubcommandsTable;
|
|
|
1886
2128
|
exports.renderSubcommandsTableFromArray = renderSubcommandsTableFromArray;
|
|
1887
2129
|
exports.renderUsage = renderUsage;
|
|
1888
2130
|
exports.resolveLazyCommand = require_subcommand_router.resolveLazyCommand;
|
|
2131
|
+
exports.rootFooterEndMarker = rootFooterEndMarker;
|
|
2132
|
+
exports.rootFooterStartMarker = rootFooterStartMarker;
|
|
2133
|
+
exports.rootHeaderEndMarker = rootHeaderEndMarker;
|
|
2134
|
+
exports.rootHeaderStartMarker = rootHeaderStartMarker;
|
|
1889
2135
|
exports.sectionEndMarker = sectionEndMarker;
|
|
1890
2136
|
exports.sectionStartMarker = sectionStartMarker;
|
|
1891
2137
|
exports.writeFile = writeFile;
|