diff --git a/examples/h2-other-side-closed-exit-0-fetch.cjs b/examples/h2-other-side-closed-exit-0-fetch.cjs index 4784c433..0215c924 100644 --- a/examples/h2-other-side-closed-exit-0-fetch.cjs +++ b/examples/h2-other-side-closed-exit-0-fetch.cjs @@ -11,13 +11,13 @@ async function main() { try { const r = await fetch('https://edgeupdates.microsoft.com/api/products'); console.log(r.status, r.headers, (await r.text()).length); - } catch (err) { + } catch (error) { // console.error(err); // throw err; - if (err.code === 'UND_ERR_SOCKET') { + if (error.code === 'UND_ERR_SOCKET') { continue; } else { - throw err; + throw error; } } } @@ -27,8 +27,8 @@ main() .then(() => { console.log('main end'); }) - .catch((err) => { - console.error('main error throw: %s', err); + .catch((error) => { + console.error('main error throw: %s', error); // console.error(err); process.exit(1); }); diff --git a/examples/h2-other-side-closed-exit-0.cjs b/examples/h2-other-side-closed-exit-0.cjs index 59c851c0..f34fd9fc 100644 --- a/examples/h2-other-side-closed-exit-0.cjs +++ b/examples/h2-other-side-closed-exit-0.cjs @@ -11,13 +11,13 @@ async function main() { try { const r = await request('https://edgeupdates.microsoft.com/api/products'); console.log(r.statusCode, r.headers, (await r.body.blob()).size); - } catch (err) { + } catch (error) { // console.error(err); // throw err; - if (err.code === 'UND_ERR_SOCKET') { + if (error.code === 'UND_ERR_SOCKET') { continue; } else { - throw err; + throw error; } } } @@ -27,8 +27,8 @@ main() .then(() => { console.log('main end'); }) - .catch((err) => { - console.error('main error throw: %s', err); + .catch((error) => { + console.error('main error throw: %s', error); // console.error(err); process.exit(1); }); diff --git a/examples/httpclient.cjs b/examples/httpclient.cjs index 8c011114..c954e2e6 100644 --- a/examples/httpclient.cjs +++ b/examples/httpclient.cjs @@ -5,7 +5,7 @@ tryHttpclient(HttpClient, 'urllib'); function tryHttpclient(HttpClient, name) { const options = { method: 'GET', - timeout: 10000, + timeout: 10_000, timing: true, }; const urllib = new HttpClient(); @@ -22,7 +22,7 @@ function tryHttpclient(HttpClient, name) { .then(function () { return urllib.request('https://nodejs.org/en/', options); }) - .catch(function (err) { - console.error('catch', err); + .catch(function (error) { + console.error('catch', error); }); } diff --git a/examples/longruning.cjs b/examples/longruning.cjs index 9adc34e9..1f593cd6 100644 --- a/examples/longruning.cjs +++ b/examples/longruning.cjs @@ -5,7 +5,7 @@ const httpClient = new HttpClient({ }); async function main() { - for (let i = 0; i < 1000000; i++) { + for (let i = 0; i < 1_000_000; i++) { // await httpClient.request('https://registry.npmmirror.com/'); // console.log(r.status, r.headers, r.res.timing); try { @@ -15,8 +15,8 @@ async function main() { // console.log(r.status, r.headers, r.data.length, r.res.timing); console.log(i, r.status, process.memoryUsage()); } - } catch (err) { - console.error('%s error: %s', i, err.message); + } catch (error) { + console.error('%s error: %s', i, error.message); } } } @@ -25,9 +25,9 @@ main() .then(() => { console.log('main end'); }) - .catch((err) => { - console.error('main error throw: %s', err); - console.error(err); + .catch((error) => { + console.error('main error throw: %s', error); + console.error(error); process.exit(1); }); diff --git a/examples/search_github.cjs b/examples/search_github.cjs index 22fb1975..9c056d42 100644 --- a/examples/search_github.cjs +++ b/examples/search_github.cjs @@ -1,12 +1,12 @@ // curl https://api.github.com/legacy/user/search/location:china -var urllib = require('../'); +const urllib = require('../'); urllib .request('https://api.github.com/legacy/user/search/location:china', { dataType: 'json', timing: true, - timeout: 10000, + timeout: 10_000, }) .then((response) => { console.log(response); diff --git a/oxlint.config.ts b/oxlint.config.ts new file mode 100644 index 00000000..38103b3c --- /dev/null +++ b/oxlint.config.ts @@ -0,0 +1,72 @@ +import nkzw from '@nkzw/oxlint-config'; +import { defineConfig } from 'oxlint'; + +export default defineConfig({ + extends: [nkzw], + // urllib is a Node.js HTTP client library — no React + plugins: ['typescript', 'import', 'unicorn'], + ignorePatterns: ['dist/**', 'test/fixtures/**', 'test/esm/**', 'test/cjs/**', 'test/mts/**'], + rules: { + // Allow console usage in a Node.js library + 'no-console': 'off', + // Allow any in internal utility code + '@typescript-eslint/no-explicit-any': 'off', + // Allow require() for CJS compat + '@typescript-eslint/no-require-imports': 'off', + + // --- Disable React rules (not a React project) --- + 'react/display-name': 'off', + 'react/jsx-key': 'off', + 'react/jsx-no-comment-textnodes': 'off', + 'react/jsx-no-duplicate-props': 'off', + 'react/jsx-no-target-blank': 'off', + 'react/jsx-no-undef': 'off', + 'react/no-children-prop': 'off', + 'react/no-danger-with-children': 'off', + 'react/no-direct-mutation-state': 'off', + 'react/no-find-dom-node': 'off', + 'react/no-is-mounted': 'off', + 'react/no-render-return-value': 'off', + 'react/no-string-refs': 'off', + 'react/no-unescaped-entities': 'off', + 'react/no-unknown-property': 'off', + 'react/require-render-return': 'off', + 'react-hooks/rules-of-hooks': 'off', + 'react-hooks/exhaustive-deps': 'off', + 'react-hooks-js/component-hook-factories': 'off', + 'react-hooks-js/config': 'off', + 'react-hooks-js/error-boundaries': 'off', + 'react-hooks-js/gating': 'off', + 'react-hooks-js/globals': 'off', + 'react-hooks-js/immutability': 'off', + 'react-hooks-js/incompatible-library': 'off', + 'react-hooks-js/preserve-manual-memoization': 'off', + 'react-hooks-js/purity': 'off', + 'react-hooks-js/refs': 'off', + 'react-hooks-js/set-state-in-effect': 'off', + 'react-hooks-js/set-state-in-render': 'off', + 'react-hooks-js/static-components': 'off', + 'react-hooks-js/unsupported-syntax': 'off', + 'react-hooks-js/use-memo': 'off', + '@nkzw/ensure-relay-types': 'off', + '@nkzw/require-use-effect-arguments': 'off', + + // --- Too invasive for an existing codebase --- + // Object/interface sorting would touch every file + 'perfectionist/sort-objects': 'off', + 'perfectionist/sort-object-types': 'off', + 'perfectionist/sort-interfaces': 'off', + 'perfectionist/sort-enums': 'off', + 'perfectionist/sort-heritage-clauses': 'off', + 'perfectionist/sort-jsx-props': 'off', + + // Allow instanceof — common pattern in Node.js error handling + '@nkzw/no-instanceof': 'off', + + // Library code legitimately uses no-undef globals (Buffer, etc.) + 'no-undef': 'off', + + // Allow top-level await flexibility + 'unicorn/prefer-top-level-await': 'off', + }, +}); diff --git a/package.json b/package.json index 9ea4b369..02c98233 100644 --- a/package.json +++ b/package.json @@ -67,8 +67,9 @@ "clean": "rm -rf dist && tsc -b --clean", "prepublishOnly": "vp run build", "prepare": "node -e \"const v = parseInt(process.versions.node, 10); if (v >= 20) require('child_process').execSync('vp config', {stdio: 'inherit'});\"", - "check": "vp check", - "check:fix": "vp check --fix" + "lint:oxlint": "oxlint", + "check": "vp check && npm run lint:oxlint", + "check:fix": "vp check --fix && npm run lint:oxlint --fix" }, "dependencies": { "form-data": "^4.0.5", @@ -82,6 +83,8 @@ "devDependencies": { "@arethetypeswrong/cli": "^0.18.2", "@eggjs/tsconfig": "^2.0.0", + "@nkzw/eslint-plugin": "^2.0.0", + "@nkzw/oxlint-config": "^1.0.1", "@types/busboy": "^1.5.4", "@types/mime-types": "^2.1.4", "@types/node": "^22.19.15", @@ -94,7 +97,11 @@ "@vitest/coverage-v8": "^4.1.0", "busboy": "^1.6.0", "cross-env": "^10.1.0", + "eslint-plugin-no-only-tests": "^3.3.0", + "eslint-plugin-perfectionist": "^5.6.0", + "eslint-plugin-unused-imports": "^4.4.1", "iconv-lite": "^0.6.3", + "oxlint": "^1.55.0", "proxy": "^1.0.2", "selfsigned": "^3.0.1", "string.prototype.towellformed": "^1.0.2", diff --git a/scripts/replace_urllib_version.js b/scripts/replace_urllib_version.js index 7a469c03..fb4f7b8c 100644 --- a/scripts/replace_urllib_version.js +++ b/scripts/replace_urllib_version.js @@ -8,7 +8,7 @@ async function main() { const pkg = JSON.parse(await fs.readFile(path.join(root, 'package.json'))); const files = [path.join(root, 'dist/commonjs/HttpClient.js'), path.join(root, 'dist/esm/HttpClient.js')]; for (const file of files) { - const content = await fs.readFile(file, 'utf-8'); + const content = await fs.readFile(file, 'utf8'); // replace "const VERSION = 'VERSION';" to "const VERSION = '4.0.0';" // "exports.VERSION = 'VERSION';" => "exports.VERSION = '4.0.0';" const newContent = content.replace(/ = 'VERSION';/, (match) => { diff --git a/src/FormData.ts b/src/FormData.ts index d67d6844..b58fdcee 100644 --- a/src/FormData.ts +++ b/src/FormData.ts @@ -2,8 +2,8 @@ import path from 'node:path'; import _FormData from 'form-data'; -// eslint-disable-next-line -const NON_ASCII_RE = /[^\x00-\x7F]/i; +// eslint-disable-next-line no-control-regex +const NON_ASCII_RE = /[^\u0000-\u007F]/i; export class FormData extends _FormData { _getContentDisposition(value: any, options: any): string | undefined { @@ -14,13 +14,13 @@ export class FormData extends _FormData { if (typeof options.filepath === 'string') { // custom filepath for relative paths - filename = path.normalize(options.filepath).replace(/\\/g, '/'); + filename = path.normalize(options.filepath).replaceAll('\\', '/'); } else if (options.filename || value.name || value.path) { // custom filename take precedence // formidable and the browser add a name property // fs- and request- streams have path property filename = path.basename(options.filename || value.name || value.path); - } else if (value.readable && value.hasOwnProperty('httpVersion')) { + } else if (value.readable && Object.prototype.hasOwnProperty.call(value, 'httpVersion')) { // or try http response filename = path.basename(value.client._httpMessage.path || ''); } diff --git a/src/HttpAgent.ts b/src/HttpAgent.ts index dc04368c..336de252 100644 --- a/src/HttpAgent.ts +++ b/src/HttpAgent.ts @@ -40,11 +40,13 @@ export class HttpAgent extends BaseAgent { const { lookup = dns.lookup, ...baseOpts } = options; const lookupFunction: LookupFunction = (hostname, dnsOptions, callback) => { - lookup(hostname, dnsOptions, (err, ...args: any[]) => { + lookup(hostname, dnsOptions, (err, ...args: Array) => { // address will be array on Node.js >= 20 const address = args[0]; const family = args[1]; - if (err) return (callback as any)(err, address, family); + if (err) { + return (callback as any)(err, address, family); + } if (options.checkAddress) { // dnsOptions.all set to default on Node.js >= 20, dns.lookup will return address array object if (typeof address === 'string') { @@ -52,7 +54,7 @@ export class HttpAgent extends BaseAgent { err = new IllegalAddressError(hostname, address, family); } } else if (Array.isArray(address)) { - const addresses = address as { address: string; family: number }[]; + const addresses = address as Array<{ address: string; family: number }>; for (const addr of addresses) { if (!options.checkAddress(addr.address, addr.family, hostname)) { err = new IllegalAddressError(hostname, addr.address, addr.family); @@ -77,7 +79,7 @@ export class HttpAgent extends BaseAgent { let hostname = originUrl.hostname; // [2001:db8:2de::e13] => 2001:db8:2de::e13 if (hostname.startsWith('[') && hostname.endsWith(']')) { - hostname = hostname.substring(1, hostname.length - 1); + hostname = hostname.slice(1, hostname.length - 1); } const family = isIP(hostname); if (family === 4 || family === 6) { diff --git a/src/HttpClient.ts b/src/HttpClient.ts index 268eb1ee..175f73be 100644 --- a/src/HttpClient.ts +++ b/src/HttpClient.ts @@ -64,6 +64,7 @@ export interface UndiciTimingInfo { } // keep typo compatibility +// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- intentional alias for backward compat export interface UnidiciTimingInfo extends UndiciTimingInfo {} function noop(): void { @@ -112,7 +113,7 @@ export type ClientOptions = { export const VERSION: string = 'VERSION'; // 'node-urllib/4.0.0 Node.js/18.19.0 (darwin; x64)' -export const HEADER_USER_AGENT: string = `node-urllib/${VERSION} Node.js/${process.version.substring(1)} (${process.platform}; ${process.arch})`; +export const HEADER_USER_AGENT: string = `node-urllib/${VERSION} Node.js/${process.version.slice(1)} (${process.platform}; ${process.arch})`; function getFileName(stream: Readable): string { const filePath: string = (stream as any).path; @@ -131,7 +132,7 @@ export type RequestContext = { socketErrorRetries: number; requestStartTime?: number; redirects: number; - history: string[]; + history: Array; }; export const channels: { @@ -232,7 +233,9 @@ export class HttpClient extends EventEmitter { const pool = (typeof ref.deref === 'function' ? ref.deref() : ref) as unknown as Pool & { dispatcher: Pool }; // NOTE: pool become to { dispatcher: Pool } in undici@v7 const stats = pool?.stats ?? pool?.dispatcher?.stats; - if (!stats) continue; + if (!stats) { + continue; + } poolStatsMap[key] = { connected: stats.connected, @@ -376,7 +379,7 @@ export class HttpClient extends EventEmitter { bodyTimeout = args.timeout[1] ?? bodyTimeout; } else { // compatible with urllib@2 timeout string format - headersTimeout = bodyTimeout = typeof args.timeout === 'string' ? parseInt(args.timeout) : args.timeout; + headersTimeout = bodyTimeout = typeof args.timeout === 'string' ? Number.parseInt(args.timeout) : args.timeout; } } if (originalHeaders) { @@ -471,7 +474,7 @@ export class HttpClient extends EventEmitter { requestOptions.method = 'POST'; } const formData = new FormData(); - const uploadFiles: [string, string | Readable | Buffer, string?][] = []; + const uploadFiles: Array<[string, string | Readable | Buffer, string?]> = []; if (Array.isArray(args.files)) { for (const [index, file] of args.files.entries()) { const field = index === 0 ? 'file' : `file${index}`; @@ -637,7 +640,7 @@ export class HttpClient extends EventEmitter { res.status = res.statusCode = response.statusCode; res.statusMessage = res.statusText = STATUS_CODES[res.status] || ''; if (res.headers['content-length']) { - res.size = parseInt(res.headers['content-length']); + res.size = Number.parseInt(res.headers['content-length']); } // https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections @@ -682,11 +685,11 @@ export class HttpClient extends EventEmitter { if (isCompressedContent && data.length > 0) { try { data = contentEncoding === 'gzip' ? gunzipSync(data) : brotliDecompressSync(data); - } catch (err: any) { - if (err.name === 'Error') { - err.name = 'UnzipError'; + } catch (error: any) { + if (error.name === 'Error') { + error.name = 'UnzipError'; } - throw err; + throw error; } } if (args.dataType === 'text' || args.dataType === 'html') { diff --git a/src/IncomingHttpHeaders.ts b/src/IncomingHttpHeaders.ts index 571fa265..c51cac27 100644 --- a/src/IncomingHttpHeaders.ts +++ b/src/IncomingHttpHeaders.ts @@ -4,5 +4,5 @@ import type { Except } from 'type-fest'; // fix set-cookie type define https://github.com/nodejs/undici/pull/1893 export interface IncomingHttpHeaders extends Except { - 'set-cookie'?: string | string[]; + 'set-cookie'?: string | Array; } diff --git a/src/Request.ts b/src/Request.ts index 0d91a8d6..4dec1a10 100644 --- a/src/Request.ts +++ b/src/Request.ts @@ -89,7 +89,7 @@ export type RequestOptions = { * Defaults is `5000`, both are 5 seconds. You can use timeout: 5000 to tell urllib use same timeout on two phase or set them separately such as * timeout: [3000, 5000], which will set connecting timeout to 3s and response 5s. */ - timeout?: number | number[]; + timeout?: number | Array; /** * Default is `4000`, 4 seconds - The timeout after which a socket without active requests will time out. * Monitors time between activity on a connected socket. @@ -112,7 +112,7 @@ export type RequestOptions = { /** Format the redirect url by your self. Default is url.resolve(from, to). */ formatRedirectUrl?: (a: any, b: any) => void; /** Before request hook, you can change every thing here. */ - beforeRequest?: (...args: any[]) => void; + beforeRequest?: (...args: Array) => void; /** Accept `gzip, br` response content and auto decode it, default is `false`. */ compressed?: boolean; /** diff --git a/src/Response.ts b/src/Response.ts index aa613bed..277257e2 100644 --- a/src/Response.ts +++ b/src/Response.ts @@ -16,7 +16,7 @@ export type SocketInfo = { connectedTime?: Date; connectErrorTime?: Date; lastRequestEndTime?: Date; - attemptedRemoteAddresses?: string[]; + attemptedRemoteAddresses?: Array; connectProtocol?: string; connectHost?: string; connectPort?: string; @@ -59,7 +59,7 @@ export type RawResponseWithMeta = Readable & { aborted: boolean; rt: number; keepAliveSocket: boolean; - requestUrls: string[]; + requestUrls: Array; retries: number; socketErrorRetries: number; }; @@ -74,6 +74,6 @@ export type HttpClientResponse = { headers: IncomingHttpHeaders; url: string; redirected: boolean; - requestUrls: string[]; + requestUrls: Array; res: RawResponseWithMeta; }; diff --git a/src/diagnosticsChannel.ts b/src/diagnosticsChannel.ts index 2b07a75e..905f0125 100644 --- a/src/diagnosticsChannel.ts +++ b/src/diagnosticsChannel.ts @@ -33,7 +33,9 @@ type SocketExtend = Socket & { let kSocketReset: symbol; function formatSocket(socket: SocketExtend) { - if (!socket) return socket; + if (!socket) { + return socket; + } if (!kSocketReset) { const symbols = Object.getOwnPropertySymbols(socket); for (const symbol of symbols) { @@ -68,7 +70,9 @@ Socket.prototype.destroy = function (err?: any) { }; function getRequestOpaque(request: DiagnosticsChannel.Request, kHandler?: symbol) { - if (!kHandler) return; + if (!kHandler) { + return; + } const handler = Reflect.get(request, kHandler); // maxRedirects = 0 will get [Symbol(handler)]: RequestHandler { // responseHeaders: null, @@ -84,7 +88,9 @@ function getRequestOpaque(request: DiagnosticsChannel.Request, kHandler?: symbol export function initDiagnosticsChannel(): void { // make sure init global DiagnosticsChannel once - if (initedDiagnosticsChannel) return; + if (initedDiagnosticsChannel) { + return; + } initedDiagnosticsChannel = true; let kHandler: symbol; @@ -103,7 +109,9 @@ export function initDiagnosticsChannel(): void { } const opaque = getRequestOpaque(request, kHandler); // ignore non HttpClient Request - if (!opaque || !opaque[symbols.kRequestId]) return; + if (!opaque || !opaque[symbols.kRequestId]) { + return; + } Reflect.set(request, symbols.kRequestInternalOpaque, opaque); debug( @@ -115,7 +123,9 @@ export function initDiagnosticsChannel(): void { request.path, request.headers, ); - if (!opaque[symbols.kEnableRequestTiming]) return; + if (!opaque[symbols.kEnableRequestTiming]) { + return; + } opaque[symbols.kRequestTiming].queuing = performanceTime(opaque[symbols.kRequestStartTime]); }); @@ -192,7 +202,9 @@ export function initDiagnosticsChannel(): void { formatSocket(socket), ); - if (!opaque[symbols.kEnableRequestTiming]) return; + if (!opaque[symbols.kEnableRequestTiming]) { + return; + } opaque[symbols.kRequestTiming].requestHeadersSent = performanceTime(opaque[symbols.kRequestStartTime]); // first socket need to calculate the connected time if (socket[symbols.kHandledRequests] === 1) { @@ -213,7 +225,9 @@ export function initDiagnosticsChannel(): void { } debug('[%s] Request#%d send body', name, opaque[symbols.kRequestId]); - if (!opaque[symbols.kEnableRequestTiming]) return; + if (!opaque[symbols.kEnableRequestTiming]) { + return; + } opaque[symbols.kRequestTiming].requestSent = performanceTime(opaque[symbols.kRequestStartTime]); }); @@ -248,7 +262,9 @@ export function initDiagnosticsChannel(): void { ); } - if (!opaque[symbols.kEnableRequestTiming]) return; + if (!opaque[symbols.kEnableRequestTiming]) { + return; + } opaque[symbols.kRequestTiming].waiting = performanceTime(opaque[symbols.kRequestStartTime]); }); @@ -263,7 +279,9 @@ export function initDiagnosticsChannel(): void { debug('[%s] Request#%d get response body and trailers', name, opaque[symbols.kRequestId]); - if (!opaque[symbols.kEnableRequestTiming]) return; + if (!opaque[symbols.kEnableRequestTiming]) { + return; + } opaque[symbols.kRequestTiming].contentDownload = performanceTime(opaque[symbols.kRequestStartTime]); }); diff --git a/src/fetch.ts b/src/fetch.ts index e9f0acb5..2c8cb07d 100644 --- a/src/fetch.ts +++ b/src/fetch.ts @@ -109,7 +109,9 @@ export class FetchFactory { const pool = (typeof ref.deref === 'function' ? ref.deref() : ref) as unknown as Pool & { dispatcher: Pool }; // NOTE: pool become to { dispatcher: Pool } in undici@v7 const stats = pool?.stats ?? pool?.dispatcher?.stats; - if (!stats) continue; + if (!stats) { + continue; + } poolStatsMap[key] = { connected: stats.connected, @@ -223,23 +225,23 @@ export class FetchFactory { await this.#opaqueLocalStorage.run(internalOpaque, async () => { res = await UndiciFetch(request); }); - } catch (e: any) { - updateSocketInfo(socketInfo, internalOpaque, e); + } catch (error: any) { + updateSocketInfo(socketInfo, internalOpaque, error); urllibResponse.rt = performanceTime(requestStartTime); - debug('Request#%d throw error: %s', requestId, e); + debug('Request#%d throw error: %s', requestId, error); channels.fetchResponse.publish({ fetch: fetchMeta, - error: e, + error: error, fetchOpaque: internalOpaque, } as FetchResponseDiagnosticsMessage); channels.response.publish({ request: reqMeta, response: urllibResponse, - error: e, + error: error, isSentByFetch: true, fetchOpaque: internalOpaque, } as ResponseDiagnosticsMessage); - throw e; + throw error; } // get undici internal response @@ -250,7 +252,7 @@ export class FetchFactory { urllibResponse.status = urllibResponse.statusCode = res!.status; urllibResponse!.statusMessage = res!.statusText; if (urllibResponse.headers['content-length']) { - urllibResponse.size = parseInt(urllibResponse.headers['content-length']); + urllibResponse.size = Number.parseInt(urllibResponse.headers['content-length']); } urllibResponse.rt = performanceTime(requestStartTime); debug( diff --git a/src/utils.ts b/src/utils.ts index 56999d07..5841619a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -11,19 +11,19 @@ import type { SocketInfo } from './Response.js'; import symbols from './symbols.js'; const JSONCtlCharsMap: Record = { - '"': '\\"', // \u0022 - '\\': '\\\\', // \u005c - '\b': '\\b', // \u0008 - '\f': '\\f', // \u000c - '\n': '\\n', // \u000a - '\r': '\\r', // \u000d - '\t': '\\t', // \u0009 + '"': String.raw`\"`, // \u0022 + '\\': String.raw`\\`, // \u005c + '\b': String.raw`\b`, // \u0008 + '\f': String.raw`\f`, // \u000c + '\n': String.raw`\n`, // \u000a + '\r': String.raw`\r`, // \u000d + '\t': String.raw`\t`, // \u0009 }; -/* eslint no-control-regex: "off"*/ +// eslint-disable-next-line no-control-regex -- intentional control character matching for JSON sanitization const JSONCtlCharsRE = /[\u0000-\u001F\u005C]/g; function replaceOneChar(c: string) { - return JSONCtlCharsMap[c] || '\\u' + (c.charCodeAt(0) + 0x10000).toString(16).substring(1); + return JSONCtlCharsMap[c] || String.raw`\u` + (c.charCodeAt(0) + 0x1_00_00).toString(16).slice(1); } function replaceJSONCtlChars(value: string) { @@ -40,22 +40,22 @@ export function parseJSON(data: string, fixJSONCtlChars?: FixJSONCtlChars): unkn } try { data = JSON.parse(data); - } catch (err: any) { - if (err.name === 'SyntaxError') { - err.name = 'JSONResponseFormatError'; + } catch (error: any) { + if (error.name === 'SyntaxError') { + error.name = 'JSONResponseFormatError'; } if (data.length > 1024) { // show 0~512 ... -512~end data - err.message += + error.message += ' (data json format: ' + JSON.stringify(data.slice(0, 512)) + ' ...skip... ' + JSON.stringify(data.slice(data.length - 512)) + ')'; } else { - err.message += ' (data json format: ' + JSON.stringify(data) + ')'; + error.message += ' (data json format: ' + JSON.stringify(data) + ')'; } - throw err; + throw error; } return data; } @@ -100,7 +100,7 @@ export function digestAuthHeader(method: string, uri: string, wwwAuthenticate: s for (const part of parts) { const m = part.match(AUTH_KEY_VALUE_RE); if (m) { - opts[m[1]] = m[2].replace(/["']/g, ''); + opts[m[1]] = m[2].replaceAll(/["']/g, ''); } } @@ -110,11 +110,11 @@ export function digestAuthHeader(method: string, uri: string, wwwAuthenticate: s let qop = opts.qop || ''; const index = userpass.indexOf(':'); - const user = userpass.substring(0, index); - const pass = userpass.substring(index + 1); + const user = userpass.slice(0, index); + const pass = userpass.slice(index + 1); let nc = String(++NC); - nc = `${NC_PAD.substring(nc.length)}${nc}`; + nc = `${NC_PAD.slice(nc.length)}${nc}`; const cnonce = randomBytes(8).toString('hex'); const ha1 = md5(`${user}:${opts.realm}:${pass}`); @@ -151,7 +151,9 @@ export function performanceTime(startTime: number, now?: number): number { } export function isReadable(stream: any): boolean { - if (typeof Readable.isReadable === 'function') return Readable.isReadable(stream); + if (typeof Readable.isReadable === 'function') { + return Readable.isReadable(stream); + } // patch from node // https://github.com/nodejs/node/blob/1287530385137dda1d44975063217ccf90759475/lib/internal/streams/utils.js#L119 // simple way https://github.com/sindresorhus/is-stream/blob/main/index.js @@ -219,28 +221,28 @@ export function convertHeader(headers: Headers): IncomingHttpHeaders { // support require from Node.js 16 export function patchForNode16(): void { - if (typeof global.ReadableStream === 'undefined') { + if (global.ReadableStream === undefined) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore global.ReadableStream = ReadableStream; } - if (typeof global.TransformStream === 'undefined') { + if (global.TransformStream === undefined) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore global.TransformStream = TransformStream; } - if (typeof global.Blob === 'undefined') { + if (global.Blob === undefined) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore global.Blob = Blob; } - if (typeof global.DOMException === 'undefined') { + if (global.DOMException === undefined) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore global.DOMException = getDOMExceptionClass(); } // multi undici version in node version less than 20 https://github.com/nodejs/undici/issues/4374 - if (typeof global.File === 'undefined') { + if (global.File === undefined) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore global.File = File; @@ -285,7 +287,7 @@ function getDOMExceptionClass() { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore atob(0); - } catch (err: any) { - return err.constructor; + } catch (error: any) { + return error.constructor; } } diff --git a/test/HttpClient.test.ts b/test/HttpClient.test.ts index 39cef5a9..6ca72749 100644 --- a/test/HttpClient.test.ts +++ b/test/HttpClient.test.ts @@ -123,7 +123,7 @@ describe('HttpClient.test.ts', () => { ]); // console.log(httpClient.getDispatcherPoolStats()); assert.equal(httpClient.getDispatcherPoolStats()['https://registry.npmmirror.com'].connected, 4); - assert(httpClient.getDispatcherPoolStats()[_url.substring(0, _url.length - 1)].connected > 1); + assert(httpClient.getDispatcherPoolStats()[_url.slice(0, _url.length - 1)].connected > 1); }); it.skipIf(process.version.startsWith('v16.'))('should not exit after other side closed error', async () => { @@ -312,7 +312,9 @@ describe('HttpClient.test.ts', () => { const httpclient = new HttpClient({ checkAddress() { count++; - if (count === 1) return false; + if (count === 1) { + return false; + } return true; }, }); @@ -355,7 +357,9 @@ describe('HttpClient.test.ts', () => { }, checkAddress() { count++; - if (count === 1) return false; + if (count === 1) { + return false; + } return true; }, }); @@ -386,7 +390,9 @@ describe('HttpClient.test.ts', () => { const httpclient = new HttpClient({ checkAddress() { count++; - if (count === 1) return false; + if (count === 1) { + return false; + } return true; }, }); diff --git a/test/cjs/index.js b/test/cjs/index.js index e5248d13..0b1ccc86 100644 --- a/test/cjs/index.js +++ b/test/cjs/index.js @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -const { strict: assert } = require('assert'); +const { strict: assert } = require('node:assert'); const urllib = require('urllib'); const { request, HttpClient, USER_AGENT } = require('urllib'); diff --git a/test/diagnostics_channel.test.ts b/test/diagnostics_channel.test.ts index 623f6a34..05f21e88 100644 --- a/test/diagnostics_channel.test.ts +++ b/test/diagnostics_channel.test.ts @@ -48,7 +48,9 @@ describe('diagnostics_channel.test.ts', () => { } } const handler = request[kHandler]; - if (!handler) return; + if (!handler) { + return; + } let opaque = handler.opaque || handler.opts?.opaque; assert(opaque); opaque = opaque[symbols.kRequestOriginalOpaque]; diff --git a/test/esm/index.js b/test/esm/index.js index 680770a8..44d0b8f9 100644 --- a/test/esm/index.js +++ b/test/esm/index.js @@ -1,4 +1,4 @@ -import { strict as assert } from 'assert'; +import { strict as assert } from 'node:assert'; import * as urllibStar from 'urllib'; import urllib from 'urllib'; diff --git a/test/index.test.ts b/test/index.test.ts index 3c392e67..fdd1d3c7 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -203,7 +203,7 @@ describe('index.test.ts', () => { it('should mocking intercept work', async () => { assert.equal(typeof getGlobalDispatcher, 'function'); assert(getGlobalDispatcher()); - const mockPool = mockAgent.get(_url.substring(0, _url.length - 1)); + const mockPool = mockAgent.get(_url.slice(0, _url.length - 1)); mockPool .intercept({ path: '/foo', @@ -285,7 +285,7 @@ describe('index.test.ts', () => { }); it('should mocking intercept work with readable', async () => { - const mockPool = mockAgent.get(_url.substring(0, _url.length - 1)); + const mockPool = mockAgent.get(_url.slice(0, _url.length - 1)); // mock response stream mockPool .intercept({ @@ -324,7 +324,7 @@ describe('index.test.ts', () => { const oldAgent = httpClient.getDispatcher(); assert(oldAgent); httpClient.setDispatcher(mockAgent); - const mockPool = mockAgent.get(_url.substring(0, _url.length - 1)); + const mockPool = mockAgent.get(_url.slice(0, _url.length - 1)); mockPool .intercept({ path: '/foo', diff --git a/test/keep-alive-header.test.ts b/test/keep-alive-header.test.ts index 9386dc31..40dd1785 100644 --- a/test/keep-alive-header.test.ts +++ b/test/keep-alive-header.test.ts @@ -26,10 +26,10 @@ describe('keep-alive-header.test.ts', () => { it('should handle Keep-Alive header and not throw reset error on 1s keepalive agent', async () => { let count = 0; - const max = process.env.TEST_KEEPALIVE_COUNT ? parseInt(process.env.TEST_KEEPALIVE_COUNT) : 3; + const max = process.env.TEST_KEEPALIVE_COUNT ? Number.parseInt(process.env.TEST_KEEPALIVE_COUNT) : 3; let otherSideClosed = 0; let readECONNRESET = 0; - const origin = _url.substring(0, _url.length - 1); + const origin = _url.slice(0, _url.length - 1); while (count < max) { count++; try { @@ -91,7 +91,7 @@ describe('keep-alive-header.test.ts', () => { assert.equal(response.headers.connection, 'keep-alive'); assert.equal(response.headers['keep-alive'], 'timeout=2'); assert( - parseInt(response.headers['x-requests-persocket'] as string) >= 1, + Number.parseInt(response.headers['x-requests-persocket'] as string) >= 1, response.headers['x-requests-persocket'] as string, ); await sleep(keepAliveTimeout / 2); @@ -138,7 +138,7 @@ describe('keep-alive-header.test.ts', () => { assert.equal(response.headers.connection, 'keep-alive'); assert.equal(response.headers['keep-alive'], 'timeout=2'); assert( - parseInt(response.headers['x-requests-persocket'] as string) >= 1, + Number.parseInt(response.headers['x-requests-persocket'] as string) >= 1, response.headers['x-requests-persocket'] as string, ); // console.log('before sleep stats: %o', httpClient.getDispatcherPoolStats()); @@ -160,15 +160,15 @@ describe('keep-alive-header.test.ts', () => { assert(httpClient.getDispatcherPoolStats()[origin].free <= 2); assert.equal(httpClient.getDispatcherPoolStats()[origin].size, 0); } - } catch (err: any) { - if (err.message === 'other side closed') { - console.log(err); + } catch (error: any) { + if (error.message === 'other side closed') { + console.log(error); otherSideClosed++; - } else if (err.message === 'read ECONNRESET') { - console.log(err); + } else if (error.message === 'read ECONNRESET') { + console.log(error); readECONNRESET++; } else { - throw err; + throw error; } } } diff --git a/test/options.data.test.ts b/test/options.data.test.ts index 422e1407..61d4ee1c 100644 --- a/test/options.data.test.ts +++ b/test/options.data.test.ts @@ -87,7 +87,7 @@ describe('options.data.test.ts', () => { response.data.url, '/?sql=SELECT%20%2A%20from%20table&data=%E5%93%88%E5%93%88&foo%5Bbar%5D=bar%20value&foo%5Barray%5D%5B0%5D=1&foo%5Barray%5D%5B1%5D=2&foo%5Barray%5D%5B2%5D=3', ); - const query = qs.parse(response.data.url.substring(2)); + const query = qs.parse(response.data.url.slice(2)); const url = new URL(response.data.href); assert.equal(url.searchParams.get('sql'), 'SELECT * from table'); assert.equal(url.searchParams.get('data'), '哈哈'); @@ -127,7 +127,7 @@ describe('options.data.test.ts', () => { response.data.url, '/ok?hello=1&sql=SELECT%20%2A%20from%20table&data=%E5%93%88%E5%93%88&foo%5Bbar%5D=bar%20value&foo%5Barray%5D%5B0%5D=1&foo%5Barray%5D%5B1%5D=2&foo%5Barray%5D%5B2%5D=3', ); - const query = qs.parse(response.data.url.substring(4)); + const query = qs.parse(response.data.url.slice(4)); const url = new URL(response.data.href); assert.equal(url.searchParams.get('hello'), '1'); assert.equal(url.searchParams.get('sql'), 'SELECT * from table'); diff --git a/test/options.dataType.test.ts b/test/options.dataType.test.ts index 520fc33c..abf3e42a 100644 --- a/test/options.dataType.test.ts +++ b/test/options.dataType.test.ts @@ -114,17 +114,17 @@ describe('options.dataType.test.ts', () => { if (nodeMajorVersion() >= 21) { assert.equal( err.message, - 'Expected \',\' or \'}\' after property value in JSON at position 9 (line 1 column 10) (data json format: "{\\"foo\\":\\"\\"")', + String.raw`Expected ',' or '}' after property value in JSON at position 9 (line 1 column 10) (data json format: "{\"foo\":\"\"")`, ); } else { // new message on Node.js >= 19 assert.equal( err.message, - 'Expected \',\' or \'}\' after property value in JSON at position 9 (data json format: "{\\"foo\\":\\"\\"")', + String.raw`Expected ',' or '}' after property value in JSON at position 9 (data json format: "{\"foo\":\"\"")`, ); } } else { - assert.equal(err.message, 'Unexpected end of JSON input (data json format: "{\\"foo\\":\\"\\"")'); + assert.equal(err.message, String.raw`Unexpected end of JSON input (data json format: "{\"foo\":\"\"")`); } assert.equal(err.res.status, 200); assert.equal(err.res.headers['content-type'], 'application/json'); diff --git a/test/options.digestAuth.test.ts b/test/options.digestAuth.test.ts index 442ed790..2774b934 100644 --- a/test/options.digestAuth.test.ts +++ b/test/options.digestAuth.test.ts @@ -89,7 +89,7 @@ describe('options.digestAuth.test.ts', () => { const response = await urllib.request(url, { digestAuth: 'user:passwd', dataType: 'json', - timeout: 10000, + timeout: 10_000, }); console.log(response.headers); assert.equal(response.status, 200); @@ -104,7 +104,7 @@ describe('options.digestAuth.test.ts', () => { const response = await urllib.request(url, { digestAuth: 'user:passwdfail', dataType: 'json', - timeout: 10000, + timeout: 10_000, }); // console.log(response.headers); assert(response.headers['www-authenticate']); diff --git a/test/options.dispatcher.test.ts b/test/options.dispatcher.test.ts index e737afc0..49626d2d 100644 --- a/test/options.dispatcher.test.ts +++ b/test/options.dispatcher.test.ts @@ -76,7 +76,7 @@ describe('options.dispatcher.test.ts', () => { dataType: 'json', timing: true, dispatcher: agent, - timeout: 30000, + timeout: 30_000, }); assert.equal(response.status, 200); assert.match(response.headers['content-type'] ?? '', /application\/json/); diff --git a/test/options.files.test.ts b/test/options.files.test.ts index 240bba6f..6813d91e 100644 --- a/test/options.files.test.ts +++ b/test/options.files.test.ts @@ -233,11 +233,11 @@ describe('options.files.test.ts', () => { it('should upload a file with args.data success', async () => { const stat = await fs.stat(__filename); - const largeFormValue = await fs.readFile(__filename, 'utf-8'); + const largeFormValue = await fs.readFile(__filename, 'utf8'); const txtEmoji = path.join(__dirname, 'fixtures', '😄foo😭.txt'); const txtEmojiStat = await fs.stat(txtEmoji); const txt = path.join(__dirname, 'fixtures', 'foo.txt'); - const txtValue = await fs.readFile(txt, 'utf-8'); + const txtValue = await fs.readFile(txt, 'utf8'); const response = await urllib.request(`${_url}multipart`, { method: 'HEAD', files: [__filename, txtEmoji], diff --git a/test/options.fixJSONCtlChars.test.ts b/test/options.fixJSONCtlChars.test.ts index cd8f6b29..d2fb20bc 100644 --- a/test/options.fixJSONCtlChars.test.ts +++ b/test/options.fixJSONCtlChars.test.ts @@ -53,7 +53,7 @@ describe('options.fixJSONCtlChars.test.ts', () => { const response = await urllib.request(`${_url}json_with_t`, { dataType: 'json', fixJSONCtlChars(str) { - return str.replace(/\t/g, '\\t'); + return str.replaceAll('\t', String.raw`\t`); }, }); assert.equal(response.status, 200); diff --git a/test/options.followRedirect.test.ts b/test/options.followRedirect.test.ts index c03683fb..b9961ad6 100644 --- a/test/options.followRedirect.test.ts +++ b/test/options.followRedirect.test.ts @@ -139,7 +139,7 @@ describe('options.followRedirect.test.ts', () => { it('should disable auto redirect', async () => { const requestURL = `${_url}redirect-full-301`; const { data, res, redirected, url } = await urllib.request(requestURL, { - timeout: 30000, + timeout: 30_000, followRedirect: false, dataType: 'text', }); diff --git a/test/options.retry.test.ts b/test/options.retry.test.ts index a00c8176..48d4a4cd 100644 --- a/test/options.retry.test.ts +++ b/test/options.retry.test.ts @@ -78,7 +78,7 @@ describe('options.retry.test.ts', () => { assert.equal(response.data, 'Mock status 500'); let requestHeaders = JSON.parse(response.headers['x-request-headers'] as string); assert.equal(requestHeaders['x-urllib-retry'], '2/2'); - assert(parseInt(response.headers['x-requests-persocket'] as string) >= 2); + assert(Number.parseInt(response.headers['x-requests-persocket'] as string) >= 2); // console.log(response.headers); response = await urllib.request(`${_url}mock-status?status=500`, { @@ -90,7 +90,7 @@ describe('options.retry.test.ts', () => { // console.log(response.headers); requestHeaders = JSON.parse(response.headers['x-request-headers'] as string); assert.equal(requestHeaders['x-urllib-retry'], '1/1'); - assert(parseInt(response.headers['x-requests-persocket'] as string) >= 2); + assert(Number.parseInt(response.headers['x-requests-persocket'] as string) >= 2); response = await urllib.request(`${_url}mock-status?status=500`, { dataType: 'text', @@ -101,7 +101,7 @@ describe('options.retry.test.ts', () => { // console.log(response.headers); requestHeaders = JSON.parse(response.headers['x-request-headers'] as string); assert.equal(requestHeaders['x-urllib-retry'], '5/5'); - assert(parseInt(response.headers['x-requests-persocket'] as string) >= 2); + assert(Number.parseInt(response.headers['x-requests-persocket'] as string) >= 2); }); it('should custom isRetry', async () => { diff --git a/test/options.stream.test.ts b/test/options.stream.test.ts index a9e79109..062785e5 100644 --- a/test/options.stream.test.ts +++ b/test/options.stream.test.ts @@ -53,7 +53,7 @@ describe('options.stream.test.ts', () => { assert.equal(response.data.headers['transfer-encoding'], 'chunked'); } assert.match(response.data.requestBody, /\('should post with stream', async \(\) => {/); - const raw = await readFile(__filename, 'utf-8'); + const raw = await readFile(__filename, 'utf8'); assert.equal(response.data.requestBody, raw); }); @@ -76,7 +76,7 @@ describe('options.stream.test.ts', () => { assert.equal(response2.status, 200); assert(!response2.headers['content-type']); assert.match(response2.data.requestBody, /\('should post with stream', async \(\) => {/); - const raw = await readFile(__filename, 'utf-8'); + const raw = await readFile(__filename, 'utf8'); assert.equal(response2.data.requestBody, raw); }); @@ -120,7 +120,9 @@ describe('options.stream.test.ts', () => { // console.error(err); assert.equal(err.name, 'HttpClientRequestTimeoutError'); assert.equal(err.message, 'Request timeout for 100 ms'); - err.cause && assert.equal(err.cause.name, 'HeadersTimeoutError'); + if (err.cause) { + assert.equal(err.cause.name, 'HeadersTimeoutError'); + } // stream should be close after request error fire assert.equal(stream.destroyed, true); return true; @@ -145,7 +147,9 @@ describe('options.stream.test.ts', () => { // console.error(err); assert.equal(err.name, 'HttpClientRequestTimeoutError'); assert.equal(err.message, 'Request timeout for 100 ms'); - err.cause && assert.equal(err.cause.name, 'HeadersTimeoutError'); + if (err.cause) { + assert.equal(err.cause.name, 'HeadersTimeoutError'); + } // stream should be close after request error fire assert.equal(stream.destroyed, true); return true; diff --git a/test/options.streaming.test.ts b/test/options.streaming.test.ts index 3698bf3d..78c76316 100644 --- a/test/options.streaming.test.ts +++ b/test/options.streaming.test.ts @@ -146,7 +146,7 @@ describe('options.streaming.test.ts', () => { // console.log(response.headers); assert(isReadable(response.res as any)); const bytes = await readableToBytes(response.res); - assert.equal(bytes.length, 1024102400); + assert.equal(bytes.length, 1_024_102_400); }); it('should save big streaming response with highWaterMark', async () => { diff --git a/test/options.timeout.test.ts b/test/options.timeout.test.ts index 4cefec6c..a8367681 100644 --- a/test/options.timeout.test.ts +++ b/test/options.timeout.test.ts @@ -152,7 +152,9 @@ describe('options.timeout.test.ts', () => { assert.equal(err.name, 'HttpClientRequestTimeoutError'); assert.equal(err.message, 'Request timeout for 500 ms'); assert.equal(err.res.status, 200); - err.cause && assert.equal(err.cause.name, 'BodyTimeoutError'); + if (err.cause) { + assert.equal(err.cause.name, 'BodyTimeoutError'); + } return true; }, ); @@ -172,7 +174,9 @@ describe('options.timeout.test.ts', () => { assert.equal(err.res!.status, -1); assert(err.headers); assert.equal(err.status, -1); - err.cause && assert.equal((err.cause as any).name, 'HeadersTimeoutError'); + if (err.cause) { + assert.equal((err.cause as any).name, 'HeadersTimeoutError'); + } return true; }, ); diff --git a/test/options.writeStream.test.ts b/test/options.writeStream.test.ts index 35b333f6..897a3a39 100644 --- a/test/options.writeStream.test.ts +++ b/test/options.writeStream.test.ts @@ -45,7 +45,7 @@ describe('options.writeStream.test.ts', () => { // console.log(response.headers); assert.equal(response.headers['content-length'], '1024123'); const stats = await stat(tmpfile); - assert.equal(stats.size, 1024123); + assert.equal(stats.size, 1_024_123); }); it('should work with compressed=true/false', async () => { @@ -59,7 +59,7 @@ describe('options.writeStream.test.ts', () => { assert.equal(response.data, null); // console.log(response.headers); // writeStream is decompressed - let data = await readFile(tmpfile, 'utf-8'); + let data = await readFile(tmpfile, 'utf8'); assert.match(data, /export async function startServer/); writeStream = createWriteStream(tmpfile); diff --git a/test/urllib.bench.ts b/test/urllib.bench.ts index 23e385cf..77b15131 100644 --- a/test/urllib.bench.ts +++ b/test/urllib.bench.ts @@ -11,7 +11,7 @@ describe('HttpClient Benchmarks', () => { bench('create HttpClient with defaultArgs', () => { new HttpClient({ defaultArgs: { - timeout: 30000, + timeout: 30_000, headers: { 'x-custom-header': 'benchmark', }, @@ -22,7 +22,7 @@ describe('HttpClient Benchmarks', () => { bench('create HttpClient with connect options', () => { new HttpClient({ connect: { - timeout: 10000, + timeout: 10_000, rejectUnauthorized: true, }, }); diff --git a/test/urllib.options.allowH2.test.ts b/test/urllib.options.allowH2.test.ts index 52be0ca4..755542d5 100644 --- a/test/urllib.options.allowH2.test.ts +++ b/test/urllib.options.allowH2.test.ts @@ -11,7 +11,7 @@ describe('urllib.options.allowH2.test.ts', () => { allowH2: true, dataType: 'json', retry: 3, - timeout: 30000, + timeout: 30_000, }); assert.equal(response.status, 200); @@ -19,7 +19,7 @@ describe('urllib.options.allowH2.test.ts', () => { allowH2: true, dataType: 'json', retry: 3, - timeout: 30000, + timeout: 30_000, }); assert.equal(response.status, 200); }); diff --git a/test/utils.ts b/test/utils.ts index bf1d621c..96d53ddc 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -6,7 +6,7 @@ import { Readable } from 'node:stream'; import { ReadableStream } from 'node:stream/web'; export async function readableToBytes(stream: Readable | ReadableStream): Promise { - const chunks: Buffer[] = []; + const chunks: Array = []; let chunk: Buffer; for await (chunk of stream) { chunks.push(chunk); @@ -38,7 +38,7 @@ export async function createTempfile( } export function nodeMajorVersion(): number { - return parseInt(process.versions.node.split('.')[0]); + return Number.parseInt(process.versions.node.split('.')[0]); } export function isWindows(): boolean { diff --git a/vite.config.ts b/vite.config.ts index d8335399..941b38a8 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -154,7 +154,7 @@ export default defineConfig({ // plugins: [codspeedPlugin()], test: { include: ['test/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], - testTimeout: 60000, + testTimeout: 60_000, coverage: { include: ['src'], },