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

@webdyne/webdyne-zeroperl-ts

v1.1.4

Published

Perl 5 interpreter powered by WebAssembly for JavaScript runtimes

Readme

ZeroPerl TypeScript bridge — WebDyne integration fork

For maintainers: architecture, verification, and release tagging and npm staging.

Runnable, maintained examples are in examples/, including data exchange, asynchronous callbacks, browser usage and a local Worker.

Working from source

This repository tracks the TypeScript bridge, tests, licenses and runtime manifest. Generated dist/, zeroperl.wasm and third-party-notices.tar.gz are local build inputs/outputs and are not tracked by Git. The WebDyne runtime package built by aspeer/zeroperl includes its own compiled bridge and runtime; it does not require publication of this standalone npm package.

To test or build the standalone package, install dependencies and import the matching artifacts produced by aspeer/zeroperl:

npm ci
npm run runtime:prepare -- /path/to/runtime/artifacts
npm test
npm run build
npm run pack:check

The directory must contain the versioned WASM and notices filenames recorded in runtime-manifest.json. Alternatively, pass an HTTP(S) base URL containing those files, or set ZEROPERL_ARTIFACT_BASE_URL. Both size and SHA-256 must match the tracked manifest. With no source argument or environment variable, runtime:prepare verifies existing local artifacts. It does not build Perl.

For GitHub Actions, configure the repository Actions variable ZEROPERL_ARTIFACT_BASE_URL with a publicly readable directory or release-asset base URL containing the matching artifacts. CI cannot run runtime tests until those artifacts are hosted and the variable is configured.

The standalone npm package still includes WASM and attribution when built; Git exclusions do not remove them from the published package. Update the manifest only when intentionally adopting a newly qualified runtime build.

This is a fork of 6over3/zeroperl-ts, the JavaScript/TypeScript bridge for the original 6over3/zeroperl project. This fork supports the WebDyne WASM runtime, primarily on Cloudflare Workers today, with the potential to support other WASM providers later. The bridge also remains usable by applications embedding Perl directly.

WebDyne-specific guidance is in WEBDYNE.md. Current generic installation and API instructions for @webdyne/webdyne-zeroperl-ts are in USAGE.md. This package is available from npm and maintained on the main branch. See LICENSE and NOTICE for licensing and attribution.

Credits

Original upstream README

The text below is from the original 6over3/zeroperl-ts repository's README at 5e12fb8, preserved with trailing whitespace removed. Its package names and examples describe that upstream revision. Use USAGE.md for this fork's current package and API, and WEBDYNE.md for the integration.


zeroperl-ts

Perl 5 compiled to WebAssembly. Run Perl scripts in the browser or other JavaScript environments without installing Perl.

Built on zeroperl.

Features

  • Runs Perl 5 in browser, Node.js, Deno, and Bun
  • Virtual filesystem for script and data files
  • Bidirectional data exchange between JavaScript and Perl
  • Register JavaScript functions callable from Perl
  • Call Perl functions from JavaScript
  • Environment variable support
  • Output capture (stdout/stderr)
  • TypeScript type definitions included

Installation

npm install @6over3/zeroperl-ts
# or
bun add @6over3/zeroperl-ts

Or, for Browser Usage, copy the zeroperl WASM binary to your local website (to avoid CORS errors).

# The -L option allows the CDN to redirect to the latest version
curl -L -O https://esm.sh/@6over3/zeroperl-ts/zeroperl.wasm

Quick Start

import { ZeroPerl } from '@6over3/zeroperl-ts';

const perl = await ZeroPerl.create();
await perl.eval('print "Hello, World!\\n"');
perl.flush(); // Required to see output
perl.dispose();

Output Buffering

Perl buffers output by default. Choose one approach:

Option 1: Call flush() after printing

await perl.eval('print "Hello!\\n"');
perl.flush();

Option 2: Enable autoflush in Perl

await perl.eval(`
  $| = 1;  # Enable autoflush
  print "Hello!\\n";
`);

Basic Usage

Evaluating Perl Code

import { ZeroPerl } from '@6over3/zeroperl-ts';

const perl = await ZeroPerl.create();

const result = await perl.eval(`
  $| = 1;
  my $x = 42;
  print "The answer is $x\\n";
`);

if (!result.success) {
  console.error('Error:', result.error);
}

perl.dispose();

Capturing Output

let output = '';

const perl = await ZeroPerl.create({
  stdout: (data) => {
    output += typeof data === 'string' ? data : new TextDecoder().decode(data);
  }
});

await perl.eval(`
  $| = 1;
  print "Line 1\\n";
  print "Line 2\\n";
`);

