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

@live-codes/pascal-wasm

v0.1.0

Published

The Free Pascal pas2js compiler compiled to WebAssembly, for browsers and Web Workers. Compiles Pascal entirely client-side.

Readme

@live-codes/pascal-wasm

The pas2js compiler — the Free Pascal team's Pascal → JavaScript transpiler — compiled to WebAssembly, for use in browsers and Web Workers.

Compilation runs entirely on the client. There is no server, no account, and the source never leaves the page.

import { compile } from '@live-codes/pascal-wasm';

const { js, diagnostics } = await compile(`
  program hello;
  begin
    Writeln('Hello from Pascal');
  end.
`);

if (js) {
  // `js` defines the program and the pas2js runtime; the host starts it.
  document.body.append(Object.assign(document.createElement('script'), { textContent: js }));
  rtl.run();
}

Install

npm install @live-codes/pascal-wasm

Or import it straight from a CDN — the package resolves its own assets relative to itself, so no configuration is needed:

import { compile } from 'https://cdn.jsdelivr.net/npm/@live-codes/[email protected]/src/index.js';

There is also a minified classic-script build for non-module workers and plain <script> tags, at dist/pascal-wasm.iife.min.js — see Classic scripts and non-module workers. Both builds share the same assets/.

API

compile(source, options?)

One-shot convenience call. Reuses a shared compiler instance.

Returns Promise<CompileResult>:

| Field | Type | Notes | | --- | --- | --- | | js | string \| null | The generated JavaScript, or null if compilation failed | | sourceMap | string \| null | The map, if sourceMap: true was requested | | diagnostics | string | Raw compiler output, including progress lines | | exitCode | number | 0 on success |

Compilation errors are not exceptions: they come back as js: null with the details in diagnostics. Only failures to load the compiler itself reject.

createCompiler(options?)

Returns Promise<Compiler> for reuse, which avoids re-loading the ~9 MB binary:

const compiler = await createCompiler();
await compiler.version();          // "3.3.1"
await compiler.compile(source);

parseDiagnostics(diagnostics)

Turns the compiler's text output into structured messages, with the progress chatter filtered out. Useful for editor markers.

parseDiagnostics(result.diagnostics);
// [{ file: 'tmp/main.pp', line: 5, column: 11, severity: 'error',
//    message: 'identifier not found "missingThing"' }]

severity is one of error, warning, hint, note or fatal.

configure(options)

Sets package-wide defaults: baseUrl and flags. Per-call options win over these, and flags are prepended to each call's own flags.

configure({ baseUrl: 'https://example.com/pascal/assets/', flags: ['-O2'] });

This is mainly for the classic-script build, where there is no import to attach options to.

defaultBaseUrl()

Returns the asset location that will be used when none is given explicitly — useful for checking what was resolved.

Options

| Option | Type | Description | | --- | --- | --- | | flags | string[] | Extra pas2js command-line options, appended as-is | | units | Record<string, string \| Uint8Array> or Map | Extra units by filename, placed on the compiler's search path | | sourceMap | boolean | Emit js.map, mapping generated JavaScript back to the Pascal | | baseUrl | string \| URL | Load pas2js.wasm and rtl/ from somewhere else. Required by the IIFE build | | wasmUrl / rtlUrl | string \| URL | Override just one of the two |

Compiler options

flags is a pass-through to the compiler, so anything pas2js accepts works. The ones you are most likely to want:

| Flag | Effect | | --- | --- | | -O2 | Optimization level | | -dNAME | Define a symbol for {$IFDEF NAME} | | -Mobjfpc, -Mdelphi, -Mtp, -Miso | Pascal dialect (modeswitch) | | -C-, -Cr, -Co | Range/overflow/object checking | | -Jm | Source maps, beyond what sourceMap: true sets up |

The compiler can list what it supports. Pass a query switch and read the answer back from diagnostics — this is how the demo UI reports them:

const { diagnostics } = await compiler.compile('', { flags: ['-iM'] }); // modeswitches
// also: -it targets, -ic JS processors, -io optimizations

Extra units

Additional units are written into the compiler's unit search path:

const result = await compile(
  `program main; uses doubler; begin Writeln(Twice(21)); end.`,
  {
    units: {
      'doubler.pas': `unit doubler;
        interface
        function Twice(x: Integer): Integer;
        implementation
        function Twice(x: Integer): Integer;
        begin Twice := x * 2; end;
        end.`,
    },
  },
);

