update devDependencies, add jsdoc lint, fix lint issues
[squeep-api-dingus] / lib / common.js
index 162b751ef23805d30bbf97eb71a69f367adf3d59..c6c21efc705cf7581dfd351ffe8ba3a8275cbdb1 100644 (file)
@@ -10,12 +10,17 @@ const uuid = require('uuid');
 const Enum = require('./enum');
 const { fileScope } = require('@squeep/log-helper');
 
+/**
+ * @typedef {import('node:http')} http
+ */
+
 /**
  * Simple ETag from data.
- * @param {String} filePath (currently unused)
- * @param {fs.Stats} fileStat
+ * @param {string} _filePath (currently unused)
+ * @param {object} fileStat node:fs.Stats object
+ * @param {number} fileStat.mtimeMs node:fs.Stats object
  * @param {crypto.BinaryLike} fileData content
- * @returns {String}
+ * @returns {string} etag
  */
 const generateETag = (_filePath, fileStat, fileData) => {
   const hash = crypto.createHash('sha256');
@@ -29,20 +34,21 @@ const generateETag = (_filePath, fileStat, fileData) => {
 
 /**
  * Access property with default.
- * @param {Object} obj
- * @param {String} prop
+ * @param {object} obj target object
+ * @param {string} prop target property
  * @param {*} def default value if prop does not exist for obj
- * @return {*}
+ * @returns {*} property value or default
  */
 const get = (obj, prop, def) => obj && prop && (prop in obj) ? obj[prop] : def;
 
 /**
  * Determine whether a client has already requested a resource,
  * based on If-Modified-Since and If-None-Match headers.
- * @param {http.ClientRequest} req 
- * @param {Number} modifiedTimeMs 
- * @param {String} eTag 
- * @returns {Boolean}
+ * @param {http.ClientRequest} req request
+ * @param {(string) => string} req.getHeader header accessor
+ * @param {number} modifiedTimeMs ms timestamp from client
+ * @param {string} eTag etag from client
+ * @returns {boolean} whether our version matches what client knows
  */
 const isClientCached = (req, modifiedTimeMs, eTag) => {
   let clientCached = false;
@@ -73,9 +79,9 @@ const isClientCached = (req, modifiedTimeMs, eTag) => {
 /**
  * Shallow merge for enums, to be called by derived constructor.
  * Expects only one-level deep, is not recursive!
- * @param {Object} origEnum
- * @param {Object} additionalEnum
- * @returns {Object}
+ * @param {object} origEnum enum object to be extended
+ * @param {object} additionalEnum enum object to add
+ * @returns {object} lightly merged enum object
  */
 const mergeEnum = (origEnum, additionalEnum) => {
   for (const e of Object.keys(additionalEnum)) {
@@ -93,17 +99,19 @@ const mergeEnum = (origEnum, additionalEnum) => {
 
 /**
  * Isolate the general category of an http status code.
- * @param {Number} statusCode
- * @returns {Number}
+ * @param {number} statusCode of response
+ * @returns {number} status category
  */
 const httpStatusCodeClass = (statusCode) => Math.floor(statusCode / 100);
 
 const _isObject = (obj) => obj && typeof obj === 'object';
 const _isArray = (obj) => Array.isArray(obj);
+
 /**
  * Return a new object with all objects combined, later properties taking precedence.
- * @param  {...Object} objects
- * @returns {Object}
+ * Arrays are concated.
+ * @param  {...object} objects to be merged onto a new object
+ * @returns {object} new merged object
  */
 const mergeDeep = (...objects) => {
   return objects.reduce((acc, obj) => {
@@ -126,9 +134,9 @@ const mergeDeep = (...objects) => {
 
 /**
  * Return a new object with selected props.
- * @param {Object} obj
- * @param {String[]} props
- * @returns {Object}
+ * @param {object} obj source object
+ * @param {string[]} props list of property names
+ * @returns {object} object with selected properties
  */
 const pick = (obj, props) => {
   const picked = {};
@@ -142,19 +150,22 @@ const pick = (obj, props) => {
 
 /**
  * Store all properties in defaultOptions on target from either options or defaultOptions.
- * @param {Object} target 
- * @param {Object} defaultOptions 
- * @param {Object} options 
+ * @param {object} target object to populate
+ * @param {object} defaultOptions object with default property values
+ * @param {object} options object with potential overrides for defaults
+ * @returns {object} object with properties
  */
 const setOptions = (target, defaultOptions, options) => {
   Object.assign(target, defaultOptions, pick(options, Object.keys(defaultOptions)));
+  return target;
 };
 
 /**
  * Return a two-item list of src, split at first delimiter encountered.
- * @param {String} src 
- * @param {String} delimiter 
- * @param {String} fill trailing stand-in if no delimiter in src
+ * @param {string} src source
+ * @param {string} delimiter delimiter
+ * @param {string} fill trailing stand-in if no delimiter in src
+ * @returns {string[]} [before-first-delimiter, rest-or-fill]
  */
 const splitFirst = (src, delimiter, fill) => {
   const idx = src.indexOf(delimiter);
@@ -167,7 +178,7 @@ const splitFirst = (src, delimiter, fill) => {
 
 /**
  * Generate a new request identifier, a time/host-based uuid.
- * @returns {String}
+ * @returns {string} uuid
  */
 const requestId = () => {
   return uuid.v1();
@@ -175,8 +186,8 @@ const requestId = () => {
 
 /**
  * Merges folded header lines
- * @param {String[]} lines
- * @returns {String}
+ * @param {string[]} lines header lines
+ * @returns {string} unfolded header string
  */
 const unfoldHeaderLines = (lines) => {
   const foldedLineRE = /^(\t| +)(.*)$/;
@@ -195,18 +206,19 @@ const unfoldHeaderLines = (lines) => {
 };
 
 /**
- * Adds a new cookie.
- * @param {http.ServerResponse} res
- * @param {String} name
- * @param {String} value
- * @param {Object=} opt
- * @param {String=} opt.domain
- * @param {Date=} opt.expires
- * @param {Boolean=} opt.httpOnly
- * @param {Number=} opt.maxAge
- * @param {String=} opt.path
- * @param {String=} opt.sameSite
- * @param {Boolean=} opt.secure
+ * Adds a new set-cookie header value to response, with supplied data.
+ * @param {http.ServerResponse} res response
+ * @param {(string, string) => void} res.appendHeader sets header values
+ * @param {string} name cookie name
+ * @param {string} value cookie value
+ * @param {object=} opt cookie options
+ * @param {string=} opt.domain cookie domain
+ * @param {Date=} opt.expires cookie expiration
+ * @param {boolean=} opt.httpOnly cookie client visibility
+ * @param {number=} opt.maxAge cookie lifetime
+ * @param {string=} opt.path cookie path
+ * @param {string=} opt.sameSite cookie sharing
+ * @param {boolean=} opt.secure cookie security
  */
 function addCookie(res, name, value, opt = {}) {
   const options = {