@bytecodealliance/jco
Version:
JavaScript tooling for working with WebAssembly Components
152 lines (143 loc) • 5.02 kB
JavaScript
import { resolve, basename, extname } from "node:path";
import { writeFile } from "node:fs/promises";
import { readFile, isWindows, styleText } from "../common.js";
import { $init, tools } from "../../obj/wasm-tools.js";
const {
print: printFn,
parse: parseFn,
componentWit: componentWitFn,
componentNew: componentNewFn,
componentEmbed: componentEmbedFn,
metadataAdd: metadataAddFn,
metadataShow: metadataShowFn,
} = tools;
export async function parse(file, opts) {
await $init;
const source = (await readFile(file)).toString();
const output = parseFn(source);
await writeFile(opts.output, output);
}
export async function print(file, opts) {
await $init;
const source = await readFile(file);
const output = printFn(source);
if (opts.output) {
await writeFile(opts.output, output);
} else {
console.log(output);
}
}
export async function componentWit(file, opts) {
await $init;
const source = await readFile(file);
const output = componentWitFn(source, opts.document);
if (opts.output) {
await writeFile(opts.output, output);
} else {
console.log(output);
}
}
export async function componentNew(file, opts) {
await $init;
const source = file ? await readFile(file) : null;
let adapters = [];
if (opts.wasiReactor && opts.wasiCommand) {
throw new Error("Must select one of --wasi-command or --wasi-reactor");
}
if (opts.wasiReactor) {
adapters = [
[
"wasi_snapshot_preview1",
(await readFile(new URL("../../lib/wasi_snapshot_preview1.reactor.wasm", import.meta.url))).buffer,
],
];
} else if (opts.wasiCommand) {
adapters = [
[
"wasi_snapshot_preview1",
(await readFile(new URL("../../lib/wasi_snapshot_preview1.command.wasm", import.meta.url))).buffer,
],
];
}
if (opts.adapt) {
adapters = adapters.concat(
await Promise.all(
opts.adapt.map(async (adapt) => {
let adapter;
if (adapt.includes("=")) {
adapter = adapt.split("=");
} else {
adapter = [basename(adapt).slice(0, -extname(adapt).length), adapt];
}
adapter[1] = await readFile(adapter[1]);
return adapter;
}),
),
);
}
const output = componentNewFn(source, adapters);
await writeFile(opts.output, output);
}
export async function componentEmbed(file, opts) {
await $init;
if (opts.metadata) {
opts.metadata = opts.metadata.map((meta) => {
const [field, data = ""] = meta.split("=");
const [name, version = ""] = data.split("@");
return [field, [[name, version]]];
});
}
const source = file ? await readFile(file) : null;
opts.binary = source;
opts.witPath = (isWindows ? "//?/" : "") + resolve(opts.wit);
const output = componentEmbedFn(opts);
await writeFile(opts.output, output);
}
export async function metadataAdd(file, opts) {
await $init;
const metadata = opts.metadata.map((meta) => {
const [field, data = ""] = meta.split("=");
const [name, version = ""] = data.split("@");
return [field, [[name, version]]];
});
const source = await readFile(file);
const output = metadataAddFn(source, metadata);
await writeFile(opts.output, output);
}
export async function metadataShow(file, opts) {
await $init;
const source = await readFile(file);
let output = "",
stack = [1];
const meta = metadataShowFn(source);
if (opts.json) {
console.log(JSON.stringify(meta, null, 2));
} else {
for (const { name, metaType, producers } of meta) {
output += " ".repeat(stack.length - 1);
const indent = " ".repeat(stack.length);
if (metaType.tag === "component") {
output += `${styleText("bold", `[component${name ? " " + name : ""}]`)}\n`;
if (metaType.val > 0) {
stack.push(metaType.val);
}
} else {
output += `${styleText("bold", `[module${name ? " " + name : ""}]`)}\n`;
}
if (producers.length === 0) {
output += `${indent}(no metadata)\n`;
}
for (const [field, items] of producers) {
for (const [name, version] of items) {
output += `${indent}${(field + ":").padEnd(13, " ")} ${name}${version ? `${styleText("cyan", version)}` : ""}\n`;
}
}
output += "\n";
if (stack[stack.length - 1] === 0) {
stack.pop();
}
stack[stack.length - 1]--;
}
process.stdout.write(output);
}
}