From 56d5e944f985e9a48e0da283dcc0309d78f8378b Mon Sep 17 00:00:00 2001 From: Serhiy Morenko Date: Thu, 9 Jul 2026 12:21:06 +0200 Subject: [PATCH 1/2] feat: ts7 upgrade --- .npmignore | 9 + package-lock.json | 632 +++++++++++---------- package.json | 15 +- scripts/strip-comment-coverage.mjs | 101 +++- test/mocks/mockBuiltin.ts | 59 +- test/mocks/redis.ts | 22 +- test/unit/UDPWorker.spec.ts | 9 +- test/unit/helpers/copyEventEmitter.spec.ts | 34 +- test/unit/profile.spec.ts | 37 +- typedoc.json | 19 - 10 files changed, 556 insertions(+), 381 deletions(-) delete mode 100644 typedoc.json diff --git a/.npmignore b/.npmignore index 37120a0..55891b6 100644 --- a/.npmignore +++ b/.npmignore @@ -45,3 +45,12 @@ test/ tsconfig.json *.tgz + +# Dev/tooling — never part of the published package +scripts/ +.oxlintrc.json +.oxfmtrc.json +.agent-out/ +# debug* are manual dev scripts; `!*.d.ts` above re-includes their declaration +# files, so re-exclude those here (a later rule wins) +debug*.d.ts diff --git a/package-lock.json b/package-lock.json index f95cd48..b07d9d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,27 +12,10 @@ "ioredis": "^5.11.1" }, "devDependencies": { - "@types/mock-require": "^3.0.0", "@types/node": "^24.9.1", - "mock-require": "^3.0.3", "oxfmt": "0.57.0", "oxlint": "1.72.0", - "typedoc": "^0.28.20", - "typescript": "^6.0.3" - } - }, - "node_modules/@gerrit0/mini-shiki": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.23.0.tgz", - "integrity": "sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/engine-oniguruma": "^3.23.0", - "@shikijs/langs": "^3.23.0", - "@shikijs/themes": "^3.23.0", - "@shikijs/types": "^3.23.0", - "@shikijs/vscode-textmate": "^10.0.2" + "typescript": "^7.0.2" } }, "node_modules/@ioredis/commands": { @@ -735,117 +718,354 @@ "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@shikijs/engine-oniguruma": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz", - "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==", + "node_modules/@types/node": { + "version": "24.13.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz", + "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "3.23.0", - "@shikijs/vscode-textmate": "^10.0.2" + "undici-types": "~7.18.0" } }, - "node_modules/@shikijs/langs": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz", - "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==", + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0" + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=16.20.0" } }, - "node_modules/@shikijs/themes": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz", - "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==", + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0" + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" } }, - "node_modules/@shikijs/types": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", - "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" } }, - "node_modules/@shikijs/vscode-textmate": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", - "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "*" + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" } }, - "node_modules/@types/mock-require": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/mock-require/-/mock-require-3.0.0.tgz", - "integrity": "sha512-TZ/s3ufaF+kEFPx9PqXKNd7OsPJoVsgOd59EA8XQLTRjJCsOdx5sEAOGhyrZ3Os78iaDKyGJWdQWyYWRg1Iyvg==", + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@types/node": { - "version": "24.13.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.2.tgz", - "integrity": "sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==", + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.18.0" + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" } }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], "dev": true, - "license": "Python-2.0" + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "18 || 20 || >=22" + "node": ">=16.20.0" } }, - "node_modules/brace-expansion": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", - "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "18 || 20 || >=22" + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" } }, "node_modules/cluster-key-slot": { @@ -883,26 +1103,6 @@ "node": ">=0.10" } }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true, - "license": "ISC" - }, "node_modules/ioredis": { "version": "5.11.1", "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.11.1.tgz", @@ -925,117 +1125,12 @@ "url": "https://opencollective.com/ioredis" } }, - "node_modules/linkify-it": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", - "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/markdown-it" - } - ], - "license": "MIT", - "dependencies": { - "uc.micro": "^2.0.0" - } - }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/markdown-it": { - "version": "14.3.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.0.tgz", - "integrity": "sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/markdown-it" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.5.0", - "linkify-it": "^5.0.2", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, - "bin": { - "markdown-it": "bin/markdown-it.mjs" - } - }, - "node_modules/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", - "dev": true, - "license": "MIT" - }, - "node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mock-require": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/mock-require/-/mock-require-3.0.3.tgz", - "integrity": "sha512-lLzfLHcyc10MKQnNUCv7dMcoY/2Qxd6wJfbqCcVk3LDb8An4hF6ohk5AztrvgKhJCqj36uyzi/p5se+tvyD+Wg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-caller-file": "^1.0.2", - "normalize-path": "^2.1.1" - }, - "engines": { - "node": ">=4.3.0" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, - "node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/oxfmt": { "version": "0.57.0", "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.57.0.tgz", @@ -1137,16 +1232,6 @@ } } }, - "node_modules/punycode.js": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/redis-errors": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", @@ -1168,13 +1253,6 @@ "node": ">=4" } }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", - "dev": true, - "license": "ISC" - }, "node_modules/standard-as-callback": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", @@ -1191,73 +1269,47 @@ "node": "^20.0.0 || >=22.0.0" } }, - "node_modules/typedoc": { - "version": "0.28.20", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.20.tgz", - "integrity": "sha512-uSKqkh8Cr48vllnEy+jdaAgOeR6Y+QCBW7usgUsKj7gJEfR7stw9U/fE49LBnj2tPRKPY0c0EBJSWe9Appmplg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@gerrit0/mini-shiki": "^3.23.0", - "lunr": "^2.3.9", - "markdown-it": "^14.3.0", - "minimatch": "^10.2.5", - "yaml": "^2.9.0" - }, - "bin": { - "typedoc": "bin/typedoc" - }, - "engines": { - "node": ">= 18", - "pnpm": ">= 10" - }, - "peerDependencies": { - "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x || 6.0.x" - } - }, "node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", "dev": true, "license": "Apache-2.0", "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "tsc": "bin/tsc" }, "engines": { - "node": ">=14.17" + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" } }, - "node_modules/uc.micro": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", - "dev": true, - "license": "MIT" - }, "node_modules/undici-types": { "version": "7.18.2", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "dev": true, "license": "MIT" - }, - "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } } } } diff --git a/package.json b/package.json index 7ad2a6b..788441a 100644 --- a/package.json +++ b/package.json @@ -18,19 +18,17 @@ "lint": "oxlint", "format": "oxfmt \"index.ts\" \"src/**/*.ts\" \"test/**/*.ts\" \"benchmark/**/*.ts\"", "format:check": "oxfmt --check \"index.ts\" \"src/**/*.ts\" \"test/**/*.ts\" \"benchmark/**/*.ts\"", - "test": "npm run build && node --test --test-timeout=15000 $(find test -name '*.spec.js')", - "test-coverage": "npm run build && node --enable-source-maps --test --experimental-test-coverage --test-timeout=15000 $(find test -name '*.spec.js')", - "test-lcov": "npm run build && mkdir -p coverage && node --enable-source-maps --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=coverage/lcov.info --test-timeout=15000 $(find test -name '*.spec.js'); node scripts/strip-comment-coverage.mjs coverage/lcov.info", + "test": "npm run build && node --experimental-test-module-mocks --test --test-timeout=15000 $(find test -name '*.spec.js')", + "test-coverage": "npm run build && node --experimental-test-module-mocks --enable-source-maps --test --experimental-test-coverage --test-timeout=15000 $(find test -name '*.spec.js')", + "test-lcov": "npm run build && mkdir -p coverage && node --experimental-test-module-mocks --enable-source-maps --test --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=coverage/lcov.info --test-timeout=15000 $(find test -name '*.spec.js'); node scripts/strip-comment-coverage.mjs coverage/lcov.info", "test-coverage-html": "npm run test-lcov; genhtml coverage/lcov.info --output-directory coverage/html --ignore-errors inconsistent,corrupt,format,mismatch && echo \"Coverage report: file://$(pwd)/coverage/html/index.html\"", "test-dev": "npm run test && npm run clean-js && npm run clean-typedefs && npm run clean-maps", "clean-typedefs": "find . -name '*.d.ts' -not -wholename '*node_modules*' -not -wholename '*generator*' -type f -delete", "clean-maps": "find . -name '*.js.map' -not -wholename '*node_modules*' -not -wholename '*generator*' -type f -delete", "clean-js": "find . -name '*.js' -not -wholename '*node_modules*' -not -wholename '*generator*' -type f -delete", "clean-tests": "rm -rf .nyc_output coverage .agent-out", - "clean-doc": "rm -rf docs", "clean-benchmark": "rm -rf benchmark-result", - "clean": "npm run clean-tests && npm run clean-typedefs && npm run clean-maps && npm run clean-js && npm run clean-doc && npm run clean-benchmark", - "doc": "typedoc && echo \"Docs generated: file://$(pwd)/docs/index.html\"" + "clean": "npm run clean-tests && npm run clean-typedefs && npm run clean-maps && npm run clean-js && npm run clean-benchmark" }, "repository": { "type": "git", @@ -46,13 +44,10 @@ "ioredis": "^5.11.1" }, "devDependencies": { - "@types/mock-require": "^3.0.0", "@types/node": "^24.9.1", - "mock-require": "^3.0.3", "oxfmt": "0.57.0", "oxlint": "1.72.0", - "typedoc": "^0.28.20", - "typescript": "^6.0.3" + "typescript": "^7.0.2" }, "main": "index.js", "types": "index.d.ts" diff --git a/scripts/strip-comment-coverage.mjs b/scripts/strip-comment-coverage.mjs index 6dd6926..f81eb3c 100644 --- a/scripts/strip-comment-coverage.mjs +++ b/scripts/strip-comment-coverage.mjs @@ -44,7 +44,11 @@ * genhtml with accurate line + branch coverage and no warnings or errors. */ import { readFileSync, writeFileSync, existsSync } from 'node:fs'; -import ts from 'typescript'; +// TypeScript 7 (native port) no longer exposes the classic compiler API from +// the package root — the lightweight scanner/AST primitives live under the +// `typescript/unstable/ast` entry point (createSourceFile is gone entirely, so +// import spans are located with the scanner rather than a parsed AST). +import * as ts from 'typescript/unstable/ast'; const lcovPath = process.argv[2] || 'coverage/lcov.info'; @@ -66,12 +70,13 @@ function nonCodeLines(text) { ts.ScriptTarget.Latest, /* skipTrivia */ false, ts.LanguageVariant.Standard, - text, ); + scanner.setText(text); + let token = scanner.scan(); - while (token !== ts.SyntaxKind.EndOfFileToken) { + while (token !== ts.SyntaxKind.EndOfFile) { if ( token === ts.SyntaxKind.SingleLineCommentTrivia || token === ts.SyntaxKind.MultiLineCommentTrivia @@ -129,26 +134,96 @@ function nonCodeLines(text) { * @returns {Set} */ function importLines(text) { - const sf = ts.createSourceFile( - 'x.ts', - text, + // TypeScript 7 dropped `createSourceFile`, so top-level import statements are + // located with the scanner: a top-level `import` keyword (depth 0, not the + // dynamic `import(...)` call nor `import.meta`) begins a declaration whose + // span reaches the terminating semicolon — both `import ... from '...'` and + // `import x = require('...')` end that way in this codebase. + const scanner = ts.createScanner( ts.ScriptTarget.Latest, - false, + /* skipTrivia */ true, + ts.LanguageVariant.Standard, ); + + scanner.setText(text); + + const lineStarts = ts.computeLineStarts(text); + // 0-based line holding `pos`: largest index with lineStarts[i] <= pos + const lineOf = pos => { + let lo = 0; + let hi = lineStarts.length - 1; + + while (lo < hi) { + const mid = (lo + hi + 1) >> 1; + + if (lineStarts[mid] <= pos) { + lo = mid; + } else { + hi = mid - 1; + } + } + + return lo; + }; + + const K = ts.SyntaxKind; const result = new Set(); + let depth = 0; + let token = scanner.scan(); - for (const stmt of sf.statements) { + while (token !== K.EndOfFile) { if ( - ts.isImportDeclaration(stmt) || - ts.isImportEqualsDeclaration(stmt) + token === K.OpenBraceToken || + token === K.OpenParenToken || + token === K.OpenBracketToken ) { - const from = sf.getLineAndCharacterOfPosition(stmt.getStart(sf)).line; - const to = sf.getLineAndCharacterOfPosition(stmt.getEnd()).line; + depth++; + } else if ( + token === K.CloseBraceToken || + token === K.CloseParenToken || + token === K.CloseBracketToken + ) { + depth--; + } else if (depth === 0 && token === K.ImportKeyword) { + const start = scanner.getTokenStart(); + let next = scanner.scan(); + + // `import(...)` dynamic call or `import.meta` — not a declaration + if (next === K.OpenParenToken || next === K.DotToken) { + token = next; + continue; + } + + // consume to the terminating semicolon at bracket depth 0 + let inner = 0; + let end = scanner.getTokenEnd(); + + while (next !== K.EndOfFile) { + if (next === K.OpenBraceToken || next === K.OpenParenToken) { + inner++; + } else if ( + next === K.CloseBraceToken || + next === K.CloseParenToken + ) { + inner--; + } else if (next === K.SemicolonToken && inner === 0) { + end = scanner.getTokenEnd(); + break; + } + + end = scanner.getTokenEnd(); + next = scanner.scan(); + } - for (let line = from; line <= to; line++) { + for (let line = lineOf(start); line <= lineOf(end); line++) { result.add(line + 1); } + + token = scanner.scan(); + continue; } + + token = scanner.scan(); } return result; diff --git a/test/mocks/mockBuiltin.ts b/test/mocks/mockBuiltin.ts index de16333..65c9cdc 100644 --- a/test/mocks/mockBuiltin.ts +++ b/test/mocks/mockBuiltin.ts @@ -21,22 +21,57 @@ * purchase a proprietary commercial license. Please contact us at * to get commercial licensing options. */ -import mock = require('mock-require'); +import { mock, MockModuleOptions } from 'node:test'; /** - * Registers a mock for a Node.js built-in module under both its bare specifier - * (e.g. `os`) and its `node:`-prefixed form (e.g. `node:os`). This keeps the - * mock effective no matter which import form the code under test uses, so the - * two never drift out of sync. + * Builds the `mock.module()` options for the running Node version. Node 24+ + * takes the mock's exports through the `exports` option (a `default` key is + * the default export; for CJS consumers `module.exports` becomes that value), + * and deprecated the earlier `defaultExport`/`namedExports` pair. Node 22 only + * understands the earlier pair, so the same exports shape is translated there. + * + * `cache: true` keeps mock-require's semantics: every `require()` of the + * mocked specifier returns the same module instance, so a test may patch a + * property in place and the code under test observes the change. + * + * @param {Record} exports - mock exports, `default` key being + * the default export + * @returns {MockModuleOptions} + */ +export function moduleMockOptions( + exports: Record, +): MockModuleOptions { + if (+process.versions.node.split('.')[0] >= 24) { + // typings (@types/node 24.x) lag the runtime's `exports` option + return { cache: true, exports } as MockModuleOptions; + } + + const { default: defaultExport, ...namedExports } = exports; + const options: MockModuleOptions = { cache: true }; + + if (defaultExport !== undefined) { + options.defaultExport = defaultExport; + } + + if (Object.keys(namedExports).length) { + options.namedExports = namedExports; + } + + return options; +} + +/** + * Registers a mock for a Node.js built-in module using the native + * `node:test` module mocking (`--experimental-test-module-mocks` must be + * enabled). Node resolves the bare specifier (e.g. `os`) and its + * `node:`-prefixed form (e.g. `node:os`) to the same module, so a single + * registration keeps the mock effective no matter which import form the code + * under test uses. * * @param {string} name - the built-in module name, without the `node:` prefix - * @param {Parameters[1]} impl - the mock implementation to register + * @param {Record} impl - the mock exports to register * @returns {void} */ -export function mockBuiltin( - name: string, - impl: Parameters[1], -): void { - mock(name, impl); - mock(`node:${name}`, impl); +export function mockBuiltin(name: string, impl: Record): void { + mock.module(`node:${name}`, moduleMockOptions(impl)); } diff --git a/test/mocks/redis.ts b/test/mocks/redis.ts index 05b54c1..a3a9fb7 100644 --- a/test/mocks/redis.ts +++ b/test/mocks/redis.ts @@ -21,9 +21,10 @@ * purchase a proprietary commercial license. Please contact us at * to get commercial licensing options. */ -import mock from 'mock-require'; +import { mock } from 'node:test'; import { EventEmitter } from 'node:events'; import { createHash, Hash } from 'node:crypto'; +import { moduleMockOptions } from './mockBuiltin'; function sha1(str: string) { let sha: Hash = createHash('sha1'); @@ -375,10 +376,19 @@ export class RedisClientMock extends EventEmitter { } } -mock('ioredis', { - __esModule: true, - default: RedisClientMock, - Redis: RedisClientMock, -}); +// Native module mocking cannot merge named exports onto a class default +// export, so the whole transpiled-ESM-shaped namespace object is registered +// as the module's default export (for CJS consumers it IS what +// `require('ioredis')` returns) — exactly the object mock-require served here. +mock.module( + 'ioredis', + moduleMockOptions({ + default: { + __esModule: true, + default: RedisClientMock, + Redis: RedisClientMock, + }, + }), +); export * from 'ioredis'; diff --git a/test/unit/UDPWorker.spec.ts b/test/unit/UDPWorker.spec.ts index 4fc952f..79a13fc 100644 --- a/test/unit/UDPWorker.spec.ts +++ b/test/unit/UDPWorker.spec.ts @@ -25,6 +25,10 @@ import '../mocks'; import { describe, it, mock } from 'node:test'; import assert from 'node:assert/strict'; import { EventEmitter } from 'node:events'; +// import-equals keeps the live (mocked) CJS module object (unlike +// `import * as`, which esModuleInterop turns into a copy), so patching +// os.networkInterfaces below is observed by the code under test +import os = require('node:os'); import { UDPWorker } from '../../src/UDPWorker'; const OPTIONS: any = { @@ -185,10 +189,9 @@ describe('UDPWorker', () => { }); it('skips interface entries with no addresses', () => { - const os = require('node:os'); const original = os.networkInterfaces; - os.networkInterfaces = () => ({ + (os as any).networkInterfaces = () => ({ empty: undefined, lo: [ { @@ -208,7 +211,7 @@ describe('UDPWorker', () => { assert.equal(worker.selectNetworkInterface(), '127.0.0.1'); } finally { - os.networkInterfaces = original; + (os as any).networkInterfaces = original; } }); diff --git a/test/unit/helpers/copyEventEmitter.spec.ts b/test/unit/helpers/copyEventEmitter.spec.ts index b43b62b..b1e151b 100644 --- a/test/unit/helpers/copyEventEmitter.spec.ts +++ b/test/unit/helpers/copyEventEmitter.spec.ts @@ -23,6 +23,10 @@ import '../../mocks'; import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { EventEmitter } from 'node:events'; +// import-equals keeps the live CJS module object (unlike `import * as`, +// which esModuleInterop turns into a copy), so patching util.inspect below +// is observed by the code under test +import util = require('node:util'); import { copyEventEmitter } from '../../../src/helpers'; describe('copyEventEmitter()', () => { @@ -92,8 +96,8 @@ describe('copyEventEmitter()', () => { source.on(eventName, mockListener); // Mock util.inspect to return onceWrapper for this listener - const originalInspect = require('node:util').inspect; - require('node:util').inspect = (obj: any) => { + const originalInspect = util.inspect; + (util as any).inspect = (obj: any) => { if (obj === mockListener) { return 'function onceWrapper() { ... }'; } @@ -103,7 +107,7 @@ describe('copyEventEmitter()', () => { copyEventEmitter(source, target); // Restore original inspect - require('node:util').inspect = originalInspect; + (util as any).inspect = originalInspect; assert.equal(target.listenerCount(eventName), 1); }); @@ -139,8 +143,8 @@ describe('copyEventEmitter()', () => { // Create a mock listener that looks like onceWrapper and has a falsy listener property const mockListener: any = function () {}; mockListener.listener = 0; // falsy value present - const originalInspect = require('node:util').inspect; - require('node:util').inspect = (obj: any) => { + const originalInspect = util.inspect; + (util as any).inspect = (obj: any) => { if (obj === mockListener) { return 'function onceWrapper() { ... }'; } @@ -151,7 +155,7 @@ describe('copyEventEmitter()', () => { copyEventEmitter(source, target); // Restore original inspect - require('node:util').inspect = originalInspect; + (util as any).inspect = originalInspect; assert.equal(target.listenerCount(eventName), 1); }); @@ -162,8 +166,8 @@ describe('copyEventEmitter()', () => { const mockListener: any = function () {}; mockListener.listener = undefined; // explicitly undefined - const originalInspect = require('node:util').inspect; - require('node:util').inspect = (obj: any) => { + const originalInspect = util.inspect; + (util as any).inspect = (obj: any) => { if (obj === mockListener) { return 'function onceWrapper() { ... }'; } @@ -174,7 +178,7 @@ describe('copyEventEmitter()', () => { copyEventEmitter(source, target); // Restore original inspect - require('node:util').inspect = originalInspect; + (util as any).inspect = originalInspect; assert.equal(target.listenerCount(eventName), 1); }); @@ -191,8 +195,8 @@ describe('copyEventEmitter()', () => { const mockListener: any = function () {}; mockListener.listener = realListener; // truthy function - const originalInspect = require('node:util').inspect; - require('node:util').inspect = (obj: any) => { + const originalInspect = util.inspect; + (util as any).inspect = (obj: any) => { if (obj === mockListener) { return 'function onceWrapper() { ... }'; } @@ -203,7 +207,7 @@ describe('copyEventEmitter()', () => { copyEventEmitter(source, target); // Restore original inspect - require('node:util').inspect = originalInspect; + (util as any).inspect = originalInspect; // Ensure the listener was attached via once() and is callable exactly once assert.equal(target.listenerCount(eventName), 1); @@ -226,8 +230,8 @@ describe('copyEventEmitter()', () => { }, on: () => {}, }; - const originalInspect = require('node:util').inspect; - require('node:util').inspect = (obj: any) => { + const originalInspect = util.inspect; + (util as any).inspect = (obj: any) => { if (typeof obj === 'undefined') { return 'function onceWrapper() { ... }'; } @@ -237,7 +241,7 @@ describe('copyEventEmitter()', () => { copyEventEmitter(source as any, target as any); // Restore original inspect - require('node:util').inspect = originalInspect; + (util as any).inspect = originalInspect; assert.equal(onceCalls.length, 1); assert.equal(onceCalls[0][0], eventName); diff --git a/test/unit/profile.spec.ts b/test/unit/profile.spec.ts index 0e237d5..8e6d364 100644 --- a/test/unit/profile.spec.ts +++ b/test/unit/profile.spec.ts @@ -25,7 +25,6 @@ import '../mocks'; import { describe, it, beforeEach, afterEach, mock, Mock } from 'node:test'; import assert from 'node:assert/strict'; -import mockRequire from 'mock-require'; import { profile, ILogger, @@ -35,6 +34,22 @@ import { } from '../..'; import { logger } from '../mocks'; +/** + * Loads a fresh, uncached copy of a module so that its module-scope state + * (e.g. env-derived constants) is re-evaluated. Replaces mock-require's + * reRequire(). + * + * @param {string} id - module id, relative to this file + * @returns {any} - the freshly loaded module + */ +function reRequire(id: string): any { + const resolved = require.resolve(id); + + delete require.cache[resolved]; + + return require(resolved); +} + const BIG_INT_SUPPORT = (() => { try { return !!BigInt(0); @@ -113,7 +128,6 @@ describe('profile()', () => { afterEach(() => { mock.restoreAll(); - mockRequire.stopAll(); delete process.env.IMQ_LOG_TIME_FORMAT; }); @@ -179,27 +193,27 @@ describe('profile()', () => { }; it('should log time in microseconds by default', () => { - const { logDebugInfo } = mockRequire.reRequire('../../src/profile'); + const { logDebugInfo } = reRequire('../../src/profile'); logDebugInfo(baseOptions); assert.equal(calledWithMatch(log, /μs/), true); }); it('should log time in milliseconds', () => { process.env.IMQ_LOG_TIME_FORMAT = 'milliseconds'; - const { logDebugInfo } = mockRequire.reRequire('../../src/profile'); + const { logDebugInfo } = reRequire('../../src/profile'); logDebugInfo(baseOptions); assert.equal(calledWithMatch(log, /ms/), true); }); it('should log time in seconds', () => { process.env.IMQ_LOG_TIME_FORMAT = 'seconds'; - const { logDebugInfo } = mockRequire.reRequire('../../src/profile'); + const { logDebugInfo } = reRequire('../../src/profile'); logDebugInfo(baseOptions); assert.equal(calledWithMatch(log, /sec/), true); }); it('should handle circular references in args', () => { - const { logDebugInfo } = mockRequire.reRequire('../../src/profile'); + const { logDebugInfo } = reRequire('../../src/profile'); const a: any = { b: 1 }; const b = { a }; a.b = b; @@ -208,7 +222,7 @@ describe('profile()', () => { }); it('should not log when logger method is missing', () => { - const { logDebugInfo } = mockRequire.reRequire('../../src/profile'); + const { logDebugInfo } = reRequire('../../src/profile'); const dummyLogger: any = { error: logger.error.bind(logger) }; logDebugInfo({ ...baseOptions, @@ -219,7 +233,7 @@ describe('profile()', () => { }); it('should handle JSON.stringify errors', () => { - const { logDebugInfo } = mockRequire.reRequire('../../src/profile'); + const { logDebugInfo } = reRequire('../../src/profile'); const badJson = { toJSON: () => { throw new Error('bad json'); @@ -234,13 +248,11 @@ describe('profile()', () => { describe('profile.ts additional branches', () => { afterEach(() => { mock.restoreAll(); - mockRequire.stopAll(); delete (process as any).env.IMQ_LOG_TIME_FORMAT; }); it('logDebugInfo: should not attempt to call missing log method (no-op path)', () => { - const { logDebugInfo, LogLevel } = - mockRequire.reRequire('../../src/profile'); + const { logDebugInfo, LogLevel } = reRequire('../../src/profile'); const fakeLogger: any = { // intentionally no 'log' or 'info' method for selected level error: mock.fn(), @@ -261,8 +273,7 @@ describe('profile.ts additional branches', () => { }); it('logDebugInfo: should call logger.error on JSON.stringify error (BigInt arg)', () => { - const { logDebugInfo, LogLevel } = - mockRequire.reRequire('../../src/profile'); + const { logDebugInfo, LogLevel } = reRequire('../../src/profile'); const fakeLogger: any = { error: mock.fn(), }; diff --git a/typedoc.json b/typedoc.json deleted file mode 100644 index 3e53bb6..0000000 --- a/typedoc.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "name": "@imqueue/core", - "entryPoints": ["."], - "entryPointStrategy": "expand", - "exclude": [ - "**/+(test|node_modules|docs|coverage|benchmark|.nyc_output)/**/*", - "**/*.d.ts" - ], - "excludePrivate": true, - "excludeExternals": true, - "hideGenerator": true, - "externalSymbolLinkMappings": { - "@types/node": { - "EventEmitter.defaultMaxListeners": "https://nodejs.org/api/events.html#eventsdefaultmaxlisteners" - } - }, - "out": "docs" -} From 864a69ae887da262193611399546b4fbe17b5dc6 Mon Sep 17 00:00:00 2001 From: Serhiy Morenko Date: Thu, 9 Jul 2026 12:23:23 +0200 Subject: [PATCH 2/2] 3.1.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index b07d9d8..9e8561a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@imqueue/core", - "version": "3.0.0", + "version": "3.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@imqueue/core", - "version": "3.0.0", + "version": "3.1.0", "license": "GPL-3.0-only", "dependencies": { "ioredis": "^5.11.1" diff --git a/package.json b/package.json index 788441a..db77fe2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@imqueue/core", - "version": "3.0.0", + "version": "3.1.0", "description": "Simple JSON-based messaging queue for inter service communication", "keywords": [ "message-queue",