console.log(output);
// Output:
// Line 1
// Line 2

perl.dispose();

Exchanging Data

const perl = await ZeroPerl.create();

// JavaScript to Perl
perl.setVariable('name', 'Alice');
perl.setVariable('age', 30);

await perl.eval(`
  $| = 1;
  print "Name: $name\\n";
  print "Age: $age\\n";
`);

// Perl to JavaScript
await perl.eval('$result = 2 + 2');
const result = perl.getVariable('result');
console.log(result.toInt()); // 4

result.dispose();
perl.dispose();

Working with Arrays and Hashes

const perl = await ZeroPerl.create();

// Create array
const arr = perl.createArray([1, 2, 3, 'hello']);
perl.setVariable('myarray', arr.toValue());

// Create hash
const hash = perl.createHash({
  name: 'Alice',
  age: 30,
  active: true
});
perl.setVariable('user', hash.toValue());

await perl.eval(`
  $| = 1;
  print "Array length: ", scalar(@$myarray), "\\n";
  print "User: $user->{name}, Age: $user->{age}\\n";
`);

// Convert back to JavaScript
const jsArray = arr.project(); // [1, 2, 3, 'hello']
const jsObject = hash.project(); // { name: 'Alice', age: 30, active: true }

arr.dispose();
hash.dispose();
perl.dispose();

Command-Line Arguments

const perl = await ZeroPerl.create();

await perl.eval(`
  $| = 1;
  print "Arguments: @ARGV\\n";
  foreach my $arg (@ARGV) {
    print "  $arg\\n";
  }
`, ['foo', 'bar', 'baz']);

perl.dispose();

Working with Files

Creating a Virtual Filesystem

import { ZeroPerl, MemoryFileSystem } from '@6over3/zeroperl-ts';

const fs = new MemoryFileSystem({ "/": "" });

fs.addFile("/data.txt", "Hello from a file!");
fs.addFile("/script.pl", `
  $| = 1;
  open my $fh, '<', '/data.txt' or die $!;
  while (my $line = <$fh>) {
    print "Read: $line";
  }
  close $fh;
`);

const perl = await ZeroPerl.create({ fileSystem: fs });

await perl.runFile('/script.pl');

perl.dispose();

Running Scripts with Arguments

const fs = new MemoryFileSystem({ "/": "" });
fs.addFile("/greet.pl", `
  $| = 1;
  my ($name, $greeting) = @ARGV;
  print "$greeting, $name!\\n";
`);

const perl = await ZeroPerl.create({ fileSystem: fs });

await perl.runFile('/greet.pl', ['Alice', 'Hello']);
// Output: Hello, Alice!

perl.dispose();

Reading and Writing Files

const fs = new MemoryFileSystem({ "/": "" });

const perl = await ZeroPerl.create({ fileSystem: fs });

// Write from Perl
await perl.eval(`
  $| = 1;
  open my $fh, '>', '/output.txt' or die $!;
  print $fh "Generated content\\n";
  close $fh;
  print "File written!\\n";
`);

// Read from JavaScript
const content = fs.readFile('/output.txt');
console.log(content); // "Generated content\n"

perl.dispose();

Advanced Usage

Registering JavaScript Functions

Register JavaScript functions that can be called from Perl:

const perl = await ZeroPerl.create();

perl.registerFunction('add', (a, b) => {
  const x = a.toInt();
  const y = b.toInt();
  return perl.createInt(x + y);
});

await perl.eval(`
  $| = 1;
  my $sum = add(10, 32);
  print "Sum: $sum\\n";
`);

perl.dispose();

Registering JavaScript Methods

const perl = await ZeroPerl.create();

perl.registerMethod('Math', 'square', (x) => {
  const num = x.toInt();
  return perl.createInt(num * num);
});

await perl.eval(`
  $| = 1;
  my $result = Math::square(7);
  print "Square: $result\\n";
`);

perl.dispose();

Calling Perl Functions from JavaScript

const perl = await ZeroPerl.create();

await perl.eval(`
  sub greet {
    my ($name) = @_;
    return "Hello, $name!";
  }

  sub get_values {
    return (1, 2, 3);
  }
`);

// Scalar context (single return value)
const arg = perl.createString("Alice");
const greeting = await perl.call("greet", [arg], "scalar");
console.log(greeting?.toString()); // "Hello, Alice!"

// List context (multiple return values)
const values = await perl.call("get_values", [], "list");
console.log(values.map(v => v.toInt())); // [1, 2, 3]

// Void context (no return value)
await perl.call("some_sub", [], "void");

