feat: add initial continous benchmarking
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Sat, 16 Sep 2023 12:12:22 +0000 (14:12 +0200)
committerJérôme Benoit <jerome.benoit@piment-noir.org>
Sat, 16 Sep 2023 12:12:22 +0000 (14:12 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
15 files changed:
.eslintrc.js
.github/workflows/benchmark.yml
.github/workflows/ci.yml
.github/workflows/publish-package.yml [moved from .github/workflows/npmpublish.yml with 96% similarity]
.gitignore
CHANGELOG.md
benchmarks/benchmarks-utils.mjs
benchmarks/internal/bench.mjs
benchmarks/internal/cluster-worker.mjs
benchmarks/internal/thread-worker.mjs
benchmarks/worker-selection/least.mjs [moved from benchmarks/worker-selection/less.mjs with 85% similarity]
benchmarks/worker-selection/round-robin.mjs
biome.json
package.json
pnpm-lock.yaml

index 952d603a43f635a5c40f8149a4dabbf26cddc166..97f787aeb53f70fba974107339ec3d95182ffb51 100644 (file)
@@ -39,7 +39,6 @@ module.exports = defineConfig({
         skipWords: [
           'axios',
           'benoit',
-          'benny',
           'browserslist',
           'builtins',
           'christopher',
index 34655f4c82ef5be8bb7b136d386727f78418e09e..196768626358d192b6f0b9fdff0e25bf95f438bc 100644 (file)
@@ -1,36 +1,43 @@
 name: Benchmark
 
 on:
-  workflow_dispatch:
+  push:
+    branches:
+      - master
+
+permissions:
+  contents: write
+  deployments: write
 
 jobs:
   internal-benchmark:
-    strategy:
-      matrix:
-        os: [windows-latest, macos-latest, ubuntu-latest]
-        node: ['16.x', '18.x', '20.x']
-
-    name: Internal benchmark with Node.js ${{ matrix.node }} on ${{ matrix.os }}
-
-    runs-on: ${{ matrix.os }}
-
+    name: Internal benchmark
+    runs-on: ubuntu-latest
     steps:
       - name: Checkout
         uses: actions/checkout@v4
-
       - name: Setup pnpm
         uses: pnpm/action-setup@v2
         with:
           version: 8
-
-      - name: Setup Node.js ${{ matrix.node }}
+      - name: Setup Node.js
         uses: actions/setup-node@v3
         with:
-          node-version: ${{ matrix.node }}
+          node-version: '18.x'
           cache: 'pnpm'
-
-      - name: Install
+      - name: Install dependencies
         run: pnpm install --ignore-scripts
-
-      - name: Production Benchmark
-        run: pnpm benchmark:prod
+      - name: Run production benchmark
+        run: pnpm benchmark:prod | tee ./benchmarks/internal/output.txt
+      - name: Store production benchmark result
+        uses: benchmark-action/github-action-benchmark@v1
+        with:
+          name: Internal benchmark
+          tool: 'benchmarkjs'
+          output-file-path: ./benchmarks/internal/output.txt
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          auto-push: true
+          alert-threshold: '200%'
+          comment-on-alert: true
+          fail-on-alert: true
+          gh-repository: 'github.com/poolifier/benchmark-results'
index 5b240db0c190eeab896cef6273c3066303f00677..3419c5719e142d55a15ef939083623bd3cc4fa26 100644 (file)
@@ -40,7 +40,7 @@ jobs:
           node-version: ${{ matrix.node }}
           cache: 'pnpm'
 
-      - name: Install
+      - name: Install Dependencies
         run: pnpm install --ignore-scripts
 
       - name: Build
similarity index 96%
rename from .github/workflows/npmpublish.yml
rename to .github/workflows/publish-package.yml
index 751e936b712f42685968f3a7a0776fe6e95c231c..ef3fc5fe24cd533810431f0da32be922f0934447 100644 (file)
@@ -1,4 +1,4 @@
-name: Node.js Package
+name: Publish package
 
 on:
   release:
@@ -23,7 +23,7 @@ jobs:
           node-version: '18.x'
           cache: 'pnpm'
 
-      - name: Install
+      - name: Install Dependencies
         run: pnpm install --ignore-scripts
 
       - name: Tests & Coverage
@@ -57,7 +57,7 @@ jobs:
           registry-url: https://registry.npmjs.org/
           cache: 'pnpm'
 
-      - name: Install
+      - name: Install Dependencies
         run: pnpm install --ignore-scripts
 
       - name: Read package.json version
@@ -105,7 +105,7 @@ jobs:
   #         registry-url: https://npm.pkg.github.com
   #         cache: 'pnpm'
 
-  #     - name: Install
+  #     - name: Install Dependencies
   #       run: pnpm install --ignore-scripts
 
   #     - name: Read package.json version
index 404473ff6a0747e4ff8bd0926bea42b74cbe02e6..5e16da97408b119188687c09d5dd811b45d30b7d 100644 (file)
@@ -79,4 +79,3 @@ lib
 dist
 tmp
 reports/
-benchmarks/internal/results/
index 59182946c007e53897c133f64953d0ecbe544aab..7b5e9bfacf7fbcc3bc3c728bc47d29a0daef3147 100644 (file)
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 - Disable publication on GitHub packages registry on release until authentication issue is fixed.
 
+### Added
+
+- Continuous internal benchmarking.
+
 ## [2.6.44] - 2023-09-08
 
 ### Fixed
index 0aeca085d9115959c46ee719f0d1c20740057def..98893f62ddde73b6b0b10feb86b84e79ad8e4683 100644 (file)
@@ -78,6 +78,11 @@ export const runPoolifierTest = async (
   })
 }
 
+export const LIST_FORMATTER = new Intl.ListFormat('en-US', {
+  style: 'long',
+  type: 'conjunction'
+})
+
 export const executeAsyncFn = async fn => {
   try {
     await fn()
index a14ecd5f12086acf98e64cc2c877c68b0bbbf91f..23ab0625807e349b89f6fabd55be766e45f9fff5 100644 (file)
@@ -1,4 +1,4 @@
-import { add, complete, cycle, save, suite } from 'benny'
+import Benchmark from 'benchmark'
 import {
   Measurements,
   PoolTypes,
@@ -7,7 +7,11 @@ import {
   availableParallelism
 } from '../../lib/index.mjs'
 import { TaskFunctions } from '../benchmarks-types.mjs'
-import { buildPoolifierPool, runPoolifierTest } from '../benchmarks-utils.mjs'
+import {
+  LIST_FORMATTER,
+  buildPoolifierPool,
+  runPoolifierTest
+} from '../benchmarks-utils.mjs'
 
 const poolSize = availableParallelism()
 const pools = []
@@ -17,7 +21,7 @@ for (const poolType of Object.values(PoolTypes)) {
       continue
     }
     for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
-      for (const enableTasksQueue of [false, true]) {
+      for (const enableTasksQueue of [false]) {
         if (workerChoiceStrategy === WorkerChoiceStrategies.FAIR_SHARE) {
           for (const measurement of [Measurements.runTime, Measurements.elu]) {
             pools.push([
@@ -48,46 +52,28 @@ for (const poolType of Object.values(PoolTypes)) {
 const taskExecutions = 1
 const workerData = {
   function: TaskFunctions.jsonIntegerSerialization,
-  taskSize: 1000
+  taskSize: 100
 }
-const addPools = pools =>
-  pools.map(([name, pool]) => {
-    return add(name, async () => {
-      await runPoolifierTest(pool, {
-        taskExecutions,
-        workerData
-      })
+
+const suite = new Benchmark.Suite('Poolifier')
+for (const [name, pool] of pools) {
+  suite.add(name, async () => {
+    await runPoolifierTest(pool, {
+      taskExecutions,
+      workerData
     })
   })
+}
 
-const resultsFile = 'poolifier'
-const resultsFolder = 'benchmarks/internal/results'
-suite(
-  'Poolifier',
-  ...addPools(pools),
-  cycle(),
-  complete(),
-  save({
-    file: resultsFile,
-    folder: resultsFolder,
-    format: 'json',
-    details: true
-  }),
-  save({
-    file: resultsFile,
-    folder: resultsFolder,
-    format: 'chart.html',
-    details: true
-  }),
-  save({
-    file: resultsFile,
-    folder: resultsFolder,
-    format: 'table.html',
-    details: true
+suite
+  .on('cycle', event => {
+    console.info(event.target.toString())
   })
-)
-  .then(() => {
+  .on('complete', function () {
+    console.info(
+      'Fastest is ' + LIST_FORMATTER.format(this.filter('fastest').map('name'))
+    )
     // eslint-disable-next-line n/no-process-exit
-    return process.exit()
+    process.exit()
   })
-  .catch(err => console.error(err))
+  .run({ async: true, maxTime: 120 })
index 69a7ad15cae0ada671f3e4f8ef1261305d26e51a..1d64fde30a19d82f0e4f52cb1781a7eab9efeae6 100644 (file)
@@ -3,13 +3,12 @@ import { ClusterWorker } from '../../lib/index.mjs'
 import { executeTaskFunction } from '../benchmarks-utils.mjs'
 import { TaskFunctions } from '../benchmarks-types.mjs'
 
-const debug = false
-
 const taskFunction = data => {
   data = data || {}
   data.function = data.function || TaskFunctions.jsonIntegerSerialization
+  data.debug = data.debug || false
   const res = executeTaskFunction(data)
-  debug === true && console.debug(`This is the main thread ${isPrimary}`)
+  data.debug === true && console.debug(`This is the main thread ${isPrimary}`)
   return res
 }
 
index 7af5fa638aed36a25bba7c384d95c8b604eac5ba..5c6a691e47af247dde38a075a3cd4c78cc15d02c 100644 (file)
@@ -3,13 +3,13 @@ import { ThreadWorker } from '../../lib/index.mjs'
 import { executeTaskFunction } from '../benchmarks-utils.mjs'
 import { TaskFunctions } from '../benchmarks-types.mjs'
 
-const debug = false
-
 const taskFunction = data => {
   data = data || {}
   data.function = data.function || TaskFunctions.jsonIntegerSerialization
+  data.debug = data.debug || false
   const res = executeTaskFunction(data)
-  debug === true && console.debug(`This is the main thread ${isMainThread}`)
+  data.debug === true &&
+    console.debug(`This is the main thread ${isMainThread}`)
   return res
 }
 
similarity index 85%
rename from benchmarks/worker-selection/less.mjs
rename to benchmarks/worker-selection/least.mjs
index e839107d0978cacb32f6d55521bcc4455e5615f0..b8766322d0240156ff2d339b378fb5f5e564db75 100644 (file)
@@ -1,5 +1,5 @@
-import Benchmark from 'benny'
-import { generateRandomInteger } from '../benchmarks-utils.mjs'
+import Benchmark from 'benchmark'
+import { LIST_FORMATTER, generateRandomInteger } from '../benchmarks-utils.mjs'
 
 function generateRandomTasksMap (
   numberOfWorkers,
@@ -167,26 +167,31 @@ function quickSelectRecursionRandomPivot (tasksMap) {
   )
 }
 
-Benchmark.suite(
-  'Least used worker tasks distribution',
-  Benchmark.add('Loop select', () => {
+new Benchmark.Suite('Least used worker tasks distribution')
+  .add('Loop select', () => {
     loopSelect(tasksMap)
-  }),
-  Benchmark.add('Array sort select', () => {
+  })
+  .add('Array sort select', () => {
     arraySortSelect(tasksMap)
-  }),
-  Benchmark.add('Quick select loop', () => {
+  })
+  .add('Quick select loop', () => {
     quickSelectLoop(tasksMap)
-  }),
-  Benchmark.add('Quick select loop with random pivot', () => {
+  })
+  .add('Quick select loop with random pivot', () => {
     quickSelectLoopRandomPivot(tasksMap)
-  }),
-  Benchmark.add('Quick select recursion', () => {
+  })
+  .add('Quick select recursion', () => {
     quickSelectRecursion(tasksMap)
-  }),
-  Benchmark.add('Quick select recursion with random pivot', () => {
+  })
+  .add('Quick select recursion with random pivot', () => {
     quickSelectRecursionRandomPivot(tasksMap)
-  }),
-  Benchmark.cycle(),
-  Benchmark.complete()
-)
+  })
+  .on('cycle', event => {
+    console.info(event.target.toString())
+  })
+  .on('complete', function () {
+    console.info(
+      'Fastest is ' + LIST_FORMATTER.format(this.filter('fastest').map('name'))
+    )
+  })
+  .run()
index b724a04ad5f6acc009bb86b0fd7e32318757a07b..483098d2ff93d0a4c0bb9b225b11ccbe963e6bd2 100644 (file)
@@ -1,4 +1,5 @@
-import Benchmark from 'benny'
+import Benchmark from 'benchmark'
+import { LIST_FORMATTER } from '../benchmarks-utils.mjs'
 
 function generateWorkersArray (numberOfWorkers) {
   return [...Array(numberOfWorkers).keys()]
@@ -36,24 +37,29 @@ function roundRobinIncrementModulo () {
   return chosenWorker
 }
 
-Benchmark.suite(
-  'Round robin tasks distribution',
-  Benchmark.add('Ternary off by one', () => {
+new Benchmark.Suite('Round robin tasks distribution')
+  .add('Ternary off by one', () => {
     nextWorkerIndex = 0
     roundRobinTernaryOffByOne()
-  }),
-  Benchmark.add('Ternary with negation', () => {
+  })
+  .add('Ternary with negation', () => {
     nextWorkerIndex = 0
     roundRobinTernaryWithNegation()
-  }),
-  Benchmark.add('Ternary with pre-choosing', () => {
+  })
+  .add('Ternary with pre-choosing', () => {
     nextWorkerIndex = 0
     roundRobinTernaryWithPreChoosing()
-  }),
-  Benchmark.add('Increment+Modulo', () => {
+  })
+  .add('Increment+Modulo', () => {
     nextWorkerIndex = 0
     roundRobinIncrementModulo()
-  }),
-  Benchmark.cycle(),
-  Benchmark.complete()
-)
+  })
+  .on('cycle', event => {
+    console.info(event.target.toString())
+  })
+  .on('complete', function () {
+    console.info(
+      'Fastest is ' + LIST_FORMATTER.format(this.filter('fastest').map('name'))
+    )
+  })
+  .run()
index 56ea361876eae835515897e0d56bad903351aa95..aac8a42cc1de57105e02edab8c160a66611abec7 100644 (file)
@@ -1,5 +1,5 @@
 {
-  "$schema": "https://biomejs.dev/schemas/1.2.1/schema.json",
+  "$schema": "https://biomejs.dev/schemas/1.2.2/schema.json",
   "organizeImports": {
     "enabled": false
   },
index e2af88855781ec71f30cff3fb48660b7b2b9c6c7..17862e2fde09b03db4514cbe579498bf308318a3 100644 (file)
     }
   },
   "devDependencies": {
-    "@biomejs/biome": "^1.2.1",
+    "@biomejs/biome": "^1.2.2",
     "@commitlint/cli": "^17.7.1",
     "@commitlint/config-conventional": "^17.7.0",
     "@release-it/bumper": "^5.1.0",
     "@release-it/keep-a-changelog": "^4.0.0",
     "@rollup/plugin-terser": "^0.4.3",
     "@rollup/plugin-typescript": "^11.1.3",
-    "@types/node": "^20.6.1",
+    "@types/node": "^20.6.2",
     "@typescript-eslint/eslint-plugin": "^6.7.0",
     "@typescript-eslint/parser": "^6.7.0",
-    "benny": "^3.7.1",
+    "benchmark": "^2.1.4",
     "c8": "^8.0.1",
     "eslint": "^8.49.0",
     "eslint-config-standard": "^17.1.0",
index 42f225510351d01458315560776110661aa1460f..bbe01e10f8bc2f634f6553953f7d462077773d34 100644 (file)
@@ -9,8 +9,8 @@ overrides:
 
 devDependencies:
   '@biomejs/biome':
-    specifier: ^1.2.1
-    version: 1.2.1
+    specifier: ^1.2.2
+    version: 1.2.2
   '@commitlint/cli':
     specifier: ^17.7.1
     version: 17.7.1
@@ -30,17 +30,17 @@ devDependencies:
     specifier: ^11.1.3
     version: 11.1.3(rollup@3.29.2)(typescript@5.2.2)
   '@types/node':
-    specifier: ^20.6.1
-    version: 20.6.1
+    specifier: ^20.6.2
+    version: 20.6.2
   '@typescript-eslint/eslint-plugin':
     specifier: ^6.7.0
     version: 6.7.0(@typescript-eslint/parser@6.7.0)(eslint@8.49.0)(typescript@5.2.2)
   '@typescript-eslint/parser':
     specifier: ^6.7.0
     version: 6.7.0(eslint@8.49.0)(typescript@5.2.2)
-  benny:
-    specifier: ^3.7.1
-    version: 3.7.1
+  benchmark:
+    specifier: ^2.1.4
+    version: 2.1.4
   c8:
     specifier: ^8.0.1
     version: 8.0.1
@@ -139,35 +139,6 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
-  /@arrows/array@1.4.1:
-    resolution: {integrity: sha512-MGYS8xi3c4tTy1ivhrVntFvufoNzje0PchjEz6G/SsWRgUKxL4tKwS6iPdO8vsaJYldagAeWMd5KRD0aX3Q39g==}
-    dependencies:
-      '@arrows/composition': 1.2.2
-    dev: true
-
-  /@arrows/composition@1.2.2:
-    resolution: {integrity: sha512-9fh1yHwrx32lundiB3SlZ/VwuStPB4QakPsSLrGJFH6rCXvdrd060ivAZ7/2vlqPnEjBkPRRXOcG1YOu19p2GQ==}
-    dev: true
-
-  /@arrows/dispatch@1.0.3:
-    resolution: {integrity: sha512-v/HwvrFonitYZM2PmBlAlCqVqxrkIIoiEuy5bQgn0BdfvlL0ooSBzcPzTMrtzY8eYktPyYcHg8fLbSgyybXEqw==}
-    dependencies:
-      '@arrows/composition': 1.2.2
-    dev: true
-
-  /@arrows/error@1.0.2:
-    resolution: {integrity: sha512-yvkiv1ay4Z3+Z6oQsUkedsQm5aFdyPpkBUQs8vejazU/RmANABx6bMMcBPPHI4aW43VPQmXFfBzr/4FExwWTEA==}
-    dev: true
-
-  /@arrows/multimethod@1.4.1:
-    resolution: {integrity: sha512-AZnAay0dgPnCJxn3We5uKiB88VL+1ZIF2SjZohLj6vqY2UyvB/sKdDnFP+LZNVsTC5lcnGPmLlRRkAh4sXkXsQ==}
-    dependencies:
-      '@arrows/array': 1.4.1
-      '@arrows/composition': 1.2.2
-      '@arrows/error': 1.0.2
-      fast-deep-equal: 3.1.3
-    dev: true
-
   /@babel/code-frame@7.22.13:
     resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==}
     engines: {node: '>=6.9.0'}
@@ -196,22 +167,22 @@ packages:
     resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
     dev: true
 
-  /@biomejs/biome@1.2.1:
-    resolution: {integrity: sha512-olT0ldjncEQx+mtVLJ1LwJikrDtMYZakJ8dIMYXEoX9t10xjKpeY4OyKBa9Os8/EUHah9YmpYL64hQooza3WrA==}
+  /@biomejs/biome@1.2.2:
+    resolution: {integrity: sha512-fXwXi56ZdaKO/N3rTmhWw41UxstoviODk+wia4WWNSlm23r8xJ/NxjaZ88scV2IsmsFHqc8rmwb2dkrStAdIEw==}
     engines: {node: '>=14.*'}
     hasBin: true
     requiresBuild: true
     optionalDependencies:
-      '@biomejs/cli-darwin-arm64': 1.2.1
-      '@biomejs/cli-darwin-x64': 1.2.1
-      '@biomejs/cli-linux-arm64': 1.2.1
-      '@biomejs/cli-linux-x64': 1.2.1
-      '@biomejs/cli-win32-arm64': 1.2.1
-      '@biomejs/cli-win32-x64': 1.2.1
+      '@biomejs/cli-darwin-arm64': 1.2.2
+      '@biomejs/cli-darwin-x64': 1.2.2
+      '@biomejs/cli-linux-arm64': 1.2.2
+      '@biomejs/cli-linux-x64': 1.2.2
+      '@biomejs/cli-win32-arm64': 1.2.2
+      '@biomejs/cli-win32-x64': 1.2.2
     dev: true
 
-  /@biomejs/cli-darwin-arm64@1.2.1:
-    resolution: {integrity: sha512-lz/Hn/isGnnZqILhnPiwO3Hy4mhGr1APrjXkCBolONyYG67x1OT3l8T5yaNW62GsIEeblabWkwLl/MkoPJJXZQ==}
+  /@biomejs/cli-darwin-arm64@1.2.2:
+    resolution: {integrity: sha512-Fx1IURKhoqH6wPawtKLT6wcfMSjRRcNK8+VWau0iDOjXvNtjJpSmICbU89B7Vt/gZRwPqkfDMBkFwm6V5vFTSQ==}
     engines: {node: '>=14.*'}
     cpu: [arm64]
     os: [darwin]
@@ -219,8 +190,8 @@ packages:
     dev: true
     optional: true
 
-  /@biomejs/cli-darwin-x64@1.2.1:
-    resolution: {integrity: sha512-mWJE2+sPiHJk0kHkuHby9ssTm2WR/R7USwJbbNmy7PM07DZdcciF2XbyLofO2ZGh0QI0LEW59OcjMwYChQnZbA==}
+  /@biomejs/cli-darwin-x64@1.2.2:
+    resolution: {integrity: sha512-JNaAFOI/ZisnmzvcFNd73geJxaFaN2L4YsWM6cgBeKyLY/ycl9C/PBTFfEmeB1c7f5XIIal8P2cj47kLJpN5Ig==}
     engines: {node: '>=14.*'}
     cpu: [x64]
     os: [darwin]
@@ -228,8 +199,8 @@ packages:
     dev: true
     optional: true
 
-  /@biomejs/cli-linux-arm64@1.2.1:
-    resolution: {integrity: sha512-M81if0mY66Feq3nsOoNRa+o57k6YecCeH4EX2EqkU/ObqYfVLmWnIvFsgqEZE/e/bguNmqBoAIJaIV26PvyyJg==}
+  /@biomejs/cli-linux-arm64@1.2.2:
+    resolution: {integrity: sha512-JHXRnfhOLx8UO/Fcyn2c5pFRri0XKqRZm2wf5oH5GSfLVpckDw2X15dYGbu3nmfM/3pcAaTV46pUpjrCnaAieg==}
     engines: {node: '>=14.*'}
     cpu: [arm64]
     os: [linux]
@@ -237,8 +208,8 @@ packages:
     dev: true
     optional: true
 
-  /@biomejs/cli-linux-x64@1.2.1:
-    resolution: {integrity: sha512-gzTpmpvBmSFu6oeUeFKP8C34WpV91rha4gS+3swAuw5G+C4PosOTpAVPKnElbgl9iS0+stfP73tXARQUXySDPA==}
+  /@biomejs/cli-linux-x64@1.2.2:
+    resolution: {integrity: sha512-5Zr+iM7lUKsw81p9PkXRESuH2/AhRZ6RCWkgE+FSLcxMhXy/4RDR+o2YQDsJM6cWKIzOJM05vDHTGrDq7vXE4A==}
     engines: {node: '>=14.*'}
     cpu: [x64]
     os: [linux]
@@ -246,8 +217,8 @@ packages:
     dev: true
     optional: true
 
-  /@biomejs/cli-win32-arm64@1.2.1:
-    resolution: {integrity: sha512-SveEeHYjiXzRZhTE3HyURQ+CyZ3yLeKHUrggH4bSDQ1+b7rgDEF/XIEgMl+/3SWFlc+HdEpgbJWWZQCfSCqxww==}
+  /@biomejs/cli-win32-arm64@1.2.2:
+    resolution: {integrity: sha512-HvUcG2p++RvYP0zfOqh+DgiUUH+JI/uETr0kzWlOJ9F3lsG525pkywg4RSd4OvJd7Wpd3wt3UpN/A4IEJaVmbA==}
     engines: {node: '>=14.*'}
     cpu: [arm64]
     os: [win32]
@@ -255,8 +226,8 @@ packages:
     dev: true
     optional: true
 
-  /@biomejs/cli-win32-x64@1.2.1:
-    resolution: {integrity: sha512-ooEjE+A6kbQhf0cPNvC8bXje1jk2uKWgJ8S3DgHZRBvr6DlBiUsU8C1ycURdhDiHZ5d6nOI98LFrj3WWR1ODzA==}
+  /@biomejs/cli-win32-x64@1.2.2:
+    resolution: {integrity: sha512-bfaFJwqJ9ApFga2o88OaROSd3pasYRzRGXHJWAE9VUUKdSNSTYxHOqVrNvV54yYPtL6Kt9xkuZa4HNu9it3TaA==}
     engines: {node: '>=14.*'}
     cpu: [x64]
     os: [win32]
@@ -358,7 +329,7 @@ packages:
       lodash.merge: 4.6.2
       lodash.uniq: 4.5.0
       resolve-from: 5.0.0
-      ts-node: 10.9.1(@types/node@20.6.1)(typescript@5.2.2)
+      ts-node: 10.9.1(@types/node@20.6.2)(typescript@5.2.2)
       typescript: 5.2.2
     transitivePeerDependencies:
       - '@swc/core'
@@ -535,7 +506,7 @@ packages:
       '@jest/schemas': 29.6.3
       '@types/istanbul-lib-coverage': 2.0.4
       '@types/istanbul-reports': 3.0.1
-      '@types/node': 20.6.1
+      '@types/node': 20.6.2
       '@types/yargs': 17.0.24
       chalk: 4.1.2
     dev: true
@@ -824,7 +795,7 @@ packages:
         optional: true
     dependencies:
       '@rollup/pluginutils': 5.0.4(rollup@3.29.2)
-      resolve: 1.22.5
+      resolve: 1.22.6
       rollup: 3.29.2
       typescript: 5.2.2
     dev: true
@@ -918,11 +889,11 @@ packages:
     resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
     dependencies:
       '@types/minimatch': 5.1.2
-      '@types/node': 20.6.1
+      '@types/node': 20.6.2
     dev: true
 
-  /@types/http-cache-semantics@4.0.1:
-    resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==}
+  /@types/http-cache-semantics@4.0.2:
+    resolution: {integrity: sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw==}
     dev: true
 
   /@types/istanbul-lib-coverage@2.0.4:
@@ -941,8 +912,8 @@ packages:
       '@types/istanbul-lib-report': 3.0.0
     dev: true
 
-  /@types/json-schema@7.0.12:
-    resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==}
+  /@types/json-schema@7.0.13:
+    resolution: {integrity: sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==}
     dev: true
 
   /@types/json5@0.0.29:
@@ -961,8 +932,8 @@ packages:
     resolution: {integrity: sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g==}
     dev: true
 
-  /@types/node@20.6.1:
-    resolution: {integrity: sha512-4LcJvuXQlv4lTHnxwyHQZ3uR9Zw2j7m1C9DfuwoTFQQP4Pmu04O6IfLYgMmHoOCt0nosItLLZAH+sOrRE0Bo8g==}
+  /@types/node@20.6.2:
+    resolution: {integrity: sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==}
     dev: true
 
   /@types/normalize-package-data@2.4.1:
@@ -1200,7 +1171,7 @@ packages:
       eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@8.49.0)
-      '@types/json-schema': 7.0.12
+      '@types/json-schema': 7.0.13
       '@types/semver': 7.5.2
       '@typescript-eslint/scope-manager': 5.62.0
       '@typescript-eslint/types': 5.62.0
@@ -1220,7 +1191,7 @@ packages:
       eslint: ^7.0.0 || ^8.0.0
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@8.49.0)
-      '@types/json-schema': 7.0.12
+      '@types/json-schema': 7.0.13
       '@types/semver': 7.5.2
       '@typescript-eslint/scope-manager': 6.7.0
       '@typescript-eslint/types': 6.7.0
@@ -1499,11 +1470,6 @@ packages:
       tslib: 2.6.2
     dev: true
 
-  /astral-regex@2.0.0:
-    resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
-    engines: {node: '>=8'}
-    dev: true
-
   /async-retry@1.3.3:
     resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==}
     dependencies:
@@ -1545,21 +1511,6 @@ packages:
       platform: 1.3.6
     dev: true
 
-  /benny@3.7.1:
-    resolution: {integrity: sha512-USzYxODdVfOS7JuQq/L0naxB788dWCiUgUTxvN+WLPt/JfcDURNNj8kN/N+uK6PDvuR67/9/55cVKGPleFQINA==}
-    engines: {node: '>=12'}
-    dependencies:
-      '@arrows/composition': 1.2.2
-      '@arrows/dispatch': 1.0.3
-      '@arrows/multimethod': 1.4.1
-      benchmark: 2.1.4
-      common-tags: 1.8.2
-      fs-extra: 10.1.0
-      json2csv: 5.0.7
-      kleur: 4.1.5
-      log-update: 4.0.0
-    dev: true
-
   /big-integer@1.6.51:
     resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==}
     engines: {node: '>=0.6'}
@@ -1695,7 +1646,7 @@ packages:
     resolution: {integrity: sha512-3SD4rrMu1msNGEtNSt8Od6enwdo//U9s4ykmXfA2TD58kcLkCobtCDiby7kNyj7a/Q7lz/mAesAFI54rTdnvBA==}
     engines: {node: '>=14.16'}
     dependencies:
-      '@types/http-cache-semantics': 4.0.1
+      '@types/http-cache-semantics': 4.0.2
       get-stream: 6.0.1
       http-cache-semantics: 4.1.1
       keyv: 4.5.3
@@ -1887,21 +1838,11 @@ packages:
     resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
     dev: true
 
-  /commander@6.2.1:
-    resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==}
-    engines: {node: '>= 6'}
-    dev: true
-
   /comment-parser@1.4.0:
     resolution: {integrity: sha512-QLyTNiZ2KDOibvFPlZ6ZngVsZ/0gYnE6uTXi5aoDg8ed3AkJAz4sEje3Y8a29hQ1s6A99MZXe47fLAXQ1rTqaw==}
     engines: {node: '>= 12.0.0'}
     dev: true
 
-  /common-tags@1.8.2:
-    resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==}
-    engines: {node: '>=4.0.0'}
-    dev: true
-
   /compare-func@2.0.0:
     resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==}
     dependencies:
@@ -1971,7 +1912,7 @@ packages:
     dependencies:
       '@types/node': 20.4.7
       cosmiconfig: 8.3.6(typescript@5.2.2)
-      ts-node: 10.9.1(@types/node@20.6.1)(typescript@5.2.2)
+      ts-node: 10.9.1(@types/node@20.6.2)(typescript@5.2.2)
       typescript: 5.2.2
     dev: true
 
@@ -2518,7 +2459,7 @@ packages:
     dependencies:
       debug: 3.2.7
       is-core-module: 2.13.0
-      resolve: 1.22.5
+      resolve: 1.22.6
     transitivePeerDependencies:
       - supports-color
     dev: true
@@ -2731,7 +2672,7 @@ packages:
       ignore: 5.2.4
       is-core-module: 2.13.0
       minimatch: 3.1.2
-      resolve: 1.22.5
+      resolve: 1.22.6
       semver: 7.5.4
     dev: true
 
@@ -2749,7 +2690,7 @@ packages:
       ignore: 5.2.4
       is-core-module: 2.13.0
       minimatch: 3.1.2
-      resolve: 1.22.5
+      resolve: 1.22.6
       semver: 7.5.4
     dev: true
 
@@ -3095,7 +3036,7 @@ packages:
     resolution: {integrity: sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==}
     engines: {node: '>=12.0.0'}
     dependencies:
-      flatted: 3.2.7
+      flatted: 3.2.8
       keyv: 4.5.3
       rimraf: 3.0.2
     dev: true
@@ -3105,8 +3046,8 @@ packages:
     hasBin: true
     dev: true
 
-  /flatted@3.2.7:
-    resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
+  /flatted@3.2.8:
+    resolution: {integrity: sha512-6qu0W+A94UKNJRs3ffE8s/fWSHQbjqdNx8elGAe95IqnJA77P68TFz4+2cwC28ouAibiZdGBeV6DsvvMg+4vhQ==}
     dev: true
 
   /for-each@0.3.3:
@@ -4084,7 +4025,7 @@ packages:
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
     dependencies:
       '@jest/types': 29.6.3
-      '@types/node': 20.6.1
+      '@types/node': 20.6.2
       chalk: 4.1.2
       ci-info: 3.8.0
       graceful-fs: 4.2.11
@@ -4139,17 +4080,6 @@ packages:
     resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
     dev: true
 
-  /json2csv@5.0.7:
-    resolution: {integrity: sha512-YRZbUnyaJZLZUJSRi2G/MqahCyRv9n/ds+4oIetjDF3jWQA7AG7iSeKTiZiCNqtMZM7HDyt0e/W6lEnoGEmMGA==}
-    engines: {node: '>= 10', npm: '>= 6.13.0'}
-    deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
-    hasBin: true
-    dependencies:
-      commander: 6.2.1
-      jsonparse: 1.3.1
-      lodash.get: 4.4.2
-    dev: true
-
   /json5@1.0.2:
     resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
     hasBin: true
@@ -4205,11 +4135,6 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
-  /kleur@4.1.5:
-    resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
-    engines: {node: '>=6'}
-    dev: true
-
   /latest-version@7.0.0:
     resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==}
     engines: {node: '>=14.16'}
@@ -4408,16 +4333,6 @@ packages:
       is-unicode-supported: 1.3.0
     dev: true
 
-  /log-update@4.0.0:
-    resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==}
-    engines: {node: '>=10'}
-    dependencies:
-      ansi-escapes: 4.3.2
-      cli-cursor: 3.1.0
-      slice-ansi: 4.0.0
-      wrap-ansi: 6.2.0
-    dev: true
-
   /log-update@5.0.1:
     resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==}
     engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -4761,7 +4676,7 @@ packages:
     resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
     dependencies:
       hosted-git-info: 2.8.9
-      resolve: 1.22.5
+      resolve: 1.22.6
       semver: 7.5.4
       validate-npm-package-license: 3.0.4
     dev: true
@@ -5333,7 +5248,7 @@ packages:
     resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==}
     engines: {node: '>= 0.10'}
     dependencies:
-      resolve: 1.22.5
+      resolve: 1.22.6
     dev: true
 
   /redent@3.0.0:
@@ -5463,8 +5378,8 @@ packages:
       path-parse: 1.0.7
     dev: true
 
-  /resolve@1.22.5:
-    resolution: {integrity: sha512-qWhv7PF1V95QPvRoUGHxOtnAlEvlXBylMZcjUR9pAumMmveFtcHJRXGIr+TkjfNJVQypqv2qcDiiars2y1PsSg==}
+  /resolve@1.22.6:
+    resolution: {integrity: sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==}
     hasBin: true
     dependencies:
       is-core-module: 2.13.0
@@ -5713,15 +5628,6 @@ packages:
     engines: {node: '>=12'}
     dev: true
 
-  /slice-ansi@4.0.0:
-    resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
-    engines: {node: '>=10'}
-    dependencies:
-      ansi-styles: 4.3.0
-      astral-regex: 2.0.0
-      is-fullwidth-code-point: 3.0.0
-    dev: true
-
   /slice-ansi@5.0.0:
     resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
     engines: {node: '>=12'}
@@ -6074,7 +5980,7 @@ packages:
       typescript: 5.2.2
     dev: true
 
-  /ts-node@10.9.1(@types/node@20.6.1)(typescript@5.2.2):
+  /ts-node@10.9.1(@types/node@20.6.2)(typescript@5.2.2):
     resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
     hasBin: true
     peerDependencies:
@@ -6093,7 +5999,7 @@ packages:
       '@tsconfig/node12': 1.0.11
       '@tsconfig/node14': 1.0.3
       '@tsconfig/node16': 1.0.4
-      '@types/node': 20.6.1
+      '@types/node': 20.6.2
       acorn: 8.10.0
       acorn-walk: 8.2.0
       arg: 4.1.3