
# Populaire pakketten

Conformiteit met de specificatie garandeert niet dat echte bibliotheken werken. JS-engines die voor 99 % van test262 slagen, lopen in productie toch vaak vast omdat bibliotheken afhankelijk zijn van een lange reeks 'randgevallen in de specificatie' — Proxy-traps in een specifieke volgorde, de vorm van `Function.prototype.toString`, regexgedrag bij lastige invoer en de precieze manier waarop de volgorde van `Object.keys` samenwerkt met berekende propertynamen.

Phasis controleert **204 veelgebruikte bibliotheken** byte voor byte tegen Node.js (V8). Ze staan in de repository onder `tests/Popular/` en CI voert ze uit telkens wanneer de enginebroncode of de suite verandert.

## Dekking per categorie

| Categorie | Bibliotheken |
|---|---|
| **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 |
| **Sjablonen / 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 |
| **Hulpmiddelen / functioneel** | 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 |
| **Objecttoegang** | 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 |
| **Validatie / 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 |
| **Datum / tijd** | dayjs 1.11.20, date-fns 4.1.0, timeago.js 4.0.2, luxon 3.7.3, moment 2.30.2 |
| **Wiskunde / getallen** | 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 |
| **Zoeken / verschillen** | 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 / gegevensindelingen** | 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 / taalkunde** | 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 |
| **Compressie / codering / archief** | pako 2.1.0, lz-string 1.5.0, base64-js 1.5.1, JSZip 3.10.1 |
| **Kleur** | 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 |
| **Klonen / gelijkheid** | rfdc 1.4.1, klona 2.0.6, fast-copy 3.0.2 |
| **Opmaak / weergave** | ms 2.1.3, bytes 3.1.2 |
| **ID's / UUID's** | uuid 10.0.0, hexoid 2.0.0, ulid 3.0.1, cuid2 2.2.2, short-unique-id 5.4.3 |
| **Typeherkenning / 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 / configuratie** | semver 7.6.3, compare-versions 6.1.1, semver-compare 1.0.0 |
| **Caches / prestaties** | lru-cache 11.0.2, marky 1.3.0, array-flatten 3.0.0, arr-diff 4.0.0 |
| **Asynchroon / gebeurtenissen** | 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 |
| **Reactieve status** | 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 |
| **Syntaxaccentuering** | highlight.js 11.11.1 |
| **Testen / assertions** | chai 6.2.1 |

Totaal: **204 bibliotheken** reproduceren exact dezelfde uitvoer als Node. Alle bibliotheken zijn vastgezet op de nieuwste upstreamversie van de laatste update.

## Werking

Elk scenario is een `tests/Popular/<lib>/`-map met drie bestanden:

