@swf2es/cli 0.0.0-stage → 0.1.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/LICENSE +202 -0
- package/LICENSE.third-party +389 -0
- package/README.md +32 -2
- package/dist/aot.d.ts +98 -0
- package/dist/aot.d.ts.map +1 -0
- package/dist/aot.js +145 -0
- package/dist/aot.js.map +1 -0
- package/dist/args.d.ts +31 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +37 -0
- package/dist/args.js.map +1 -0
- package/dist/commands/compile.d.ts +3 -0
- package/dist/commands/compile.d.ts.map +1 -0
- package/dist/commands/compile.js +233 -0
- package/dist/commands/compile.js.map +1 -0
- package/dist/commands/help.d.ts +6 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +52 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/run.d.ts +3 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +122 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/files.d.ts +10 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +35 -0
- package/dist/files.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +45 -0
- package/dist/main.js.map +1 -0
- package/dist/output.d.ts +7 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +20 -0
- package/dist/output.js.map +1 -0
- package/dist/shell-memories.d.ts +2 -0
- package/dist/shell-memories.d.ts.map +1 -0
- package/dist/shell-memories.js +32 -0
- package/dist/shell-memories.js.map +1 -0
- package/dist/shell-thread.d.ts +2 -0
- package/dist/shell-thread.d.ts.map +1 -0
- package/dist/shell-thread.js +49 -0
- package/dist/shell-thread.js.map +1 -0
- package/dist/shell-toplevel-library.d.ts +2 -0
- package/dist/shell-toplevel-library.d.ts.map +1 -0
- package/dist/shell-toplevel-library.js +22 -0
- package/dist/shell-toplevel-library.js.map +1 -0
- package/dist/shell.d.ts +62 -0
- package/dist/shell.d.ts.map +1 -0
- package/dist/shell.js +135 -0
- package/dist/shell.js.map +1 -0
- package/dist/threads.d.ts +85 -0
- package/dist/threads.d.ts.map +1 -0
- package/dist/threads.js +145 -0
- package/dist/threads.js.map +1 -0
- package/package.json +46 -3
- package/src/aot.ts +239 -0
- package/src/args.ts +53 -0
- package/src/commands/compile.ts +286 -0
- package/src/commands/help.ts +60 -0
- package/src/commands/run.ts +131 -0
- package/src/files.ts +38 -0
- package/src/index.ts +25 -0
- package/src/main.ts +51 -0
- package/src/output.ts +23 -0
- package/src/shell-memories.ts +35 -0
- package/src/shell-thread.ts +54 -0
- package/src/shell-toplevel-library.ts +28 -0
- package/src/shell.ts +211 -0
- package/src/threads.ts +223 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// swf2es run: ABCs run as avmshell runs them, each compiled by codegen and
|
|
2
|
+
// loaded into the runtime, their trace and print on stdout.
|
|
3
|
+
import { readFileSync, statSync, writeFileSync, writeSync } from "node:fs";
|
|
4
|
+
import { basename, extname, resolve } from "node:path";
|
|
5
|
+
import { parseArgs } from "node:util";
|
|
6
|
+
import { createCodegen } from "@swf2es/codegen";
|
|
7
|
+
import { builtinLibrary, createRuntime, type ShellFiles } from "@swf2es/runtime/avm2";
|
|
8
|
+
import { InputError, RejectedError, readInput } from "../aot.js";
|
|
9
|
+
import { COMMON_OPTIONS, COMMON_USAGE, type Command, parse } from "../args.js";
|
|
10
|
+
import { codegenModule, read, readLibraries } from "../files.js";
|
|
11
|
+
import { fail, usageError } from "../output.js";
|
|
12
|
+
import { runShell } from "../shell.js";
|
|
13
|
+
import { shellToplevelLibrary } from "../shell-toplevel-library.js";
|
|
14
|
+
import { nodeShellThreads } from "../threads.js";
|
|
15
|
+
|
|
16
|
+
const USAGE = `usage: swf2es run <file.abc> [more.abc ...] [options]
|
|
17
|
+
|
|
18
|
+
Runs ABCs as avmshell does: its libraries first, their scripts run on
|
|
19
|
+
first use, then each ABC in the order given, in one domain, its entry
|
|
20
|
+
point run once it loads. What they trace and print goes to stdout. An ABC
|
|
21
|
+
rejected with a VerifyError, or an exception nothing catches, is printed
|
|
22
|
+
there too, as avmshell prints it, and ends the run; the ABCs after it do
|
|
23
|
+
not run. avmshell's File reads and writes in the working directory, and
|
|
24
|
+
its workers run on threads of their own, stopped when the ABCs end.
|
|
25
|
+
|
|
26
|
+
options:
|
|
27
|
+
--lib <file.abc> a library to load first, into the root domain, in
|
|
28
|
+
the order given; repeat for each. Default:
|
|
29
|
+
avmshell's builtin.abc and shell_toplevel.abc,
|
|
30
|
+
which swf2es ships
|
|
31
|
+
${COMMON_USAGE}
|
|
32
|
+
|
|
33
|
+
exit status: 0 when every ABC ran to its end, 1 as avmshell's for a
|
|
34
|
+
VerifyError or an uncaught exception, 2 for a mistake in the command line,
|
|
35
|
+
and 1 for what stopped it besides (an unreadable input or library, a SWF,
|
|
36
|
+
a library rejected, an error of swf2es' own), said on stderr`;
|
|
37
|
+
|
|
38
|
+
/** avmshell's libraries, as its own build has them. */
|
|
39
|
+
const SHELL_LIBRARIES = [
|
|
40
|
+
{ name: "builtin", abc: builtinLibrary },
|
|
41
|
+
{ name: "shell_toplevel", abc: shellToplevelLibrary },
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const SWF_SIGNATURES = new Set(["FWS", "CWS", "ZWS"]);
|
|
45
|
+
|
|
46
|
+
const OPTIONS = {
|
|
47
|
+
lib: { type: "string", multiple: true },
|
|
48
|
+
...COMMON_OPTIONS,
|
|
49
|
+
} as const;
|
|
50
|
+
|
|
51
|
+
/** avmshell's File: the working directory's files, as it reads and writes them. */
|
|
52
|
+
function workingFiles(): ShellFiles {
|
|
53
|
+
return {
|
|
54
|
+
read(name) {
|
|
55
|
+
// One it cannot open, unreadable or a directory, avmshell's File cannot
|
|
56
|
+
// open either: Error #1500 for the ABC to catch, not swf2es failing.
|
|
57
|
+
try {
|
|
58
|
+
const path = resolve(name);
|
|
59
|
+
return statSync(path).isFile() ? new Uint8Array(readFileSync(path)) : null;
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
write(name, bytes) {
|
|
65
|
+
try {
|
|
66
|
+
writeFileSync(resolve(name), bytes);
|
|
67
|
+
return true;
|
|
68
|
+
} catch {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const run: Command = {
|
|
76
|
+
name: "run",
|
|
77
|
+
summary: "run ABCs as avmshell does, printing what they trace",
|
|
78
|
+
usage: USAGE,
|
|
79
|
+
async main(argv) {
|
|
80
|
+
const parsed = parse(run, () =>
|
|
81
|
+
parseArgs({ args: argv, allowPositionals: true, options: OPTIONS }),
|
|
82
|
+
);
|
|
83
|
+
if (!parsed) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const { values, positionals } = parsed;
|
|
88
|
+
if (positionals.length === 0) {
|
|
89
|
+
usageError("expected an ABC file to run", "run");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const abcs: { name: string; abc: Uint8Array }[] = [];
|
|
93
|
+
for (const file of positionals) {
|
|
94
|
+
const abc = await read(file, "input");
|
|
95
|
+
if (SWF_SIGNATURES.has(String.fromCharCode(...abc.subarray(0, 3)))) {
|
|
96
|
+
fail(`${file}: a SWF; run takes ABCs, as a SWF's code needs the player's playerglobal`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
readInput(abc);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
fail(e instanceof InputError ? `${file}: ${e.message}` : String(e));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
abcs.push({ name: basename(file, extname(file)), abc });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const libs = values.lib ? await readLibraries(values.lib) : SHELL_LIBRARIES;
|
|
109
|
+
const codegen = await codegenModule();
|
|
110
|
+
const compiler = await createCodegen(codegen);
|
|
111
|
+
// A line at a time, as avmshell's console writes it; its workers' threads write their own.
|
|
112
|
+
const print = (line: string) => writeSync(1, `${line}\n`);
|
|
113
|
+
const threads = nodeShellThreads({ codegen, libraries: libs, abcs });
|
|
114
|
+
try {
|
|
115
|
+
process.exitCode = await runShell(libs, abcs, {
|
|
116
|
+
compiler,
|
|
117
|
+
createRuntime,
|
|
118
|
+
print,
|
|
119
|
+
files: workingFiles(),
|
|
120
|
+
workers: threads.host,
|
|
121
|
+
});
|
|
122
|
+
await threads.close();
|
|
123
|
+
} catch (e) {
|
|
124
|
+
if (e instanceof RejectedError) {
|
|
125
|
+
fail(e.message);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
fail(`swf2es itself failed: ${(e as Error).stack ?? e}`);
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
};
|
package/src/files.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Reading the commands' inputs and writing their outputs, a failure said
|
|
2
|
+
// as such rather than as a stack.
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { basename, extname } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { fail } from "./output.js";
|
|
7
|
+
|
|
8
|
+
export async function read(path: string, what: string): Promise<Uint8Array> {
|
|
9
|
+
try {
|
|
10
|
+
return new Uint8Array(await readFile(path));
|
|
11
|
+
} catch (e) {
|
|
12
|
+
fail(`cannot read ${what} ${path}: ${(e as NodeJS.ErrnoException).code ?? e}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function writing(path: string, write: () => Promise<unknown>): Promise<void> {
|
|
17
|
+
try {
|
|
18
|
+
await write();
|
|
19
|
+
} catch (e) {
|
|
20
|
+
fail(`cannot write ${path}: ${(e as NodeJS.ErrnoException).code ?? e}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** The libraries at `paths`, read, each named by its file. */
|
|
25
|
+
export function readLibraries(paths: string[]): Promise<{ name: string; abc: Uint8Array }[]> {
|
|
26
|
+
return Promise.all(
|
|
27
|
+
paths.map(async (path) => ({
|
|
28
|
+
name: basename(path, extname(path)),
|
|
29
|
+
abc: await read(path, "library"),
|
|
30
|
+
})),
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The release codegen.wasm, compiled. */
|
|
35
|
+
export async function codegenModule(): Promise<WebAssembly.Module> {
|
|
36
|
+
const path = fileURLToPath(import.meta.resolve("@swf2es/codegen/codegen.wasm"));
|
|
37
|
+
return WebAssembly.compile(await readFile(path));
|
|
38
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** The ahead-of-time compiler and avmshell's way of running ABCs as a library, for a host that does without the command. */
|
|
2
|
+
export {
|
|
3
|
+
type AbcInput,
|
|
4
|
+
type ActionsModule,
|
|
5
|
+
AIR_API_VERSION,
|
|
6
|
+
API_VERSION,
|
|
7
|
+
type Avm1Input,
|
|
8
|
+
compileActionsAhead,
|
|
9
|
+
compileAhead,
|
|
10
|
+
type Input,
|
|
11
|
+
type Module,
|
|
12
|
+
RejectedError,
|
|
13
|
+
readInput,
|
|
14
|
+
sha256,
|
|
15
|
+
} from "./aot.js";
|
|
16
|
+
export {
|
|
17
|
+
evaluateModule,
|
|
18
|
+
runShell,
|
|
19
|
+
type ShellCompiler,
|
|
20
|
+
type ShellLibrary,
|
|
21
|
+
type ShellModule,
|
|
22
|
+
type ShellOptions,
|
|
23
|
+
shellDomain,
|
|
24
|
+
} from "./shell.js";
|
|
25
|
+
export { nodeShellThreads, type ShellThreads, type ShellThreadsOptions } from "./threads.js";
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The swf2es command: the first argument names a command, and any other
|
|
3
|
+
// first argument is compile's input, as before there were commands.
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { printVersion } from "./args.js";
|
|
6
|
+
import { compile } from "./commands/compile.js";
|
|
7
|
+
import { commands, usage } from "./commands/help.js";
|
|
8
|
+
import { USAGE_ERROR, usageError } from "./output.js";
|
|
9
|
+
|
|
10
|
+
async function main(argv: string[]): Promise<void> {
|
|
11
|
+
const [first, ...rest] = argv;
|
|
12
|
+
const command = commands.get(first);
|
|
13
|
+
if (command) {
|
|
14
|
+
await command.main(rest);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
switch (first) {
|
|
19
|
+
case undefined:
|
|
20
|
+
process.stderr.write(`${usage()}\n`);
|
|
21
|
+
process.exitCode = USAGE_ERROR;
|
|
22
|
+
return;
|
|
23
|
+
case "-h":
|
|
24
|
+
case "--help":
|
|
25
|
+
if (rest.length === 0) {
|
|
26
|
+
console.log(usage());
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
break;
|
|
31
|
+
case "-v":
|
|
32
|
+
case "--version":
|
|
33
|
+
if (rest.length === 0) {
|
|
34
|
+
printVersion();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// An option before the input, as `swf2es -o dir file.swf`, is compile's
|
|
42
|
+
// too; a word that is no command nor a file is taken for a mistyped command.
|
|
43
|
+
if (first.startsWith("-") || /[./\\]/.test(first) || existsSync(first)) {
|
|
44
|
+
await compile.main(argv);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
usageError(`no command ${first}; to compile a file of that name, swf2es compile ${first}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
await main(process.argv.slice(2));
|
package/src/output.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// What the command says about itself on stderr. styleText colours only a
|
|
2
|
+
// terminal that takes colour: not with NO_COLOR, nor when stderr is a pipe
|
|
3
|
+
// or a file, unless FORCE_COLOR asks.
|
|
4
|
+
import { styleText } from "node:util";
|
|
5
|
+
|
|
6
|
+
/** The exit status for a mistake in how the command was run. */
|
|
7
|
+
export const USAGE_ERROR = 2;
|
|
8
|
+
|
|
9
|
+
/** Say what went wrong, and a hint on another line if there is one, and exit. */
|
|
10
|
+
export function fail(message: string, status = 1, hint?: string): never {
|
|
11
|
+
const head = styleText(["bold", "red"], "error:", { stream: process.stderr });
|
|
12
|
+
process.stderr.write(`swf2es: ${head} ${message}\n`);
|
|
13
|
+
if (hint) {
|
|
14
|
+
process.stderr.write(`${styleText("dim", hint, { stream: process.stderr })}\n`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
process.exit(status);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** A mistake in the command line, with where to read how to run it. */
|
|
21
|
+
export function usageError(message: string, command?: string): never {
|
|
22
|
+
fail(message, USAGE_ERROR, `run swf2es help${command ? ` ${command}` : ""} for usage`);
|
|
23
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// The shared memory of a primordial's threads, kept by a thread of its own
|
|
2
|
+
// (threads.ts): every shareable ByteArray's memory a thread shares is
|
|
3
|
+
// posted on the group's BroadcastChannel, which this thread, its event
|
|
4
|
+
// loop always free, keeps, and answers a thread that asks for one it
|
|
5
|
+
// missed, as one does that was still starting when the memory was shared.
|
|
6
|
+
import { workerData } from "node:worker_threads";
|
|
7
|
+
import type { SharedBytesMemory } from "@swf2es/runtime/avm2";
|
|
8
|
+
import type { MemoriesData, MemoryMessage } from "./threads.js";
|
|
9
|
+
|
|
10
|
+
const { group, memories: seen, ready } = workerData as MemoriesData;
|
|
11
|
+
const memories = new Map<number, SharedBytesMemory>(seen.map((m) => [m.id, m]));
|
|
12
|
+
const channel = new BroadcastChannel(group);
|
|
13
|
+
channel.onmessage = (event) => {
|
|
14
|
+
const message = (event as unknown as { data: MemoryMessage }).data;
|
|
15
|
+
switch (message.type) {
|
|
16
|
+
case "memory":
|
|
17
|
+
memories.set(message.memory.id, message.memory);
|
|
18
|
+
break;
|
|
19
|
+
case "ask":
|
|
20
|
+
channel.postMessage({
|
|
21
|
+
type: "answer",
|
|
22
|
+
id: message.id,
|
|
23
|
+
memory: memories.get(message.id) ?? null,
|
|
24
|
+
} satisfies MemoryMessage);
|
|
25
|
+
Atomics.store(message.answered, 0, 1);
|
|
26
|
+
Atomics.notify(message.answered, 0);
|
|
27
|
+
break;
|
|
28
|
+
case "answer":
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Subscribed: the threads may start.
|
|
34
|
+
Atomics.store(ready, 0, 1);
|
|
35
|
+
Atomics.notify(ready, 0);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// A background worker's thread (threads.ts): its ABCs, or the primordial's,
|
|
2
|
+
// run after the libraries as runShell runs them, in a runtime that is the
|
|
3
|
+
// worker's; the workers it starts run on threads of its own, which it waits
|
|
4
|
+
// for once its code ends, as they outlive it in avmshell.
|
|
5
|
+
import { writeSync } from "node:fs";
|
|
6
|
+
import { parentPort, workerData } from "node:worker_threads";
|
|
7
|
+
import { createCodegen } from "@swf2es/codegen";
|
|
8
|
+
import {
|
|
9
|
+
createRuntime,
|
|
10
|
+
endShellWorker,
|
|
11
|
+
shellWorkerTerminated,
|
|
12
|
+
startShellWorker,
|
|
13
|
+
} from "@swf2es/runtime/avm2";
|
|
14
|
+
import { runShell } from "./shell.js";
|
|
15
|
+
import { nodeShellThreads, type ShellThreadData } from "./threads.js";
|
|
16
|
+
|
|
17
|
+
const { codegen, libraries, abcs, init, post, group, memories, apiVersion } =
|
|
18
|
+
workerData as ShellThreadData;
|
|
19
|
+
const print = post
|
|
20
|
+
? (line: string) => parentPort?.postMessage(line)
|
|
21
|
+
: (line: string) => writeSync(1, `${line}\n`);
|
|
22
|
+
|
|
23
|
+
if (startShellWorker(init)) {
|
|
24
|
+
const threads = nodeShellThreads({
|
|
25
|
+
codegen,
|
|
26
|
+
libraries,
|
|
27
|
+
abcs,
|
|
28
|
+
group,
|
|
29
|
+
memories,
|
|
30
|
+
apiVersion,
|
|
31
|
+
...(post ? { print } : {}),
|
|
32
|
+
});
|
|
33
|
+
let exception = true;
|
|
34
|
+
try {
|
|
35
|
+
const code = init.code ? [{ name: `worker-${init.id}`, abc: init.code }] : abcs;
|
|
36
|
+
const exitCode = await runShell(libraries, code, {
|
|
37
|
+
compiler: await createCodegen(codegen),
|
|
38
|
+
createRuntime,
|
|
39
|
+
print,
|
|
40
|
+
workers: threads.host,
|
|
41
|
+
worker: init,
|
|
42
|
+
apiVersion,
|
|
43
|
+
});
|
|
44
|
+
exception = exitCode !== 0;
|
|
45
|
+
} catch (e) {
|
|
46
|
+
// Terminated by another worker, its code stops where it was.
|
|
47
|
+
if (!shellWorkerTerminated(init)) {
|
|
48
|
+
print(`swf2es: a background worker failed: ${(e as Error).stack ?? e}`);
|
|
49
|
+
}
|
|
50
|
+
} finally {
|
|
51
|
+
endShellWorker(init, exception);
|
|
52
|
+
await threads.ended();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// avmplus' shell_toplevel.abc: avmshell's own classes, which `swf2es run` loads after builtin.
|
|
2
|
+
// Generated by tools/avmplus-libraries.ts --update; not to be edited.
|
|
3
|
+
//
|
|
4
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
|
+
//
|
|
8
|
+
// Its source form is the ActionScript in shell/ and extensions/ (Sampler.as, Trace.as)
|
|
9
|
+
// of avmplus, https://github.com/swf2es/avmplus at commit
|
|
10
|
+
// 858d034a3bd3a54d9b70909386435cf4aec81d21,
|
|
11
|
+
// which shell/shell_toplevel.py compiles into generated/shell_toplevel.abc.
|
|
12
|
+
|
|
13
|
+
declare function atob(data: string): string;
|
|
14
|
+
|
|
15
|
+
/** Base64 to bytes with a plain loop: Uint8Array.from with a callback takes some 8 times as long. */
|
|
16
|
+
function decode(text: string): Uint8Array {
|
|
17
|
+
const raw = atob(text);
|
|
18
|
+
const bytes = new Uint8Array(raw.length);
|
|
19
|
+
for (let i = 0; i < raw.length; i++) {
|
|
20
|
+
bytes[i] = raw.charCodeAt(i);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return bytes;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const shellToplevelLibrary: Uint8Array = decode(
|
|
27
|
+
"EAAuAAgqZQACAQMEAAgAAAAAAADoPwAAAAAAAPA/AAAAAAAAAEAAAAAAAAAIQAAAAAAAABBAAAAAAAAAFEAAAAAAAAAYQKUDAAR2b2lkB0Jvb2xlYW4GU3lzdGVtE3NoZWxsX3RvcGxldmVsLmFzJDEHYXZtcGx1cwVkZW9wdAhyZWFkTGluZQZTdHJpbmcIZ2V0VGltZXIEdWludAV0cmFjZQZEb21haW4NY3VycmVudERvbWFpbghnZXRDbGFzcwVDbGFzcwhkZWJ1Z2dlcg1hdm1wbHVzOklUZXN0BHRlc3QFSVRlc3QNYXZtcGx1czpDVGVzdAPuipQFQ1Rlc3QGT2JqZWN0CmF2bXBsdXM6TUkGTnVtYmVyBHBsdXMCTUkOYXZtcGx1czpTeXN0ZW0EYXJndgdnZXRBcmd2A2ludAVBcnJheQNYTUwLX19BUzNfXy52ZWMGVmVjdG9yCEZ1bmN0aW9uBGV4aXQDZm9vBGV4ZWMDYmFyBGF0dHIId2hhdGV2ZXIFc2xlZXARZ2V0QXZtcGx1c1ZlcnNpb24LZ2V0RmVhdHVyZXMKZ2V0UnVubW9kZQV3cml0ZQppc0RlYnVnZ2VyEmdldE5hbm9zZWNvbmRUaW1lcgt0b3RhbE1lbW9yeQpmcmVlTWVtb3J5DXByaXZhdGVNZW1vcnkTZm9yY2VGdWxsQ29sbGVjdGlvbg9xdWV1ZUNvbGxlY3Rpb24WaHR0cDovL3d3dy5leGFtcGxlLmNvbQZuc3Rlc3QIaXNHbG9iYWwKc3dmVmVyc2lvbgphcGlWZXJzaW9uCmRpc3Bvc2VYTUwVc21hc2hPYmplY3RWZWN0b3JTaXplEnNtYXNoSW50VmVjdG9yU2l6ZRNzbWFzaFVJbnRWZWN0b3JTaXplFXNtYXNoRG91YmxlVmVjdG9yU2l6ZR5wYXVzZUZvckdDSWZDb2xsZWN0aW9uSW1taW5lbnQHaXM2NGJpdAhpc0ludHB0cg5ydW5JblNhZmVwb2ludBJjYW5vbmljYWxpemVOdW1iZXIMYXZtcGx1czpGaWxlC2ZsYXNoLnV0aWxzCUJ5dGVBcnJheQZleGlzdHMEcmVhZA1yZWFkQnl0ZUFycmF5DndyaXRlQnl0ZUFycmF5BEZpbGUVYXZtc2hlbGw6QWJzdHJhY3RCYXNlCGF2bXNoZWxsDEFic3RyYWN0QmFzZRdhdm1zaGVsbDpSZXN0cmljdGVkQmFzZQ5SZXN0cmljdGVkQmFzZR9hdm1zaGVsbDpBYnN0cmFjdFJlc3RyaWN0ZWRCYXNlFkFic3RyYWN0UmVzdHJpY3RlZEJhc2USYXZtc2hlbGw6Q2hlY2tCYXNlCUNoZWNrQmFzZRNhdm1zaGVsbDpOYXRpdmVCYXNlCk5hdGl2ZUJhc2UWYXZtc2hlbGw6TmF0aXZlQmFzZUFTMw1OYXRpdmVCYXNlQVMzGWF2bXNoZWxsOlNoZWxsQ29yZUZyaWVuZDEQU2hlbGxDb3JlRnJpZW5kMRlhdm1zaGVsbDpTaGVsbENvcmVGcmllbmQyEFNoZWxsQ29yZUZyaWVuZDIZZmxhc2guc3lzdGVtOkNhcGFiaWxpdGllcwdBVk1QbHVzDGZsYXNoLnN5c3RlbQpwbGF5ZXJUeXBlDENhcGFiaWxpdGllcxVhdm1zaGVsbDpwdWJsaWNfY2xhc3MKcHVibGljX3ZhcgPuipUScHVibGljX3Zhcl9BSVJfMV8wA0FQSQM2NjED7oqWEnB1YmxpY192YXJfRlBfMTBfMAM2NjID7oqXEnB1YmxpY192YXJfQUlSXzFfNQM2NjMD7oqYFHB1YmxpY192YXJfQUlSXzFfNV8xAzY2NAPuipkVcHVibGljX3Zhcl9GUF8xMF8wXzMyAzY2NQPuipoUcHVibGljX3Zhcl9BSVJfMV81XzIDNjY2GnB1YmxpY192YXJfQUlSXzFfMF9GUF8xMF8wJnB1YmxpY192YXJfQUlSXzFfNV8xX0ZQXzEwXzBfQUlSXzFfNV8yJXB1YmxpY192YXJfRlBfMTBfMF8zMl9BSVJfMV8wX0ZQXzEwXzAMcHVibGljX2NvbnN0FHB1YmxpY19jb25zdF9BSVJfMV8wFHB1YmxpY19jb25zdF9GUF8xMF8wFHB1YmxpY19jb25zdF9BSVJfMV81FnB1YmxpY19jb25zdF9BSVJfMV81XzEXcHVibGljX2NvbnN0X0ZQXzEwXzBfMzIWcHVibGljX2NvbnN0X0FJUl8xXzVfMhxwdWJsaWNfY29uc3RfQUlSXzFfMF9GUF8xMF8wKHB1YmxpY19jb25zdF9BSVJfMV81XzFfRlBfMTBfMF9BSVJfMV81XzIncHVibGljX2NvbnN0X0ZQXzEwXzBfMzJfQUlSXzFfMF9GUF8xMF8wD3B1YmxpY19mdW5jdGlvbhdwdWJsaWNfZnVuY3Rpb25fQUlSXzFfMBdwdWJsaWNfZnVuY3Rpb25fRlBfMTBfMBdwdWJsaWNfZnVuY3Rpb25fQUlSXzFfNRlwdWJsaWNfZnVuY3Rpb25fQUlSXzFfNV8xGnB1YmxpY19mdW5jdGlvbl9GUF8xMF8wXzMyGXB1YmxpY19mdW5jdGlvbl9BSVJfMV81XzIfcHVibGljX2Z1bmN0aW9uX0FJUl8xXzBfRlBfMTBfMCtwdWJsaWNfZnVuY3Rpb25fQUlSXzFfNV8xX0ZQXzEwXzBfQUlSXzFfNV8yKnB1YmxpY19mdW5jdGlvbl9GUF8xMF8wXzMyX0FJUl8xXzBfRlBfMTBfMA1wdWJsaWNfZ2V0c2V0FXB1YmxpY19nZXRzZXRfQUlSXzFfMBVwdWJsaWNfZ2V0c2V0X0ZQXzEwXzAVcHVibGljX2dldHNldF9BSVJfMV81F3B1YmxpY19nZXRzZXRfQUlSXzFfNV8xGHB1YmxpY19nZXRzZXRfRlBfMTBfMF8zMhdwdWJsaWNfZ2V0c2V0X0FJUl8xXzVfMh1wdWJsaWNfZ2V0c2V0X0FJUl8xXzBfRlBfMTBfMClwdWJsaWNfZ2V0c2V0X0FJUl8xXzVfMV9GUF8xMF8wX0FJUl8xXzVfMihwdWJsaWNfZ2V0c2V0X0ZQXzEwXzBfMzJfQUlSXzFfMF9GUF8xMF8wDHB1YmxpY19jbGFzcx1hdm1zaGVsbDpwdWJsaWNfY2xhc3NfQUlSXzFfMBRwdWJsaWNfY2xhc3NfQUlSXzFfMB1hdm1zaGVsbDpwdWJsaWNfY2xhc3NfRlBfMTBfMBRwdWJsaWNfY2xhc3NfRlBfMTBfMB1hdm1zaGVsbDpwdWJsaWNfY2xhc3NfQUlSXzFfNRRwdWJsaWNfY2xhc3NfQUlSXzFfNR9hdm1zaGVsbDpwdWJsaWNfY2xhc3NfQUlSXzFfNV8xFnB1YmxpY19jbGFzc19BSVJfMV81XzEgYXZtc2hlbGw6cHVibGljX2NsYXNzX0ZQXzEwXzBfMzIXcHVibGljX2NsYXNzX0ZQXzEwXzBfMzIfYXZtc2hlbGw6cHVibGljX2NsYXNzX0FJUl8xXzVfMhZwdWJsaWNfY2xhc3NfQUlSXzFfNV8yJWF2bXNoZWxsOnB1YmxpY19jbGFzc19BSVJfMV8wX0ZQXzEwXzAccHVibGljX2NsYXNzX0FJUl8xXzBfRlBfMTBfMDFhdm1zaGVsbDpwdWJsaWNfY2xhc3NfQUlSXzFfNV8xX0ZQXzEwXzBfQUlSXzFfNV8yKHB1YmxpY19jbGFzc19BSVJfMV81XzFfRlBfMTBfMF9BSVJfMV81XzIwYXZtc2hlbGw6cHVibGljX2NsYXNzX0ZQXzEwXzBfMzJfQUlSXzFfMF9GUF8xMF8wJ3B1YmxpY19jbGFzc19GUF8xMF8wXzMyX0FJUl8xXzBfRlBfMTBfMBBwdWJsaWNfaW50ZXJmYWNlGHB1YmxpY19pbnRlcmZhY2VfQUlSXzFfMBhwdWJsaWNfaW50ZXJmYWNlX0ZQXzEwXzAYcHVibGljX2ludGVyZmFjZV9BSVJfMV81GnB1YmxpY19pbnRlcmZhY2VfQUlSXzFfNV8xG3B1YmxpY19pbnRlcmZhY2VfRlBfMTBfMF8zMhpwdWJsaWNfaW50ZXJmYWNlX0FJUl8xXzVfMiBwdWJsaWNfaW50ZXJmYWNlX0FJUl8xXzBfRlBfMTBfMCxwdWJsaWNfaW50ZXJmYWNlX0FJUl8xXzVfMV9GUF8xMF8wX0FJUl8xXzVfMitwdWJsaWNfaW50ZXJmYWNlX0ZQXzEwXzBfMzJfQUlSXzFfMF9GUF8xMF8wJWF2bXNoZWxsOk5hdGl2ZVN1YmNsYXNzT2ZBYnN0cmFjdEJhc2UcTmF0aXZlU3ViY2xhc3NPZkFic3RyYWN0QmFzZR9hdm1zaGVsbDpTdWJjbGFzc09mQWJzdHJhY3RCYXNlFlN1YmNsYXNzT2ZBYnN0cmFjdEJhc2UnYXZtc2hlbGw6TmF0aXZlU3ViY2xhc3NPZlJlc3RyaWN0ZWRCYXNlHk5hdGl2ZVN1YmNsYXNzT2ZSZXN0cmljdGVkQmFzZSFhdm1zaGVsbDpTdWJjbGFzc09mUmVzdHJpY3RlZEJhc2UYU3ViY2xhc3NPZlJlc3RyaWN0ZWRCYXNlL2F2bXNoZWxsOk5hdGl2ZVN1YmNsYXNzT2ZBYnN0cmFjdFJlc3RyaWN0ZWRCYXNlJk5hdGl2ZVN1YmNsYXNzT2ZBYnN0cmFjdFJlc3RyaWN0ZWRCYXNlKWF2bXNoZWxsOlN1YmNsYXNzT2ZBYnN0cmFjdFJlc3RyaWN0ZWRCYXNlIFN1YmNsYXNzT2ZBYnN0cmFjdFJlc3RyaWN0ZWRCYXNlHGF2bXNoZWxsOk5hdGl2ZUJhc2VFeHRlbmRlcjETTmF0aXZlQmFzZUV4dGVuZGVyMRxhdm1zaGVsbDpOYXRpdmVCYXNlRXh0ZW5kZXIyBGZvbzEEZm9vMhNOYXRpdmVCYXNlRXh0ZW5kZXIyC0FQSV9BSVJfMV8wC0FQSV9GUF8xMF8wC0FQSV9BSVJfMV81DUFQSV9BSVJfMV81XzEOQVBJX0ZQXzEwXzBfMzINQVBJX0FJUl8xXzVfMgpuc19leGFtcGxlBm5hdGl2ZQNjbHMTOjphdm1zaGVsbDo6TUlDbGFzcwhpbnN0YW5jZRQ6OmF2bXNoZWxsOjpNSU9iamVjdAdtZXRob2RzGDo6YXZtc2hlbGw6Ok1JT2JqZWN0SW1wbAphdm1wbHVz7oqUFzo6YXZtc2hlbGw6OlN5c3RlbUNsYXNzB2NsYXNzZ2MFZXhhY3QEYXV0bwljb25zdHJ1Y3QEbm9uZRU6OmF2bXNoZWxsOjpGaWxlQ2xhc3MLYXZtc2hlbGzuipQdOjphdm1zaGVsbDo6QWJzdHJhY3RCYXNlQ2xhc3MeOjphdm1zaGVsbDo6QWJzdHJhY3RCYXNlT2JqZWN0AmdjCGFic3RyYWN0LTo6YXZtc2hlbGw6Ok5hdGl2ZVN1YmNsYXNzT2ZBYnN0cmFjdEJhc2VDbGFzcy46OmF2bXNoZWxsOjpOYXRpdmVTdWJjbGFzc09mQWJzdHJhY3RCYXNlT2JqZWN0Hzo6YXZtc2hlbGw6OlJlc3RyaWN0ZWRCYXNlQ2xhc3MgOjphdm1zaGVsbDo6UmVzdHJpY3RlZEJhc2VPYmplY3QKcmVzdHJpY3RlZC86OmF2bXNoZWxsOjpOYXRpdmVTdWJjbGFzc09mUmVzdHJpY3RlZEJhc2VDbGFzczA6OmF2bXNoZWxsOjpOYXRpdmVTdWJjbGFzc09mUmVzdHJpY3RlZEJhc2VPYmplY3QnOjphdm1zaGVsbDo6QWJzdHJhY3RSZXN0cmljdGVkQmFzZUNsYXNzKDo6YXZtc2hlbGw6OkFic3RyYWN0UmVzdHJpY3RlZEJhc2VPYmplY3QTYWJzdHJhY3QtcmVzdHJpY3RlZDc6OmF2bXNoZWxsOjpOYXRpdmVTdWJjbGFzc09mQWJzdHJhY3RSZXN0cmljdGVkQmFzZUNsYXNzODo6YXZtc2hlbGw6Ok5hdGl2ZVN1YmNsYXNzT2ZBYnN0cmFjdFJlc3RyaWN0ZWRCYXNlT2JqZWN0Gjo6YXZtc2hlbGw6OkNoZWNrQmFzZUNsYXNzGzo6YXZtc2hlbGw6OkNoZWNrQmFzZU9iamVjdAVjaGVjaxs6OmF2bXNoZWxsOjpOYXRpdmVCYXNlQ2xhc3McOjphdm1zaGVsbDo6TmF0aXZlQmFzZU9iamVjdAZmcmllbmQTYXZtc2hlbGw6OlNoZWxsQ29yZSthdm1zaGVsbDo6U2hlbGxDb3JlLGF2bXNoZWxsOjpTaGVsbFRvcGxldmVsD2ZsYXNoLnN5c3Rlbe6KlA5nZXRDbGFzc0J5TmFtZQVwcmludAthdm1zaGVsbO6KlQthdm1zaGVsbO6Klgthdm1zaGVsbO6Klwthdm1zaGVsbO6KmAthdm1zaGVsbO6KmQthdm1zaGVsbO6Kmg5hdm1wbHVzOkRvbWFpbgRpbml0C0RvbWFpbi5hcyQyCWxvYWRCeXRlcxhNSU5fRE9NQUlOX01FTU9SWV9MRU5HVEgEbG9hZAxkb21haW5NZW1vcnkLRG9tYWluQ2xhc3MMRG9tYWluT2JqZWN0BVFOYW1lE19nZXRJbnZvY2F0aW9uQ291bnQMU2FtcGxlci5hcyQzDWZsYXNoLnNhbXBsZXILX2dldFNhbXBsZXMBZgFlA3JldBNfc2V0U2FtcGxlckNhbGxiYWNrB3dyYXBwZXIYZmxhc2guc2FtcGxlcjpTdGFja0ZyYW1lBG5hbWUCKCkEZmlsZQFbAToEbGluZQFdCHNjcmlwdElECHRvU3RyaW5nClN0YWNrRnJhbWUUZmxhc2guc2FtcGxlcjpTYW1wbGUEdGltZQVzdGFjawZTYW1wbGUaZmxhc2guc2FtcGxlcjpDbGFzc0ZhY3RvcnkPU3RhY2tGcmFtZUNsYXNzC1NhbXBsZUNsYXNzF0RlbGV0ZU9iamVjdFNhbXBsZUNsYXNzFE5ld09iamVjdFNhbXBsZUNsYXNzDENsYXNzRmFjdG9yeR1mbGFzaC5zYW1wbGVyOk5ld09iamVjdFNhbXBsZQJpZAR0eXBlBm9iamVjdARzaXplD05ld09iamVjdFNhbXBsZSBmbGFzaC5zYW1wbGVyOkRlbGV0ZU9iamVjdFNhbXBsZRJEZWxldGVPYmplY3RTYW1wbGUQZmxhc2guc2FtcGxlcu6KlBVOZXdPYmplY3RTYW1wbGVPYmplY3QMY2xlYXJTYW1wbGVzG1NhbXBsZXJTY3JpcHQ6OmNsZWFyU2FtcGxlcw1zdGFydFNhbXBsaW5nHFNhbXBsZXJTY3JpcHQ6OnN0YXJ0U2FtcGxpbmcMc3RvcFNhbXBsaW5nG1NhbXBsZXJTY3JpcHQ6OnN0b3BTYW1wbGluZw1wYXVzZVNhbXBsaW5nHFNhbXBsZXJTY3JpcHQ6OnBhdXNlU2FtcGxpbmcUc2FtcGxlSW50ZXJuYWxBbGxvY3MjU2FtcGxlclNjcmlwdDo6c2FtcGxlSW50ZXJuYWxBbGxvY3MSc2V0U2FtcGxlckNhbGxiYWNrIlNhbXBsZXJTY3JpcHQ6Ol9zZXRTYW1wbGVyQ2FsbGJhY2sHZ2V0U2l6ZRZTYW1wbGVyU2NyaXB0OjpnZXRTaXplDmdldE1lbWJlck5hbWVzHVNhbXBsZXJTY3JpcHQ6OmdldE1lbWJlck5hbWVzCmdldFNhbXBsZXMaU2FtcGxlclNjcmlwdDo6X2dldFNhbXBsZXMOZ2V0U2FtcGxlQ291bnQdU2FtcGxlclNjcmlwdDo6Z2V0U2FtcGxlQ291bnQSZ2V0SW52b2NhdGlvbkNvdW50GGdldFNldHRlckludm9jYXRpb25Db3VudBhnZXRHZXR0ZXJJbnZvY2F0aW9uQ291bnQiU2FtcGxlclNjcmlwdDo6X2dldEludm9jYXRpb25Db3VudA5pc0dldHRlclNldHRlch1TYW1wbGVyU2NyaXB0Ojppc0dldHRlclNldHRlchBnZXRMZXhpY2FsU2NvcGVzH1NhbXBsZXJTY3JpcHQ6OmdldExleGljYWxTY29wZXMMZ2V0U2F2ZWRUaGlzG1NhbXBsZXJTY3JpcHQ6OmdldFNhdmVkVGhpcw9nZXRNYXN0ZXJTdHJpbmceU2FtcGxlclNjcmlwdDo6Z2V0TWFzdGVyU3RyaW5nAzcxMhFmbGFzaC50cmFjZTpUcmFjZQNPRkYHTUVUSE9EUxFNRVRIT0RTX1dJVEhfQVJHUxFNRVRIT0RTX0FORF9MSU5FUxtNRVRIT0RTX0FORF9MSU5FU19XSVRIX0FSR1MERklMRQhMSVNURU5FUghzZXRMZXZlbAhnZXRMZXZlbAtzZXRMaXN0ZW5lcgtnZXRMaXN0ZW5lcgtmbGFzaC50cmFjZQVUcmFjZQpUcmFjZS5hcyQ0DmZsYXNoLnRyYWNl7oqUClRyYWNlQ2xhc3MSZmxhc2gudXRpbHM6RW5kaWFuCkJJR19FTkRJQU4JYmlnRW5kaWFuDUxJVFRMRV9FTkRJQU4MbGl0dGxlRW5kaWFuBkVuZGlhbgtFbmRpYW4uYXMkNQ5mbGFzaC51dGlsc+6KlBhmbGFzaC5zeXN0ZW06V29ya2VyU3RhdGUDTkVXA25ldwdSVU5OSU5HB3J1bm5pbmcKVEVSTUlOQVRFRAp0ZXJtaW5hdGVkBkZBSUxFRAZmYWlsZWQHQUJPUlRFRAdhYm9ydGVkCUVYQ0VQVElPTglleGNlcHRpb24LV29ya2VyLmFzJDYFRXJyb3ITbm90IGFuIGVudW0gdmFsdWU6IARjb2RlC1dvcmtlclN0YXRlE2ZsYXNoLnN5c3RlbTpXb3JrZXIJbV9jdXJyZW50BldvcmtlchBpbnRlcm5hbEdldFN0YXRlB2N1cnJlbnQCcHIFc3RhdGUFc3RhcnQKaXNQYXJlbnRPZgxpc1ByaW1vcmRpYWwRc2V0U2hhcmVkUHJvcGVydHkRZ2V0U2hhcmVkUHJvcGVydHkJdGVybWluYXRlCm1fYnl0ZUNvZGUYZmxhc2guc3lzdGVtOldvcmtlckV2ZW50DFdPUktFUl9TVEFURQt3b3JrZXJTdGF0ZQ9tX3ByZXZpb3VzU3RhdGUObV9jdXJyZW50U3RhdGUIbV90YXJnZXQMY3VycmVudFN0YXRlDXByZXZpb3VzU3RhdGUGdGFyZ2V0C1dvcmtlckV2ZW50D2ZsYXNoLnN5c3Rlbe6KqgM2ODIcOjphdm1zaGVsbDo6U2hlbGxXb3JrZXJDbGFzcx06OmF2bXNoZWxsOjpTaGVsbFdvcmtlck9iamVjdBlmbGFzaC5zeXN0ZW06V29ya2VyRG9tYWluEVdvcmtlckRvbWFpbi5hcyQ3DFdvcmtlckRvbWFpbiFjcmVhdGVXb3JrZXJGcm9tQnl0ZUFycmF5SW50ZXJuYWwZY3JlYXRlV29ya2VyRnJvbUJ5dGVBcnJheRpjcmVhdGVXb3JrZXJGcm9tUHJpbW9yZGlhbAtsaXN0V29ya2VycyI6OmF2bXNoZWxsOjpTaGVsbFdvcmtlckRvbWFpbkNsYXNzIzo6YXZtc2hlbGw6OlNoZWxsV29ya2VyRG9tYWluT2JqZWN0jAEWAQUFFwEWBhcGCBIFFRYWGBUFGRgZBR0YHRodGhgWIwg4BUcWSBhHBU8WUBhPBVIYUgVUGFQFVhhWBVgYWAVaGFoFXBhcBV4YXgVgFmIXYhhgGmAFZRZnFmsWbhZxFnQWdxhlBZwBGJwBBZ4BGJ4BBaABGKABBaIBGKIBBaQBGKQBBaYBGKYBBagBGKgBBaoBGKoBBawBGKwBBbgBGLgBBboBGLoBBbwBGLwBBb4BGL4BBcABGMABBcIBGMIBBcQBGMQBBcYBGMYBF1AW2AEW4AEW+QEW/AEW/QEW/gEW/wEWgAIWgQIFggIFhAIYggIaggIFjQIWjgIXjgIFlQIYlQIalQIFoAIYoAIFpAIYpAIFqgIYqgIFsAIYsAIWsgIF1QIW4QIY1QIF4wIX4QIW5AIF5gIY5gIF7AIXSBbtAgXuAgX7AhjuAhruAgWAAxiAAxqAAwWOAxiOAxqOAxaYAwWcAwWdAxicAxqcAz4EAQIDBAQBAgQFAQYBCAgBAgQFDA0ODwEMAREBIgEkCQECBA8mJygpKgEsAS0BLgEvATABMQIsLQMtLzEDLC0wAVEBUwEFAQQBFgQBAhZVAScFAQIEJygBVgFXAVgBWQFaAVsBXAFdAV4CWVoDWlxeA1laXQgBBAUPX2BhYgFfBAEEBWAEAWNkZQFlCAEPY2RlZmdoAXEEAXN1dgF3BAETensBfAgBDycofX5/gAEIAQ8nKH6BAYIBgwEBgQEIAQ8nKH6EAYUBhgEBhAEBKAQBJyh+AYcBCAEPJyiIAYkBigGLAQGIAQQBJyiJAY4EBwECBwEDCQQBCQcBCQgBBwEJCQoBBwELCQwBCQ0BCQ4BCQ8BBwEQCQQCCRECCRMDBwUUCRMEBwUXBwEYBwEaCRsEBwUcBwEeCR8FBwEgBwEhBwEiBxAkHR0BFB0dARodHQEIHR0BFQcBJQkmBAkoBAksBAktBAkuBAkvBAkMBAkwBAkRBAkxBAkyBAkKBAkfBgkeBAkIBAkzBAk0BAk1BAk2BAk3BAk5Bwk6BAk7BAk8BAk9BAkHBAk+BAk/BAlABAlBBAlCBAlDBAlEBAlFBAlGBAcEBAcTSQlKBAlLBAlMBAlNBAcETgcWUQcWUwcWVQcWVwcWWQcWWwciJwknCAcWXQckKQkpCQcWXwkECgkxCgljBAcnZAlmBAloCwlsDAlvDQlyDgl1Dwl4EAl6EQl7Egl8Ewl9BAl+Cwl/DAmAAQ0JgQEOCYIBDwmDARAJhAERCYUBEgmGARMJhwEECYgBCwmJAQwJigENCYsBDgmMAQ8JjQEQCY4BEQmPARIJkAETCZEBBAmSAQsJkwEMCZQBDQmVAQ4JlgEPCZcBEAmYAREJmQESCZoBEwcWmwEHFp0BBxafAQcWoQEHFqMBBxalAQcWpwEHFqkBBxarAQcWrQEHFq4BBxavAQcWsAEHFrEBBxayAQcWswEHFrQBBxa1AQcWtgEHFrcBBxa5AQcWuwEHFr0BBxa/AQcWwQEHFsMBCScUBxbFAQknFQnHARUJyAEVBxbJAQkUFgkXFgkYAgkcFgkEFwlOFwlRGAkYGQm5ARgJURkJuwEYCVMYCb0BGAlTGQm/ARgJVRgJwQEYCVUZCcMBGAlXGAlZGAnFARgJWRkJyQEYCVsYCV0YCV8YCWQaCRgbCZsBGAmdARgJnwEYCaEBGAmjARgJpQEYCacBGAmpARgJqwEYCa0BGAmuARgJrwEYCbABGAmxARgJsgEYCbMBGAm0ARgJtQEYCbYBGAm3ARgJygEYBxbKAQnLARgHFssBCcwBGAcWzAEJzQEYBxbNAQnOARgHFs4BCc8BGAcWzwEJZhgHFmYJaBgHFmgJbBgHFmwJbxgHFm8JchgHFnIJdRgHFnUJeBgHFngJehgHFnoJexgHFnsJfBgHFnwJfRgHFn0JfhgHFn4JfxgHFn8JgAEYBxaAAQmBARgHFoEBCYIBGAcWggEJgwEYBxaDAQmEARgHFoQBCYUBGAcWhQEJhgEYBxaGAQnQARYJBBwJThwJERwJUR0JuQEdCbsBHQlTHQm9AR0JvwEdCVUdCcEBHQnDAR0JVx0JWR0JxQEdCckBHQlbHQldHQlfHQlkHgn6AQQJ+wEECcoBHQnLAR0JzAEdCc0BHQnOAR0JzwEdCWYdCWgfCWwgCW8hCXIiCXUjCXgkCXolCXsmCXwnCX0dCX4fCX8gCYABIQmBASIJggEjCYMBJAmEASUJhQEmCYYBJwmHAR0JiAEfCYkBIAmKASEJiwEiCYwBIwmNASQJjgElCY8BJgmQAScJkQEdCZIBHwmTASAJlAEhCZUBIgmWASMJlwEkCZgBJQmZASYJmgEnCZsBHQmdAR8JnwEgCaEBIQmjASIJpQEjCacBJAmpASUJqwEmCa0BJwmuAR0JrwEfCbABIAmxASEJsgEiCbMBIwm0ASQJtQElCbYBJgm3AScHBA0JgwIoCU4oCUwoCYUCKAkOBAmGAgQJgwIpCYUCBAkPBAmHAgQJiAIECQ0XCRgqCQ0cBwGLAgmMAisJjwIrCZACKwcBkQIJkgIsCZMCKwmQAiwJlAIsCZYCLQmYAi0JmwItCZYCBAmYAgQJmwIECZ0CBAmeAgQHZJ8CCaECBAmiAgQHZKMCBwGlAgcBpgIHAacCBwGoAgmlAgQJpgIECacCBAmoAgQHZakCCasCBAmsAgQJrQIECa4CBAdkrwIHZLECCRgrCZ8CLgmjAi4JrwIuCbECLgm0Ai4JtgIuCbgCLgm6Ai4JvAIuCb4CLgmTAiwJwAIuCcICLgnEAi4JjwIsCcYCLgnIAi4JyQIuCcoCLgmMAiwJzAIuCc4CLgnQAi4J0gIuCakCLAcB1gIHAdcCBwHYAgcB2QIHAdoCBwHbAgcB3AIJ1gIECdcCBAnYAgQJ2QIECdoCBAnbAgQJ3AIECd0CBAneAgQJ3wIECeACBAdz4gIJGC8J4gIwBwHnAgcB6QIJ5wIECekCBAcT6wIJGDEJ6wIyBwHvAgcB8QIHAfMCBwH1AgcB9wIHAfkCCe8CMwnxAjMJ8wIzCfUCMwn3AjMJ+QIzCfwCMwnvAgQJ8QIECfMCBAn1AgQJ9wIECfkCBAn+AgQHJ/8CCYEDNAcnggMJgwM0CYQDBAmFAwQJgQM1CYYDBAmDAzUJhwMECYgDBAmJAwQJigMECYsDBAmMAwQJjQM1BwGPAwmRAzYJkgM2CZMDNgmPAwQJlAMECZUDBAmWAwQJkQM3CZIDNwmTAzgHJ5cDCf8CGgkYOQmCAxoJlwMaCf8COgmCAx4JlwMeCYEDOwcnngMJnwM7HR0B4gMJgQM8CaADBAmhAwQJnwM8CaIDBAkYPQmeAx6ZAgEBAAEAAQEAAQABAQABAAEBAAEAAQEAAQABAQABAAEBAAEAAQEAAQABAQABAAEBAAEAAAIBAAACAQAAAgEAAAIBAAACAQAAAgEAAAIBAAACAQAAAgEAAAIBAAACAQAAAgEAAAIBAAACAQAAAgEAAAIBAAACAQAAAgEAAAIBAAACAQABAQABAAAGAQAACAEAAAABBAAAAQQBDQYBAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAARUVASAAAAEAAAABAAEBGgEgARoGASABARoBIAAGASAABgEgAAYBIAEBGwEgAQEGASAAAQEgAAIBIAAVASAACAEgABsBIAAGASAAFQEgABUBIAAVASAAAQEgAAEBIAABASABAhQBIAAaASAAGgEgAQEcASABARoBIAIBHggBIAIBHwgBIAIBIAgBIAIBIQgBIAEBFQEoAQEGAAIBIAECAAEgAQEiASABAAABIAAAAQAAAAEAAQIGASABBgYBIAIBBgYBIAFHBgEgAgIGRwEgAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAYBAAACAQAAAAEAAAABAAACAQAAAgEAAAIBAAACAQAAAgEAAAIBAAACAQAAAgEAAAIBAAACAQAAAgEAAAIBAAACAQAAAgEAAAIBAAACAQAAAgEAAAIBAAACAQAAAgEAAQEAAQABAQABAAEBAAEAAQEAAQABAQABAAEBAAEAAQEAAQABAQABAAEBAAEAAQEAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA4wIBIAAIASABAeMCASABAOMCAQACAEcIASgBAwMBDQYBIAIABggBCAEDAwBHASABAEcBIAAAAQABBgYBIAEUIgEgARsiASACAhTyAgEgAxUU8gIIASACFRTyAgEAAhUU8gIBAAIVFPICAQAAFQEgARQNASAA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",
|
|
28
|
+
);
|
package/src/shell.ts
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// avmshell's way of running ABCs, in node: the libraries it loads (builtin
|
|
2
|
+
// and shell_toplevel), their scripts run on first use, then each ABC given,
|
|
3
|
+
// added to the same domain and its entry point run, until one throws. One
|
|
4
|
+
// compiler domain serves the one runtime, each ABC compiled in the
|
|
5
|
+
// application domain the runtime loads it into, so that an ABC
|
|
6
|
+
// Domain.loadBytes loads compiles against what its domain sees, a
|
|
7
|
+
// sibling's ABCs left out.
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import { API_VERSION, type Codegen } from "@swf2es/codegen";
|
|
10
|
+
import type {
|
|
11
|
+
Abc,
|
|
12
|
+
CompileUnit,
|
|
13
|
+
Runtime,
|
|
14
|
+
RuntimeOptions,
|
|
15
|
+
ShellFiles,
|
|
16
|
+
ShellWorkerHost,
|
|
17
|
+
ShellWorkerInit,
|
|
18
|
+
Value,
|
|
19
|
+
} from "@swf2es/runtime/avm2";
|
|
20
|
+
import { floatLibrary, hasFloatLibrary } from "@swf2es/runtime/avm2";
|
|
21
|
+
import { RejectedError } from "./aot.js";
|
|
22
|
+
|
|
23
|
+
/** What the shell needs of a compiler: a Codegen, or a build of it for tests. */
|
|
24
|
+
export type ShellCompiler = Pick<
|
|
25
|
+
Codegen,
|
|
26
|
+
"reset" | "add" | "childDomain" | "found" | "compileModule"
|
|
27
|
+
>;
|
|
28
|
+
|
|
29
|
+
/** A module the compiler wrote, loaded: run with a runtime, it gives the ABC. */
|
|
30
|
+
export type ShellModule = (rt: Runtime) => Abc;
|
|
31
|
+
|
|
32
|
+
export interface ShellLibrary {
|
|
33
|
+
name: string;
|
|
34
|
+
abc: Uint8Array;
|
|
35
|
+
/** Its module, compiled before for the same libraries before it: linked again but not compiled. */
|
|
36
|
+
module?: ShellModule;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ShellOptions {
|
|
40
|
+
compiler: ShellCompiler;
|
|
41
|
+
/** The runtime's createRuntime, or another build's. */
|
|
42
|
+
createRuntime: (options: RuntimeOptions) => Runtime;
|
|
43
|
+
/** Where trace and print write a line. */
|
|
44
|
+
print: (line: string) => void;
|
|
45
|
+
/** Where avmshell's File reads and writes; the runtime keeps them in memory by default. */
|
|
46
|
+
files?: ShellFiles;
|
|
47
|
+
/**
|
|
48
|
+
* Load a module the compiler has just written, `name` naming its script
|
|
49
|
+
* (which Runtime.codeDomain tells domains by); by default evaluated as a
|
|
50
|
+
* script of its own.
|
|
51
|
+
*/
|
|
52
|
+
load?: (js: string, name: string) => ShellModule | Promise<ShellModule>;
|
|
53
|
+
/** What starts the background workers' threads (RuntimeOptions.workers), as nodeShellThreads does. */
|
|
54
|
+
workers?: ShellWorkerHost;
|
|
55
|
+
/** The background worker these ABCs run as, in the thread its host started (RuntimeOptions.worker). */
|
|
56
|
+
worker?: ShellWorkerInit;
|
|
57
|
+
/**
|
|
58
|
+
* The ABCs' API version, as avmshell's -api gives it, whose series is
|
|
59
|
+
* the run's: Flash Player's latest, 50, by default.
|
|
60
|
+
*/
|
|
61
|
+
apiVersion?: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const sha256 = (bytes: Uint8Array) => createHash("sha256").update(bytes).digest("hex");
|
|
65
|
+
|
|
66
|
+
/** A module's source as a script of its own: its default export returned, `name` its sourceURL. */
|
|
67
|
+
export function evaluateModule(js: string, name: string): ShellModule {
|
|
68
|
+
// Strict, as a module is: a sloppy function boxes a primitive `this`, such
|
|
69
|
+
// as the string a String method is called on.
|
|
70
|
+
const script = `"use strict";${js.replace(/^export default /, "return ")}//# sourceURL=${name}\n`;
|
|
71
|
+
return new Function(script)();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* The compiler for one runtime: the libraries and ABCs added to the root
|
|
76
|
+
* domain, and RuntimeOptions.compileAbc for those Domain.loadBytes loads.
|
|
77
|
+
*/
|
|
78
|
+
export function shellDomain(compiler: ShellCompiler, apiVersion = API_VERSION) {
|
|
79
|
+
// The compiler's number for each of the runtime's domains, and the
|
|
80
|
+
// compiler's index of each ABC loaded into one, in load order.
|
|
81
|
+
const domains = new Map<number, number>([[0, 0]]);
|
|
82
|
+
const abcs = new Map<number, number[]>([[0, []]]);
|
|
83
|
+
// The findings each domain has been told, reported once.
|
|
84
|
+
const reported = new Map<number, Set<string>>();
|
|
85
|
+
// Every ABC's hash, in load order, as the compiler names a module's.
|
|
86
|
+
const hashes: string[] = [];
|
|
87
|
+
let added = 0;
|
|
88
|
+
let evaluated = 0;
|
|
89
|
+
|
|
90
|
+
compiler.reset(apiVersion);
|
|
91
|
+
|
|
92
|
+
/** Add an ABC to the runtime's domain `domain`: 0, or the VerifyError it was rejected with. */
|
|
93
|
+
const add = (bytes: Uint8Array, builtin: boolean, domain = 0): number => {
|
|
94
|
+
const error = compiler.add(bytes, builtin, domains.get(domain));
|
|
95
|
+
if (!error) {
|
|
96
|
+
abcs.get(domain)?.push(added++);
|
|
97
|
+
hashes.push(sha256(bytes));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return error;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
/** Add an ABC to the root domain, as avmshell loads its libraries and the ABCs it runs. */
|
|
105
|
+
add: (bytes: Uint8Array, builtin: boolean): number => add(bytes, builtin),
|
|
106
|
+
/** The module of the ABC added last. */
|
|
107
|
+
compile: (): string => compiler.compileModule(hashes),
|
|
108
|
+
/** RuntimeOptions.compileAbc: `bytes` compiled into the unit's domain, evaluated at once. */
|
|
109
|
+
compileAbc(bytes: Uint8Array, unit: CompileUnit): ShellModule | number {
|
|
110
|
+
for (let i = unit.domains.length - 2; i >= 0; i--) {
|
|
111
|
+
const id = unit.domains[i];
|
|
112
|
+
if (!domains.has(id)) {
|
|
113
|
+
domains.set(id, compiler.childDomain(domains.get(unit.domains[i + 1]) ?? 0));
|
|
114
|
+
abcs.set(id, []);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const domain = unit.domains[0];
|
|
119
|
+
const at = domains.get(domain) ?? 0;
|
|
120
|
+
const told = reported.get(domain) ?? new Set<string>();
|
|
121
|
+
reported.set(domain, told);
|
|
122
|
+
for (const f of unit.found) {
|
|
123
|
+
const key = JSON.stringify([f.asType, f.nsKind, f.uri, f.name, f.domain, f.index]);
|
|
124
|
+
const abc = abcs.get(f.domain)?.[f.index];
|
|
125
|
+
if (abc !== undefined && !told.has(key)) {
|
|
126
|
+
told.add(key);
|
|
127
|
+
const { nsKind, uri, name, asType } = f;
|
|
128
|
+
compiler.found({ domain: at, nsKind, uri, name, abc, asType });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const error = add(bytes, false, domain);
|
|
133
|
+
if (error) {
|
|
134
|
+
return error;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// A script of its own, by which Runtime.codeDomain finds its frames.
|
|
138
|
+
return evaluateModule(compiler.compileModule(hashes), `loaded-${evaluated++}.js`);
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Run `abcs` after `libraries` as avmshell runs them, printing what they
|
|
145
|
+
* trace: avmshell's exit status, 0, or 1 once an ABC is rejected, with
|
|
146
|
+
* its VerifyError, or throws an exception nothing catches, printed as its
|
|
147
|
+
* string; the ABCs after it do not run. A library's rejection throws a
|
|
148
|
+
* RejectedError, and an error of the host's, a JavaScript Error, is thrown.
|
|
149
|
+
*/
|
|
150
|
+
export async function runShell(
|
|
151
|
+
libraries: ShellLibrary[],
|
|
152
|
+
abcs: { name: string; abc: Uint8Array }[],
|
|
153
|
+
options: ShellOptions,
|
|
154
|
+
): Promise<number> {
|
|
155
|
+
if (
|
|
156
|
+
abcs.some(
|
|
157
|
+
({ abc }) =>
|
|
158
|
+
abc.length >= 4 && abc[2] === 47 && abc[3] === 0 && (abc[0] | (abc[1] << 8)) >= 16,
|
|
159
|
+
) &&
|
|
160
|
+
!hasFloatLibrary(libraries.map((lib) => lib.abc))
|
|
161
|
+
) {
|
|
162
|
+
libraries = [...libraries, { name: "float", abc: floatLibrary }];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const { print } = options;
|
|
166
|
+
const load = options.load ?? evaluateModule;
|
|
167
|
+
const apiVersion = options.apiVersion ?? API_VERSION;
|
|
168
|
+
const domain = shellDomain(options.compiler, apiVersion);
|
|
169
|
+
const rt = options.createRuntime({
|
|
170
|
+
print,
|
|
171
|
+
apiVersion,
|
|
172
|
+
// Domain.loadBytes runs the ABC at once, so its module is evaluated, not imported.
|
|
173
|
+
compileAbc: (bytes, unit) => domain.compileAbc(bytes, unit),
|
|
174
|
+
...(options.files ? { files: options.files } : {}),
|
|
175
|
+
...(options.workers ? { workers: options.workers } : {}),
|
|
176
|
+
...(options.worker ? { worker: options.worker } : {}),
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
for (const { name, abc, module } of libraries) {
|
|
180
|
+
const error = domain.add(abc, true);
|
|
181
|
+
if (error) {
|
|
182
|
+
throw new RejectedError(`library ${name}`, error, true);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// The libraries' scripts run on first use, as avmshell's builtins do.
|
|
186
|
+
(module ?? (await load(domain.compile(), `${name}.js`)))(rt);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
for (const { name, abc } of abcs) {
|
|
190
|
+
const error = domain.add(abc, false);
|
|
191
|
+
if (error) {
|
|
192
|
+
print(`VerifyError: Error #${error}`);
|
|
193
|
+
return 1;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const loaded = (await load(domain.compile(), `${name}.js`))(rt);
|
|
197
|
+
try {
|
|
198
|
+
rt.run(loaded);
|
|
199
|
+
} catch (e) {
|
|
200
|
+
// An AS3 exception nothing caught: avmshell prints it, as its string, and exits with 1.
|
|
201
|
+
if (e instanceof Error) {
|
|
202
|
+
throw e;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
print(rt.toString(e as Value));
|
|
206
|
+
return 1;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return 0;
|
|
211
|
+
}
|