@optique/core 0.3.0-dev.39 → 0.3.0-dev.41
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/facade.cjs +32 -6
- package/dist/facade.js +33 -7
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/parser.cjs +141 -13
- package/dist/parser.d.cts +95 -5
- package/dist/parser.d.ts +95 -5
- package/dist/parser.js +141 -14
- package/package.json +1 -1
package/dist/facade.cjs
CHANGED
|
@@ -38,22 +38,48 @@ function run(parser, programName, args, options = {}) {
|
|
|
38
38
|
let { colors, maxWidth, help = "none", onHelp = () => {}, aboveError = "usage", onError = () => {
|
|
39
39
|
throw new RunError("Failed to parse command line arguments.");
|
|
40
40
|
}, stderr = console.error, stdout = console.log } = options;
|
|
41
|
+
const contextualHelpParser = require_parser.object({
|
|
42
|
+
help: require_parser.constant(true),
|
|
43
|
+
commands: require_parser.multiple(require_parser.argument(require_valueparser.string({ metavar: "COMMAND" }))),
|
|
44
|
+
__help: require_parser.flag("--help")
|
|
45
|
+
});
|
|
41
46
|
const helpCommand = require_parser.command("help", require_parser.multiple(require_parser.argument(require_valueparser.string({ metavar: "COMMAND" }))), { description: require_message.message`Show help information.` });
|
|
42
47
|
const helpOption = require_parser.option("--help", { description: require_message.message`Show help information.` });
|
|
43
|
-
const augmentedParser = help === "none" ? require_parser.object({
|
|
48
|
+
const augmentedParser = help === "none" ? parser : help === "command" ? require_parser.longestMatch(require_parser.object({
|
|
49
|
+
help: require_parser.constant(true),
|
|
50
|
+
commands: helpCommand
|
|
51
|
+
}), require_parser.object({
|
|
44
52
|
help: require_parser.constant(false),
|
|
45
53
|
result: parser
|
|
46
|
-
}) : require_parser.
|
|
54
|
+
})) : help === "option" ? require_parser.longestMatch(require_parser.object({
|
|
55
|
+
help: require_parser.constant(false),
|
|
56
|
+
result: parser
|
|
57
|
+
}), contextualHelpParser, require_parser.merge(require_parser.object({
|
|
58
|
+
help: require_parser.constant(true),
|
|
59
|
+
commands: require_parser.constant([])
|
|
60
|
+
}), helpOption)) : require_parser.longestMatch(require_parser.object({
|
|
47
61
|
help: require_parser.constant(false),
|
|
48
62
|
result: parser
|
|
49
63
|
}), require_parser.object({
|
|
50
64
|
help: require_parser.constant(true),
|
|
51
|
-
|
|
52
|
-
})
|
|
65
|
+
commands: helpCommand
|
|
66
|
+
}), contextualHelpParser, require_parser.merge(require_parser.object({
|
|
67
|
+
help: require_parser.constant(true),
|
|
68
|
+
commands: require_parser.constant([])
|
|
69
|
+
}), helpOption));
|
|
53
70
|
const result = require_parser.parse(augmentedParser, args);
|
|
54
71
|
if (result.success) {
|
|
55
|
-
|
|
56
|
-
|
|
72
|
+
const value = result.value;
|
|
73
|
+
if (help === "none") return value;
|
|
74
|
+
if (typeof value === "object" && value != null && "help" in value) {
|
|
75
|
+
const helpValue$1 = value;
|
|
76
|
+
if (!helpValue$1.help) return helpValue$1.result;
|
|
77
|
+
} else return value;
|
|
78
|
+
let commandContext = [];
|
|
79
|
+
const helpValue = value;
|
|
80
|
+
if (Array.isArray(helpValue.commands)) commandContext = helpValue.commands;
|
|
81
|
+
else if (typeof helpValue.commands === "object" && helpValue.commands != null && "length" in helpValue.commands) commandContext = helpValue.commands;
|
|
82
|
+
const doc = require_parser.getDocPage(commandContext.length < 1 ? augmentedParser : parser, commandContext);
|
|
57
83
|
if (doc != null) stdout(require_doc.formatDocPage(programName, doc, {
|
|
58
84
|
colors,
|
|
59
85
|
maxWidth
|
package/dist/facade.js
CHANGED
|
@@ -2,7 +2,7 @@ import { formatMessage, message } from "./message.js";
|
|
|
2
2
|
import { formatUsage } from "./usage.js";
|
|
3
3
|
import { formatDocPage } from "./doc.js";
|
|
4
4
|
import { string } from "./valueparser.js";
|
|
5
|
-
import { argument, command, constant, getDocPage, multiple, object, option,
|
|
5
|
+
import { argument, command, constant, flag, getDocPage, longestMatch, merge, multiple, object, option, parse } from "./parser.js";
|
|
6
6
|
|
|
7
7
|
//#region src/facade.ts
|
|
8
8
|
/**
|
|
@@ -38,22 +38,48 @@ function run(parser, programName, args, options = {}) {
|
|
|
38
38
|
let { colors, maxWidth, help = "none", onHelp = () => {}, aboveError = "usage", onError = () => {
|
|
39
39
|
throw new RunError("Failed to parse command line arguments.");
|
|
40
40
|
}, stderr = console.error, stdout = console.log } = options;
|
|
41
|
+
const contextualHelpParser = object({
|
|
42
|
+
help: constant(true),
|
|
43
|
+
commands: multiple(argument(string({ metavar: "COMMAND" }))),
|
|
44
|
+
__help: flag("--help")
|
|
45
|
+
});
|
|
41
46
|
const helpCommand = command("help", multiple(argument(string({ metavar: "COMMAND" }))), { description: message`Show help information.` });
|
|
42
47
|
const helpOption = option("--help", { description: message`Show help information.` });
|
|
43
|
-
const augmentedParser = help === "none" ? object({
|
|
48
|
+
const augmentedParser = help === "none" ? parser : help === "command" ? longestMatch(object({
|
|
49
|
+
help: constant(true),
|
|
50
|
+
commands: helpCommand
|
|
51
|
+
}), object({
|
|
44
52
|
help: constant(false),
|
|
45
53
|
result: parser
|
|
46
|
-
}) :
|
|
54
|
+
})) : help === "option" ? longestMatch(object({
|
|
55
|
+
help: constant(false),
|
|
56
|
+
result: parser
|
|
57
|
+
}), contextualHelpParser, merge(object({
|
|
58
|
+
help: constant(true),
|
|
59
|
+
commands: constant([])
|
|
60
|
+
}), helpOption)) : longestMatch(object({
|
|
47
61
|
help: constant(false),
|
|
48
62
|
result: parser
|
|
49
63
|
}), object({
|
|
50
64
|
help: constant(true),
|
|
51
|
-
|
|
52
|
-
})
|
|
65
|
+
commands: helpCommand
|
|
66
|
+
}), contextualHelpParser, merge(object({
|
|
67
|
+
help: constant(true),
|
|
68
|
+
commands: constant([])
|
|
69
|
+
}), helpOption));
|
|
53
70
|
const result = parse(augmentedParser, args);
|
|
54
71
|
if (result.success) {
|
|
55
|
-
|
|
56
|
-
|
|
72
|
+
const value = result.value;
|
|
73
|
+
if (help === "none") return value;
|
|
74
|
+
if (typeof value === "object" && value != null && "help" in value) {
|
|
75
|
+
const helpValue$1 = value;
|
|
76
|
+
if (!helpValue$1.help) return helpValue$1.result;
|
|
77
|
+
} else return value;
|
|
78
|
+
let commandContext = [];
|
|
79
|
+
const helpValue = value;
|
|
80
|
+
if (Array.isArray(helpValue.commands)) commandContext = helpValue.commands;
|
|
81
|
+
else if (typeof helpValue.commands === "object" && helpValue.commands != null && "length" in helpValue.commands) commandContext = helpValue.commands;
|
|
82
|
+
const doc = getDocPage(commandContext.length < 1 ? augmentedParser : parser, commandContext);
|
|
57
83
|
if (doc != null) stdout(formatDocPage(programName, doc, {
|
|
58
84
|
colors,
|
|
59
85
|
maxWidth
|
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ exports.getDocPage = require_parser.getDocPage;
|
|
|
21
21
|
exports.integer = require_valueparser.integer;
|
|
22
22
|
exports.isValueParser = require_valueparser.isValueParser;
|
|
23
23
|
exports.locale = require_valueparser.locale;
|
|
24
|
+
exports.longestMatch = require_parser.longestMatch;
|
|
24
25
|
exports.map = require_parser.map;
|
|
25
26
|
exports.merge = require_parser.merge;
|
|
26
27
|
exports.message = require_message.message;
|
package/dist/index.d.cts
CHANGED
|
@@ -2,6 +2,6 @@ import { Message, MessageFormatOptions, MessageTerm, formatMessage, message, met
|
|
|
2
2
|
import { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, formatUsage, formatUsageTerm, normalizeUsage } from "./usage.cjs";
|
|
3
3
|
import { DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, formatDocPage } from "./doc.cjs";
|
|
4
4
|
import { ChoiceOptions, FloatOptions, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, StringOptions, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, choice, float, integer, isValueParser, locale, string, url, uuid } from "./valueparser.cjs";
|
|
5
|
-
import { ArgumentOptions, CommandOptions, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, concat, constant, flag, getDocPage, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.cjs";
|
|
5
|
+
import { ArgumentOptions, CommandOptions, DocState, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, concat, constant, flag, getDocPage, longestMatch, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.cjs";
|
|
6
6
|
import { RunError, RunOptions, run } from "./facade.cjs";
|
|
7
|
-
export { ArgumentOptions, ChoiceOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, Message, MessageFormatOptions, MessageTerm, MultipleOptions, OptionName, OptionOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, StringOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, argument, choice, command, concat, constant, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, integer, isValueParser, locale, map, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
|
|
7
|
+
export { ArgumentOptions, ChoiceOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, Message, MessageFormatOptions, MessageTerm, MultipleOptions, OptionName, OptionOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, StringOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, argument, choice, command, concat, constant, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,6 @@ import { Message, MessageFormatOptions, MessageTerm, formatMessage, message, met
|
|
|
2
2
|
import { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, formatUsage, formatUsageTerm, normalizeUsage } from "./usage.js";
|
|
3
3
|
import { DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, formatDocPage } from "./doc.js";
|
|
4
4
|
import { ChoiceOptions, FloatOptions, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, StringOptions, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, choice, float, integer, isValueParser, locale, string, url, uuid } from "./valueparser.js";
|
|
5
|
-
import { ArgumentOptions, CommandOptions, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, concat, constant, flag, getDocPage, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.js";
|
|
5
|
+
import { ArgumentOptions, CommandOptions, DocState, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, concat, constant, flag, getDocPage, longestMatch, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.js";
|
|
6
6
|
import { RunError, RunOptions, run } from "./facade.js";
|
|
7
|
-
export { ArgumentOptions, ChoiceOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, Message, MessageFormatOptions, MessageTerm, MultipleOptions, OptionName, OptionOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, StringOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, argument, choice, command, concat, constant, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, integer, isValueParser, locale, map, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
|
|
7
|
+
export { ArgumentOptions, ChoiceOptions, CommandOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, Message, MessageFormatOptions, MessageTerm, MultipleOptions, OptionName, OptionOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, StringOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, argument, choice, command, concat, constant, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { formatMessage, message, metavar, optionName, optionNames, text, value,
|
|
|
2
2
|
import { formatUsage, formatUsageTerm, normalizeUsage } from "./usage.js";
|
|
3
3
|
import { formatDocPage } from "./doc.js";
|
|
4
4
|
import { choice, float, integer, isValueParser, locale, string, url, uuid } from "./valueparser.js";
|
|
5
|
-
import { argument, command, concat, constant, flag, getDocPage, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.js";
|
|
5
|
+
import { argument, command, concat, constant, flag, getDocPage, longestMatch, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault } from "./parser.js";
|
|
6
6
|
import { RunError, run } from "./facade.js";
|
|
7
7
|
|
|
8
|
-
export { RunError, argument, choice, command, concat, constant, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, integer, isValueParser, locale, map, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
|
|
8
|
+
export { RunError, argument, choice, command, concat, constant, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, object, option, optionName, optionNames, optional, or, parse, run, string, text, tuple, url, uuid, value, values, withDefault };
|
package/dist/parser.cjs
CHANGED
|
@@ -514,7 +514,11 @@ function optional(parser) {
|
|
|
514
514
|
return parser.complete(state[0]);
|
|
515
515
|
},
|
|
516
516
|
getDocFragments(state, defaultValue) {
|
|
517
|
-
|
|
517
|
+
const innerState = state.kind === "unavailable" ? { kind: "unavailable" } : state.state === void 0 ? { kind: "unavailable" } : {
|
|
518
|
+
kind: "available",
|
|
519
|
+
state: state.state[0]
|
|
520
|
+
};
|
|
521
|
+
return parser.getDocFragments(innerState, defaultValue);
|
|
518
522
|
}
|
|
519
523
|
};
|
|
520
524
|
}
|
|
@@ -566,7 +570,11 @@ function withDefault(parser, defaultValue) {
|
|
|
566
570
|
return parser.complete(state[0]);
|
|
567
571
|
},
|
|
568
572
|
getDocFragments(state, upperDefaultValue) {
|
|
569
|
-
|
|
573
|
+
const innerState = state.kind === "unavailable" ? { kind: "unavailable" } : state.state === void 0 ? { kind: "unavailable" } : {
|
|
574
|
+
kind: "available",
|
|
575
|
+
state: state.state[0]
|
|
576
|
+
};
|
|
577
|
+
return parser.getDocFragments(innerState, upperDefaultValue != null ? upperDefaultValue : typeof defaultValue === "function" ? defaultValue() : defaultValue);
|
|
570
578
|
}
|
|
571
579
|
};
|
|
572
580
|
}
|
|
@@ -697,7 +705,11 @@ function multiple(parser, options = {}) {
|
|
|
697
705
|
};
|
|
698
706
|
},
|
|
699
707
|
getDocFragments(state, defaultValue) {
|
|
700
|
-
|
|
708
|
+
const innerState = state.kind === "unavailable" ? { kind: "unavailable" } : state.state.length > 0 ? {
|
|
709
|
+
kind: "available",
|
|
710
|
+
state: state.state.at(-1)
|
|
711
|
+
} : { kind: "unavailable" };
|
|
712
|
+
return parser.getDocFragments(innerState, defaultValue != null && defaultValue.length > 0 ? defaultValue[0] : void 0);
|
|
701
713
|
}
|
|
702
714
|
};
|
|
703
715
|
}
|
|
@@ -788,7 +800,13 @@ function object(labelOrParsers, maybeParsers) {
|
|
|
788
800
|
};
|
|
789
801
|
},
|
|
790
802
|
getDocFragments(state, defaultValue) {
|
|
791
|
-
const fragments = parserPairs.flatMap(([field, p]) =>
|
|
803
|
+
const fragments = parserPairs.flatMap(([field, p]) => {
|
|
804
|
+
const fieldState = state.kind === "unavailable" ? { kind: "unavailable" } : {
|
|
805
|
+
kind: "available",
|
|
806
|
+
state: state.state[field]
|
|
807
|
+
};
|
|
808
|
+
return p.getDocFragments(fieldState, defaultValue?.[field]).fragments;
|
|
809
|
+
});
|
|
792
810
|
const entries = fragments.filter((d) => d.type === "entry");
|
|
793
811
|
const sections = [];
|
|
794
812
|
for (const fragment of fragments) {
|
|
@@ -892,7 +910,13 @@ function tuple(labelOrParsers, maybeParsers) {
|
|
|
892
910
|
};
|
|
893
911
|
},
|
|
894
912
|
getDocFragments(state, defaultValue) {
|
|
895
|
-
const fragments = parsers.flatMap((p, i) =>
|
|
913
|
+
const fragments = parsers.flatMap((p, i) => {
|
|
914
|
+
const indexState = state.kind === "unavailable" ? { kind: "unavailable" } : {
|
|
915
|
+
kind: "available",
|
|
916
|
+
state: state.state[i]
|
|
917
|
+
};
|
|
918
|
+
return p.getDocFragments(indexState, defaultValue?.[i]).fragments;
|
|
919
|
+
});
|
|
896
920
|
const entries = fragments.filter((d) => d.type === "entry");
|
|
897
921
|
const sections = [];
|
|
898
922
|
for (const fragment of fragments) {
|
|
@@ -976,10 +1000,14 @@ function or(...parsers) {
|
|
|
976
1000
|
getDocFragments(state, _defaultValue) {
|
|
977
1001
|
let description;
|
|
978
1002
|
let fragments;
|
|
979
|
-
if (state == null) fragments = parsers.flatMap((p) => p.getDocFragments(
|
|
1003
|
+
if (state.kind === "unavailable" || state.state == null) fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }, void 0).fragments);
|
|
980
1004
|
else {
|
|
981
|
-
const [index, parserResult] = state;
|
|
982
|
-
const
|
|
1005
|
+
const [index, parserResult] = state.state;
|
|
1006
|
+
const innerState = parserResult.success ? {
|
|
1007
|
+
kind: "available",
|
|
1008
|
+
state: parserResult.next.state
|
|
1009
|
+
} : { kind: "unavailable" };
|
|
1010
|
+
const docFragments = parsers[index].getDocFragments(innerState, void 0);
|
|
983
1011
|
description = docFragments.description;
|
|
984
1012
|
fragments = docFragments.fragments;
|
|
985
1013
|
}
|
|
@@ -1003,6 +1031,86 @@ function or(...parsers) {
|
|
|
1003
1031
|
}
|
|
1004
1032
|
};
|
|
1005
1033
|
}
|
|
1034
|
+
function longestMatch(...parsers) {
|
|
1035
|
+
return {
|
|
1036
|
+
$valueType: [],
|
|
1037
|
+
$stateType: [],
|
|
1038
|
+
priority: Math.max(...parsers.map((p) => p.priority)),
|
|
1039
|
+
usage: [{
|
|
1040
|
+
type: "exclusive",
|
|
1041
|
+
terms: parsers.map((p) => p.usage)
|
|
1042
|
+
}],
|
|
1043
|
+
initialState: void 0,
|
|
1044
|
+
complete(state) {
|
|
1045
|
+
if (state == null) return {
|
|
1046
|
+
success: false,
|
|
1047
|
+
error: require_message.message`No parser matched.`
|
|
1048
|
+
};
|
|
1049
|
+
const [i, result] = state;
|
|
1050
|
+
if (result.success) return parsers[i].complete(result.next.state);
|
|
1051
|
+
return {
|
|
1052
|
+
success: false,
|
|
1053
|
+
error: result.error
|
|
1054
|
+
};
|
|
1055
|
+
},
|
|
1056
|
+
parse(context) {
|
|
1057
|
+
let bestMatch = null;
|
|
1058
|
+
let error = {
|
|
1059
|
+
consumed: 0,
|
|
1060
|
+
error: context.buffer.length < 1 ? require_message.message`No parser matched.` : require_message.message`Unexpected option or subcommand: ${require_message.optionName(context.buffer[0])}.`
|
|
1061
|
+
};
|
|
1062
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1063
|
+
const parser = parsers[i];
|
|
1064
|
+
const result = parser.parse({
|
|
1065
|
+
...context,
|
|
1066
|
+
state: context.state == null || context.state[0] !== i || !context.state[1].success ? parser.initialState : context.state[1].next.state
|
|
1067
|
+
});
|
|
1068
|
+
if (result.success) {
|
|
1069
|
+
const consumed = context.buffer.length - result.next.buffer.length;
|
|
1070
|
+
if (bestMatch === null || consumed > bestMatch.consumed) bestMatch = {
|
|
1071
|
+
index: i,
|
|
1072
|
+
result,
|
|
1073
|
+
consumed
|
|
1074
|
+
};
|
|
1075
|
+
} else if (error.consumed < result.consumed) error = result;
|
|
1076
|
+
}
|
|
1077
|
+
if (bestMatch && bestMatch.result.success) return {
|
|
1078
|
+
success: true,
|
|
1079
|
+
next: {
|
|
1080
|
+
...context,
|
|
1081
|
+
buffer: bestMatch.result.next.buffer,
|
|
1082
|
+
optionsTerminated: bestMatch.result.next.optionsTerminated,
|
|
1083
|
+
state: [bestMatch.index, bestMatch.result]
|
|
1084
|
+
},
|
|
1085
|
+
consumed: bestMatch.result.consumed
|
|
1086
|
+
};
|
|
1087
|
+
return {
|
|
1088
|
+
...error,
|
|
1089
|
+
success: false
|
|
1090
|
+
};
|
|
1091
|
+
},
|
|
1092
|
+
getDocFragments(state, _defaultValue) {
|
|
1093
|
+
let description;
|
|
1094
|
+
let fragments;
|
|
1095
|
+
if (state.kind === "unavailable" || state.state == null) fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }).fragments);
|
|
1096
|
+
else {
|
|
1097
|
+
const [i, result] = state.state;
|
|
1098
|
+
if (result.success) {
|
|
1099
|
+
const docResult = parsers[i].getDocFragments({
|
|
1100
|
+
kind: "available",
|
|
1101
|
+
state: result.next.state
|
|
1102
|
+
});
|
|
1103
|
+
description = docResult.description;
|
|
1104
|
+
fragments = docResult.fragments;
|
|
1105
|
+
} else fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }).fragments);
|
|
1106
|
+
}
|
|
1107
|
+
return {
|
|
1108
|
+
description,
|
|
1109
|
+
fragments
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1006
1114
|
function merge(...parsers) {
|
|
1007
1115
|
parsers = parsers.toSorted((a, b) => b.priority - a.priority);
|
|
1008
1116
|
const initialState = {};
|
|
@@ -1082,7 +1190,13 @@ function merge(...parsers) {
|
|
|
1082
1190
|
};
|
|
1083
1191
|
},
|
|
1084
1192
|
getDocFragments(state, _defaultValue) {
|
|
1085
|
-
const fragments = parsers.flatMap((p) =>
|
|
1193
|
+
const fragments = parsers.flatMap((p) => {
|
|
1194
|
+
const parserState = p.initialState === void 0 ? { kind: "unavailable" } : state.kind === "unavailable" ? { kind: "unavailable" } : {
|
|
1195
|
+
kind: "available",
|
|
1196
|
+
state: state.state
|
|
1197
|
+
};
|
|
1198
|
+
return p.getDocFragments(parserState, void 0).fragments;
|
|
1199
|
+
});
|
|
1086
1200
|
const entries = fragments.filter((f) => f.type === "entry");
|
|
1087
1201
|
const sections = [];
|
|
1088
1202
|
for (const fragment of fragments) {
|
|
@@ -1183,7 +1297,13 @@ function concat(...parsers) {
|
|
|
1183
1297
|
};
|
|
1184
1298
|
},
|
|
1185
1299
|
getDocFragments(state, _defaultValue) {
|
|
1186
|
-
const fragments = parsers.flatMap((p, index) =>
|
|
1300
|
+
const fragments = parsers.flatMap((p, index) => {
|
|
1301
|
+
const indexState = state.kind === "unavailable" ? { kind: "unavailable" } : {
|
|
1302
|
+
kind: "available",
|
|
1303
|
+
state: state.state[index]
|
|
1304
|
+
};
|
|
1305
|
+
return p.getDocFragments(indexState, void 0).fragments;
|
|
1306
|
+
});
|
|
1187
1307
|
const entries = fragments.filter((f) => f.type === "entry");
|
|
1188
1308
|
const sections = [];
|
|
1189
1309
|
for (const fragment of fragments) {
|
|
@@ -1290,7 +1410,7 @@ function command(name, parser, options = {}) {
|
|
|
1290
1410
|
};
|
|
1291
1411
|
},
|
|
1292
1412
|
getDocFragments(state, defaultValue) {
|
|
1293
|
-
if (typeof state === "undefined") return {
|
|
1413
|
+
if (state.kind === "unavailable" || typeof state.state === "undefined") return {
|
|
1294
1414
|
description: options.description,
|
|
1295
1415
|
fragments: [{
|
|
1296
1416
|
type: "entry",
|
|
@@ -1301,7 +1421,11 @@ function command(name, parser, options = {}) {
|
|
|
1301
1421
|
description: options.description
|
|
1302
1422
|
}]
|
|
1303
1423
|
};
|
|
1304
|
-
const
|
|
1424
|
+
const innerState = state.state[0] === "parsing" ? {
|
|
1425
|
+
kind: "available",
|
|
1426
|
+
state: state.state[1]
|
|
1427
|
+
} : { kind: "unavailable" };
|
|
1428
|
+
const innerFragments = parser.getDocFragments(innerState, defaultValue);
|
|
1305
1429
|
return {
|
|
1306
1430
|
...innerFragments,
|
|
1307
1431
|
description: innerFragments.description ?? options.description
|
|
@@ -1398,7 +1522,10 @@ function getDocPage(parser, args = []) {
|
|
|
1398
1522
|
if (!result.success) break;
|
|
1399
1523
|
context = result.next;
|
|
1400
1524
|
} while (context.buffer.length > 0);
|
|
1401
|
-
const { description, fragments } = parser.getDocFragments(
|
|
1525
|
+
const { description, fragments } = parser.getDocFragments({
|
|
1526
|
+
kind: "available",
|
|
1527
|
+
state: context.state
|
|
1528
|
+
}, void 0);
|
|
1402
1529
|
const entries = fragments.filter((f) => f.type === "entry");
|
|
1403
1530
|
const sections = [];
|
|
1404
1531
|
for (const fragment of fragments) {
|
|
@@ -1436,6 +1563,7 @@ exports.concat = concat;
|
|
|
1436
1563
|
exports.constant = constant;
|
|
1437
1564
|
exports.flag = flag;
|
|
1438
1565
|
exports.getDocPage = getDocPage;
|
|
1566
|
+
exports.longestMatch = longestMatch;
|
|
1439
1567
|
exports.map = map;
|
|
1440
1568
|
exports.merge = merge;
|
|
1441
1569
|
exports.multiple = multiple;
|
package/dist/parser.d.cts
CHANGED
|
@@ -5,6 +5,19 @@ import { ValueParser, ValueParserResult } from "./valueparser.cjs";
|
|
|
5
5
|
|
|
6
6
|
//#region src/parser.d.ts
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Represents the state passed to getDocFragments.
|
|
10
|
+
* Can be either the actual parser state or an explicit indicator
|
|
11
|
+
* that no state is available.
|
|
12
|
+
* @template TState The type of the actual state when available.
|
|
13
|
+
* @since 0.3.0
|
|
14
|
+
*/
|
|
15
|
+
type DocState<TState> = {
|
|
16
|
+
readonly kind: "available";
|
|
17
|
+
readonly state: TState;
|
|
18
|
+
} | {
|
|
19
|
+
readonly kind: "unavailable";
|
|
20
|
+
};
|
|
8
21
|
/**
|
|
9
22
|
* Parser interface for command-line argument parsing.
|
|
10
23
|
* @template TValue The type of the value returned by the parser.
|
|
@@ -65,15 +78,14 @@ interface Parser<TValue, TState> {
|
|
|
65
78
|
/**
|
|
66
79
|
* Generates a documentation fragment for this parser, which can be used
|
|
67
80
|
* to describe the parser's usage, description, and default value.
|
|
68
|
-
* @param state The current state of the parser,
|
|
69
|
-
*
|
|
70
|
-
* the documentation.
|
|
81
|
+
* @param state The current state of the parser, wrapped in a DocState
|
|
82
|
+
* to indicate whether the actual state is available or not.
|
|
71
83
|
* @param defaultValue An optional default value that can be used
|
|
72
84
|
* to provide a default value in the documentation.
|
|
73
85
|
* @returns {@link DocFragments} object containing documentation
|
|
74
86
|
* fragments for this parser.
|
|
75
87
|
*/
|
|
76
|
-
getDocFragments(state: TState
|
|
88
|
+
getDocFragments(state: DocState<TState>, defaultValue?: TValue): DocFragments;
|
|
77
89
|
}
|
|
78
90
|
/**
|
|
79
91
|
* The context of the parser, which includes the input buffer and the state.
|
|
@@ -636,6 +648,84 @@ declare function or<TA, TB, TC, TD, TE, TF, TG, TH, TI, TStateA, TStateB, TState
|
|
|
636
648
|
* in order, returning the result of the first successful parser.
|
|
637
649
|
*/
|
|
638
650
|
declare function or<TA, TB, TC, TD, TE, TF, TG, TH, TI, TJ, TStateA, TStateB, TStateC, TStateD, TStateE, TStateF, TStateG, TStateH, TStateI, TStateJ>(a: Parser<TA, TStateA>, b: Parser<TB, TStateB>, c: Parser<TC, TStateC>, d: Parser<TD, TStateD>, e: Parser<TE, TStateE>, f: Parser<TF, TStateF>, g: Parser<TG, TStateG>, h: Parser<TH, TStateH>, i: Parser<TI, TStateI>, j: Parser<TJ, TStateJ>): Parser<TA | TB | TC | TD | TE | TF | TG | TH | TI | TJ, undefined | [0, ParserResult<TStateA>] | [1, ParserResult<TStateB>] | [2, ParserResult<TStateC>] | [3, ParserResult<TStateD>] | [4, ParserResult<TStateE>] | [5, ParserResult<TStateF>] | [6, ParserResult<TStateG>] | [7, ParserResult<TStateH>] | [8, ParserResult<TStateI>] | [9, ParserResult<TStateJ>]>;
|
|
651
|
+
/**
|
|
652
|
+
* Creates a parser that combines two mutually exclusive parsers into one,
|
|
653
|
+
* selecting the parser that consumes the most tokens.
|
|
654
|
+
* The resulting parser will try both parsers and return the result
|
|
655
|
+
* of the parser that consumed more input tokens.
|
|
656
|
+
* @template TA The type of the value returned by the first parser.
|
|
657
|
+
* @template TB The type of the value returned by the second parser.
|
|
658
|
+
* @template TStateA The type of the state used by the first parser.
|
|
659
|
+
* @template TStateB The type of the state used by the second parser.
|
|
660
|
+
* @param a The first {@link Parser} to try.
|
|
661
|
+
* @param b The second {@link Parser} to try.
|
|
662
|
+
* @returns A {@link Parser} that tries to parse using both parsers
|
|
663
|
+
* and returns the result of the parser that consumed more tokens.
|
|
664
|
+
*/
|
|
665
|
+
declare function longestMatch<TA, TB, TStateA, TStateB>(a: Parser<TA, TStateA>, b: Parser<TB, TStateB>): Parser<TA | TB, undefined | [0, ParserResult<TStateA>] | [1, ParserResult<TStateB>]>;
|
|
666
|
+
/**
|
|
667
|
+
* Creates a parser that combines three mutually exclusive parsers into one,
|
|
668
|
+
* selecting the parser that consumes the most tokens.
|
|
669
|
+
* The resulting parser will try all parsers and return the result
|
|
670
|
+
* of the parser that consumed the most input tokens.
|
|
671
|
+
* @template TA The type of the value returned by the first parser.
|
|
672
|
+
* @template TB The type of the value returned by the second parser.
|
|
673
|
+
* @template TC The type of the value returned by the third parser.
|
|
674
|
+
* @template TStateA The type of the state used by the first parser.
|
|
675
|
+
* @template TStateB The type of the state used by the second parser.
|
|
676
|
+
* @template TStateC The type of the state used by the third parser.
|
|
677
|
+
* @param a The first {@link Parser} to try.
|
|
678
|
+
* @param b The second {@link Parser} to try.
|
|
679
|
+
* @param c The third {@link Parser} to try.
|
|
680
|
+
* @returns A {@link Parser} that tries to parse using all parsers
|
|
681
|
+
* and returns the result of the parser that consumed the most tokens.
|
|
682
|
+
*/
|
|
683
|
+
declare function longestMatch<TA, TB, TC, TStateA, TStateB, TStateC>(a: Parser<TA, TStateA>, b: Parser<TB, TStateB>, c: Parser<TC, TStateC>): Parser<TA | TB | TC, undefined | [0, ParserResult<TStateA>] | [1, ParserResult<TStateB>] | [2, ParserResult<TStateC>]>;
|
|
684
|
+
/**
|
|
685
|
+
* Creates a parser that combines four mutually exclusive parsers into one,
|
|
686
|
+
* selecting the parser that consumes the most tokens.
|
|
687
|
+
* The resulting parser will try all parsers and return the result
|
|
688
|
+
* of the parser that consumed the most input tokens.
|
|
689
|
+
* @template TA The type of the value returned by the first parser.
|
|
690
|
+
* @template TB The type of the value returned by the second parser.
|
|
691
|
+
* @template TC The type of the value returned by the third parser.
|
|
692
|
+
* @template TD The type of the value returned by the fourth parser.
|
|
693
|
+
* @template TStateA The type of the state used by the first parser.
|
|
694
|
+
* @template TStateB The type of the state used by the second parser.
|
|
695
|
+
* @template TStateC The type of the state used by the third parser.
|
|
696
|
+
* @template TStateD The type of the state used by the fourth parser.
|
|
697
|
+
* @param a The first {@link Parser} to try.
|
|
698
|
+
* @param b The second {@link Parser} to try.
|
|
699
|
+
* @param c The third {@link Parser} to try.
|
|
700
|
+
* @param d The fourth {@link Parser} to try.
|
|
701
|
+
* @returns A {@link Parser} that tries to parse using all parsers
|
|
702
|
+
* and returns the result of the parser that consumed the most tokens.
|
|
703
|
+
*/
|
|
704
|
+
declare function longestMatch<TA, TB, TC, TD, TStateA, TStateB, TStateC, TStateD>(a: Parser<TA, TStateA>, b: Parser<TB, TStateB>, c: Parser<TC, TStateC>, d: Parser<TD, TStateD>): Parser<TA | TB | TC | TD, undefined | [0, ParserResult<TStateA>] | [1, ParserResult<TStateB>] | [2, ParserResult<TStateC>] | [3, ParserResult<TStateD>]>;
|
|
705
|
+
/**
|
|
706
|
+
* Creates a parser that combines five mutually exclusive parsers into one,
|
|
707
|
+
* selecting the parser that consumes the most tokens.
|
|
708
|
+
* The resulting parser will try all parsers and return the result
|
|
709
|
+
* of the parser that consumed the most input tokens.
|
|
710
|
+
* @template TA The type of the value returned by the first parser.
|
|
711
|
+
* @template TB The type of the value returned by the second parser.
|
|
712
|
+
* @template TC The type of the value returned by the third parser.
|
|
713
|
+
* @template TD The type of the value returned by the fourth parser.
|
|
714
|
+
* @template TE The type of the value returned by the fifth parser.
|
|
715
|
+
* @template TStateA The type of the state used by the first parser.
|
|
716
|
+
* @template TStateB The type of the state used by the second parser.
|
|
717
|
+
* @template TStateC The type of the state used by the third parser.
|
|
718
|
+
* @template TStateD The type of the state used by the fourth parser.
|
|
719
|
+
* @template TStateE The type of the state used by the fifth parser.
|
|
720
|
+
* @param a The first {@link Parser} to try.
|
|
721
|
+
* @param b The second {@link Parser} to try.
|
|
722
|
+
* @param c The third {@link Parser} to try.
|
|
723
|
+
* @param d The fourth {@link Parser} to try.
|
|
724
|
+
* @param e The fifth {@link Parser} to try.
|
|
725
|
+
* @returns A {@link Parser} that tries to parse using all parsers
|
|
726
|
+
* and returns the result of the parser that consumed the most tokens.
|
|
727
|
+
*/
|
|
728
|
+
declare function longestMatch<TA, TB, TC, TD, TE, TStateA, TStateB, TStateC, TStateD, TStateE>(a: Parser<TA, TStateA>, b: Parser<TB, TStateB>, c: Parser<TC, TStateC>, d: Parser<TD, TStateD>, e: Parser<TE, TStateE>): Parser<TA | TB | TC | TD | TE, undefined | [0, ParserResult<TStateA>] | [1, ParserResult<TStateB>] | [2, ParserResult<TStateC>] | [3, ParserResult<TStateD>] | [4, ParserResult<TStateE>]>;
|
|
639
729
|
/**
|
|
640
730
|
* Helper type to check if all members of a union are object-like.
|
|
641
731
|
* This allows merge() to work with parsers like withDefault() that produce union types.
|
|
@@ -924,4 +1014,4 @@ declare function parse<T>(parser: Parser<T, unknown>, args: readonly string[]):
|
|
|
924
1014
|
*/
|
|
925
1015
|
declare function getDocPage(parser: Parser<unknown, unknown>, args?: readonly string[]): DocPage | undefined;
|
|
926
1016
|
//#endregion
|
|
927
|
-
export { ArgumentOptions, CommandOptions, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, concat, constant, flag, getDocPage, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
|
|
1017
|
+
export { ArgumentOptions, CommandOptions, DocState, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, concat, constant, flag, getDocPage, longestMatch, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
|
package/dist/parser.d.ts
CHANGED
|
@@ -5,6 +5,19 @@ import { ValueParser, ValueParserResult } from "./valueparser.js";
|
|
|
5
5
|
|
|
6
6
|
//#region src/parser.d.ts
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Represents the state passed to getDocFragments.
|
|
10
|
+
* Can be either the actual parser state or an explicit indicator
|
|
11
|
+
* that no state is available.
|
|
12
|
+
* @template TState The type of the actual state when available.
|
|
13
|
+
* @since 0.3.0
|
|
14
|
+
*/
|
|
15
|
+
type DocState<TState> = {
|
|
16
|
+
readonly kind: "available";
|
|
17
|
+
readonly state: TState;
|
|
18
|
+
} | {
|
|
19
|
+
readonly kind: "unavailable";
|
|
20
|
+
};
|
|
8
21
|
/**
|
|
9
22
|
* Parser interface for command-line argument parsing.
|
|
10
23
|
* @template TValue The type of the value returned by the parser.
|
|
@@ -65,15 +78,14 @@ interface Parser<TValue, TState> {
|
|
|
65
78
|
/**
|
|
66
79
|
* Generates a documentation fragment for this parser, which can be used
|
|
67
80
|
* to describe the parser's usage, description, and default value.
|
|
68
|
-
* @param state The current state of the parser,
|
|
69
|
-
*
|
|
70
|
-
* the documentation.
|
|
81
|
+
* @param state The current state of the parser, wrapped in a DocState
|
|
82
|
+
* to indicate whether the actual state is available or not.
|
|
71
83
|
* @param defaultValue An optional default value that can be used
|
|
72
84
|
* to provide a default value in the documentation.
|
|
73
85
|
* @returns {@link DocFragments} object containing documentation
|
|
74
86
|
* fragments for this parser.
|
|
75
87
|
*/
|
|
76
|
-
getDocFragments(state: TState
|
|
88
|
+
getDocFragments(state: DocState<TState>, defaultValue?: TValue): DocFragments;
|
|
77
89
|
}
|
|
78
90
|
/**
|
|
79
91
|
* The context of the parser, which includes the input buffer and the state.
|
|
@@ -636,6 +648,84 @@ declare function or<TA, TB, TC, TD, TE, TF, TG, TH, TI, TStateA, TStateB, TState
|
|
|
636
648
|
* in order, returning the result of the first successful parser.
|
|
637
649
|
*/
|
|
638
650
|
declare function or<TA, TB, TC, TD, TE, TF, TG, TH, TI, TJ, TStateA, TStateB, TStateC, TStateD, TStateE, TStateF, TStateG, TStateH, TStateI, TStateJ>(a: Parser<TA, TStateA>, b: Parser<TB, TStateB>, c: Parser<TC, TStateC>, d: Parser<TD, TStateD>, e: Parser<TE, TStateE>, f: Parser<TF, TStateF>, g: Parser<TG, TStateG>, h: Parser<TH, TStateH>, i: Parser<TI, TStateI>, j: Parser<TJ, TStateJ>): Parser<TA | TB | TC | TD | TE | TF | TG | TH | TI | TJ, undefined | [0, ParserResult<TStateA>] | [1, ParserResult<TStateB>] | [2, ParserResult<TStateC>] | [3, ParserResult<TStateD>] | [4, ParserResult<TStateE>] | [5, ParserResult<TStateF>] | [6, ParserResult<TStateG>] | [7, ParserResult<TStateH>] | [8, ParserResult<TStateI>] | [9, ParserResult<TStateJ>]>;
|
|
651
|
+
/**
|
|
652
|
+
* Creates a parser that combines two mutually exclusive parsers into one,
|
|
653
|
+
* selecting the parser that consumes the most tokens.
|
|
654
|
+
* The resulting parser will try both parsers and return the result
|
|
655
|
+
* of the parser that consumed more input tokens.
|
|
656
|
+
* @template TA The type of the value returned by the first parser.
|
|
657
|
+
* @template TB The type of the value returned by the second parser.
|
|
658
|
+
* @template TStateA The type of the state used by the first parser.
|
|
659
|
+
* @template TStateB The type of the state used by the second parser.
|
|
660
|
+
* @param a The first {@link Parser} to try.
|
|
661
|
+
* @param b The second {@link Parser} to try.
|
|
662
|
+
* @returns A {@link Parser} that tries to parse using both parsers
|
|
663
|
+
* and returns the result of the parser that consumed more tokens.
|
|
664
|
+
*/
|
|
665
|
+
declare function longestMatch<TA, TB, TStateA, TStateB>(a: Parser<TA, TStateA>, b: Parser<TB, TStateB>): Parser<TA | TB, undefined | [0, ParserResult<TStateA>] | [1, ParserResult<TStateB>]>;
|
|
666
|
+
/**
|
|
667
|
+
* Creates a parser that combines three mutually exclusive parsers into one,
|
|
668
|
+
* selecting the parser that consumes the most tokens.
|
|
669
|
+
* The resulting parser will try all parsers and return the result
|
|
670
|
+
* of the parser that consumed the most input tokens.
|
|
671
|
+
* @template TA The type of the value returned by the first parser.
|
|
672
|
+
* @template TB The type of the value returned by the second parser.
|
|
673
|
+
* @template TC The type of the value returned by the third parser.
|
|
674
|
+
* @template TStateA The type of the state used by the first parser.
|
|
675
|
+
* @template TStateB The type of the state used by the second parser.
|
|
676
|
+
* @template TStateC The type of the state used by the third parser.
|
|
677
|
+
* @param a The first {@link Parser} to try.
|
|
678
|
+
* @param b The second {@link Parser} to try.
|
|
679
|
+
* @param c The third {@link Parser} to try.
|
|
680
|
+
* @returns A {@link Parser} that tries to parse using all parsers
|
|
681
|
+
* and returns the result of the parser that consumed the most tokens.
|
|
682
|
+
*/
|
|
683
|
+
declare function longestMatch<TA, TB, TC, TStateA, TStateB, TStateC>(a: Parser<TA, TStateA>, b: Parser<TB, TStateB>, c: Parser<TC, TStateC>): Parser<TA | TB | TC, undefined | [0, ParserResult<TStateA>] | [1, ParserResult<TStateB>] | [2, ParserResult<TStateC>]>;
|
|
684
|
+
/**
|
|
685
|
+
* Creates a parser that combines four mutually exclusive parsers into one,
|
|
686
|
+
* selecting the parser that consumes the most tokens.
|
|
687
|
+
* The resulting parser will try all parsers and return the result
|
|
688
|
+
* of the parser that consumed the most input tokens.
|
|
689
|
+
* @template TA The type of the value returned by the first parser.
|
|
690
|
+
* @template TB The type of the value returned by the second parser.
|
|
691
|
+
* @template TC The type of the value returned by the third parser.
|
|
692
|
+
* @template TD The type of the value returned by the fourth parser.
|
|
693
|
+
* @template TStateA The type of the state used by the first parser.
|
|
694
|
+
* @template TStateB The type of the state used by the second parser.
|
|
695
|
+
* @template TStateC The type of the state used by the third parser.
|
|
696
|
+
* @template TStateD The type of the state used by the fourth parser.
|
|
697
|
+
* @param a The first {@link Parser} to try.
|
|
698
|
+
* @param b The second {@link Parser} to try.
|
|
699
|
+
* @param c The third {@link Parser} to try.
|
|
700
|
+
* @param d The fourth {@link Parser} to try.
|
|
701
|
+
* @returns A {@link Parser} that tries to parse using all parsers
|
|
702
|
+
* and returns the result of the parser that consumed the most tokens.
|
|
703
|
+
*/
|
|
704
|
+
declare function longestMatch<TA, TB, TC, TD, TStateA, TStateB, TStateC, TStateD>(a: Parser<TA, TStateA>, b: Parser<TB, TStateB>, c: Parser<TC, TStateC>, d: Parser<TD, TStateD>): Parser<TA | TB | TC | TD, undefined | [0, ParserResult<TStateA>] | [1, ParserResult<TStateB>] | [2, ParserResult<TStateC>] | [3, ParserResult<TStateD>]>;
|
|
705
|
+
/**
|
|
706
|
+
* Creates a parser that combines five mutually exclusive parsers into one,
|
|
707
|
+
* selecting the parser that consumes the most tokens.
|
|
708
|
+
* The resulting parser will try all parsers and return the result
|
|
709
|
+
* of the parser that consumed the most input tokens.
|
|
710
|
+
* @template TA The type of the value returned by the first parser.
|
|
711
|
+
* @template TB The type of the value returned by the second parser.
|
|
712
|
+
* @template TC The type of the value returned by the third parser.
|
|
713
|
+
* @template TD The type of the value returned by the fourth parser.
|
|
714
|
+
* @template TE The type of the value returned by the fifth parser.
|
|
715
|
+
* @template TStateA The type of the state used by the first parser.
|
|
716
|
+
* @template TStateB The type of the state used by the second parser.
|
|
717
|
+
* @template TStateC The type of the state used by the third parser.
|
|
718
|
+
* @template TStateD The type of the state used by the fourth parser.
|
|
719
|
+
* @template TStateE The type of the state used by the fifth parser.
|
|
720
|
+
* @param a The first {@link Parser} to try.
|
|
721
|
+
* @param b The second {@link Parser} to try.
|
|
722
|
+
* @param c The third {@link Parser} to try.
|
|
723
|
+
* @param d The fourth {@link Parser} to try.
|
|
724
|
+
* @param e The fifth {@link Parser} to try.
|
|
725
|
+
* @returns A {@link Parser} that tries to parse using all parsers
|
|
726
|
+
* and returns the result of the parser that consumed the most tokens.
|
|
727
|
+
*/
|
|
728
|
+
declare function longestMatch<TA, TB, TC, TD, TE, TStateA, TStateB, TStateC, TStateD, TStateE>(a: Parser<TA, TStateA>, b: Parser<TB, TStateB>, c: Parser<TC, TStateC>, d: Parser<TD, TStateD>, e: Parser<TE, TStateE>): Parser<TA | TB | TC | TD | TE, undefined | [0, ParserResult<TStateA>] | [1, ParserResult<TStateB>] | [2, ParserResult<TStateC>] | [3, ParserResult<TStateD>] | [4, ParserResult<TStateE>]>;
|
|
639
729
|
/**
|
|
640
730
|
* Helper type to check if all members of a union are object-like.
|
|
641
731
|
* This allows merge() to work with parsers like withDefault() that produce union types.
|
|
@@ -924,4 +1014,4 @@ declare function parse<T>(parser: Parser<T, unknown>, args: readonly string[]):
|
|
|
924
1014
|
*/
|
|
925
1015
|
declare function getDocPage(parser: Parser<unknown, unknown>, args?: readonly string[]): DocPage | undefined;
|
|
926
1016
|
//#endregion
|
|
927
|
-
export { ArgumentOptions, CommandOptions, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, concat, constant, flag, getDocPage, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
|
|
1017
|
+
export { ArgumentOptions, CommandOptions, DocState, FlagOptions, InferValue, MultipleOptions, OptionOptions, Parser, ParserContext, ParserResult, Result, argument, command, concat, constant, flag, getDocPage, longestMatch, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
|
package/dist/parser.js
CHANGED
|
@@ -514,7 +514,11 @@ function optional(parser) {
|
|
|
514
514
|
return parser.complete(state[0]);
|
|
515
515
|
},
|
|
516
516
|
getDocFragments(state, defaultValue) {
|
|
517
|
-
|
|
517
|
+
const innerState = state.kind === "unavailable" ? { kind: "unavailable" } : state.state === void 0 ? { kind: "unavailable" } : {
|
|
518
|
+
kind: "available",
|
|
519
|
+
state: state.state[0]
|
|
520
|
+
};
|
|
521
|
+
return parser.getDocFragments(innerState, defaultValue);
|
|
518
522
|
}
|
|
519
523
|
};
|
|
520
524
|
}
|
|
@@ -566,7 +570,11 @@ function withDefault(parser, defaultValue) {
|
|
|
566
570
|
return parser.complete(state[0]);
|
|
567
571
|
},
|
|
568
572
|
getDocFragments(state, upperDefaultValue) {
|
|
569
|
-
|
|
573
|
+
const innerState = state.kind === "unavailable" ? { kind: "unavailable" } : state.state === void 0 ? { kind: "unavailable" } : {
|
|
574
|
+
kind: "available",
|
|
575
|
+
state: state.state[0]
|
|
576
|
+
};
|
|
577
|
+
return parser.getDocFragments(innerState, upperDefaultValue != null ? upperDefaultValue : typeof defaultValue === "function" ? defaultValue() : defaultValue);
|
|
570
578
|
}
|
|
571
579
|
};
|
|
572
580
|
}
|
|
@@ -697,7 +705,11 @@ function multiple(parser, options = {}) {
|
|
|
697
705
|
};
|
|
698
706
|
},
|
|
699
707
|
getDocFragments(state, defaultValue) {
|
|
700
|
-
|
|
708
|
+
const innerState = state.kind === "unavailable" ? { kind: "unavailable" } : state.state.length > 0 ? {
|
|
709
|
+
kind: "available",
|
|
710
|
+
state: state.state.at(-1)
|
|
711
|
+
} : { kind: "unavailable" };
|
|
712
|
+
return parser.getDocFragments(innerState, defaultValue != null && defaultValue.length > 0 ? defaultValue[0] : void 0);
|
|
701
713
|
}
|
|
702
714
|
};
|
|
703
715
|
}
|
|
@@ -788,7 +800,13 @@ function object(labelOrParsers, maybeParsers) {
|
|
|
788
800
|
};
|
|
789
801
|
},
|
|
790
802
|
getDocFragments(state, defaultValue) {
|
|
791
|
-
const fragments = parserPairs.flatMap(([field, p]) =>
|
|
803
|
+
const fragments = parserPairs.flatMap(([field, p]) => {
|
|
804
|
+
const fieldState = state.kind === "unavailable" ? { kind: "unavailable" } : {
|
|
805
|
+
kind: "available",
|
|
806
|
+
state: state.state[field]
|
|
807
|
+
};
|
|
808
|
+
return p.getDocFragments(fieldState, defaultValue?.[field]).fragments;
|
|
809
|
+
});
|
|
792
810
|
const entries = fragments.filter((d) => d.type === "entry");
|
|
793
811
|
const sections = [];
|
|
794
812
|
for (const fragment of fragments) {
|
|
@@ -892,7 +910,13 @@ function tuple(labelOrParsers, maybeParsers) {
|
|
|
892
910
|
};
|
|
893
911
|
},
|
|
894
912
|
getDocFragments(state, defaultValue) {
|
|
895
|
-
const fragments = parsers.flatMap((p, i) =>
|
|
913
|
+
const fragments = parsers.flatMap((p, i) => {
|
|
914
|
+
const indexState = state.kind === "unavailable" ? { kind: "unavailable" } : {
|
|
915
|
+
kind: "available",
|
|
916
|
+
state: state.state[i]
|
|
917
|
+
};
|
|
918
|
+
return p.getDocFragments(indexState, defaultValue?.[i]).fragments;
|
|
919
|
+
});
|
|
896
920
|
const entries = fragments.filter((d) => d.type === "entry");
|
|
897
921
|
const sections = [];
|
|
898
922
|
for (const fragment of fragments) {
|
|
@@ -976,10 +1000,14 @@ function or(...parsers) {
|
|
|
976
1000
|
getDocFragments(state, _defaultValue) {
|
|
977
1001
|
let description;
|
|
978
1002
|
let fragments;
|
|
979
|
-
if (state == null) fragments = parsers.flatMap((p) => p.getDocFragments(
|
|
1003
|
+
if (state.kind === "unavailable" || state.state == null) fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }, void 0).fragments);
|
|
980
1004
|
else {
|
|
981
|
-
const [index, parserResult] = state;
|
|
982
|
-
const
|
|
1005
|
+
const [index, parserResult] = state.state;
|
|
1006
|
+
const innerState = parserResult.success ? {
|
|
1007
|
+
kind: "available",
|
|
1008
|
+
state: parserResult.next.state
|
|
1009
|
+
} : { kind: "unavailable" };
|
|
1010
|
+
const docFragments = parsers[index].getDocFragments(innerState, void 0);
|
|
983
1011
|
description = docFragments.description;
|
|
984
1012
|
fragments = docFragments.fragments;
|
|
985
1013
|
}
|
|
@@ -1003,6 +1031,86 @@ function or(...parsers) {
|
|
|
1003
1031
|
}
|
|
1004
1032
|
};
|
|
1005
1033
|
}
|
|
1034
|
+
function longestMatch(...parsers) {
|
|
1035
|
+
return {
|
|
1036
|
+
$valueType: [],
|
|
1037
|
+
$stateType: [],
|
|
1038
|
+
priority: Math.max(...parsers.map((p) => p.priority)),
|
|
1039
|
+
usage: [{
|
|
1040
|
+
type: "exclusive",
|
|
1041
|
+
terms: parsers.map((p) => p.usage)
|
|
1042
|
+
}],
|
|
1043
|
+
initialState: void 0,
|
|
1044
|
+
complete(state) {
|
|
1045
|
+
if (state == null) return {
|
|
1046
|
+
success: false,
|
|
1047
|
+
error: message`No parser matched.`
|
|
1048
|
+
};
|
|
1049
|
+
const [i, result] = state;
|
|
1050
|
+
if (result.success) return parsers[i].complete(result.next.state);
|
|
1051
|
+
return {
|
|
1052
|
+
success: false,
|
|
1053
|
+
error: result.error
|
|
1054
|
+
};
|
|
1055
|
+
},
|
|
1056
|
+
parse(context) {
|
|
1057
|
+
let bestMatch = null;
|
|
1058
|
+
let error = {
|
|
1059
|
+
consumed: 0,
|
|
1060
|
+
error: context.buffer.length < 1 ? message`No parser matched.` : message`Unexpected option or subcommand: ${optionName(context.buffer[0])}.`
|
|
1061
|
+
};
|
|
1062
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1063
|
+
const parser = parsers[i];
|
|
1064
|
+
const result = parser.parse({
|
|
1065
|
+
...context,
|
|
1066
|
+
state: context.state == null || context.state[0] !== i || !context.state[1].success ? parser.initialState : context.state[1].next.state
|
|
1067
|
+
});
|
|
1068
|
+
if (result.success) {
|
|
1069
|
+
const consumed = context.buffer.length - result.next.buffer.length;
|
|
1070
|
+
if (bestMatch === null || consumed > bestMatch.consumed) bestMatch = {
|
|
1071
|
+
index: i,
|
|
1072
|
+
result,
|
|
1073
|
+
consumed
|
|
1074
|
+
};
|
|
1075
|
+
} else if (error.consumed < result.consumed) error = result;
|
|
1076
|
+
}
|
|
1077
|
+
if (bestMatch && bestMatch.result.success) return {
|
|
1078
|
+
success: true,
|
|
1079
|
+
next: {
|
|
1080
|
+
...context,
|
|
1081
|
+
buffer: bestMatch.result.next.buffer,
|
|
1082
|
+
optionsTerminated: bestMatch.result.next.optionsTerminated,
|
|
1083
|
+
state: [bestMatch.index, bestMatch.result]
|
|
1084
|
+
},
|
|
1085
|
+
consumed: bestMatch.result.consumed
|
|
1086
|
+
};
|
|
1087
|
+
return {
|
|
1088
|
+
...error,
|
|
1089
|
+
success: false
|
|
1090
|
+
};
|
|
1091
|
+
},
|
|
1092
|
+
getDocFragments(state, _defaultValue) {
|
|
1093
|
+
let description;
|
|
1094
|
+
let fragments;
|
|
1095
|
+
if (state.kind === "unavailable" || state.state == null) fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }).fragments);
|
|
1096
|
+
else {
|
|
1097
|
+
const [i, result] = state.state;
|
|
1098
|
+
if (result.success) {
|
|
1099
|
+
const docResult = parsers[i].getDocFragments({
|
|
1100
|
+
kind: "available",
|
|
1101
|
+
state: result.next.state
|
|
1102
|
+
});
|
|
1103
|
+
description = docResult.description;
|
|
1104
|
+
fragments = docResult.fragments;
|
|
1105
|
+
} else fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }).fragments);
|
|
1106
|
+
}
|
|
1107
|
+
return {
|
|
1108
|
+
description,
|
|
1109
|
+
fragments
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1006
1114
|
function merge(...parsers) {
|
|
1007
1115
|
parsers = parsers.toSorted((a, b) => b.priority - a.priority);
|
|
1008
1116
|
const initialState = {};
|
|
@@ -1082,7 +1190,13 @@ function merge(...parsers) {
|
|
|
1082
1190
|
};
|
|
1083
1191
|
},
|
|
1084
1192
|
getDocFragments(state, _defaultValue) {
|
|
1085
|
-
const fragments = parsers.flatMap((p) =>
|
|
1193
|
+
const fragments = parsers.flatMap((p) => {
|
|
1194
|
+
const parserState = p.initialState === void 0 ? { kind: "unavailable" } : state.kind === "unavailable" ? { kind: "unavailable" } : {
|
|
1195
|
+
kind: "available",
|
|
1196
|
+
state: state.state
|
|
1197
|
+
};
|
|
1198
|
+
return p.getDocFragments(parserState, void 0).fragments;
|
|
1199
|
+
});
|
|
1086
1200
|
const entries = fragments.filter((f) => f.type === "entry");
|
|
1087
1201
|
const sections = [];
|
|
1088
1202
|
for (const fragment of fragments) {
|
|
@@ -1183,7 +1297,13 @@ function concat(...parsers) {
|
|
|
1183
1297
|
};
|
|
1184
1298
|
},
|
|
1185
1299
|
getDocFragments(state, _defaultValue) {
|
|
1186
|
-
const fragments = parsers.flatMap((p, index) =>
|
|
1300
|
+
const fragments = parsers.flatMap((p, index) => {
|
|
1301
|
+
const indexState = state.kind === "unavailable" ? { kind: "unavailable" } : {
|
|
1302
|
+
kind: "available",
|
|
1303
|
+
state: state.state[index]
|
|
1304
|
+
};
|
|
1305
|
+
return p.getDocFragments(indexState, void 0).fragments;
|
|
1306
|
+
});
|
|
1187
1307
|
const entries = fragments.filter((f) => f.type === "entry");
|
|
1188
1308
|
const sections = [];
|
|
1189
1309
|
for (const fragment of fragments) {
|
|
@@ -1290,7 +1410,7 @@ function command(name, parser, options = {}) {
|
|
|
1290
1410
|
};
|
|
1291
1411
|
},
|
|
1292
1412
|
getDocFragments(state, defaultValue) {
|
|
1293
|
-
if (typeof state === "undefined") return {
|
|
1413
|
+
if (state.kind === "unavailable" || typeof state.state === "undefined") return {
|
|
1294
1414
|
description: options.description,
|
|
1295
1415
|
fragments: [{
|
|
1296
1416
|
type: "entry",
|
|
@@ -1301,7 +1421,11 @@ function command(name, parser, options = {}) {
|
|
|
1301
1421
|
description: options.description
|
|
1302
1422
|
}]
|
|
1303
1423
|
};
|
|
1304
|
-
const
|
|
1424
|
+
const innerState = state.state[0] === "parsing" ? {
|
|
1425
|
+
kind: "available",
|
|
1426
|
+
state: state.state[1]
|
|
1427
|
+
} : { kind: "unavailable" };
|
|
1428
|
+
const innerFragments = parser.getDocFragments(innerState, defaultValue);
|
|
1305
1429
|
return {
|
|
1306
1430
|
...innerFragments,
|
|
1307
1431
|
description: innerFragments.description ?? options.description
|
|
@@ -1398,7 +1522,10 @@ function getDocPage(parser, args = []) {
|
|
|
1398
1522
|
if (!result.success) break;
|
|
1399
1523
|
context = result.next;
|
|
1400
1524
|
} while (context.buffer.length > 0);
|
|
1401
|
-
const { description, fragments } = parser.getDocFragments(
|
|
1525
|
+
const { description, fragments } = parser.getDocFragments({
|
|
1526
|
+
kind: "available",
|
|
1527
|
+
state: context.state
|
|
1528
|
+
}, void 0);
|
|
1402
1529
|
const entries = fragments.filter((f) => f.type === "entry");
|
|
1403
1530
|
const sections = [];
|
|
1404
1531
|
for (const fragment of fragments) {
|
|
@@ -1430,4 +1557,4 @@ function getDocPage(parser, args = []) {
|
|
|
1430
1557
|
}
|
|
1431
1558
|
|
|
1432
1559
|
//#endregion
|
|
1433
|
-
export { argument, command, concat, constant, flag, getDocPage, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
|
|
1560
|
+
export { argument, command, concat, constant, flag, getDocPage, longestMatch, map, merge, multiple, object, option, optional, or, parse, tuple, withDefault };
|