arg.dispose();
greeting?.dispose();
for (const v of values) v.dispose();
perl.dispose();

Error Handling

const perl = await ZeroPerl.create();

const result = await perl.eval(`
  die "Something went wrong!";
`);

if (!result.success) {
  console.log('Exit code:', result.exitCode);
  console.log('Error:', result.error);
}

// Get error directly
const error = perl.getLastError();
console.log(error); // "Something went wrong! at ..."

// Clear error
perl.clearError();

perl.dispose();

Environment Variables

const perl = await ZeroPerl.create({
  env: {
    API_KEY: 'secret123',
    DEBUG: 'true'
  }
});

await perl.eval(`
  $| = 1;
  print "API Key: $ENV{API_KEY}\\n";
  print "Debug: $ENV{DEBUG}\\n";
`);

perl.dispose();

Resetting State

const perl = await ZeroPerl.create();

await perl.eval('$counter = 1');
const val1 = perl.getVariable('counter');
console.log(val1?.toInt()); // 1

await perl.reset();

const val2 = perl.getVariable('counter');
console.log(val2); // null

val1?.dispose();
perl.dispose();

Progressive Output

const perl = await ZeroPerl.create({
  stdout: (data) => process.stdout.write(data)
});

for (let i = 0; i < 5; i++) {
  await perl.eval('print "."');
  perl.flush();
  await new Promise(r => setTimeout(r, 500));
}

perl.dispose();

Browser Usage

With bundler (recommended):

import { ZeroPerl } from '@6over3/zeroperl-ts';
import zeroperl from '@6over3/zeroperl-ts/zeroperl.wasm';

const perl = await ZeroPerl.create({
  fetch: () => fetch(zeroperl),
  stdout: (data) => console.log(data)
});

await perl.eval(`
  $| = 1;
  print "Hello from Perl!\\n";
  print "Running in: $^O\\n";
`);

perl.dispose();

Note: Most bundlers should copy the WASM file when imported explicitly. If your bundler doesn't handle this, configure it to copy static assets or use the CDN approach below.

From CDN:

<!DOCTYPE html>
<html>
<body>
  <div id="output"></div>

  <script type="module">
    import { ZeroPerl } from 'https://esm.sh/@6over3/zeroperl-ts';

    const output = document.getElementById('output');

    const perl = await ZeroPerl.create({
      stdout: (data) => {
        const text = typeof data === 'string' ? data : new TextDecoder().decode(data);
        output.innerHTML += text.replace(/\n/g, '<br>');
      }
    });

    await perl.eval(`
      $| = 1;
      print "Hello from Perl!\\n";
      print "Running in: $^O\\n";
    `);

    perl.dispose();
  </script>
</body>
</html>

API Reference

ZeroPerl.create(options?)

Create a new Perl interpreter instance.

Options:

  • env - Environment variables (Record<string, string>)
  • fileSystem - Virtual filesystem (MemoryFileSystem)
  • stdout - stdout callback ((data: string | Uint8Array) => void)
  • stderr - stderr callback ((data: string | Uint8Array) => void)
  • fetch - Custom fetch for WASM loading
const perl = await ZeroPerl.create({
  env: { KEY: 'value' },
  fileSystem: fs,
  stdout: (data) => console.log(data),
  stderr: (data) => console.error(data)
});

perl.eval(code, args?)

Evaluate Perl code. Returns { success: boolean, error?: string, exitCode: number }.

const result = await perl.eval('print "Hello\\n"', ['arg1', 'arg2']);

perl.runFile(path, args?)

Run a Perl script from the virtual filesystem.

await perl.runFile('/script.pl', ['arg1', 'arg2']);

perl.createInt(value), perl.createDouble(value), perl.createString(value), perl.createBool(value), perl.createUndef()

Create Perl values. Returns PerlValue.

const num = perl.createInt(42);
const str = perl.createString("hello");
const bool = perl.createBool(true);

perl.createArray(values?), perl.createHash(object?)

Create Perl arrays and hashes. Returns PerlArray or PerlHash.

const arr = perl.createArray([1, 2, 3]);
const hash = perl.createHash({ key: 'value' });

perl.toPerlValue(value)

Convert JavaScript value to Perl. Handles primitives, arrays, and objects.

const perlVal = perl.toPerlValue({ name: 'Alice', age: 30 });

perl.setVariable(name, value), perl.getVariable(name)

Set and get scalar variables. Variable names should not include the $ prefix.

perl.setVariable('x', 42);
const x = perl.getVariable('x');
console.log(x?.toInt()); // 42

