@optique/core 1.0.0-dev.416 → 1.0.0-dev.428
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/constructs.cjs +72 -52
- package/dist/constructs.d.cts +24 -2
- package/dist/constructs.d.ts +24 -2
- package/dist/constructs.js +73 -53
- package/dist/doc.cjs +59 -12
- package/dist/doc.js +59 -12
- package/dist/facade.cjs +7 -1
- package/dist/facade.js +7 -1
- package/dist/index.cjs +4 -0
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/message.cjs +1 -9
- package/dist/message.js +1 -9
- package/dist/modifiers.cjs +8 -8
- package/dist/modifiers.js +8 -8
- package/dist/parser.d.cts +2 -2
- package/dist/parser.d.ts +2 -2
- package/dist/primitives.cjs +18 -18
- package/dist/primitives.d.cts +36 -20
- package/dist/primitives.d.ts +36 -20
- package/dist/primitives.js +19 -19
- package/dist/usage.cjs +78 -6
- package/dist/usage.d.cts +33 -13
- package/dist/usage.d.ts +33 -13
- package/dist/usage.js +75 -7
- package/package.json +1 -1
package/dist/constructs.cjs
CHANGED
|
@@ -19,6 +19,60 @@ function createUnexpectedInputErrorWithScopedSuggestions(baseError, invalidInput
|
|
|
19
19
|
...suggestionMsg
|
|
20
20
|
] : baseError;
|
|
21
21
|
}
|
|
22
|
+
function applyHiddenToUsageTerm(term, hidden) {
|
|
23
|
+
if (hidden == null) return term;
|
|
24
|
+
if (term.type === "optional") return {
|
|
25
|
+
type: "optional",
|
|
26
|
+
terms: applyHiddenToUsage(term.terms, hidden)
|
|
27
|
+
};
|
|
28
|
+
if (term.type === "multiple") return {
|
|
29
|
+
type: "multiple",
|
|
30
|
+
terms: applyHiddenToUsage(term.terms, hidden),
|
|
31
|
+
min: term.min
|
|
32
|
+
};
|
|
33
|
+
if (term.type === "exclusive") return {
|
|
34
|
+
type: "exclusive",
|
|
35
|
+
terms: term.terms.map((u) => applyHiddenToUsage(u, hidden))
|
|
36
|
+
};
|
|
37
|
+
if (term.type === "argument" || term.type === "option" || term.type === "command" || term.type === "passthrough") return {
|
|
38
|
+
...term,
|
|
39
|
+
hidden: require_usage.mergeHidden(term.hidden, hidden)
|
|
40
|
+
};
|
|
41
|
+
return term;
|
|
42
|
+
}
|
|
43
|
+
function applyHiddenToUsage(usage, hidden) {
|
|
44
|
+
if (hidden == null) return usage;
|
|
45
|
+
return usage.map((term) => applyHiddenToUsageTerm(term, hidden));
|
|
46
|
+
}
|
|
47
|
+
function applyHiddenToDocEntry(entry, hidden) {
|
|
48
|
+
const mergedTerm = applyHiddenToUsageTerm(entry.term, hidden);
|
|
49
|
+
if ((mergedTerm.type === "argument" || mergedTerm.type === "option" || mergedTerm.type === "command" || mergedTerm.type === "passthrough") && require_usage.isDocHidden(mergedTerm.hidden)) return void 0;
|
|
50
|
+
return {
|
|
51
|
+
...entry,
|
|
52
|
+
term: mergedTerm
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function applyHiddenToDocFragments(fragments, hidden) {
|
|
56
|
+
if (hidden == null) return fragments;
|
|
57
|
+
const result = [];
|
|
58
|
+
for (const fragment of fragments) {
|
|
59
|
+
if (fragment.type === "entry") {
|
|
60
|
+
const entry = applyHiddenToDocEntry(fragment, hidden);
|
|
61
|
+
if (entry != null) result.push({
|
|
62
|
+
...entry,
|
|
63
|
+
type: "entry"
|
|
64
|
+
});
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const entries = fragment.entries.map((entry) => applyHiddenToDocEntry(entry, hidden)).filter((entry) => entry != null);
|
|
68
|
+
result.push({
|
|
69
|
+
type: "section",
|
|
70
|
+
title: fragment.title,
|
|
71
|
+
entries
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
22
76
|
/**
|
|
23
77
|
* Checks if the given token is an option name that requires a value
|
|
24
78
|
* (i.e., has a metavar) within the given usage terms.
|
|
@@ -919,7 +973,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
|
|
|
919
973
|
$valueType: [],
|
|
920
974
|
$stateType: [],
|
|
921
975
|
priority: Math.max(...parserKeys.map((k) => parsers[k].priority)),
|
|
922
|
-
usage: parserPairs.flatMap(([_, p]) => p.usage),
|
|
976
|
+
usage: applyHiddenToUsage(parserPairs.flatMap(([_, p]) => p.usage), options.hidden),
|
|
923
977
|
initialState,
|
|
924
978
|
parse(context) {
|
|
925
979
|
return require_mode_dispatch.dispatchByMode(combinedMode, () => parseSync(context), () => parseAsync(context));
|
|
@@ -1028,6 +1082,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
|
|
|
1028
1082
|
});
|
|
1029
1083
|
},
|
|
1030
1084
|
suggest(context, prefix) {
|
|
1085
|
+
if (options.hidden === true) return require_mode_dispatch.dispatchIterableByMode(combinedMode, function* () {}, async function* () {});
|
|
1031
1086
|
return require_mode_dispatch.dispatchIterableByMode(combinedMode, () => {
|
|
1032
1087
|
const syncParserPairs = parserPairs;
|
|
1033
1088
|
return suggestObjectSync(context, prefix, syncParserPairs);
|
|
@@ -1041,9 +1096,10 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
|
|
|
1041
1096
|
};
|
|
1042
1097
|
return p.getDocFragments(fieldState, defaultValue?.[field]).fragments;
|
|
1043
1098
|
});
|
|
1044
|
-
const
|
|
1099
|
+
const hiddenAwareFragments = applyHiddenToDocFragments(fragments, options.hidden);
|
|
1100
|
+
const entries = hiddenAwareFragments.filter((d) => d.type === "entry");
|
|
1045
1101
|
const sections = [];
|
|
1046
|
-
for (const fragment of
|
|
1102
|
+
for (const fragment of hiddenAwareFragments) {
|
|
1047
1103
|
if (fragment.type !== "section") continue;
|
|
1048
1104
|
if (fragment.title == null) entries.push(...fragment.entries);
|
|
1049
1105
|
else sections.push(fragment);
|
|
@@ -1518,7 +1574,7 @@ function merge(...args) {
|
|
|
1518
1574
|
$valueType: [],
|
|
1519
1575
|
$stateType: [],
|
|
1520
1576
|
priority: Math.max(...parsers.map((p) => p.priority)),
|
|
1521
|
-
usage: parsers.flatMap((p) => p.usage),
|
|
1577
|
+
usage: applyHiddenToUsage(parsers.flatMap((p) => p.usage), options.hidden),
|
|
1522
1578
|
initialState,
|
|
1523
1579
|
parse(context) {
|
|
1524
1580
|
if (isAsync) return parseAsync(context);
|
|
@@ -1572,6 +1628,7 @@ function merge(...args) {
|
|
|
1572
1628
|
})();
|
|
1573
1629
|
},
|
|
1574
1630
|
suggest(context, prefix) {
|
|
1631
|
+
if (options.hidden === true) return require_mode_dispatch.dispatchIterableByMode(combinedMode, function* () {}, async function* () {});
|
|
1575
1632
|
const extractState = (p, i) => {
|
|
1576
1633
|
if (p.initialState === void 0) {
|
|
1577
1634
|
const key = `__parser_${i}`;
|
|
@@ -1638,9 +1695,10 @@ function merge(...args) {
|
|
|
1638
1695
|
footer ??= docFragments.footer;
|
|
1639
1696
|
return docFragments.fragments;
|
|
1640
1697
|
});
|
|
1641
|
-
const
|
|
1698
|
+
const hiddenAwareFragments = applyHiddenToDocFragments(fragments, options.hidden);
|
|
1699
|
+
const entries = hiddenAwareFragments.filter((f) => f.type === "entry");
|
|
1642
1700
|
const sections = [];
|
|
1643
|
-
for (const fragment of
|
|
1701
|
+
for (const fragment of hiddenAwareFragments) {
|
|
1644
1702
|
if (fragment.type !== "section") continue;
|
|
1645
1703
|
if (fragment.title == null) entries.push(...fragment.entries);
|
|
1646
1704
|
else sections.push(fragment);
|
|
@@ -1915,64 +1973,26 @@ function concat(...parsers) {
|
|
|
1915
1973
|
}
|
|
1916
1974
|
};
|
|
1917
1975
|
}
|
|
1918
|
-
|
|
1919
|
-
* Wraps a parser with a group label for documentation purposes.
|
|
1920
|
-
*
|
|
1921
|
-
* The `group()` function is a documentation-only wrapper that applies a label
|
|
1922
|
-
* to any parser for help text organization. This allows you to use clean code
|
|
1923
|
-
* structure with combinators like {@link merge} while maintaining well-organized
|
|
1924
|
-
* help text through group labeling.
|
|
1925
|
-
*
|
|
1926
|
-
* The wrapped parser has identical parsing behavior but generates documentation
|
|
1927
|
-
* fragments wrapped in a labeled section. This is particularly useful when
|
|
1928
|
-
* combining parsers using {@link merge}—you can wrap the merged result with
|
|
1929
|
-
* `group()` to add a section header in help output.
|
|
1930
|
-
*
|
|
1931
|
-
* @example
|
|
1932
|
-
* ```typescript
|
|
1933
|
-
* const apiOptions = merge(
|
|
1934
|
-
* object({ endpoint: option("--endpoint", string()) }),
|
|
1935
|
-
* object({ timeout: option("--timeout", integer()) })
|
|
1936
|
-
* );
|
|
1937
|
-
*
|
|
1938
|
-
* const groupedApiOptions = group("API Options", apiOptions);
|
|
1939
|
-
* // Now produces a labeled "API Options" section in help text
|
|
1940
|
-
* ```
|
|
1941
|
-
*
|
|
1942
|
-
* @example
|
|
1943
|
-
* ```typescript
|
|
1944
|
-
* // Can be used with any parser, not just merge()
|
|
1945
|
-
* const verboseGroup = group("Verbosity", object({
|
|
1946
|
-
* verbose: option("-v", "--verbose"),
|
|
1947
|
-
* quiet: option("-q", "--quiet")
|
|
1948
|
-
* }));
|
|
1949
|
-
* ```
|
|
1950
|
-
*
|
|
1951
|
-
* @template TValue The value type of the wrapped parser.
|
|
1952
|
-
* @template TState The state type of the wrapped parser.
|
|
1953
|
-
* @param label A descriptive label for this parser group, used for
|
|
1954
|
-
* documentation and help text organization.
|
|
1955
|
-
* @param parser The parser to wrap with a group label.
|
|
1956
|
-
* @returns A new parser that behaves identically to the input parser
|
|
1957
|
-
* but generates documentation within a labeled section.
|
|
1958
|
-
* @since 0.4.0
|
|
1959
|
-
*/
|
|
1960
|
-
function group(label, parser) {
|
|
1976
|
+
function group(label, parser, options = {}) {
|
|
1961
1977
|
return {
|
|
1962
1978
|
$mode: parser.$mode,
|
|
1963
1979
|
$valueType: parser.$valueType,
|
|
1964
1980
|
$stateType: parser.$stateType,
|
|
1965
1981
|
priority: parser.priority,
|
|
1966
|
-
usage: parser.usage,
|
|
1982
|
+
usage: applyHiddenToUsage(parser.usage, options.hidden),
|
|
1967
1983
|
initialState: parser.initialState,
|
|
1968
1984
|
parse: (context) => parser.parse(context),
|
|
1969
1985
|
complete: (state) => parser.complete(state),
|
|
1970
|
-
suggest: (context, prefix) =>
|
|
1986
|
+
suggest: (context, prefix) => {
|
|
1987
|
+
if (options.hidden === true) return require_mode_dispatch.dispatchIterableByMode(parser.$mode, function* () {}, async function* () {});
|
|
1988
|
+
return parser.suggest(context, prefix);
|
|
1989
|
+
},
|
|
1971
1990
|
getDocFragments: (state, defaultValue) => {
|
|
1972
1991
|
const { brief, description, footer, fragments } = parser.getDocFragments(state, defaultValue);
|
|
1992
|
+
const hiddenAwareFragments = applyHiddenToDocFragments(fragments, options.hidden);
|
|
1973
1993
|
const allEntries = [];
|
|
1974
1994
|
const titledSections = [];
|
|
1975
|
-
for (const fragment of
|
|
1995
|
+
for (const fragment of hiddenAwareFragments) if (fragment.type === "entry") allEntries.push(fragment);
|
|
1976
1996
|
else if (fragment.type === "section") if (fragment.title) titledSections.push(fragment);
|
|
1977
1997
|
else allEntries.push(...fragment.entries);
|
|
1978
1998
|
const initialFragments = parser.getDocFragments({
|
package/dist/constructs.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Message } from "./message.cjs";
|
|
2
|
+
import { HiddenVisibility } from "./usage.cjs";
|
|
2
3
|
import { CombineModes, InferValue, Mode, Parser, ParserResult } from "./parser.cjs";
|
|
3
4
|
|
|
4
5
|
//#region src/constructs.d.ts
|
|
@@ -626,6 +627,11 @@ interface ObjectOptions {
|
|
|
626
627
|
* @since 0.7.0
|
|
627
628
|
*/
|
|
628
629
|
readonly allowDuplicates?: boolean;
|
|
630
|
+
/**
|
|
631
|
+
* Controls visibility of all terms emitted by this object parser.
|
|
632
|
+
* @since 1.0.0
|
|
633
|
+
*/
|
|
634
|
+
readonly hidden?: HiddenVisibility;
|
|
629
635
|
}
|
|
630
636
|
/**
|
|
631
637
|
* Options for customizing error messages in the {@link object} parser.
|
|
@@ -799,6 +805,11 @@ interface MergeOptions {
|
|
|
799
805
|
* @since 0.7.0
|
|
800
806
|
*/
|
|
801
807
|
readonly allowDuplicates?: boolean;
|
|
808
|
+
/**
|
|
809
|
+
* Controls visibility of all terms emitted by this merged parser.
|
|
810
|
+
* @since 1.0.0
|
|
811
|
+
*/
|
|
812
|
+
readonly hidden?: HiddenVisibility;
|
|
802
813
|
}
|
|
803
814
|
/**
|
|
804
815
|
* Merges multiple {@link object} parsers into a single {@link object} parser.
|
|
@@ -1387,11 +1398,22 @@ declare function concat<MA extends Mode, MB extends Mode, MC extends Mode, MD ex
|
|
|
1387
1398
|
* @param label A descriptive label for this parser group, used for
|
|
1388
1399
|
* documentation and help text organization.
|
|
1389
1400
|
* @param parser The parser to wrap with a group label.
|
|
1401
|
+
* @param options Optional visibility controls for the wrapped parser terms.
|
|
1390
1402
|
* @returns A new parser that behaves identically to the input parser
|
|
1391
1403
|
* but generates documentation within a labeled section.
|
|
1392
1404
|
* @since 0.4.0
|
|
1393
1405
|
*/
|
|
1394
|
-
|
|
1406
|
+
/**
|
|
1407
|
+
* Options for the {@link group} parser wrapper.
|
|
1408
|
+
* @since 1.0.0
|
|
1409
|
+
*/
|
|
1410
|
+
interface GroupOptions {
|
|
1411
|
+
/**
|
|
1412
|
+
* Controls visibility of all terms emitted by this group.
|
|
1413
|
+
*/
|
|
1414
|
+
readonly hidden?: HiddenVisibility;
|
|
1415
|
+
}
|
|
1416
|
+
declare function group<M extends Mode, TValue, TState>(label: string, parser: Parser<M, TValue, TState>, options?: GroupOptions): Parser<M, TValue, TState>;
|
|
1395
1417
|
/**
|
|
1396
1418
|
* Tagged union type representing which branch is selected.
|
|
1397
1419
|
* Uses tagged union to avoid collision with discriminator values.
|
|
@@ -1476,4 +1498,4 @@ declare function conditional<TDiscriminator extends string, TBranches extends {
|
|
|
1476
1498
|
*/
|
|
1477
1499
|
declare function conditional<TDiscriminator extends string, TBranches extends { [K in TDiscriminator]: Parser<Mode, unknown, unknown> }, TDefault extends Parser<Mode, unknown, unknown>, TD extends Parser<Mode, TDiscriminator, unknown>>(discriminator: TD, branches: TBranches, defaultBranch: TDefault, options?: ConditionalOptions): Parser<CombineModes<readonly [ExtractMode<TD>, ExtractMode<TDefault>, ...{ [K in keyof TBranches]: ExtractMode<TBranches[K]> }[keyof TBranches][]]>, ConditionalResultWithDefault<TDiscriminator, TBranches, TDefault>, ConditionalState<TDiscriminator>>;
|
|
1478
1500
|
//#endregion
|
|
1479
|
-
export { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple };
|
|
1501
|
+
export { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, GroupOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple };
|
package/dist/constructs.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Message } from "./message.js";
|
|
2
|
+
import { HiddenVisibility } from "./usage.js";
|
|
2
3
|
import { CombineModes, InferValue, Mode, Parser, ParserResult } from "./parser.js";
|
|
3
4
|
|
|
4
5
|
//#region src/constructs.d.ts
|
|
@@ -626,6 +627,11 @@ interface ObjectOptions {
|
|
|
626
627
|
* @since 0.7.0
|
|
627
628
|
*/
|
|
628
629
|
readonly allowDuplicates?: boolean;
|
|
630
|
+
/**
|
|
631
|
+
* Controls visibility of all terms emitted by this object parser.
|
|
632
|
+
* @since 1.0.0
|
|
633
|
+
*/
|
|
634
|
+
readonly hidden?: HiddenVisibility;
|
|
629
635
|
}
|
|
630
636
|
/**
|
|
631
637
|
* Options for customizing error messages in the {@link object} parser.
|
|
@@ -799,6 +805,11 @@ interface MergeOptions {
|
|
|
799
805
|
* @since 0.7.0
|
|
800
806
|
*/
|
|
801
807
|
readonly allowDuplicates?: boolean;
|
|
808
|
+
/**
|
|
809
|
+
* Controls visibility of all terms emitted by this merged parser.
|
|
810
|
+
* @since 1.0.0
|
|
811
|
+
*/
|
|
812
|
+
readonly hidden?: HiddenVisibility;
|
|
802
813
|
}
|
|
803
814
|
/**
|
|
804
815
|
* Merges multiple {@link object} parsers into a single {@link object} parser.
|
|
@@ -1387,11 +1398,22 @@ declare function concat<MA extends Mode, MB extends Mode, MC extends Mode, MD ex
|
|
|
1387
1398
|
* @param label A descriptive label for this parser group, used for
|
|
1388
1399
|
* documentation and help text organization.
|
|
1389
1400
|
* @param parser The parser to wrap with a group label.
|
|
1401
|
+
* @param options Optional visibility controls for the wrapped parser terms.
|
|
1390
1402
|
* @returns A new parser that behaves identically to the input parser
|
|
1391
1403
|
* but generates documentation within a labeled section.
|
|
1392
1404
|
* @since 0.4.0
|
|
1393
1405
|
*/
|
|
1394
|
-
|
|
1406
|
+
/**
|
|
1407
|
+
* Options for the {@link group} parser wrapper.
|
|
1408
|
+
* @since 1.0.0
|
|
1409
|
+
*/
|
|
1410
|
+
interface GroupOptions {
|
|
1411
|
+
/**
|
|
1412
|
+
* Controls visibility of all terms emitted by this group.
|
|
1413
|
+
*/
|
|
1414
|
+
readonly hidden?: HiddenVisibility;
|
|
1415
|
+
}
|
|
1416
|
+
declare function group<M extends Mode, TValue, TState>(label: string, parser: Parser<M, TValue, TState>, options?: GroupOptions): Parser<M, TValue, TState>;
|
|
1395
1417
|
/**
|
|
1396
1418
|
* Tagged union type representing which branch is selected.
|
|
1397
1419
|
* Uses tagged union to avoid collision with discriminator values.
|
|
@@ -1476,4 +1498,4 @@ declare function conditional<TDiscriminator extends string, TBranches extends {
|
|
|
1476
1498
|
*/
|
|
1477
1499
|
declare function conditional<TDiscriminator extends string, TBranches extends { [K in TDiscriminator]: Parser<Mode, unknown, unknown> }, TDefault extends Parser<Mode, unknown, unknown>, TD extends Parser<Mode, TDiscriminator, unknown>>(discriminator: TD, branches: TBranches, defaultBranch: TDefault, options?: ConditionalOptions): Parser<CombineModes<readonly [ExtractMode<TD>, ExtractMode<TDefault>, ...{ [K in keyof TBranches]: ExtractMode<TBranches[K]> }[keyof TBranches][]]>, ConditionalResultWithDefault<TDiscriminator, TBranches, TDefault>, ConditionalState<TDiscriminator>>;
|
|
1478
1500
|
//#endregion
|
|
1479
|
-
export { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple };
|
|
1501
|
+
export { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, GroupOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple };
|
package/dist/constructs.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { message, optionName, text, values } from "./message.js";
|
|
2
2
|
import { DependencyRegistry, dependencyId, isDeferredParseState, isDependencySourceState, isPendingDependencySourceState, isWrappedDependencySource, parseWithDependency, wrappedDependencySourceMarker } from "./dependency.js";
|
|
3
3
|
import { dispatchByMode, dispatchIterableByMode } from "./mode-dispatch.js";
|
|
4
|
-
import { extractArgumentMetavars, extractCommandNames, extractOptionNames } from "./usage.js";
|
|
4
|
+
import { extractArgumentMetavars, extractCommandNames, extractOptionNames, isDocHidden, mergeHidden } from "./usage.js";
|
|
5
5
|
import { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggestionMessage, deduplicateSuggestions, findSimilar } from "./suggestion.js";
|
|
6
6
|
import { collectLeadingCandidates } from "./usage-internals.js";
|
|
7
7
|
|
|
@@ -19,6 +19,60 @@ function createUnexpectedInputErrorWithScopedSuggestions(baseError, invalidInput
|
|
|
19
19
|
...suggestionMsg
|
|
20
20
|
] : baseError;
|
|
21
21
|
}
|
|
22
|
+
function applyHiddenToUsageTerm(term, hidden) {
|
|
23
|
+
if (hidden == null) return term;
|
|
24
|
+
if (term.type === "optional") return {
|
|
25
|
+
type: "optional",
|
|
26
|
+
terms: applyHiddenToUsage(term.terms, hidden)
|
|
27
|
+
};
|
|
28
|
+
if (term.type === "multiple") return {
|
|
29
|
+
type: "multiple",
|
|
30
|
+
terms: applyHiddenToUsage(term.terms, hidden),
|
|
31
|
+
min: term.min
|
|
32
|
+
};
|
|
33
|
+
if (term.type === "exclusive") return {
|
|
34
|
+
type: "exclusive",
|
|
35
|
+
terms: term.terms.map((u) => applyHiddenToUsage(u, hidden))
|
|
36
|
+
};
|
|
37
|
+
if (term.type === "argument" || term.type === "option" || term.type === "command" || term.type === "passthrough") return {
|
|
38
|
+
...term,
|
|
39
|
+
hidden: mergeHidden(term.hidden, hidden)
|
|
40
|
+
};
|
|
41
|
+
return term;
|
|
42
|
+
}
|
|
43
|
+
function applyHiddenToUsage(usage, hidden) {
|
|
44
|
+
if (hidden == null) return usage;
|
|
45
|
+
return usage.map((term) => applyHiddenToUsageTerm(term, hidden));
|
|
46
|
+
}
|
|
47
|
+
function applyHiddenToDocEntry(entry, hidden) {
|
|
48
|
+
const mergedTerm = applyHiddenToUsageTerm(entry.term, hidden);
|
|
49
|
+
if ((mergedTerm.type === "argument" || mergedTerm.type === "option" || mergedTerm.type === "command" || mergedTerm.type === "passthrough") && isDocHidden(mergedTerm.hidden)) return void 0;
|
|
50
|
+
return {
|
|
51
|
+
...entry,
|
|
52
|
+
term: mergedTerm
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function applyHiddenToDocFragments(fragments, hidden) {
|
|
56
|
+
if (hidden == null) return fragments;
|
|
57
|
+
const result = [];
|
|
58
|
+
for (const fragment of fragments) {
|
|
59
|
+
if (fragment.type === "entry") {
|
|
60
|
+
const entry = applyHiddenToDocEntry(fragment, hidden);
|
|
61
|
+
if (entry != null) result.push({
|
|
62
|
+
...entry,
|
|
63
|
+
type: "entry"
|
|
64
|
+
});
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const entries = fragment.entries.map((entry) => applyHiddenToDocEntry(entry, hidden)).filter((entry) => entry != null);
|
|
68
|
+
result.push({
|
|
69
|
+
type: "section",
|
|
70
|
+
title: fragment.title,
|
|
71
|
+
entries
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
22
76
|
/**
|
|
23
77
|
* Checks if the given token is an option name that requires a value
|
|
24
78
|
* (i.e., has a metavar) within the given usage terms.
|
|
@@ -919,7 +973,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
|
|
|
919
973
|
$valueType: [],
|
|
920
974
|
$stateType: [],
|
|
921
975
|
priority: Math.max(...parserKeys.map((k) => parsers[k].priority)),
|
|
922
|
-
usage: parserPairs.flatMap(([_, p]) => p.usage),
|
|
976
|
+
usage: applyHiddenToUsage(parserPairs.flatMap(([_, p]) => p.usage), options.hidden),
|
|
923
977
|
initialState,
|
|
924
978
|
parse(context) {
|
|
925
979
|
return dispatchByMode(combinedMode, () => parseSync(context), () => parseAsync(context));
|
|
@@ -1028,6 +1082,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
|
|
|
1028
1082
|
});
|
|
1029
1083
|
},
|
|
1030
1084
|
suggest(context, prefix) {
|
|
1085
|
+
if (options.hidden === true) return dispatchIterableByMode(combinedMode, function* () {}, async function* () {});
|
|
1031
1086
|
return dispatchIterableByMode(combinedMode, () => {
|
|
1032
1087
|
const syncParserPairs = parserPairs;
|
|
1033
1088
|
return suggestObjectSync(context, prefix, syncParserPairs);
|
|
@@ -1041,9 +1096,10 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
|
|
|
1041
1096
|
};
|
|
1042
1097
|
return p.getDocFragments(fieldState, defaultValue?.[field]).fragments;
|
|
1043
1098
|
});
|
|
1044
|
-
const
|
|
1099
|
+
const hiddenAwareFragments = applyHiddenToDocFragments(fragments, options.hidden);
|
|
1100
|
+
const entries = hiddenAwareFragments.filter((d) => d.type === "entry");
|
|
1045
1101
|
const sections = [];
|
|
1046
|
-
for (const fragment of
|
|
1102
|
+
for (const fragment of hiddenAwareFragments) {
|
|
1047
1103
|
if (fragment.type !== "section") continue;
|
|
1048
1104
|
if (fragment.title == null) entries.push(...fragment.entries);
|
|
1049
1105
|
else sections.push(fragment);
|
|
@@ -1518,7 +1574,7 @@ function merge(...args) {
|
|
|
1518
1574
|
$valueType: [],
|
|
1519
1575
|
$stateType: [],
|
|
1520
1576
|
priority: Math.max(...parsers.map((p) => p.priority)),
|
|
1521
|
-
usage: parsers.flatMap((p) => p.usage),
|
|
1577
|
+
usage: applyHiddenToUsage(parsers.flatMap((p) => p.usage), options.hidden),
|
|
1522
1578
|
initialState,
|
|
1523
1579
|
parse(context) {
|
|
1524
1580
|
if (isAsync) return parseAsync(context);
|
|
@@ -1572,6 +1628,7 @@ function merge(...args) {
|
|
|
1572
1628
|
})();
|
|
1573
1629
|
},
|
|
1574
1630
|
suggest(context, prefix) {
|
|
1631
|
+
if (options.hidden === true) return dispatchIterableByMode(combinedMode, function* () {}, async function* () {});
|
|
1575
1632
|
const extractState = (p, i) => {
|
|
1576
1633
|
if (p.initialState === void 0) {
|
|
1577
1634
|
const key = `__parser_${i}`;
|
|
@@ -1638,9 +1695,10 @@ function merge(...args) {
|
|
|
1638
1695
|
footer ??= docFragments.footer;
|
|
1639
1696
|
return docFragments.fragments;
|
|
1640
1697
|
});
|
|
1641
|
-
const
|
|
1698
|
+
const hiddenAwareFragments = applyHiddenToDocFragments(fragments, options.hidden);
|
|
1699
|
+
const entries = hiddenAwareFragments.filter((f) => f.type === "entry");
|
|
1642
1700
|
const sections = [];
|
|
1643
|
-
for (const fragment of
|
|
1701
|
+
for (const fragment of hiddenAwareFragments) {
|
|
1644
1702
|
if (fragment.type !== "section") continue;
|
|
1645
1703
|
if (fragment.title == null) entries.push(...fragment.entries);
|
|
1646
1704
|
else sections.push(fragment);
|
|
@@ -1915,64 +1973,26 @@ function concat(...parsers) {
|
|
|
1915
1973
|
}
|
|
1916
1974
|
};
|
|
1917
1975
|
}
|
|
1918
|
-
|
|
1919
|
-
* Wraps a parser with a group label for documentation purposes.
|
|
1920
|
-
*
|
|
1921
|
-
* The `group()` function is a documentation-only wrapper that applies a label
|
|
1922
|
-
* to any parser for help text organization. This allows you to use clean code
|
|
1923
|
-
* structure with combinators like {@link merge} while maintaining well-organized
|
|
1924
|
-
* help text through group labeling.
|
|
1925
|
-
*
|
|
1926
|
-
* The wrapped parser has identical parsing behavior but generates documentation
|
|
1927
|
-
* fragments wrapped in a labeled section. This is particularly useful when
|
|
1928
|
-
* combining parsers using {@link merge}—you can wrap the merged result with
|
|
1929
|
-
* `group()` to add a section header in help output.
|
|
1930
|
-
*
|
|
1931
|
-
* @example
|
|
1932
|
-
* ```typescript
|
|
1933
|
-
* const apiOptions = merge(
|
|
1934
|
-
* object({ endpoint: option("--endpoint", string()) }),
|
|
1935
|
-
* object({ timeout: option("--timeout", integer()) })
|
|
1936
|
-
* );
|
|
1937
|
-
*
|
|
1938
|
-
* const groupedApiOptions = group("API Options", apiOptions);
|
|
1939
|
-
* // Now produces a labeled "API Options" section in help text
|
|
1940
|
-
* ```
|
|
1941
|
-
*
|
|
1942
|
-
* @example
|
|
1943
|
-
* ```typescript
|
|
1944
|
-
* // Can be used with any parser, not just merge()
|
|
1945
|
-
* const verboseGroup = group("Verbosity", object({
|
|
1946
|
-
* verbose: option("-v", "--verbose"),
|
|
1947
|
-
* quiet: option("-q", "--quiet")
|
|
1948
|
-
* }));
|
|
1949
|
-
* ```
|
|
1950
|
-
*
|
|
1951
|
-
* @template TValue The value type of the wrapped parser.
|
|
1952
|
-
* @template TState The state type of the wrapped parser.
|
|
1953
|
-
* @param label A descriptive label for this parser group, used for
|
|
1954
|
-
* documentation and help text organization.
|
|
1955
|
-
* @param parser The parser to wrap with a group label.
|
|
1956
|
-
* @returns A new parser that behaves identically to the input parser
|
|
1957
|
-
* but generates documentation within a labeled section.
|
|
1958
|
-
* @since 0.4.0
|
|
1959
|
-
*/
|
|
1960
|
-
function group(label, parser) {
|
|
1976
|
+
function group(label, parser, options = {}) {
|
|
1961
1977
|
return {
|
|
1962
1978
|
$mode: parser.$mode,
|
|
1963
1979
|
$valueType: parser.$valueType,
|
|
1964
1980
|
$stateType: parser.$stateType,
|
|
1965
1981
|
priority: parser.priority,
|
|
1966
|
-
usage: parser.usage,
|
|
1982
|
+
usage: applyHiddenToUsage(parser.usage, options.hidden),
|
|
1967
1983
|
initialState: parser.initialState,
|
|
1968
1984
|
parse: (context) => parser.parse(context),
|
|
1969
1985
|
complete: (state) => parser.complete(state),
|
|
1970
|
-
suggest: (context, prefix) =>
|
|
1986
|
+
suggest: (context, prefix) => {
|
|
1987
|
+
if (options.hidden === true) return dispatchIterableByMode(parser.$mode, function* () {}, async function* () {});
|
|
1988
|
+
return parser.suggest(context, prefix);
|
|
1989
|
+
},
|
|
1971
1990
|
getDocFragments: (state, defaultValue) => {
|
|
1972
1991
|
const { brief, description, footer, fragments } = parser.getDocFragments(state, defaultValue);
|
|
1992
|
+
const hiddenAwareFragments = applyHiddenToDocFragments(fragments, options.hidden);
|
|
1973
1993
|
const allEntries = [];
|
|
1974
1994
|
const titledSections = [];
|
|
1975
|
-
for (const fragment of
|
|
1995
|
+
for (const fragment of hiddenAwareFragments) if (fragment.type === "entry") allEntries.push(fragment);
|
|
1976
1996
|
else if (fragment.type === "section") if (fragment.title) titledSections.push(fragment);
|
|
1977
1997
|
else allEntries.push(...fragment.entries);
|
|
1978
1998
|
const initialFragments = parser.getDocFragments({
|
package/dist/doc.cjs
CHANGED
|
@@ -17,12 +17,22 @@ function classifySection(section) {
|
|
|
17
17
|
return 2;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
+
* Scores a section for the default smart sort. Untitled sections receive
|
|
21
|
+
* a bonus of `-1` so that the main (untitled) section appears before titled
|
|
22
|
+
* sections of a similar classification.
|
|
23
|
+
*/
|
|
24
|
+
function scoreSection(section) {
|
|
25
|
+
return classifySection(section) + (section.title == null ? -1 : 0);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
20
28
|
* The default section comparator: command-only sections come first, then
|
|
21
|
-
* mixed sections, then option/argument-only sections.
|
|
29
|
+
* mixed sections, then option/argument-only sections. Untitled sections
|
|
30
|
+
* receive a slight priority boost so the main (untitled) section appears
|
|
31
|
+
* before titled sections of a similar classification. Sections with the
|
|
22
32
|
* same score preserve their original relative order (stable sort).
|
|
23
33
|
*/
|
|
24
34
|
function defaultSectionOrder(a, b) {
|
|
25
|
-
return
|
|
35
|
+
return scoreSection(a) - scoreSection(b);
|
|
26
36
|
}
|
|
27
37
|
/**
|
|
28
38
|
* Formats a documentation page into a human-readable string.
|
|
@@ -109,18 +119,37 @@ function formatDocPage(programName, page, options = {}) {
|
|
|
109
119
|
optionsSeparator: ", ",
|
|
110
120
|
maxWidth: options.maxWidth == null ? void 0 : options.maxWidth - termIndent
|
|
111
121
|
});
|
|
112
|
-
|
|
122
|
+
const descColumnWidth = options.maxWidth == null ? void 0 : options.maxWidth - termIndent - termWidth - 2;
|
|
123
|
+
const termVisibleWidth = lastLineVisibleLength(term);
|
|
124
|
+
const extraTermOffset = descColumnWidth != null ? Math.max(0, termVisibleWidth - termWidth) : 0;
|
|
125
|
+
const currentExtraOffset = () => description.includes("\n") ? 0 : extraTermOffset;
|
|
126
|
+
const descFormatOptions = {
|
|
113
127
|
colors: options.colors,
|
|
114
128
|
quotes: !options.colors,
|
|
115
|
-
maxWidth:
|
|
116
|
-
|
|
129
|
+
maxWidth: descColumnWidth,
|
|
130
|
+
startWidth: extraTermOffset > 0 ? extraTermOffset : void 0
|
|
131
|
+
};
|
|
132
|
+
let description = entry.description == null ? "" : require_message.formatMessage(entry.description, descFormatOptions);
|
|
117
133
|
if (options.showDefault && entry.default != null) {
|
|
118
134
|
const prefix = typeof options.showDefault === "object" ? options.showDefault.prefix ?? " [" : " [";
|
|
119
135
|
const suffix = typeof options.showDefault === "object" ? options.showDefault.suffix ?? "]" : "]";
|
|
120
|
-
|
|
136
|
+
let defaultStartWidth;
|
|
137
|
+
if (descColumnWidth != null) {
|
|
138
|
+
const lastW = lastLineVisibleLength(description);
|
|
139
|
+
const effectiveLastW = lastW + currentExtraOffset();
|
|
140
|
+
if (effectiveLastW + prefix.length >= descColumnWidth) {
|
|
141
|
+
description += "\n";
|
|
142
|
+
defaultStartWidth = prefix.length;
|
|
143
|
+
} else defaultStartWidth = effectiveLastW + prefix.length;
|
|
144
|
+
}
|
|
145
|
+
const defaultFormatOptions = {
|
|
121
146
|
colors: options.colors ? { resetSuffix: "\x1B[2m" } : false,
|
|
122
|
-
quotes: !options.colors
|
|
123
|
-
|
|
147
|
+
quotes: !options.colors,
|
|
148
|
+
maxWidth: descColumnWidth == null ? void 0 : descColumnWidth - suffix.length,
|
|
149
|
+
startWidth: defaultStartWidth
|
|
150
|
+
};
|
|
151
|
+
const defaultContent = require_message.formatMessage(entry.default, defaultFormatOptions);
|
|
152
|
+
const defaultText = `${prefix}${defaultContent}${suffix}`;
|
|
124
153
|
const formattedDefault = options.colors ? `\x1b[2m${defaultText}\x1b[0m` : defaultText;
|
|
125
154
|
description += formattedDefault;
|
|
126
155
|
}
|
|
@@ -145,10 +174,23 @@ function formatDocPage(programName, page, options = {}) {
|
|
|
145
174
|
}
|
|
146
175
|
if (truncated) truncatedTerms = [...terms.slice(0, cutIndex), require_message.text(", ...")];
|
|
147
176
|
}
|
|
148
|
-
|
|
177
|
+
let choicesStartWidth;
|
|
178
|
+
if (descColumnWidth != null) {
|
|
179
|
+
const lastW = lastLineVisibleLength(description);
|
|
180
|
+
const effectiveLastW = lastW + currentExtraOffset();
|
|
181
|
+
const prefixLabelLen = prefix.length + label.length;
|
|
182
|
+
if (effectiveLastW + prefixLabelLen >= descColumnWidth) {
|
|
183
|
+
description += "\n";
|
|
184
|
+
choicesStartWidth = prefixLabelLen;
|
|
185
|
+
} else choicesStartWidth = effectiveLastW + prefixLabelLen;
|
|
186
|
+
}
|
|
187
|
+
const choicesFormatOptions = {
|
|
149
188
|
colors: options.colors ? { resetSuffix: "\x1B[2m" } : false,
|
|
150
|
-
quotes: false
|
|
151
|
-
|
|
189
|
+
quotes: false,
|
|
190
|
+
maxWidth: descColumnWidth == null ? void 0 : descColumnWidth - suffix.length,
|
|
191
|
+
startWidth: choicesStartWidth
|
|
192
|
+
};
|
|
193
|
+
const choicesDisplay = require_message.formatMessage(truncatedTerms, choicesFormatOptions);
|
|
152
194
|
const choicesText = `${prefix}${label}${choicesDisplay}${suffix}`;
|
|
153
195
|
const formattedChoices = options.colors ? `\x1b[2m${choicesText}\x1b[0m` : choicesText;
|
|
154
196
|
description += formattedChoices;
|
|
@@ -205,12 +247,17 @@ function formatDocPage(programName, page, options = {}) {
|
|
|
205
247
|
function indentLines(text$1, indent) {
|
|
206
248
|
return text$1.split("\n").join("\n" + " ".repeat(indent));
|
|
207
249
|
}
|
|
250
|
+
const ansiEscapeCodeRegex = /\x1B\[[0-9;]*[a-zA-Z]/g;
|
|
208
251
|
function ansiAwareRightPad(text$1, length, char = " ") {
|
|
209
|
-
const ansiEscapeCodeRegex = /\x1B\[[0-9;]*[a-zA-Z]/g;
|
|
210
252
|
const strippedText = text$1.replace(ansiEscapeCodeRegex, "");
|
|
211
253
|
if (strippedText.length >= length) return text$1;
|
|
212
254
|
return text$1 + char.repeat(length - strippedText.length);
|
|
213
255
|
}
|
|
256
|
+
function lastLineVisibleLength(text$1) {
|
|
257
|
+
const lastNewline = text$1.lastIndexOf("\n");
|
|
258
|
+
const lastLine = lastNewline === -1 ? text$1 : text$1.slice(lastNewline + 1);
|
|
259
|
+
return lastLine.replace(ansiEscapeCodeRegex, "").length;
|
|
260
|
+
}
|
|
214
261
|
|
|
215
262
|
//#endregion
|
|
216
263
|
exports.formatDocPage = formatDocPage;
|