npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@synapticforge1/binaryang

v2.2.0

Published

WebAssembly toolchain in TypeScript: Binaryen and WABT ported (wasm-opt, wat2wasm, wasm2wat, wasm-validate, wasm-interp, …), as a library and a CLI. Also on JSR as @jrmarcum/binaryang.

Readme

binaryang

JSR JSR Score npm CI

A WebAssembly toolchain in TypeScript — a port of both Binaryen and WABT in one package, with no binary dependency and no WASM blob to load.

Assemble and disassemble WAT, validate and inspect modules, build and optimise IR — from a single source tree that runs on Deno, Node, Bun and modern browsers.

Supersedes @jrmarcum/binaryen-ts and @jrmarcum/wabt-ts. If you are migrating from either, see Migrating — it is a package rename plus two subpaths.

Install

The same package is published to two registries, under two names. The code, the version and the subpaths are identical; only the package name in an import differs.

| registry | package name | best for | | --------------------------------------------------------------------------- | --------------------------- | ---------------------------------------- | | npm (from 1.13.1) | @synapticforge1/binaryang | Node, Bun, pnpm, yarn: no .npmrc, npx | | JSR (the source) | @jrmarcum/binaryang | Deno; any runtime through jsr add |

From npm:

npm install @synapticforge1/binaryang    # or: bun add / pnpm add / yarn add
import { wat2wasm } from '@synapticforge1/binaryang/wat2wasm';

From JSR:

npx  jsr add @jrmarcum/binaryang         # Node (npm)
bunx jsr add @jrmarcum/binaryang         # Bun
pnpm add jsr:@jrmarcum/binaryang         # pnpm 10.9+ (yarn 4.9+: yarn add jsr:@jrmarcum/binaryang)
deno add jsr:@jrmarcum/binaryang         # Deno
import { wat2wasm } from '@jrmarcum/binaryang/wat2wasm';

Only Deno can import JSR packages without installing them first. Node and Bun reject the jsr: prefix, and so do npm install and bun add. npx jsr add / bunx jsr add record the package as an npm:@jsr/jrmarcum__binaryang alias in package.json and write an .npmrc pointing the @jsr scope at JSR's registry. Commit both. pnpm 10.9+ and yarn 4.9+ understand jsr: natively and need no .npmrc. On Deno, import … from 'jsr:@jrmarcum/binaryang/wat2wasm' also works with no install.

Either way, Node and Bun receive compiled JavaScript with type declarations, so no TypeScript setup is needed. The examples below use the JSR name; from npm, write @synapticforge1/binaryang where they say @jrmarcum/binaryang.

Quick start

Assemble and disassemble

import { wat2wasm } from '@jrmarcum/binaryang/wat2wasm';
import { wasm2wat } from '@jrmarcum/binaryang/wasm2wat';
import { formatErrors, Result } from '@jrmarcum/binaryang/ir';

const source = `
  (module
    (func (export "add") (param i32 i32) (result i32)
      (i32.add (local.get 0) (local.get 1))))
`;

const { binary, errors, result } = wat2wasm(source, { filename: 'add.wat' });
if (result !== Result.Ok) {
  console.error(formatErrors(errors));
} else {
  console.log(binary.length); // 41

  const { text } = wasm2wat(binary, {});
  console.log(text); // the module, back as WAT — in the form it was written (folded here)
  // ...or wasm2wat(binary, { fold: false }) for the flat stack-machine form throughout
}

Every tool returns its outcome as a Result with an errors list rather than throwing, so a malformed input is a value you inspect. formatErrors renders it for humans.

Build a module

import { BinaryOp, createModule, ValType } from '@jrmarcum/binaryang/api';

const mod = createModule((b, e) => {
  b.addFunction(
    'add',
    [ValType.I32, ValType.I32],
    [ValType.I32],
    e.binary(BinaryOp.AddI32, e.localGet(0, ValType.I32), e.localGet(1, ValType.I32)),
  );
  b.addExport('add', 'add');
});

const bytes = mod.toBinary();
console.log(mod.toWat());

