@reventlessdev/reventless-spec 3.0.0-alpha.142 → 3.0.0-alpha.144
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/CHANGELOG.md +21 -0
- package/package.json +2 -2
- package/run-certify-trait.mjs +2 -1
- package/run-generator.mjs +2 -1
- package/run-graft-trait.mjs +2 -1
- package/run-platform-generator.mjs +2 -1
- package/run-trait-manifest.mjs +2 -1
- package/src/CliArgs.res +209 -0
- package/src/CliArgs.res.mjs +325 -0
- package/src/generator/CertifyTrait.res +96 -93
- package/src/generator/CertifyTrait.res.mjs +92 -75
- package/src/generator/GraftTrait.res +147 -148
- package/src/generator/GraftTrait.res.mjs +131 -128
- package/src/generator/PlatformGenerator.res +50 -31
- package/src/generator/PlatformGenerator.res.mjs +107 -76
- package/src/generator/PluginGenerator.res +29 -29
- package/src/generator/PluginGenerator.res.mjs +87 -55
- package/src/generator/TraitManifestCli.res +69 -68
- package/src/generator/TraitManifestCli.res.mjs +67 -51
- package/src/lifecycle/CheckLifecycleModel.res +203 -189
- package/src/lifecycle/CheckLifecycleModel.res.mjs +146 -141
- package/src/types/PrepareAccounts.res +38 -57
- package/src/types/PrepareAccounts.res.mjs +28 -82
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,27 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.144 (2026-09-23)
|
|
7
|
+
|
|
8
|
+
* feat(node)!: every command-line tool reads its arguments through parseArgs ([2e41979](https://github.com/ReventlessDev/reventless-core/commit/2e41979b73646c46356e197e17eb4a3da0154c73))
|
|
9
|
+
|
|
10
|
+
### BREAKING CHANGES
|
|
11
|
+
|
|
12
|
+
* NodeProcess.onSignal takes the new NodeProcess.signal
|
|
13
|
+
variant (SIGINT | SIGTERM | SIGHUP) instead of a polymorphic variant:
|
|
14
|
+
write onSignal(SIGINT, …) for onSignal(#SIGINT, …). Node receives the
|
|
15
|
+
same string.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# 3.0.0-alpha.143 (2026-09-23)
|
|
20
|
+
|
|
21
|
+
**Note:** Version bump only for package @reventlessdev/reventless-spec
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
6
27
|
# 3.0.0-alpha.142 (2026-09-22)
|
|
7
28
|
|
|
8
29
|
### Features
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-spec",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.144",
|
|
4
4
|
"description": "Specifications for Reventless",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"sury": "11.0.0",
|
|
27
27
|
"sury-ppx": "11.0.0",
|
|
28
28
|
"yaml": "^2.8.3",
|
|
29
|
-
"@reventlessdev/rescript-node": "2.0.0-alpha.
|
|
29
|
+
"@reventlessdev/rescript-node": "2.0.0-alpha.15"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"rescript": "12.3.1",
|
package/run-certify-trait.mjs
CHANGED
package/run-generator.mjs
CHANGED
package/run-graft-trait.mjs
CHANGED
package/run-trait-manifest.mjs
CHANGED
package/src/CliArgs.res
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/***
|
|
2
|
+
How every command-line tool in this repository reads `process.argv`: through
|
|
3
|
+
Node's `parseArgs`, with mistakes worded the way these tools word them, and one
|
|
4
|
+
behaviour on `--help`, on a usage mistake and on a bare invocation (see [run]).
|
|
5
|
+
Non-strict with tokens rather than strict mode, because strict mode names the
|
|
6
|
+
offending argument only inside English prose.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** An undeclared `--key` under `~pairs=true`: with a value, or on its own. */
|
|
10
|
+
type value =
|
|
11
|
+
| Text(string)
|
|
12
|
+
| Present
|
|
13
|
+
|
|
14
|
+
type t = {
|
|
15
|
+
values: NodeUtil.values,
|
|
16
|
+
positionals: array<string>,
|
|
17
|
+
pairs: array<(string, value)>,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** A usage mistake. A tool that ran and failed exits 1, so a caller can tell a
|
|
21
|
+
misinvocation from a run whose answer was no. */
|
|
22
|
+
let usageMistakeExit = 2
|
|
23
|
+
|
|
24
|
+
let unknown = (arg: string) => `unknown argument "${arg}"`
|
|
25
|
+
|
|
26
|
+
/** A positional the tool has no place for, worded like any other unknown argument. */
|
|
27
|
+
let extra = (arg: string): result<'a, string> => Error(unknown(arg))
|
|
28
|
+
|
|
29
|
+
/** `-` alone is a value (stdin, by convention); anything else starting with a
|
|
30
|
+
dash is the next flag, which a string option must not swallow. */
|
|
31
|
+
let flagShaped = (value: string) => value->String.startsWith("-") && value != "-"
|
|
32
|
+
|
|
33
|
+
/** Package managers can forward a bare `--` ahead of a script's own arguments.
|
|
34
|
+
Anywhere else it ends the options, as POSIX says. */
|
|
35
|
+
let withoutLeadingTerminator = (argv: array<string>) =>
|
|
36
|
+
argv->Array.get(0) == Some("--") ? argv->Array.slice(~start=1, ~end=Array.length(argv)) : argv
|
|
37
|
+
|
|
38
|
+
/** Parse against the declared options. `-h`/`--help` is declared for every
|
|
39
|
+
tool. The first mistake in argv order is the one reported. Under
|
|
40
|
+
`~pairs=true` an undeclared long option is kept as a `(key, value)` pair
|
|
41
|
+
instead of refused, taking the argument after it as its value when that
|
|
42
|
+
argument is not itself an option. */
|
|
43
|
+
let parse = (
|
|
44
|
+
~strings: array<string>=[],
|
|
45
|
+
~bools: array<string>=[],
|
|
46
|
+
~lists: array<string>=[],
|
|
47
|
+
~pairs: bool=false,
|
|
48
|
+
argv: array<string>,
|
|
49
|
+
): result<t, string> => {
|
|
50
|
+
let args = withoutLeadingTerminator(argv)
|
|
51
|
+
let options: dict<NodeUtil.optionConfig> = Dict.make()
|
|
52
|
+
options->Dict.set("help", {type_: Boolean, short: "h"})
|
|
53
|
+
bools->Array.forEach(name => options->Dict.set(name, {type_: Boolean}))
|
|
54
|
+
strings->Array.forEach(name => options->Dict.set(name, {type_: String}))
|
|
55
|
+
lists->Array.forEach(name => options->Dict.set(name, {type_: String, multiple: true}))
|
|
56
|
+
|
|
57
|
+
let parsed = NodeUtil.parseArgs({
|
|
58
|
+
args,
|
|
59
|
+
options,
|
|
60
|
+
strict: false,
|
|
61
|
+
allowPositionals: true,
|
|
62
|
+
tokens: true,
|
|
63
|
+
})
|
|
64
|
+
let tokens = parsed.tokens->Option.getOr([])
|
|
65
|
+
let positionals = []
|
|
66
|
+
let found = []
|
|
67
|
+
|
|
68
|
+
// Non-strict `parseArgs` types an undeclared option as a boolean and emits
|
|
69
|
+
// the argument after it as the next positional token, so a pair's value is
|
|
70
|
+
// read back from token order.
|
|
71
|
+
let rec walk = i =>
|
|
72
|
+
switch tokens->Array.get(i) {
|
|
73
|
+
| None => Ok()
|
|
74
|
+
| Some(token) =>
|
|
75
|
+
switch token.kind {
|
|
76
|
+
| Terminator => walk(i + 1)
|
|
77
|
+
| Positional =>
|
|
78
|
+
positionals->Array.push(token.value->Option.getOr(""))
|
|
79
|
+
walk(i + 1)
|
|
80
|
+
| Flag =>
|
|
81
|
+
let name = token.name->Option.getOr("")
|
|
82
|
+
let rawName = token.rawName->Option.getOr(name)
|
|
83
|
+
let inline = token.inlineValue->Option.getOr(false)
|
|
84
|
+
switch (options->Dict.get(name), token.value) {
|
|
85
|
+
| (Some({type_: String}), None) => Error(`${rawName} needs a value`)
|
|
86
|
+
| (Some({type_: String}), Some(v)) if !inline && flagShaped(v) =>
|
|
87
|
+
Error(`${rawName} needs a value`)
|
|
88
|
+
| (Some({type_: Boolean}), Some(_)) => Error(`${rawName} takes no value`)
|
|
89
|
+
| (Some(_), _) => walk(i + 1)
|
|
90
|
+
| (None, _) if !pairs || !(rawName->String.startsWith("--")) => Error(unknown(rawName))
|
|
91
|
+
| (None, Some(v)) =>
|
|
92
|
+
found->Array.push((name, Text(v)))
|
|
93
|
+
walk(i + 1)
|
|
94
|
+
| (None, None) =>
|
|
95
|
+
switch tokens->Array.get(i + 1) {
|
|
96
|
+
| Some({kind: Positional, index, value: ?Some(v)}) if index == token.index + 1 =>
|
|
97
|
+
found->Array.push((name, Text(v)))
|
|
98
|
+
walk(i + 2)
|
|
99
|
+
| _ =>
|
|
100
|
+
found->Array.push((name, Present))
|
|
101
|
+
walk(i + 1)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
walk(0)->Result.map(() => {values: parsed.values, positionals, pairs: found})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
let string = (t: t, name: string): option<string> => t.values->NodeUtil.string(name)
|
|
111
|
+
let bool = (t: t, name: string): bool => t.values->NodeUtil.bool(name)->Option.getOr(false)
|
|
112
|
+
let strings = (t: t, name: string): array<string> =>
|
|
113
|
+
t.values->NodeUtil.strings(name)->Option.getOr([])
|
|
114
|
+
let positionals = (t: t): array<string> => t.positionals
|
|
115
|
+
let pairs = (t: t): array<(string, value)> => t.pairs
|
|
116
|
+
let help = (t: t): bool => t->bool("help")
|
|
117
|
+
|
|
118
|
+
/** For a tool that takes at most `max` positionals: the first beyond them is
|
|
119
|
+
refused as [extra]. */
|
|
120
|
+
let atMost = (t: t, max: int): result<t, string> =>
|
|
121
|
+
switch t.positionals->Array.get(max) {
|
|
122
|
+
| None => Ok(t)
|
|
123
|
+
| Some(arg) => extra(arg)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
let noPositionals = (t: t): result<t, string> => t->atMost(0)
|
|
127
|
+
|
|
128
|
+
/** Whether `-h` or `--help` appears before any `--` that ends the options.
|
|
129
|
+
Read off argv rather than a parse, so it answers even when the other
|
|
130
|
+
arguments are wrong. */
|
|
131
|
+
let asksForHelp = (argv: array<string>): bool => {
|
|
132
|
+
let argv = withoutLeadingTerminator(argv)
|
|
133
|
+
let options = switch argv->Array.indexOf("--") {
|
|
134
|
+
| -1 => argv
|
|
135
|
+
| end => argv->Array.slice(~start=0, ~end)
|
|
136
|
+
}
|
|
137
|
+
options->Array.some(arg => arg == "-h" || arg == "--help")
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** A tool's command line: its name, its usage (first line `Usage: <bin> …`),
|
|
141
|
+
and how it turns argv into its arguments. */
|
|
142
|
+
type cli<'args> = {
|
|
143
|
+
bin: string,
|
|
144
|
+
usage: string,
|
|
145
|
+
parse: array<string> => result<'args, string>,
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Where [run] writes and how it ends the process, so a test can watch it. */
|
|
149
|
+
type io = {
|
|
150
|
+
out: string => unit,
|
|
151
|
+
err: string => unit,
|
|
152
|
+
exit: int => unit,
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let processIo = {
|
|
156
|
+
out: text => Console.log(text),
|
|
157
|
+
err: text => Console.error(text),
|
|
158
|
+
exit: NodeProcess.exit,
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Help anywhere prints the usage to stdout and exits 0, whatever else is
|
|
162
|
+
wrong. A usage mistake prints `<bin>: <message>`, a blank line and the usage
|
|
163
|
+
to stderr and exits 2. Otherwise `main` gets the arguments, and its own
|
|
164
|
+
failures keep their exit 1. */
|
|
165
|
+
let run = async (
|
|
166
|
+
cli: cli<'args>,
|
|
167
|
+
~argv: option<array<string>>=?,
|
|
168
|
+
~io: io=processIo,
|
|
169
|
+
main: 'args => promise<unit>,
|
|
170
|
+
): unit => {
|
|
171
|
+
let argv =
|
|
172
|
+
argv->Option.getOr(NodeProcess.argv->Array.slice(~start=2, ~end=NodeProcess.argv->Array.length))
|
|
173
|
+
let usage = cli.usage->String.trim
|
|
174
|
+
if asksForHelp(argv) {
|
|
175
|
+
io.out(usage)
|
|
176
|
+
io.exit(0)
|
|
177
|
+
} else {
|
|
178
|
+
switch cli.parse(argv) {
|
|
179
|
+
| Error(message) =>
|
|
180
|
+
io.err(`${cli.bin}: ${message}\n\n${usage}`)
|
|
181
|
+
io.exit(usageMistakeExit)
|
|
182
|
+
| Ok(args) => await main(args)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** What [run] did with one argv, for a tool's own tests. */
|
|
188
|
+
type observed = {
|
|
189
|
+
stdout: array<string>,
|
|
190
|
+
stderr: array<string>,
|
|
191
|
+
exitCode: option<int>,
|
|
192
|
+
reachedMain: bool,
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Run a tool's command line without a process: nothing is printed, nothing
|
|
196
|
+
exits, and `main` is not called — only whether it would have been. */
|
|
197
|
+
let observe = async (cli: cli<'args>, argv: array<string>): observed => {
|
|
198
|
+
let stdout = []
|
|
199
|
+
let stderr = []
|
|
200
|
+
let exitCode = ref(None)
|
|
201
|
+
let reachedMain = ref(false)
|
|
202
|
+
let io = {
|
|
203
|
+
out: text => stdout->Array.push(text),
|
|
204
|
+
err: text => stderr->Array.push(text),
|
|
205
|
+
exit: code => exitCode := Some(code),
|
|
206
|
+
}
|
|
207
|
+
await run(cli, ~argv, ~io, async _ => reachedMain := true)
|
|
208
|
+
{stdout, stderr, exitCode: exitCode.contents, reachedMain: reachedMain.contents}
|
|
209
|
+
}
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Nodeutil from "node:util";
|
|
4
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
import * as Stdlib_Result from "@rescript/runtime/lib/es6/Stdlib_Result.js";
|
|
6
|
+
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
7
|
+
|
|
8
|
+
function unknown(arg) {
|
|
9
|
+
return `unknown argument "` + arg + `"`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function extra(arg) {
|
|
13
|
+
return {
|
|
14
|
+
TAG: "Error",
|
|
15
|
+
_0: unknown(arg)
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function flagShaped(value) {
|
|
20
|
+
if (value.startsWith("-")) {
|
|
21
|
+
return value !== "-";
|
|
22
|
+
} else {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function withoutLeadingTerminator(argv) {
|
|
28
|
+
if (Primitive_object.equal(argv[0], "--")) {
|
|
29
|
+
return argv.slice(1, argv.length);
|
|
30
|
+
} else {
|
|
31
|
+
return argv;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function parse(stringsOpt, boolsOpt, listsOpt, pairsOpt, argv) {
|
|
36
|
+
let strings = stringsOpt !== undefined ? stringsOpt : [];
|
|
37
|
+
let bools = boolsOpt !== undefined ? boolsOpt : [];
|
|
38
|
+
let lists = listsOpt !== undefined ? listsOpt : [];
|
|
39
|
+
let pairs = pairsOpt !== undefined ? pairsOpt : false;
|
|
40
|
+
let args = withoutLeadingTerminator(argv);
|
|
41
|
+
let options = {};
|
|
42
|
+
options["help"] = {
|
|
43
|
+
type: "boolean",
|
|
44
|
+
short: "h"
|
|
45
|
+
};
|
|
46
|
+
bools.forEach(name => {
|
|
47
|
+
options[name] = {
|
|
48
|
+
type: "boolean"
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
strings.forEach(name => {
|
|
52
|
+
options[name] = {
|
|
53
|
+
type: "string"
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
lists.forEach(name => {
|
|
57
|
+
options[name] = {
|
|
58
|
+
type: "string",
|
|
59
|
+
multiple: true
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
let parsed = Nodeutil.parseArgs({
|
|
63
|
+
args: args,
|
|
64
|
+
options: options,
|
|
65
|
+
strict: false,
|
|
66
|
+
allowPositionals: true,
|
|
67
|
+
tokens: true
|
|
68
|
+
});
|
|
69
|
+
let tokens = Stdlib_Option.getOr(parsed.tokens, []);
|
|
70
|
+
let positionals = [];
|
|
71
|
+
let found = [];
|
|
72
|
+
let walk = _i => {
|
|
73
|
+
while (true) {
|
|
74
|
+
let i = _i;
|
|
75
|
+
let token = tokens[i];
|
|
76
|
+
if (token === undefined) {
|
|
77
|
+
return {
|
|
78
|
+
TAG: "Ok",
|
|
79
|
+
_0: undefined
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
let match = token.kind;
|
|
83
|
+
switch (match) {
|
|
84
|
+
case "option" :
|
|
85
|
+
let name = Stdlib_Option.getOr(token.name, "");
|
|
86
|
+
let rawName = Stdlib_Option.getOr(token.rawName, name);
|
|
87
|
+
let inline = Stdlib_Option.getOr(token.inlineValue, false);
|
|
88
|
+
let match$1 = options[name];
|
|
89
|
+
let match$2 = token.value;
|
|
90
|
+
if (match$1 !== undefined) {
|
|
91
|
+
if (match$1.type === "string") {
|
|
92
|
+
if (match$2 === undefined) {
|
|
93
|
+
return {
|
|
94
|
+
TAG: "Error",
|
|
95
|
+
_0: rawName + ` needs a value`
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (!inline && flagShaped(match$2)) {
|
|
99
|
+
return {
|
|
100
|
+
TAG: "Error",
|
|
101
|
+
_0: rawName + ` needs a value`
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
_i = i + 1 | 0;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (match$2 !== undefined) {
|
|
108
|
+
return {
|
|
109
|
+
TAG: "Error",
|
|
110
|
+
_0: rawName + ` takes no value`
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
_i = i + 1 | 0;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (!pairs || !rawName.startsWith("--")) {
|
|
117
|
+
return {
|
|
118
|
+
TAG: "Error",
|
|
119
|
+
_0: unknown(rawName)
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (match$2 !== undefined) {
|
|
123
|
+
found.push([
|
|
124
|
+
name,
|
|
125
|
+
{
|
|
126
|
+
TAG: "Text",
|
|
127
|
+
_0: match$2
|
|
128
|
+
}
|
|
129
|
+
]);
|
|
130
|
+
_i = i + 1 | 0;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
let match$3 = tokens[i + 1 | 0];
|
|
134
|
+
if (match$3 !== undefined) {
|
|
135
|
+
switch (match$3.kind) {
|
|
136
|
+
case "positional" :
|
|
137
|
+
let v = match$3.value;
|
|
138
|
+
if (v !== undefined && match$3.index === (token.index + 1 | 0)) {
|
|
139
|
+
found.push([
|
|
140
|
+
name,
|
|
141
|
+
{
|
|
142
|
+
TAG: "Text",
|
|
143
|
+
_0: v
|
|
144
|
+
}
|
|
145
|
+
]);
|
|
146
|
+
_i = i + 2 | 0;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
break;
|
|
150
|
+
case "option" :
|
|
151
|
+
case "option-terminator" :
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
found.push([
|
|
156
|
+
name,
|
|
157
|
+
"Present"
|
|
158
|
+
]);
|
|
159
|
+
_i = i + 1 | 0;
|
|
160
|
+
continue;
|
|
161
|
+
break;
|
|
162
|
+
case "positional" :
|
|
163
|
+
positionals.push(Stdlib_Option.getOr(token.value, ""));
|
|
164
|
+
_i = i + 1 | 0;
|
|
165
|
+
continue;
|
|
166
|
+
case "option-terminator" :
|
|
167
|
+
_i = i + 1 | 0;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
return Stdlib_Result.map(walk(0), () => ({
|
|
173
|
+
values: parsed.values,
|
|
174
|
+
positionals: positionals,
|
|
175
|
+
pairs: found
|
|
176
|
+
}));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function string(t, name) {
|
|
180
|
+
return t.values[name];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function bool(t, name) {
|
|
184
|
+
return Stdlib_Option.getOr(t.values[name], false);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function strings(t, name) {
|
|
188
|
+
return Stdlib_Option.getOr(t.values[name], []);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function positionals(t) {
|
|
192
|
+
return t.positionals;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function pairs(t) {
|
|
196
|
+
return t.pairs;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function help(t) {
|
|
200
|
+
return bool(t, "help");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function atMost(t, max) {
|
|
204
|
+
let arg = t.positionals[max];
|
|
205
|
+
if (arg !== undefined) {
|
|
206
|
+
return {
|
|
207
|
+
TAG: "Error",
|
|
208
|
+
_0: unknown(arg)
|
|
209
|
+
};
|
|
210
|
+
} else {
|
|
211
|
+
return {
|
|
212
|
+
TAG: "Ok",
|
|
213
|
+
_0: t
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function noPositionals(t) {
|
|
219
|
+
return atMost(t, 0);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function asksForHelp(argv) {
|
|
223
|
+
let argv$1 = withoutLeadingTerminator(argv);
|
|
224
|
+
let end = argv$1.indexOf("--");
|
|
225
|
+
let options = end !== -1 ? argv$1.slice(0, end) : argv$1;
|
|
226
|
+
return options.some(arg => {
|
|
227
|
+
if (arg === "-h") {
|
|
228
|
+
return true;
|
|
229
|
+
} else {
|
|
230
|
+
return arg === "--help";
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function processIo_out(text) {
|
|
236
|
+
console.log(text);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function processIo_err(text) {
|
|
240
|
+
console.error(text);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function processIo_exit(prim) {
|
|
244
|
+
process.exit(prim);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
let processIo = {
|
|
248
|
+
out: processIo_out,
|
|
249
|
+
err: processIo_err,
|
|
250
|
+
exit: processIo_exit
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
async function run(cli, argv, ioOpt, main) {
|
|
254
|
+
let io = ioOpt !== undefined ? ioOpt : processIo;
|
|
255
|
+
let argv$1 = Stdlib_Option.getOr(argv, process.argv.slice(2, process.argv.length));
|
|
256
|
+
let usage = cli.usage.trim();
|
|
257
|
+
if (asksForHelp(argv$1)) {
|
|
258
|
+
io.out(usage);
|
|
259
|
+
return io.exit(0);
|
|
260
|
+
}
|
|
261
|
+
let message = cli.parse(argv$1);
|
|
262
|
+
if (message.TAG === "Ok") {
|
|
263
|
+
return await main(message._0);
|
|
264
|
+
}
|
|
265
|
+
io.err(cli.bin + `: ` + message._0 + `\n\n` + usage);
|
|
266
|
+
return io.exit(2);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async function observe(cli, argv) {
|
|
270
|
+
let stdout = [];
|
|
271
|
+
let stderr = [];
|
|
272
|
+
let exitCode = {
|
|
273
|
+
contents: undefined
|
|
274
|
+
};
|
|
275
|
+
let reachedMain = {
|
|
276
|
+
contents: false
|
|
277
|
+
};
|
|
278
|
+
let io_out = text => {
|
|
279
|
+
stdout.push(text);
|
|
280
|
+
};
|
|
281
|
+
let io_err = text => {
|
|
282
|
+
stderr.push(text);
|
|
283
|
+
};
|
|
284
|
+
let io_exit = code => {
|
|
285
|
+
exitCode.contents = code;
|
|
286
|
+
};
|
|
287
|
+
let io = {
|
|
288
|
+
out: io_out,
|
|
289
|
+
err: io_err,
|
|
290
|
+
exit: io_exit
|
|
291
|
+
};
|
|
292
|
+
await run(cli, argv, io, async param => {
|
|
293
|
+
reachedMain.contents = true;
|
|
294
|
+
});
|
|
295
|
+
return {
|
|
296
|
+
stdout: stdout,
|
|
297
|
+
stderr: stderr,
|
|
298
|
+
exitCode: exitCode.contents,
|
|
299
|
+
reachedMain: reachedMain.contents
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
let usageMistakeExit = 2;
|
|
304
|
+
|
|
305
|
+
export {
|
|
306
|
+
usageMistakeExit,
|
|
307
|
+
unknown,
|
|
308
|
+
extra,
|
|
309
|
+
flagShaped,
|
|
310
|
+
withoutLeadingTerminator,
|
|
311
|
+
parse,
|
|
312
|
+
string,
|
|
313
|
+
bool,
|
|
314
|
+
strings,
|
|
315
|
+
positionals,
|
|
316
|
+
pairs,
|
|
317
|
+
help,
|
|
318
|
+
atMost,
|
|
319
|
+
noPositionals,
|
|
320
|
+
asksForHelp,
|
|
321
|
+
processIo,
|
|
322
|
+
run,
|
|
323
|
+
observe,
|
|
324
|
+
}
|
|
325
|
+
/* node:util Not a pure module */
|