Przejdź do treści

Popularne pakiety

Zgodność ze specyfikacją nie gwarantuje działania rzeczywistych bibliotek. Silniki JS, które przechodzą 99 % testów test262, wciąż regularnie zawodzą w kodzie produkcyjnym, ponieważ biblioteki zależą od wielu rzadkich „szczegółów specyfikacji” — pułapek Proxy w określonej kolejności, kształtu Function.prototype.toString, zachowania wyrażeń regularnych przy trudnych danych wejściowych oraz dokładnego wpływu kolejności Object.keys na nazwy obliczanych właściwości.

Phasis weryfikuje 204 szeroko używanych bibliotek bajt po bajcie względem Node.js (V8). Znajdują się one w repozytorium pod tests/Popular/, a CI uruchamia testy przy każdej zmianie kodu źródłowego silnika lub zestawu testów.

Zakres według kategorii

Kategoria Biblioteki
Parsery / 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
Szablony / 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
Narzędzia / funkcyjne 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
Dostęp do obiektów 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
Walidacja / schematy 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
Daty / godziny dayjs 1.11.20, date-fns 4.1.0, timeago.js 4.0.2, luxon 3.7.3, moment 2.30.2
Matematyka / liczby 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
Skróty / kryptografia 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
Wyszukiwanie / różnice 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 / formaty danych 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
Ciągi / językoznawstwo 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 / internet 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
Kompresja / kodowanie / archiwa pako 2.1.0, lz-string 1.5.0, base64-js 1.5.1, JSZip 3.10.1
Kolory 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
Klonowanie / równość rfdc 1.4.1, klona 2.0.6, fast-copy 3.0.2
Formatowanie / wyświetlanie ms 2.1.3, bytes 3.1.2
Identyfikatory / UUID uuid 10.0.0, hexoid 2.0.0, ulid 3.0.1, cuid2 2.2.2, short-unique-id 5.4.3
Rozpoznawanie typów / 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 / konfiguracja semver 7.6.3, compare-versions 6.1.1, semver-compare 1.0.0
Pamięć podręczna / wydajność lru-cache 11.0.2, marky 1.3.0, array-flatten 3.0.0, arr-diff 4.0.0
Asynchroniczność / zdarzenia 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
Stan reaktywny 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 / stylizacja postcss 8.5.7, stylis 4.3.6, css-tree 3.0.4
Budowanie / AST / kompilatory 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 (kompilator), typescript 6.0.3
MQTT / protokół mqtt-packet 9.0.4
GraphQL graphql-js 16.11.0
Podświetlanie składni highlight.js 11.11.1
Testowanie / asercje chai 6.2.1

Łącznie: 204 bibliotek dokładnie odtwarza wynik Node. Wszystkie są przypięte do najnowszego wydania upstream z chwili ostatniej aktualizacji.

Jak to działa

Każdy scenariusz to katalog tests/Popular/<lib>/ zawierający trzy pliki:

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 to test z dostawcą danych PHPUnit, który:

  1. Ładuje lodash.js + runner.js do nowego new Phasis\Engine().
  2. Zapisuje wyjście console.log w buforze.
  3. Sprawdza, czy przechwycony bufor jest bajtowo identyczny z oracle.txt.

Ponownie wygeneruj wzorzec za pomocą:

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

(Używane po aktualizacji dołączonej biblioteki — ponownie uruchamia program testowy w rzeczywistym Node i nadpisuje oracle.txt.)

Kontrola CI

Workflow: .github/workflows/popular.yml.

Uruchamia się przy wypchnięciu zmian i żądaniach pull do main, jeśli zmieniono src/, tests/Popular/, phpunit.xml.dist, pliki Composer lub sam workflow, a także przy ręcznym uruchomieniu. Dwa kroki:

  1. Strona Phasis — uruchamia zestaw testów PHPUnit popular, który wykonuje każdą bibliotekę przez Phasis i porównuje wynik z zatwierdzonym wzorcem. Kończy się błędem, jeśli różni się choćby jeden bajt.
  2. Ponowna weryfikacja w Node — uruchamia node tests/Popular/gen-oracle.js … dla każdej biblioteki i sprawdza, czy świeżo wygenerowany wzorzec zgadza się z tym zapisanym w repozytorium. Wykrywa rozbieżności typu „zaktualizowano dołączoną bibliotekę bez aktualizacji wzorca”.