const { exports } = new WebAssembly.Instance(new WebAssembly.Module(bytes));
console.log((exports.add as (a: number, b: number) => number)(19, 23)); // 42

Read a module's structure

import { readBinary } from '@jrmarcum/binaryang/compat/binaryen';

const mod = readBinary(bytes); // the upstream binaryen.js shape
console.log(mod.getNumExports(), mod._inner.functions.length); // `_inner` is the Binaryen IR

Command line

One entry point, seven commands:

npx binaryang <command> [options]                                   # installed from npm
npx @synapticforge1/binaryang <command> [options]                   # from npm, no install
node node_modules/@jrmarcum/binaryang/main.js <command> [options]   # Node, installed from JSR
bun  node_modules/@jrmarcum/binaryang/main.js <command> [options]   # Bun, installed from JSR
deno run -A jsr:@jrmarcum/binaryang <command> [options]             # Deno, no install

| command | does | | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | wat2wasm <in.wat> | assemble and validate WAT to a WASM binary, as upstream · -o <file> · --no-check · --enable-all, --enable-<feature>, --disable-<feature> · --no-text-form¹ | | wasm2wat <in.wasm> | disassemble to WAT, every instruction in its written form¹ · -o <file> · --linear / --fold for one form throughout | | wasm-validate <in.wasm> | validate · --enable-all, --enable-<feature>, --disable-<feature> | | wasm-objdump <in.wasm> | dump sections | | wasm-strip <in.wasm> | remove custom sections · -o <file>, -s <section> | | wasm-opt <in> | optimise · -O0–-O4, -Os, -Oz, -S · --target portable (below) | | wasm-ctor-eval <in> | run constructors at build time and write their memory and globals into the module · --ctors=a,b, --kept-exports=a,b, --ignore-external-input, -o <file>, -S | | wasm-interp <in> | run exported functions on the interpreter and print each result · --run-all-exports, --run-export=NAME, --argument=V, --dummy-import-func | | wasm-bundle <in>... | bundle modules into one with ONE memory, each image relocated exactly through its linking / reloc.* sections (wasm-ld --emit-relocs, or (@reloc data) marks in WAT) · -o <file>, --on-conflict=prefix\|alias\|exclude, --alias a.wasm=m, --unmarked=guess, --start=NAME, -S · writes <out>.wit (the interface, from core signatures) unless --no-wit | | wasm2ts <in.wasm> | emit TypeScript — not yet implemented |

Every command answers --help — what it does, examples, and every option it accepts, in upstream wabt's layout — and --version:

npx binaryang wasm-opt --help

¹ wat2wasm → wasm2wat transpiles verbatim: wat2wasm records how each instruction was written — bare or folded, and grouped how — in a binaryang.text-form custom section, and wasm2wat gives it back that way: linear stays linear, folded stays folded, a mix stays the same mix (the plain nested fold where nothing is recorded, as for any other tool's binary). --no-text-form omits the record — upstream wat2wasm's bytes exactly. Optimizing drops it, and so does wasm-strip.

npx binaryang wat2wasm add.wat -o add.wasm                                  # from npm
npx binaryang wasm-opt add.wasm -o add.min.wasm -Oz
node node_modules/@jrmarcum/binaryang/main.js wat2wasm add.wat -o add.wasm  # from JSR

The installed package is compiled JavaScript (main.js), so Node needs no flags. The npm package declares binaryang as its command. JSR packages cannot (no bin entry), so after a JSR install a package.json script gives the same short form:

{ "scripts": { "binaryang": "node node_modules/@jrmarcum/binaryang/main.js" } }
npm run binaryang -- wat2wasm add.wat -o add.wasm

Node needs no flag, for the installed package (compiled JavaScript) or for this repository's source (erasable TypeScript, which Node's default type stripping runs, from 22.18 through 26).

What's in the package

Each import below is the JSR name; from npm, each starts with @synapticforge1/binaryang instead.

