monocart-coverage-reports 2.12.11 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -66,7 +66,7 @@
66
66
  * [Thanks](#thanks)
67
67
 
68
68
  ## Usage
69
- > It's recommended to use [Node.js 20+](https://nodejs.org/).
69
+ > [Node.js 22+](https://nodejs.org/) is recommended and is the actively maintained target.
70
70
  - Install
71
71
  ```sh
72
72
  npm install monocart-coverage-reports
@@ -89,6 +89,8 @@ import { CoverageReport } from 'monocart-coverage-reports';
89
89
  const mcr = new CoverageReport();
90
90
  await mcr.loadConfig();
91
91
  ```
92
+ > Both `MCR({...})` and `new CoverageReport()` create the same instance. `MCR()` is a shorthand factory function; use `new CoverageReport()` when you prefer class instantiation or need to call `loadConfig()` separately.
93
+
92
94
  For more information, see [Multiprocessing Support](#multiprocessing-support)
93
95
 
94
96
  - CLI
@@ -106,7 +108,7 @@ For more information, see [Command Line](#command-line)
106
108
  | :-- | :-- | :-- | :-- |
107
109
  | `logging` | `"off" \| "error" \| "info" \| "debug"` | `"info"` | Logging level. Use `"debug"` to keep raw cache and dump sourcemaps for troubleshooting. See [Debug for Coverage and Sourcemap](#debug-for-coverage-and-sourcemap). |
108
110
  | `name` | `string` | `"Coverage Report"` | Report title shown in the UI and summary reports. |
109
- | `reports` | `string \| (string \| ReportDescription)[]` | `"v8"` (V8) / `"html"` (Istanbul) | Reports to generate. See [Available Reports](#available-reports). |
111
+ | `reports` | `string \| (string \| ReportDescription)[]` | `""` (auto) | Reports to generate. Defaults to `"v8"` for V8 data and `"html"` for Istanbul data. See [Available Reports](#available-reports). |
110
112
  | `outputDir` | `string` | `"./coverage-reports"` | Output directory for all reports and the `.cache` folder. |
111
113
  | `inputDir` | `string \| string[]` | `null` | Input directories of raw coverage data for [merging](#merge-coverage-reports). |
112
114
  | `baseDir` | `string` | `process.cwd()` | Base dir used to normalize relative source paths. Set when the report is generated from a different working directory than the sources. |
@@ -123,15 +125,13 @@ For more information, see [Command Line](#command-line)
123
125
  | `v8Ignore` | `boolean` | `true` | (V8 only) Enable/disable comment-based ignoring (`v8 ignore …`). See [Ignoring Uncovered Codes](#ignoring-uncovered-codes). |
124
126
  | `reportPath` | `string \| () => string` | `null` | Override the report entry path (defaults to `outputDir/index.html`). Useful when multiple reports share an `outputDir`. |
125
127
  | `watermarks` | `[number, number] \| object` | `[50, 80]` | Low/high thresholds (percent). Accepts per-metric object like `{ bytes:[50,80], lines:[50,80] }`. |
126
- | `clean` | `boolean` | `true` | Clean previous reports in `outputDir` before generating. |
127
- | `cleanCache` | `boolean` | `false` | Clean the cache dir on start. |
128
+ | `clean` | `boolean` | `true` | Clean previous reports in `outputDir` before generating (the `.cache` dir is preserved unless `cleanCache` is also `true`). |
129
+ | `cleanCache` | `boolean` | `false` | Clean the cache dir on start. When both `clean` and `cleanCache` are `false`, cached coverage data from previous runs is preserved and can be reused across processes. |
128
130
  | `gc` | `number` | `null` | Memory threshold in MB; force GC at critical stages when RSS exceeds it. Useful for very large data sets, see [JavaScript heap out of memory](#javascript-heap-out-of-memory). |
129
131
  | `sourceMap` | `boolean` | `false` | Save source/sourcemap files to cache for debugging (requires `logging: "debug"`). |
130
132
  | `sourceMapResolver` | `(url, defaultResolver) => Promise<string \| object>` | `null` | Custom sourcemap loader (e.g. from a build cache). Call `defaultResolver(url)` to fall back. |
131
133
  | `onEntry` | `(entry) => void \| Promise<void>` | `null` | (V8 only) Per-entry hook; see [Hooks](#hooks). |
132
134
  | `onEnd` | `(coverageResults) => void \| Promise<void>` | `null` | Hook invoked after report generation; see [Hooks](#hooks). |
133
- | `onStart` | `(coverageReport) => void \| Promise<void>` | `null` | (CLI only) Before the child process starts; see [Hooks](#hooks). |
134
- | `onReady` | `(coverageReport, nodeV8CoverageDir, subprocess) => void \| Promise<void>` | `null` | (CLI only) After the child exits, before MCR reads coverage data; see [Hooks](#hooks). |
135
135
 
136
136
  ## Available Reports
137
137
 
@@ -223,6 +223,11 @@ cat path-to/coverage-summary.md >> $GITHUB_STEP_SUMMARY
223
223
  - V8 custom reporter
224
224
  > example: [./test/custom-v8-reporter.js](./test/custom-v8-reporter.js)
225
225
 
226
+ The `type` option determines which coverage format the reporter receives:
227
+ - `'istanbul'` — the reporter receives Istanbul-format coverage data (`coverageResults.istanbulData`).
228
+ - `'v8'` — the reporter receives native V8-format coverage data (`coverageResults.v8Data`).
229
+ - `'both'` — the reporter receives both formats, accessible via `coverageResults.v8Data` and `coverageResults.istanbulData`.
230
+
226
231
  ### Multiple Reports:
227
232
  ```js
228
233
  const MCR = require('monocart-coverage-reports');
@@ -526,7 +531,22 @@ export type V8CoverageData = ScriptCoverage[];
526
531
  | Firefox (2%) | ❌ | |
527
532
  | Node.js | ✅ | |
528
533
  | Deno | ❌ | [issue](https://github.com/denoland/deno/issues/23359) |
529
- | Bun | ❌ | |
534
+ | Bun | ❌ | [issue](https://github.com/oven-sh/bun/issues/30968) |
535
+
536
+ > MCR extends each V8 coverage entry with additional fields:
537
+
538
+ | Field | Type | Description |
539
+ | :-- | :-- | :-- |
540
+ | `url` | `string` | Script URL or file path |
541
+ | `type` | `"js" \| "css"` | Entry type |
542
+ | `source` | `string` | (JS) Source code text |
543
+ | `sourceMap` | `object` | (JS) Parsed sourcemap object |
544
+ | `scriptOffset` | `number` | (JS) Byte offset for the script wrapper (e.g. in `vm` modules). This offset is automatically added to all range start/end values |
545
+ | `distFile` | `string` | (JS) The dist bundle file this source was unpacked from |
546
+ | `empty` | `boolean` | Marked as `true` when this entry was added via the `all` option (no real coverage data), showing 0% coverage |
547
+ | `fake` | `boolean` | Marked as `true` when the source code is not original (e.g. compiled from `.ts`/`.jsx`). The AST parser skips coverage extraction for fake sources |
548
+
549
+ These fields can be read/mutated in [`onEntry`](#hooks) hooks.
530
550
 
531
551
  ## Filtering Results
532
552
  ### Using `entryFilter` and `sourceFilter` to filter the results for V8 report
@@ -847,7 +867,19 @@ npx mcr node ./test/specs/node.test.js -r v8,console-details --lcov
847
867
  ```
848
868
 
849
869
  - CLI Options
850
- see all options with running `mcr` or `mcr --help`
870
+
871
+ The options below are only available when using the CLI (`mcr <command>`):
872
+
873
+ | Option | Type | Default | Description |
874
+ | :-- | :-- | :-- | :-- |
875
+ | `-c, --config` | `string` | — | Custom config file path |
876
+ | `--import` | `string` | `null` | Preload ESM module via `NODE_OPTIONS`, e.g. `tsx` for TypeScript. Requires Node.js `>= 18.19` |
877
+ | `--require` | `string` | `null` | Preload CJS module via `NODE_OPTIONS` |
878
+ | `--env` | `string` | `null` | Load environment variables from a dotenv file (defaults to `.env`). Requires Node.js `>= 20.6` |
879
+ | `onStart` | `(coverageReport) => Promise<void>` | `null` | Runs before the child process is spawned; see [Hooks](#hooks) |
880
+ | `onReady` | `(coverageReport, nodeV8CoverageDir, subprocess) => Promise<void>` | `null` | Runs after the child exits, before MCR reads coverage; see [Hooks](#hooks) |
881
+
882
+ For other options (e.g. `--name`, `--reports`, `--outputDir`, `--lcov`, etc.), see the [Options](#options) table — they work the same way in CLI.
851
883
 
852
884
  - Use `--` to separate sub CLI args
853
885
  ```sh
@@ -864,6 +896,12 @@ mcr --import tsx node ./test.ts
864
896
  mcr --env .env.test node ./test.js
865
897
  ```
866
898
 
899
+ - `merge`: merge raw coverage data from `inputDir`(s) and generate merged reports directly, without running a child process.
900
+ ```sh
901
+ mcr merge -r v8,console-details --inputDir ./coverage-reports/unit/raw,./coverage-reports/e2e/raw --outputDir ./coverage-reports/merged
902
+ ```
903
+ See [Merge Coverage Reports](#merge-coverage-reports).
904
+
867
905
  - Examples
868
906
  - [Mocha](#mocha)
869
907
  - [TypeScript](#typescript)
@@ -1234,7 +1272,7 @@ const coverageOptions = {
1234
1272
  ```
1235
1273
 
1236
1274
  ## Contributing
1237
- - Node.js 20+
1275
+ - Node.js 22+ (recommended development version)
1238
1276
  - VSCode (extensions: eslint/stylelint/vue)
1239
1277
  ```sh
1240
1278
  npm install
package/README.zh-Hans.md CHANGED
@@ -66,7 +66,7 @@
66
66
  * [感谢](#thanks)
67
67
 
68
68
  ## Usage
69
- > 推荐使用 [Node.js 20+](https://nodejs.org/).
69
+ > 推荐使用 [Node.js 22+](https://nodejs.org/),项目将其作为持续维护的目标版本。
70
70
  - 安装
71
71
  ```sh
72
72
  npm install monocart-coverage-reports
@@ -89,6 +89,8 @@ import { CoverageReport } from 'monocart-coverage-reports';
89
89
  const mcr = new CoverageReport();
90
90
  await mcr.loadConfig();
91
91
  ```
92
+ > `MCR({...})` 和 `new CoverageReport()` 创建的是同一个实例。`MCR()` 是简写工厂函数;`new CoverageReport()` 更适合需要单独调用 `loadConfig()` 的场景。
93
+
92
94
  参见 [多进程支持](#multiprocessing-support)
93
95
 
94
96
  - CLI
@@ -106,7 +108,7 @@ mcr node my-app.js -r v8,console-details
106
108
  | :-- | :-- | :-- | :-- |
107
109
  | `logging` | `"off" \| "error" \| "info" \| "debug"` | `"info"` | 日志级别。设为 `"debug"` 会保留原始缓存并输出 sourcemap,便于排查问题。参见 [调试覆盖率和sourcemap](#debug-for-coverage-and-sourcemap)。 |
108
110
  | `name` | `string` | `"Coverage Report"` | 报告标题,显示在 UI 以及 summary 报告中。 |
109
- | `reports` | `string \| (string \| ReportDescription)[]` | V8 默认 `"v8"` / Istanbul 默认 `"html"` | 生成哪些报告,参见 [所有支持的报告类型](#available-reports)。 |
111
+ | `reports` | `string \| (string \| ReportDescription)[]` | `""` (自动) | 生成哪些报告。V8 数据默认 `"v8"`,Istanbul 数据默认 `"html"`。参见 [所有支持的报告类型](#available-reports)。 |
110
112
  | `outputDir` | `string` | `"./coverage-reports"` | 所有报告以及 `.cache` 的输出目录。 |
111
113
  | `inputDir` | `string \| string[]` | `null` | 导入的原始覆盖率数据目录(用于 [合并](#merge-coverage-reports))。 |
112
114
  | `baseDir` | `string` | `process.cwd()` | 规范化相对源路径的基准目录。当生成报告的工作目录和源码目录不一致时需要设置。 |
@@ -123,15 +125,13 @@ mcr node my-app.js -r v8,console-details
123
125
  | `v8Ignore` | `boolean` | `true` | (仅 V8)启用/禁用基于注释的忽略(`v8 ignore …`),参见 [忽略未覆盖代码](#ignoring-uncovered-codes)。 |
124
126
  | `reportPath` | `string \| () => string` | `null` | 覆盖默认的报告入口路径(默认 `outputDir/index.html`)。多个报告共用同一 `outputDir` 时很有用。 |
125
127
  | `watermarks` | `[number, number] \| object` | `[50, 80]` | 覆盖率高/低阈值百分比。也支持按指标配置:`{ bytes:[50,80], lines:[50,80] }`。 |
126
- | `clean` | `boolean` | `true` | 生成报告前清理 `outputDir` 中的旧报告。 |
127
- | `cleanCache` | `boolean` | `false` | 启动时清理缓存目录。 |
128
+ | `clean` | `boolean` | `true` | 生成报告前清理 `outputDir` 中的旧报告(`.cache` 目录在 `cleanCache` 也为 `true` 时才会被清理)。 |
129
+ | `cleanCache` | `boolean` | `false` | 启动时清理缓存目录。当 `clean` 和 `cleanCache` 都为 `false` 时,之前运行的缓存数据会保留,可在多进程间复用。 |
128
130
  | `gc` | `number` | `null` | 内存阈值(MB),在关键阶段若 RSS 超过阈值则强制触发 GC,适用于超大数据集,参见 [JavaScript heap out of memory](#javascript-heap-out-of-memory)。 |
129
131
  | `sourceMap` | `boolean` | `false` | 将源文件和 sourcemap 也保存到 cache 便于调试(需要 `logging: "debug"`)。 |
130
132
  | `sourceMapResolver` | `(url, defaultResolver) => Promise<string \| object>` | `null` | 自定义 sourcemap 加载逻辑(例如从构建缓存中读取),可调用 `defaultResolver(url)` 回退到默认解析。 |
131
133
  | `onEntry` | `(entry) => void \| Promise<void>` | `null` | (仅 V8)每个入口文件处理前触发,参见 [Hooks](#hooks)。 |
132
134
  | `onEnd` | `(coverageResults) => void \| Promise<void>` | `null` | 报告生成完成后触发,参见 [Hooks](#hooks)。 |
133
- | `onStart` | `(coverageReport) => void \| Promise<void>` | `null` | (仅 CLI)子进程启动前触发,参见 [Hooks](#hooks)。 |
134
- | `onReady` | `(coverageReport, nodeV8CoverageDir, subprocess) => void \| Promise<void>` | `null` | (仅 CLI)子进程退出后、MCR 读取覆盖率数据前触发,参见 [Hooks](#hooks)。 |
135
135
 
136
136
  ## Available Reports
137
137
 
@@ -223,6 +223,11 @@ cat path-to/coverage-summary.md >> $GITHUB_STEP_SUMMARY
223
223
  - V8自定义报告
224
224
  > 例子: [./test/custom-v8-reporter.js](./test/custom-v8-reporter.js)
225
225
 
226
+ `type` 选项决定报告接收的覆盖率数据格式:
227
+ - `'istanbul'` — 报告接收 Istanbul 格式的覆盖率数据(`coverageResults.istanbulData`)。
228
+ - `'v8'` — 报告接收原生 V8 格式的覆盖率数据(`coverageResults.v8Data`)。
229
+ - `'both'` — 报告同时接收两种格式,可通过 `coverageResults.v8Data` 和 `coverageResults.istanbulData` 访问。
230
+
226
231
  ### Multiple Reports:
227
232
  如何配置多个报告
228
233
  ```js
@@ -530,7 +535,22 @@ export type V8CoverageData = ScriptCoverage[];
530
535
  | Firefox (2%) | ❌ | |
531
536
  | Node.js | ✅ | |
532
537
  | Deno | ❌ | [issue](https://github.com/denoland/deno/issues/23359) |
533
- | Bun | ❌ | |
538
+ | Bun | ❌ | [issue](https://github.com/oven-sh/bun/issues/30968) |
539
+
540
+ > MCR 为每个 V8 覆盖率条目扩展了以下字段:
541
+
542
+ | 字段 | 类型 | 说明 |
543
+ | :-- | :-- | :-- |
544
+ | `url` | `string` | 脚本 URL 或文件路径 |
545
+ | `type` | `"js" \| "css"` | 条目类型 |
546
+ | `source` | `string` | (JS)源代码文本 |
547
+ | `sourceMap` | `object` | (JS)已解析的 sourcemap 对象 |
548
+ | `scriptOffset` | `number` | (JS)脚本包裹层的字节偏移(例如 `vm` 模块中)。此偏移会自动加到所有 range 的 start/end 值上 |
549
+ | `distFile` | `string` | (JS)该 source 解包自的 dist 打包文件 |
550
+ | `empty` | `boolean` | 当条目通过 `all` 选项添加(无真实覆盖率数据)时标记为 `true`,显示为 0% 覆盖 |
551
+ | `fake` | `boolean` | 当源代码非原始代码(例如从 `.ts`/`.jsx` 编译而来)时标记为 `true`。AST 解析器会跳过 fake 源的覆盖率提取 |
552
+
553
+ 这些字段可以在 [`onEntry`](#hooks) 钩子中读取或修改。
534
554
 
535
555
  ## Filtering Results
536
556
  ### Using `entryFilter` and `sourceFilter` to filter the results for V8 report
@@ -849,8 +869,20 @@ npm i monocart-coverage-reports
849
869
  npx mcr node ./test/specs/node.test.js -r v8,console-details --lcov
850
870
  ```
851
871
 
852
- - 命令行参数
853
- 直接运行 `mcr` 或 `mcr --help` 查看所有CLI的参数
872
+ - CLI 选项
873
+
874
+ 以下选项仅在 CLI 模式(`mcr <command>`)下可用:
875
+
876
+ | 选项 | 类型 | 默认值 | 说明 |
877
+ | :-- | :-- | :-- | :-- |
878
+ | `-c, --config` | `string` | — | 自定义配置文件路径 |
879
+ | `--import` | `string` | `null` | 通过 `NODE_OPTIONS` 预加载 ESM 模块,如 `tsx`。需要 Node.js `>= 18.19` |
880
+ | `--require` | `string` | `null` | 通过 `NODE_OPTIONS` 预加载 CJS 模块 |
881
+ | `--env` | `string` | `null` | 从 dotenv 文件加载环境变量(默认 `.env`)。需要 Node.js `>= 20.6` |
882
+ | `onStart` | `(coverageReport) => Promise<void>` | `null` | 子进程启动前触发;参见 [Hooks](#hooks) |
883
+ | `onReady` | `(coverageReport, nodeV8CoverageDir, subprocess) => Promise<void>` | `null` | 子进程退出后、MCR 读取覆盖率前触发;参见 [Hooks](#hooks) |
884
+
885
+ 其他选项(如 `--name`、`--reports`、`--outputDir`、`--lcov` 等)参见 [选项配置](#options) 表格,它们在 CLI 中的用法相同。
854
886
 
855
887
  - 使用 `--` 可以隔离子程序参数,以免两种参数混淆
856
888
  ```sh
@@ -867,6 +899,12 @@ mcr --import tsx node ./test.ts
867
899
  mcr --env .env.test node ./test.js
868
900
  ```
869
901
 
902
+ - `merge`: 直接合并 `inputDir` 中的原始覆盖率数据并生成合并报告,无需启动子进程。
903
+ ```sh
904
+ mcr merge -r v8,console-details --inputDir ./coverage-reports/unit/raw,./coverage-reports/e2e/raw --outputDir ./coverage-reports/merged
905
+ ```
906
+ 参见 [合并覆盖率报告](#merge-coverage-reports)。
907
+
870
908
  - 参见例子
871
909
  - [Mocha](#mocha)
872
910
  - [TypeScript](#typescript)
@@ -1239,7 +1277,7 @@ const coverageOptions = {
1239
1277
  ```
1240
1278
 
1241
1279
  ## Contributing
1242
- - Node.js 20+
1280
+ - Node.js 22+(推荐的开发版本)
1243
1281
  - VSCode (extensions: eslint/stylelint/vue)
1244
1282
  ```sh
1245
1283
  npm install
package/lib/assets.js CHANGED
@@ -53,7 +53,7 @@ const Assets = {
53
53
  });
54
54
 
55
55
  // html content
56
- let htmlStr = '';
56
+ let htmlStr;
57
57
  const EOL = Util.getEOL();
58
58
  if (inline) {
59
59
  htmlStr = [
@@ -89,7 +89,7 @@ const applyBytesToLines = (bytes, locator, lineMap) => {
89
89
  } = lineItem;
90
90
 
91
91
  // default count to 1, both js and css
92
- let count = 1;
92
+ let count;
93
93
  // full covered true/false for entire line
94
94
  let covered = true;
95
95
 
@@ -288,9 +288,9 @@ const collectFileCoverage = (v8Data, state, options) => {
288
288
  sortRanges(data.functions);
289
289
 
290
290
  // branch group with locations to flat branches
291
- data.branches = branches.map((info) => {
291
+ data.branches = branches.flatMap((info) => {
292
292
  return info.getRanges();
293
- }).flat();
293
+ });
294
294
  sortRanges(data.branches);
295
295
 
296
296
  data.statements = statements.map((info) => {
@@ -326,21 +326,36 @@ const collectFileCoverage = (v8Data, state, options) => {
326
326
  b: {}
327
327
  };
328
328
 
329
- statements.filter((it) => !it.ignored).forEach((statement, index) => {
329
+ let index = 0;
330
+ for (const statement of statements) {
331
+ if (statement.ignored) {
332
+ continue;
333
+ }
330
334
  istanbulData.statementMap[`${index}`] = statement.generate(locator);
331
335
  istanbulData.s[`${index}`] = statement.count;
332
- });
336
+ index += 1;
337
+ }
333
338
 
334
- functions.filter((it) => !it.ignored).forEach((fn, index) => {
339
+ index = 0;
340
+ for (const fn of functions) {
341
+ if (fn.ignored) {
342
+ continue;
343
+ }
335
344
  istanbulData.fnMap[`${index}`] = fn.generate(locator, index);
336
345
  istanbulData.f[`${index}`] = fn.count;
337
- });
346
+ index += 1;
347
+ }
338
348
 
339
- branches.filter((it) => !it.ignored).forEach((branch, index) => {
349
+ index = 0;
350
+ for (const branch of branches) {
351
+ if (branch.ignored) {
352
+ continue;
353
+ }
340
354
  const { map, counts } = branch.generate(locator);
341
355
  istanbulData.branchMap[`${index}`] = map;
342
356
  istanbulData.b[`${index}`] = counts;
343
- });
357
+ index += 1;
358
+ }
344
359
 
345
360
  return istanbulData;
346
361
 
@@ -1610,7 +1625,7 @@ const mergeV8Data = (state, stateList) => {
1610
1625
 
1611
1626
  // ===========================================================
1612
1627
  // functions
1613
- const allFunctions = stateList.map((it) => it.functions).flat();
1628
+ const allFunctions = stateList.flatMap((it) => it.functions);
1614
1629
  const functionComparer = (lastRange, range) => {
1615
1630
  // if (lastRange.start === range.start && lastRange.end === range.end) {
1616
1631
  // return true;
@@ -1649,7 +1664,7 @@ const mergeV8Data = (state, stateList) => {
1649
1664
 
1650
1665
  // ===========================================================
1651
1666
  // statements
1652
- const allStatements = stateList.map((it) => it.statements).flat();
1667
+ const allStatements = stateList.flatMap((it) => it.statements);
1653
1668
  const statementComparer = (lastRange, range) => {
1654
1669
  // exact matched because the statement range is generated from ast
1655
1670
  return lastRange.start === range.start && lastRange.end === range.end;
@@ -1663,7 +1678,7 @@ const mergeV8Data = (state, stateList) => {
1663
1678
 
1664
1679
  // ===========================================================
1665
1680
  // branches
1666
- const allBranches = stateList.map((it) => it.branches).flat();
1681
+ const allBranches = stateList.flatMap((it) => it.branches);
1667
1682
  const branchComparer = (lastRange, range) => {
1668
1683
  // exact matched because the branch range is generated from ast
1669
1684
  return lastRange.start === range.start && lastRange.end === range.end;
@@ -1743,7 +1758,7 @@ const generateV8DataList = (stateList, options) => {
1743
1758
 
1744
1759
  // merge istanbul and v8(converted)
1745
1760
  const mergeMap = new Map();
1746
- allOriginalList.flat().forEach((originalState) => {
1761
+ allOriginalList.flatMap((arr) => arr).forEach((originalState) => {
1747
1762
  const { v8Data } = originalState;
1748
1763
  const id = v8Data.id;
1749
1764
  // exists item