Merge branch 'v2.0-dev' as v2.0.0 v2.0.0
authorJustin Wind <justin.wind+git@gmail.com>
Sun, 27 Aug 2023 21:07:04 +0000 (14:07 -0700)
committerJustin Wind <justin.wind+git@gmail.com>
Sun, 27 Aug 2023 21:07:04 +0000 (14:07 -0700)
14 files changed:
CHANGELOG.md
README.md
lib/common.js
lib/content-negotiation.js
lib/dingus.js
lib/errors.js
lib/mime-helper.js
lib/router/index.js
package-lock.json
package.json
test/lib/common.js
test/lib/dingus.js
test/lib/enum.js
test/lib/router.js

index ffd23ff62621ce25034e9a84603cbce987fc1c1e..cb60b74d5d5f303ed53b5184f9c644b0df730c5e 100644 (file)
@@ -4,7 +4,13 @@ Releases and notable changes to this project are documented here.
 
 ## [Unreleased]
 
--
+## [v2.0.0] - 2023-08-27
+
+- HEAD requests are now handled automatically by default, if not otherwise specifically registered, on a route with a GET handler
+- trailing slashes on a request url now default to being ignored when matching routes
+- removed deprecated functions
+- minor refactors
+- updated devDependencies
 
 ## [v1.2.10] - 2023-07-20
 
@@ -93,7 +99,8 @@ Releases and notable changes to this project are documented here.
 
 ---
 
-[Unreleased]: https://git.squeep.com/?p=squeep-api-dingus;a=commitdiff;h=HEAD;hp=v1.2.10
+[Unreleased]: https://git.squeep.com/?p=squeep-api-dingus;a=commitdiff;h=HEAD;hp=v2.0.0
+[v2.0.0]: https://git.squeep.com/?p=squeep-api-dingus;a=commitdiff;h=v2.0.0;hp=v1.2.10
 [v1.2.10]: https://git.squeep.com/?p=squeep-api-dingus;a=commitdiff;h=v1.2.10;hp=v1.2.9
 [v1.2.9]: https://git.squeep.com/?p=squeep-api-dingus;a=commitdiff;h=v1.2.9;hp=v1.2.8
 [v1.2.8]: https://git.squeep.com/?p=squeep-api-dingus;a=commitdiff;h=v1.2.8;hp=v1.2.7
index 7056184ac2f0341b2477190fd357482e34f632f7..e4c153c1e6dddb6c12edc0fb8bb8466babf00c13 100644 (file)
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ This is not drop-in compatible with the industry standards, and is in no way int
 
 The primary design goals are:
 - self-contained: Uses as few external dependencies as are feasible.
-- not-infinitely-extensible: The projects it gets used in drive the feature set.
+- not-infinitely-extensible: The projects it gets used in drive the feature set, so some expected functionality may be surprisingly missing.
 - learning from mistakes made along the way: This was partly created as a means to gain a better understanding of the existing web framework ecosystem by fussing with all the involved fiddly bits, a priori, from the bottom up.
 
 ## Getting Started
@@ -16,11 +16,11 @@ The primary design goals are:
 Construct it with a console-level-compatible logger object capable of doing something meaningful with calls like `logger[level](scopeString, messageString, dataObject)`.
 
 Within the server request handler:
-- `dispatch(req, res)` makes things go.
+- `async dispatch(req, res)` makes things go.
 
 Within the application implementation:
 - `on(method, urlPath, handler)` declares a thing to do when a request matches.
-- `preHandler(req, res, ctx)` is called on every request before the handler function, by default adding some request information to the context.
+- `async preHandler(req, res, ctx)` is called on every request before the handler function, by default adding some request information to the context.
 
 Within your handlers:
 - parameters from the route and query, along with other metadata, are set in each context.
@@ -33,5 +33,9 @@ Negotiated content types can be extended by overriding:
 - `renderError(contentType, err)` for outgoing types.
 
 Some handler functions are provided:
