Skip to content
This repository was archived by the owner on Nov 20, 2023. It is now read-only.

Commit aea49ff

Browse files
committed
Build declarations as well
1 parent 4eaf5c3 commit aea49ff

File tree

7 files changed

+92
-75
lines changed

7 files changed

+92
-75
lines changed

bin/build

+10-39
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/usr/bin/env node
22

3+
const { execSync } = require("child_process");
34
const esbuild = require("esbuild");
45
const path = require("path");
56

@@ -9,48 +10,18 @@ const wasmPlugin = {
910
let path = require("path")
1011
let fs = require("fs")
1112

12-
// Resolve ".wasm" files to a path with a namespace
13-
build.onResolve({ filter: /\.wasm$/ }, (args) => {
14-
// If this is the import inside the stub module, import the
15-
// binary itself. Put the path in the "wasm-binary" namespace
16-
// to tell our binary load callback to load the binary file.
17-
if (args.namespace === "wasm-stub") {
18-
return { path: args.path, namespace: "wasm-binary" };
19-
}
13+
build.onLoad({ filter: /\.wasm$/ }, async (args) => ({
14+
contents: await fs.promises.readFile(args.path),
15+
loader: "binary"
16+
}));
2017

21-
// Otherwise, generate the JavaScript stub module for this
22-
// ".wasm" file. Put it in the "wasm-stub" namespace to tell
23-
// our stub load callback to fill it with JavaScript.
24-
//
25-
// Resolve relative paths to absolute paths here since this
26-
// resolve callback is given "resolveDir", the directory to
27-
// resolve imports against.
28-
if (args.resolveDir === "") {
29-
return; // Ignore unresolvable paths
18+
// When we're done building the output, we'll want to additionally build the
19+
// typescript declarations file.
20+
build.onEnd((result) => {
21+
if (result.errors.length === 0) {
22+
execSync("./node_modules/.bin/tsc");
3023
}
31-
32-
return {
33-
path: path.isAbsolute(args.path) ? args.path : path.join(args.resolveDir, args.path),
34-
namespace: "wasm-stub"
35-
};
3624
});
37-
38-
// Virtual modules in the "wasm-stub" namespace are filled with
39-
// the JavaScript code for compiling the WebAssembly binary. The
40-
// binary itself is imported from a second virtual module.
41-
build.onLoad({ filter: /.*/, namespace: "wasm-stub" }, async (args) => ({
42-
contents: `import wasm from ${JSON.stringify(args.path)};
43-
export default (imports) => WebAssembly.instantiate(wasm, imports).then((result) => result.instance);`,
44-
}));
45-
46-
// Virtual modules in the "wasm-binary" namespace contain the
47-
// actual bytes of the WebAssembly file. This uses esbuild's
48-
// built-in "binary" loader instead of manually embedding the
49-
// binary data inside JavaScript code ourselves.
50-
build.onLoad({ filter: /.*/, namespace: "wasm-binary" }, async (args) => ({
51-
contents: await fs.promises.readFile(args.path),
52-
loader: "binary",
53-
}));
5425
}
5526
};
5627

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
"@wasmer/wasi": "^0.12.0",
1919
"@wasmer/wasmfs": "^0.12.0",
2020
"path-browserify": "^1.0.1",
21+
"randomfill": "^1.0.4",
2122
"ruby-head-wasm-wasi": "^0.3.0"
2223
},
2324
"devDependencies": {
2425
"@types/node": "^17.0.33",
2526
"@types/path-browserify": "^1.0.0",
26-
"esbuild": "^0.14.39"
27+
"esbuild": "^0.14.39",
28+
"typescript": "^4.7.4"
2729
}
2830
}

src/app.d.ts

-9
This file was deleted.

src/declarations.d.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
declare module "*.wasm" {
2+
const buffer: BufferSource;
3+
export default buffer;
4+
}
5+
6+
declare module "randomfill" {
7+
export function randomFillSync<T>(buffer: T, offset: number, size: number): T;
8+
}

src/index.ts

+63-26
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
import crypto from "crypto";
21
import { WASI } from "@wasmer/wasi";
32
import { WasmFs } from "@wasmer/wasmfs";
4-
import path from "path-browserify";
53
import { RubyVM } from "ruby-head-wasm-wasi/dist/index";
64

7-
import load from "./app.wasm";
5+
import { randomFillSync } from "randomfill";
6+
import path from "path-browserify";
7+
8+
import app from "./app.wasm";
9+
10+
type AppExports = {
11+
_initialize: () => void;
12+
memory: WebAssembly.Memory;
13+
};
814

915
// This overwrites the default writeSync function used by the WasmFs to instead
1016
// pipe it out to the console.
@@ -31,7 +37,18 @@ function createWriter(originalWriter: Function) {
3137
}
3238
}
3339

