
# 인기 패키지

명세 적합성만으로 실제 라이브러리가 작동한다고 보장할 수는 없습니다. 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 |
| **검증 / 스키마** | 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`와 바이트 단위로 동일한지 확인합니다.

oracle을 다시 생성하려면 다음을 실행하세요:

```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 측** — 각 라이브러리를 Phasis을 통해 실행하고 커밋된 oracle과 비교하는 PHPUnit `popular` 테스트 모음을 실행합니다. 단 한 바이트라도 다르면 실패합니다.
2. **Node 재검증** — 각 라이브러리에 대해 `node tests/Popular/gen-oracle.js …`를 실행하고 새로 생성한 oracle이 체크인된 내용과 일치하는지 확인합니다. "oracle을 업데이트하지 않고 벤더링한 라이브러리만 업데이트한" 불일치를 감지합니다.

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는 생성자 변형, DST에 해당하는 월 경계를 넘는 연산, 형식 토큰 확장을 다루며, 대부분의 JS 날짜 라이브러리가 사용하는 코드 경로와 거의 같습니다.
- **bignumber.js** — TypedArray 없이 임의 정밀도 연산을 수행하므로 문자열 기반 숫자 파싱, 큰 정수의 곱셈 및 나눗셈 반복, 반올림 모드 선택을 시험합니다. 이 모든 작업이 순수 JS로 이뤄져 엔진이 전체 비용을 부담합니다. Number ↔ String 변환에서 미묘한 문제가 있는지도 드러냅니다.
- **json5** — 느슨한 JSON 파싱은 문자 클래스 정규식과 상태를 유지하는 토큰화에 크게 의존합니다. 정규식의 정확성과 문자열 순회 경계를 모두 확인하기에 좋은 카나리아입니다.
- **fuse.js** — Babel로 트랜스파일된 UMD로, `_classCallCheck`(ES6 이전에 트랜스파일된 모든 클래스에서 사용하는 `this instanceof Ctor` 패턴)과 전체 bitap 퍼지 매칭 알고리즘을 시험합니다. Babel로 트랜스파일된 라이브러리에서 흔히 볼 수 있는 형태이므로 Fuse를 망가뜨리는 문제는 npm 생태계의 절반을 망가뜨립니다.
- **handlebars** — 컴파일 후 렌더링하는 기능이 풍부한 템플릿 엔진입니다. 단일 대형 `compile()` 엔트리를 통한 `eval` 없는 런타임 경로, AST 순회, 동적 조회 테이블을 통한 헬퍼 호출, 여러 realm에서 `instanceof`을 사용하는 `SafeString` 브랜드 검사를 시험합니다. mustache.js의 더 단순한 템플릿 순회 방식과 대조됩니다.
- **zod** — 런타임 스키마 검증에 사용됩니다. 메서드 체이닝이 정제된 하위 클래스를 반환하는 복잡한 클래스 계층(`ZodString`, `ZodObject`, `ZodArray`, `ZodUnion`, …), JS 측의 `.issues` 배열 형태가 Node와 바이트 단위로 일치해야 하는 구조화된 오류 형식 지정, 판별자 및 리터럴 태그 패턴을 다룹니다. 최신 TypeScript 앱의 절반을 감싸는 객체 지향 중심 검증 코드 유형을 시험합니다.
- **typescript** — 임베디드 엔진에서 실행되는 *실제* TypeScript 컴파일러입니다. 9 MB 크기의 최소화된 컴파일러가 임의의 TS를 다시 파싱하고 AST를 순회해 JS를 출력합니다. 상상할 수 있는 가장 무거운 순수 JS 페이로드입니다. Phasis가 제네릭, async/await, enum, 클래스 계층을 `tsc`와 바이트 단위로 동일하게 트랜스파일할 수 있다면 언어 의미론은 안정적입니다.
- **prettier** — 의견이 반영된 JS 포맷터입니다. JS를 포함한 JS의 형식을 지정하면 엔진이 다루는 모든 사양상의 예외가 코드 형식을 지정하는 동일한 제어 흐름을 거칩니다. 매우 까다로운 작업 부하입니다.
- **svelte/compiler** — Svelte의 독립형 컴파일러입니다. `.svelte` 소스를 파싱하고 AST를 순회해 클라이언트 및 SSR 대상용 JS를 출력합니다.
- **terser / @babel/parser / postcss** — JS 최소화 도구, JS 파서, CSS 후처리기입니다. 임의의 입력을 다시 파싱하는 수만 줄의 최소화된 코드로, 드문 AST 형태가 나타나는 영역입니다.
- **ajv** — 각 스키마를 `new Function(...)`를 통해 사용자 지정 검증 함수로 JIT 컴파일하는 JSON 스키마 검증기입니다. 대부분의 스키마 및 템플릿 라이브러리가 사용하는 Function 생성자 경로를 시험합니다.
- **mobx** — 프록시 기반 반응형 상태 관리 도구입니다. 관찰 가능한 값을 읽을 때마다 Proxy `get` 트랩이 종속성을 등록하고, 쓸 때마다 반응을 실행합니다. Proxy 인프라, 관찰 가능한 Map/배열/중첩 객체, autorun 스케줄러를 집중적으로 시험합니다.
- **cheerio / htmlparser2** — 빠른 HTML 파서를 기반으로 한 서버 측 jQuery입니다. 선택자 엔진 파싱, 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** — 현대 상태 관리 방식의 폭넓은 사례입니다. 상태 머신, 프록시 상태, atom 저장소, 파생 atom, 제너레이터 기반 효과 실행기를 다루며 각 라이브러리는 서로 다른 반응성 형태를 시험합니다.
- **escodegen / acorn-walk / estraverse / magic-string** — AST 도구입니다. 코드 생성, 순회, 원본을 손상하지 않는 편집은 모든 JS-on-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보다 폭넓은 시간대 처리).
