JavaScript

Prism provides bindings to JavaScript out of the box.

Node

To use the package from node, install the @ruby/prism dependency:

npm install @ruby/prism

Then import the package:

import { loadPrism } from "@ruby/prism";

Then call the load function to get a parse function:

const parse = await loadPrism();

Browser

To use the package from the browser, you will need to do some additional work. The javascript/example.html file shows an example of running Prism in the browser. You will need to instantiate the WebAssembly module yourself and then pass it to the parsePrism function.

First, get a shim for WASI since not all browsers support it yet.

import { WASI } from "https://unpkg.com/@bjorn3/browser_wasi_shim@latest/dist/index.js";

Next, import the parsePrism function from @ruby/prism, either through a CDN or by bundling it with your application.

import { parsePrism } from "https://unpkg.com/@ruby/prism@latest/src/parsePrism.js";

Next, fetch and instantiate the WebAssembly module. You can access it through a CDN or by bundling it with your application.

const wasm = await WebAssembly.compileStreaming(fetch("https://unpkg.com/@ruby/prism@latest/src/prism.wasm"));

Next, instantiate the module and initialize WASI.

const wasi = new WASI([], [], []);
const instance = await WebAssembly.instantiate(wasm, { wasi_snapshot_preview1: wasi.wasiImport });
wasi.initialize(instance);

Finally, you can create a function that will parse a string of Ruby code.

function parse(source) {
  return parsePrism(instance.exports, source);
}

API

Now that we have access to a parse function, we can use it to parse Ruby code:

const parseResult = parse("1 + 2");

A ParseResult object is very similar to the Prism::ParseResult object from Ruby. It has the same properties: value, comments, magicComments, errors, and warnings. Here we can serialize the AST to JSON.

console.log(JSON.stringify(parseResult.value, null, 2));

Visitors

Prism allows you to traverse the AST of parsed Ruby code using visitors.

Here’s an example of a custom FooCalls visitor:

import { loadPrism, Visitor } from "@ruby/prism"

const parse = await loadPrism();
const parseResult = parse("foo()");

class FooCalls extends Visitor {
  visitCallNode(node) {
    if (node.name === "foo") {
      // Do something with the node
    }

    // Call super so that the visitor continues walking the tree
    super.visitCallNode(node);
  }
}

const fooVisitor = new FooCalls();

parseResult.value.accept(fooVisitor);

Building

To build the WASM package yourself, first obtain a copy of wasi-sdk. You can retrieve this here: github.com/WebAssembly/wasi-sdk. Next, run:

make wasm WASI_SDK_PATH=path/to/wasi-sdk

This will generate javascript/src/prism.wasm. From there, you can run the tests to verify everything was generated correctly.

cd javascript
node test