Популярні пакети
Відповідність специфікації не гарантує, що реальні бібліотеки працюватимуть. Рушії JS, які проходять 99 % test262, усе одно регулярно ламаються на промисловому коді, бо бібліотеки залежать від численних «кутових випадків специфікації»: пасток Proxy у певному порядку, форми Function.prototype.toString, поведінки regex на складних вхідних даних і точного впливу порядку Object.keys на обчислювані назви властивостей.
Phasis перевіряє побайтно 204 широко вживаних бібліотек на відповідність Node.js (V8). Вони містяться в репозиторії в tests/Popular/, а CI запускає їх щоразу, коли змінюється код рушія або набір тестів.
Покриття за категоріями
| Категорія | Бібліотеки |
|---|---|
| Парсери / 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 |
| Шаблонізація / 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 |
| Утиліти / функціональне програмування | 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 |
| Доступ до об’єктів | 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 |
| Перевірка / схеми | 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 |
| Дата / час | dayjs 1.11.20, date-fns 4.1.0, timeago.js 4.0.2, luxon 3.7.3, moment 2.30.2 |
| Математика / числа | 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 |
| Хешування / криптографія | 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 |
| Пошук / різниця | 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 / формати даних | 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 |
| Рядки / лінгвістика | 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 / веб | 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 |
| Стиснення / кодування / архіви | pako 2.1.0, lz-string 1.5.0, base64-js 1.5.1, JSZip 3.10.1 |
| Кольори | 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 |
| Клонування / рівність | rfdc 1.4.1, klona 2.0.6, fast-copy 3.0.2 |
| Форматування / відображення | ms 2.1.3, bytes 3.1.2 |
| Ідентифікатори / UUID | uuid 10.0.0, hexoid 2.0.0, ulid 3.0.1, cuid2 2.2.2, short-unique-id 5.4.3 |
| Визначення типів / 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 / конфігурація | semver 7.6.3, compare-versions 6.1.1, semver-compare 1.0.0 |
| Кеші / продуктивність | lru-cache 11.0.2, marky 1.3.0, array-flatten 3.0.0, arr-diff 4.0.0 |
| Асинхронність / події | 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 |
| Реактивний стан | 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 / стилізація | postcss 8.5.7, stylis 4.3.6, css-tree 3.0.4 |
| Збирання / AST / компілятори | 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 (компілятор), typescript 6.0.3 |
| MQTT / протокол | mqtt-packet 9.0.4 |
| GraphQL | graphql-js 16.11.0 |
| Підсвічування синтаксису | highlight.js 11.11.1 |
| Тестування / перевірки | chai 6.2.1 |
Усього: 204 бібліотек відтворюють точний результат Node. Усі зафіксовано на останньому релізі в upstream на момент останнього оновлення версій.
Як це працює
Кожен сценарій — це каталог tests/Popular/<lib>/ із трьома файлами:
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 — це тест постачальника даних PHPUnit, який:
- Завантажує
lodash.js+runner.jsу новийnew Phasis\Engine(). - Записує вивід
console.logу буфер. - Перевіряє, що вміст буфера побайтно збігається з
oracle.txt.
Перегенеруйте еталон за допомогою:
node tests/Popular/gen-oracle.js tests/Popular/<lib>
(Використовується під час оновлення вендорної бібліотеки — повторно запускає виконавець у справжньому Node і перезаписує oracle.txt.)
Перевірка CI
Робочий процес: .github/workflows/popular.yml.
Запускається після надсилання змін і створення запитів на злиття в main, якщо вони змінюють src/, tests/Popular/, phpunit.xml.dist, файли Composer або сам робочий процес, а також запускається вручну. Два кроки:
- Сторона Phasis — запускає набір тестів PHPUnit
popular, який виконує кожну бібліотеку через Phasis і порівнює результат із зафіксованим еталоном. Помилка виникає, якщо відрізняється хоча б один байт. - Повторна перевірка в Node — запускає
node tests/Popular/gen-oracle.js …для кожної бібліотеки й перевіряє, що щойно згенерований еталон збігається з тим, що збережено в репозиторії. Виявляє розбіжність, коли «вендорну бібліотеку оновили, але еталон не оновили».
Обидві перевірки мають пройти до злиття PR. Перемога test262, що ламає lodash, неприйнятна; так само неприйнятний виграш lodash, що ламає test262.
Чому саме ці бібліотеки
- acorn — парсинг є найкрихкішою частиною будь-якого рушія JS. Він перевіряє всі синтаксичні крайові випадки, які додає сучасний JS. Якщо Phasis може розібрати довільний сучасний код за допомогою acorn, середовище виконання працює належно.
- mustache.js — шаблонізація є одним зі сценаріїв вбудовування, на які явно орієнтується Phasis (перший конкретний приклад у README — «шаблонізатори»). Mustache перевіряє ітерацію, визначення області видимості та перетворення рядків у порядку, характерному для реальних шаблонів.
- lodash — найпопулярніша у світі бібліотека утиліт JS. Її понад 300 функцій опосередковано задіюють усі методи стандартної бібліотеки. Якщо працює lodash, працюють і узагальнені засоби перетворення даних JS.
- marked — відтворення Markdown. Практичний сценарій, що перевіряє regex (дуже багато) і маніпуляції з рядками зі станом між рядками. Виявляє розбіжності між рушієм regex PCRE2 (запасний варіант у Phasis) та Irregexp у V8.
- dayjs — арифметика дати й часу — класичне джерело помилок на одиницю, яких не виявить жоден тест test262. dayjs охоплює варіанти конструктора, арифметику через межі місяців, еквівалентні переходу на літній час, і розгортання токенів форматування приблизно тими самими шляхами коду, що й будь-яка бібліотека дат JS.
- bignumber.js — арифметика довільної точності без TypedArrays перевіряє розбір чисел із рядків, цикли множення та ділення великих цілих чисел і вибір режиму округлення — усе на чистому JS, тож рушій бере на себе всі витрати. Виявляє будь-які непомітні порушення перетворення Number ↔ String.
- json5 — розбір невимушеного формату JSON значною мірою покладається на регулярні вирази з класами символів і токенізацію зі станом. Це вдалий індикатор правильності regex і крайових випадків ітерації рядків.
- fuse.js — UMD, транспільований Babel, який перевіряє
_classCallCheck(шаблонthis instanceof Ctor, який використовує кожен транспільований клас до ES6), а також повний алгоритм нечіткого пошуку bitap. Це типова структура для бібліотек, транспільованих Babel, тож усе, що ламає Fuse, ламає половину екосистеми npm. - handlebars — повнофункціональна шаблонізація з компіляцією перед рендерингом. Перевіряє шлях виконання без
evalчерез один великий записcompile(), обхід AST, виклик допоміжних функцій через динамічну таблицю пошуку та перевірку брендуSafeString, яка використовуєinstanceofміж різними realm. Для порівняння з простішим обхідником шаблонів у mustache.js. - zod — перевірка схем під час виконання. Глибокі ієрархії класів (
ZodString,ZodObject,ZodArray,ZodUnion, …) із ланцюжками методів, що повертають уточнені підкласи; форматування структурованих помилок, у якому форма масиву.issuesна боці JS має побайтово збігатися з Node; а також шаблони дискримінаторів і літеральних тегів. Перевіряє код із насиченим ООП для валідації, який лежить в основі половини сучасних застосунків TypeScript. - typescript — справжній компілятор TypeScript, що працює у вбудованому рушії. Це 9 MB мінімізованого компілятора, який повторно розбирає довільний TS, обходить AST і генерує JS — найважчий можливий тягар на чистому JS. Якщо Phasis може транспілювати узагальнення, async/await, перелічення та ієрархії класів із побайтовою відповідністю до
tsc, семантика мови реалізована правильно. - prettier — форматувач JS із чіткою думкою. Форматування JS разом із JS зачіпає всі крайові випадки специфікації рушія тим самим потоком керування, що й під час форматування вашого коду. Це надзвичайно вимогливе навантаження.
- svelte/compiler — окремий компілятор Svelte. Розбирає код
.svelte, обходить AST і генерує JS для клієнта й SSR. - terser / @babel/parser / postcss — JS мініфікатор, JS парсер, CSS постпроцесор. Десятки тисяч рядків мініфікованого коду повторно розбирають довільний вхід — саме тут трапляються рідкісні форми AST.
- ajv — JSON валідатор схем, який JIT-компілює кожну схему в користувацьку функцію-валідатор за допомогою
new Function(...). Перевіряє шлях конструктора Function, на який покладається більшість бібліотек для схем і шаблонів. - mobx — реактивний стан на основі проксі. Кожне читання спостережуваного значення проходить через пастку Proxy
get, яка реєструє залежність; кожен запис запускає реакції. Це стрес-тест інфраструктури Proxy, спостережуваних Map, масивів і вкладених об’єктів, а також планувальника autorun. - cheerio / htmlparser2 — jQuery на стороні сервера поверх швидкого парсера HTML. В одному пакеті — розбір селекторним рушієм, обхід у стилі DOM, маніпуляції атрибутами та серіалізація HTML.
- graphql-js / jsonata — еталонна реалізація GraphQL і мова запитів JSON. Обидві активно працюють зі схемами, валідацією та рекурсивними обчислювачами — типовим кодом «рівня даних у браузері».
- JSZip — асинхронний засіб створення ZIP-архівів. Спрямовує роботу через планування на основі
setImmediateі створює справжній двійковий результат, перевіряючи як поверхню таймерів, так і шляхи з інтенсивним використаннямUint8Array. - moment / luxon — арифметика дат і часу. moment — змінювана, вручну оптимізована UMD-бібліотека; luxon — сучасна незмінювана переробка. Разом вони охоплюють усе форматування, розбір і математичні операції з місяцями та роками з урахуванням часових поясів.
- mqtt-packet — MQTT-кодек JS 3.1.1 / 5.0. Пакування й декодування на рівні байтів, а також класи символів регулярних виразів для символів поза алфавітом base64, що перевіряють граничні випадки граматики Annex B.
- xstate / valtio / nanostores / jotai / redux-saga — широкий спектр сучасних засобів керування станом. Автомати станів, стан на основі проксі, сховища атомів, похідні атоми, виконавці ефектів на основі генераторів — кожна бібліотека охоплює окрему форму реактивності.
- escodegen / acorn-walk / estraverse / magic-string — інструменти для AST. Генерація коду, обхід і недеструктивне редагування джерела — основа будь-якого трансформера JS-на-JS (інструментів збирання, кодмодів, лінтерів).
- papaparse / lunr / yaml / sax / css-tree — чисті парсери й токенізатори. CSV, індекс повнотекстового пошуку, YAML 1.2, потоковий XML у стилі SAX і AST CSS. Різні граматики — чудові індикатори для посимвольного сканування та поведінки регулярних виразів.
Додавання нових
Створіть нову директорію в tests/Popular/<name>/ зі структурою з трьох файлів, а потім:
node tests/Popular/gen-oracle.js tests/Popular/<name> # one-time, generates oracle.txt
git add tests/Popular/<name>
Набір PHPUnit автоматично виявить її під час наступного запуску, а CI підхопить зміни, оскільки вони стосуються tests/Popular/.
Варто додати такі кандидати: chevrotain (комбінатор парсерів, перевіряє замикання та регулярні вирази), nanoid (межа криптографії та випадковості), date-fns (робота з часовими поясами ширша, ніж у dayjs).