Phasis
Compatibility

Popular packages

Spec conformance doesn't guarantee real libraries work. JS engines that pass 99 % of test262 still routinely break on production code because libraries depend on a long tail of "spec corners" — Proxy traps in specific orders, Function.prototype.toString shape, regex behavior on tricky inputs, the exact way Object.keys ordering interacts with computed property names.

Phasis verifies 204 widely-used libraries byte-for-byte against Node.js (V8) on every push. They live under tests/Popular/ in the repo.

Coverage by category

CategoryLibraries
Parsers / ASTacorn 8.16.0, chevrotain 11.0.3, parse5 7.2.1, parsimmon 1.18.1, jsep 1.4.0, postcss-value-parser 4.2.0, acorn-walk 8.3.4, estraverse 5.3.0, escodegen 2.1.0, css-tree 3.0.4, sax 1.4.1, nearley 2.20.1
Templating / Markdown / HTMLmustache 4.2.0, handlebars 4.7.9, marked 18.0.3, markdown-it 14.1.0 (+ markdown-it-emoji), markdown-table 3.0.4, showdown 2.1.0, cheerio 1.1.2, htmlparser2 11.0.0
Utility / Functionallodash 4.18.1, ramda 0.31.3, remeda 2.17.4, es-toolkit 1.27.0, immutable 5.1.3, immer 10.1.1, redux 5.0.1, deepmerge 4.3.1, dot-object 2.1.5, lodash.merge 4.6.2, lodash.clonedeep 4.5.0, extend 3.0.2, extend-shallow 3.0.2, mixin-deep 2.0.1, merge-options 3.0.4
Object accessdequal 2.0.3, clsx 2.1.1, classnames 2.5.1, get-value 4.0.1, set-value 4.1.0, object.omit 3.0.0, object.pick 1.3.0, is-plain-obj 4.1.0, kind-of 6.0.3
Validation / Schemazod 4.4.3, yup 1.4.0, valibot 1.1.0, superstruct 2.0.2, validator 13.12.0, email-validator 2.0.4, ajv 8.17.1, @sinclair/typebox 0.34.42, runtypes 6.7.0, typanion 3.14.0, ow 2.0.0
Date / timedayjs 1.11.20, date-fns 4.1.0, timeago.js 4.0.2, luxon 3.7.3, moment 2.30.2
Math / numbersbignumber.js 11.1.1, decimal.js 10.6.0, numeral 2.0.6, jsbi 4.3.0, big.js 6.2.2, fraction.js 4.3.7, complex.js 2.4.2, simple-statistics 7.8.8
Hashing / cryptoblueimp-md5 2.19.0, crypto-js 4.2.0, fnv-plus 1.3.1, murmurhash3js 3.0.1, hash-sum 2.0.0, jwt-decode 4.0.0, @noble/hashes 2.2.0, tweetnacl 1.0.3, aes-js 3.1.2, bcryptjs 3.0.2, xxhashjs 0.2.2, object-hash 3.0.0
Search / difffuse.js 7.3.0, minisearch 7.1.1, diff 8.0.2, diff-match-patch 1.0.5, fast-deep-equal 3.1.3, fast-equals 5.2.2, fastest-levenshtein 1.0.16, lunr 2.3.9
JSON / data formatsjson5 2.2.3, js-yaml 4.1.0, yaml 2.6.1, toml 3.0.0, smol-toml 1.3.1, fast-json-patch 3.1.1, jmespath 0.16.0, jsonata 2.0.6, jsonpath-plus 10.3.0, mingo 6.7.0, sift 17.1.3, fast-json-stable-stringify 2.1.0, safe-stable-stringify 2.5.0, json-stringify-safe 5.0.1, canonicalize 2.1.0, papaparse 5.5.4
Strings / linguistiche 1.2.0, slugify 1.6.9, camelcase 8.0.0, entities 6.0.1, pluralize 8.0.0, inflection 3.0.2, wcwidth 1.0.1, emoji-regex 10.4.0, unraw 3.0.0, jsesc 3.1.0, lower-case 2.0.2, upper-case 2.0.2, dot-case 3.0.4, pascal-case 3.1.2, snake-case 3.0.4, title-case 3.0.3, xregexp 5.1.1, escape-string-regexp 5.0.0, ansi-regex 6.1.0, strip-ansi 7.1.2, string-width 8.1.0
URL / weburl-parse 1.5.10, qs 6.13.1, query-string 9.1.1, tldts 6.1.69, punycode 2.3.1, linkifyjs 4.3.1, ipaddr.js 2.2.0, uri-js 4.4.1, url-template 3.1.1, bowser 2.11.0
Compression / encoding / archivepako 2.1.0, lz-string 1.5.0, base64-js 1.5.1, JSZip 3.10.1
Colorcolor-string 2.1.1, d3-color 3.1.0, chroma-js 3.1.2, color-name 2.0.0, tinycolor2 1.6.0, color 5.0.3
Clone / equalityrfdc 1.4.1, klona 2.0.6, fast-copy 3.0.2
Format / displayms 2.1.3, bytes 3.1.2
IDs / UUIDsuuid 10.0.0, hexoid 2.0.0, ulid 3.0.1, cuid2 2.2.2, short-unique-id 5.4.3
Type detection / globtype-detect 4.1.0, picomatch 4.0.2, minimatch 10.1.1, wildcard-match 5.1.4, glob-to-regexp 0.4.1, to-regex 4.0.4, array-uniq 3.0.0, array-unique 0.3.2
Semver / configsemver 7.6.3, compare-versions 6.1.1, semver-compare 1.0.0
Caches / perflru-cache 11.0.2, marky 1.3.0, array-flatten 3.0.0, arr-diff 4.0.0
Async / eventseventemitter3 5.0.1, eventemitter2 6.4.10, mitt 3.0.1, p-limit 7.1.1, p-queue 9.0.2, p-defer 5.0.0, p-retry 7.1.0, throttle-debounce 5.0.2, async 3.2.6
Reactive statemobx 6.13.7, xstate 5.23.0, valtio 2.1.5, nanostores 1.0.1, jotai 2.16.1, redux-saga 1.3.0, redux 5.0.1
CSS / stylingpostcss 8.5.7, stylis 4.3.6, css-tree 3.0.4
Build / AST / compilersmagic-string 0.30.20, escodegen 2.1.0, acorn-walk 8.3.4, estraverse 5.3.0, @babel/parser 7.28.5, terser 5.46.0, prettier 3.3.3, svelte 5.55.7 (compiler), typescript 6.0.3
MQTT / protocolmqtt-packet 9.0.4
GraphQLgraphql-js 16.11.0
Syntax highlightinghighlight.js 11.11.1
Testing / assertionchai 6.2.1