-- `handlerGetStaticFile(req, res, ctx, file)` will return a file from a configured directory, and also supports including CERN-style header metadata.  It will also serve pre-encoded variations (e.g `.gz` or `.br`) if available and requested.
-- `handlerRedirect(req, res, ctx, newPath, statusCode)` will return a redirect response.
+- `async handlerGetStaticFile(req, res, ctx, file)` will return a file from a configured directory, and also supports including CERN-style header metadata.  It will also serve pre-encoded variations (e.g. `.gz` or `.br`) if available and requested.
+- `async handlerRedirect(req, res, ctx, newPath, statusCode)` will return a redirect response.
+
+## Performance
+
+While not a specifically-focused target, performance falls roughly midway between [koa](https://koajs.com/) and [fastify](https://fastify.dev/).
index 723f922b20930355d6adc53ead1fc97f6e719597..f839e7a05cf16790779a75a2d6c15d19689d9f98 100644 (file)
@@ -55,18 +55,6 @@ const generateETag = (_filePath, fileStat, fileData) => {
  */
 const get = (obj, prop, def) => obj && prop && (prop in obj) ? obj[prop] : def;
 
-/**
- * @param {http.ClientRequest} req 
- * @param {http.ServerResponse} res 
- * @param {Object} ctx 
- * @deprecated after v1.2.5 (integrated into logger module)
- */
-const handlerLogData = (req, res, ctx) => ({
-  req: requestLogData(req),
-  res: responseLogData(res),
-  ctx,
-});
-
 /**
  * Determine whether a client has already requested a resource,
  * based on If-Modified-Since and If-None-Match headers.
@@ -171,71 +159,6 @@ const pick = (obj, props) => {
   return picked;
 };
 
-/**
- * Return a subset of a request object, suitable for logging.
- * Obscures sensitive header values.
- * @param {http.ClientRequest} req 
- * @deprecated after v1.2.5 (integrated into logger module)
- */
-const requestLogData = (req) => {
-  const data = pick(req, [
-    'method',
-    'url',
-    'httpVersion',
-    'headers',
-    'trailers',
-  ]);
-  scrubHeaderObject(data);
-  return data;
-};
-
-
-/**
- * Remove sensitive header data.
- * @param {Object} data
- * @param {Object} data.headers
- * @deprecated after v1.2.5 (integrated into logger module)
- */
-const scrubHeaderObject = (data) => {
-  if (data?.headers && 'authorization' in data.headers) {
-    data.headers = Object.assign({}, data.headers, {
-      authorization: obscureAuthorizationHeader(data.headers['authorization']),
-    });
-  }
-};
-
-
-/**
- * Hide sensitive part of an Authorization header.
- * @param {String} authHeader
- * @returns {String}
- * @deprecated after v1.2.5 (integrated into logger module)
- */
-const obscureAuthorizationHeader = (authHeader) => {
-  if (!authHeader) {
-    return authHeader;
-  }
-  const space = authHeader.indexOf(' ');
-  // This blurs entire string if no space found, because -1.
-  return authHeader.slice(0, space + 1) + '*'.repeat(authHeader.length - (space + 1));
-};
-
-
-/**
- * Return a subset of a response object, suitable for logging.
- * @param {http.ServerResponse} res 
- * @deprecated after v1.2.5 (integrated into logger module)
- */
-const responseLogData = (res) => {
-  const response = pick(res, [
-    'statusCode',
-    'statusMessage',
-  ]);
-  response.headers = res.getHeaders();
-  return response;
-};
-
-
 /**
  * Store all properties in defaultOptions on target from either options or defaultOptions.
  * @param {Object} target 
@@ -269,37 +192,6 @@ const requestId = () => {
   return uuid.v1();
 };
 
-/**
- * Do nothing.
- */
-const nop = () => { /**/ };
-
-/**
- * A logger object which does nothing.
- */
-const nullLogger = {
-  error: nop,
-  warn: nop,
-  info: nop,
-  log: nop,
-  debug: nop,
-};
-
-/**
- * Populates any absent logger level functions on a logger object.
- * @param {Object} logger
- * @returns {Object}
- * @deprecated after v1.2.9 (this is not our responsibility)
- */
-const ensureLoggerLevels = (logger = {}) => {
-  for (const level in nullLogger) {
-    if (! (level in logger)) {
-      logger[level] = nullLogger[level];
-    }
-  }
-  return logger;
-};
-
 /**
  * Merges folded header lines
  * @param {String[]} lines
@@ -322,23 +214,15 @@ const unfoldHeaderLines = (lines) => {
 };
 
 module.exports = {
-  ensureLoggerLevels,
   fileScope,
   generateETag,
   get,
-  handlerLogData,
   httpStatusCodeClass,
   isClientCached,
   mergeDeep,
   mergeEnum,
-  nop,
-  nullLogger,
-  obscureAuthorizationHeader,
   pick,
   requestId,
-  requestLogData,
-  responseLogData,
-  scrubHeaderObject,
   setOptions,
   splitFirst,
   unfoldHeaderLines,
index 440137448895b393fe2d7dc0903d9086a60347a9..e78fe359303ae8bf2eb06902763ea2297f1baae4 100644 (file)
@@ -102,6 +102,7 @@ class ContentNegotiation {
       if (acc === undefined && validTypesQuality[cur] !== 0.0) {
         return cur;
       }
+      // istanbul ignore next
       // eslint-disable-next-line security/detect-object-injection
       return validTypesQuality[acc] < validTypesQuality[cur] ? cur : acc;
     }, undefined);
index d8eed919a6fd992b463f2fc154edc034ff7dfdb2..9bc428282b94c3f187563266377a370c65b38ccf 100644 (file)
@@ -13,7 +13,7 @@ const querystring = require('querystring');
 const common = require('./common');
 const ContentNegotiation = require('./content-negotiation');
 const Enum = require('./enum');
-const { DingusError, ResponseError } = require('./errors');
+const { ResponseError, RouterNoPathError, RouterNoMethodError } = require('./errors');
 const { extensionToMime } = require('./mime-helper');
 const Router = require('./router');
 const Template = require('./template');
@@ -22,13 +22,15 @@ const Template = require('./template');
 const _fileScope = common.fileScope(__filename);
 
 const defaultOptions = {
-  ignoreTrailingSlash: false,
+  ignoreTrailingSlash: true,
   proxyPrefix: '',
   strictAccept: true,
   selfBaseUrl: '',
   staticMetadata: true,
   staticPath: undefined, // No reasonable default
   trustProxy: true,
+  intrinsicHeadMethod: true,
+  intrinsicHeadPersistBody: false,
   querystring,
 };
 
@@ -36,15 +38,17 @@ class Dingus {
   /**
    * @param {Object} logger object which implements logging methods
    * @param {Object} options
-   * @param {Boolean} options.ignoreTrailingSlash 
+   * @param {Boolean} options.ignoreTrailingSlash requests for '/foo/' will match a '/foo' route
    * @param {string} options.proxyPrefix leading part of url path to strip
    * @param {Boolean} options.strictAccept whether to error on unsupported Accept type
    * @param {string} options.selfBaseUrl for constructing links
    * @param {Boolean} options.staticMetadata serve static headers with static files
    * @param {Boolean} options.trustProxy trust some header data to be provided by proxy
+   * @param {Boolean} options.intrinsicHeadMethod handle HEAD requests automatically if not specified as a route method
+   * @param {Boolean} options.intrinsicHeadPersistBody include un-sent body on ctx for automatic HEAD requests
    * @param {Object} options.querystring alternate qs parser to use
    */
-  constructor(logger = common.nullLogger, options = {}) {
+  constructor(logger = console, options = {}) {
     common.setOptions(this, defaultOptions, options);
 
     this.router = new Router(options);
@@ -253,13 +257,14 @@ class Dingus {
 
 
   /**
-   * Dispatch the handler for a request
-   * @param {http.ClientRequest} req 
-   * @param {http.ServerResponse} res 
-   * @param {object} ctx 
+   * Resolve the handler to invoke for a request.
+   * @param {http.ClientRequest} req
+   * @param {http.ServerResponse} res
+   * @param {object} ctx
+   * @returns {object}
    */
-  async dispatch(req, res, ctx = {}) {
-    const _scope = _fileScope('dispatch');
+  _determineHandler(req, res, ctx) {
+    const _scope = _fileScope('_determineHandler');
 
     const { pathPart, queryParams } = this._splitUrl(req.url);
     ctx.queryParams = queryParams;
@@ -268,26 +273,59 @@ class Dingus {
     try {
       ({ handler, handlerArgs } = this.router.lookup(req.method, pathPart, ctx));
     } catch (e) {
-      if (e instanceof DingusError) {
-        switch (e.message) {
-          case 'NoPath':
-            handler = this.handlerNotFound.bind(this);
-            break;
-          case 'NoMethod':
-            handler = this.handlerMethodNotAllowed.bind(this);
-            break;
-          default:
-            this.logger.error(_scope, 'unknown dingus error', { error: e });
-            handler = this.handlerInternalServerError.bind(this);
-        }
-      } else if (e instanceof URIError) {
+      if (e instanceof URIError) {
         handler = this.handlerBadRequest.bind(this);
+      } else if (e instanceof RouterNoPathError) {
+        handler = this.handlerNotFound.bind(this);
+      } else if (e instanceof RouterNoMethodError) {
+        if (this.intrinsicHeadMethod && req.method === 'HEAD') {
+          ({ handler, handlerArgs } = this._determineHeadHandler(req, res, ctx, pathPart));
+        } else {
+          handler = this.handlerMethodNotAllowed.bind(this);
+        }
+      } else {
+        this.logger.error(_scope, 'unexpected error', { error: e });
+        handler = this.handlerInternalServerError.bind(this);
+      }
+    }
+    return { handler, handlerArgs };
+  }
+
+
+  /**
+   * For intrinsic HEAD requests, resolve the handler to invoke.
+   * @param {http.ClientRequest} req
+   * @param {http.ServerResponse} res
+   * @param {object} ctx
+   * @param {string} pathPart
+   * @returns {object}
+   */
+  _determineHeadHandler(req, res, ctx, pathPart) {
+    const _scope = _fileScope('_determineHeadHandler');
+    let handler, handlerArgs = [];
+    try {
+      ({ handler, handlerArgs } = this.router.lookup('GET', pathPart, ctx));
+      Dingus.setHeadHandler(req, res, ctx, this.intrinsicHeadPersistBody);
+    } catch (e) {
+      if (e instanceof RouterNoMethodError) {
+        handler = this.handlerMethodNotAllowed.bind(this);
       } else {
-        this.logger.error(_scope, 'lookup failure', { error: e });
+        this.logger.error(_scope, 'unexpected error', { error: e });
         handler = this.handlerInternalServerError.bind(this);
       }
     }
+    return { handler, handlerArgs };
+  }
+
 
+  /**
+   * Dispatch the handler for a request
+   * @param {http.ClientRequest} req
+   * @param {http.ServerResponse} res
+   * @param {object} ctx
+   */
+  async dispatch(req, res, ctx = {}) {
+    const { handler, handlerArgs } = this._determineHandler(req, res, ctx);
     try {
       await this.preHandler(req, res, ctx);
       return await handler(req, res, ctx, ...handlerArgs);
@@ -313,16 +351,11 @@ class Dingus {
    * Parse rawBody as contentType into ctx.parsedBody.
    * @param {string} contentType
    * @param {object} ctx
-   * @param {string|buffer}
+   * @param {string|buffer} rawBody
   */
   parseBody(contentType, ctx, rawBody) {
     const _scope = _fileScope('parseBody');
 
-    if (!rawBody) {
-      // 1.2.4 and earlier expected rawBody on context
-      rawBody = ctx.rawBody;
-    }
-
     switch (contentType) {
       case Enum.ContentType.ApplicationForm:
         ctx.parsedBody = this.querystring.parse(rawBody);
index ed5b151461060215146bdcfdccacafce9fe76c1a..942ecc0f684656059f4e0fad66288db7c57f2647 100644 (file)
@@ -22,7 +22,23 @@ class ResponseError extends DingusError {
   }
 }
 
+class RouterError extends DingusError {
+  constructor(...args) {
+    super(...args);
+    delete this.stack;
+  }
+}
+
+class RouterNoPathError extends RouterError {
+}
+
+class RouterNoMethodError extends RouterError {
+}
+
 module.exports = {
   DingusError,
   ResponseError,
+  RouterError,
+  RouterNoPathError,
+  RouterNoMethodError,
 };
index 086dc6a4bf16b8a59765b8f60e97d23fe96f849f..687d27b7c33bf9baca52c9e47df45313dc7cb542 100644 (file)
@@ -4,15 +4,23 @@
 const mimeDb = require('mime-db');
 
 const defaultType = 'application/octet-stream';
+
+/**
+ * Expects mime-db source data as object:
+ *   mime-type:
+ *     source: <String>
+ *     charset: <String>
+ *     compressible: <Boolean>
+ *     extensions: <String[]>
+ * Populate `extension` as an index from extensions to mime-types.
+ */
 const extension = {};
 for (const [mimeType, entry] of Object.entries(mimeDb)) {
-  if (entry.extensions) {
-    entry.extensions.forEach((ext) => {
-      if (!(ext in extension)) {
-        extension[ext] = [];
-      }
-      extension[ext].push(mimeType);
-    });
+  for (const ext of entry?.extensions || []) {
+    if (!(ext in extension)) {
+      extension[ext] = [];
+    }
+    extension[ext].push(mimeType);
   }
 }
 
@@ -20,8 +28,9 @@ for (const [mimeType, entry] of Object.entries(mimeDb)) {
  * Return a suitable type for a file extension.
  * @param {string} ext file extension
  * @param {string} def type to return if no match
+ * @returns {string}
  */
-const extensionToMime = (ext, def = defaultType) => extension[ext] && extension[ext][extension[ext].length - 1] || def;
+const extensionToMime = (ext, def = defaultType) => extension?.[ext]?.[0] || def;
 
 module.exports = {
   extensionToMime,
index 1585065e14ce79b804cd6de967965951ab0d535a..fd19bdf5192cfd9efd7b4c00023f1ae92265cbd1 100644 (file)
@@ -7,7 +7,7 @@
 
 const { METHODS: httpMethods } = require('http');
 const common = require('../common');
-const { DingusError } = require('../errors');
+const { DingusError, RouterNoPathError, RouterNoMethodError } = require('../errors');
 const PathParameter = require('./path-parameter');
 
 // Internal identifiers for route entries.
@@ -266,10 +266,10 @@ class Router {
       if ('*' in matchedPath[kPathMethods]) {
         return matchedPath[kPathMethods]['*'];
       }
-      throw new DingusError('NoMethod');
+      throw new RouterNoMethodError();
     }
     ctx.unmatchedPath = pathParts;
-    throw new DingusError('NoPath');
+    throw new RouterNoPathError();
   }
 
 
index 848f960b247d8906759fc8876075c0117372b55f..25a4a28dbb1a8f24657189eda8fd3ad5a112768b 100644 (file)
@@ -1,22 +1,22 @@
 {
   "name": "@squeep/api-dingus",
-  "version": "1.2.10",
+  "version": "2.0.0",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "@squeep/api-dingus",
-      "version": "1.2.10",
+      "version": "2.0.0",
       "license": "ISC",
       "dependencies": {
         "mime-db": "^1.52.0",
         "uuid": "^9.0.0"
       },
       "devDependencies": {
-        "eslint": "^8.45.0",
+        "eslint": "^8.48.0",
         "eslint-plugin-node": "^11.1.0",
         "eslint-plugin-security": "^1.7.1",
-        "eslint-plugin-sonarjs": "^0.19.0",
+        "eslint-plugin-sonarjs": "^0.21.0",
         "mocha": "^10.2.0",
         "nyc": "^15.1.0",
         "pre-commit": "^1.2.2",
       }
     },
     "node_modules/@babel/code-frame": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
-      "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz",
+      "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==",
       "dev": true,
       "dependencies": {
-        "@babel/highlight": "^7.22.5"
+        "@babel/highlight": "^7.22.10",
+        "chalk": "^2.4.2"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
+    "node_modules/@babel/code-frame/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+      "dev": true
+    },
+    "node_modules/@babel/code-frame/node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/@babel/compat-data": {
       "version": "7.22.9",
       "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz",
       }
     },
     "node_modules/@babel/core": {
-      "version": "7.22.9",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz",
-      "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==",
+      "version": "7.22.11",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.11.tgz",
+      "integrity": "sha512-lh7RJrtPdhibbxndr6/xx0w8+CVlY5FJZiaSz908Fpy+G0xkBFTvwLcKJFF4PJxVfGhVWNebikpWGnOoC71juQ==",
       "dev": true,
       "dependencies": {
         "@ampproject/remapping": "^2.2.0",
-        "@babel/code-frame": "^7.22.5",
-        "@babel/generator": "^7.22.9",
-        "@babel/helper-compilation-targets": "^7.22.9",
+        "@babel/code-frame": "^7.22.10",
+        "@babel/generator": "^7.22.10",
+        "@babel/helper-compilation-targets": "^7.22.10",
         "@babel/helper-module-transforms": "^7.22.9",
-        "@babel/helpers": "^7.22.6",
-        "@babel/parser": "^7.22.7",
+        "@babel/helpers": "^7.22.11",
+        "@babel/parser": "^7.22.11",
         "@babel/template": "^7.22.5",
-        "@babel/traverse": "^7.22.8",
-        "@babel/types": "^7.22.5",
+        "@babel/traverse": "^7.22.11",
+        "@babel/types": "^7.22.11",
         "convert-source-map": "^1.7.0",
         "debug": "^4.1.0",
         "gensync": "^1.0.0-beta.2",
-        "json5": "^2.2.2",
+        "json5": "^2.2.3",
         "semver": "^6.3.1"
       },
       "engines": {
       }
     },
     "node_modules/@babel/generator": {
-      "version": "7.22.9",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz",
-      "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==",
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz",
+      "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==",
       "dev": true,
       "dependencies": {
-        "@babel/types": "^7.22.5",
+        "@babel/types": "^7.22.10",
         "@jridgewell/gen-mapping": "^0.3.2",
         "@jridgewell/trace-mapping": "^0.3.17",
         "jsesc": "^2.5.1"
       }
     },
     "node_modules/@babel/helper-compilation-targets": {
-      "version": "7.22.9",
-      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz",
-      "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==",
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz",
+      "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==",
       "dev": true,
       "dependencies": {
         "@babel/compat-data": "^7.22.9",
       },
       "engines": {
         "node": ">=6.9.0"
-      },
-      "peerDependencies": {
-        "@babel/core": "^7.0.0"
       }
     },
     "node_modules/@babel/helper-environment-visitor": {
       }
     },
     "node_modules/@babel/helpers": {
-      "version": "7.22.6",
-      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz",
-      "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==",
+      "version": "7.22.11",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.11.tgz",
+      "integrity": "sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==",
       "dev": true,
       "dependencies": {
         "@babel/template": "^7.22.5",
-        "@babel/traverse": "^7.22.6",
-        "@babel/types": "^7.22.5"
+        "@babel/traverse": "^7.22.11",
+        "@babel/types": "^7.22.11"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/highlight": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
-      "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz",
+      "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==",
       "dev": true,
       "dependencies": {
         "@babel/helper-validator-identifier": "^7.22.5",
-        "chalk": "^2.0.0",
+        "chalk": "^2.4.2",
         "js-tokens": "^4.0.0"
       },
       "engines": {
       }
     },
     "node_modules/@babel/parser": {
-      "version": "7.22.7",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz",
-      "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==",
+      "version": "7.22.11",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.11.tgz",
+      "integrity": "sha512-R5zb8eJIBPJriQtbH/htEQy4k7E2dHWlD2Y2VT07JCzwYZHBxV5ZYtM0UhXSNMT74LyxuM+b1jdL7pSesXbC/g==",
       "dev": true,
       "bin": {
         "parser": "bin/babel-parser.js"
       }
     },
     "node_modules/@babel/traverse": {
-      "version": "7.22.8",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz",
-      "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==",
+      "version": "7.22.11",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.11.tgz",
+      "integrity": "sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==",
       "dev": true,
       "dependencies": {
-        "@babel/code-frame": "^7.22.5",
-        "@babel/generator": "^7.22.7",
+        "@babel/code-frame": "^7.22.10",
+        "@babel/generator": "^7.22.10",
         "@babel/helper-environment-visitor": "^7.22.5",
         "@babel/helper-function-name": "^7.22.5",
         "@babel/helper-hoist-variables": "^7.22.5",
         "@babel/helper-split-export-declaration": "^7.22.6",
-        "@babel/parser": "^7.22.7",
-        "@babel/types": "^7.22.5",
+        "@babel/parser": "^7.22.11",
+        "@babel/types": "^7.22.11",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
       },
       }
     },
     "node_modules/@babel/types": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
-      "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
+      "version": "7.22.11",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.11.tgz",
+      "integrity": "sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==",
       "dev": true,
       "dependencies": {
         "@babel/helper-string-parser": "^7.22.5",
       }
     },
     "node_modules/@eslint-community/regexpp": {
-      "version": "4.5.1",
-      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz",
-      "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==",
+      "version": "4.8.0",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz",
+      "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==",
       "dev": true,
       "engines": {
         "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
       }
     },
     "node_modules/@eslint/eslintrc": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz",
-      "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==",
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
+      "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
       "dev": true,
       "dependencies": {
         "ajv": "^6.12.4",
       }
     },
     "node_modules/@eslint/js": {
-      "version": "8.44.0",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz",
-      "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==",
+      "version": "8.48.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz",
+      "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==",
       "dev": true,
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       }
     },
     "node_modules/@jridgewell/resolve-uri": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
-      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
+      "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
       "dev": true,
       "engines": {
         "node": ">=6.0.0"
       "dev": true
     },
     "node_modules/@jridgewell/trace-mapping": {
-      "version": "0.3.18",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
-      "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
+      "version": "0.3.19",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
+      "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
       "dev": true,
       "dependencies": {
-        "@jridgewell/resolve-uri": "3.1.0",
-        "@jridgewell/sourcemap-codec": "1.4.14"
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
       }
     },
-    "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": {
-      "version": "1.4.14",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
-      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
-      "dev": true
-    },
     "node_modules/@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
       "dev": true
     },
     "node_modules/browserslist": {
-      "version": "4.21.9",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz",
-      "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==",
+      "version": "4.21.10",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
+      "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==",
       "dev": true,
       "funding": [
         {
         }
       ],
       "dependencies": {
-        "caniuse-lite": "^1.0.30001503",
-        "electron-to-chromium": "^1.4.431",
-        "node-releases": "^2.0.12",
+        "caniuse-lite": "^1.0.30001517",
+        "electron-to-chromium": "^1.4.477",
+        "node-releases": "^2.0.13",
         "update-browserslist-db": "^1.0.11"
       },
       "bin": {
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001516",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001516.tgz",
-      "integrity": "sha512-Wmec9pCBY8CWbmI4HsjBeQLqDTqV91nFVR83DnZpYyRnPI1wePDsTg0bGLPC5VU/3OIZV1fmxEea1b+tFKe86g==",
+      "version": "1.0.30001523",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001523.tgz",
+      "integrity": "sha512-I5q5cisATTPZ1mc588Z//pj/Ox80ERYDfR71YnvY7raS/NOk8xXlZcB0sF7JdqaV//kOaa6aus7lRfpdnt1eBA==",
       "dev": true,
       "funding": [
         {
       }
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.4.462",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.462.tgz",
-      "integrity": "sha512-ux2LqN9JKRBDKXMT+78jtiBLPiXf+rLtYlsrOg5Qn7uv6Cbg7+9JyIalE3wcqkOdB2wPCUYNWAuL7suKRMHe9w==",
+      "version": "1.4.502",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.502.tgz",
+      "integrity": "sha512-xqeGw3Gr6o3uyHy/yKjdnDQHY2RQvXcGC2cfHjccK1IGkH6cX1WQBN8EeC/YpwPhGkBaikDTecJ8+ssxSVRQlw==",
       "dev": true
     },
     "node_modules/emoji-regex": {
       }
     },
     "node_modules/eslint": {
-      "version": "8.45.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz",
-      "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==",
+      "version": "8.48.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz",
+      "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.2.0",
-        "@eslint-community/regexpp": "^4.4.0",
-        "@eslint/eslintrc": "^2.1.0",
-        "@eslint/js": "8.44.0",
+        "@eslint-community/regexpp": "^4.6.1",
+        "@eslint/eslintrc": "^2.1.2",
+        "@eslint/js": "8.48.0",
         "@humanwhocodes/config-array": "^0.11.10",
         "@humanwhocodes/module-importer": "^1.0.1",
         "@nodelib/fs.walk": "^1.2.8",
-        "ajv": "^6.10.0",
+        "ajv": "^6.12.4",
         "chalk": "^4.0.0",
         "cross-spawn": "^7.0.2",
         "debug": "^4.3.2",
         "doctrine": "^3.0.0",
         "escape-string-regexp": "^4.0.0",
-        "eslint-scope": "^7.2.0",
-        "eslint-visitor-keys": "^3.4.1",
-        "espree": "^9.6.0",
+        "eslint-scope": "^7.2.2",
+        "eslint-visitor-keys": "^3.4.3",
+        "espree": "^9.6.1",
         "esquery": "^1.4.2",
         "esutils": "^2.0.2",
         "fast-deep-equal": "^3.1.3",
       }
     },
     "node_modules/eslint-plugin-sonarjs": {
-      "version": "0.19.0",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.19.0.tgz",
-      "integrity": "sha512-6+s5oNk5TFtVlbRxqZN7FIGmjdPCYQKaTzFPmqieCmsU1kBYDzndTeQav0xtQNwZJWu5awWfTGe8Srq9xFOGnw==",
+      "version": "0.21.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.21.0.tgz",
+      "integrity": "sha512-oezUDfFT5S6j3rQheZ4DLPrbetPmMS7zHIKWGHr0CM3g5JgyZroz1FpIKa4jV83NsGpmgIeagpokWDKIJzRQmw==",
       "dev": true,
       "engines": {
         "node": ">=14"
       }
     },
     "node_modules/eslint-scope": {
-      "version": "7.2.1",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.1.tgz",
-      "integrity": "sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA==",
+      "version": "7.2.2",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+      "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
       "dev": true,
       "dependencies": {
         "esrecurse": "^4.3.0",
       }
     },
     "node_modules/eslint-visitor-keys": {
-      "version": "3.4.1",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz",
-      "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==",
+      "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"
       "dev": true
     },
     "node_modules/fsevents": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
-      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
       "dev": true,
       "hasInstallScript": true,
       "optional": true,
       }
     },
     "node_modules/globals": {
-      "version": "13.20.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
-      "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+      "version": "13.21.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz",
+      "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==",
       "dev": true,
       "dependencies": {
         "type-fest": "^0.20.2"
       }
     },
     "node_modules/is-core-module": {
-      "version": "2.12.1",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
-      "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
+      "version": "2.13.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
+      "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
       "dev": true,
       "dependencies": {
         "has": "^1.0.3"
       }
     },
     "node_modules/istanbul-lib-report": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
-      "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
+      "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
       "dev": true,
       "dependencies": {
         "istanbul-lib-coverage": "^3.0.0",
-        "make-dir": "^3.0.0",
+        "make-dir": "^4.0.0",
         "supports-color": "^7.1.0"
       },
       "engines": {
-        "node": ">=8"
+        "node": ">=10"
       }
     },
+    "node_modules/istanbul-lib-report/node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/istanbul-lib-report/node_modules/make-dir": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
+      "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
+      "dev": true,
+      "dependencies": {
+        "semver": "^7.5.3"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/istanbul-lib-report/node_modules/semver": {
+      "version": "7.5.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/istanbul-lib-report/node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true
+    },
     "node_modules/istanbul-lib-source-maps": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
       }
     },
     "node_modules/istanbul-reports": {
-      "version": "3.1.5",
-      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
-      "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz",
+      "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==",
       "dev": true,
       "dependencies": {
         "html-escaper": "^2.0.0",
       "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
       "dev": true
     },
-    "node_modules/readable-stream/node_modules/safe-buffer": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-      "dev": true
-    },
     "node_modules/readdirp": {
       "version": "3.6.0",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
       "dev": true
     },
     "node_modules/resolve": {
-      "version": "1.22.2",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
-      "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
+      "version": "1.22.4",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz",
+      "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==",
       "dev": true,
       "dependencies": {
-        "is-core-module": "^2.11.0",
+        "is-core-module": "^2.13.0",
         "path-parse": "^1.0.7",
         "supports-preserve-symlinks-flag": "^1.0.0"
       },
       }
     },
     "node_modules/safe-buffer": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-      "dev": true,
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ]
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
     },
     "node_modules/safe-regex": {
       "version": "2.1.1",
         "safe-buffer": "~5.1.0"
       }
     },