perl.getArrayVariable(name), perl.getHashVariable(name)

Get array and hash variables. Returns PerlArray or PerlHash.

const arr = perl.getArrayVariable('myarray');
const hash = perl.getHashVariable('myhash');

perl.registerFunction(name, fn)

Register a JavaScript function callable from Perl.

perl.registerFunction('add', (a, b) => {
  const x = a.toInt();
  const y = b.toInt();
  return perl.createInt(x + y);
});

perl.registerMethod(packageName, methodName, fn)

Register a JavaScript method callable from Perl.

perl.registerMethod('Math', 'square', (x) => {
  const num = x.toInt();
  return perl.createInt(num * num);
});

perl.call(name, args, context?)

Call a Perl function. Context can be "void", "scalar", or "list".

const result = await perl.call('my_sub', [arg1, arg2], 'scalar');
const results = await perl.call('my_sub', [], 'list');
await perl.call('my_sub', [], 'void');

perl.flush()

Flush output buffers. Required if autoflush ($| = 1) is not set.

await perl.eval('print "text"');
perl.flush();

perl.reset()

Reset interpreter to clean state. Clears all variables.

await perl.reset();

perl.getLastError(), perl.clearError()

Get and clear the Perl error state ($@).

const error = perl.getLastError();
perl.clearError();

perl.isInitialized(), perl.canEvaluate()

Check interpreter state.

const ready = perl.isInitialized() && perl.canEvaluate();

perl.dispose(), perl.shutdown()

Free resources. Use dispose() for normal cleanup, shutdown() for complete termination.

perl.dispose();
// or
perl.shutdown();

PerlValue Methods

  • toInt() - Convert to 32-bit integer
  • toDouble() - Convert to double-precision float
  • toString() - Convert to UTF-8 string
  • toBoolean() - Convert to boolean (Perl truth test)
  • isUndef() - Check if undefined
  • isRef() - Check if reference
  • getType() - Get Perl type
  • project() - Convert to JavaScript primitive
  • createRef() - Create reference
  • deref() - Dereference value
  • dispose() - Free memory

PerlArray Methods

  • push(value) - Add to end
  • pop() - Remove from end
  • get(index) - Get value at index
  • set(index, value) - Set value at index
  • getLength() - Get array length
  • clear() - Remove all elements
  • toValue() - Convert to PerlValue (array reference)
  • project() - Convert to JavaScript array
  • [Symbol.iterator]() - Iterate over values
  • dispose() - Free memory

PerlHash Methods

  • set(key, value) - Set key-value pair
  • get(key) - Get value by key
  • has(key) - Check if key exists
  • delete(key) - Delete key
  • clear() - Remove all entries
  • toValue() - Convert to PerlValue (hash reference)
  • project() - Convert to JavaScript object
  • entries() - Iterate over key-value pairs
  • keys() - Iterate over keys
  • values() - Iterate over values
  • dispose() - Free memory

Examples

Processing JSON

import { ZeroPerl, MemoryFileSystem } from '@6over3/zeroperl-ts';

const fs = new MemoryFileSystem({ "/": "" });
fs.addFile("/data.json", JSON.stringify({ users: ['Alice', 'Bob'] }));
fs.addFile("/process.pl", `
  $| = 1;
  use strict;
  use warnings;

  open my $fh, '<', '/data.json' or die $!;
  my $json = do { local $/; <$fh> };
  close $fh;

  print "Processing: $json\\n";
`);

const perl = await ZeroPerl.create({ fileSystem: fs });
await perl.runFile('/process.pl');
perl.dispose();

Interactive REPL

const perl = await ZeroPerl.create({
  stdout: (data) => console.log(data)
});

await perl.eval('$| = 1');

await perl.eval('$x = 10');
await perl.eval('print "$x\\n"');
await perl.eval('$x *= 2');
await perl.eval('print "$x\\n"');

perl.dispose();

Complex Data Structures

const perl = await ZeroPerl.create();

perl.setVariable('config', {
  server: {
    host: 'localhost',
    port: 8080
  },
  features: ['auth', 'logging']
});

await perl.eval(`
  $| = 1;
  print "Host: $config->{server}{host}\\n";
  print "Port: $config->{server}{port}\\n";
  print "Features: @{$config->{features}}\\n";
`);

perl.dispose();

Development

npm i              # Install dependencies
bun run build      # Build distributions
bun test           # Run tests

License

Apache-2.0

About

ZeroPerl compiles Perl 5 to WebAssembly using a WASI-compliant implementation. This package provides a TypeScript/JavaScript API for the ZeroPerl WASM module.