| import | contents | | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | @jrmarcum/binaryang/wat2wasm … /wasm2ts | the six WABT tools, one subpath each | | @jrmarcum/binaryang/ir | the IR: its records, the expression factories, the module builder, the value and GC types, and the vocabulary tool results use (Result, ErrorList, formatErrors) | | @jrmarcum/binaryang/api | high-level builder API | | @jrmarcum/binaryang/passes | optimisation pass registry and runner | | @jrmarcum/binaryang/wasm · /wasm-runtime | WASM helpers and a small runtime | | @jrmarcum/binaryang/tools/wasm-opt | wasm-opt as a library | | @jrmarcum/binaryang/tools/wasm-ctor-eval | wasm-ctor-eval as a library (ctorEval(module, options)) | | @jrmarcum/binaryang/tools/wasm-interp | wasm-interp as a library (interpModule(module, options)) | | @jrmarcum/binaryang/tools/wasm-bundle | wasm-bundle as a library (bundle(inputs, options), wasmBundle(paths, options)) | | @jrmarcum/binaryang/compat/binaryen | the upstream npm:binaryen API shape | | @jrmarcum/binaryang/compat/wabt | the upstream wabt.js API shape | | @jrmarcum/binaryang/definitions | shared data for other projects: the instructions (D1), features (D2), trap vocabulary (D3) and portability profiles (D4), with the JSON beside them |