-    "node_modules/string_decoder/node_modules/safe-buffer": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-      "dev": true
-    },
     "node_modules/string-width": {
       "version": "4.2.3",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
       }
     },
     "@babel/code-frame": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
-      "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz",
+      "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==",
       "dev": true,
       "requires": {
-        "@babel/highlight": "^7.22.5"
+        "@babel/highlight": "^7.22.10",
+        "chalk": "^2.4.2"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "color-convert": {
+          "version": "1.9.3",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+          "dev": true,
+          "requires": {
+            "color-name": "1.1.3"
+          }
+        },
+        "color-name": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+          "dev": true
+        },
+        "escape-string-regexp": {
+          "version": "1.0.5",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+          "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
       }
     },
     "@babel/compat-data": {
       "dev": true
     },
     "@babel/core": {
-      "version": "7.22.9",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz",
-      "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==",
+      "version": "7.22.11",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.11.tgz",
+      "integrity": "sha512-lh7RJrtPdhibbxndr6/xx0w8+CVlY5FJZiaSz908Fpy+G0xkBFTvwLcKJFF4PJxVfGhVWNebikpWGnOoC71juQ==",
       "dev": true,
       "requires": {
         "@ampproject/remapping": "^2.2.0",
-        "@babel/code-frame": "^7.22.5",
-        "@babel/generator": "^7.22.9",
-        "@babel/helper-compilation-targets": "^7.22.9",
+        "@babel/code-frame": "^7.22.10",
+        "@babel/generator": "^7.22.10",
+        "@babel/helper-compilation-targets": "^7.22.10",
         "@babel/helper-module-transforms": "^7.22.9",
-        "@babel/helpers": "^7.22.6",
-        "@babel/parser": "^7.22.7",
+        "@babel/helpers": "^7.22.11",
+        "@babel/parser": "^7.22.11",
         "@babel/template": "^7.22.5",
-        "@babel/traverse": "^7.22.8",
-        "@babel/types": "^7.22.5",
+        "@babel/traverse": "^7.22.11",
+        "@babel/types": "^7.22.11",
         "convert-source-map": "^1.7.0",
         "debug": "^4.1.0",
         "gensync": "^1.0.0-beta.2",
-        "json5": "^2.2.2",
+        "json5": "^2.2.3",
         "semver": "^6.3.1"
       }
     },
     "@babel/generator": {
-      "version": "7.22.9",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz",
-      "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==",
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz",
+      "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.22.5",
+        "@babel/types": "^7.22.10",
         "@jridgewell/gen-mapping": "^0.3.2",
         "@jridgewell/trace-mapping": "^0.3.17",
         "jsesc": "^2.5.1"
       }
     },
     "@babel/helper-compilation-targets": {
-      "version": "7.22.9",
-      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz",
-      "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==",
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz",
+      "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==",
       "dev": true,
       "requires": {
         "@babel/compat-data": "^7.22.9",
       "dev": true
     },
     "@babel/helpers": {
-      "version": "7.22.6",
-      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz",
-      "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==",
+      "version": "7.22.11",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.11.tgz",
+      "integrity": "sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==",
       "dev": true,
       "requires": {
         "@babel/template": "^7.22.5",
-        "@babel/traverse": "^7.22.6",
-        "@babel/types": "^7.22.5"
+        "@babel/traverse": "^7.22.11",
+        "@babel/types": "^7.22.11"
       }
     },
     "@babel/highlight": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
-      "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz",
+      "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==",
       "dev": true,
       "requires": {
         "@babel/helper-validator-identifier": "^7.22.5",
-        "chalk": "^2.0.0",
+        "chalk": "^2.4.2",
         "js-tokens": "^4.0.0"
       },
       "dependencies": {
       }
     },
     "@babel/parser": {
-      "version": "7.22.7",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz",
-      "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==",
+      "version": "7.22.11",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.11.tgz",
+      "integrity": "sha512-R5zb8eJIBPJriQtbH/htEQy4k7E2dHWlD2Y2VT07JCzwYZHBxV5ZYtM0UhXSNMT74LyxuM+b1jdL7pSesXbC/g==",
       "dev": true
     },
     "@babel/template": {
       }
     },
     "@babel/traverse": {
-      "version": "7.22.8",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz",
-      "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==",
+      "version": "7.22.11",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.11.tgz",
+      "integrity": "sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==",
       "dev": true,
       "requires": {
-        "@babel/code-frame": "^7.22.5",
-        "@babel/generator": "^7.22.7",
+        "@babel/code-frame": "^7.22.10",
+        "@babel/generator": "^7.22.10",
         "@babel/helper-environment-visitor": "^7.22.5",
         "@babel/helper-function-name": "^7.22.5",
         "@babel/helper-hoist-variables": "^7.22.5",
         "@babel/helper-split-export-declaration": "^7.22.6",
-        "@babel/parser": "^7.22.7",
-        "@babel/types": "^7.22.5",
+        "@babel/parser": "^7.22.11",
+        "@babel/types": "^7.22.11",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
       },
       }
     },
     "@babel/types": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
