X-Git-Url: https://git.squeep.com/?a=blobdiff_plain;f=lib%2Fcommon.js;h=6b72129223cf88e8248706afa5679f853eb5d5ae;hb=1b2868b99eba20b50d88a0d858bcd8c51c5b8f07;hp=284427a7bd769742eafda2838b66275951a25de3;hpb=29837f0eeb9fcb4c53426e5bd89e9bdf7e9d961b;p=squeep-api-dingus diff --git a/lib/common.js b/lib/common.js index 284427a..6b72129 100644 --- a/lib/common.js +++ b/lib/common.js @@ -5,32 +5,21 @@ * Utility and miscellaneous functions. */ -const path = require('path'); -const crypto = require('crypto'); +const crypto = require('node:crypto'); const uuid = require('uuid'); const Enum = require('./enum'); - -/** - * Return a function which combines a part of the filename with a scope, for use in logging. - * @param {string} filename - */ -const fileScope = (filename) => { - let fScope = path.basename(filename, '.js'); - if (fScope === 'index') { - fScope = path.basename(path.dirname(filename)); - } - return (scope) => `${fScope}:${scope}`; -} +const { fileScope } = require('@squeep/log-helper'); /** * Simple ETag from data. - * @param {string} filePath - * @param {object} fileStat - * @param {*} fileData + * @param {String} filePath (currently unused) + * @param {fs.Stats} fileStat + * @param {crypto.BinaryLike} fileData content + * @returns {String} */ const generateETag = (_filePath, fileStat, fileData) => { const hash = crypto.createHash('sha256'); - if (fileStat && fileStat.mtimeMs) { + if (fileStat?.mtimeMs) { hash.update(fileStat.mtimeMs.toString()); } hash.update(fileData); @@ -39,28 +28,21 @@ const generateETag = (_filePath, fileStat, fileData) => { }; /** - * @param {object} obj - * @param {string} prop - * @param {*} def + * Access property with default. + * @param {Object} obj + * @param {String} prop + * @param {*} def default value if prop does not exist for obj + * @return {*} */ const get = (obj, prop, def) => obj && prop && (prop in obj) ? obj[prop] : def; /** - * @param {http.ClientRequest} req - * @param {http.ServerResponse} res - * @param {object} ctx - */ -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. * @param {http.ClientRequest} req * @param {Number} modifiedTimeMs - * @param {string} eTag + * @param {String} eTag + * @returns {Boolean} */ const isClientCached = (req, modifiedTimeMs, eTag) => { let clientCached = false; @@ -93,6 +75,7 @@ const isClientCached = (req, modifiedTimeMs, eTag) => { * Expects only one-level deep, is not recursive! * @param {Object} origEnum * @param {Object} additionalEnum + * @returns {Object} */ const mergeEnum = (origEnum, additionalEnum) => { for (const e of Object.keys(additionalEnum)) { @@ -118,9 +101,9 @@ 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. - * @param {...any} objects - * @returns + * Return a new object with all objects combined, later properties taking precedence. + * @param {...Object} objects + * @returns {Object} */ const mergeDeep = (...objects) => { return objects.reduce((acc, obj) => { @@ -144,7 +127,8 @@ const mergeDeep = (...objects) => { /** * Return a new object with selected props. * @param {Object} obj - * @param {string[]} props + * @param {String[]} props + * @returns {Object} */ const pick = (obj, props) => { const picked = {}; @@ -157,36 +141,7 @@ const pick = (obj, props) => { }; /** - * Return a subset of a request object, suitable for logging. - * @param {http.ClientRequest} req - */ -const requestLogData = (req) => { - return pick(req, [ - 'method', - 'url', - 'httpVersion', - 'headers', - 'trailers', - ]); -}; - - -/** - * Return a subset of a response object, suitable for logging. - * @param {http.ServerResponse} res - */ -const responseLogData = (res) => { - const response = pick(res, [ - 'statusCode', - 'statusMessage', - ]); - response.headers = res.getHeaders(); - return response; -}; - - -/** - * Store updates to defaultOptions, but no new properties. + * Store all properties in defaultOptions on target from either options or defaultOptions. * @param {Object} target * @param {Object} defaultOptions * @param {Object} options @@ -196,10 +151,10 @@ const setOptions = (target, defaultOptions, options) => { }; /** - * Return a list of source split at first delimiter. - * @param {string} src - * @param {string} delimiter - * @param {string} fill trailing stand-in if no delimiter in src + * 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 */ const splitFirst = (src, delimiter, fill) => { const idx = src.indexOf(delimiter); @@ -211,47 +166,45 @@ const splitFirst = (src, delimiter, fill) => { }; /** - * Generate a new request identifier. + * Generate a new request identifier, a time/host-based uuid. * @returns {String} */ const requestId = () => { return uuid.v1(); }; -const nop = () => { /**/ }; -const nullLogger = { - error: nop, - warn: nop, - info: nop, - log: nop, - debug: nop, -}; - -const ensureLoggerLevels = (logger = {}) => { - for (const level in nullLogger) { - if (! (level in logger)) { - logger[level] = nullLogger[level]; - } +/** + * Merges folded header lines + * @param {String[]} lines + * @returns {String} + */ +const unfoldHeaderLines = (lines) => { + const foldedLineRE = /^(\t| +)(.*)$/; + if (lines) { + lines.reduceRight((_, line, idx) => { // NOSONAR + const result = foldedLineRE.exec(line); + if (result && idx) { + const prevIdx = idx - 1; + const mergedLine = `${lines[prevIdx]} ${result[2]}`; + lines.splice(prevIdx, 2, mergedLine); + return mergedLine; + } + }, null); } - return logger; + return lines; }; module.exports = { fileScope, generateETag, get, - handlerLogData, - isClientCached, httpStatusCodeClass, + isClientCached, mergeDeep, mergeEnum, - nop, - nullLogger, - ensureLoggerLevels, pick, requestId, - requestLogData, - responseLogData, setOptions, splitFirst, + unfoldHeaderLines, };