34-
export default async function createRuby() {
40+
type SyntaxTreeHandler = {
41+
format(source: string): string;
42+
parse(source: string): string;
43+
read(filepath: string): string;
44+
};
45+
46+
export type SyntaxTree = {
47+
rubyVM: RubyVM;
48+
handlers: Record<"haml" | "ruby", SyntaxTreeHandler>;
49+
};
50+
51+
export default async function createSyntaxTree(): Promise<SyntaxTree> {
3552
// First, create a new file system that we can use internally within the Ruby
3653
// WASM VM.
3754
const wasmFs = new WasmFs();
@@ -41,12 +58,7 @@ export default async function createRuby() {
4158
// Next, create a new WASI instance with the correct options overridden from
4259
// the defaults.
4360
const wasi = new WASI({
44-
bindings: {
45-
...WASI.defaultBindings,
46-
fs: wasmFs.fs,
47-
path: path,
48-
randomFillSync: crypto.randomFillSync as typeof WASI.defaultBindings.randomFillSync,
49-
},
61+
bindings: { ...WASI.defaultBindings, fs: wasmFs.fs, path, randomFillSync },
5062
preopens: { "/": "/tmp" }
5163
});
5264

@@ -57,7 +69,11 @@ export default async function createRuby() {
5769
rubyVM.addToImports(imports);
5870

5971
// Set the WASI memory to use the memory for our application.
60-
const instance = await load(imports);
72+
const instance = await WebAssembly.instantiate(app, imports).then((result) => {
73+
return result.instance as WebAssembly.Instance & { exports: AppExports };
74+
});
75+
76+
// Make sure WASI and our web assembly instance share their memory.
6177
wasi.setMemory(instance.exports.memory);
6278

6379
// Load our application into the virtual machine.
@@ -83,22 +99,43 @@ export default async function createRuby() {
8399

84100
return {
85101
rubyVM,
86-
formatHAML(source: string) {
87-
return format(source, ".haml");
88-
},
89-
formatRuby(source: string) {
90-
return format(source, ".rb");
91-
},
92-
// formatRBS(source: string) {
93-
// return format(source, ".rbs");
94-
// }
102+
handlers: {
103+
haml: makeSyntaxTreeHandler(".haml"),
104+
// rbs: makeSyntaxTreeHandler(".rbs"),
105+
ruby: makeSyntaxTreeHandler(".rb")
106+
}
95107
};
96108

97-
function format(source: string, kind: string) {
98-
const jsonSource = JSON.stringify(JSON.stringify(source));
99-
const rubySource = `SyntaxTree::HANDLERS.fetch("${kind}").format(JSON.parse(${jsonSource}))`;
100-
return rubyVM.eval(rubySource).toString();
109+
function makeSyntaxTreeHandler(extension: string): SyntaxTreeHandler {
110+
return {
111+
format(source) {
112+
const jsonSource = JSON.stringify(JSON.stringify(source));
113+
const rubySource = `
114+
handler = SyntaxTree::HANDLERS["${extension}"]
115+
handler.format(JSON.parse(${jsonSource}))
116+
`;
117+
118+
return rubyVM.eval(rubySource).toString();
119+
},
120+
parse(source) {
121+
const jsonSource = JSON.stringify(JSON.stringify(source));
122+
const rubySource = `
123+
handler = SyntaxTree::HANDLERS["${extension}"]
124+
node = handler.parse(JSON.parse(${jsonSource}))
125+
PP.pp(node, +"", 80)
126+
`;
127+
128+
return rubyVM.eval(rubySource).toString();
129+
},
130+
read(filepath) {
131+
const jsonSource = JSON.stringify(JSON.stringify(filepath));
132+
const rubySource = `
133+
handler = SyntaxTree::HANDLERS["${extension}"]
134+
handler.read(JSON.parse(${jsonSource}))
135+
`;
136+
137+
return rubyVM.eval(rubySource).toString();
138+
}
139+
};
101140
}
102141
};
103-
104-
export type Ruby = Awaited<ReturnType<typeof createRuby>>;

tsconfig.json

+3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
{
22
"compilerOptions": {
3+
"declaration": true,
4+
"emitDeclarationOnly": true,
35
"esModuleInterop": true,
46
"module": "commonjs",
57
"moduleResolution": "node",
68
"noImplicitAny": true,
9+
"outDir": "./dist",
710
"strict": true
811
},
912
"include": ["src"]

yarn.lock

+5
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,11 @@ tar-stream@^2.1.0:
304304
inherits "^2.0.3"
305305
readable-stream "^3.1.1"
306306

307+
typescript@^4.7.4:
308+
version "4.7.4"
309+
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
310+
integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
311+
307312
util-deprecate@^1.0.1:
308313
version "1.0.2"
309314
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"

0 commit comments

Comments
 (0)