UNPKG

@neodx/log

Version:

A lightweight universal logging framework

178 lines (170 loc) 6.44 kB
'use strict'; /* eslint-disable @typescript-eslint/no-explicit-any */ const toArray = value => Array.isArray(value) ? value : [value]; const toInt = value => Number.parseInt(value, 10); const is = target => value => target === value; const identity = value => value; const isTruthy = Boolean; const True = () => true; const setMapValue = (map, key, value) => { map.set(key, value); return value; }; const getOrCreateMapValue = (map, key, create) => map.has(key) ? map.get(key) : setMapValue(map, key, create()); //#region Object const values = Object.values; const fromEntries = Object.fromEntries; const entries = Object.entries; const hasOwn = Object.hasOwn; const keys = Object.keys; //#endregion const toString = Object.prototype.toString; const getPrototypeOf = Object.getPrototypeOf; const objectString = '[object Object]'; const isEmpty = target => target.length === 0; const isError = target => target instanceof Error; const isEmptyObject = target => isEmpty(keys(target)); const createTypeof = type => value => typeof value === type; const isTypeOfString = createTypeof('string'); const isTypeOfFunction = createTypeof('function'); const isPrimitive = value => value === null || (typeof value !== 'function' && typeof value !== 'object'); const isObject = target => { if (isNil(target) || !isObjectLike(target) || toString.call(target) !== objectString) { return false; } const proto = getPrototypeOf(target); return proto === null || proto === getLastPrototypeOf(target); }; const isNil = target => target == null; const isObjectLike = target => typeof target === 'object' && target !== null; const getLastPrototypeOf = target => { const proto = getPrototypeOf(target); return proto === null ? target : getLastPrototypeOf(proto); }; function mapValues(target, fn) { return mapEntries(target, ([key, value]) => [key, fn(value, key)]); } function mapEntries(target, fn) { return fromEntries(entries(target).map(fn)); } const createCase = pattern => (input, delimiters = DEFAULT_DELIMITERS) => toCase(input, pattern, delimiters); /** * Converts a string to a specified case pattern. * @param input The string to convert. * @param pattern The pattern to convert to. * @param delimiters The delimiters to use when splitting the string. * @example toCase('foo-bar baz', 'CaSe') // PascalCase 'FooBarBaz' * @example toCase('foo_bar baz', 'caSe') // camelCase 'fooBarBaz' * @example toCase('foo_bar baz', 'CASE') // upper case 'FOOBARBAZ' * @example toCase('foo_bar baz', 'case') // lower case 'foobarbaz' * @example toCase('foo_bar baz', 'CA_SE') // screaming snake case 'FOO_BAR_BAZ' * @example toCase('foo_bar baz', 'ca-se') // kebab case 'foo-bar-baz' * @example toCase('foo_bar baz', 'ca_se') // snake case 'foo_bar_baz' * @example toCase('foo_bar baz', 'Case') // capitalised 'Foobarbaz' */ function toCase(input, pattern, delimiters = DEFAULT_DELIMITERS) { const end = pattern.slice(Math.max(0, pattern.length - 2)); const sep = pattern.slice(2, -2); const start = pattern.slice(0, 2); return matches(input, delimiters) .map((match, index) => applyPattern(match, index === 0 ? start : end)) .join(sep); } /** * Presets for common cases. */ mapValues( { camel: 'caSe', kebab: 'ca-se', snake: 'ca_se', upper: 'CASE', lower: 'case', pascal: 'CaSe', capital: 'Case', screamingSnake: 'CA_SE' }, createCase ); const applyPattern = (str, pattern) => apply(pattern[0], str[0]) + apply(pattern[1], str.slice(1)); function matches(str, delimiters) { const regex = new RegExp('([A-Z]?)([^' + delimiters + ']*)', 'g'); return str.match(regex)?.filter(Boolean) ?? []; } function apply(letter, str) { if (letter === '-') return ''; if (letter === '*') return str; const isUpperCase = letter === letter.toUpperCase(); return isUpperCase ? str.toUpperCase() : str.toLowerCase(); } const DEFAULT_DELIMITERS = 'A-Z\\s_-'; const createLoggerAutoFactory = factory => (log, defaultParams) => { const params = isTypeOfString(log) ? { level: log } : log; return 'level' in params ? factory({ ...defaultParams, ...params }) : params; }; /** * Reads arguments array and extract fields, error and message arguments. * @return [messageFragments, fields, error] * * Strings * @example readArguments('hello') -> [ ['hello'], {} ] * @example readArguments('hello %s', 'world') -> [ ['hello %s', 'world'], {} ] * @example readArguments('hello %s %d %j', 'world', 1, { id: 2 }) -> [ ['hello %s %d %j', 'world', 1, { id: 2 }], {} ] * * Additional fields * @example readArguments({ id: 2 }) -> [ [], { id: 2 } ] * @example readArguments({ id: 2 }, 'hello') -> [ ['hello'], { id: 2 } ] * @example readArguments({ id: 2 }, 'hello %s', 'world') -> [ ['hello %s', 'world'], { id: 2 } ] * * Errors * @example readArguments(myError) -> [ ['my error'], {}, myError ] * @example readArguments({ err: myError }) -> [ ['my error'], {}, myError ] * @example readArguments({ err: myError, id: 2 }) -> [ ['my error'], { id: 2 }, myError ] * @example readArguments({ err: myError, id: 2 }, 'hello') -> [ ['hello'], { id: 2 }, myError ] * @example readArguments({ err: myError, id: 2 }, 'hello %s', 'world') -> [ ['hello %s', 'world'], { id: 2 }, myError ] */ function readArguments(args) { const [firstArg, ...otherArgs] = args; if (isError(firstArg)) { return [isEmpty(otherArgs) ? [firstArg.message] : otherArgs, {}, firstArg]; } if (isObjectLike(firstArg)) { if ('err' in firstArg && isError(firstArg.err)) { const { err, ...fields } = firstArg; return [isEmpty(otherArgs) ? [err.message] : otherArgs, fields, err]; } return [otherArgs, firstArg]; } return [args, {}]; } exports.True = True; exports.createLoggerAutoFactory = createLoggerAutoFactory; exports.entries = entries; exports.getOrCreateMapValue = getOrCreateMapValue; exports.hasOwn = hasOwn; exports.identity = identity; exports.is = is; exports.isEmpty = isEmpty; exports.isEmptyObject = isEmptyObject; exports.isObject = isObject; exports.isPrimitive = isPrimitive; exports.isTruthy = isTruthy; exports.isTypeOfFunction = isTypeOfFunction; exports.isTypeOfString = isTypeOfString; exports.keys = keys; exports.readArguments = readArguments; exports.toArray = toArray; exports.toInt = toInt; exports.values = values; //# sourceMappingURL=read-arguments-BBlq0hOP.cjs.map