diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..490b37c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 +indent_style = space +indent_size = 2 \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..81e9305 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "bracketSpacing": false, + "printWidth": 80, + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "none", + "useTabs": false, + "arrowParens": "always" +} \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..703dffe --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,9 @@ +import js from '@eslint/js'; +import mocha from 'eslint-plugin-mocha'; +export default [ + mocha.configs.flat.recommended, + { + ...js.configs.recommended, + files: ['**/*.js'] + } +]; diff --git a/index.js b/index.js index 355127d..c134387 100644 --- a/index.js +++ b/index.js @@ -1,2 +1,2 @@ -import fn from "./lib/http.js"; +import fn from './lib/http.js'; export default fn; diff --git a/lib/http.js b/lib/http.js index bdcd043..4c05aab 100644 --- a/lib/http.js +++ b/lib/http.js @@ -14,13 +14,12 @@ /*! * Module dependencies. */ -import net from "net" -import url from "url" -import Cookie from "cookiejar" -import charset from "charset" -import qs from "qs" -import * as _request from "./request.js" - +import net from 'net'; +import url from 'url'; +import Cookie from 'cookiejar'; +import charset from 'charset'; +import qs from 'qs'; +import * as _request from './request.js'; /** * @@ -28,13 +27,12 @@ import * as _request from "./request.js" * @param {ChaiUtils} _ */ export default function (chai, _) { - /*! * Aliases. */ - var Assertion = chai.Assertion - , i = _.inspect; + const Assertion = chai.Assertion; + const i = _.inspect; /*! * Expose request builder @@ -49,10 +47,10 @@ export default function (chai, _) { * @type {Object} */ - var contentTypes = { - json: 'application/json' - , text: 'text/plain' - , html: 'text/html' + const contentTypes = { + json: 'application/json', + text: 'text/plain', + html: 'text/html' }; /*! @@ -67,7 +65,7 @@ export default function (chai, _) { if (key) key = key.toLowerCase(); if (obj.getHeader) return obj.getHeader(key); if (obj.headers) return obj.headers[key]; - }; + } /** * ### .status (code) @@ -84,24 +82,26 @@ export default function (chai, _) { */ Assertion.addMethod('status', function (code) { - var hasStatus = Boolean('status' in this._obj || 'statusCode' in this._obj); + const hasStatus = Boolean( + 'status' in this._obj || 'statusCode' in this._obj + ); new Assertion(hasStatus).assert( - hasStatus - , "expected #{act} to have keys 'status', or 'statusCode'" - , null // never negated - , hasStatus // expected - , this._obj // actual - , false // no diff + hasStatus, + "expected #{act} to have keys 'status', or 'statusCode'", + null, // never negated + hasStatus, // expected + this._obj, // actual + false // no diff ); - var status = this._obj.status || this._obj.statusCode; + const status = this._obj.status || this._obj.statusCode; this.assert( - status == code - , 'expected #{this} to have status code #{exp} but got #{act}' - , 'expected #{this} to not have status code #{act}' - , code - , status + status == code, + 'expected #{this} to have status code #{exp} but got #{act}', + 'expected #{this} to not have status code #{act}', + code, + status ); }); @@ -131,29 +131,44 @@ export default function (chai, _) { */ Assertion.addMethod('header', function (key, value) { - var header = getHeader(this._obj, key); + const header = getHeader(this._obj, key); if (arguments.length < 2) { this.assert( - 'undefined' !== typeof header || null === header - , 'expected header \'' + key + '\' to exist' - , 'expected header \'' + key + '\' to not exist' + 'undefined' !== typeof header || null === header, + "expected header '" + key + "' to exist", + "expected header '" + key + "' to not exist" ); } else if (arguments[1] instanceof RegExp) { this.assert( - value.test(header) - , 'expected header \'' + key + '\' to match ' + value + ' but got ' + i(header) - , 'expected header \'' + key + '\' not to match ' + value + ' but got ' + i(header) - , value - , header + value.test(header), + "expected header '" + + key + + "' to match " + + value + + ' but got ' + + i(header), + "expected header '" + + key + + "' not to match " + + value + + ' but got ' + + i(header), + value, + header ); } else { this.assert( - header == value - , 'expected header \'' + key + '\' to have value ' + value + ' but got ' + i(header) - , 'expected header \'' + key + '\' to not have value ' + value - , value - , header + header == value, + "expected header '" + + key + + "' to have value " + + value + + ' but got ' + + i(header), + "expected header '" + key + "' to not have value " + value, + value, + header ); } }); @@ -179,9 +194,9 @@ export default function (chai, _) { Assertion.addProperty('headers', function () { this.assert( - this._obj.headers || this._obj.getHeader - , 'expected #{this} to have headers or getHeader method' - , 'expected #{this} to not have headers or getHeader method' + this._obj.headers || this._obj.getHeader, + 'expected #{this} to have headers or getHeader method', + 'expected #{this} to not have headers or getHeader method' ); }); @@ -201,9 +216,9 @@ export default function (chai, _) { Assertion.addProperty('ip', function () { this.assert( - net.isIP(this._obj) - , 'expected #{this} to be an ip' - , 'expected #{this} to not be an ip' + net.isIP(this._obj), + 'expected #{this} to be an ip', + 'expected #{this} to not be an ip' ); }); @@ -224,27 +239,23 @@ export default function (chai, _) { * @api public */ - function checkContentType (name) { - var val = contentTypes[name]; + function checkContentType(name) { + const val = contentTypes[name]; Assertion.addProperty(name, function () { new Assertion(this._obj).to.have.headers; - var ct = getHeader(this._obj, 'content-type') - , ins = i(ct) === 'undefined' - ? 'headers' - : i(ct); + const ct = getHeader(this._obj, 'content-type'), + ins = i(ct) === 'undefined' ? 'headers' : i(ct); this.assert( - ct && ~ct.indexOf(val) - , 'expected ' + ins + ' to include \'' + val + '\'' - , 'expected ' + ins + ' to not include \'' + val + '\'' + ct && ~ct.indexOf(val), + 'expected ' + ins + " to include '" + val + "'", + 'expected ' + ins + " to not include '" + val + "'" ); }); } - Object - .keys(contentTypes) - .forEach(checkContentType); + Object.keys(contentTypes).forEach(checkContentType); /** * ### .charset @@ -262,22 +273,22 @@ export default function (chai, _) { Assertion.addMethod('charset', function (value) { value = value.toLowerCase(); - var headers = this._obj.headers; - var cs = charset(headers); + const headers = this._obj.headers; + let cs = charset(headers); /* * Fix charset() treating "utf8" as a special case * See https://github.com/node-modules/charset/issues/12 */ - if (cs === "utf8") { - cs = "utf-8"; + if (cs === 'utf8') { + cs = 'utf-8'; } this.assert( - cs != null && value === cs - , 'expected content type to have ' + value + ' charset' - , 'expected content type to not have ' + value + ' charset' - ) + cs != null && value === cs, + 'expected content type to have ' + value + ' charset', + 'expected content type to not have ' + value + ' charset' + ); }); /** @@ -293,15 +304,15 @@ export default function (chai, _) { * @api public */ - Assertion.addProperty('redirect', function() { - var redirectCodes = [301, 302, 303, 307, 308] - , status = this._obj.status - , redirects = this._obj.redirects; + Assertion.addProperty('redirect', function () { + const redirectCodes = [301, 302, 303, 307, 308], + status = this._obj.status, + redirects = this._obj.redirects; this.assert( - redirectCodes.indexOf(status) >= 0 || redirects && redirects.length - , "expected redirect with 30X status code but got " + status - , "expected not to redirect but got " + status + " status" + redirectCodes.indexOf(status) >= 0 || (redirects && redirects.length), + 'expected redirect with 30X status code but got ' + status, + 'expected not to redirect but got ' + status + ' status' ); }); @@ -319,27 +330,34 @@ export default function (chai, _) { * @api public */ - Assertion.addMethod('redirectTo', function(destination) { - var redirects = this._obj.redirects; + Assertion.addMethod('redirectTo', function (destination) { + const redirects = this._obj.redirects; new Assertion(this._obj).to.redirect; - if(redirects && redirects.length) { - var hasRedirected; + if (redirects && redirects.length) { + let hasRedirected; if (Object.prototype.toString.call(destination) === '[object RegExp]') { - hasRedirected = redirects.some(redirect => destination.test(redirect)); - + hasRedirected = redirects.some((redirect) => + destination.test(redirect) + ); } else { hasRedirected = redirects.indexOf(destination) > -1; } this.assert( - hasRedirected - , 'expected redirect to ' + destination + ' but got ' + redirects.join(' then ') - , 'expected not to redirect to ' + destination + ' but got ' + redirects.join(' then ') + hasRedirected, + 'expected redirect to ' + + destination + + ' but got ' + + redirects.join(' then '), + 'expected not to redirect to ' + + destination + + ' but got ' + + redirects.join(' then ') ); } else { - var assertion = new Assertion(this._obj); + const assertion = new Assertion(this._obj); _.transferFlags(this, assertion); assertion.with.header('location', destination); } @@ -363,8 +381,8 @@ export default function (chai, _) { * @api public */ - Assertion.addMethod('param', function(name, value) { - var assertion = new Assertion(); + Assertion.addMethod('param', function (name, value) { + const assertion = new Assertion(); _.transferFlags(this, assertion); assertion._obj = qs.parse(url.parse(this._obj.url).query); assertion.property.apply(assertion, arguments); @@ -395,11 +413,11 @@ export default function (chai, _) { */ Assertion.addMethod('cookie', function (key, value) { - var header = getHeader(this._obj, 'set-cookie') - , cookie; + let header = getHeader(this._obj, 'set-cookie'), + cookie; if (!header) { - header = (getHeader(this._obj, 'cookie') || '').split(';'); + header = (getHeader(this._obj, 'cookie') || '').split(';'); } if (this._obj instanceof chai.request.agent && this._obj.jar) { @@ -412,18 +430,18 @@ export default function (chai, _) { if (arguments.length === 2) { this.assert( - cookie.value == value - , 'expected cookie \'' + key + '\' to have value #{exp} but got #{act}' - , 'expected cookie \'' + key + '\' to not have value #{exp}' - , value - , cookie.value + cookie.value == value, + "expected cookie '" + key + "' to have value #{exp} but got #{act}", + "expected cookie '" + key + "' to not have value #{exp}", + value, + cookie.value ); } else { this.assert( - 'undefined' !== typeof cookie || null === cookie - , 'expected cookie \'' + key + '\' to exist' - , 'expected cookie \'' + key + '\' to not exist' + 'undefined' !== typeof cookie || null === cookie, + "expected cookie '" + key + "' to exist", + "expected cookie '" + key + "' to not exist" ); } }); -}; +} diff --git a/lib/net.js b/lib/net.js index 1ea447b..1b69218 100644 --- a/lib/net.js +++ b/lib/net.js @@ -7,8 +7,4 @@ /*! * net.isIP shim for browsers */ -import isIP from 'is-ip'; - -exports.isIP = isIP; -exports.isIPv4 = isIP.isIPv4; -exports.isIPv6 = isIP.isIPv6; +export {isIP, isIPv4, isIPv6} from 'is-ip'; diff --git a/lib/request.js b/lib/request.js index 8ee76bd..56cac2a 100644 --- a/lib/request.js +++ b/lib/request.js @@ -7,11 +7,11 @@ /*! * Module dependancies */ -import superagent from "superagent" -import http from "http" -import https from "https" -import methods from "methods" -import util from "util" +import superagent from 'superagent'; +import http from 'http'; +import https from 'https'; +import methods from 'methods'; +import util from 'util'; const Agent = superagent.agent; const Request = superagent.Request; @@ -173,7 +173,7 @@ const Request = superagent.Request; * if (!global.Promise) { * global.Promise = require('q'); * } - * var chai = require('chai'); + * const chai = require('chai'); * chai.use(require('chai-http')); * * ``` @@ -185,7 +185,7 @@ const Request = superagent.Request; * * ```js * // Log in - * var agent = chai.request.agent(app) + * const agent = chai.request.agent(app) * agent * .post('/session') * .send({ username: 'me', password: '123' }) @@ -207,51 +207,46 @@ const Request = superagent.Request; * @param {ChaiHttpRequest} app * @returns {ChaiHttp.Agent} */ -function execute (app) { - +function execute(app) { /*! * @param {Mixed} function or server * @returns {Object} API */ - var server = ('function' === typeof app) - ? http.createServer(app) - : app - , obj = {}; + let server = 'function' === typeof app ? http.createServer(app) : app, + obj = {}; - var keepOpen = false + let keepOpen = false; if (typeof server !== 'string' && server && server.listen && server.address) { if (!server.address()) { - server = server.listen(0) + server = server.listen(0); } } - obj.keepOpen = function() { - keepOpen = true - return this - } - obj.close = function(callback) { + obj.keepOpen = function () { + keepOpen = true; + return this; + }; + obj.close = function (callback) { if (server && server.close) { server.close(callback); - } - else if(callback) { + } else if (callback) { callback(); } - - return this - } + + return this; + }; methods.forEach(function (method) { obj[method] = function (path) { - return new Test(server, method, path) - .on('end', function() { - if(keepOpen === false) { - obj.close(); - } - }); + return new Test(server, method, path).on('end', function () { + if (keepOpen === false) { + obj.close(); + } + }); }; }); obj.del = obj.delete; return obj; -}; +} /*! * Test @@ -266,25 +261,25 @@ function execute (app) { * @api private */ -function Test (app, method, path) { +function Test(app, method, path) { Request.call(this, method, path); this.app = app; this.url = typeof app === 'string' ? app + path : serverAddress(app, path); - this.ok(function() { + this.ok(function () { return true; }); } util.inherits(Test, Request); -function serverAddress (app, path) { +function serverAddress(app, path) { if ('string' === typeof app) { return app + path; } - var addr = app.address(); + const addr = app.address(); if (!addr) { - throw new Error('Server is not listening') + throw new Error('Server is not listening'); } - var protocol = (app instanceof https.Server) ? 'https' : 'http'; + const protocol = app instanceof https.Server ? 'https' : 'http'; // If address is "unroutable" IPv4/6 address, then set to localhost if (addr.address === '0.0.0.0' || addr.address === '::') { addr.address = '127.0.0.1'; @@ -292,7 +287,6 @@ function serverAddress (app, path) { return protocol + '://' + addr.address + ':' + addr.port + path; } - /*! * agent * @@ -305,43 +299,54 @@ function serverAddress (app, path) { * @api private */ -function TestAgent(app, options={}) { +function TestAgent(app, options = {}) { if (!(this instanceof TestAgent)) return new TestAgent(app); if (typeof app === 'function') app = http.createServer(app); const agent = new Agent(options); Object.assign(this, agent); this.app = app; - if (typeof app !== 'string' && app && app.listen && app.address && !app.address()) { - this.app = app.listen(0) + if ( + typeof app !== 'string' && + app && + app.listen && + app.address && + !app.address() + ) { + this.app = app.listen(0); } } util.inherits(TestAgent, Agent || Request); TestAgent.prototype.close = function close(callback) { if (this.app && this.app.close) { - this.app.close(callback) + this.app.close(callback); } - return this -} + return this; +}; TestAgent.prototype.keepOpen = function keepOpen() { - return this -} + return this; +}; // override HTTP verb methods -methods.forEach(function(method){ - TestAgent.prototype[method] = function(url){ - var req = new Test(this.app, method, url) - , self = this; +methods.forEach(function (method) { + TestAgent.prototype[method] = function (url) { + const req = new Test(this.app, method, url), + self = this; if (Agent) { // When running in Node, cookies are managed via // `Agent._saveCookies()` and `Agent._attachCookies()`. - req.on('response', function (res) { self._saveCookies(res); }); - req.on('redirect', function (res) { self._saveCookies(res); }); - req.on('redirect', function () { self._attachCookies(req); }); + req.on('response', function (res) { + self._saveCookies(res); + }); + req.on('redirect', function (res) { + self._saveCookies(res); + }); + req.on('redirect', function () { + self._attachCookies(req); + }); this._attachCookies(req); - } - else { + } else { // When running in a web browser, cookies are managed via `Request.withCredentials()`. // The browser will attach cookies based on same-origin policy. // https://tools.ietf.org/html/rfc6454#section-3 @@ -354,8 +359,4 @@ methods.forEach(function(method){ TestAgent.prototype.del = TestAgent.prototype.delete; -export { - execute, - Test as Request, - TestAgent as agent -} +export {execute, Test as Request, TestAgent as agent}; diff --git a/package-lock.json b/package-lock.json index 922151b..e34f401 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "superagent": "^9" }, "devDependencies": { + "@eslint/js": "^9.3.0", "@semantic-release/changelog": "^6", "@semantic-release/commit-analyzer": "^12.0.0", "@semantic-release/git": "^10", @@ -26,10 +27,13 @@ "@types/superagent": "^8.1.7", "chai": "^5.1.0", "coveralls": "^3.1.1", + "eslint": "^9.3.0", + "eslint-plugin-mocha": "^10.4.3", "http-server": "^14.1.1", "mocha": "^10.4.0", "npm-run-all": "^4.1.5", "nyc": "^15.1.0", + "prettier": "^3.2.5", "semantic-release": "^23.0.8", "typescript": "^5.4.5" }, @@ -489,6 +493,138 @@ "node": ">=0.1.90" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/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==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/js": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.3.0.tgz", + "integrity": "sha512-niBqk8iwv96+yuTwjM6bWg8ovzAPF9qkICsGtcoa5/dmqcEMfdwNAX7+/OHcJHc7wj7XqPxH98oAHytFYlw6Sw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1383,6 +1519,27 @@ "@types/node": "*" } }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/agent-base": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", @@ -2383,6 +2540,12 @@ "node": ">=4.0.0" } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "node_modules/default-require-extensions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", @@ -2832,6 +2995,185 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.3.0.tgz", + "integrity": "sha512-5Iv4CsZW030lpUqHBapdPo3MJetAPtejVW8B84GIcIIv8+ohFaddXsrn1Gn8uD9ijDb+kcYKFUVmC8qG8B2ORQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.3.0", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.1", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-mocha": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.4.3.tgz", + "integrity": "sha512-emc4TVjq5Ht0/upR+psftuz6IBG5q279p+1dSRDeHf+NS9aaerBi3lXKo1SEzwC29hFIW21gO89CEWSvRsi8IQ==", + "dev": true, + "dependencies": { + "eslint-utils": "^3.0.0", + "globals": "^13.24.0", + "rambda": "^7.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-mocha/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-mocha/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", + "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/espree": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -2845,6 +3187,48 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -2929,6 +3313,12 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, "node_modules/fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", @@ -2970,6 +3360,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -3080,6 +3482,25 @@ "flat": "cli.js" } }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, "node_modules/follow-redirects": { "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", @@ -3425,6 +3846,18 @@ "node": ">= 6" } }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globalthis": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", @@ -4131,6 +4564,15 @@ "node": ">=8" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -4473,6 +4915,12 @@ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -4497,6 +4945,12 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -4567,6 +5021,15 @@ "node": ">=0.6.0" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/lcov-parse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", @@ -4576,6 +5039,19 @@ "lcov-parse": "bin/cli.js" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -4676,6 +5152,12 @@ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", "dev": true }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "node_modules/lodash.uniqby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", @@ -5053,6 +5535,12 @@ "thenify-all": "^1.0.0" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -8260,6 +8748,23 @@ "opener": "bin/opener-bin.js" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/p-each-series": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz", @@ -8717,6 +9222,30 @@ "node": ">= 0.4" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -8781,6 +9310,12 @@ } ] }, + "node_modules/rambda": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/rambda/-/rambda-7.5.0.tgz", + "integrity": "sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA==", + "dev": true + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -10182,6 +10717,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -10292,6 +10833,18 @@ "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -10680,6 +11233,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", diff --git a/package.json b/package.json index 412d84a..f252ccb 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,8 @@ "server": "http-server -o -c-1", "test": "nyc --reporter=lcovonly --reporter=text-summary mocha", "coverage": "if [ -z \"$COVERALLS_REPO_TOKEN\" ]; then cat coverage/lcov.info | coveralls; fi", - "release": "npm run build && semantic-release" + "release": "npm run build && semantic-release", + "eslint": "eslint" }, "browser": { "http": false, @@ -55,6 +56,7 @@ "superagent": "^9" }, "devDependencies": { + "@eslint/js": "^9.3.0", "@semantic-release/changelog": "^6", "@semantic-release/commit-analyzer": "^12.0.0", "@semantic-release/git": "^10", @@ -64,10 +66,13 @@ "@types/superagent": "^8.1.7", "chai": "^5.1.0", "coveralls": "^3.1.1", + "eslint": "^9.3.0", + "eslint-plugin-mocha": "^10.4.3", "http-server": "^14.1.1", "mocha": "^10.4.0", "npm-run-all": "^4.1.5", "nyc": "^15.1.0", + "prettier": "^3.2.5", "semantic-release": "^23.0.8", "typescript": "^5.4.5" }, diff --git a/test/bootstrap/index.js b/test/bootstrap/index.js index c3069f4..52b0f9f 100644 --- a/test/bootstrap/index.js +++ b/test/bootstrap/index.js @@ -1,5 +1,5 @@ import * as originalChai from 'chai'; -import * as http from "http"; +import * as http from 'http'; import project from '../../index.js'; global.http = http; @@ -7,4 +7,4 @@ global.http = http; global.should = originalChai.should(); global.expect = originalChai.expect; -global["chai"] = originalChai.use(project); +global['chai'] = originalChai.use(project); diff --git a/test/http.js b/test/http.js index 71a7670..9c45f9f 100644 --- a/test/http.js +++ b/test/http.js @@ -1,7 +1,6 @@ describe('assertions', function () { - it('#status property "status"', function () { - var res = { status: 200 }; + const res = {status: 200}; res.should.to.have.status(200); (function () { @@ -14,14 +13,14 @@ describe('assertions', function () { }); it('#status property "statusCode"', function () { - var res = { statusCode: 200 }; + const res = {statusCode: 200}; res.should.to.have.status(200); }); it('#status property "status" should work with inheritance', function () { - function TestError() {}; + function TestError() {} TestError.prototype.status = 404; - var testError = new TestError(); + const testError = new TestError(); testError.should.have.status(404); }); @@ -31,16 +30,18 @@ describe('assertions', function () { (function () { '127.0.0.1'.should.not.be.an.ip; - }).should.throw('expected \'127.0.0.1\' to not be an ip'); + }).should.throw("expected '127.0.0.1' to not be an ip"); (function () { '2001:0db8:85a3:0000:0000:8a2e:0370:7334'.should.not.be.an.ip; - }).should.throw('expected \'2001:0db8:85a3:0000:0000:8a2e:0370:73…\' to not be an ip'); + }).should.throw( + "expected '2001:0db8:85a3:0000:0000:8a2e:0370:73…' to not be an ip" + ); }); it('#header test existence', function () { - var req = { headers: { foo: 'bar' }}; - var res = { + const req = {headers: {foo: 'bar'}}; + const res = { getHeader: function (key) { return key == 'foo' ? 'bar' : undefined; } @@ -54,16 +55,16 @@ describe('assertions', function () { (function () { req.should.have.header('bar'); - }).should.throw('expected header \'bar\' to exist'); + }).should.throw("expected header 'bar' to exist"); (function () { res.should.have.header('bar'); - }).should.throw('expected header \'bar\' to exist'); + }).should.throw("expected header 'bar' to exist"); }); it('#header test value', function () { - var req = { headers: { foo: 'bar' }}; - var res = { + const req = {headers: {foo: 'bar'}}; + const res = { getHeader: function (key) { return 'foo'; } @@ -75,20 +76,21 @@ describe('assertions', function () { (function () { req.should.not.have.header('foo', 'bar'); - }, 'expected header \'foo\' to not have value bar'); + }), + "expected header 'foo' to not have value bar"; (function () { res.should.not.have.header('bar', 'foo'); - }).should.throw('expected header \'bar\' to not have value foo'); + }).should.throw("expected header 'bar' to not have value foo"); (function () { res.should.not.have.header('bar', /^fo/); - }).should.throw('expected header \'bar\' not to match /^fo/ but got \'foo\''); + }).should.throw("expected header 'bar' not to match /^fo/ but got 'foo'"); }); it('#header case insensitive', function () { - var req = { headers: { foo: 'bar' }}; - var res = { + const req = {headers: {foo: 'bar'}}; + const res = { getHeader: function (key) { return 'foo'; } @@ -100,9 +102,9 @@ describe('assertions', function () { res.should.have.header('BAr', 'foo'); }); - it('#headers', function() { - var req = { headers: { foo: 'bar' }}; - var res = { + it('#headers', function () { + const req = {headers: {foo: 'bar'}}; + const res = { getHeader: function (key) { return 'foo'; } @@ -113,18 +115,22 @@ describe('assertions', function () { (function () { req.should.not.have.headers; - }).should.throw('expected { headers: { foo: \'bar\' } } to not have headers or getHeader method'); + }).should.throw( + "expected { headers: { foo: 'bar' } } to not have headers or getHeader method" + ); (function () { res.should.not.have.headers; - }).should.throw(/expected .*getHeader.* to not have headers or getHeader method/); + }).should.throw( + /expected .*getHeader.* to not have headers or getHeader method/ + ); }); - it('#json', function() { - var req = { headers: { 'content-type': [ 'application/json' ] }}; - var res = { + it('#json', function () { + const req = {headers: {'content-type': ['application/json']}}; + const res = { getHeader: function (key) { - return 'application/json' + return 'application/json'; } }; @@ -133,18 +139,22 @@ describe('assertions', function () { (function () { req.should.not.be.json; - }).should.throw('expected [ \'application/json\' ] to not include \'application/json\''); + }).should.throw( + "expected [ 'application/json' ] to not include 'application/json'" + ); (function () { res.should.not.be.json; - }).should.throw('expected \'application/json\' to not include \'application/json\''); + }).should.throw( + "expected 'application/json' to not include 'application/json'" + ); }); - it('#text', function() { - var req = { headers: { 'content-type': [ 'text/plain' ] }}; - var res = { + it('#text', function () { + const req = {headers: {'content-type': ['text/plain']}}; + const res = { getHeader: function (key) { - return 'text/plain' + return 'text/plain'; } }; @@ -153,18 +163,18 @@ describe('assertions', function () { (function () { req.should.not.be.text; - }).should.throw('expected [ \'text/plain\' ] to not include \'text/plain\''); + }).should.throw("expected [ 'text/plain' ] to not include 'text/plain'"); (function () { res.should.not.be.text; - }).should.throw('expected \'text/plain\' to not include \'text/plain\''); + }).should.throw("expected 'text/plain' to not include 'text/plain'"); }); it('#html', function () { - var req = { headers: { 'content-type': [ 'text/html' ] }}; - var res = { + const req = {headers: {'content-type': ['text/html']}}; + const res = { getHeader: function (key) { - return 'text/html' + return 'text/html'; } }; @@ -173,19 +183,19 @@ describe('assertions', function () { (function () { req.should.not.be.html; - }).should.throw('expected [ \'text/html\' ] to not include \'text/html\''); + }).should.throw("expected [ 'text/html' ] to not include 'text/html'"); (function () { res.should.not.be.html; - }).should.throw('expected \'text/html\' to not include \'text/html\''); + }).should.throw("expected 'text/html' to not include 'text/html'"); }); it('#redirect', function () { - var res = { status: 200 }; + const res = {status: 200}; res.should.not.redirect; [301, 302, 303, 307, 308].forEach(function (status) { - var res = { status: status }; + const res = {status: status}; res.should.redirect; }); @@ -200,63 +210,65 @@ describe('assertions', function () { }).should.not.redirect; (function () { - var res = { status: 200 }; + const res = {status: 200}; res.should.redirect; }).should.throw('expected redirect with 30X status code but got 200'); (function () { - var res = { status: 301 }; + const res = {status: 301}; res.should.not.redirect; }).should.throw('expected not to redirect but got 301 status'); }); it('#redirectTo', function () { - var res = { status: 301, headers: { location: 'foo' } }; + let res = {status: 301, headers: {location: 'foo'}}; res.should.redirectTo('foo'); - res = { status: 301, headers: { location: 'bar' } }; + res = {status: 301, headers: {location: 'bar'}}; res.should.not.redirectTo('foo'); - res = { status: 200, redirects: ['bar'] }; + res = {status: 200, redirects: ['bar']}; res.should.redirectTo('bar'); - res = { status: 200, redirects: ['bar'] }; + res = {status: 200, redirects: ['bar']}; res.should.not.redirectTo('foo'); - res = { status: 200, redirects: ['foo'] }; + res = {status: 200, redirects: ['foo']}; res.should.redirectTo(/foo/); - res = { status: 200, redirects: ['foo/bar?baz=qux'] }; + res = {status: 200, redirects: ['foo/bar?baz=qux']}; res.should.redirectTo(/^foo\/bar/); (function () { - var res = { status: 301, headers: { location: 'foo' } }; + const res = {status: 301, headers: {location: 'foo'}}; res.should.not.redirectTo('foo'); - }).should.throw('expected header \'location\' to not have value foo'); + }).should.throw("expected header 'location' to not have value foo"); (function () { - var res = { status: 301, headers: { location: 'bar' } }; + const res = {status: 301, headers: {location: 'bar'}}; res.should.redirectTo('foo'); - }).should.throw('expected header \'location\' to have value foo'); + }).should.throw("expected header 'location' to have value foo"); (function () { - var res = { status: 200, redirects: ['bar', 'baz'] }; + const res = {status: 200, redirects: ['bar', 'baz']}; res.should.redirectTo('foo'); }).should.throw('expected redirect to foo but got bar then baz'); (function () { - var res = { status: 301, headers: { location: 'foo' } }; + const res = {status: 301, headers: {location: 'foo'}}; res.should.not.redirectTo(/foo/); - }).should.throw('expected header \'location\' not to match /foo/ but got \'foo\''); + }).should.throw( + "expected header 'location' not to match /foo/ but got 'foo'" + ); (function () { - var res = { status: 200, redirects: ['bar', 'baz'] }; + const res = {status: 200, redirects: ['bar', 'baz']}; res.should.redirectTo(/foo/); }).should.throw('expected redirect to /foo/ but got bar then baz'); }); it('#param', function () { - var req = { url: '/test?x=y&foo=bar' }; + const req = {url: '/test?x=y&foo=bar'}; req.should.have.param('x'); req.should.have.param('foo'); req.should.have.param('x', 'y'); @@ -276,7 +288,7 @@ describe('assertions', function () { }); it('#param (nested)', function () { - var req = { url: '/test?form[name]=jim&form[lastName]=bob' }; + const req = {url: '/test?form[name]=jim&form[lastName]=bob'}; req.should.have.param('form'); req.should.have.nested.param('form.name'); req.should.have.nested.param('form.name', 'jim'); @@ -292,11 +304,13 @@ describe('assertions', function () { (function () { req.should.not.have.nested.param('form.lastName', 'bob'); - }).should.throw(/expected .* to not have nested property \'form.lastName\' of \'bob\'/); + }).should.throw( + /expected .* to not have nested property \'form.lastName\' of \'bob\'/ + ); }); it('#cookie', function () { - var res = { + const res = { headers: { 'set-cookie': [ 'name=value', @@ -313,28 +327,30 @@ describe('assertions', function () { (function () { res.should.not.have.cookie('name'); - }).should.throw('expected cookie \'name\' to not exist'); + }).should.throw("expected cookie 'name' to not exist"); (function () { res.should.have.cookie('foo'); - }).should.throw('expected cookie \'foo\' to exist'); + }).should.throw("expected cookie 'foo' to exist"); (function () { res.should.not.have.cookie('name', 'value'); - }).should.throw('expected cookie \'name\' to not have value \'value\''); + }).should.throw("expected cookie 'name' to not have value 'value'"); (function () { res.should.have.cookie('name2', 'value'); - }).should.throw('expected cookie \'name2\' to have value \'value\' but got \'value2\''); + }).should.throw( + "expected cookie 'name2' to have value 'value' but got 'value2'" + ); }); it('#cookie (request)', function () { - var req = { + const req = { headers: { 'set-cookie': [ 'name=value;', 'name2=value2; Expires=Wed, 09 Jun 2038 10:18:14 GMT', - 'name3=value3; Domain=.somedomain.com', + 'name3=value3; Domain=.somedomain.com' ] } }; @@ -349,33 +365,35 @@ describe('assertions', function () { (function () { req.should.not.have.cookie('name'); - }).should.throw('expected cookie \'name\' to not exist'); + }).should.throw("expected cookie 'name' to not exist"); (function () { req.should.have.cookie('foo'); - }).should.throw('expected cookie \'foo\' to exist'); + }).should.throw("expected cookie 'foo' to exist"); (function () { req.should.not.have.cookie('name', 'value'); - }).should.throw('expected cookie \'name\' to not have value \'value\''); + }).should.throw("expected cookie 'name' to not have value 'value'"); (function () { req.should.have.cookie('name2', 'value'); - }).should.throw('expected cookie \'name2\' to have value \'value\' but got \'value2\''); - + }).should.throw( + "expected cookie 'name2' to have value 'value' but got 'value2'" + ); }); it('#cookie (agent)', function () { - var agent = chai.request.agent(); - var cookies = [ + const agent = chai.request.agent(); + const cookies = [ 'name=value', 'name2=value2; Expires=Wed, 09 Jun 2038 10:18:14 GMT', - 'name3=value3; Domain=.somedomain.com', + 'name3=value3; Domain=.somedomain.com' ]; - if (agent.jar) // Using superagent.Agent (node) + if (agent.jar) + // Using superagent.Agent (node) agent.jar.setCookies(cookies); - else // using superagent.Request (browser) - agent.set('set-cookie', cookies); + // using superagent.Request (browser) + else agent.set('set-cookie', cookies); agent.should.have.cookie('name'); agent.should.have.cookie('name2'); @@ -388,47 +406,50 @@ describe('assertions', function () { (function () { agent.should.not.have.cookie('name'); - }).should.throw('expected cookie \'name\' to not exist'); + }).should.throw("expected cookie 'name' to not exist"); (function () { agent.should.have.cookie('foo'); - }).should.throw('expected cookie \'foo\' to exist'); + }).should.throw("expected cookie 'foo' to exist"); (function () { agent.should.not.have.cookie('name', 'value'); - }).should.throw('expected cookie \'name\' to not have value \'value\''); + }).should.throw("expected cookie 'name' to not have value 'value'"); (function () { agent.should.have.cookie('name2', 'value'); - }).should.throw('expected cookie \'name2\' to have value \'value\' but got \'value2\''); - + }).should.throw( + "expected cookie 'name2' to have value 'value' but got 'value2'" + ); }); describe('#charset', function () { - it("should match charset in content type", function() { - var req = { headers: { 'content-type': [ 'text/plain; charset=utf-8' ] } }; - req.should.to.have.charset("utf-8"); + it('should match charset in content type', function () { + const req = { + headers: {'content-type': ['text/plain; charset=utf-8']} + }; + req.should.to.have.charset('utf-8'); (function () { - req.should.not.have.charset("utf-8"); + req.should.not.have.charset('utf-8'); }).should.throw('expected content type to not have utf-8 charset'); }); - it("should handle no content type", function() { - var req = { headers: {} }; - req.should.not.have.charset("utf-8"); + it('should handle no content type', function () { + const req = {headers: {}}; + req.should.not.have.charset('utf-8'); (function () { - req.should.to.have.charset("utf-8"); + req.should.to.have.charset('utf-8'); }).should.throw('expected content type to have utf-8 charset'); }); - it("should handle no charset in content type", function() { - var req = { headers: { 'content-type': [ 'text/plain' ] } }; - req.should.not.have.charset("utf-8"); + it('should handle no charset in content type', function () { + const req = {headers: {'content-type': ['text/plain']}}; + req.should.not.have.charset('utf-8'); (function () { - req.should.to.have.charset("utf-8"); + req.should.to.have.charset('utf-8'); }).should.throw('expected content type to have utf-8 charset'); }); }); diff --git a/test/request.js b/test/request.js index 6a85442..27b8734 100644 --- a/test/request.js +++ b/test/request.js @@ -1,17 +1,17 @@ -import superagent from "superagent" +import superagent from 'superagent'; describe('request', function () { - var isNode = typeof process === 'object'; - var isBrowser = typeof window === 'object'; - var request = chai.request; + const isNode = typeof process === 'object'; + const isBrowser = typeof window === 'object'; + const request = chai.request; describe('Browser and Node.js', function () { it('is present on chai', function () { - expect(chai.request).to.not.eq('undefined') + expect(chai.request).to.not.eq('undefined'); expect(chai.request).to.respondTo('execute'); }); it('request method returns instanceof superagent', function () { - var req = request.execute('').get('/'); + const req = request.execute('').get('/'); req.should.be.instanceof(request.Request.super_); if (isNode) { req.should.be.instanceof(superagent.Request); @@ -19,7 +19,8 @@ describe('request', function () { }); it('can request a web page', function (done) { - request.execute('https://chaijs.com') + request + .execute('https://chaijs.com') .get('/guide/') .end(function (err, res) { res.should.have.status(200); @@ -37,7 +38,8 @@ describe('request', function () { }); it('can request JSON data', function (done) { - request.execute('https://chaijs.com') + request + .execute('https://chaijs.com') .get('/package-lock.json') .end(function (err, res) { res.should.have.status(200); @@ -51,33 +53,56 @@ describe('request', function () { }); it('can read response headers', function (done) { - this.timeout(5000) - request.execute('https://webhook.site') + this.timeout(5000); + request + .execute('https://webhook.site') .post('/token') .end(function (err, res) { const uuid = res.body.uuid; - request.execute('https://webhook.site') + request + .execute('https://webhook.site') .get('/' + uuid) .query({'content-type': 'application/json'}) - .query({'pragma': 'test1'}) - .query({'location': 'test2'}) + .query({pragma: 'test1'}) + .query({location: 'test2'}) .query({'x-api-key': 'test3'}) .end(function (err, res) { res.should.have.status(200); - request.execute('https://webhook.site') + request + .execute('https://webhook.site') .get('/token/' + uuid + '/requests?sorting=newest&per_page=1') .end(function (err, res) { // Content-Type and Pragma are supported on Node and browser res.should.be.json; - res.should.have.nested.property('.body.data.0.query.content-type', 'application/json') - res.should.have.nested.property('.body.data.0.query.pragma', 'test1') + res.should.have.nested.property( + '.body.data.0.query.content-type', + 'application/json' + ); + res.should.have.nested.property( + '.body.data.0.query.pragma', + 'test1' + ); // When running in a browser, only "simple" headers are readable // https://www.w3.org/TR/cors/#simple-response-header - isNode && res.should.have.nested.property('.body.data.0.query.location', 'test2') - isNode && res.should.have.nested.property('.body.data.0.query.x-api-key', 'test3') - isBrowser && res.should.not.have.nested.property('.body.data.0.query.location'); - isBrowser && res.should.not.have.nested.property('.body.data.0.query.x-api-key'); + isNode && + res.should.have.nested.property( + '.body.data.0.query.location', + 'test2' + ); + isNode && + res.should.have.nested.property( + '.body.data.0.query.x-api-key', + 'test3' + ); + isBrowser && + res.should.not.have.nested.property( + '.body.data.0.query.location' + ); + isBrowser && + res.should.not.have.nested.property( + '.body.data.0.query.x-api-key' + ); done(err); }); @@ -86,7 +111,8 @@ describe('request', function () { }); it('succeeds when response has an error status', function (done) { - request.execute('https://chaijs.com') + request + .execute('https://chaijs.com') .get('/404') .end(function (err, res) { res.should.have.status(404); @@ -95,30 +121,39 @@ describe('request', function () { }); it('can be augmented with promises', function (done) { - this.timeout(5000) - let uuid = '' - request.execute('https://webhook.site') + this.timeout(5000); + let uuid = ''; + request + .execute('https://webhook.site') .post('/token') .then(function (res) { uuid = res.body.uuid; return res.body.uuid; }) .then(function (uuid) { - return request.execute('https://webhook.site') + return request + .execute('https://webhook.site') .get('/' + uuid) .query({'content-type': 'application/json'}) - .query({'x-api-key': 'test3'}) + .query({'x-api-key': 'test3'}); }) .then(function (res) { res.should.have.status(200); - return request.execute('https://webhook.site') - .get('/token/' + uuid + '/requests?sorting=newest&per_page=1') + return request + .execute('https://webhook.site') + .get('/token/' + uuid + '/requests?sorting=newest&per_page=1'); }) .then(function (res) { res.should.have.status(200); res.should.be.json; - res.should.have.nested.property('.body.data.0.query.content-type', 'application/json') - res.should.have.nested.property('.body.data.0.query.x-api-key', 'test3') + res.should.have.nested.property( + '.body.data.0.query.content-type', + 'application/json' + ); + res.should.have.nested.property( + '.body.data.0.query.x-api-key', + 'test3' + ); }) .then(function () { throw new Error('Testing catch'); @@ -135,7 +170,8 @@ describe('request', function () { }); it('can resolve a promise given status code of 404', function () { - return request.execute('https://chaijs.com') + return request + .execute('https://chaijs.com') .get('/404') .then(function (res) { res.should.have.status(404); @@ -143,146 +179,158 @@ describe('request', function () { }); }); - isNode && describe('Node.js', function () { - it('can request a functioned "app"', function (done) { - var app = function (req, res) { - req.headers['x-api-key'].should.equal('testing'); - res.writeHeader(200, { 'content-type' : 'text/plain' }); - res.end('hello universe'); - }; - - request.execute(app).get('/') - .set('X-API-Key', 'testing') - .end(function (err, res) { - if (err) return done(err) - res.should.have.status(200); - res.text.should.equal('hello universe'); - done(); - }); - }); + isNode && + describe('Node.js', function () { + it('can request a functioned "app"', function (done) { + const app = function (req, res) { + req.headers['x-api-key'].should.equal('testing'); + res.writeHeader(200, {'content-type': 'text/plain'}); + res.end('hello universe'); + }; - it('can request an already existing url', function (done) { - var server = http.createServer(function (req, res) { - req.headers['x-api-key'].should.equal('test2'); - res.writeHeader(200, { 'content-type' : 'text/plain' }); - res.end('hello world'); - }); - - server.listen(0, function () { - request.execute('http://127.0.0.1:' + server.address().port) + request + .execute(app) .get('/') - .set('X-API-Key', 'test2') + .set('X-API-Key', 'testing') .end(function (err, res) { + if (err) return done(err); res.should.have.status(200); - res.text.should.equal('hello world'); - server.once('close', function () { done(err); }); - server.close(); + res.text.should.equal('hello universe'); + done(); }); }); - }); + it('can request an already existing url', function (done) { + const server = http.createServer(function (req, res) { + req.headers['x-api-key'].should.equal('test2'); + res.writeHeader(200, {'content-type': 'text/plain'}); + res.end('hello world'); + }); - it('agent can be used to persist cookies', function (done) { - var app = function (req, res) { - res.setHeader('Set-Cookie', 'mycookie=test'); - res.writeHeader(200, { 'content-type' : 'text/plain' }); - res.end('your cookie: ' + req.headers.cookie); - }; - var agent = request.agent(app); + server.listen(0, function () { + request + .execute('http://127.0.0.1:' + server.address().port) + .get('/') + .set('X-API-Key', 'test2') + .end(function (err, res) { + res.should.have.status(200); + res.text.should.equal('hello world'); + server.once('close', function () { + done(err); + }); + server.close(); + }); + }); + }); - agent - .get('/') - .then(function (res) { - res.headers['set-cookie'][0].should.equal('mycookie=test'); - res.text.should.equal('your cookie: undefined'); - }) - .then(function () { - return agent.get('/'); - }) - .then(function (res) { - res.text.should.equal('your cookie: mycookie=test'); - agent.close() - }) - .then(done, done); - }); + it('agent can be used to persist cookies', function (done) { + const app = function (req, res) { + res.setHeader('Set-Cookie', 'mycookie=test'); + res.writeHeader(200, {'content-type': 'text/plain'}); + res.end('your cookie: ' + req.headers.cookie); + }; + const agent = request.agent(app); - it('automatically closes the server down once done with it', function (done) { - var server = http.createServer(function (req, res) { - res.writeHeader(200, { 'content-type' : 'text/plain' }); - res.end('hello world'); + agent + .get('/') + .then(function (res) { + res.headers['set-cookie'][0].should.equal('mycookie=test'); + res.text.should.equal('your cookie: undefined'); + }) + .then(function () { + return agent.get('/'); + }) + .then(function (res) { + res.text.should.equal('your cookie: mycookie=test'); + agent.close(); + }) + .then(done, done); }); - request.execute(server) + it('automatically closes the server down once done with it', function (done) { + const server = http.createServer(function (req, res) { + res.writeHeader(200, {'content-type': 'text/plain'}); + res.end('hello world'); + }); + + request + .execute(server) .get('/') .end(function (err, res) { res.should.have.status(200); res.text.should.equal('hello world'); - should.not.exist(server.address()) - done(err) + should.not.exist(server.address()); + done(err); }); - }); - - it('can use keepOpen() to not close the server', function (done) { - var server = http.createServer(function (req, res) { - res.writeHeader(200, { 'content-type' : 'text/plain' }); - res.end('hello world'); }); - var cachedRequest = request.execute(server).keepOpen(); - server.listen = function () { throw new Error('listen was called when it shouldnt have been') } - cachedRequest.get('/') .end(function (err, res) { - cachedRequest.get('/').end(function (err2, res) { - server.close(function () { done(err || err2) }) - }) + + it('can use keepOpen() to not close the server', function (done) { + const server = http.createServer(function (req, res) { + res.writeHeader(200, {'content-type': 'text/plain'}); + res.end('hello world'); + }); + const cachedRequest = request.execute(server).keepOpen(); + server.listen = function () { + throw new Error('listen was called when it shouldnt have been'); + }; + cachedRequest.get('/').end(function (err, res) { + cachedRequest.get('/').end(function (err2, res) { + server.close(function () { + done(err || err2); + }); + }); + }); }); - }); - it('can close server after using keepOpen()', function (done) { - var server = http.createServer(function (req, res) { - res.writeHeader(200, { 'content-type' : 'text/plain' }); - res.end('hello world'); - }); - var cachedRequest = request.execute(server).keepOpen(); - cachedRequest.close(function (err) { - should.not.exist(server.address()); - done(); + it('can close server after using keepOpen()', function (done) { + const server = http.createServer(function (req, res) { + res.writeHeader(200, {'content-type': 'text/plain'}); + res.end('hello world'); + }); + const cachedRequest = request.execute(server).keepOpen(); + cachedRequest.close(function (err) { + should.not.exist(server.address()); + done(); + }); + }); }); - }); -}); - - isBrowser && describe('Browser', function () { - it('cannot request a functioned "app"', function () { - function tryToRequestAFunctionedApp() { - var app = function () {}; - request.execute(app); - } - expect(tryToRequestAFunctionedApp).to.throw(Error, - /http.createServer is not a function|createServer/); - }); + isBrowser && + describe('Browser', function () { + it('cannot request a functioned "app"', function () { + function tryToRequestAFunctionedApp() { + const app = function () {}; + request.execute(app); + } + expect(tryToRequestAFunctionedApp).to.throw( + Error, + /http.createServer is not a function|createServer/ + ); + }); - it('agent can be used to persist cookies', function (done) { - var agent = request.agent('https://httpbin.org'); + it('agent can be used to persist cookies', function (done) { + const agent = request.agent('https://httpbin.org'); - agent - .get('/cookies/set') - .query({foo: 'bar', biz: 'baz'}) - .then(function (res) { - // When running in a web browser, cookies are protected and cannot be read by SuperAgent. - // They ARE set, but only the browser has access to them. - expect(res.headers['set-cookie']).to.be.undefined; - res.should.not.have.cookie('foo'); - res.should.not.have.cookie('bar'); - }) - .then(function () { - // When making a subsequent request to the same server, the cookies will be sent - return agent.get('/cookies'); - }) - .then(function (res) { - // HttpBin echoes the cookies back as JSON - res.body.cookies.foo.should.equal('bar'); - res.body.cookies.biz.should.equal('baz'); - }) - .then(done, done); + agent + .get('/cookies/set') + .query({foo: 'bar', biz: 'baz'}) + .then(function (res) { + // When running in a web browser, cookies are protected and cannot be read by SuperAgent. + // They ARE set, but only the browser has access to them. + expect(res.headers['set-cookie']).to.be.undefined; + res.should.not.have.cookie('foo'); + res.should.not.have.cookie('bar'); + }) + .then(function () { + // When making a subsequent request to the same server, the cookies will be sent + return agent.get('/cookies'); + }) + .then(function (res) { + // HttpBin echoes the cookies back as JSON + res.body.cookies.foo.should.equal('bar'); + res.body.cookies.biz.should.equal('baz'); + }) + .then(done, done); + }); }); - }); }); diff --git a/types/index.d.ts b/types/index.d.ts index 38c60b4..cd1b70b 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -9,51 +9,51 @@ import * as request from 'superagent'; // Merge namespace with global chai declare global { - namespace Chai { - interface ChaiStatic { - request: ChaiHttpRequest; - } + namespace Chai { + interface ChaiStatic { + request: ChaiHttpRequest; + } - interface ChaiHttpRequest { - agent(server: any): ChaiHttp.Agent; - Request(app: string | any, method: string, path: string): void, - execute: (app: string | any) => ChaiHttp.Agent - } + interface ChaiHttpRequest { + agent(server: any): ChaiHttp.Agent; + Request(app: string | any, method: string, path: string): void; + execute: (app: string | any) => ChaiHttp.Agent; + } - interface Assertion { - redirectTo(location: string|RegExp): Assertion; + interface Assertion { + redirectTo(location: string | RegExp): Assertion; - param(key: string, value?: string): Assertion; + param(key: string, value?: string): Assertion; - cookie(key: string, value?: string): Assertion; + cookie(key: string, value?: string): Assertion; - status(code: number): Assertion; + status(code: number): Assertion; - statusCode(code: number): Assertion; + statusCode(code: number): Assertion; - header(key: string, value?: string | RegExp): Assertion; + header(key: string, value?: string | RegExp): Assertion; - charset(charset: string): Assertion; + charset(charset: string): Assertion; - headers: Assertion; - json: Assertion; - text: Assertion; - html: Assertion; - redirect: Assertion; - } + headers: Assertion; + json: Assertion; + text: Assertion; + html: Assertion; + redirect: Assertion; + } - interface TypeComparison { - ip: Assertion; - } + interface TypeComparison { + ip: Assertion; } + } - namespace ChaiHttp { - interface Response extends request.Response {} - interface Agent extends request.SuperAgentStatic { - keepOpen(): Agent; - close(callback?: (err: any) => void): Agent; - } + namespace ChaiHttp { + interface Response extends request.Response {} + interface Agent extends request.SuperAgentStatic { + keepOpen(): Agent; + close(callback?: (err: any) => void): Agent; } + } } declare function chaiHttp(chai: any, utils: any): void; diff --git a/types/test.ts b/types/test.ts index a0e080d..f872292 100644 --- a/types/test.ts +++ b/types/test.ts @@ -1,7 +1,7 @@ -import * as fs from "fs"; -import * as http from "http"; -import * as originalChai from "chai"; -import ChaiHttp from "./index"; +import * as fs from 'fs'; +import * as http from 'http'; +import * as originalChai from 'chai'; +import ChaiHttp from './index'; const chai = originalChai.use(ChaiHttp); @@ -10,24 +10,25 @@ declare const app: http.Server; chai.request.execute(app).get('/'); chai.request.execute('http://localhost:8080').get('/'); -chai.request.execute(app) - .put('/user/me') - .set('X-API-Key', 'foobar') - .send({ password: '123', confirmPassword: '123' }); +chai.request + .execute(app) + .put('/user/me') + .set('X-API-Key', 'foobar') + .send({password: '123', confirmPassword: '123'}); -chai.request.execute(app) - .post('/user/me') - .field('_method', 'put') - .field('password', '123') - .field('confirmPassword', '123'); +chai.request + .execute(app) + .post('/user/me') + .field('_method', 'put') + .field('password', '123') + .field('confirmPassword', '123'); -chai.request.execute(app) - .post('/user/avatar') - .attach('imageField', fs.readFileSync('avatar.png'), 'avatar.png'); +chai.request + .execute(app) + .post('/user/avatar') + .attach('imageField', fs.readFileSync('avatar.png'), 'avatar.png'); -chai.request.execute(app) - .get('/protected') - .auth('user', 'pass'); +chai.request.execute(app).get('/protected').auth('user', 'pass'); // HTTPS request, from: https://github.com/visionmedia/superagent/commit/6158efbf42cb93d77c1a70887284be783dd7dabe const ca = fs.readFileSync('ca.cert.pem'); @@ -35,91 +36,105 @@ const key = fs.readFileSync('key.pem'); const cert = fs.readFileSync('cert.pem'); const callback = (err: any, res: ChaiHttp.Response) => {}; -chai.request.execute(app) - .post('/secure') - .ca(ca) - .key(key) - .cert(cert) - .end(callback); +chai.request + .execute(app) + .post('/secure') + .ca(ca) + .key(key) + .cert(cert) + .end(callback); const pfx = fs.readFileSync('cert.pfx'); -chai.request.execute(app) - .post('/secure') - .pfx(pfx) - .end(callback); - -chai.request.execute(app) - .get('/search') - .query({ name: 'foo', limit: 10 }); - -chai.request.execute(app) - .get('/download') - .buffer() - .parse((res, cb) => { - let data = ''; - res.setEncoding('binary'); - res.on('data', (chunk: any) => { data += chunk; }); - res.on('end', () => { cb(undefined, new Buffer(data, 'binary')); }); +chai.request.execute(app).post('/secure').pfx(pfx).end(callback); + +chai.request.execute(app).get('/search').query({name: 'foo', limit: 10}); + +chai.request + .execute(app) + .get('/download') + .buffer() + .parse((res, cb) => { + let data = ''; + res.setEncoding('binary'); + res.on('data', (chunk: any) => { + data += chunk; }); - -chai.request.execute(app) - .put('/user/me') - .send({ passsword: '123', confirmPassword: '123' }) - .end((err: any, res: ChaiHttp.Response) => { - chai.expect(err).to.be.null; - chai.expect(res).to.have.status(200); + res.on('end', () => { + cb(undefined, new Buffer(data, 'binary')); }); - -chai.request.execute(app) - .put('/user/me') - .send({ passsword: '123', confirmPassword: '123' }) - .then((res: ChaiHttp.Response) => chai.expect(res).to.have.status(200)) - .catch((err: any) => { throw err; }); - -chai.request.execute(app) - .keepOpen() - .close((err: any) => { throw err; }); + }); + +chai.request + .execute(app) + .put('/user/me') + .send({passsword: '123', confirmPassword: '123'}) + .end((err: any, res: ChaiHttp.Response) => { + chai.expect(err).to.be.null; + chai.expect(res).to.have.status(200); + }); + +chai.request + .execute(app) + .put('/user/me') + .send({passsword: '123', confirmPassword: '123'}) + .then((res: ChaiHttp.Response) => chai.expect(res).to.have.status(200)) + .catch((err: any) => { + throw err; + }); + +chai.request + .execute(app) + .keepOpen() + .close((err: any) => { + throw err; + }); const agent = chai.request.agent(app); agent - .post('/session') - .send({ username: 'me', password: '123' }) - .then((res: ChaiHttp.Response) => { - chai.expect(res).to.have.cookie('sessionid'); - // The `agent` now has the sessionid cookie saved, and will send it - // back to the server in the next request: - return agent.get('/user/me') - .then((res: ChaiHttp.Response) => chai.expect(res).to.have.status(200)); - }); - -agent.close((err: any) => { throw err; }); + .post('/session') + .send({username: 'me', password: '123'}) + .then((res: ChaiHttp.Response) => { + chai.expect(res).to.have.cookie('sessionid'); + // The `agent` now has the sessionid cookie saved, and will send it + // back to the server in the next request: + return agent + .get('/user/me') + .then((res: ChaiHttp.Response) => chai.expect(res).to.have.status(200)); + }); + +agent.close((err: any) => { + throw err; +}); function test1() { - const req = chai.request.execute(app).get('/'); - req.then((res: ChaiHttp.Response) => { - chai.expect(res).to.have.status(200); - chai.expect(res).to.have.header('content-type', 'text/plain'); - chai.expect(res).to.have.header('content-type', /^text/); - chai.expect(res).to.have.headers; - chai.expect('127.0.0.1').to.be.an.ip; - chai.expect(res).to.be.json; - chai.expect(res).to.be.html; - chai.expect(res).to.be.text; - chai.expect(res).to.redirect; - chai.expect(res).to.redirectTo('http://example.com'); - chai.expect(res).to.have.param('orderby'); - chai.expect(res).to.have.param('orderby', 'date'); - chai.expect(res).to.not.have.param('limit'); - chai.expect(req).to.have.cookie('session_id'); - chai.expect(req).to.have.cookie('session_id', '1234'); - chai.expect(req).to.not.have.cookie('PHPSESSID'); - chai.expect(res).to.have.cookie('session_id'); - chai.expect(res).to.have.cookie('session_id', '1234'); - chai.expect(res).to.not.have.cookie('PHPSESSID'); - chai.expect(res.body).to.have.property('version', '4.0.0'); - chai.expect(res.text).to.equal(''); - }, (err: any) => { - throw err; - }); + const req = chai.request.execute(app).get('/'); + req.then( + (res: ChaiHttp.Response) => { + chai.expect(res).to.have.status(200); + chai.expect(res).to.have.header('content-type', 'text/plain'); + chai.expect(res).to.have.header('content-type', /^text/); + chai.expect(res).to.have.headers; + chai.expect('127.0.0.1').to.be.an.ip; + chai.expect(res).to.be.json; + chai.expect(res).to.be.html; + chai.expect(res).to.be.text; + chai.expect(res).to.redirect; + chai.expect(res).to.redirectTo('http://example.com'); + chai.expect(res).to.have.param('orderby'); + chai.expect(res).to.have.param('orderby', 'date'); + chai.expect(res).to.not.have.param('limit'); + chai.expect(req).to.have.cookie('session_id'); + chai.expect(req).to.have.cookie('session_id', '1234'); + chai.expect(req).to.not.have.cookie('PHPSESSID'); + chai.expect(res).to.have.cookie('session_id'); + chai.expect(res).to.have.cookie('session_id', '1234'); + chai.expect(res).to.not.have.cookie('PHPSESSID'); + chai.expect(res.body).to.have.property('version', '4.0.0'); + chai.expect(res.text).to.equal(''); + }, + (err: any) => { + throw err; + } + ); }