Total: 204 libraries all reproduce Node's exact output. All pinned to the latest upstream release as of the last bump.

How it works

Each scenario is a tests/Popular/<lib>/ directory with three files:

tests/Popular/lodash/
├── lodash.js     ← vendored upstream library (untouched, UMD bundle)
├── runner.js     ← Phasis-side script that exercises the library
└── oracle.txt    ← Node.js output of running runner.js (committed)

tests/Popular/PopularPackagesTest.php is a PHPUnit data-provider test that:

  1. Loads lodash.js + runner.js into a fresh new Phasis\Engine().
  2. Captures console.log output into a buffer.
  3. Asserts the captured buffer is byte-equal to oracle.txt.

Regenerate an oracle with:

node tests/Popular/gen-oracle.js tests/Popular/<lib>

(Used when you bump the vendored library — re-runs the runner under real Node and overwrites oracle.txt.)

CI gate

Workflow: .github/workflows/popular.yml.

Runs on every push to main and on every PR. Two jobs:

  1. Phasis side — runs the PHPUnit popular testsuite, which executes each library through Phasis and diffs against the committed oracle. Fails if a single byte differs.
  2. Node re-verify — runs node tests/Popular/gen-oracle.js … against each library and asserts the freshly regenerated oracle matches what's checked in. Detects "vendored library was bumped without updating the oracle" drift.

Both jobs must pass before the PR merges. A test262 win that breaks lodash isn't acceptable; a lodash win that breaks test262 isn't either.