Web Workers

The package has no DOM dependencies, so it runs unchanged in a module worker — which is the sensible place for it, since compiling blocks for a moment.

// compiler-worker.js
import { createCompiler } from 'https://cdn.jsdelivr.net/npm/@live-codes/[email protected]/src/index.js';

const compiler = await createCompiler();
self.postMessage({ type: 'ready' });

self.onmessage = async ({ data }) => {
  self.postMessage({ type: 'result', ...(await compiler.compile(data.source)) });
};
const worker = new Worker('compiler-worker.js', { type: 'module' });
worker.onmessage = ({ data }) => {
  if (data.type !== 'result' || !data.js) return;
  const script = document.createElement('script');
  script.textContent = data.js;
  document.body.append(script);
  rtl.run();
};

Note the worker must be a module worker ({ type: 'module' }) because the package is ESM.

Classic scripts and non-module workers

Not every consumer can use ES modules — a classic worker cannot, because importScripts() only runs classic scripts. For those, a minified IIFE bundle is shipped in dist/, exposing the same API on a global named pascalWasm:

// compiler-worker.js — a *classic* worker, no { type: 'module' }
importScripts('https://cdn.jsdelivr.net/npm/@live-codes/[email protected]/dist/pascal-wasm.iife.min.js');

// This build has no module URL, so it cannot find the assets by itself.
pascalWasm.configure({ baseUrl: 'https://cdn.jsdelivr.net/npm/@live-codes/[email protected]/assets/' });

pascalWasm.compile('begin Writeln(42) end.').then(({ js, diagnostics }) => {
  self.postMessage({ js, diagnostics });
});
new Worker('compiler-worker.js'); // ...and no module type here either
<!-- the same bundle works as a plain script tag -->
<script src="https://cdn.jsdelivr.net/npm/@live-codes/[email protected]/dist/pascal-wasm.iife.min.js"></script>
<script>
  pascalWasm.configure({ baseUrl: 'https://cdn.jsdelivr.net/npm/@live-codes/[email protected]/assets/' });
  pascalWasm.compile('begin Writeln(42) end.').then(console.log);
</script>

The bundle is ~27 kB and contains only the glue — the compiler itself stays in assets/, which is shared with the ES module build and cached between them.

baseUrl can be relative, in which case it resolves against the worker's or page's own location:

pascalWasm.configure({ baseUrl: '../packages/pascal-wasm/assets/' });

It may also be passed per call instead — createCompiler({ baseUrl }) — which takes precedence over configure(). Calling compile() without a usable baseUrl in this build fails with an explanatory error rather than guessing, and pascalWasm.defaultBaseUrl() reports what a resolution would produce.

Running the compiled output

pas2js emits a script that registers the program with its runtime but does not start it. The host document starts it with rtl.run(), and the program then behaves like any other page script: it can read and write the DOM (uses web), call host functions, and set ExitCode.

Uncaught Pascal exceptions can be captured through the runtime's hooks:

rtl.showUncaughtExceptions = true;
rtl.onUncaughtException = (error) => {
  console.error(error.$classname, error.fMessage);
  return true; // handled — suppress the default alert()
};
rtl.run();

Node

The same API works in Node, reading the assets from disk. Node needs a flag for the WebAssembly exception-handling instructions this compiler uses:

node --experimental-wasm-exnref app.mjs

Assets

assets/pas2js.wasm is about 9 MB and assets/rtl/ about 1.2 MB. The binary is downloaded and compiled once per compiler instance, then reused across calls. compile() memoizes instances by asset location.

To host the assets yourself, either point baseUrl at your own copy, or import them from the package — @live-codes/pascal-wasm/assets/... is exported for that.

Licensing

The package is licensed under LGPL-2.1-or-later, matching pas2js, which is itself LGPL-2.1 — this package redistributes its compiler binary and runtime library. The WASI shim it bundles is MIT OR Apache-2.0.

See `THIRD-PARTY-NOTICES.md for versions, the provenance and SHA-256 of the compiler binary, and pointers to the corresponding source. Note in particular that the bundled binary comes from the official Free Pascal demo deployment rather than a tagged release, and that building it from source is preferable if you need a version-pinned artifact.