-      "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
+      "version": "7.22.11",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.11.tgz",
+      "integrity": "sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==",
       "dev": true,
       "requires": {
         "@babel/helper-string-parser": "^7.22.5",
       }
     },
     "@eslint-community/regexpp": {
-      "version": "4.5.1",
-      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz",
-      "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==",
+      "version": "4.8.0",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz",
+      "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==",
       "dev": true
     },
     "@eslint/eslintrc": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz",
-      "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==",
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
+      "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
       "dev": true,
       "requires": {
         "ajv": "^6.12.4",
       }
     },
     "@eslint/js": {
-      "version": "8.44.0",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz",
-      "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==",
+      "version": "8.48.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz",
+      "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==",
       "dev": true
     },
     "@humanwhocodes/config-array": {
       }
     },
     "@jridgewell/resolve-uri": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
-      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
+      "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
       "dev": true
     },
     "@jridgewell/set-array": {
       "dev": true
     },
     "@jridgewell/trace-mapping": {
-      "version": "0.3.18",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
-      "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
+      "version": "0.3.19",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
+      "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
       "dev": true,
       "requires": {
-        "@jridgewell/resolve-uri": "3.1.0",
-        "@jridgewell/sourcemap-codec": "1.4.14"
-      },
-      "dependencies": {
-        "@jridgewell/sourcemap-codec": {
-          "version": "1.4.14",
-          "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
-          "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
-          "dev": true
-        }
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
       }
     },
     "@nodelib/fs.scandir": {
       "dev": true
     },
     "browserslist": {
-      "version": "4.21.9",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz",
-      "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==",
+      "version": "4.21.10",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
+      "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==",
       "dev": true,
       "requires": {
-        "caniuse-lite": "^1.0.30001503",
-        "electron-to-chromium": "^1.4.431",
-        "node-releases": "^2.0.12",
+        "caniuse-lite": "^1.0.30001517",
+        "electron-to-chromium": "^1.4.477",
+        "node-releases": "^2.0.13",
         "update-browserslist-db": "^1.0.11"
       }
     },
       "dev": true
     },
     "caniuse-lite": {
-      "version": "1.0.30001516",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001516.tgz",
-      "integrity": "sha512-Wmec9pCBY8CWbmI4HsjBeQLqDTqV91nFVR83DnZpYyRnPI1wePDsTg0bGLPC5VU/3OIZV1fmxEea1b+tFKe86g==",
+      "version": "1.0.30001523",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001523.tgz",
+      "integrity": "sha512-I5q5cisATTPZ1mc588Z//pj/Ox80ERYDfR71YnvY7raS/NOk8xXlZcB0sF7JdqaV//kOaa6aus7lRfpdnt1eBA==",
       "dev": true
     },
     "chalk": {
       }
     },
     "electron-to-chromium": {
-      "version": "1.4.462",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.462.tgz",
-      "integrity": "sha512-ux2LqN9JKRBDKXMT+78jtiBLPiXf+rLtYlsrOg5Qn7uv6Cbg7+9JyIalE3wcqkOdB2wPCUYNWAuL7suKRMHe9w==",
+      "version": "1.4.502",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.502.tgz",
+      "integrity": "sha512-xqeGw3Gr6o3uyHy/yKjdnDQHY2RQvXcGC2cfHjccK1IGkH6cX1WQBN8EeC/YpwPhGkBaikDTecJ8+ssxSVRQlw==",
       "dev": true
     },
     "emoji-regex": {
       "dev": true
     },
     "eslint": {
-      "version": "8.45.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz",
-      "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==",
+      "version": "8.48.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz",
+      "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==",
       "dev": true,
       "requires": {
         "@eslint-community/eslint-utils": "^4.2.0",
-        "@eslint-community/regexpp": "^4.4.0",
-        "@eslint/eslintrc": "^2.1.0",
-        "@eslint/js": "8.44.0",
+        "@eslint-community/regexpp": "^4.6.1",
+        "@eslint/eslintrc": "^2.1.2",
+        "@eslint/js": "8.48.0",
         "@humanwhocodes/config-array": "^0.11.10",
         "@humanwhocodes/module-importer": "^1.0.1",
         "@nodelib/fs.walk": "^1.2.8",
-        "ajv": "^6.10.0",
+        "ajv": "^6.12.4",
         "chalk": "^4.0.0",
         "cross-spawn": "^7.0.2",
         "debug": "^4.3.2",
         "doctrine": "^3.0.0",
         "escape-string-regexp": "^4.0.0",
-        "eslint-scope": "^7.2.0",
-        "eslint-visitor-keys": "^3.4.1",
-        "espree": "^9.6.0",
+        "eslint-scope": "^7.2.2",
+        "eslint-visitor-keys": "^3.4.3",
+        "espree": "^9.6.1",
         "esquery": "^1.4.2",
         "esutils": "^2.0.2",
         "fast-deep-equal": "^3.1.3",
       }
     },
     "eslint-plugin-sonarjs": {
-      "version": "0.19.0",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.19.0.tgz",
-      "integrity": "sha512-6+s5oNk5TFtVlbRxqZN7FIGmjdPCYQKaTzFPmqieCmsU1kBYDzndTeQav0xtQNwZJWu5awWfTGe8Srq9xFOGnw==",
+      "version": "0.21.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.21.0.tgz",
+      "integrity": "sha512-oezUDfFT5S6j3rQheZ4DLPrbetPmMS7zHIKWGHr0CM3g5JgyZroz1FpIKa4jV83NsGpmgIeagpokWDKIJzRQmw==",
       "dev": true,
       "requires": {}
     },
     "eslint-scope": {
-      "version": "7.2.1",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.1.tgz",
-      "integrity": "sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA==",
+      "version": "7.2.2",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+      "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
       "dev": true,
       "requires": {
         "esrecurse": "^4.3.0",
       }
     },
     "eslint-visitor-keys": {
-      "version": "3.4.1",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz",
-      "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==",
+      "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
     },
     "espree": {
       "dev": true
     },
     "fsevents": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