Why these libraries

  • acorn — parsing is the most fragile surface in any JS engine. It exercises every syntactic corner case modern JS adds. If Phasis can parse arbitrary modern code with acorn, the runtime is sound.
  • mustache.js — templating is one of the embedding use cases Phasis explicitly targets (the README's first concrete example is "templating engines"). Mustache exercises iteration, scope resolution, and string transforms in the order real templates do.
  • lodash — the most-used JS utility library on the planet. Its 300+ functions transitively touch every standard-library method. If lodash works, generic data-transformation JS works.
  • marked — markdown rendering. Practical and exercises regex (lots of it) plus string manipulation with cross-line state. Surfaces regex-engine drift between PCRE2 (Phasis' fallback) and V8's Irregexp.
  • dayjs — Date/time arithmetic is a classic source of off-by-one bugs that no test262 case catches. dayjs hits constructor variants, arithmetic across DST-equivalent month boundaries, and format-token expansion in roughly the same code paths every JS Date library uses.
  • bignumber.js — arbitrary-precision arithmetic without TypedArrays exercises string-based number parsing, large-integer multiply / divide loops, and rounding-mode dispatch — all in pure JS so the engine carries the entire cost. Surfaces any subtle break in Number ↔ String conversion.
  • json5 — relaxed JSON parsing leans heavily on character-class regexes and stateful tokenization. A good canary for both regex correctness and string-iteration edges.
  • fuse.js — a Babel-transpiled UMD that exercises _classCallCheck (the this instanceof Ctor pattern that every pre-ES6 transpiled class uses) plus the full bitap fuzzy-match algorithm. The kind of shape every Babel-transpiled library shares, so anything that breaks Fuse breaks half the npm ecosystem.
  • handlebars — full-featured templating with compile-then-render. Exercises the eval-free runtime path through a single huge compile() entry, AST traversal, helper dispatch through a dynamic lookup table, and SafeString brand-checking that uses instanceof across realms. A counterpoint to mustache.js's simpler template walker.
  • zod — runtime schema validation. Heavy class hierarchies (ZodString, ZodObject, ZodArray, ZodUnion, …) with method chaining that returns refined sub-classes, structured error formatting where the JS-side .issues array shape has to match Node byte-for-byte, and discriminator/literal-tag patterns. Tests the kind of OO-heavy validation code that wraps half of modern TypeScript apps.
  • typescript — the actual TypeScript compiler running on the embedded engine. 9 MB of minified compiler that re-parses arbitrary TS, walks the AST, and emits JS — the heaviest pure-JS payload imaginable. If Phasis can transpile generics, async/await, enums, and class hierarchies byte-for-byte equal to tsc, the language semantics are sound.
  • prettier — opinionated JS formatter. Formatting JS with JS means every spec corner the engine has gets touched by the same control flow that formats your code — a uniquely demanding workload.
  • svelte/compiler — Svelte's standalone compiler. Parses .svelte source, walks the AST, emits JS for both client and SSR targets.
  • terser / @babel/parser / postcss — JS minifier, JS parser, CSS post-processor. Tens of thousands of lines of minified code that re-parse arbitrary input — the surface where rare AST shapes show up.
  • ajv — JSON Schema validator that JIT-compiles each schema to a custom validator function via new Function(...). Exercises the Function-constructor path that most schema/templating libraries lean on.
  • mobx — proxy-based reactive state. Every read of an observable runs through a Proxy get trap that registers a dependency; every write fires reactions. A stress test for the Proxy infrastructure, observable Maps / arrays / nested objects, and the autorun scheduler.
  • cheerio / htmlparser2 — server-side jQuery on top of a fast HTML parser. Selector-engine parsing, DOM-style traversal, attribute manipulation, and HTML serialization in one package.
  • graphql-js / jsonata — GraphQL reference implementation and a JSON query language. Both are heavy on schemas, validation, and recursive evaluators — typical "data layer in the browser" code.
  • JSZip — async ZIP archive builder. Routes work through setImmediate-driven scheduling and produces real binary output, exercising both the timer surface and Uint8Array-heavy paths.
  • moment / luxon — date/time arithmetic. moment's a mutable, hand-tuned UMD; luxon is the modern immutable rewrite. Together they cover the full surface of formatting, parsing, and timezone-equivalent month/year math.
  • mqtt-packet — pure-JS MQTT 3.1.1 / 5.0 codec. Byte-level packing and decoding plus the kind of base64-non-alphabet regex character classes that exercise Annex-B grammar edges.
  • xstate / valtio / nanostores / jotai / redux-saga — the modern state-management spread. State machines, proxy state, atom stores, derived atoms, generator-based effect runners — each library hits a different shape of reactivity.
  • escodegen / acorn-walk / estraverse / magic-string — AST tooling. Code generation, traversal, and non-destructive source editing — the building blocks for any JS-on-JS transformer (build tools, codemods, linters).
  • papaparse / lunr / yaml / sax / css-tree — pure parsers and tokenizers. CSV, full-text search index, YAML 1.2, streaming SAX-style XML, and CSS AST. Different grammars, all good canaries for character-level scanning and regex behavior.

Adding more

Drop a new directory under tests/Popular/<name>/ with the three-file shape, then:

node tests/Popular/gen-oracle.js tests/Popular/<name>   # one-time, generates oracle.txt
git add tests/Popular/<name>

The PHPUnit suite auto-discovers it on the next run. CI picks it up on the next push.

Strong candidates worth adding: chevrotain (parser combinator, exercises closures + regex), nanoid (crypto/randomness boundary), date-fns (timezone surface beyond dayjs).

On this page