@lowlighter/run 3.0.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -13
- package/command.d.ts +138 -0
- package/command.js +332 -0
- package/mod.d.ts +1 -0
- package/mod.js +2 -0
- package/package.json +20 -20
- package/command.mjs +0 -1
- package/command.ts +0 -324
- package/command_test.ts +0 -127
- package/deno.jsonc +0 -82
- package/deno.lock +0 -95
- package/mod.mjs +0 -1
- package/mod.ts +0 -1
- package/mod_test.ts +0 -1
package/README.md
CHANGED
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
```ts
|
|
17
17
|
import { command } from "./command.ts"
|
|
18
18
|
|
|
19
|
-
// Commands are run asynchronously, and support Deno.
|
|
20
|
-
//
|
|
21
|
-
await command("deno", ["version"], { stdout: "
|
|
19
|
+
// Commands are run asynchronously, and support Deno.Command options alongside additional options
|
|
20
|
+
// Piped channels are captured into the result and mirrored to a LogTape sub-logger; you can also automatically append an extension when running on Windows
|
|
21
|
+
await command("deno", ["--version"], { stdout: "piped", stderr: "piped", winext: ".exe" })
|
|
22
22
|
|
|
23
23
|
// Commands can be run synchronously too, and can also throw an error automatically when the process exits with a non-zero code
|
|
24
|
-
command("deno", ["version"], { sync: true, throw: true })
|
|
24
|
+
command("deno", ["--version"], { sync: true, throw: true })
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
### Writing to stdin
|
|
@@ -31,15 +31,16 @@ import { command } from "./command.ts"
|
|
|
31
31
|
|
|
32
32
|
const { stdout } = await command("deno", ["repl"], {
|
|
33
33
|
env: { NO_COLOR: "true" },
|
|
34
|
-
// Passing a callback
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
// Passing a callback automatically pipes stdin.
|
|
35
|
+
// The callback is an async generator: `for await` over `stdio` to react to output,
|
|
36
|
+
// `yield` to write to stdin (verbatim — add your own newlines), and `return` to close it.
|
|
37
|
+
callback: async function* ({ stdio }) {
|
|
38
|
+
for await (const { stdout } of stdio) {
|
|
39
|
+
if (!stdout.includes("exit using"))
|
|
40
|
+
continue
|
|
41
|
+
yield "console.log('hello')\n"
|
|
38
42
|
return
|
|
39
43
|
}
|
|
40
|
-
await write("console.log('hello')")
|
|
41
|
-
await wait(1000)
|
|
42
|
-
close()
|
|
43
44
|
},
|
|
44
45
|
})
|
|
45
46
|
console.assert(stdout.includes("hello"))
|
|
@@ -47,12 +48,28 @@ console.assert(stdout.includes("hello"))
|
|
|
47
48
|
|
|
48
49
|
## ✨ Features
|
|
49
50
|
|
|
50
|
-
- Supports `stdin` interactivity through
|
|
51
|
-
-
|
|
51
|
+
- Supports `stdin` interactivity through an async generator callback.
|
|
52
|
+
- `for await` over process output, `yield` to write to stdin, `return` to close it.
|
|
52
53
|
- Auto-detects os and can automatically append an extension when running on Windows.
|
|
53
54
|
- Supports both `sync` and `async` modes in a single function.
|
|
54
55
|
- Optionally decide to throw an error when the process exits with a non-zero code.
|
|
56
|
+
- Background processes support `await using` for automatic cleanup (killed and awaited on scope exit).
|
|
55
57
|
- Generates a `stdio` history that contains timestamped entries with configurable buffering
|
|
58
|
+
- Integrates with [`LogTape`](https://logtape.org): each piped channel is mirrored to a sub-logger (`stdin`/`stdout`/`stderr`).
|
|
59
|
+
- Logging defaults to the `["run"]` category, leaving output configuration to the host application.
|
|
60
|
+
|
|
61
|
+
## 🕊️ Migrating from `3.x.x` to `4.x.x`
|
|
62
|
+
|
|
63
|
+
Version `4.x.x` replaces the [`@libs/logger`](https://jsr.io/@libs/logger) dependency with [`LogTape`](https://logtape.org) and reworks the stdin callback:
|
|
64
|
+
|
|
65
|
+
- The `logger` option is now a category (`string[]`) forwarded to `getLogger()`, defaulting to `["run"]`.
|
|
66
|
+
- As recommended for libraries, `command()` never calls `configure()` — the host application is in charge of setting up sinks and levels.
|
|
67
|
+
- Each channel is mirrored to a sub-logger: `stdin` at `debug`, `stdout` at `info`, `stderr` at `error`.
|
|
68
|
+
- The `stdin`, `stdout` and `stderr` options now only accept `"piped"`, `"inherit"` or `null` (log levels are no longer set per-channel).
|
|
69
|
+
- The `callback` option is now an **async generator** instead of a function:
|
|
70
|
+
- `for await (const { stdout } of stdio)` to react to output, `yield "text"` to write to stdin (verbatim, no automatic newline), and `return` to close it.
|
|
71
|
+
- The `write()`, `close()` and `wait()` helpers are gone — use `yield`, `return` and `await` respectively.
|
|
72
|
+
- If the generator throws, stdin is closed, the process is killed, and the result rejects with the error.
|
|
56
73
|
|
|
57
74
|
## 🕊️ Migrating from `2.x.x` to `3.x.x`
|
|
58
75
|
|
package/command.d.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import type { Nullable, Promisable } from "@lowlighter/typing";
|
|
2
|
+
import { type Logger } from "@logtape/logtape";
|
|
3
|
+
export type { Logger, Promisable };
|
|
4
|
+
/**
|
|
5
|
+
* Handling of a stdio channel.
|
|
6
|
+
* - `"piped"`: the channel is captured into the {@link Result} and mirrored to a {@link https://logtape.org | LogTape} sub-logger.
|
|
7
|
+
* - `"inherit"`: the channel is forwarded to the parent process.
|
|
8
|
+
* - `null`: the channel is discarded.
|
|
9
|
+
*/ export type Channel = Nullable<"piped" | "inherit">;
|
|
10
|
+
/** Run options. */ export type Options = {
|
|
11
|
+
/**
|
|
12
|
+
* Logger categories forwarded to {@link https://logtape.org | LogTape}'s `getLogger()`.
|
|
13
|
+
* Each channel is mirrored through a sub-category (`stdin`, `stdout`, `stderr`) so the host application can route or filter them.
|
|
14
|
+
* Defaults to `["run"]`.
|
|
15
|
+
*/ logger?: string[];
|
|
16
|
+
/** Environment variables. */ env?: Deno.CommandOptions["env"];
|
|
17
|
+
/** Current working directory. */ cwd?: Deno.CommandOptions["cwd"];
|
|
18
|
+
/** Raw arguments (Windows only). */ raw?: boolean;
|
|
19
|
+
/** Handling of stdin. */ stdin?: Channel;
|
|
20
|
+
/** Handling of stdout. */ stdout?: Channel;
|
|
21
|
+
/** Handling of stderr. */ stderr?: Channel;
|
|
22
|
+
/**
|
|
23
|
+
* Stdin interaction callback.
|
|
24
|
+
* Passing this option automatically pipes stdin.
|
|
25
|
+
* See {@link Callback} for the interaction protocol.
|
|
26
|
+
*/ callback?: Callback;
|
|
27
|
+
/**
|
|
28
|
+
* Stdio buffering.
|
|
29
|
+
* This is used to merge messages that are received relatively closely.
|
|
30
|
+
* Buffering is skipped when a different channel is used in-between.
|
|
31
|
+
*/ buffering?: number;
|
|
32
|
+
/** Abort signal. */ signal?: Deno.CommandOptions["signal"];
|
|
33
|
+
/**
|
|
34
|
+
* Execute process synchronously.
|
|
35
|
+
* Note that stdin is not usable in sync mode.
|
|
36
|
+
*/ sync?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Run process in background.
|
|
39
|
+
* This implies `sync: false`.
|
|
40
|
+
*/ background?: boolean;
|
|
41
|
+
/** Process extension on Windows. */ winext?: string;
|
|
42
|
+
/** Operating system. */ os?: typeof Deno.build.os;
|
|
43
|
+
/** Throw an error if exit code is non-zero rather than returning a result. */ throw?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Do not actually execute the command.
|
|
46
|
+
* In this case you will instead receive an empty successful result object.
|
|
47
|
+
*/ dryrun?: boolean;
|
|
48
|
+
};
|
|
49
|
+
/** Run result. */ export type Result = {
|
|
50
|
+
/** Whether the process exited with a zero-code. */ success: Deno.CommandStatus["success"];
|
|
51
|
+
/** Process exit code. */ code: Deno.CommandStatus["code"];
|
|
52
|
+
/**
|
|
53
|
+
* Process stdio content.
|
|
54
|
+
* First element is the delta timestamp since process start, second element is the channel (0:stdin, 1:stdout, 2:stderr), third element is the content.
|
|
55
|
+
*/ stdio: Array<[number, 0 | 1 | 2, string]>;
|
|
56
|
+
/** Process stdin content. */ stdin: string;
|
|
57
|
+
/** Process stdout content. */ stdout: string;
|
|
58
|
+
/** Process stderr content. */ stderr: string;
|
|
59
|
+
};
|
|
60
|
+
/** Handle to a process running in background. */ export type Background = {
|
|
61
|
+
/** Send a signal to the process (defaults to `"SIGTERM"`). */ kill: (signal?: Deno.Signal) => Promise<void>;
|
|
62
|
+
/** Prevent the process from keeping the parent process alive. */ unref: () => void;
|
|
63
|
+
/** Process identifier. */ pid: number;
|
|
64
|
+
/** Process result (resolves once the process exits). */ result: Promise<Result>;
|
|
65
|
+
/** Kill the process and wait for it to fully terminate. */ [Symbol.asyncDispose]: () => Promise<void>;
|
|
66
|
+
};
|
|
67
|
+
/** Snapshot of the accumulated process stdio content. */ export type Snapshot = Pick<Result, "stdin" | "stdout" | "stderr">;
|
|
68
|
+
/**
|
|
69
|
+
* Stdin interaction callback.
|
|
70
|
+
*
|
|
71
|
+
* It is an async generator that lets you drive an interactive process with plain language constructs:
|
|
72
|
+
* ```ts ignore
|
|
73
|
+
* // Iterate over process output to react to new data.
|
|
74
|
+
* // (one iteration per buffered event)
|
|
75
|
+
* for await (const { stdout } of stdio) {
|
|
76
|
+
* // Use await to pause or poll for a condition
|
|
77
|
+
* await delay(1000)
|
|
78
|
+
* // Use yield to write to stdin (verbatim)
|
|
79
|
+
* yield "content\n"
|
|
80
|
+
* // Use return to close stdin and end the interaction
|
|
81
|
+
* return
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* If the generator throws, stdin is closed, the process is killed and the returned {@link Result} rejects with the thrown error.
|
|
86
|
+
* When the process exits on its own, the `stdio` iterator ends, so a generator parked on `for await` completes naturally.
|
|
87
|
+
*/ export type Callback = (options: {
|
|
88
|
+
stdio: AsyncIterable<Snapshot>;
|
|
89
|
+
}) => AsyncGenerator<string, void, unknown>;
|
|
90
|
+
/**
|
|
91
|
+
* Asynchronous version of {@link command} running in background.
|
|
92
|
+
*
|
|
93
|
+
* ```ts
|
|
94
|
+
* import { command } from "./command.ts"
|
|
95
|
+
* const process = command("deno", ["eval", "Deno.exit(0)"], { background: true })
|
|
96
|
+
* await process.kill()
|
|
97
|
+
* ```
|
|
98
|
+
*/ export declare function command(bin: string, args: string[], options?: Options & {
|
|
99
|
+
sync?: false;
|
|
100
|
+
background: true;
|
|
101
|
+
}): Background;
|
|
102
|
+
/**
|
|
103
|
+
* Asynchronous version of {@link command}.
|
|
104
|
+
*
|
|
105
|
+
* ```ts
|
|
106
|
+
* import { command } from "./command.ts"
|
|
107
|
+
* try {
|
|
108
|
+
* await command("deno", ["eval", "Deno.exit(1)"], { throw: true })
|
|
109
|
+
* }
|
|
110
|
+
* catch (error) {
|
|
111
|
+
* console.log(error)
|
|
112
|
+
* }
|
|
113
|
+
* ```
|
|
114
|
+
*/ export declare function command(bin: string, args: string[], options?: Options & {
|
|
115
|
+
sync?: false;
|
|
116
|
+
background?: false;
|
|
117
|
+
}): Promise<Result>;
|
|
118
|
+
/**
|
|
119
|
+
* Synchronous version of {@link command}.
|
|
120
|
+
*
|
|
121
|
+
* Note that stdin is not usable in sync mode and will always be empty.
|
|
122
|
+
*
|
|
123
|
+
* ```ts
|
|
124
|
+
* import { command } from "./command.ts"
|
|
125
|
+
* command("deno", ["--version"], { sync: true })
|
|
126
|
+
* ```
|
|
127
|
+
* ```ts
|
|
128
|
+
* import { command } from "./command.ts"
|
|
129
|
+
* try {
|
|
130
|
+
* command("deno", ["eval", "Deno.exit(1)"], { sync: true, throw: true })
|
|
131
|
+
* }
|
|
132
|
+
* catch (error) {
|
|
133
|
+
* console.log(error)
|
|
134
|
+
* }
|
|
135
|
+
* ```
|
|
136
|
+
*/ export declare function command(bin: string, args: string[], options?: Options & {
|
|
137
|
+
sync: true;
|
|
138
|
+
}): Result;
|
package/command.js
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
// Imports
|
|
2
|
+
import { getLogger } from "@logtape/logtape";
|
|
3
|
+
import { TextLineStream } from "@std/streams";
|
|
4
|
+
import { debounce } from "@std/async/debounce";
|
|
5
|
+
/** Text encoder */ const encoder = new TextEncoder();
|
|
6
|
+
/** Text decoder */ const decoder = new TextDecoder();
|
|
7
|
+
/** Default interaction: an empty generator that closes stdin immediately. */ const noop = async function*() {};
|
|
8
|
+
/**
|
|
9
|
+
* Run a command.
|
|
10
|
+
*
|
|
11
|
+
* This is a wrapper around {@link https://docs.deno.com/api/deno/~/Deno.Command | Deno.Command} that provides a better handling of stdio for interactive processes.
|
|
12
|
+
*
|
|
13
|
+
* Like `Deno.Command`, the `env`, `cwd`, and `raw` (alias for `windowsRawArguments`) options are supported.
|
|
14
|
+
*
|
|
15
|
+
* The `stdin`, `stdout` and `stderr` options accept `"piped"` (captured into the result and mirrored to a {@link https://logtape.org | LogTape} sub-logger), `"inherit"` (forwarded to the parent process) or `null` (discarded).
|
|
16
|
+
*
|
|
17
|
+
* Logging is performed through {@link https://logtape.org | LogTape}.
|
|
18
|
+
* The `logger` option is a category forwarded to `getLogger()` (defaulting to `["run"]`), and each channel is mirrored through its own sub-category — `stdin` at `debug`, `stdout` at `info`, `stderr` at `error`.
|
|
19
|
+
* As recommended for libraries, `command()` never configures LogTape itself: the host application is in charge of the actual output (through {@link https://logtape.org/manual/config | LogTape configuration}).
|
|
20
|
+
*
|
|
21
|
+
* Set `winext` option to automatically append an extension to the binary path on Windows (like `.cmd` or `.exe`).
|
|
22
|
+
* This is useful when the binary path isn't automatically resolved on Windows.
|
|
23
|
+
*
|
|
24
|
+
* Pass a `callback` option (an async generator) to interact with the process stdin.
|
|
25
|
+
* See {@link Callback} for the interaction protocol: `for await` over `stdio` to read output, `yield` to write to stdin, `return` to close it.
|
|
26
|
+
*
|
|
27
|
+
* The `buffering` option is used to merge messages that are received relatively closely.
|
|
28
|
+
* Setting this option to a low value will also increase the rate at which the interaction generator is resumed.
|
|
29
|
+
*
|
|
30
|
+
* Resulting object contains the same properties as {@link https://docs.deno.com/api/deno/~/Deno.CommandStatus | Deno.CommandStatus}
|
|
31
|
+
* with an additional `stdio` property that contains an array of ordered tuples with the delta timestamp since process start, the channel idenfitier (0:stdin, 1:stdout, 2:stderr) and the content.
|
|
32
|
+
* This offers a proper history of exchanged content.
|
|
33
|
+
*
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { command } from "./command.ts"
|
|
36
|
+
* await command("deno", ["--version"], { env: { NO_COLOR: "true" }, cwd: "/tmp", raw: true })
|
|
37
|
+
* await command("deno", ["--version"], { stdout: "piped" })
|
|
38
|
+
* await command("deno", ["--version"], { logger: ["my-app", "run"], stdout: "piped" })
|
|
39
|
+
* await command("deno", ["--version"], { winext: ".exe" })
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { command } from "./command.ts"
|
|
44
|
+
*
|
|
45
|
+
* const { stdout } = await command("deno", ["repl"], {
|
|
46
|
+
* env: { NO_COLOR: "true" },
|
|
47
|
+
* // Passing a callback automatically pipes stdin.
|
|
48
|
+
* // Iterate `stdio` to react to output, `yield` to write to stdin (verbatim), `return` to close it.
|
|
49
|
+
* callback: async function* ({ stdio }) {
|
|
50
|
+
* for await (const { stdout } of stdio) {
|
|
51
|
+
* if (!stdout.includes("exit using")) {
|
|
52
|
+
* continue
|
|
53
|
+
* }
|
|
54
|
+
* yield "console.log('hello')\n"
|
|
55
|
+
* return
|
|
56
|
+
* }
|
|
57
|
+
* },
|
|
58
|
+
* })
|
|
59
|
+
* console.assert(stdout.includes("hello"))
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @author Simon Lecoq (lowlighter)
|
|
63
|
+
* @license MIT
|
|
64
|
+
* @module
|
|
65
|
+
*/ export function command(bin, args, { logger: category = [
|
|
66
|
+
"run"
|
|
67
|
+
], stdin = null, stdout = "piped", stderr = "piped", env, cwd, raw, callback, buffering, signal, sync, background, throw: _throw, dryrun, winext = "", os = Deno.build.os } = {}) {
|
|
68
|
+
if (os === "windows") bin = `${bin}${winext}`;
|
|
69
|
+
const log = getLogger(category).with({
|
|
70
|
+
bin
|
|
71
|
+
});
|
|
72
|
+
if (callback && handle(stdin) !== "piped") stdin = "piped";
|
|
73
|
+
const command1 = new Deno.Command(bin, {
|
|
74
|
+
args,
|
|
75
|
+
stdin: !sync ? handle(stdin) : "null",
|
|
76
|
+
stdout: handle(stdout),
|
|
77
|
+
stderr: handle(stderr),
|
|
78
|
+
clearEnv: true,
|
|
79
|
+
env,
|
|
80
|
+
cwd,
|
|
81
|
+
windowsRawArguments: raw,
|
|
82
|
+
signal,
|
|
83
|
+
detached: background
|
|
84
|
+
});
|
|
85
|
+
if (dryrun) {
|
|
86
|
+
log.warn("dryrun: {bin} not executed", {
|
|
87
|
+
bin
|
|
88
|
+
});
|
|
89
|
+
const result = {
|
|
90
|
+
success: true,
|
|
91
|
+
code: 0,
|
|
92
|
+
stdio: [],
|
|
93
|
+
stdin: "",
|
|
94
|
+
stdout: "",
|
|
95
|
+
stderr: ""
|
|
96
|
+
};
|
|
97
|
+
return sync ? result : Promise.resolve(result);
|
|
98
|
+
}
|
|
99
|
+
if (sync) return exec(command1, {
|
|
100
|
+
bin,
|
|
101
|
+
log,
|
|
102
|
+
throw: _throw,
|
|
103
|
+
stdout,
|
|
104
|
+
stderr
|
|
105
|
+
});
|
|
106
|
+
return spawn(command1, {
|
|
107
|
+
bin,
|
|
108
|
+
log,
|
|
109
|
+
callback,
|
|
110
|
+
buffering,
|
|
111
|
+
throw: _throw,
|
|
112
|
+
background,
|
|
113
|
+
stdin,
|
|
114
|
+
stdout,
|
|
115
|
+
stderr
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/** Returns the handle type for a given mode. */ function handle(mode) {
|
|
119
|
+
return [
|
|
120
|
+
"inherit",
|
|
121
|
+
"null"
|
|
122
|
+
].includes(`${mode}`) ? `${mode}` : "piped";
|
|
123
|
+
}
|
|
124
|
+
/** Execute a command synchronously. */ function exec(command, { bin, log, throw: _throw, stdout, stderr }) {
|
|
125
|
+
const start = Date.now();
|
|
126
|
+
const output = command.outputSync();
|
|
127
|
+
const { success, code } = output // Do not access stdout or stderr before "piped" status check
|
|
128
|
+
;
|
|
129
|
+
const t = Date.now() - start;
|
|
130
|
+
const stdio = {
|
|
131
|
+
get stdio () {
|
|
132
|
+
return [
|
|
133
|
+
[
|
|
134
|
+
t,
|
|
135
|
+
1,
|
|
136
|
+
this.stdout
|
|
137
|
+
],
|
|
138
|
+
[
|
|
139
|
+
t,
|
|
140
|
+
2,
|
|
141
|
+
this.stderr
|
|
142
|
+
]
|
|
143
|
+
];
|
|
144
|
+
},
|
|
145
|
+
stdin: "",
|
|
146
|
+
stdout: handle(stdout) === "piped" ? decoder.decode(output.stdout) : "",
|
|
147
|
+
stderr: handle(stderr) === "piped" ? decoder.decode(output.stderr) : ""
|
|
148
|
+
};
|
|
149
|
+
for (const { channel, mode } of [
|
|
150
|
+
{
|
|
151
|
+
channel: "stdout",
|
|
152
|
+
mode: stdout
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
channel: "stderr",
|
|
156
|
+
mode: stderr
|
|
157
|
+
}
|
|
158
|
+
]){
|
|
159
|
+
if (handle(mode) === "piped" && stdio[channel]) logged(log, channel, t, stdio[channel]);
|
|
160
|
+
}
|
|
161
|
+
if (!success && _throw) throw new EvalError(`${bin} exited with non-zero code ${code}:\n${stdio.stdout}\n${stdio.stderr}`);
|
|
162
|
+
return {
|
|
163
|
+
success,
|
|
164
|
+
code,
|
|
165
|
+
...stdio
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/** Spawn a command. */ function spawn(command, { bin, log, callback = noop, buffering = 250, throw: _throw, background, ...channels }) {
|
|
169
|
+
const process = command.spawn();
|
|
170
|
+
const start = Date.now();
|
|
171
|
+
const stdio = {
|
|
172
|
+
stdio: [],
|
|
173
|
+
get stdin () {
|
|
174
|
+
return this.stdio.filter(([_, i])=>i === 0).map(([_, __, content])=>content).join("");
|
|
175
|
+
},
|
|
176
|
+
get stdout () {
|
|
177
|
+
return this.stdio.filter(([_, i])=>i === 1).map(([_, __, content])=>content).join("\n");
|
|
178
|
+
},
|
|
179
|
+
get stderr () {
|
|
180
|
+
return this.stdio.filter(([_, i])=>i === 2).map(([_, __, content])=>content).join("\n");
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
let last = "";
|
|
184
|
+
// Drive the interaction generator when stdin is piped
|
|
185
|
+
let release = ()=>{};
|
|
186
|
+
let notify = null;
|
|
187
|
+
let pending = true;
|
|
188
|
+
let ended = false;
|
|
189
|
+
let interaction = Promise.resolve();
|
|
190
|
+
if (handle(channels.stdin) === "piped") {
|
|
191
|
+
const writer = process.stdin.getWriter();
|
|
192
|
+
const close = async ()=>{
|
|
193
|
+
try {
|
|
194
|
+
await writer.close();
|
|
195
|
+
log.with({
|
|
196
|
+
t: Date.now() - start
|
|
197
|
+
}).trace("closed stdin");
|
|
198
|
+
} catch {
|
|
199
|
+
// Ignore (stdin may already be closed if the process exited)
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
release = ()=>{
|
|
203
|
+
ended = true;
|
|
204
|
+
notify?.();
|
|
205
|
+
notify = null;
|
|
206
|
+
};
|
|
207
|
+
const input = {
|
|
208
|
+
async *[Symbol.asyncIterator] () {
|
|
209
|
+
while(true){
|
|
210
|
+
if (pending) {
|
|
211
|
+
pending = false;
|
|
212
|
+
yield stdio;
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (ended) return;
|
|
216
|
+
await new Promise((resolve)=>notify = resolve);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
interaction = (async ()=>{
|
|
221
|
+
const generator = callback({
|
|
222
|
+
stdio: input
|
|
223
|
+
});
|
|
224
|
+
try {
|
|
225
|
+
for await (const content of generator){
|
|
226
|
+
const t = Date.now() - start;
|
|
227
|
+
logged(log, "stdin", t, `${content}`);
|
|
228
|
+
stdio.stdio.push([
|
|
229
|
+
t,
|
|
230
|
+
0,
|
|
231
|
+
`${content}`
|
|
232
|
+
]);
|
|
233
|
+
await writer.write(encoder.encode(`${content}`));
|
|
234
|
+
last = "stdin";
|
|
235
|
+
}
|
|
236
|
+
await close();
|
|
237
|
+
} catch (error) {
|
|
238
|
+
await close();
|
|
239
|
+
abort(process);
|
|
240
|
+
await process.status;
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
243
|
+
})();
|
|
244
|
+
}
|
|
245
|
+
// Buffer output and resume the interaction generator
|
|
246
|
+
const debounced = debounce(()=>{
|
|
247
|
+
last = "";
|
|
248
|
+
pending = true;
|
|
249
|
+
notify?.();
|
|
250
|
+
notify = null;
|
|
251
|
+
}, buffering);
|
|
252
|
+
const outputs = Promise.all([
|
|
253
|
+
"stdout",
|
|
254
|
+
"stderr"
|
|
255
|
+
].filter((channel)=>handle(channels[channel]) === "piped").map(async (channel)=>{
|
|
256
|
+
for await (const line of process[channel].pipeThrough(new TextDecoderStream()).pipeThrough(new TextLineStream())){
|
|
257
|
+
const t = Date.now() - start;
|
|
258
|
+
const stdi = {
|
|
259
|
+
stdout: 1,
|
|
260
|
+
stderr: 2
|
|
261
|
+
}[channel];
|
|
262
|
+
logged(log, channel, t, line);
|
|
263
|
+
if (stdio.stdio.length && last === channel) {
|
|
264
|
+
const previous = stdio.stdio.at(-1);
|
|
265
|
+
if (previous[1] === stdi) previous[2] += `\n${line}`;
|
|
266
|
+
} else {
|
|
267
|
+
stdio.stdio.push([
|
|
268
|
+
t,
|
|
269
|
+
stdi,
|
|
270
|
+
line
|
|
271
|
+
]);
|
|
272
|
+
}
|
|
273
|
+
last = channel;
|
|
274
|
+
debounced();
|
|
275
|
+
}
|
|
276
|
+
}));
|
|
277
|
+
void outputs.then(release, release);
|
|
278
|
+
// Compute result
|
|
279
|
+
const result = (async ()=>{
|
|
280
|
+
const [output, interacted] = await Promise.allSettled([
|
|
281
|
+
outputs,
|
|
282
|
+
interaction
|
|
283
|
+
]);
|
|
284
|
+
debounced.clear();
|
|
285
|
+
const { success, code } = await process.status;
|
|
286
|
+
if (output.status === "rejected" || interacted.status === "rejected") throw output.reason ?? interacted.reason;
|
|
287
|
+
if (!success && _throw) throw new EvalError(`${bin} exited with non-zero code ${code}:\n${stdio.stdout}\n${stdio.stderr}`);
|
|
288
|
+
return {
|
|
289
|
+
success,
|
|
290
|
+
code,
|
|
291
|
+
...stdio
|
|
292
|
+
};
|
|
293
|
+
})();
|
|
294
|
+
const terminate = async (signal = "SIGTERM")=>{
|
|
295
|
+
abort(process, signal);
|
|
296
|
+
await result.catch(()=>{});
|
|
297
|
+
};
|
|
298
|
+
return background ? {
|
|
299
|
+
kill: terminate,
|
|
300
|
+
unref: ()=>process.unref(),
|
|
301
|
+
pid: process.pid,
|
|
302
|
+
result,
|
|
303
|
+
[Symbol.asyncDispose]: ()=>terminate()
|
|
304
|
+
} : result;
|
|
305
|
+
}
|
|
306
|
+
/** Send a signal to a process, ignoring the error raised when it has already terminated. */ function abort(process, signal = "SIGTERM") {
|
|
307
|
+
try {
|
|
308
|
+
process.kill(signal);
|
|
309
|
+
} catch {
|
|
310
|
+
// Already terminated
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/** Mirror a stdio line through the channel's sub-logger. */ function logged(log, channel, t, content) {
|
|
314
|
+
const logger = log.getChild(channel).with({
|
|
315
|
+
t
|
|
316
|
+
});
|
|
317
|
+
switch(channel){
|
|
318
|
+
case "stdin":
|
|
319
|
+
return void logger.debug("{content}", {
|
|
320
|
+
content
|
|
321
|
+
});
|
|
322
|
+
case "stdout":
|
|
323
|
+
return void logger.info("{content}", {
|
|
324
|
+
content
|
|
325
|
+
});
|
|
326
|
+
case "stderr":
|
|
327
|
+
return void logger.error("{content}", {
|
|
328
|
+
content
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9saWJzL2xpYnMvQGxpYnMvcnVuL2NvbW1hbmQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gSW1wb3J0c1xuaW1wb3J0IHR5cGUgeyBOdWxsYWJsZSwgUHJvbWlzYWJsZSB9IGZyb20gXCJAbGlicy90eXBpbmdcIlxuaW1wb3J0IHsgZ2V0TG9nZ2VyLCB0eXBlIExvZ2dlciB9IGZyb20gXCJAbG9ndGFwZS9sb2d0YXBlXCJcbmltcG9ydCB7IFRleHRMaW5lU3RyZWFtIH0gZnJvbSBcIkBzdGQvc3RyZWFtc1wiXG5pbXBvcnQgeyBkZWJvdW5jZSB9IGZyb20gXCJAc3RkL2FzeW5jL2RlYm91bmNlXCJcbmV4cG9ydCB0eXBlIHsgTG9nZ2VyLCBQcm9taXNhYmxlIH1cblxuLyoqXG4gKiBIYW5kbGluZyBvZiBhIHN0ZGlvIGNoYW5uZWwuXG4gKiAtIGBcInBpcGVkXCJgOiB0aGUgY2hhbm5lbCBpcyBjYXB0dXJlZCBpbnRvIHRoZSB7QGxpbmsgUmVzdWx0fSBhbmQgbWlycm9yZWQgdG8gYSB7QGxpbmsgaHR0cHM6Ly9sb2d0YXBlLm9yZyB8IExvZ1RhcGV9IHN1Yi1sb2dnZXIuXG4gKiAtIGBcImluaGVyaXRcImA6IHRoZSBjaGFubmVsIGlzIGZvcndhcmRlZCB0byB0aGUgcGFyZW50IHByb2Nlc3MuXG4gKiAtIGBudWxsYDogdGhlIGNoYW5uZWwgaXMgZGlzY2FyZGVkLlxuICovXG5leHBvcnQgdHlwZSBDaGFubmVsID0gTnVsbGFibGU8XCJwaXBlZFwiIHwgXCJpbmhlcml0XCI+XG5cbi8qKiBSdW4gb3B0aW9ucy4gKi9cbmV4cG9ydCB0eXBlIE9wdGlvbnMgPSB7XG4gIC8qKlxuICAgKiBMb2dnZXIgY2F0ZWdvcmllcyBmb3J3YXJkZWQgdG8ge0BsaW5rIGh0dHBzOi8vbG9ndGFwZS5vcmcgfCBMb2dUYXBlfSdzIGBnZXRMb2dnZXIoKWAuXG4gICAqIEVhY2ggY2hhbm5lbCBpcyBtaXJyb3JlZCB0aHJvdWdoIGEgc3ViLWNhdGVnb3J5IChgc3RkaW5gLCBgc3Rkb3V0YCwgYHN0ZGVycmApIHNvIHRoZSBob3N0IGFwcGxpY2F0aW9uIGNhbiByb3V0ZSBvciBmaWx0ZXIgdGhlbS5cbiAgICogRGVmYXVsdHMgdG8gYFtcInJ1blwiXWAuXG4gICAqL1xuICBsb2dnZXI/OiBzdHJpbmdbXVxuICAvKiogRW52aXJvbm1lbnQgdmFyaWFibGVzLiAqL1xuICBlbnY/OiBEZW5vLkNvbW1hbmRPcHRpb25zW1wiZW52XCJdXG4gIC8qKiBDdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5LiAqL1xuICBjd2Q/OiBEZW5vLkNvbW1hbmRPcHRpb25zW1wiY3dkXCJdXG4gIC8qKiBSYXcgYXJndW1lbnRzIChXaW5kb3dzIG9ubHkpLiAqL1xuICByYXc/OiBib29sZWFuXG4gIC8qKiBIYW5kbGluZyBvZiBzdGRpbi4gKi9cbiAgc3RkaW4/OiBDaGFubmVsXG4gIC8qKiBIYW5kbGluZyBvZiBzdGRvdXQuICovXG4gIHN0ZG91dD86IENoYW5uZWxcbiAgLyoqIEhhbmRsaW5nIG9mIHN0ZGVyci4gKi9cbiAgc3RkZXJyPzogQ2hhbm5lbFxuICAvKipcbiAgICogU3RkaW4gaW50ZXJhY3Rpb24gY2FsbGJhY2suXG4gICAqIFBhc3NpbmcgdGhpcyBvcHRpb24gYXV0b21hdGljYWxseSBwaXBlcyBzdGRpbi5cbiAgICogU2VlIHtAbGluayBDYWxsYmFja30gZm9yIHRoZSBpbnRlcmFjdGlvbiBwcm90b2NvbC5cbiAgICovXG4gIGNhbGxiYWNrPzogQ2FsbGJhY2tcbiAgLyoqXG4gICAqIFN0ZGlvIGJ1ZmZlcmluZy5cbiAgICogVGhpcyBpcyB1c2VkIHRvIG1lcmdlIG1lc3NhZ2VzIHRoYXQgYXJlIHJlY2VpdmVkIHJlbGF0aXZlbHkgY2xvc2VseS5cbiAgICogQnVmZmVyaW5nIGlzIHNraXBwZWQgd2hlbiBhIGRpZmZlcmVudCBjaGFubmVsIGlzIHVzZWQgaW4tYmV0d2Vlbi5cbiAgICovXG4gIGJ1ZmZlcmluZz86IG51bWJlclxuICAvKiogQWJvcnQgc2lnbmFsLiAqL1xuICBzaWduYWw/OiBEZW5vLkNvbW1hbmRPcHRpb25zW1wic2lnbmFsXCJdXG4gIC8qKlxuICAgKiBFeGVjdXRlIHByb2Nlc3Mgc3luY2hyb25vdXNseS5cbiAgICogTm90ZSB0aGF0IHN0ZGluIGlzIG5vdCB1c2FibGUgaW4gc3luYyBtb2RlLlxuICAgKi9cbiAgc3luYz86IGJvb2xlYW5cbiAgLyoqXG4gICAqIFJ1biBwcm9jZXNzIGluIGJhY2tncm91bmQuXG4gICAqIFRoaXMgaW1wbGllcyBgc3luYzogZmFsc2VgLlxuICAgKi9cbiAgYmFja2dyb3VuZD86IGJvb2xlYW5cbiAgLyoqIFByb2Nlc3MgZXh0ZW5zaW9uIG9uIFdpbmRvd3MuICovXG4gIHdpbmV4dD86IHN0cmluZ1xuICAvKiogT3BlcmF0aW5nIHN5c3RlbS4gKi9cbiAgb3M/OiB0eXBlb2YgRGVuby5idWlsZC5vc1xuICAvKiogVGhyb3cgYW4gZXJyb3IgaWYgZXhpdCBjb2RlIGlzIG5vbi16ZXJvIHJhdGhlciB0aGFuIHJldHVybmluZyBhIHJlc3VsdC4gKi9cbiAgdGhyb3c/OiBib29sZWFuXG4gIC8qKlxuICAgKiBEbyBub3QgYWN0dWFsbHkgZXhlY3V0ZSB0aGUgY29tbWFuZC5cbiAgICogSW4gdGhpcyBjYXNlIHlvdSB3aWxsIGluc3RlYWQgcmVjZWl2ZSBhbiBlbXB0eSBzdWNjZXNzZnVsIHJlc3VsdCBvYmplY3QuXG4gICAqL1xuICBkcnlydW4/OiBib29sZWFuXG59XG5cbi8qKiBSdW4gcmVzdWx0LiAqL1xuZXhwb3J0IHR5cGUgUmVzdWx0ID0ge1xuICAvKiogV2hldGhlciB0aGUgcHJvY2VzcyBleGl0ZWQgd2l0aCBhIHplcm8tY29kZS4gKi9cbiAgc3VjY2VzczogRGVuby5Db21tYW5kU3RhdHVzW1wic3VjY2Vzc1wiXVxuICAvKiogUHJvY2VzcyBleGl0IGNvZGUuICovXG4gIGNvZGU6IERlbm8uQ29tbWFuZFN0YXR1c1tcImNvZGVcIl1cbiAgLyoqXG4gICAqIFByb2Nlc3Mgc3RkaW8gY29udGVudC5cbiAgICogRmlyc3QgZWxlbWVudCBpcyB0aGUgZGVsdGEgdGltZXN0YW1wIHNpbmNlIHByb2Nlc3Mgc3RhcnQsIHNlY29uZCBlbGVtZW50IGlzIHRoZSBjaGFubmVsICgwOnN0ZGluLCAxOnN0ZG91dCwgMjpzdGRlcnIpLCB0aGlyZCBlbGVtZW50IGlzIHRoZSBjb250ZW50LlxuICAgKi9cbiAgc3RkaW86IEFycmF5PFtudW1iZXIsIDAgfCAxIHwgMiwgc3RyaW5nXT5cbiAgLyoqIFByb2Nlc3Mgc3RkaW4gY29udGVudC4gKi9cbiAgc3RkaW46IHN0cmluZ1xuICAvKiogUHJvY2VzcyBzdGRvdXQgY29udGVudC4gKi9cbiAgc3Rkb3V0OiBzdHJpbmdcbiAgLyoqIFByb2Nlc3Mgc3RkZXJyIGNvbnRlbnQuICovXG4gIHN0ZGVycjogc3RyaW5nXG59XG5cbi8qKiBIYW5kbGUgdG8gYSBwcm9jZXNzIHJ1bm5pbmcgaW4gYmFja2dyb3VuZC4gKi9cbmV4cG9ydCB0eXBlIEJhY2tncm91bmQgPSB7XG4gIC8qKiBTZW5kIGEgc2lnbmFsIHRvIHRoZSBwcm9jZXNzIChkZWZhdWx0cyB0byBgXCJTSUdURVJNXCJgKS4gKi9cbiAga2lsbDogKHNpZ25hbD86IERlbm8uU2lnbmFsKSA9PiBQcm9taXNlPHZvaWQ+XG4gIC8qKiBQcmV2ZW50IHRoZSBwcm9jZXNzIGZyb20ga2VlcGluZyB0aGUgcGFyZW50IHByb2Nlc3MgYWxpdmUuICovXG4gIHVucmVmOiAoKSA9PiB2b2lkXG4gIC8qKiBQcm9jZXNzIGlkZW50aWZpZXIuICovXG4gIHBpZDogbnVtYmVyXG4gIC8qKiBQcm9jZXNzIHJlc3VsdCAocmVzb2x2ZXMgb25jZSB0aGUgcHJvY2VzcyBleGl0cykuICovXG4gIHJlc3VsdDogUHJvbWlzZTxSZXN1bHQ+XG4gIC8qKiBLaWxsIHRoZSBwcm9jZXNzIGFuZCB3YWl0IGZvciBpdCB0byBmdWxseSB0ZXJtaW5hdGUuICovXG4gIFtTeW1ib2wuYXN5bmNEaXNwb3NlXTogKCkgPT4gUHJvbWlzZTx2b2lkPlxufVxuXG4vKiogU25hcHNob3Qgb2YgdGhlIGFjY3VtdWxhdGVkIHByb2Nlc3Mgc3RkaW8gY29udGVudC4gKi9cbmV4cG9ydCB0eXBlIFNuYXBzaG90ID0gUGljazxSZXN1bHQsIFwic3RkaW5cIiB8IFwic3Rkb3V0XCIgfCBcInN0ZGVyclwiPlxuXG4vKipcbiAqIFN0ZGluIGludGVyYWN0aW9uIGNhbGxiYWNrLlxuICpcbiAqIEl0IGlzIGFuIGFzeW5jIGdlbmVyYXRvciB0aGF0IGxldHMgeW91IGRyaXZlIGFuIGludGVyYWN0aXZlIHByb2Nlc3Mgd2l0aCBwbGFpbiBsYW5ndWFnZSBjb25zdHJ1Y3RzOlxuICogYGBgdHMgaWdub3JlXG4gKiAvLyBJdGVyYXRlIG92ZXIgcHJvY2VzcyBvdXRwdXQgdG8gcmVhY3QgdG8gbmV3IGRhdGEuXG4gKiAvLyAob25lIGl0ZXJhdGlvbiBwZXIgYnVmZmVyZWQgZXZlbnQpXG4gKiBmb3IgYXdhaXQgKGNvbnN0IHsgc3Rkb3V0IH0gb2Ygc3RkaW8pIHtcbiAqICAgLy8gVXNlIGF3YWl0IHRvIHBhdXNlIG9yIHBvbGwgZm9yIGEgY29uZGl0aW9uXG4gKiAgIGF3YWl0IGRlbGF5KDEwMDApXG4gKiAgIC8vIFVzZSB5aWVsZCB0byB3cml0ZSB0byBzdGRpbiAodmVyYmF0aW0pXG4gKiAgIHlpZWxkIFwiY29udGVudFxcblwiXG4gKiAgIC8vIFVzZSByZXR1cm4gdG8gY2xvc2Ugc3RkaW4gYW5kIGVuZCB0aGUgaW50ZXJhY3Rpb25cbiAqICAgcmV0dXJuXG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBJZiB0aGUgZ2VuZXJhdG9yIHRocm93cywgc3RkaW4gaXMgY2xvc2VkLCB0aGUgcHJvY2VzcyBpcyBraWxsZWQgYW5kIHRoZSByZXR1cm5lZCB7QGxpbmsgUmVzdWx0fSByZWplY3RzIHdpdGggdGhlIHRocm93biBlcnJvci5cbiAqIFdoZW4gdGhlIHByb2Nlc3MgZXhpdHMgb24gaXRzIG93biwgdGhlIGBzdGRpb2AgaXRlcmF0b3IgZW5kcywgc28gYSBnZW5lcmF0b3IgcGFya2VkIG9uIGBmb3IgYXdhaXRgIGNvbXBsZXRlcyBuYXR1cmFsbHkuXG4gKi9cbmV4cG9ydCB0eXBlIENhbGxiYWNrID0gKG9wdGlvbnM6IHsgc3RkaW86IEFzeW5jSXRlcmFibGU8U25hcHNob3Q+IH0pID0+IEFzeW5jR2VuZXJhdG9yPHN0cmluZywgdm9pZCwgdW5rbm93bj5cblxuLyoqIFRleHQgZW5jb2RlciAqL1xuY29uc3QgZW5jb2RlciA9IG5ldyBUZXh0RW5jb2RlcigpXG5cbi8qKiBUZXh0IGRlY29kZXIgKi9cbmNvbnN0IGRlY29kZXIgPSBuZXcgVGV4dERlY29kZXIoKVxuXG4vKiogRGVmYXVsdCBpbnRlcmFjdGlvbjogYW4gZW1wdHkgZ2VuZXJhdG9yIHRoYXQgY2xvc2VzIHN0ZGluIGltbWVkaWF0ZWx5LiAqL1xuY29uc3Qgbm9vcDogQ2FsbGJhY2sgPSBhc3luYyBmdW5jdGlvbiogKCkge31cblxuLyoqXG4gKiBBc3luY2hyb25vdXMgdmVyc2lvbiBvZiB7QGxpbmsgY29tbWFuZH0gcnVubmluZyBpbiBiYWNrZ3JvdW5kLlxuICpcbiAqIGBgYHRzXG4gKiBpbXBvcnQgeyBjb21tYW5kIH0gZnJvbSBcIi4vY29tbWFuZC50c1wiXG4gKiBjb25zdCBwcm9jZXNzID0gY29tbWFuZChcImRlbm9cIiwgW1wiZXZhbFwiLCBcIkRlbm8uZXhpdCgwKVwiXSwgeyBiYWNrZ3JvdW5kOiB0cnVlIH0pXG4gKiBhd2FpdCBwcm9jZXNzLmtpbGwoKVxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21tYW5kKGJpbjogc3RyaW5nLCBhcmdzOiBzdHJpbmdbXSwgb3B0aW9ucz86IE9wdGlvbnMgJiB7IHN5bmM/OiBmYWxzZTsgYmFja2dyb3VuZDogdHJ1ZSB9KTogQmFja2dyb3VuZFxuLyoqXG4gKiBBc3luY2hyb25vdXMgdmVyc2lvbiBvZiB7QGxpbmsgY29tbWFuZH0uXG4gKlxuICogYGBgdHNcbiAqIGltcG9ydCB7IGNvbW1hbmQgfSBmcm9tIFwiLi9jb21tYW5kLnRzXCJcbiAqIHRyeSB7XG4gKiAgIGF3YWl0IGNvbW1hbmQoXCJkZW5vXCIsIFtcImV2YWxcIiwgXCJEZW5vLmV4aXQoMSlcIl0sIHsgdGhyb3c6IHRydWUgfSlcbiAqIH1cbiAqIGNhdGNoIChlcnJvcikge1xuICogICBjb25zb2xlLmxvZyhlcnJvcilcbiAqIH1cbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tbWFuZChiaW46IHN0cmluZywgYXJnczogc3RyaW5nW10sIG9wdGlvbnM/OiBPcHRpb25zICYgeyBzeW5jPzogZmFsc2U7IGJhY2tncm91bmQ/OiBmYWxzZSB9KTogUHJvbWlzZTxSZXN1bHQ+XG4vKipcbiAqIFN5bmNocm9ub3VzIHZlcnNpb24gb2Yge0BsaW5rIGNvbW1hbmR9LlxuICpcbiAqIE5vdGUgdGhhdCBzdGRpbiBpcyBub3QgdXNhYmxlIGluIHN5bmMgbW9kZSBhbmQgd2lsbCBhbHdheXMgYmUgZW1wdHkuXG4gKlxuICogYGBgdHNcbiAqIGltcG9ydCB7IGNvbW1hbmQgfSBmcm9tIFwiLi9jb21tYW5kLnRzXCJcbiAqIGNvbW1hbmQoXCJkZW5vXCIsIFtcIi0tdmVyc2lvblwiXSwgeyBzeW5jOiB0cnVlIH0pXG4gKiBgYGBcbiAqIGBgYHRzXG4gKiBpbXBvcnQgeyBjb21tYW5kIH0gZnJvbSBcIi4vY29tbWFuZC50c1wiXG4gKiB0cnkge1xuICogICBjb21tYW5kKFwiZGVub1wiLCBbXCJldmFsXCIsIFwiRGVuby5leGl0KDEpXCJdLCB7IHN5bmM6IHRydWUsIHRocm93OiB0cnVlIH0pXG4gKiB9XG4gKiBjYXRjaCAoZXJyb3IpIHtcbiAqICAgY29uc29sZS5sb2coZXJyb3IpXG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbW1hbmQoYmluOiBzdHJpbmcsIGFyZ3M6IHN0cmluZ1tdLCBvcHRpb25zPzogT3B0aW9ucyAmIHsgc3luYzogdHJ1ZSB9KTogUmVzdWx0XG4vKipcbiAqIFJ1biBhIGNvbW1hbmQuXG4gKlxuICogVGhpcyBpcyBhIHdyYXBwZXIgYXJvdW5kIHtAbGluayBodHRwczovL2RvY3MuZGVuby5jb20vYXBpL2Rlbm8vfi9EZW5vLkNvbW1hbmQgfCBEZW5vLkNvbW1hbmR9IHRoYXQgcHJvdmlkZXMgYSBiZXR0ZXIgaGFuZGxpbmcgb2Ygc3RkaW8gZm9yIGludGVyYWN0aXZlIHByb2Nlc3Nlcy5cbiAqXG4gKiBMaWtlIGBEZW5vLkNvbW1hbmRgLCB0aGUgYGVudmAsIGBjd2RgLCBhbmQgYHJhd2AgKGFsaWFzIGZvciBgd2luZG93c1Jhd0FyZ3VtZW50c2ApIG9wdGlvbnMgYXJlIHN1cHBvcnRlZC5cbiAqXG4gKiBUaGUgYHN0ZGluYCwgYHN0ZG91dGAgYW5kIGBzdGRlcnJgIG9wdGlvbnMgYWNjZXB0IGBcInBpcGVkXCJgIChjYXB0dXJlZCBpbnRvIHRoZSByZXN1bHQgYW5kIG1pcnJvcmVkIHRvIGEge0BsaW5rIGh0dHBzOi8vbG9ndGFwZS5vcmcgfCBMb2dUYXBlfSBzdWItbG9nZ2VyKSwgYFwiaW5oZXJpdFwiYCAoZm9yd2FyZGVkIHRvIHRoZSBwYXJlbnQgcHJvY2Vzcykgb3IgYG51bGxgIChkaXNjYXJkZWQpLlxuICpcbiAqIExvZ2dpbmcgaXMgcGVyZm9ybWVkIHRocm91Z2gge0BsaW5rIGh0dHBzOi8vbG9ndGFwZS5vcmcgfCBMb2dUYXBlfS5cbiAqIFRoZSBgbG9nZ2VyYCBvcHRpb24gaXMgYSBjYXRlZ29yeSBmb3J3YXJkZWQgdG8gYGdldExvZ2dlcigpYCAoZGVmYXVsdGluZyB0byBgW1wicnVuXCJdYCksIGFuZCBlYWNoIGNoYW5uZWwgaXMgbWlycm9yZWQgdGhyb3VnaCBpdHMgb3duIHN1Yi1jYXRlZ29yeSDigJQgYHN0ZGluYCBhdCBgZGVidWdgLCBgc3Rkb3V0YCBhdCBgaW5mb2AsIGBzdGRlcnJgIGF0IGBlcnJvcmAuXG4gKiBBcyByZWNvbW1lbmRlZCBmb3IgbGlicmFyaWVzLCBgY29tbWFuZCgpYCBuZXZlciBjb25maWd1cmVzIExvZ1RhcGUgaXRzZWxmOiB0aGUgaG9zdCBhcHBsaWNhdGlvbiBpcyBpbiBjaGFyZ2Ugb2YgdGhlIGFjdHVhbCBvdXRwdXQgKHRocm91Z2gge0BsaW5rIGh0dHBzOi8vbG9ndGFwZS5vcmcvbWFudWFsL2NvbmZpZyB8IExvZ1RhcGUgY29uZmlndXJhdGlvbn0pLlxuICpcbiAqIFNldCBgd2luZXh0YCBvcHRpb24gdG8gYXV0b21hdGljYWxseSBhcHBlbmQgYW4gZXh0ZW5zaW9uIHRvIHRoZSBiaW5hcnkgcGF0aCBvbiBXaW5kb3dzIChsaWtlIGAuY21kYCBvciBgLmV4ZWApLlxuICogVGhpcyBpcyB1c2VmdWwgd2hlbiB0aGUgYmluYXJ5IHBhdGggaXNuJ3QgYXV0b21hdGljYWxseSByZXNvbHZlZCBvbiBXaW5kb3dzLlxuICpcbiAqIFBhc3MgYSBgY2FsbGJhY2tgIG9wdGlvbiAoYW4gYXN5bmMgZ2VuZXJhdG9yKSB0byBpbnRlcmFjdCB3aXRoIHRoZSBwcm9jZXNzIHN0ZGluLlxuICogU2VlIHtAbGluayBDYWxsYmFja30gZm9yIHRoZSBpbnRlcmFjdGlvbiBwcm90b2NvbDogYGZvciBhd2FpdGAgb3ZlciBgc3RkaW9gIHRvIHJlYWQgb3V0cHV0LCBgeWllbGRgIHRvIHdyaXRlIHRvIHN0ZGluLCBgcmV0dXJuYCB0byBjbG9zZSBpdC5cbiAqXG4gKiBUaGUgYGJ1ZmZlcmluZ2Agb3B0aW9uIGlzIHVzZWQgdG8gbWVyZ2UgbWVzc2FnZXMgdGhhdCBhcmUgcmVjZWl2ZWQgcmVsYXRpdmVseSBjbG9zZWx5LlxuICogU2V0dGluZyB0aGlzIG9wdGlvbiB0byBhIGxvdyB2YWx1ZSB3aWxsIGFsc28gaW5jcmVhc2UgdGhlIHJhdGUgYXQgd2hpY2ggdGhlIGludGVyYWN0aW9uIGdlbmVyYXRvciBpcyByZXN1bWVkLlxuICpcbiAqIFJlc3VsdGluZyBvYmplY3QgY29udGFpbnMgdGhlIHNhbWUgcHJvcGVydGllcyBhcyB7QGxpbmsgaHR0cHM6Ly9kb2NzLmRlbm8uY29tL2FwaS9kZW5vL34vRGVuby5Db21tYW5kU3RhdHVzIHwgRGVuby5Db21tYW5kU3RhdHVzfVxuICogd2l0aCBhbiBhZGRpdGlvbmFsIGBzdGRpb2AgcHJvcGVydHkgdGhhdCBjb250YWlucyBhbiBhcnJheSBvZiBvcmRlcmVkIHR1cGxlcyB3aXRoIHRoZSBkZWx0YSB0aW1lc3RhbXAgc2luY2UgcHJvY2VzcyBzdGFydCwgdGhlIGNoYW5uZWwgaWRlbmZpdGllciAoMDpzdGRpbiwgMTpzdGRvdXQsIDI6c3RkZXJyKSBhbmQgdGhlIGNvbnRlbnQuXG4gKiBUaGlzIG9mZmVycyBhIHByb3BlciBoaXN0b3J5IG9mIGV4Y2hhbmdlZCBjb250ZW50LlxuICpcbiAqIGBgYHRzXG4gKiBpbXBvcnQgeyBjb21tYW5kIH0gZnJvbSBcIi4vY29tbWFuZC50c1wiXG4gKiBhd2FpdCBjb21tYW5kKFwiZGVub1wiLCBbXCItLXZlcnNpb25cIl0sIHsgZW52OiB7IE5PX0NPTE9SOiBcInRydWVcIiB9LCBjd2Q6IFwiL3RtcFwiLCByYXc6IHRydWUgfSlcbiAqIGF3YWl0IGNvbW1hbmQoXCJkZW5vXCIsIFtcIi0tdmVyc2lvblwiXSwgeyBzdGRvdXQ6IFwicGlwZWRcIiB9KVxuICogYXdhaXQgY29tbWFuZChcImRlbm9cIiwgW1wiLS12ZXJzaW9uXCJdLCB7IGxvZ2dlcjogW1wibXktYXBwXCIsIFwicnVuXCJdLCBzdGRvdXQ6IFwicGlwZWRcIiB9KVxuICogYXdhaXQgY29tbWFuZChcImRlbm9cIiwgW1wiLS12ZXJzaW9uXCJdLCB7IHdpbmV4dDogXCIuZXhlXCIgfSlcbiAqIGBgYFxuICpcbiAqIGBgYHRzXG4gKiBpbXBvcnQgeyBjb21tYW5kIH0gZnJvbSBcIi4vY29tbWFuZC50c1wiXG4gKlxuICogY29uc3QgeyBzdGRvdXQgfSA9IGF3YWl0IGNvbW1hbmQoXCJkZW5vXCIsIFtcInJlcGxcIl0sIHtcbiAqICAgZW52OiB7IE5PX0NPTE9SOiBcInRydWVcIiB9LFxuICogICAvLyBQYXNzaW5nIGEgY2FsbGJhY2sgYXV0b21hdGljYWxseSBwaXBlcyBzdGRpbi5cbiAqICAgLy8gSXRlcmF0ZSBgc3RkaW9gIHRvIHJlYWN0IHRvIG91dHB1dCwgYHlpZWxkYCB0byB3cml0ZSB0byBzdGRpbiAodmVyYmF0aW0pLCBgcmV0dXJuYCB0byBjbG9zZSBpdC5cbiAqICAgY2FsbGJhY2s6IGFzeW5jIGZ1bmN0aW9uKiAoeyBzdGRpbyB9KSB7XG4gKiAgICAgZm9yIGF3YWl0IChjb25zdCB7IHN0ZG91dCB9IG9mIHN0ZGlvKSB7XG4gKiAgICAgICBpZiAoIXN0ZG91dC5pbmNsdWRlcyhcImV4aXQgdXNpbmdcIikpIHtcbiAqICAgICAgICAgY29udGludWVcbiAqICAgICAgIH1cbiAqICAgICAgIHlpZWxkIFwiY29uc29sZS5sb2coJ2hlbGxvJylcXG5cIlxuICogICAgICAgcmV0dXJuXG4gKiAgICAgfVxuICogICB9LFxuICogfSlcbiAqIGNvbnNvbGUuYXNzZXJ0KHN0ZG91dC5pbmNsdWRlcyhcImhlbGxvXCIpKVxuICogYGBgXG4gKlxuICogQGF1dGhvciBTaW1vbiBMZWNvcSAobG93bGlnaHRlcilcbiAqIEBsaWNlbnNlIE1JVFxuICogQG1vZHVsZVxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tbWFuZChcbiAgYmluOiBzdHJpbmcsXG4gIGFyZ3M6IHN0cmluZ1tdLFxuICB7IGxvZ2dlcjogY2F0ZWdvcnkgPSBbXCJydW5cIl0sIHN0ZGluID0gbnVsbCwgc3Rkb3V0ID0gXCJwaXBlZFwiLCBzdGRlcnIgPSBcInBpcGVkXCIsIGVudiwgY3dkLCByYXcsIGNhbGxiYWNrLCBidWZmZXJpbmcsIHNpZ25hbCwgc3luYywgYmFja2dyb3VuZCwgdGhyb3c6IF90aHJvdywgZHJ5cnVuLCB3aW5leHQgPSBcIlwiLCBvcyA9IERlbm8uYnVpbGQub3MgfSA9IHt9IGFzIE9wdGlvbnMsXG4pOiBQcm9taXNhYmxlPFJlc3VsdD4gfCBCYWNrZ3JvdW5kIHtcbiAgaWYgKG9zID09PSBcIndpbmRvd3NcIilcbiAgICBiaW4gPSBgJHtiaW59JHt3aW5leHR9YFxuICBjb25zdCBsb2cgPSBnZXRMb2dnZXIoY2F0ZWdvcnkpLndpdGgoeyBiaW4gfSlcbiAgaWYgKGNhbGxiYWNrICYmIChoYW5kbGUoc3RkaW4pICE9PSBcInBpcGVkXCIpKVxuICAgIHN0ZGluID0gXCJwaXBlZFwiXG4gIGNvbnN0IGNvbW1hbmQgPSBuZXcgRGVuby5Db21tYW5kKGJpbiwgeyBhcmdzLCBzdGRpbjogIXN5bmMgPyBoYW5kbGUoc3RkaW4pIDogXCJudWxsXCIsIHN0ZG91dDogaGFuZGxlKHN0ZG91dCksIHN0ZGVycjogaGFuZGxlKHN0ZGVyciksIGNsZWFyRW52OiB0cnVlLCBlbnYsIGN3ZCwgd2luZG93c1Jhd0FyZ3VtZW50czogcmF3LCBzaWduYWwsIGRldGFjaGVkOiBiYWNrZ3JvdW5kIH0pXG4gIGlmIChkcnlydW4pIHtcbiAgICBsb2cud2FybihcImRyeXJ1bjoge2Jpbn0gbm90IGV4ZWN1dGVkXCIsIHsgYmluIH0pXG4gICAgY29uc3QgcmVzdWx0ID0geyBzdWNjZXNzOiB0cnVlLCBjb2RlOiAwLCBzdGRpbzogW10sIHN0ZGluOiBcIlwiLCBzdGRvdXQ6IFwiXCIsIHN0ZGVycjogXCJcIiB9XG4gICAgcmV0dXJuIHN5bmMgPyByZXN1bHQgOiBQcm9taXNlLnJlc29sdmUocmVzdWx0KVxuICB9XG4gIGlmIChzeW5jKVxuICAgIHJldHVybiBleGVjKGNvbW1hbmQsIHsgYmluLCBsb2csIHRocm93OiBfdGhyb3csIHN0ZG91dCwgc3RkZXJyIH0pXG4gIHJldHVybiBzcGF3bihjb21tYW5kLCB7IGJpbiwgbG9nLCBjYWxsYmFjaywgYnVmZmVyaW5nLCB0aHJvdzogX3Rocm93LCBiYWNrZ3JvdW5kLCBzdGRpbiwgc3Rkb3V0LCBzdGRlcnIgfSlcbn1cblxuLyoqIFJldHVybnMgdGhlIGhhbmRsZSB0eXBlIGZvciBhIGdpdmVuIG1vZGUuICovXG5mdW5jdGlvbiBoYW5kbGUobW9kZTogQ2hhbm5lbCkge1xuICByZXR1cm4gW1wiaW5oZXJpdFwiLCBcIm51bGxcIl0uaW5jbHVkZXMoYCR7bW9kZX1gKSA/IGAke21vZGV9YCBhcyBcImluaGVyaXRcIiB8IFwibnVsbFwiIDogXCJwaXBlZFwiXG59XG5cbi8qKiBFeGVjdXRlIGEgY29tbWFuZCBzeW5jaHJvbm91c2x5LiAqL1xuZnVuY3Rpb24gZXhlYyhjb21tYW5kOiBEZW5vLkNvbW1hbmQsIHsgYmluLCBsb2csIHRocm93OiBfdGhyb3csIHN0ZG91dCwgc3RkZXJyIH06IHsgYmluOiBzdHJpbmc7IGxvZzogTG9nZ2VyOyB0aHJvdz86IGJvb2xlYW47IHN0ZG91dDogQ2hhbm5lbDsgc3RkZXJyOiBDaGFubmVsIH0pIHtcbiAgY29uc3Qgc3RhcnQgPSBEYXRlLm5vdygpXG4gIGNvbnN0IG91dHB1dCA9IGNvbW1hbmQub3V0cHV0U3luYygpXG4gIGNvbnN0IHsgc3VjY2VzcywgY29kZSB9ID0gb3V0cHV0IC8vIERvIG5vdCBhY2Nlc3Mgc3Rkb3V0IG9yIHN0ZGVyciBiZWZvcmUgXCJwaXBlZFwiIHN0YXR1cyBjaGVja1xuICBjb25zdCB0ID0gRGF0ZS5ub3coKSAtIHN0YXJ0XG4gIGNvbnN0IHN0ZGlvID0ge1xuICAgIGdldCBzdGRpbygpIHtcbiAgICAgIHJldHVybiBbW3QsIDEsIHRoaXMuc3Rkb3V0XSwgW3QsIDIsIHRoaXMuc3RkZXJyXV1cbiAgICB9LFxuICAgIHN0ZGluOiBcIlwiLFxuICAgIHN0ZG91dDogaGFuZGxlKHN0ZG91dCkgPT09IFwicGlwZWRcIiA/IGRlY29kZXIuZGVjb2RlKG91dHB1dC5zdGRvdXQpIDogXCJcIixcbiAgICBzdGRlcnI6IGhhbmRsZShzdGRlcnIpID09PSBcInBpcGVkXCIgPyBkZWNvZGVyLmRlY29kZShvdXRwdXQuc3RkZXJyKSA6IFwiXCIsXG4gIH0gYXMgU25hcHNob3QgJiBQaWNrPFJlc3VsdCwgXCJzdGRpb1wiPlxuICBmb3IgKGNvbnN0IHsgY2hhbm5lbCwgbW9kZSB9IG9mIFt7IGNoYW5uZWw6IFwic3Rkb3V0XCIsIG1vZGU6IHN0ZG91dCB9LCB7IGNoYW5uZWw6IFwic3RkZXJyXCIsIG1vZGU6IHN0ZGVyciB9XSBhcyBjb25zdCkge1xuICAgIGlmICgoaGFuZGxlKG1vZGUpID09PSBcInBpcGVkXCIpICYmIChzdGRpb1tjaGFubmVsXSkpXG4gICAgICBsb2dnZWQobG9nLCBjaGFubmVsLCB0LCBzdGRpb1tjaGFubmVsXSlcbiAgfVxuICBpZiAoKCFzdWNjZXNzKSAmJiBfdGhyb3cpXG4gICAgdGhyb3cgbmV3IEV2YWxFcnJvcihgJHtiaW59IGV4aXRlZCB3aXRoIG5vbi16ZXJvIGNvZGUgJHtjb2RlfTpcXG4ke3N0ZGlvLnN0ZG91dH1cXG4ke3N0ZGlvLnN0ZGVycn1gKVxuICByZXR1cm4geyBzdWNjZXNzLCBjb2RlLCAuLi5zdGRpbyB9XG59XG5cbi8qKiBTcGF3biBhIGNvbW1hbmQgYXN5bmNocm9ub3VzbHkgaW4gYmFja2dyb3VuZC4gKi9cbmZ1bmN0aW9uIHNwYXduKFxuICBjb21tYW5kOiBEZW5vLkNvbW1hbmQsXG4gIG9wdGlvbnM6IHsgYmluOiBzdHJpbmc7IGxvZzogTG9nZ2VyOyBjYWxsYmFjaz86IENhbGxiYWNrOyBidWZmZXJpbmc/OiBudW1iZXI7IHRocm93PzogYm9vbGVhbjsgYmFja2dyb3VuZDogdHJ1ZTsgc3RkaW46IENoYW5uZWw7IHN0ZG91dDogQ2hhbm5lbDsgc3RkZXJyOiBDaGFubmVsIH0sXG4pOiBCYWNrZ3JvdW5kXG4vKiogU3Bhd24gYSBjb21tYW5kIGFzeW5jaHJvbm91c2x5LiAqL1xuZnVuY3Rpb24gc3Bhd24oY29tbWFuZDogRGVuby5Db21tYW5kLCBvcHRpb25zOiB7IGJpbjogc3RyaW5nOyBsb2c6IExvZ2dlcjsgY2FsbGJhY2s/OiBDYWxsYmFjazsgYnVmZmVyaW5nPzogbnVtYmVyOyB0aHJvdz86IGJvb2xlYW47IGJhY2tncm91bmQ/OiBib29sZWFuOyBzdGRpbjogQ2hhbm5lbDsgc3Rkb3V0OiBDaGFubmVsOyBzdGRlcnI6IENoYW5uZWwgfSk6IFByb21pc2U8UmVzdWx0PlxuLyoqIFNwYXduIGEgY29tbWFuZC4gKi9cbmZ1bmN0aW9uIHNwYXduKFxuICBjb21tYW5kOiBEZW5vLkNvbW1hbmQsXG4gIHsgYmluLCBsb2csIGNhbGxiYWNrID0gbm9vcCwgYnVmZmVyaW5nID0gMjUwLCB0aHJvdzogX3Rocm93LCBiYWNrZ3JvdW5kLCAuLi5jaGFubmVscyB9OiB7XG4gICAgYmluOiBzdHJpbmdcbiAgICBsb2c6IExvZ2dlclxuICAgIGNhbGxiYWNrPzogQ2FsbGJhY2tcbiAgICBidWZmZXJpbmc/OiBudW1iZXJcbiAgICB0aHJvdz86IGJvb2xlYW5cbiAgICBiYWNrZ3JvdW5kPzogYm9vbGVhblxuICAgIHN0ZGluOiBDaGFubmVsXG4gICAgc3Rkb3V0OiBDaGFubmVsXG4gICAgc3RkZXJyOiBDaGFubmVsXG4gIH0sXG4pIHtcbiAgY29uc3QgcHJvY2VzcyA9IGNvbW1hbmQuc3Bhd24oKVxuICBjb25zdCBzdGFydCA9IERhdGUubm93KClcbiAgY29uc3Qgc3RkaW8gPSB7XG4gICAgc3RkaW86IFtdLFxuICAgIGdldCBzdGRpbigpIHtcbiAgICAgIHJldHVybiB0aGlzLnN0ZGlvLmZpbHRlcigoW18sIGldKSA9PiBpID09PSAwKS5tYXAoKFtfLCBfXywgY29udGVudF0pID0+IGNvbnRlbnQpLmpvaW4oXCJcIilcbiAgICB9LFxuICAgIGdldCBzdGRvdXQoKSB7XG4gICAgICByZXR1cm4gdGhpcy5zdGRpby5maWx0ZXIoKFtfLCBpXSkgPT4gaSA9PT0gMSkubWFwKChbXywgX18sIGNvbnRlbnRdKSA9PiBjb250ZW50KS5qb2luKFwiXFxuXCIpXG4gICAgfSxcbiAgICBnZXQgc3RkZXJyKCkge1xuICAgICAgcmV0dXJuIHRoaXMuc3RkaW8uZmlsdGVyKChbXywgaV0pID0+IGkgPT09IDIpLm1hcCgoW18sIF9fLCBjb250ZW50XSkgPT4gY29udGVudCkuam9pbihcIlxcblwiKVxuICAgIH0sXG4gIH0gYXMgU25hcHNob3QgJiBQaWNrPFJlc3VsdCwgXCJzdGRpb1wiPlxuICBsZXQgbGFzdCA9IFwiXCJcblxuICAvLyBEcml2ZSB0aGUgaW50ZXJhY3Rpb24gZ2VuZXJhdG9yIHdoZW4gc3RkaW4gaXMgcGlwZWRcbiAgbGV0IHJlbGVhc2UgPSAoKSA9PiB7fVxuICBsZXQgbm90aWZ5ID0gbnVsbCBhcyBOdWxsYWJsZTwoKSA9PiB2b2lkPlxuICBsZXQgcGVuZGluZyA9IHRydWVcbiAgbGV0IGVuZGVkID0gZmFsc2VcbiAgbGV0IGludGVyYWN0aW9uID0gUHJvbWlzZS5yZXNvbHZlKClcbiAgaWYgKGhhbmRsZShjaGFubmVscy5zdGRpbikgPT09IFwicGlwZWRcIikge1xuICAgIGNvbnN0IHdyaXRlciA9IHByb2Nlc3Muc3RkaW4uZ2V0V3JpdGVyKClcbiAgICBjb25zdCBjbG9zZSA9IGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHdyaXRlci5jbG9zZSgpXG4gICAgICAgIGxvZy53aXRoKHsgdDogRGF0ZS5ub3coKSAtIHN0YXJ0IH0pLnRyYWNlKFwiY2xvc2VkIHN0ZGluXCIpXG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8gSWdub3JlIChzdGRpbiBtYXkgYWxyZWFkeSBiZSBjbG9zZWQgaWYgdGhlIHByb2Nlc3MgZXhpdGVkKVxuICAgICAgfVxuICAgIH1cbiAgICByZWxlYXNlID0gKCkgPT4ge1xuICAgICAgZW5kZWQgPSB0cnVlXG4gICAgICBub3RpZnk/LigpXG4gICAgICBub3RpZnkgPSBudWxsXG4gICAgfVxuICAgIGNvbnN0IGlucHV0ID0ge1xuICAgICAgYXN5bmMgKltTeW1ib2wuYXN5bmNJdGVyYXRvcl0oKSB7XG4gICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgaWYgKHBlbmRpbmcpIHtcbiAgICAgICAgICAgIHBlbmRpbmcgPSBmYWxzZVxuICAgICAgICAgICAgeWllbGQgc3RkaW8gYXMgU25hcHNob3RcbiAgICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChlbmRlZClcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiBub3RpZnkgPSByZXNvbHZlKVxuICAgICAgICB9XG4gICAgICB9LFxuICAgIH1cbiAgICBpbnRlcmFjdGlvbiA9IChhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBnZW5lcmF0b3IgPSBjYWxsYmFjayh7IHN0ZGlvOiBpbnB1dCB9KVxuICAgICAgdHJ5IHtcbiAgICAgICAgZm9yIGF3YWl0IChjb25zdCBjb250ZW50IG9mIGdlbmVyYXRvcikge1xuICAgICAgICAgIGNvbnN0IHQgPSBEYXRlLm5vdygpIC0gc3RhcnRcbiAgICAgICAgICBsb2dnZWQobG9nLCBcInN0ZGluXCIsIHQsIGAke2NvbnRlbnR9YClcbiAgICAgICAgICBzdGRpby5zdGRpby5wdXNoKFt0LCAwLCBgJHtjb250ZW50fWBdKVxuICAgICAgICAgIGF3YWl0IHdyaXRlci53cml0ZShlbmNvZGVyLmVuY29kZShgJHtjb250ZW50fWApKVxuICAgICAgICAgIGxhc3QgPSBcInN0ZGluXCJcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCBjbG9zZSgpXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBhd2FpdCBjbG9zZSgpXG4gICAgICAgIGFib3J0KHByb2Nlc3MpXG4gICAgICAgIGF3YWl0IHByb2Nlc3Muc3RhdHVzXG4gICAgICAgIHRocm93IGVycm9yXG4gICAgICB9XG4gICAgfSkoKVxuICB9XG5cbiAgLy8gQnVmZmVyIG91dHB1dCBhbmQgcmVzdW1lIHRoZSBpbnRlcmFjdGlvbiBnZW5lcmF0b3JcbiAgY29uc3QgZGVib3VuY2VkID0gZGVib3VuY2UoKCkgPT4ge1xuICAgIGxhc3QgPSBcIlwiXG4gICAgcGVuZGluZyA9IHRydWVcbiAgICBub3RpZnk/LigpXG4gICAgbm90aWZ5ID0gbnVsbFxuICB9LCBidWZmZXJpbmcpXG4gIGNvbnN0IG91dHB1dHMgPSBQcm9taXNlLmFsbChcbiAgICAoW1wic3Rkb3V0XCIsIFwic3RkZXJyXCJdIGFzIGNvbnN0KS5maWx0ZXIoKGNoYW5uZWwpID0+IGhhbmRsZShjaGFubmVsc1tjaGFubmVsXSkgPT09IFwicGlwZWRcIikubWFwKGFzeW5jIChjaGFubmVsKSA9PiB7XG4gICAgICBmb3IgYXdhaXQgKGNvbnN0IGxpbmUgb2YgcHJvY2Vzc1tjaGFubmVsXS5waXBlVGhyb3VnaChuZXcgVGV4dERlY29kZXJTdHJlYW0oKSkucGlwZVRocm91Z2gobmV3IFRleHRMaW5lU3RyZWFtKCkpKSB7XG4gICAgICAgIGNvbnN0IHQgPSBEYXRlLm5vdygpIC0gc3RhcnRcbiAgICAgICAgY29uc3Qgc3RkaSA9IHsgc3Rkb3V0OiAxLCBzdGRlcnI6IDIgfVtjaGFubmVsXSBhcyAxIHwgMlxuICAgICAgICBsb2dnZWQobG9nLCBjaGFubmVsLCB0LCBsaW5lKVxuICAgICAgICBpZiAoKHN0ZGlvLnN0ZGlvLmxlbmd0aCkgJiYgKGxhc3QgPT09IGNoYW5uZWwpKSB7XG4gICAgICAgICAgY29uc3QgcHJldmlvdXMgPSBzdGRpby5zdGRpby5hdCgtMSkhXG4gICAgICAgICAgaWYgKHByZXZpb3VzWzFdID09PSBzdGRpKVxuICAgICAgICAgICAgcHJldmlvdXNbMl0gKz0gYFxcbiR7bGluZX1gXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc3RkaW8uc3RkaW8ucHVzaChbdCwgc3RkaSwgbGluZV0pXG4gICAgICAgIH1cbiAgICAgICAgbGFzdCA9IGNoYW5uZWxcbiAgICAgICAgZGVib3VuY2VkKClcbiAgICAgIH1cbiAgICB9KSxcbiAgKVxuICB2b2lkIG91dHB1dHMudGhlbihyZWxlYXNlLCByZWxlYXNlKVxuXG4gIC8vIENvbXB1dGUgcmVzdWx0XG4gIGNvbnN0IHJlc3VsdCA9IChhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgW291dHB1dCwgaW50ZXJhY3RlZF0gPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW291dHB1dHMsIGludGVyYWN0aW9uXSlcbiAgICBkZWJvdW5jZWQuY2xlYXIoKVxuICAgIGNvbnN0IHsgc3VjY2VzcywgY29kZSB9ID0gYXdhaXQgcHJvY2Vzcy5zdGF0dXNcbiAgICBpZiAoKG91dHB1dC5zdGF0dXMgPT09IFwicmVqZWN0ZWRcIikgfHwgKGludGVyYWN0ZWQuc3RhdHVzID09PSBcInJlamVjdGVkXCIpKVxuICAgICAgdGhyb3cgKChvdXRwdXQgYXMgeyByZWFzb24/OiB1bmtub3duIH0pLnJlYXNvbiA/PyAoaW50ZXJhY3RlZCBhcyB7IHJlYXNvbj86IHVua25vd24gfSkucmVhc29uKVxuICAgIGlmICgoIXN1Y2Nlc3MpICYmIF90aHJvdylcbiAgICAgIHRocm93IG5ldyBFdmFsRXJyb3IoYCR7YmlufSBleGl0ZWQgd2l0aCBub24temVybyBjb2RlICR7Y29kZX06XFxuJHtzdGRpby5zdGRvdXR9XFxuJHtzdGRpby5zdGRlcnJ9YClcbiAgICByZXR1cm4geyBzdWNjZXNzLCBjb2RlLCAuLi5zdGRpbyB9XG4gIH0pKClcbiAgY29uc3QgdGVybWluYXRlID0gYXN5bmMgKHNpZ25hbDogRGVuby5TaWduYWwgPSBcIlNJR1RFUk1cIikgPT4ge1xuICAgIGFib3J0KHByb2Nlc3MsIHNpZ25hbClcbiAgICBhd2FpdCByZXN1bHQuY2F0Y2goKCkgPT4ge30pXG4gIH1cbiAgcmV0dXJuIGJhY2tncm91bmRcbiAgICA/IHtcbiAgICAgIGtpbGw6IHRlcm1pbmF0ZSxcbiAgICAgIHVucmVmOiAoKSA9PiBwcm9jZXNzLnVucmVmKCksXG4gICAgICBwaWQ6IHByb2Nlc3MucGlkLFxuICAgICAgcmVzdWx0LFxuICAgICAgW1N5bWJvbC5hc3luY0Rpc3Bvc2VdOiAoKSA9PiB0ZXJtaW5hdGUoKSxcbiAgICB9XG4gICAgOiByZXN1bHRcbn1cblxuLyoqIFNlbmQgYSBzaWduYWwgdG8gYSBwcm9jZXNzLCBpZ25vcmluZyB0aGUgZXJyb3IgcmFpc2VkIHdoZW4gaXQgaGFzIGFscmVhZHkgdGVybWluYXRlZC4gKi9cbmZ1bmN0aW9uIGFib3J0KHByb2Nlc3M6IERlbm8uQ2hpbGRQcm9jZXNzLCBzaWduYWw6IERlbm8uU2lnbmFsID0gXCJTSUdURVJNXCIpIHtcbiAgdHJ5IHtcbiAgICBwcm9jZXNzLmtpbGwoc2lnbmFsKVxuICB9IGNhdGNoIHtcbiAgICAvLyBBbHJlYWR5IHRlcm1pbmF0ZWRcbiAgfVxufVxuXG4vKiogTWlycm9yIGEgc3RkaW8gbGluZSB0aHJvdWdoIHRoZSBjaGFubmVsJ3Mgc3ViLWxvZ2dlci4gKi9cbmZ1bmN0aW9uIGxvZ2dlZChsb2c6IExvZ2dlciwgY2hhbm5lbDogXCJzdGRpblwiIHwgXCJzdGRvdXRcIiB8IFwic3RkZXJyXCIsIHQ6IG51bWJlciwgY29udGVudDogc3RyaW5nKSB7XG4gIGNvbnN0IGxvZ2dlciA9IGxvZy5nZXRDaGlsZChjaGFubmVsKS53aXRoKHsgdCB9KVxuICBzd2l0Y2ggKGNoYW5uZWwpIHtcbiAgICBjYXNlIFwic3RkaW5cIjpcbiAgICAgIHJldHVybiB2b2lkIGxvZ2dlci5kZWJ1ZyhcIntjb250ZW50fVwiLCB7IGNvbnRlbnQgfSlcbiAgICBjYXNlIFwic3Rkb3V0XCI6XG4gICAgICByZXR1cm4gdm9pZCBsb2dnZXIuaW5mbyhcIntjb250ZW50fVwiLCB7IGNvbnRlbnQgfSlcbiAgICBjYXNlIFwic3RkZXJyXCI6XG4gICAgICByZXR1cm4gdm9pZCBsb2dnZXIuZXJyb3IoXCJ7Y29udGVudH1cIiwgeyBjb250ZW50IH0pXG4gIH1cbn1cbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxVQUFVO0FBRVYsU0FBUyxTQUFTLFFBQXFCLG1CQUFrQjtBQUN6RCxTQUFTLGNBQWMsUUFBUSxlQUFjO0FBQzdDLFNBQVMsUUFBUSxRQUFRLHNCQUFxQjtBQThIOUMsaUJBQWlCLEdBQ2pCLE1BQU0sVUFBVSxJQUFJO0FBRXBCLGlCQUFpQixHQUNqQixNQUFNLFVBQVUsSUFBSTtBQUVwQiwyRUFBMkUsR0FDM0UsTUFBTSxPQUFpQixtQkFBb0I7QUE4QzNDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Q0F5REMsR0FDRCxPQUFPLFNBQVMsUUFDZCxHQUFXLEVBQ1gsSUFBYyxFQUNkLEVBQUUsUUFBUSxXQUFXO0VBQUM7Q0FBTSxFQUFFLFFBQVEsSUFBSSxFQUFFLFNBQVMsT0FBTyxFQUFFLFNB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
|
package/mod.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./command.js";
|
package/mod.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export * from "./command.js";
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9saWJzL2xpYnMvQGxpYnMvcnVuL21vZC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tIFwiLi9jb21tYW5kLmpzXCJcbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLGVBQWMifQ==
|
package/package.json
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lowlighter/run",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"devDependencies": {},
|
|
8
|
-
"description": "Utilities to run subprocess.",
|
|
9
|
-
"keywords": [
|
|
10
|
-
"subprocess",
|
|
11
|
-
"esm"
|
|
12
|
-
],
|
|
13
|
-
"license": "MIT",
|
|
14
|
-
"author": "lowlighter (Simon Lecoq)",
|
|
15
|
-
"homepage": "https://github.com/lowlighter/libs",
|
|
16
|
-
"repository": {
|
|
17
|
-
"type": "git",
|
|
18
|
-
"url": "git+https://github.com/lowlighter/libs.git"
|
|
19
|
-
},
|
|
20
|
-
"funding": "https://github.com/sponsors/lowlighter",
|
|
5
|
+
"main": "./mod.js",
|
|
6
|
+
"types": "./mod.d.ts",
|
|
21
7
|
"exports": {
|
|
22
|
-
".":
|
|
23
|
-
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./mod.d.ts",
|
|
10
|
+
"import": "./mod.js",
|
|
11
|
+
"default": "./mod.js"
|
|
12
|
+
},
|
|
13
|
+
"./command": {
|
|
14
|
+
"types": "./command.d.ts",
|
|
15
|
+
"import": "./command.js",
|
|
16
|
+
"default": "./command.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@jsr/logtape__logtape": "^2.2.0",
|
|
21
|
+
"@jsr/std__async": "^1.2.0",
|
|
22
|
+
"@jsr/std__streams": "^1.0.17",
|
|
23
|
+
"@lowlighter/typing": "^4.1.0"
|
|
24
24
|
}
|
|
25
|
-
}
|
|
25
|
+
}
|