
# Популярные пакеты

Соответствие спецификации не гарантирует работу реальных библиотек. Движки JS, проходящие 99 % тестов test262, регулярно дают сбои на рабочем коде, потому что библиотеки зависят от множества редких «угловых случаев спецификации»: ловушек Proxy в определенном порядке, формы `Function.prototype.toString`, поведения регулярных выражений на сложных входных данных и точного взаимодействия порядка `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. Все закреплены на последнем выпуске из основного репозитория на момент последнего обновления.

## Как это работает

Каждый сценарий — это каталог `tests/Popular/<lib>/` с тремя файлами:

```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` — тест с поставщиком данных PHPUnit, который:

1. Загружает `lodash.js` + `runner.js` в новый экземпляр `new Phasis\Engine()`.
2. Перехватывает вывод `console.log` в буфер.
3. Проверяет, что содержимое буфера побайтно совпадает с `oracle.txt`.

Пересоздать эталон можно командой:

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

(Используется при обновлении подключенной библиотеки: повторно запускает тестовый сценарий в настоящем Node и перезаписывает `oracle.txt`.)

## Проверка в CI

Рабочий процесс: [`.github/workflows/popular.yml`](https://github.com/inline0/phasis/blob/main/.github/workflows/popular.yml).

Запускается при отправке изменений и создании запросов на слияние в `main`, затрагивающих `src/`, `tests/Popular/`, `phpunit.xml.dist`, файлы Composer или сам рабочий процесс, а также вручную. Два шага:

1. **Сторона Phasis** — запускает набор тестов PHPUnit `popular`, который выполняет каждую библиотеку через Phasis и сравнивает результат с сохраненным эталоном. Проверка завершается с ошибкой, если отличается хотя бы один байт.
2. **Повторная проверка в Node** — запускает `node tests/Popular/gen-oracle.js …` для каждой библиотеки и проверяет, что заново созданный эталон совпадает с сохраненным в репозитории. Обнаруживает расхождение, когда подключенную библиотеку обновили, но эталон не обновили.

Оба шага должны пройти успешно, прежде чем запрос на слияние будет принят. Успешный результат test262, ломающий lodash, недопустим; недопустим и успех для lodash, ломающий test262.

## Почему выбраны эти библиотеки

- **acorn** — разбор кода является самой уязвимой частью любого движка JS. Эта библиотека проверяет все синтаксические крайние случаи, появившиеся в современном JS. Если Phasis умеет разбирать с помощью acorn произвольный современный код, значит, среда выполнения работает надежно.
- **mustache.js** — шаблонизация относится к сценариям встраивания, на которые прямо ориентирован Phasis (первый конкретный пример в README — «движки шаблонов»). Mustache проверяет итерацию, разрешение областей видимости и преобразование строк в том порядке, в котором они используются в настоящих шаблонах.
- **lodash** — самая популярная в мире библиотека утилит JS. Ее функции 300+ транзитивно затрагивают все методы стандартной библиотеки. Если работает lodash, работают и универсальные средства преобразования данных JS.
- **marked** — средство отображения markdown. Практическая библиотека, проверяющая регулярные выражения (их там много) и манипуляции со строками с сохранением состояния между строками. Выявляет расхождения движка регулярных выражений между PCRE2 (резервный вариант Phasis) и Irregexp в V8.
- **dayjs** — арифметика дат и времени часто приводит к ошибкам на единицу, которые не выявит ни один тест test262. dayjs охватывает разные варианты конструктора, вычисления через границы месяцев, эквивалентные переходу на летнее время, и раскрытие токенов формата — примерно те же участки кода, которые использует каждая библиотека дат JS.
- **bignumber.js** — арифметика произвольной точности без TypedArrays проверяет разбор чисел из строк, циклы умножения и деления больших целых чисел и выбор режима округления — все на чистом JS, поэтому движок выполняет всю работу. Так выявляются тонкие ошибки преобразования Number ↔ String.
- **json5** — разбор JSON с послаблениями активно использует регулярные выражения с классами символов и токенизацию с сохранением состояния. Хорошая проверка корректности регулярных выражений и обработки строк посимвольно.
- **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** — чистый JS-кодек MQTT 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, потоковый парсер в стиле SAX XML и AST CSS. Разные грамматики — отличные индикаторы проблем при посимвольном сканировании и работе регулярных выражений.

## Добавление новых тестов

Добавьте новый каталог в `tests/Popular/<name>/`, соблюдая структуру из трёх файлов, затем:

```bash
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).
