Skip to content

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). They live under tests/Popular/ in the repo, and CI runs them whenever the engine source or the suite changes.

Coverage by category

Category Libraries
Parsers / AST acorn 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 / HTML mustache 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 / Functional lodash 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 access dequal 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 / Schema zod 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 / time dayjs 1.11.20, date-fns 4.1.0, timeago.js 4.0.2, luxon 3.7.3, moment 2.30.2
Math / numbers bignumber.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 / crypto blueimp-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 / diff fuse.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 formats json5 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 / linguistic he 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 / web url-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 / archive pako 2.1.0, lz-string 1.5.0, base64-js 1.5.1, JSZip 3.10.1
Color color-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 / equality rfdc 1.4.1, klona 2.0.6, fast-copy 3.0.2
Format / display ms 2.1.3, bytes 3.1.2
IDs / UUIDs uuid 10.0.0, hexoid 2.0.0, ulid 3.0.1, cuid2 2.2.2, short-unique-id 5.4.3
Type detection / glob type-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 / config semver 7.6.3, compare-versions 6.1.1, semver-compare 1.0.0
Caches / perf lru-cache 11.0.2, marky 1.3.0, array-flatten 3.0.0, arr-diff 4.0.0
Async / events eventemitter3 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 state mobx 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 / styling postcss 8.5.7, stylis 4.3.6, css-tree 3.0.4
Build / AST / compilers magic-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 / protocol mqtt-packet 9.0.4
GraphQL graphql-js 16.11.0
Syntax highlighting highlight.js 11.11.1
Testing / assertion chai 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:

Text
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:

Shell
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 pushes and pull requests to main that change src/, tests/Popular/, phpunit.xml.dist, the Composer files or the workflow itself, and on manual dispatch. Two steps:

  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 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:

Shell
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, and CI picks it up because the change touches tests/Popular/.

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