Oba kroki muszą się powieść, zanim PR zostanie scalony. Zmiana w test262, która psuje lodash, jest nie do przyjęcia; podobnie zmiana w lodash, która psuje test262.

Dlaczego te biblioteki

  • acorn — parsowanie to najbardziej podatny na błędy obszar każdego silnika JS. Sprawdza każdy przypadek brzegowy składni dodany przez współczesny JS. Jeśli Phasis potrafi analizować dowolny nowoczesny kod za pomocą acorn, środowisko wykonawcze działa poprawnie.
  • mustache.js — obsługa szablonów to jedno z zastosowań osadzania, które Phasis wyraźnie wspiera (pierwszym konkretnym przykładem w README są „silniki szablonów”). Mustache sprawdza iterację, rozwiązywanie zakresów i przekształcanie ciągów w kolejności stosowanej w rzeczywistych szablonach.
  • lodash — najczęściej używana biblioteka narzędziowa JS na świecie. Jej ponad 300 funkcji pośrednio wykorzystuje każdą metodę biblioteki standardowej. Jeśli lodash działa, działają też ogólne JS do przekształcania danych.
  • marked — renderowanie markdown. Praktyczny test, który sprawdza wyrażenia regularne (w dużej liczbie) i manipulowanie ciągami ze stanem między wierszami. Ujawnia rozbieżności między silnikiem wyrażeń regularnych PCRE2 (awaryjnym dla Phasis) a Irregexp używanym przez V8.
  • dayjs — działania na datach i godzinach często powodują błędy o jeden dzień, których nie wykrywa żaden przypadek test262. dayjs sprawdza różne warianty konstruktora, działania na granicach miesięcy odpowiadających zmianom czasu letniego oraz rozwijanie tokenów formatu w zbliżonych ścieżkach kodu, z których korzysta każda biblioteka dat JS.
  • bignumber.js — arytmetyka dowolnej precyzji bez TypedArrays sprawdza parsowanie liczb z ciągów, pętle mnożenia i dzielenia dużych liczb całkowitych oraz wybór trybu zaokrąglania — wszystko w czystym JS, więc cały koszt ponosi silnik. Ujawnia subtelne problemy z konwersją Number ↔ String.
  • json5 — liberalne parsowanie JSON w dużej mierze opiera się na wyrażeniach regularnych z klasami znaków i tokenizacji zachowującej stan. To dobry test zarówno poprawności wyrażeń regularnych, jak i granicznych przypadków iteracji po ciągach.
  • fuse.js — UMD przetranspilowany przez Babel, który sprawdza _classCallCheck (wzorzec this instanceof Ctor stosowany przez każdą klasę transpilowaną sprzed ES6), a także pełny algorytm rozmytego dopasowywania bitap. Tę postać mają biblioteki transpilowane przez Babel, więc każda usterka w Fuse psuje połowę ekosystemu npm.
  • handlebars — zaawansowana obsługa szablonów z kompilacją przed renderowaniem. Sprawdza ścieżkę środowiska wykonawczego bez eval przez jeden ogromny wpis compile(), przechodzenie po AST, wywoływanie helperów za pomocą dynamicznej tabeli wyszukiwania oraz sprawdzanie marki SafeString przy użyciu instanceof między różnymi realmami. Stanowi kontrast dla prostszego mechanizmu przechodzenia po szablonach w mustache.js.
  • zod — walidacja schematów w czasie działania. Rozbudowane hierarchie klas (ZodString, ZodObject, ZodArray, ZodUnion, …) z łańcuchami metod zwracającymi uszczegółowione podklasy, formatowanie ustrukturyzowanych błędów, w którym tablica .issues po stronie JS musi być bajtowo zgodna z Node, oraz wzorce dyskryminatorów i tagów literałów. Sprawdza kod walidacji intensywnie wykorzystujący programowanie obiektowe, który stanowi warstwę dla połowy współczesnych aplikacji TypeScript.
  • typescript — rzeczywisty kompilator TypeScript działający na osadzonym silniku. Zminifikowany kompilator o rozmiarze 9 MB, który ponownie parsuje dowolny kod TS, przechodzi po AST i generuje JS — najcięższy możliwy ładunek czystego JS. Jeśli Phasis potrafi transpilować typy generyczne, async/await, wyliczenia i hierarchie klas, zachowując zgodność bajt po bajcie z tsc, semantyka języka jest poprawna.
  • prettier — formatter JS narzucający określony styl. Formatowanie kodu JS z JS sprawia, że ta sama ścieżka sterowania, która formatuje kod, sprawdza każdy szczegół specyfikacji obsługiwany przez silnik — to wyjątkowo wymagające obciążenie.
  • svelte/compiler — samodzielny kompilator Svelte. Parsuje kod źródłowy .svelte, przechodzi po AST i generuje JS dla celów klienta i SSR.
  • terser / @babel/parser / postcss — minifikator JS, parser JS, narzędzie do przetwarzania końcowego CSS. Dziesiątki tysięcy wierszy zminifikowanego kodu ponownie parsującego dowolne dane wejściowe — to obszar, w którym pojawiają się rzadkie struktury AST.
  • ajv — walidator schematów JSON, który kompiluje każde schematy JIT do niestandardowej funkcji walidującej za pomocą new Function(...). Sprawdza ścieżkę konstruktora Function, z której korzysta większość bibliotek schematów i szablonów.
  • mobx — reaktywny stan oparty na proxy. Każdy odczyt obserwowalnej wartości przechodzi przez pułapkę Proxy get, która rejestruje zależność; każdy zapis wywołuje reakcje. To test obciążeniowy infrastruktury Proxy, obserwowalnych map, tablic i zagnieżdżonych obiektów oraz harmonogramu autorun.
  • cheerio / htmlparser2 — jQuery po stronie serwera, oparte na szybkim parserze HTML. Parsowanie selektorów, przechodzenie po strukturze w stylu DOM, modyfikowanie atrybutów i serializacja HTML w jednym pakiecie.
  • graphql-js / jsonata — implementacja referencyjna GraphQL i język zapytań JSON. Oba rozwiązania intensywnie wykorzystują schematy, walidację i rekurencyjne ewaluatory — typowy kod „warstwy danych w przeglądarce”.
  • JSZip — asynchroniczne narzędzie do tworzenia archiwów ZIP. Przetwarza zadania według harmonogramu opartego na setImmediate i generuje rzeczywiste dane binarne, sprawdzając zarówno warstwę timerów, jak i ścieżki intensywnie wykorzystujące Uint8Array.
  • moment / luxon — działania na datach i godzinach. moment to mutowalny, ręcznie dostrojony UMD; luxon to nowoczesne, niemutowalne przepisanie. Razem obejmują pełen zakres formatowania, parsowania i obliczeń na miesiącach i latach odpowiadających różnym strefom czasowym.
  • mqtt-packet — czysty JS-owy kodek MQTT 3.1.1 / 5.0. Pakowanie i dekodowanie na poziomie bajtów oraz klasy znaków wyrażeń regularnych dla znaków spoza alfabetu base64, które sprawdzają graniczne przypadki gramatyki Annex-B.
  • xstate / valtio / nanostores / jotai / redux-saga — przekrój współczesnych rozwiązań do zarządzania stanem. Maszyny stanów, stan oparty na proxy, magazyny atomów, atomy pochodne i generatory uruchamiające efekty — każda biblioteka sprawdza inny model reaktywności.
  • escodegen / acorn-walk / estraverse / magic-string — narzędzia AST. Generowanie kodu, przechodzenie po strukturze i niedestrukcyjna edycja źródła — podstawowe elementy transformatorów JS na JS (narzędzi budujących, codemodów i linterów).
  • papaparse / lunr / yaml / sax / css-tree — czyste parsery i tokenizatory. CSV, indeks wyszukiwania pełnotekstowego, YAML 1.2, strumieniowe parsowanie XML w stylu SAX i AST CSS. Różne gramatyki, a każda dobrze sprawdza skanowanie znak po znaku i zachowanie wyrażeń regularnych.

Dodawanie kolejnych bibliotek

Umieść nowy katalog w tests/Popular/<name>/, zachowując strukturę trzech plików, a następnie:

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

Przy następnym uruchomieniu zestaw PHPUnit automatycznie wykryje nowy katalog, a CI uwzględni go, ponieważ zmiana dotyczy tests/Popular/.

Warto dodać między innymi: chevrotain (kombinator parserów, sprawdza domknięcia i wyrażenia regularne), nanoid (granice kryptografii i losowości), date-fns (obsługę stref czasowych wykraczającą poza dayjs).