From 5b777eb323ad0924139e854be1f22f5493e4ba4f Mon Sep 17 00:00:00 2001 From: mspiess <30656914+mspiess@users.noreply.github.com> Date: Sun, 2 Aug 2026 19:27:25 +0200 Subject: [PATCH 1/2] chore(deps): update vitest to v5 --- package-lock.json | 182 ++++++++++++++++++---------------------------- package.json | 11 ++- 2 files changed, 80 insertions(+), 113 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4bcfb52..13d4b19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@marco.spiess/enumset", - "version": "0.0.2", + "version": "0.0.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@marco.spiess/enumset", - "version": "0.0.2", + "version": "0.0.4", "license": "MIT", "devDependencies": { "@changesets/changelog-github": "^0.7.0", @@ -16,8 +16,8 @@ "@microsoft/api-extractor": "^7.58.11", "@stylistic/eslint-plugin": "^5.10.0", "@types/node": "^26.1.1", - "@vitest/coverage-v8": "^4.1.10", - "@vitest/eslint-plugin": "^1.6.23", + "@vitest/coverage-v8": "^5.0.0-beta.7", + "@vitest/eslint-plugin": "^1.6.25", "eslint": "^10.7.0", "globals": "^17.7.0", "typescript": "~5.9.3", @@ -25,7 +25,7 @@ "unplugin-dts": "^1.0.3", "vite": "^8.1.5", "vite-plugin-doctest": "^3.0.0", - "vitest": "^4.1.10" + "vitest": "^5.0.0-beta.7" } }, "node_modules/@babel/helper-string-parser": { @@ -1469,13 +1469,6 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" - }, "node_modules/@stylistic/eslint-plugin": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.10.0.tgz", @@ -1859,15 +1852,15 @@ } }, "node_modules/@vitest/coverage-v8": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.10.tgz", - "integrity": "sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==", + "version": "5.0.0-beta.7", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-5.0.0-beta.7.tgz", + "integrity": "sha512-1EiXmCq9KiqB8xAueEZ/hbnVnAl6TuMQyYlQwU4trb+QoGoxAOKQeVWKtho59t4mk2ziEtnJphy/cVFGgkuzTA==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.1.10", - "ast-v8-to-istanbul": "^1.0.0", + "@vitest/utils": "5.0.0-beta.7", + "ast-v8-to-istanbul": "^1.0.5", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.2.0", @@ -1880,8 +1873,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.1.10", - "vitest": "4.1.10" + "@vitest/browser": "5.0.0-beta.7", + "vitest": "5.0.0-beta.7" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -1890,9 +1883,9 @@ } }, "node_modules/@vitest/eslint-plugin": { - "version": "1.6.24", - "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.6.24.tgz", - "integrity": "sha512-U5isuChJ58H1M6oRGaIotYbH2gM1rhzKUjtiarqpLNG/3+fzXIXs5RyTLrYQJmQPnXbvIMPFvI9z8ufpFZc8lg==", + "version": "1.6.25", + "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.6.25.tgz", + "integrity": "sha512-ylqFL2TYRgtTewl5Kr2NCL3fnLOMNo91XEyniB4tA1zlnZs0GbrNj6ER6ldR9J3r5RSL0dQ7EeMUiXsbfHrvpg==", "dev": true, "license": "MIT", "dependencies": { @@ -1920,34 +1913,17 @@ } } }, - "node_modules/@vitest/expect": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", - "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, "node_modules/@vitest/mocker": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", - "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "version": "5.0.0-beta.7", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-5.0.0-beta.7.tgz", + "integrity": "sha512-SczTGMNh6ksM5r8ogUwAf8zVbQPgbc6yvdZO9xBsTKT2rLUwpHn95Upod0s0Cpm3/bH898iqRBLXovRZSUbJBg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.10", + "@jridgewell/trace-mapping": "0.3.31", + "@vitest/spy": "5.0.0-beta.7", "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" + "magic-string": "^1.0.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -1965,53 +1941,33 @@ } } }, - "node_modules/@vitest/pretty-format": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", - "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", - "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "node_modules/@vitest/mocker/node_modules/magic-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.1.0.tgz", + "integrity": "sha512-kS3VHe0nEPST2saQV4Rbkchcd3UBRkVTQHo1D3h/ZTwFDhai/mfKkmtPAtD129EOI7K3HlHIsFOt0WrI2/oU9g==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.10", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/@vitest/snapshot": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", - "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "node_modules/@vitest/pretty-format": { + "version": "5.0.0-beta.7", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-5.0.0-beta.7.tgz", + "integrity": "sha512-mYUiYNj9BcF4BawuqncdUlR+zNNbWOWBNsp57jJon2Gq5R2fMqTYQJWHpfvkNqkAAgt/lC6bH5+JISjLIhHa4w==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.10", - "@vitest/utils": "4.1.10", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/spy": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", - "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "version": "5.0.0-beta.7", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-5.0.0-beta.7.tgz", + "integrity": "sha512-NiE4frPDnDjFaMvaZaj4ASyxc/c2fvSQU8Fpo7D0YNj9AetE4hcA7ewRxhlrg6dHEOt1JhhCgy67e8SCXDh5VQ==", "dev": true, "license": "MIT", "funding": { @@ -2019,13 +1975,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", - "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "version": "5.0.0-beta.7", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-5.0.0-beta.7.tgz", + "integrity": "sha512-DFjgVac0frIqGUZnQCd8lTGYfWnPJfzUNhOubZuvUMgzb+v0mdJjeMEcpmesujZIPasFOR+SzsQ4dS/BCEWGvg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.10", + "@vitest/pretty-format": "5.0.0-beta.7", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -5422,11 +5378,14 @@ } }, "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-6.1.2.tgz", + "integrity": "sha512-REdMxUreK3VSUeWcLd5+ijUGNKFyHT8s1trKmYEE/tlYE6ggdOkFOlKba/vI/l1fIqh/NTEEr1Cyw4AwttOicA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } }, "node_modules/tinyexec": { "version": "1.0.2", @@ -5826,38 +5785,31 @@ } }, "node_modules/vitest": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", - "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", + "version": "5.0.0-beta.7", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-5.0.0-beta.7.tgz", + "integrity": "sha512-YT/AWBSxJW/GHyNVQzVA7lIj39oRcEPEj1AYMi1Oko7l5GwCh8MO0ufavjVZI0oEYXcAoNmthegJhzGA2pkU2A==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.10", - "@vitest/mocker": "4.1.10", - "@vitest/pretty-format": "4.1.10", - "@vitest/runner": "4.1.10", - "@vitest/snapshot": "4.1.10", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", + "@types/chai": "^5.2.2", + "@vitest/mocker": "5.0.0-beta.7", + "chai": "^6.2.2", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", - "magic-string": "^0.30.21", + "magic-string": "^1.0.0", "obug": "^2.1.1", - "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", - "tinybench": "^2.9.0", + "tinybench": "^6.0.1", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.1.0", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "bin": { "vitest": "vitest.mjs" }, "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + "node": "^22.12.0 || ^24.0.0 || >=26.0.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -5865,16 +5817,16 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.10", - "@vitest/browser-preview": "4.1.10", - "@vitest/browser-webdriverio": "4.1.10", - "@vitest/coverage-istanbul": "4.1.10", - "@vitest/coverage-v8": "4.1.10", - "@vitest/ui": "4.1.10", + "@types/node": "^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "5.0.0-beta.7", + "@vitest/browser-preview": "5.0.0-beta.7", + "@vitest/browser-webdriverio": "^5.0.0-beta.5 || >=5.0.0", + "@vitest/coverage-istanbul": "5.0.0-beta.7", + "@vitest/coverage-v8": "5.0.0-beta.7", + "@vitest/ui": "5.0.0-beta.7", "happy-dom": "*", "jsdom": "*", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + "vite": "^6.4.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { @@ -5915,6 +5867,16 @@ } } }, + "node_modules/vitest/node_modules/magic-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.1.0.tgz", + "integrity": "sha512-kS3VHe0nEPST2saQV4Rbkchcd3UBRkVTQHo1D3h/ZTwFDhai/mfKkmtPAtD129EOI7K3HlHIsFOt0WrI2/oU9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/vscode-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", diff --git a/package.json b/package.json index 7c21039..0509bb3 100644 --- a/package.json +++ b/package.json @@ -47,8 +47,8 @@ "@microsoft/api-extractor": "^7.58.11", "@stylistic/eslint-plugin": "^5.10.0", "@types/node": "^26.1.1", - "@vitest/coverage-v8": "^4.1.10", - "@vitest/eslint-plugin": "^1.6.23", + "@vitest/coverage-v8": "^5.0.0-beta.7", + "@vitest/eslint-plugin": "^1.6.25", "eslint": "^10.7.0", "globals": "^17.7.0", "typescript": "~5.9.3", @@ -56,6 +56,11 @@ "unplugin-dts": "^1.0.3", "vite": "^8.1.5", "vite-plugin-doctest": "^3.0.0", - "vitest": "^4.1.10" + "vitest": "^5.0.0-beta.7" + }, + "overrides": { + "vite-plugin-doctest": { + "vitest": "^5.0.0-beta.7" + } } } From e855824a5ee94592cf98ce8cc742cc68f3ffb50a Mon Sep 17 00:00:00 2001 From: mspiess <30656914+mspiess@users.noreply.github.com> Date: Sun, 2 Aug 2026 20:36:35 +0200 Subject: [PATCH 2/2] test: add benchmarks --- .github/workflows/node.js.yml | 2 + package.json | 1 + src/main.benchmark.ts | 104 ++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 src/main.benchmark.ts diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 1697d33..5a40710 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -31,3 +31,5 @@ jobs: run: npm test -- --coverage - if: ${{ matrix.node-version == '26.x' }} uses: coverallsapp/github-action@v2 + - if: ${{ matrix.node-version == '26.x' }} + run: npm run benchmark diff --git a/package.json b/package.json index 0509bb3..a3c59fe 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "build": "tsc && vite build", "lint": "eslint src/", "test": "vitest --typecheck --run", + "benchmark": "vitest bench", "changeset": "changeset", "release": "npm run build && changeset tag && npm publish --provenance --access public" }, diff --git a/src/main.benchmark.ts b/src/main.benchmark.ts new file mode 100644 index 0000000..b8b5974 --- /dev/null +++ b/src/main.benchmark.ts @@ -0,0 +1,104 @@ +import { describe, expect, test } from 'vitest'; +import type { IntegerLessThan32 } from './IntegerLessThan32.ts'; +import { EnumSet } from './main.ts'; + +const allValues = [...Array(32).keys()] as IntegerLessThan32[]; + +describe('has', () => { + test('empty set', async ({ bench }) => { + const nativeSet = new Set(); + const enumSet = new EnumSet(); + + await bench.compare( + bench('native set', () => { + allValues.forEach((value) => { + nativeSet.has(value); + }); + }), bench('enum set', () => { + allValues.forEach((value) => { + enumSet.has(value); + }); + }), + ); + }); + + test('full set', async ({ bench }) => { + const nativeSet = new Set(allValues); + const enumSet = new EnumSet(allValues); + + await bench.compare( + bench('native set', () => { + allValues.forEach((value) => { + nativeSet.has(value); + }); + }), bench('enum set', () => { + allValues.forEach((value) => { + enumSet.has(value); + }); + }), + ); + }); +}); + +test('add', async ({ bench }) => { + const nativeSet = new Set(); + const enumSet = new EnumSet(); + + const result = await bench.compare( + bench('native set', () => { + allValues.forEach((value) => { + nativeSet.add(value); + }); + }), bench('enum set', () => { + allValues.forEach((value) => { + enumSet.add(value); + }); + }), + ); + + expect([...nativeSet.values()]).toStrictEqual(allValues); + expect([...enumSet.values()]).toStrictEqual(allValues); + expect(result.get('enum set')).toBeFasterThan(result.get('native set')); +}); + +test('delete', async ({ bench }) => { + const nativeSet = new Set(allValues); + const enumSet = new EnumSet(allValues); + + const result = await bench.compare( + bench('native set', () => { + allValues.forEach((value) => { + nativeSet.delete(value); + }); + }), bench('enum set', () => { + allValues.forEach((value) => { + enumSet.delete(value); + }); + }), + ); + + expect(nativeSet.size).toBe(0); + expect(enumSet.size).toBe(0); + expect(result.get('enum set')).toBeFasterThan(result.get('native set')); +}); + +describe.for([ + { method: 'keys' as const }, + { method: 'values' as const }, + // workaround for https://github.com/microsoft/TypeScript/issues/54100 + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + { method: Symbol.iterator } as { method: typeof Symbol.iterator }, +])('$method', ({ method }) => { + test('iterate', async ({ bench }) => { + const nativeSet = new Set(allValues); + const enumSet = new EnumSet(allValues); + + await bench.compare( + bench('native set', () => { + nativeSet[method](); + }), bench('enum set', () => { + enumSet[method](); + }), + ); + }); +});