Perl 5 interpreter powered by WebAssembly for JavaScript runtimes
npm install @6over3/zeroperl-tsPerl 5 compiled to WebAssembly. Run Perl scripts in the browser or other JavaScript environments without installing Perl.
Built on zeroperl.
- 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
``bash`
npm install @6over3/zeroperl-tsor
bun add @6over3/zeroperl-ts
Or, for Browser Usage, copy the zeroperl WASM binary to your local website (to avoid CORS errors).
`bash`The -L option allows the CDN to redirect to the latest version
curl -L -O https://esm.sh/@6over3/zeroperl-ts/zeroperl.wasm
`typescript
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();
`
Perl buffers output by default. Choose one approach:
Option 1: Call flush() after printing
`typescript`
await perl.eval('print "Hello!\\n"');
perl.flush();
Option 2: Enable autoflush in Perl
`typescript
await perl.eval(
$| = 1; # Enable autoflush
print "Hello!\\n";);`
`typescript
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();
`
`typescript
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();
`
`typescript
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();
`
`typescript
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();
`
`typescript
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();
`
`typescript
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();
`
`typescript
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();
`
`typescript
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();
`
Register JavaScript functions that can be called from Perl:
`typescript
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();
`
`typescript
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();
`
`typescript
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();
`
`typescript
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();
`
`typescript
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();
`
`typescript
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();
`
`typescript
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();
`
With bundler (recommended):
`typescript
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:
`html`
Create a new Perl interpreter instance.
Options:
- env - Environment variables (RecordfileSystem
- - Virtual filesystem (MemoryFileSystem)stdout
- - stdout callback ((data: string | Uint8Array) => void)stderr
- - stderr callback ((data: string | Uint8Array) => void)fetch
- - Custom fetch for WASM loading
`typescript`
const perl = await ZeroPerl.create({
env: { KEY: 'value' },
fileSystem: fs,
stdout: (data) => console.log(data),
stderr: (data) => console.error(data)
});
Evaluate Perl code. Returns { success: boolean, error?: string, exitCode: number }.
`typescript`
const result = await perl.eval('print "Hello\\n"', ['arg1', 'arg2']);
Run a Perl script from the virtual filesystem.
`typescript`
await perl.runFile('/script.pl', ['arg1', 'arg2']);
Create Perl values. Returns PerlValue.
`typescript`
const num = perl.createInt(42);
const str = perl.createString("hello");
const bool = perl.createBool(true);
Create Perl arrays and hashes. Returns PerlArray or PerlHash.
`typescript`
const arr = perl.createArray([1, 2, 3]);
const hash = perl.createHash({ key: 'value' });
Convert JavaScript value to Perl. Handles primitives, arrays, and objects.
`typescript`
const perlVal = perl.toPerlValue({ name: 'Alice', age: 30 });
Set and get scalar variables. Variable names should not include the $ prefix.
`typescript`
perl.setVariable('x', 42);
const x = perl.getVariable('x');
console.log(x?.toInt()); // 42
Get array and hash variables. Returns PerlArray or PerlHash.
`typescript`
const arr = perl.getArrayVariable('myarray');
const hash = perl.getHashVariable('myhash');
Register a JavaScript function callable from Perl.
`typescript`
perl.registerFunction('add', (a, b) => {
const x = a.toInt();
const y = b.toInt();
return perl.createInt(x + y);
});
Register a JavaScript method callable from Perl.
`typescript`
perl.registerMethod('Math', 'square', (x) => {
const num = x.toInt();
return perl.createInt(num * num);
});
Call a Perl function. Context can be "void", "scalar", or "list".
`typescript`
const result = await perl.call('my_sub', [arg1, arg2], 'scalar');
const results = await perl.call('my_sub', [], 'list');
await perl.call('my_sub', [], 'void');
Flush output buffers. Required if autoflush ($| = 1) is not set.
`typescript`
await perl.eval('print "text"');
perl.flush();
Reset interpreter to clean state. Clears all variables.
`typescript`
await perl.reset();
Get and clear the Perl error state ($@).
`typescript`
const error = perl.getLastError();
perl.clearError();
Check interpreter state.
`typescript`
const ready = perl.isInitialized() && perl.canEvaluate();
Free resources. Use dispose() for normal cleanup, shutdown() for complete termination.
`typescript`
perl.dispose();
// or
perl.shutdown();
- toInt() - Convert to 32-bit integertoDouble()
- - Convert to double-precision floattoString()
- - Convert to UTF-8 stringtoBoolean()
- - Convert to boolean (Perl truth test)isUndef()
- - Check if undefinedisRef()
- - Check if referencegetType()
- - Get Perl typeproject()
- - Convert to JavaScript primitivecreateRef()
- - Create referencederef()
- - Dereference valuedispose()
- - Free memory
- push(value) - Add to endpop()
- - Remove from endget(index)
- - Get value at indexset(index, value)
- - Set value at indexgetLength()
- - Get array lengthclear()
- - Remove all elementstoValue()
- - Convert to PerlValue (array reference)project()
- - Convert to JavaScript array[Symbol.iterator]()
- - Iterate over valuesdispose()
- - Free memory
- set(key, value) - Set key-value pairget(key)
- - Get value by keyhas(key)
- - Check if key existsdelete(key)
- - Delete keyclear()
- - Remove all entriestoValue()
- - Convert to PerlValue (hash reference)project()
- - Convert to JavaScript objectentries()
- - Iterate over key-value pairskeys()
- - Iterate over keysvalues()
- - Iterate over valuesdispose()
- - Free memory
`typescript
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();
`
`typescript
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();
`
`typescript
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();
`
`bash``
npm i # Install dependencies
bun run build # Build distributions
bun test # Run tests
Apache-2.0
ZeroPerl compiles Perl 5 to WebAssembly using a WASI-compliant implementation. This package provides a TypeScript/JavaScript API for the ZeroPerl WASM module.