```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 een test met gegevensprovider in PHPUnit die:

1. `lodash.js` + `runner.js` laadt in een nieuwe `new Phasis\Engine()`.
2. De uitvoer van `console.log` opvangt in een buffer.
3. Controleert of de opgevangen buffer byte voor byte gelijk is aan `oracle.txt`.

Een oracle opnieuw genereren:

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

(Wordt gebruikt wanneer u de meegeleverde bibliotheek bijwerkt — voert de runner opnieuw uit onder echte Node en overschrijft `oracle.txt`.)

## CI-controle

Workflow: [`.github/workflows/popular.yml`](https://github.com/inline0/phasis/blob/main/.github/workflows/popular.yml).

Wordt uitgevoerd bij pushes en pull requests naar `main` die `src/`, `tests/Popular/`, `phpunit.xml.dist`, de bestanden in Composer of de workflow zelf wijzigen, en bij handmatige uitvoering. Twee stappen:

1. **Kant van Phasis** — voert de PHPUnit-`popular`-testsuite uit, die elke bibliotheek via Phasis uitvoert en vergelijkt met de vastgelegde oracle. Mislukt als ook maar één byte verschilt.
2. **Opnieuw verifiëren met Node** — voert `node tests/Popular/gen-oracle.js …` uit voor elke bibliotheek en controleert of de nieuw gegenereerde oracle overeenkomt met de ingecheckte versie. Spoort afwijkingen op wanneer 'een meegeleverde bibliotheek is bijgewerkt zonder de oracle bij te werken'.

Beide controles moeten slagen voordat de PR wordt samengevoegd. Een verbetering van test262 die lodash breekt, is onaanvaardbaar; een verbetering van lodash die test262 breekt, evenmin.

## Waarom deze bibliotheken

- **acorn** — parsen is het kwetsbaarste onderdeel van elke JS-engine. Het test alle syntactische randgevallen die moderne JS toevoegt. Als Phasis willekeurige moderne code met acorn kan parsen, is de runtime solide.
- **mustache.js** — sjablonen verwerken is een van de toepassingen waarvoor Phasis expliciet bedoeld is (het eerste concrete voorbeeld van README is 'sjabloonengines'). Mustache test iteratie, scope-resolutie en tekenreeksbewerkingen in de volgorde waarin echte sjablonen die uitvoeren.
- **lodash** — de meestgebruikte JS-hulpmiddelenbibliotheek ter wereld. De meer dan 300 functies raken indirect elke methode van de standaardbibliotheek. Als lodash werkt, werken algemene JS-gegevensbewerkingen ook.
- **marked** — Markdown weergeven. Praktisch en test regex (veel regex) plus tekenreeksbewerkingen met status over meerdere regels. Brengt verschillen tussen regex-engines aan het licht: PCRE2 (de fallback van Phasis) en Irregexp van V8.
- **dayjs** — datum- en tijdsberekeningen zijn een klassieke bron van fouten van één dag die geen enkele test van test262 opspoort. dayjs test varianten van constructors, berekeningen over maandgrenzen die overeenkomen door zomertijd en de uitbreiding van formaattokens in ongeveer dezelfde codepaden die elke datum-bibliotheek van JS gebruikt.
- **bignumber.js** — rekenen met willekeurige precisie zonder TypedArrays test getalparsing op basis van tekenreeksen, vermenigvuldigings- en delingslussen voor grote gehele getallen en afhandeling van afrondingsmodi — allemaal in zuivere JS, zodat de engine alle kosten draagt. Brengt subtiele fouten aan het licht bij de conversie tussen getallen en tekenreeksen.
- **json5** — het parsen van soepele JSON-syntax steunt sterk op regexen met tekenklassen en tokenisatie met status. Een goede graadmeter voor de juistheid van regex en de omgang met randgevallen bij iteratie over tekenreeksen.
- **fuse.js** — een met Babel getranspilde UMD die `_classCallCheck` test (het `this instanceof Ctor`-patroon dat elke klasse gebruikt die vóór ES6 is getranspild), plus het volledige bitap-algoritme voor fuzzy matching. Dit is een vorm die elke met Babel getranspilde bibliotheek deelt; alles wat Fuse breekt, breekt dus de helft van het npm-ecosysteem.
- **handlebars** — uitgebreide sjablonenverwerking met eerst compileren en daarna weergeven. Test het runtimepad zonder `eval` via één groot `compile()`-item, AST-traversal, dispatch van helpers via een dynamische opzoektabel en `SafeString`-typecontrole die `instanceof` over verschillende realms gebruikt. Een tegenhanger van de eenvoudigere sjabloonverwerker van mustache.js.
- **zod** — schemavalidatie tijdens runtime. Uitgebreide klassehiërarchieën (`ZodString`, `ZodObject`, `ZodArray`, `ZodUnion`, …) met methodenketens die verfijnde subklassen teruggeven, gestructureerde foutopmaak waarbij de vorm van de array JS-zijde-`.issues` byte voor byte moet overeenkomen met Node, en patronen met discriminators en letterlijke tags. Test het soort validatiecode met veel objectgeoriënteerde code dat de helft van moderne TypeScript-apps omhult.
- **typescript** — de *echte* TypeScript-compiler die op de ingebedde engine draait. Een compiler van 9 MB met minificatie die willekeurige TS opnieuw parseert, de AST doorloopt en JS produceert — de zwaarste denkbare payload in zuivere JS. Als Phasis generics, async/await, enums en klassehiërarchieën byte voor byte gelijk aan `tsc` kan transpilen, zijn de taalregels solide.
- **prettier** — een eigenzinnige JS-formatter. JS opmaken *met* JS raakt elk randgeval van de specificatie in de engine via dezelfde besturingsstroom die uw code opmaakt — een bijzonder veeleisende werklast.
- **svelte/compiler** — de zelfstandige compiler van Svelte. Parseert `.svelte`-broncode, doorloopt de AST en produceert JS voor zowel client- als SSR-doelen.
- **terser / @babel/parser / postcss** — JS-minifier, JS-parser, CSS-nabewerker. Tienduizenden regels geminificeerde code die willekeurige invoer opnieuw parsen: het oppervlak waar zeldzame AST-vormen opduiken.
- **ajv** — JSON-schemavalidator die elk schema JIT compileert tot een aangepaste validatorfunctie via `new Function(...)`. Dit test het Function-constructorpad waar de meeste schema- en templatingbibliotheken op steunen.
- **mobx** — proxygebaseerde reactieve status. Elke uitlezing van een observable loopt via een Proxy `get`-trap die een afhankelijkheid registreert; elke schrijfoperatie activeert reacties. Een stresstest voor de Proxy-infrastructuur, observable Maps / arrays / geneste objecten en de autorun-planner.
- **cheerio / htmlparser2** — jQuery aan de serverzijde boven op een snelle HTML-parser. Selector-engine-parsing, DOM-achtige traversering, attribuutmanipulatie en HTML-serialisatie in één pakket.
- **graphql-js / jsonata** — GraphQL-referentie-implementatie en een JSON-querytaal. Beide maken intensief gebruik van schema's, validatie en recursieve evaluatoren: typische code voor een 'datalaag in de browser'.
- **JSZip** — asynchrone ZIP-archiefbouwer. Routeert werk via `setImmediate`-gestuurde planning en produceert echte binaire uitvoer, waarmee zowel het timeroppervlak als `Uint8Array`-intensieve paden worden getest.
- **moment / luxon** — datum- en tijdrekenkunde. moment is mutable en met de hand geoptimaliseerde UMD; luxon is de moderne immutable herschrijving. Samen bestrijken ze het volledige oppervlak van formattering, parsing en tijdzone-equivalente maand- en jaarberekeningen.
- **mqtt-packet** — pure-JS MQTT 3.1.1 / 5.0-codec. Inpakken en decoderen op byteniveau, plus regex-tekenklassen voor tekens buiten het base64-alfabet die grammaticale randgevallen van Annex B testen.
- **xstate / valtio / nanostores / jotai / redux-saga** — het moderne aanbod voor statusbeheer. Statusmachines, proxystatus, atomstores, afgeleide atomen en generatorgebaseerde effectuitvoerders: elke bibliotheek raakt een andere vorm van reactiviteit.
- **escodegen / acorn-walk / estraverse / magic-string** — AST-tools. Codegeneratie, traversering en niet-destructieve bronbewerking: de bouwstenen voor elke JS-op-JS-transformator (buildtools, codemods, linters).
- **papaparse / lunr / yaml / sax / css-tree** — pure parsers en tokenizers. CSV, full-textzoekindex, YAML 1.2, streaming SAX-achtige XML en CSS-AST. Verschillende grammatica's, allemaal goede kanaries voor scannen op tekenniveau en regexgedrag.

## Meer toevoegen

Voeg een nieuwe map met de structuur van drie bestanden toe onder `tests/Popular/<name>/` en voer daarna het volgende uit:

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

De PHPUnit-suite ontdekt deze automatisch bij de volgende uitvoering, en CI neemt deze mee omdat de wijziging `tests/Popular/` raakt.

Goede kandidaten om toe te voegen: `chevrotain` (parsercombinator, test closures + regex), `nanoid` (grensgebied van cryptografie en willekeurigheid), `date-fns` (tijdzonefunctionaliteit buiten dayjs).