-      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
       "dev": true,
       "optional": true
     },
       }
     },
     "globals": {
-      "version": "13.20.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
-      "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+      "version": "13.21.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz",
+      "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==",
       "dev": true,
       "requires": {
         "type-fest": "^0.20.2"
       }
     },
     "is-core-module": {
-      "version": "2.12.1",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
-      "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
+      "version": "2.13.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
+      "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
       "dev": true,
       "requires": {
         "has": "^1.0.3"
       }
     },
     "istanbul-lib-report": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
-      "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
+      "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
       "dev": true,
       "requires": {
         "istanbul-lib-coverage": "^3.0.0",
-        "make-dir": "^3.0.0",
+        "make-dir": "^4.0.0",
         "supports-color": "^7.1.0"
+      },
+      "dependencies": {
+        "lru-cache": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+          "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+          "dev": true,
+          "requires": {
+            "yallist": "^4.0.0"
+          }
+        },
+        "make-dir": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
+          "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
+          "dev": true,
+          "requires": {
+            "semver": "^7.5.3"
+          }
+        },
+        "semver": {
+          "version": "7.5.4",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+          "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "yallist": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+          "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+          "dev": true
+        }
       }
     },
     "istanbul-lib-source-maps": {
       }
     },
     "istanbul-reports": {
-      "version": "3.1.5",
-      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
-      "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz",
+      "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==",
       "dev": true,
       "requires": {
         "html-escaper": "^2.0.0",
           "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
           "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
           "dev": true
-        },
-        "safe-buffer": {
-          "version": "5.1.2",
-          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-          "dev": true
         }
       }
     },
       "dev": true
     },
     "resolve": {
-      "version": "1.22.2",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
-      "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
+      "version": "1.22.4",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz",
+      "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==",
       "dev": true,
       "requires": {
-        "is-core-module": "^2.11.0",
+        "is-core-module": "^2.13.0",
         "path-parse": "^1.0.7",
         "supports-preserve-symlinks-flag": "^1.0.0"
       }
       }
     },
     "safe-buffer": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
       "dev": true
     },
     "safe-regex": {
       "dev": true,
       "requires": {
         "safe-buffer": "~5.1.0"
-      },
-      "dependencies": {
-        "safe-buffer": {
-          "version": "5.1.2",
-          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-          "dev": true
-        }
       }
     },
     "string-width": {
index 5ae6e87a7d06fb2bbc1c426866591234f3546b42..4e2fbe5d24a7a0f08101d647f9f63a40c2b879f3 100644 (file)
@@ -1,6 +1,6 @@
 {
   "name": "@squeep/api-dingus",
-  "version": "1.2.10",
+  "version": "2.0.0",
   "description": "An API server framework",
   "main": "index.js",
   "scripts": {
     "uuid": "^9.0.0"
   },
   "devDependencies": {
-    "eslint": "^8.45.0",
+    "eslint": "^8.48.0",
     "eslint-plugin-node": "^11.1.0",
     "eslint-plugin-security": "^1.7.1",
-    "eslint-plugin-sonarjs": "^0.19.0",
+    "eslint-plugin-sonarjs": "^0.21.0",
     "mocha": "^10.2.0",
     "nyc": "^15.1.0",
     "pre-commit": "^1.2.2",
index 57c4113a9db986dbee499942e6e11ea0a78964b9..15e9c4adb07652b1e0376327f5aa4a5e55426bf2 100644 (file)
@@ -128,100 +128,6 @@ describe('common', function () {
     });
   }); // pick
 
-  describe('requestLogData', function () {
-    it('gives data', function () {
-      const req = {
-        method: 'GET',
-        somethingElse: 'blah',
-      };
-      const result = common.requestLogData(req);
-      assert.deepStrictEqual(result, {
-        method: 'GET',
-      });
-    });
-  }); // requestLogData
-
-  describe('obscureAuthorizationHeader', function () {
-    it('obscures basic data', function () {
-      const authHeader = 'Basic Zm9vOmJhcg==';
-      const expected = 'Basic ************';
-      const result = common.obscureAuthorizationHeader(authHeader);
-      assert.strictEqual(result, expected);
-    });
-    it('obscures all of other types', function () {
-      const authHeader = 'someWeirdAuth';
-      const expected = '*************';
-      const result = common.obscureAuthorizationHeader(authHeader);
-      assert.strictEqual(result, expected);
-    });
-    it('does nothing when empty', function () {
-      const authHeader = undefined;
-      const expected = undefined;
-      const result = common.obscureAuthorizationHeader(authHeader);
-      assert.strictEqual(result, expected);
-    });
-  }); // obscureAuthorizationHeader
-
-  describe('scrubHeaderObject', function () {
-    it('', function () {
-      const data = {
-        headers: {
-          'foo': 'bar',
-          'authorization': 'Basic Zm9vOmJhcg==',
-        },
-      };
-      const expected = {
-        headers: {
-          'foo': 'bar',
-          'authorization': 'Basic ************',
-        },
-      };
-      common.scrubHeaderObject(data);
-      assert.deepStrictEqual(data, expected);
-    });
-  }); // scrubHeaderObject
-
-  describe('responseLogData', function () {
-    it('gives data', function () {
-      const res = {
-        getHeaders: () => ({}),
-        statusCode: 200,
-        blah: 'blah',
-      };
-      const result = common.responseLogData(res);
-      assert.deepStrictEqual(result, {
-        headers: {},
-        statusCode: 200,
-      });
-    });
-  }); // responseLogData
-
-  describe('handlerLogData', function () {
-    it('covers', function () {
-      const req = {
-        method: 'GET',
-        somethingElse: 'blah',
-      };
-      const res = {
-        getHeaders: () => ({}),
-        statusCode: 200,
-        blah: 'blah',
-      };
-      const ctx = {};
-      const result = common.handlerLogData(req, res, ctx);
-      assert.deepStrictEqual(result, {
-        req: {
-          method: 'GET',
-        },
-        res: {
-          headers: {},
-          statusCode: 200,
-        },
-        ctx: {},
-      });
-    });
-  }); // handlerLogData
-
   describe('setOptions', function () {
     it('sets options', function () {
       const expected = {
@@ -324,13 +230,6 @@ describe('common', function () {
     });
   }); // requestId
 
-  describe('ensureLoggerLevels', function () {
-    it('adds missing levels', function () {
-      const result = common.ensureLoggerLevels();
-      assert.deepStrictEqual(result, common.nullLogger);
-    });
-  }); // ensureLoggerLevels
-
   describe('httpStatusCodeClass', function () {
     it('works', function () {
       for (const [statusCode, statusClassExpected] of Object.entries({
index 12f40e8a83dad33690f7bbc535d68dfc19a4c9c3..9d471229d3a26ebde87ebfae9d53efbde46c9aaa 100644 (file)
@@ -7,15 +7,20 @@ const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-requi
 const fs = require('fs');
 
 const Dingus = require('../../lib/dingus');
-const { DingusError } = require('../../lib/errors');
+const { DingusError, RouterNoMethodError } = require('../../lib/errors');
 const Enum = require('../../lib/enum');
 
 const noExpectedException = 'did not get expected exception';
 
+const noLogger = {
+  debug: () => {},
+  error: () => {},
+};
+
 describe('Dingus', function () {
   let dingus;
   beforeEach(function () {
-    dingus = new Dingus();
+    dingus = new Dingus(noLogger, {});
   });
   afterEach(function () {
     sinon.restore();
@@ -23,7 +28,7 @@ describe('Dingus', function () {
 
   describe('constructor', function () {
     it('covers', function () {
-      const d = new Dingus({}, {});
+      const d = new Dingus();
       assert(d);
     });
   }); // constructor
@@ -36,7 +41,7 @@ describe('Dingus', function () {
     });
     it('returns normal path', function () {
       const p = '////a///b/./bar/..///c';
-      const expected = '/a/b/c'
+      const expected = '/a/b/c';
       const r = dingus._normalizePath(p);
       assert.strictEqual(r, expected);
     });
@@ -152,7 +157,7 @@ describe('Dingus', function () {
       const expected = {
         clientAddress: '',
         clientProtocol: 'http',
-      }
+      };
       dingus.clientAddressContext(req, res, ctx);
       assert.deepStrictEqual(ctx, expected);
       assert(!req.getHeader.called);
@@ -162,7 +167,7 @@ describe('Dingus', function () {
       const expected = {
         clientAddress: '::1',
         clientProtocol: 'https',
-      }
+      };
       req.connection.remoteAddress = '::1';
       req.connection.encrypted = true;
       dingus.clientAddressContext(req, res, ctx);
@@ -350,6 +355,7 @@ describe('Dingus', function () {
       sinon.spy(dingus, 'handlerNotFound');
       sinon.spy(dingus, 'handlerBadRequest');
       sinon.spy(dingus, 'handlerInternalServerError');
+      sinon.spy(Dingus, 'setHeadHandler');
       stubHandler = sinon.stub();
     });
     afterEach(function () {
@@ -455,6 +461,40 @@ describe('Dingus', function () {
       assert.strictEqual(stubHandler.args[0][3], 'foo');
       assert.strictEqual(stubHandler.args[0][4], 'bar');
     });
+    describe('intrinsic HEAD handling', function () {
+      it('covers no intrinsic HEAD handling', async function () {
+        dingus.intrinsicHeadMethod = false;
+        dingus.on('GET', '/', stubHandler);
+        req.method = 'HEAD';
+        await dingus.dispatch(req, res, ctx);
+        assert(!stubHandler.called);
+        assert(dingus.handlerMethodNotAllowed.called);
+      });
+      it('calls HEAD setup and GET handler', async function () {
+        dingus.on('GET', '/', stubHandler);
+        req.method = 'HEAD';
+        await dingus.dispatch(req, res, ctx);
+        assert(Dingus.setHeadHandler.called);
+        assert(stubHandler.called);
+      });
+      it('covers no GET handler', async function () {
+        dingus.on('POST', '/', stubHandler);
+        req.method = 'HEAD';
+        await dingus.dispatch(req, res, ctx);
+        assert(!stubHandler.called);
+        assert(dingus.handlerMethodNotAllowed.called);
+      });
+      it('covers unexpected router error', async function () {
+        sinon.stub(dingus.router, 'lookup')
+          .onFirstCall().throws(new RouterNoMethodError())
+          .onSecondCall().throws(new DingusError())
+        ;
+        dingus.on('GET', '/', stubHandler);
+        req.method = 'HEAD';
+        await dingus.dispatch(req, res, ctx);
+        assert(dingus.handlerInternalServerError.called);
+      });
+    });
   }); // dispatch
 
   describe('parseBody', function () {
@@ -472,14 +512,14 @@ describe('Dingus', function () {
     });
     it('parses json', function () {
       const src = { foo: 'bar' };
-      ctx.rawBody = JSON.stringify(src);
-      dingus.parseBody(Enum.ContentType.ApplicationJson, ctx);
+      const rawBody = JSON.stringify(src);
+      dingus.parseBody(Enum.ContentType.ApplicationJson, ctx, rawBody);
       assert.deepStrictEqual(ctx.parsedBody, src);
     });
     it('handles unparsable json', function () {
-      ctx.rawBody = 'not json';
+      const rawBody = 'not json';
       try {
-        dingus.parseBody(Enum.ContentType.ApplicationJson, ctx);
+        dingus.parseBody(Enum.ContentType.ApplicationJson, ctx, rawBody);
         assert.fail(noExpectedException);
       } catch (e) {
         assert.strictEqual(e.statusCode, 400);
@@ -489,8 +529,8 @@ describe('Dingus', function () {
       const expected = Object.assign(Object.create(null), {
         foo: 'bar',
       });
-      ctx.rawBody = 'foo=bar';
-      dingus.parseBody('application/x-www-form-urlencoded', ctx);
+      const rawBody = 'foo=bar';
+      dingus.parseBody('application/x-www-form-urlencoded', ctx, rawBody);
       assert.deepStrictEqual(ctx.parsedBody, expected);
     });
 
@@ -549,7 +589,7 @@ describe('Dingus', function () {
       const req = {};
       const res = {};
       const ctx = {};
-      sinon.stub(dingus, 'bodyData').resolves('{"foo":"bar"}')
+      sinon.stub(dingus, 'bodyData').resolves('{"foo":"bar"}');
       sinon.stub(Dingus, 'getRequestContentType').returns(Enum.ContentType.ApplicationJson);
       await dingus.ingestBody(req, res, ctx);
       assert.deepStrictEqual(ctx.parsedBody, { foo: 'bar' });
index 0a86ec59e1518c7e534aa49f5750a2fbb06060db..bdd353f358ee1a7b8e9a9c1823f5e0f645a45948 100644 (file)
@@ -9,13 +9,18 @@ const Enum = require('../../lib/enum');
 describe('enum', function () {
 
   describe('ErrorResponse', function () {
-    it('covers default', function () {
+    it('covers broken', function () {
       const result = Enum.ErrorResponse.notPresent;
       const expected = {
         errorMessage: 'undefined error response \'notPresent\'',
       };
       assert.deepStrictEqual(result, expected);
     });
+    it('covers success', function () {
+      const { statusCode } = Enum.ErrorResponse.ReallyForbidden;
+      const expected = 403;
+      assert.deepStrictEqual(statusCode, expected);
+    });
   }); // ErrorResponse
 
 });
index c89cc196472a1cb6d1959126a572afb3f7789aa6..bcb45f2d00bbfacad8bb33c5fe593cbfce6183b5 100644 (file)
@@ -5,8 +5,8 @@
 const assert = require('assert');
 const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
 const Router = require('../../lib/router');
-const PathParameter = require('../../lib/router/path-parameter')
-const { DingusError } = require('../../lib/errors');
+const PathParameter = require('../../lib/router/path-parameter');
+const { DingusError, RouterNoPathError, RouterNoMethodError } = require('../../lib/errors');
 
 const noExpectedException = 'did not get expected exception';
 
@@ -311,8 +311,7 @@ describe('Router', function () {
         router.lookup(method, path, ctx);
         assert.fail(noExpectedException);
       } catch (e) {
-        assert(e instanceof DingusError);
-        assert.strictEqual(e.message, 'NoPath');
+        assert(e instanceof RouterNoPathError);
       }
     });
     it('finds handler', function () {
@@ -353,8 +352,7 @@ describe('Router', function () {
         router.lookup(method, path, ctx);
         assert.fail(noExpectedException);
       } catch (e) {
-        assert(e instanceof DingusError);
-        assert.strictEqual(e.message, 'NoMethod');
+        assert(e instanceof RouterNoMethodError);
       }
     });
     it('does not lookup non-existent path', async function () {
@@ -365,8 +363,7 @@ describe('Router', function () {
         router.lookup(method, path, ctx);
         assert.fail(noExpectedException);
       } catch (e) {
-        assert(e instanceof DingusError);
-        assert.strictEqual(e.message, 'NoPath');
+        assert(e instanceof RouterNoPathError);
       }
     });