From 955ec6d7a4f4ab64555d6dd4bb2e2db0f43312c4 Mon Sep 17 00:00:00 2001 From: sunyiteng Date: Tue, 17 Mar 2026 15:44:52 +0800 Subject: [PATCH 1/6] docs: enrich README with full API docs, usage examples, and feature table --- README.md | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 150 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 727b54b..041c142 100644 --- a/README.md +++ b/README.md @@ -2,27 +2,46 @@ [![npm latest version](https://img.shields.io/npm/v/path-serializer?style=flat-square&color=98c379)](https://www.npmjs.com/package/path-serializer) -1. stabilize pnpm dependencies path in snapshot -2. transform win32 path to posix path -3. escapeEOL \r\n -> \n - and more... +A snapshot serializer that normalizes system-specific paths into stable, readable placeholders — designed for Vitest, Jest, and Rstest. + +- Stabilize pnpm dependencies path in snapshot +- Transform win32 path to posix path +- Replace absolute paths with placeholders (``, ``, ``, ``) +- Handle `file://` protocol URLs +- Escape EOL (`\r\n` -> `\n`) +- Normalize ANSI color codes ```ts // __snapshots__/index.test.ts.snap -// 😭 bad + +// 😭 Without path-serializer — fragile, platform-specific, unreadable { "loader" : "D:\\user\\rspack\\node_modules\\.pnpm\\css-loader@6.11.0_@rspack+core@packages+rspack_webpack@5.94.0_@swc+core@1.4.0_@swc+helpers@0._jlcdgjlw2ezzhg43ml3d627wdu\\node_modules\\css-loader\\utils.ts" } -//😎👍🏻 good + +// 😎 With path-serializer — stable, cross-platform, clean { "loader" : "/node_modules//css-loader/utils.ts" } ``` +## Installation + +```bash +# npm +npm install path-serializer -D + +# pnpm +pnpm add path-serializer -D +``` + ## Usage +### Basic + ```typescript // vitest.setup.ts +import path from 'node:path'; import { createSnapshotSerializer } from 'path-serializer'; expect.addSnapshotSerializer( @@ -32,12 +51,133 @@ expect.addSnapshotSerializer( ); ``` -More features can be found in [./src/types.ts](https://github.com/rspack-contrib/path-serializer/blob/main/src/types.ts) +### With Workspace (Monorepo) + +```typescript +expect.addSnapshotSerializer( + createSnapshotSerializer({ + root: path.join(__dirname, '../..'), + workspace: path.join(__dirname, '..'), + }), +); +``` + +This replaces: +- Workspace paths → `/...` +- Root paths → `/...` + +### Custom Replacements + +Use `replace` and `replacePost` to add custom path matchers: + +```typescript +expect.addSnapshotSerializer( + createSnapshotSerializer({ + root: path.join(__dirname, '..'), + replace: [ + { match: /port\s\d+/, mark: 'port ' }, + { match: '/specific/path', mark: '' }, + ], + }), +); +``` + +### Hooks + +Use `beforeSerialize` and `afterSerialize` for custom pre/post processing: + +```typescript +expect.addSnapshotSerializer( + createSnapshotSerializer({ + root: path.join(__dirname, '..'), + beforeSerialize: (val) => val.replace(/hash:\w{8}/g, 'hash:'), + afterSerialize: (val) => val.trim(), + }), +); +``` + +## Options + +### `root` + +- **Type:** `string` +- **Default:** `process.cwd()` + +Repository root path. Paths under this directory are replaced with ``. + +### `workspace` + +- **Type:** `string` +- **Default:** `''` + +Workspace root path (for monorepos). Paths under this directory are replaced with ``. + +### `replace` + +- **Type:** `PathMatcher[]` + +Custom matchers applied **before** built-in replacements. + +### `replacePost` + +- **Type:** `PathMatcher[]` + +Custom matchers applied **after** built-in replacements. + +### `beforeSerialize` + +- **Type:** `(val: string) => string` + +Transform the raw string before any replacements. + +### `afterSerialize` + +- **Type:** `(val: string) => string` + +Transform the final string after all replacements. + +### `features` + +Toggle individual features (all enabled by default): + +| Feature | Default | Description | +|---|---|---| +| `replaceWorkspace` | `true` | `/foo/packages/core/src` → `/src` | +| `replaceRoot` | `true` | `/foo/node_modules/.pnpm` → `/node_modules/.pnpm` | +| `replaceWorkspaceWithFileProtocol` | `true` | `file:///foo/packages/core/src` → `/src` | +| `replaceRootWithFileProtocol` | `true` | `file:///foo/node_modules/.pnpm` → `/node_modules/.pnpm` | +| `replacePnpmInner` | `true` | Collapse pnpm's long `.pnpm/...` paths to `` | +| `replaceTmpDir` | `true` | `os.tmpdir()` paths → `` | +| `replaceHomeDir` | `true` | `os.homedir()` paths → `` | +| `transformWin32Path` | `true` | Convert `D:\\foo\\bar` to `/d/foo/bar` | +| `transformCLR` | `true` | Normalize ANSI color escape codes | +| `escapeDoubleQuotes` | `true` | Escape `"` to `\"` | +| `escapeEOL` | `true` | Normalize `\r\n` to `\n` | +| `addDoubleQuotes` | `true` | Wrap output in double quotes | + +## Processing Pipeline + +``` +beforeSerialize → replace → [built-in features] → replacePost → afterSerialize +``` + +Built-in features are applied in this order: + +1. `replaceWorkspaceWithFileProtocol` +2. `replaceRootWithFileProtocol` +3. `transformWin32Path` +4. `replaceWorkspace` / `replaceRoot` / `replacePnpmInner` / `replaceTmpDir` / `replaceHomeDir` +5. `transformCLR` +6. `escapeDoubleQuotes` +7. `escapeEOL` +8. `addDoubleQuotes` ## Showcases -[Rslib](https://github.com/web-infra-dev/rslib/blob/3ff6859eb38171c731e447a1364afc021f8c501a/tests/setupVitestTests.ts) +- [Rslib](https://github.com/web-infra-dev/rslib/blob/3ff6859eb38171c731e447a1364afc021f8c501a/tests/setupVitestTests.ts) +- [Rsbuild](https://github.com/web-infra-dev/rsbuild/blob/a50eafa3519caaa66ecd6b0ccb2897a8194781ff/scripts/test-helper/vitest.setup.ts) +- [Rspack](https://github.com/web-infra-dev/rspack/blob/5a6162c/packages/rspack-test-tools/src/helper/expect/placeholder.ts) -[Rsbuild](https://github.com/web-infra-dev/rsbuild/blob/a50eafa3519caaa66ecd6b0ccb2897a8194781ff/scripts/test-helper/vitest.setup.ts) +## License -[Rspack](https://github.com/web-infra-dev/rspack/blob/5a6162c/packages/rspack-test-tools/src/helper/expect/placeholder.ts) +[MIT](./LICENSE) From bb33419c923ebadb650eeeaa36b90f4bd6e36c5f Mon Sep 17 00:00:00 2001 From: sunyiteng Date: Tue, 17 Mar 2026 15:47:20 +0800 Subject: [PATCH 2/6] docs: add Rspress to showcases --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 041c142..ef426ca 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,7 @@ Built-in features are applied in this order: - [Rslib](https://github.com/web-infra-dev/rslib/blob/3ff6859eb38171c731e447a1364afc021f8c501a/tests/setupVitestTests.ts) - [Rsbuild](https://github.com/web-infra-dev/rsbuild/blob/a50eafa3519caaa66ecd6b0ccb2897a8194781ff/scripts/test-helper/vitest.setup.ts) - [Rspack](https://github.com/web-infra-dev/rspack/blob/5a6162c/packages/rspack-test-tools/src/helper/expect/placeholder.ts) +- [Rspress](https://github.com/web-infra-dev/rspress/blob/8d620050cc2590954838e201d39c10744b6d1bac/scripts/test-helper/rstest.setup.ts) ## License From 61a42870fa952daa96a75b85df9b594f8e1c074f Mon Sep 17 00:00:00 2001 From: sunyiteng Date: Tue, 17 Mar 2026 15:49:40 +0800 Subject: [PATCH 3/6] docs: remove Processing Pipeline section and fix mark example --- README.md | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/README.md b/README.md index ef426ca..18ef34b 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ expect.addSnapshotSerializer( createSnapshotSerializer({ root: path.join(__dirname, '..'), replace: [ - { match: /port\s\d+/, mark: 'port ' }, + { match: /port\s\d+/, mark: 'PORT' }, { match: '/specific/path', mark: '' }, ], }), @@ -155,23 +155,6 @@ Toggle individual features (all enabled by default): | `escapeEOL` | `true` | Normalize `\r\n` to `\n` | | `addDoubleQuotes` | `true` | Wrap output in double quotes | -## Processing Pipeline - -``` -beforeSerialize → replace → [built-in features] → replacePost → afterSerialize -``` - -Built-in features are applied in this order: - -1. `replaceWorkspaceWithFileProtocol` -2. `replaceRootWithFileProtocol` -3. `transformWin32Path` -4. `replaceWorkspace` / `replaceRoot` / `replacePnpmInner` / `replaceTmpDir` / `replaceHomeDir` -5. `transformCLR` -6. `escapeDoubleQuotes` -7. `escapeEOL` -8. `addDoubleQuotes` - ## Showcases - [Rslib](https://github.com/web-infra-dev/rslib/blob/3ff6859eb38171c731e447a1364afc021f8c501a/tests/setupVitestTests.ts) From e9d757c787ee4014afc0b9e65fceeb4b0f3378a1 Mon Sep 17 00:00:00 2001 From: sunyiteng Date: Tue, 17 Mar 2026 15:54:33 +0800 Subject: [PATCH 4/6] docs: fix mark example to use plain string without angle brackets --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 18ef34b..500a6ee 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ expect.addSnapshotSerializer( root: path.join(__dirname, '..'), replace: [ { match: /port\s\d+/, mark: 'PORT' }, - { match: '/specific/path', mark: '' }, + { match: '/specific/path', mark: 'CUSTOM' }, ], }), ); From 08e46e872b91d953c64ffa85b614ad7d018f7c5e Mon Sep 17 00:00:00 2001 From: sunyiteng Date: Tue, 17 Mar 2026 16:02:26 +0800 Subject: [PATCH 5/6] docs: add reference link to src/types.ts for more details --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 500a6ee..dca0d22 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,8 @@ Toggle individual features (all enabled by default): | `escapeEOL` | `true` | Normalize `\r\n` to `\n` | | `addDoubleQuotes` | `true` | Wrap output in double quotes | +More details can be found in [./src/types.ts](https://github.com/rspack-contrib/path-serializer/blob/main/src/types.ts). + ## Showcases - [Rslib](https://github.com/web-infra-dev/rslib/blob/3ff6859eb38171c731e447a1364afc021f8c501a/tests/setupVitestTests.ts) From d7b8f2e0ad9105428408c3090b747694e28ccd58 Mon Sep 17 00:00:00 2001 From: Soon Date: Tue, 17 Mar 2026 16:03:13 +0800 Subject: [PATCH 6/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dca0d22..c61e202 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ pnpm add path-serializer -D ```typescript // vitest.setup.ts import path from 'node:path'; +import { expect } from 'vitest'; import { createSnapshotSerializer } from 'path-serializer'; expect.addSnapshotSerializer(