
# 热门包

符合规范并不保证真实库能够正常运行。即使 JS 引擎通过了 test262 中 99 % 的测试，在生产代码中仍经常出问题，因为库依赖许多边缘的“规范细节”——例如按特定顺序触发 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 |
| **验证 / 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 |
| **日期 / 时间** | 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 |
| **ID / 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>
```

（更新 vendored 库时使用——在真实 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 …`，并断言新生成的基准结果与仓库中的版本一致。用于检测“更新了 vendored 库但未更新基准结果”的偏差。

两项检查都必须通过，PR 才能合并。test262 方面的改进若导致 lodash 出问题，就不可接受；lodash 方面的改进若破坏 test262，也同样不可接受。

## 为什么选择这些库

- **acorn** — 解析是任何 JS 引擎中最脆弱的环节。它会测试现代 JS 新增的每个语法边界情况。如果 Phasis 能用 acorn 解析任意现代代码，说明运行时是可靠的。
- **mustache.js** — 模板处理是 Phasis 明确支持的嵌入式用例之一（README 的第一个具体示例是“模板引擎”）。Mustache 会按照真实模板的处理顺序测试迭代、作用域解析和字符串转换。
- **lodash** — 全球使用最广泛的 JS 实用工具库。其 300 多个函数会间接调用每个标准库方法。若 lodash 能正常工作，通用数据转换 JS 也能正常工作。
- **marked** — Markdown 渲染工具，实用且能测试正则表达式（大量使用）以及带跨行状态的字符串处理。可暴露 PCRE2（Phasis 的备用引擎）与 V8 的 Irregexp 之间的正则引擎差异。
- **dayjs** — 日期和时间运算是经典的差一错误来源，没有任何 test262 用例能捕获所有这类问题。dayjs 会测试构造函数的不同形式、跨夏令时等效月份边界的运算，以及格式令牌展开；这些都位于几乎每个 JS 日期库使用的相同代码路径中。
- **bignumber.js** — 不使用 TypedArrays 的任意精度运算会测试基于字符串的数字解析、大整数乘除循环和舍入模式分派——全部使用纯 JS，因此所有开销都由引擎承担。它可以暴露 Number 与 String 转换中的细微问题。
- **json5** — 宽松的 JSON 解析大量依赖字符类正则表达式和有状态分词，可作为正则表达式正确性和字符串迭代边界的良好探针。
- **fuse.js** — 一个经 Babel 转译的 UMD，能测试 `_classCallCheck`（每个 ES6 之前转译的类都会使用的 `this instanceof Ctor` 模式）以及完整的 Bitap 模糊匹配算法。这是 Babel 转译库共有的结构，因此任何会破坏 Fuse 的问题也会影响半数 npm 生态。
- **handlebars** — 功能齐全的模板工具，采用先编译后渲染的方式。通过单个超大的 `compile()` 入口测试 `eval`-free 运行时路径、AST 遍历、通过动态查找表分派辅助函数，以及跨 realm 使用 `instanceof` 的 `SafeString` 品牌检查。这与 mustache.js 更简单的模板遍历器形成对照。
- **zod** — 运行时 Schema 验证。包含复杂的类层次结构（`ZodString`、`ZodObject`、`ZodArray`、`ZodUnion`、……），方法链会返回经过细化的子类；结构化错误格式化要求 JS 端 `.issues` 数组的形状与 Node 逐字节一致；还会测试判别符和字面量标签模式。可测试现代 TypeScript 应用中常见的面向对象密集型验证代码。
- **typescript** — 在嵌入式引擎上运行的*真正的* TypeScript 编译器。9 MB 的压缩编译器会重新解析任意 TS、遍历 AST 并生成 JS，是能想象到的最重型纯 JS 负载。如果 Phasis 能将泛型、async/await、枚举和类层次结构转译为与 `tsc` 逐字节相同的结果，说明语言语义是可靠的。
- **prettier** — 一款遵循既定风格的 JS 格式化工具。格式化包含 JS 的 JS 时，引擎的每个规范边界都会经过格式化代码的同一控制流，构成极具挑战性的工作负载。
- **svelte/compiler** — Svelte 的独立编译器。解析 `.svelte` 源代码、遍历 AST，并为客户端和 SSR 目标生成 JS。
- **terser / @babel/parser / postcss** — JS 压缩器、JS 解析器、CSS 后处理器。数万行压缩代码会重新解析任意输入，正是罕见 AST 结构可能出现的地方。
- **ajv** — JSON Schema 验证器通过 `new Function(...)` 将每个 Schema 即时编译成自定义验证函数。测试大多数 Schema 和模板库所依赖的 Function 构造函数路径。
- **mobx** — 基于代理的响应式状态。每次读取可观察对象时都会经过 Proxy `get` 陷阱来注册依赖；每次写入都会触发反应。这是对 Proxy 基础设施、可观察 Map、数组、嵌套对象和 autorun 调度器的压力测试。
- **cheerio / htmlparser2** — 构建于快速 HTML 解析器之上的服务器端 jQuery。一个包中包含选择器引擎解析、DOM 风格遍历、属性操作和 HTML 序列化。
- **graphql-js / jsonata** — GraphQL 参考实现和一种 JSON 查询语言。两者都大量涉及 Schema、验证和递归求值器，是典型的“浏览器中的数据层”代码。
- **JSZip** — 异步 ZIP 归档构建器。通过 `setImmediate` 驱动的调度来执行任务并生成真实的二进制输出，可测试计时器接口和大量使用 `Uint8Array` 的路径。
- **moment / luxon** — 日期和时间运算。moment 是可变的、经过手工调优的 UMD；luxon 是现代的不可变改写版本。两者结合覆盖了格式化、解析以及时区等效的年月运算。
- **mqtt-packet** — 纯 JS MQTT 3.1.1 / 5.0 编解码器。字节级打包和解码，以及会测试 Annex-B 语法边界的 Base64 非字母字符类正则表达式。
- **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 和 CSS AST。语法各不相同，都是测试字符级扫描和正则表达式行为的良好探针。

## 添加更多

在 `tests/Popular/<name>/` 下新建一个目录，包含上述三种文件，然后：

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

下次运行时，PHPUnit 套件会自动发现它；由于改动涉及 `tests/Popular/`，CI 也会将其纳入检查。

值得考虑添加的候选库：`chevrotain`（解析器组合器，可测试闭包和正则表达式）、`nanoid`（加密和随机性边界）、`date-fns`（覆盖 dayjs 之外的时区功能）。