No external dependencies. binaryang's reader, validator, writers, text tools and optimizer are entirely its own TypeScript; it has no external dependencies beyond the standard Node and Deno packages, and calls no external tool. Upstream tools (wast2json, wasm-tools, upstream binaryen) are used only by the repository's tests and its separate comparison suite — never by the published package. The compat/* subpaths reproduce upstream's API shapes; they do not load upstream.

One IR, one subpath. The reader, writers and validator and the optimisation passes all work on one IR, and ./ir exports it under both WABT's names (Expr, Module) and Binaryen's (Expression, WasmModule) — the same types. One name means one thing: Type is the value-type enum (Type.I32); the type of a node's type field is ExprType.

Runtime support

Runs on Deno, Node.js, Bun and modern browsers from a single source tree.

| runtime | minimum | tested in CI | note | | -------- | ----------- | ------------------------------------------------------ | --------------------------------- | | Deno | 2.x | 2.x | | | Node.js | 22.18.0 | 22.18.0, latest 22, 24, 26 | no flags¹ | | Bun | 1.4.0 | 1.4.0 | | | browsers | modern | Chromium, Chrome, Edge, Brave, Opera, Firefox, WebKit² | library surface only, not the CLI |

¹ Node users receive compiled JavaScript: the npm package's, or JSR's own build. binaryang's TypeScript source (a clone of this repository) also runs on Node with no flag: it is ERASABLE TypeScript, with no enums and no constructor parameter properties, which Node's default type stripping accepts, Node 26 included. The compiler option erasableSyntaxOnly keeps it that way.

² Every export is bundled for the browser target in CI and must not import a Node builtin; the library's command-line paths load Node's file system only when they run. CI then RUNS the library in each of these browsers, headless (WebKit is Safari's engine): every export loads, and wat2wasm and wasmOpt give byte-identical output to Deno, Node and Bun on 421 modules, which each browser's engine accepts. The browser recipe below runs there too.

Making a module run on every widely used engine

--target portable makes the output run, with the same behaviour, on the engines most people run WebAssembly on: wasmtime, wasmer, WasmEdge and wazero; Node, Deno and Bun; Chrome, Edge, Firefox (release and ESR) and Safari's engine. What some of them refuse is rewritten into what all of them run (the passes below), before any optimization. What nothing can rewrite is refused, every such feature named with the engines that refuse it:

npx binaryang wasm-opt in.wasm --target portable -Oz -o out.wasm
wasm-opt: --target portable: the module uses features no pass makes portable (engines measured 2026-10-24):
  gc — refused by wasmer, wazero
  multiMemory — refused by wazero

| the module uses | --target portable | | --- | --- | | Wasm 2.0, threads, standard exception handling, typed function references, tail calls, extended-const | keeps it | | memory64, custom page sizes, wide arithmetic, relaxed SIMD, legacy exception handling | lowers it | | GC, multi-memory, custom descriptors, br_on_non_null | refuses the module |

import { TargetError, wasmOpt } from '@jrmarcum/binaryang/tools/wasm-opt';
try {
  const out = await wasmOpt(bytes, { target: 'portable', optimizeLevel: 2, shrinkLevel: 2 });
} catch (e) {
  if (e instanceof TargetError) for (const f of e.findings) console.log(f.name, f.refusedBy);
}

The profile is data, measured: @jrmarcum/binaryang/definitions exports it as D4 (PROFILE_DEFINITIONS, and profiles.json for other languages), each feature with its tier, the engines measured refusing it, and the builds measured. An engine that catches up moves a feature when it is measured again. Safari's engine was measured as Playwright's WebKit build, which is newer than any shipped Safari; for Safari itself, the profile follows MDN's compatibility data (memory64, multi-memory and relaxed SIMD are Technology Preview only there, and the profile lowers or refuses each). For projects that produce, run or load modules, the opcode guide sets out the whole profile — every feature's tier, what a producer, a runtime and a loader should do with it, and the behaviour that differs between engines.

Making a module run on Safari and Bun

binaryang runs everywhere; a module you build may not. JavaScriptCore — the engine in Safari and in Bun — refuses some features V8 (Chrome, Node, Deno) accepts. Two passes rewrite a module so it runs there, with the same behaviour:

| the module uses | JavaScriptCore says | run | | --------------- | ------------------- | --- | | a 64-bit memory or table (memory64) | "Memory64 is not enabled" | --memory64-lowering | | legacy exception handling (try … delegate) | "delegate target isn't a try block" | --translate-to-exnref |

npx binaryang wasm-opt in.wasm --memory64-lowering --translate-to-exnref -o out.wasm
import { wasmOpt } from '@jrmarcum/binaryang/tools/wasm-opt';
const out = await wasmOpt(bytes, { passes: ['memory64-lowering', 'translate-to-exnref'] });

--memory64-lowering keeps the module's behaviour, unlike Binaryen's pass of the same name: an address, index or length of 2^32 or more still traps out of bounds (Binaryen's wraps it, so a load reads the wrong bytes and a store overwrites them). A lowered memory holds at most 65,535 pages (4 GiB less one page) and a lowered table 2^32 − 2 elements; a module that starts larger is refused with a message. An imported or exported 64-bit memory or table becomes a 32-bit one, so the host supplies or receives a 32-bit one. Every spec module with a 64-bit memory or table is checked lowered, against the original, on V8 and on JavaScriptCore (bun run lowering). Multi-memory has no pass: Bun's JavaScriptCore runs it (up to 100 memories; V8 has no such limit), but Safari ships it only in Technology Preview (MDN browser-compat-data, 2026-10), so a module for Safari should use one memory — which is all any compiler measured emits.

Making a module run without wide arithmetic

The wide-arithmetic instructions (i64.add128, i64.sub128, i64.mul_wide_s, i64.mul_wide_u) run on Bun, Firefox and wasmtime, but V8 (Chrome, Edge, Node, Deno), Safari's engine, WasmEdge, wasmer, wazero and Firefox ESR refuse them. --wide-arithmetic-lowering rewrites each to plain i64 arithmetic — exact for every input, a 128-bit result as the proposal defines it — through one small helper function per instruction used:

npx binaryang wasm-opt in.wasm --wide-arithmetic-lowering -o out.wasm

Making a module run without relaxed SIMD

The relaxed-SIMD instructions (f32x4.relaxed_madd, i8x16.relaxed_swizzle, the relaxed dot products, …) let each engine pick the fastest answer its hardware gives, so the same module returns different results on different engines. On 68 edge cases (NaN, -0, out-of-range floats, swizzle indices of 16 or more, …), engines matched the specification's deterministic answer on anywhere from 32 to 67 of them, depending on the engine. wasmer and wazero refuse the instructions outright, and Safari ships them only in Technology Preview. --relaxed-simd-lowering rewrites each one to plain SIMD-128 that computes the WebAssembly specification's deterministic profile: the one answer the specification fixes for every relaxed instruction, the same on every engine:

| relaxed | becomes | | --- | --- | | relaxed_swizzle, relaxed_trunc_*, relaxed_min / max, relaxed_q15mulr_s | the regular instruction | | relaxed_laneselect | v128.bitselect | | relaxed_madd / relaxed_nmadd | multiply, then add (unfused: two roundings) | | relaxed_dot_i8x16_i7x16_s / _add_s | both operands signed, 16-bit sums wrapping |

npx binaryang wasm-opt in.wasm --relaxed-simd-lowering -o out.wasm

The hardware's fused multiply-add and single-instruction dot products are given up for plain SIMD-128 instructions that every engine runs. The cost, measured on a loop of nothing but the one instruction (each result feeding the next) on Node, Bun and wasmtime:

| instruction | lowered, time against the original | | --- | --- | | swizzle, laneselect | the same | | madd / nmadd, q15mulr, the truncations | up to about 2.3× (Bun: the same, except nmadd 1.2×) | | the dot products | about 1.7 – 4.3× | | min / max | about 3.4 – 4.7× (a regular min / max is slower than the relaxed one everywhere) |

A real program spends a share of its time on these instructions, so its slowdown is that share scaled by these factors. Lower only for an engine that cannot run relaxed SIMD, or where every engine must give the same result.

TinyGo's memcpy, as one instruction

TinyGo builds without bulk memory, so its modules carry wasi-libc's memcpy and memmove as loops. --memcpy-to-bulk-memory replaces each with one memory.copy — about 1.1–1.5 KB, 9–11% of a TinyGo module measured — and so does --target portable with an optimization level. Only a function whose code is byte for byte a known wasi-libc one is replaced; anything else is left alone. For every call with a defined result the bytes and return value are the same. Two calls are not: a memcpy of OVERLAPPING ranges (undefined in C; memory.copy copies them correctly) and a copy out of bounds (both trap, but the loop writes the bytes before the bad address first).

npx binaryang wasm-opt tinygo.wasm --memcpy-to-bulk-memory -Oz -o out.wasm

Optimizing in the browser

A page can shrink a WebAssembly module it does not control (third-party, user-supplied, a playground's) on the user's machine. Expect a size win, not speed. Measured in Chrome, Firefox and Safari's engine on real compiler output (Rust, Zig, TinyGo; debug and release builds of one compute workload): code bytes −0.1% to −27%, 60 ms to 1.7 s to optimize, and no run-time speedup, not even on the debug builds; the engines' own optimizing tiers already did that work. A site that builds its own module should optimize it at build time instead.

examples/browser-optimize is the recipe, two files to copy and bundle side by side. It runs wasmOpt in a Worker with a time limit, keeps the original whenever the browser refuses the input, the optimizer fails or the result is no smaller, and caches results by the input's SHA-256 (Cache API):

import { optimizeInBrowser } from './optimize.ts';

const original = new Uint8Array(await (await fetch(url)).arrayBuffer());
const { bytes, optimized, reason } = await optimizeInBrowser(original);
const { instance } = await WebAssembly.instantiate(bytes, imports);

Node.js: every current LTS line is supported and tested (Node 22 "Jod" and Node 24 "Krypton" as of 2026-10). Supported means not end-of-life: Node 18 ended 2025-04-30 and Node 20 on 2026-04-30, so neither is supported. Node 22 is in maintenance until 2027-04-30. The floor is 22.18.0 rather than 22.0 because import.meta.main was backported to the v22 line in 22.18.0.

Bun: 1.4.0 is the Zig → Rust rewrite. The floor sits on that boundary so binaryang never spans two different implementations of the same runtime. Bun 1.3 is not end-of-life and is still not supported here — the one place the two runtimes are governed differently, said plainly rather than buried.

Migrating

⚠️ Breaking Changes

Every release that removed or renamed something you could import. From the release after 1.15.0 on, a break is a major version, and the release tooling refuses a lower one (Semantic Versioning, checked against a committed snapshot of the API); the three before 2.0.0 came out as minors, before that rule.

| Version | What changed | How to migrate | | ------- | --------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | 2.0.0 | --enable-sat-float-to-int / --disable-sat-float-to-int removed (deprecated in 1.17.0); ./definitions: FeatureDefinition.cliAliases removed, D2 data version 2.0.0 | spell it as upstream wabt and wasm-tools do: --enable-saturating-float-to-int / --disable-saturating-float-to-int | | 1.12.0 | ./ir/binaryen-ts, ./ir/wabt-ts, ./core/wabt-ts removed (deprecated in 1.11.0); type names Type in ./api, Features / WasmModule in ./compat/wabt removed | import from ./ir, which exports the same names from the same declarations; use ExprType, WabtFeatures, WabtWasmModule | | 1.7.0 | ./interop removed, with Module.optimize(flags, hybridMode)'s hybridMode and wasm-opt --hybrid | run upstream wasm-opt directly to compare; the compat/* APIs are unchanged | | 1.6.0 | ./binary and ./encoder removed; the Binaryen IR took wabt-ts's record shapes | read with readBinary from ./compat/binaryen, write with module.emitBinary() or toBinary() from ./api; CHANGELOG § 1.6.0 lists the renames |

From the predecessors

From either predecessor, this is a package rename plus two subpaths.

| was | now | | ------------------------------------------------------- | ------------------------------------- | | @jrmarcum/binaryen-ts/compat | @jrmarcum/binaryang/compat/binaryen | | @jrmarcum/wabt-ts/compat | @jrmarcum/binaryang/compat/wabt | | @jrmarcum/binaryen-ts/ir | @jrmarcum/binaryang/ir ¹ | | the WABT IR, via the wabt-ts package root | @jrmarcum/binaryang/ir | | Result, ErrorList, formatErrors, via the root | @jrmarcum/binaryang/ir |

¹ Binaryen's Type union is ExprType there. (Through 1.11.0 these three were also ./ir/binaryen-ts, ./ir/wabt-ts and ./core/wabt-ts, deprecated in 1.11.0 and removed after.)

Everything else keeps its name: ./api, ./passes, ./wasm, ./wasm-runtime, ./tools/wasm-opt, and the six WABT tool subpaths. (./binary and ./encoder were removed at 1.6.0, and ./interop — the bridge to upstream binaryen.js — at 1.7.0.)

If you imported from the wabt-ts package root, you need a named subpath now. That package shipped its IR and its core vocabulary through the root; binaryang's root is deliberately narrow, because a root spanning both IRs would surface every colliding type name at one specifier.

// was
import { Result, wat2wasm } from 'jsr:@jrmarcum/wabt-ts';
// now
import { wat2wasm } from 'jsr:@jrmarcum/binaryang/wat2wasm';
import { Result } from 'jsr:@jrmarcum/binaryang/ir';

The six WABT tools were previously separate published entry points that self-executed. They are now registered in one CLI dispatcher, which is what lets them run on Node and Bun rather than Deno alone.

Pinned to an old version? Nothing breaks. @jrmarcum/binaryen-ts and @jrmarcum/wabt-ts each get a final 1.5.1 release pointing here and are then archived. Every published version keeps resolving — nothing is yanked.

Contributing

Project memory lives in cmem/ — start with cmem/INDEX.md. Two rules are binding and enforced in CI: upstream project names are reserved for upstream-compatibility paths, and runtime portability is enforced (no Deno-specific globals in shipped source, and no top-level import of a node: builtin anywhere in it, because those do not load in a browser; the CLI loads Node's file system only when it runs, and every export is bundled for the browser in CI).

Licence

MIT, with Apache-2.0 available as an alternative. binaryang is a derivative of the Apache-2.0 WebAssembly/wabt and WebAssembly/binaryen projects and carries LICENSE-APACHE, NOTICE.md and per-file attribution headers. See cmem/licensing.md.