UNPKG

@neodx/log

Version:

A lightweight universal logging framework

1,233 lines (1,207 loc) 54 kB
import { hostname } from 'node:os'; import { c as createLoggerFactory, D as DEFAULT_LOGGER_PARAMS } from './create-logger-factory-DktgHJZq.mjs'; import { i as identity, h as entries, j as getOrCreateMapValue, a as isEmptyObject, l as toInt, t as toArray, m as isPrimitive, T as True, n as hasOwn, v as values, o as isObject, e as isEmpty, k as keys, r as readArguments, c as createLoggerAutoFactory } from './read-arguments-BklHPmep.mjs'; import { readFileSync, existsSync, createWriteStream } from 'node:fs'; import { colors } from '@neodx/colors'; import { resolve, relative } from 'pathe'; import { serializeJSON, printf } from '../utils/index.mjs'; function fromLength(length, fn = identity) { return Array.from( { length }, (_, index) => fn(index) ); } function filterObject(record, fn) { return Object.fromEntries(entries(record).filter(([key, value]) => fn(value, key))); } const omit = (obj, keys) => filterObject(obj, (_, key) => !keys.includes(key)); const pick = (target, keys) => Object.fromEntries(Object.entries(target).filter(([key]) => keys.includes(key))); const sum = values => values.reduce((acc, item) => acc + item, 0); function memoizeWeak(fn) { return memoize(fn, { cache: new WeakMap() }); } function memoize(fn, { cache = new Map(), key = identity } = {}) { function cachedFn(input) { return getOrCreateMapValue(cache, key(input), () => fn(input)); } cachedFn.cache = cache; return cachedFn; } const truncateString = (str, maxLength, suffix = '...') => str.length <= maxLength ? str : str.slice(0, maxLength - suffix.length) + suffix; const formatOutgoingMessageStatus = res => { if (!res.headersSent) return 'unknown status'; const { statusCode, statusMessage } = res; return `${statusCode} ${statusMessage}`; }; const formatIncomingMessage = (req, colors, delimiter = ' ') => `${colors.bold(req.method?.toUpperCase() ?? 'GET')}${delimiter}${colors.underline(colors.gray(truncateString(getIncomingMessageUrl(req).split('?')?.shift() ?? '', 50)))}`; const formatResponseTime = time => { const showSeconds = time >= 100; const timeValue = showSeconds ? time / 1000 : time; return timeValue .toLocaleString('en', { style: 'unit', unit: showSeconds ? 'second' : 'millisecond', unitDisplay: 'narrow', maximumFractionDigits: 1 }) .padEnd(4); }; function serializeHttpRequest(req) { const { id, info, query, method, params, headers, [HTTP_LOG_RAW_SYMBOL]: raw } = req; const connection = info || req.socket; return { id: typeof id === 'function' ? id() : id ?? info?.id, url: getIncomingMessageUrl(req), query, params, method, headers, remotePort: connection?.remotePort, remoteAddress: connection?.remoteAddress, [HTTP_LOG_RAW_SYMBOL]: raw || req }; } function serializeHttpResponse(res) { return { statusCode: res.headersSent ? res.statusCode : null, headers: res.getHeaders(), [HTTP_LOG_RAW_SYMBOL]: res }; } const getIncomingMessageUrl = ({ originalUrl, path, url }) => originalUrl || (typeof path === 'string' ? path : url?.path ?? url); const createRequestIdGenerator = () => { let currentRequestId = 0; return function generateRequestId() { currentRequestId = currentRequestId >= maxInt ? 0 : currentRequestId + 1; return currentRequestId; }; }; const HTTP_LOG_START_TIME_SYMBOL = Symbol('HTTP_LOG_START_TIME'); const HTTP_LOG_RAW_SYMBOL = Symbol('raw'); const maxInt = 2147483647; /* eslint-disable yoda */ function isFullwidthCodePoint(codePoint) { if (!Number.isInteger(codePoint)) { return false; } // Code points are derived from: // https://unicode.org/Public/UNIDATA/EastAsianWidth.txt return ( codePoint >= 0x1100 && (codePoint <= 0x115f || // Hangul Jamo codePoint === 0x2329 || // LEFT-POINTING ANGLE BRACKET codePoint === 0x232a || // RIGHT-POINTING ANGLE BRACKET // CJK Radicals Supplement .. Enclosed CJK Letters and Months (0x2e80 <= codePoint && codePoint <= 0x3247 && codePoint !== 0x303f) || // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A (0x3250 <= codePoint && codePoint <= 0x4dbf) || // CJK Unified Ideographs .. Yi Radicals (0x4e00 <= codePoint && codePoint <= 0xa4c6) || // Hangul Jamo Extended-A (0xa960 <= codePoint && codePoint <= 0xa97c) || // Hangul Syllables (0xac00 <= codePoint && codePoint <= 0xd7a3) || // CJK Compatibility Ideographs (0xf900 <= codePoint && codePoint <= 0xfaff) || // Vertical Forms (0xfe10 <= codePoint && codePoint <= 0xfe19) || // CJK Compatibility Forms .. Small Form Variants (0xfe30 <= codePoint && codePoint <= 0xfe6b) || // Halfwidth and Fullwidth Forms (0xff01 <= codePoint && codePoint <= 0xff60) || (0xffe0 <= codePoint && codePoint <= 0xffe6) || // Kana Supplement (0x1b000 <= codePoint && codePoint <= 0x1b001) || // Enclosed Ideographic Supplement (0x1f200 <= codePoint && codePoint <= 0x1f251) || // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane (0x20000 <= codePoint && codePoint <= 0x3fffd)) ); } const ANSI_BACKGROUND_OFFSET = 10; const wrapAnsi16 = (offset = 0) => code => `\u001B[${code + offset}m`; const wrapAnsi256 = (offset = 0) => code => `\u001B[${38 + offset};5;${code}m`; const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`; const styles = { modifier: { reset: [0, 0], // 21 isn't widely supported and 22 does the same thing bold: [1, 22], dim: [2, 22], italic: [3, 23], underline: [4, 24], overline: [53, 55], inverse: [7, 27], hidden: [8, 28], strikethrough: [9, 29] }, color: { black: [30, 39], red: [31, 39], green: [32, 39], yellow: [33, 39], blue: [34, 39], magenta: [35, 39], cyan: [36, 39], white: [37, 39], // Bright color blackBright: [90, 39], gray: [90, 39], grey: [90, 39], redBright: [91, 39], greenBright: [92, 39], yellowBright: [93, 39], blueBright: [94, 39], magentaBright: [95, 39], cyanBright: [96, 39], whiteBright: [97, 39] }, bgColor: { bgBlack: [40, 49], bgRed: [41, 49], bgGreen: [42, 49], bgYellow: [43, 49], bgBlue: [44, 49], bgMagenta: [45, 49], bgCyan: [46, 49], bgWhite: [47, 49], // Bright color bgBlackBright: [100, 49], bgGray: [100, 49], bgGrey: [100, 49], bgRedBright: [101, 49], bgGreenBright: [102, 49], bgYellowBright: [103, 49], bgBlueBright: [104, 49], bgMagentaBright: [105, 49], bgCyanBright: [106, 49], bgWhiteBright: [107, 49] } }; function assembleStyles() { const codes = new Map(); for (const [groupName, group] of Object.entries(styles)) { for (const [styleName, style] of Object.entries(group)) { styles[styleName] = { open: `\u001B[${style[0]}m`, close: `\u001B[${style[1]}m` }; group[styleName] = styles[styleName]; codes.set(style[0], style[1]); } Object.defineProperty(styles, groupName, { value: group, enumerable: false }); } Object.defineProperty(styles, 'codes', { value: codes, enumerable: false }); styles.color.close = '\u001B[39m'; styles.bgColor.close = '\u001B[49m'; styles.color.ansi = wrapAnsi16(); styles.color.ansi256 = wrapAnsi256(); styles.color.ansi16m = wrapAnsi16m(); styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET); styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET); styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET); // From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js Object.defineProperties(styles, { rgbToAnsi256: { value: (red, green, blue) => { // We use the extended greyscale palette here, with the exception of // black and white. normal palette only has 4 greyscale shades. if (red === green && green === blue) { if (red < 8) { return 16; } if (red > 248) { return 231; } return Math.round(((red - 8) / 247) * 24) + 232; } return ( 16 + 36 * Math.round((red / 255) * 5) + 6 * Math.round((green / 255) * 5) + Math.round((blue / 255) * 5) ); }, enumerable: false }, hexToRgb: { value: hex => { const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16)); if (!matches) { return [0, 0, 0]; } let [colorString] = matches; if (colorString.length === 3) { colorString = [...colorString].map(character => character + character).join(''); } const integer = Number.parseInt(colorString, 16); return [ /* eslint-disable no-bitwise */ (integer >> 16) & 0xff, (integer >> 8) & 0xff, integer & 0xff ]; }, enumerable: false }, hexToAnsi256: { value: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)), enumerable: false }, ansi256ToAnsi: { value: code => { if (code < 8) { return 30 + code; } if (code < 16) { return 90 + (code - 8); } let red; let green; let blue; if (code >= 232) { red = ((code - 232) * 10 + 8) / 255; green = red; blue = red; } else { code -= 16; const remainder = code % 36; red = Math.floor(code / 36) / 5; green = Math.floor(remainder / 6) / 5; blue = (remainder % 6) / 5; } const value = Math.max(red, green, blue) * 2; if (value === 0) { return 30; } // eslint-disable-next-line no-bitwise let result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red)); if (value === 2) { result += 60; } return result; }, enumerable: false }, rgbToAnsi: { value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)), enumerable: false }, hexToAnsi: { value: hex => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), enumerable: false } }); return styles; } const ansiStyles = assembleStyles(); const astralRegex = /^[\uD800-\uDBFF][\uDC00-\uDFFF]$/; const ESCAPES = ['\u001B', '\u009B']; const wrapAnsi = code => `${ESCAPES[0]}[${code}m`; const checkAnsi = (ansiCodes, isEscapes, endAnsiCode) => { let output = []; ansiCodes = [...ansiCodes]; for (let ansiCode of ansiCodes) { const ansiCodeOrigin = ansiCode; if (ansiCode.includes(';')) { ansiCode = ansiCode.split(';')[0][0] + '0'; } const item = ansiStyles.codes.get(Number.parseInt(ansiCode, 10)); if (item) { const indexEscape = ansiCodes.indexOf(item.toString()); if (indexEscape === -1) { output.push(wrapAnsi(isEscapes ? item : ansiCodeOrigin)); } else { ansiCodes.splice(indexEscape, 1); } } else if (isEscapes) { output.push(wrapAnsi(0)); break; } else { output.push(wrapAnsi(ansiCodeOrigin)); } } if (isEscapes) { output = output.filter((element, index) => output.indexOf(element) === index); if (endAnsiCode !== undefined) { const fistEscapeCode = wrapAnsi(ansiStyles.codes.get(Number.parseInt(endAnsiCode, 10))); // TODO: Remove the use of `.reduce` here. // eslint-disable-next-line unicorn/no-array-reduce output = output.reduce( (current, next) => (next === fistEscapeCode ? [next, ...current] : [...current, next]), [] ); } } return output.join(''); }; function sliceAnsi(string, begin, end) { const characters = [...string]; const ansiCodes = []; let stringEnd = typeof end === 'number' ? end : characters.length; let isInsideEscape = false; let ansiCode; let visible = 0; let output = ''; for (const [index, character] of characters.entries()) { let leftEscape = false; if (ESCAPES.includes(character)) { const code = /\d[^m]*/.exec(string.slice(index, index + 18)); ansiCode = code && code.length > 0 ? code[0] : undefined; if (visible < stringEnd) { isInsideEscape = true; if (ansiCode !== undefined) { ansiCodes.push(ansiCode); } } } else if (isInsideEscape && character === 'm') { isInsideEscape = false; leftEscape = true; } if (!isInsideEscape && !leftEscape) { visible++; } if (!astralRegex.test(character) && isFullwidthCodePoint(character.codePointAt())) { visible++; if (typeof end !== 'number') { stringEnd++; } } if (visible > begin && visible <= stringEnd) { output += character; } else if (visible === begin && !isInsideEscape && ansiCode !== undefined) { output = checkAnsi(ansiCodes); } else if (visible >= stringEnd) { output += checkAnsi(ansiCodes, true, ansiCode); break; } } return output; } function ansiRegex({ onlyFirst = false } = {}) { const pattern = [ '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)', '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))' ].join('|'); return new RegExp(pattern, onlyFirst ? undefined : 'g'); } const regex = ansiRegex(); function stripAnsi(string) { if (typeof string !== 'string') { throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``); } // Even though the regex is global, we don't need to reset the `.lastIndex` // because unlike `.exec()` and `.test()`, `.replace()` does it automatically // and doing it manually has a performance penalty. return string.replace(regex, ''); } // Generated code. function isAmbiguous(x) { return ( x === 0xa1 || x === 0xa4 || x === 0xa7 || x === 0xa8 || x === 0xaa || x === 0xad || x === 0xae || (x >= 0xb0 && x <= 0xb4) || (x >= 0xb6 && x <= 0xba) || (x >= 0xbc && x <= 0xbf) || x === 0xc6 || x === 0xd0 || x === 0xd7 || x === 0xd8 || (x >= 0xde && x <= 0xe1) || x === 0xe6 || (x >= 0xe8 && x <= 0xea) || x === 0xec || x === 0xed || x === 0xf0 || x === 0xf2 || x === 0xf3 || (x >= 0xf7 && x <= 0xfa) || x === 0xfc || x === 0xfe || x === 0x101 || x === 0x111 || x === 0x113 || x === 0x11b || x === 0x126 || x === 0x127 || x === 0x12b || (x >= 0x131 && x <= 0x133) || x === 0x138 || (x >= 0x13f && x <= 0x142) || x === 0x144 || (x >= 0x148 && x <= 0x14b) || x === 0x14d || x === 0x152 || x === 0x153 || x === 0x166 || x === 0x167 || x === 0x16b || x === 0x1ce || x === 0x1d0 || x === 0x1d2 || x === 0x1d4 || x === 0x1d6 || x === 0x1d8 || x === 0x1da || x === 0x1dc || x === 0x251 || x === 0x261 || x === 0x2c4 || x === 0x2c7 || (x >= 0x2c9 && x <= 0x2cb) || x === 0x2cd || x === 0x2d0 || (x >= 0x2d8 && x <= 0x2db) || x === 0x2dd || x === 0x2df || (x >= 0x300 && x <= 0x36f) || (x >= 0x391 && x <= 0x3a1) || (x >= 0x3a3 && x <= 0x3a9) || (x >= 0x3b1 && x <= 0x3c1) || (x >= 0x3c3 && x <= 0x3c9) || x === 0x401 || (x >= 0x410 && x <= 0x44f) || x === 0x451 || x === 0x2010 || (x >= 0x2013 && x <= 0x2016) || x === 0x2018 || x === 0x2019 || x === 0x201c || x === 0x201d || (x >= 0x2020 && x <= 0x2022) || (x >= 0x2024 && x <= 0x2027) || x === 0x2030 || x === 0x2032 || x === 0x2033 || x === 0x2035 || x === 0x203b || x === 0x203e || x === 0x2074 || x === 0x207f || (x >= 0x2081 && x <= 0x2084) || x === 0x20ac || x === 0x2103 || x === 0x2105 || x === 0x2109 || x === 0x2113 || x === 0x2116 || x === 0x2121 || x === 0x2122 || x === 0x2126 || x === 0x212b || x === 0x2153 || x === 0x2154 || (x >= 0x215b && x <= 0x215e) || (x >= 0x2160 && x <= 0x216b) || (x >= 0x2170 && x <= 0x2179) || x === 0x2189 || (x >= 0x2190 && x <= 0x2199) || x === 0x21b8 || x === 0x21b9 || x === 0x21d2 || x === 0x21d4 || x === 0x21e7 || x === 0x2200 || x === 0x2202 || x === 0x2203 || x === 0x2207 || x === 0x2208 || x === 0x220b || x === 0x220f || x === 0x2211 || x === 0x2215 || x === 0x221a || (x >= 0x221d && x <= 0x2220) || x === 0x2223 || x === 0x2225 || (x >= 0x2227 && x <= 0x222c) || x === 0x222e || (x >= 0x2234 && x <= 0x2237) || x === 0x223c || x === 0x223d || x === 0x2248 || x === 0x224c || x === 0x2252 || x === 0x2260 || x === 0x2261 || (x >= 0x2264 && x <= 0x2267) || x === 0x226a || x === 0x226b || x === 0x226e || x === 0x226f || x === 0x2282 || x === 0x2283 || x === 0x2286 || x === 0x2287 || x === 0x2295 || x === 0x2299 || x === 0x22a5 || x === 0x22bf || x === 0x2312 || (x >= 0x2460 && x <= 0x24e9) || (x >= 0x24eb && x <= 0x254b) || (x >= 0x2550 && x <= 0x2573) || (x >= 0x2580 && x <= 0x258f) || (x >= 0x2592 && x <= 0x2595) || x === 0x25a0 || x === 0x25a1 || (x >= 0x25a3 && x <= 0x25a9) || x === 0x25b2 || x === 0x25b3 || x === 0x25b6 || x === 0x25b7 || x === 0x25bc || x === 0x25bd || x === 0x25c0 || x === 0x25c1 || (x >= 0x25c6 && x <= 0x25c8) || x === 0x25cb || (x >= 0x25ce && x <= 0x25d1) || (x >= 0x25e2 && x <= 0x25e5) || x === 0x25ef || x === 0x2605 || x === 0x2606 || x === 0x2609 || x === 0x260e || x === 0x260f || x === 0x261c || x === 0x261e || x === 0x2640 || x === 0x2642 || x === 0x2660 || x === 0x2661 || (x >= 0x2663 && x <= 0x2665) || (x >= 0x2667 && x <= 0x266a) || x === 0x266c || x === 0x266d || x === 0x266f || x === 0x269e || x === 0x269f || x === 0x26bf || (x >= 0x26c6 && x <= 0x26cd) || (x >= 0x26cf && x <= 0x26d3) || (x >= 0x26d5 && x <= 0x26e1) || x === 0x26e3 || x === 0x26e8 || x === 0x26e9 || (x >= 0x26eb && x <= 0x26f1) || x === 0x26f4 || (x >= 0x26f6 && x <= 0x26f9) || x === 0x26fb || x === 0x26fc || x === 0x26fe || x === 0x26ff || x === 0x273d || (x >= 0x2776 && x <= 0x277f) || (x >= 0x2b56 && x <= 0x2b59) || (x >= 0x3248 && x <= 0x324f) || (x >= 0xe000 && x <= 0xf8ff) || (x >= 0xfe00 && x <= 0xfe0f) || x === 0xfffd || (x >= 0x1f100 && x <= 0x1f10a) || (x >= 0x1f110 && x <= 0x1f12d) || (x >= 0x1f130 && x <= 0x1f169) || (x >= 0x1f170 && x <= 0x1f18d) || x === 0x1f18f || x === 0x1f190 || (x >= 0x1f19b && x <= 0x1f1ac) || (x >= 0xe0100 && x <= 0xe01ef) || (x >= 0xf0000 && x <= 0xffffd) || (x >= 0x100000 && x <= 0x10fffd) ); } function isFullWidth(x) { return x === 0x3000 || (x >= 0xff01 && x <= 0xff60) || (x >= 0xffe0 && x <= 0xffe6); } function isWide(x) { return ( (x >= 0x1100 && x <= 0x115f) || x === 0x231a || x === 0x231b || x === 0x2329 || x === 0x232a || (x >= 0x23e9 && x <= 0x23ec) || x === 0x23f0 || x === 0x23f3 || x === 0x25fd || x === 0x25fe || x === 0x2614 || x === 0x2615 || (x >= 0x2648 && x <= 0x2653) || x === 0x267f || x === 0x2693 || x === 0x26a1 || x === 0x26aa || x === 0x26ab || x === 0x26bd || x === 0x26be || x === 0x26c4 || x === 0x26c5 || x === 0x26ce || x === 0x26d4 || x === 0x26ea || x === 0x26f2 || x === 0x26f3 || x === 0x26f5 || x === 0x26fa || x === 0x26fd || x === 0x2705 || x === 0x270a || x === 0x270b || x === 0x2728 || x === 0x274c || x === 0x274e || (x >= 0x2753 && x <= 0x2755) || x === 0x2757 || (x >= 0x2795 && x <= 0x2797) || x === 0x27b0 || x === 0x27bf || x === 0x2b1b || x === 0x2b1c || x === 0x2b50 || x === 0x2b55 || (x >= 0x2e80 && x <= 0x2e99) || (x >= 0x2e9b && x <= 0x2ef3) || (x >= 0x2f00 && x <= 0x2fd5) || (x >= 0x2ff0 && x <= 0x2fff) || (x >= 0x3001 && x <= 0x303e) || (x >= 0x3041 && x <= 0x3096) || (x >= 0x3099 && x <= 0x30ff) || (x >= 0x3105 && x <= 0x312f) || (x >= 0x3131 && x <= 0x318e) || (x >= 0x3190 && x <= 0x31e3) || (x >= 0x31ef && x <= 0x321e) || (x >= 0x3220 && x <= 0x3247) || (x >= 0x3250 && x <= 0x4dbf) || (x >= 0x4e00 && x <= 0xa48c) || (x >= 0xa490 && x <= 0xa4c6) || (x >= 0xa960 && x <= 0xa97c) || (x >= 0xac00 && x <= 0xd7a3) || (x >= 0xf900 && x <= 0xfaff) || (x >= 0xfe10 && x <= 0xfe19) || (x >= 0xfe30 && x <= 0xfe52) || (x >= 0xfe54 && x <= 0xfe66) || (x >= 0xfe68 && x <= 0xfe6b) || (x >= 0x16fe0 && x <= 0x16fe4) || x === 0x16ff0 || x === 0x16ff1 || (x >= 0x17000 && x <= 0x187f7) || (x >= 0x18800 && x <= 0x18cd5) || (x >= 0x18d00 && x <= 0x18d08) || (x >= 0x1aff0 && x <= 0x1aff3) || (x >= 0x1aff5 && x <= 0x1affb) || x === 0x1affd || x === 0x1affe || (x >= 0x1b000 && x <= 0x1b122) || x === 0x1b132 || (x >= 0x1b150 && x <= 0x1b152) || x === 0x1b155 || (x >= 0x1b164 && x <= 0x1b167) || (x >= 0x1b170 && x <= 0x1b2fb) || x === 0x1f004 || x === 0x1f0cf || x === 0x1f18e || (x >= 0x1f191 && x <= 0x1f19a) || (x >= 0x1f200 && x <= 0x1f202) || (x >= 0x1f210 && x <= 0x1f23b) || (x >= 0x1f240 && x <= 0x1f248) || x === 0x1f250 || x === 0x1f251 || (x >= 0x1f260 && x <= 0x1f265) || (x >= 0x1f300 && x <= 0x1f320) || (x >= 0x1f32d && x <= 0x1f335) || (x >= 0x1f337 && x <= 0x1f37c) || (x >= 0x1f37e && x <= 0x1f393) || (x >= 0x1f3a0 && x <= 0x1f3ca) || (x >= 0x1f3cf && x <= 0x1f3d3) || (x >= 0x1f3e0 && x <= 0x1f3f0) || x === 0x1f3f4 || (x >= 0x1f3f8 && x <= 0x1f43e) || x === 0x1f440 || (x >= 0x1f442 && x <= 0x1f4fc) || (x >= 0x1f4ff && x <= 0x1f53d) || (x >= 0x1f54b && x <= 0x1f54e) || (x >= 0x1f550 && x <= 0x1f567) || x === 0x1f57a || x === 0x1f595 || x === 0x1f596 || x === 0x1f5a4 || (x >= 0x1f5fb && x <= 0x1f64f) || (x >= 0x1f680 && x <= 0x1f6c5) || x === 0x1f6cc || (x >= 0x1f6d0 && x <= 0x1f6d2) || (x >= 0x1f6d5 && x <= 0x1f6d7) || (x >= 0x1f6dc && x <= 0x1f6df) || x === 0x1f6eb || x === 0x1f6ec || (x >= 0x1f6f4 && x <= 0x1f6fc) || (x >= 0x1f7e0 && x <= 0x1f7eb) || x === 0x1f7f0 || (x >= 0x1f90c && x <= 0x1f93a) || (x >= 0x1f93c && x <= 0x1f945) || (x >= 0x1f947 && x <= 0x1f9ff) || (x >= 0x1fa70 && x <= 0x1fa7c) || (x >= 0x1fa80 && x <= 0x1fa88) || (x >= 0x1fa90 && x <= 0x1fabd) || (x >= 0x1fabf && x <= 0x1fac5) || (x >= 0x1face && x <= 0x1fadb) || (x >= 0x1fae0 && x <= 0x1fae8) || (x >= 0x1faf0 && x <= 0x1faf8) || (x >= 0x20000 && x <= 0x2fffd) || (x >= 0x30000 && x <= 0x3fffd) ); } function validate(codePoint) { if (!Number.isSafeInteger(codePoint)) { throw new TypeError(`Expected a code point, got \`${typeof codePoint}\`.`); } } function eastAsianWidth(codePoint, { ambiguousAsWide = false } = {}) { validate(codePoint); if (isFullWidth(codePoint) || isWide(codePoint) || (ambiguousAsWide && isAmbiguous(codePoint))) { return 2; } return 1; } var emojiRegex = () => { // https://mths.be/emoji return /[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26D3\uFE0F?(?:\u200D\uD83D\uDCA5)?|\u26F9(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF43\uDF45-\uDF4A\uDF4C-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDF44(?:\u200D\uD83D\uDFEB)?|\uDF4B(?:\u200D\uD83D\uDFE9)?|\uDFC3(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4\uDEB5](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC25\uDC27-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE41\uDE43\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDC-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC08(?:\u200D\u2B1B)?|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC26(?:\u200D(?:\u2B1B|\uD83D\uDD25))?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE])))?))?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDD75(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?|\uDE42(?:\u200D[\u2194\u2195]\uFE0F?)?|\uDEB6(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF8](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE7C\uDE80-\uDE88\uDE90-\uDEBD\uDEBF-\uDEC2\uDECE-\uDEDB\uDEE0-\uDEE8]|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF])?|\uDDCE(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1|\uDDD1\u200D\uD83E\uDDD2(?:\u200D\uD83E\uDDD2)?|\uDDD2(?:\u200D\uD83E\uDDD2)?))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?)/g; }; const segmenter = new Intl.Segmenter(); function stringWidth(string, options = {}) { if (typeof string !== 'string' || string.length === 0) { return 0; } const { ambiguousIsNarrow = true, countAnsiEscapeCodes = false } = options; if (!countAnsiEscapeCodes) { string = stripAnsi(string); } if (string.length === 0) { return 0; } let width = 0; const eastAsianWidthOptions = { ambiguousAsWide: !ambiguousIsNarrow }; for (const { segment: character } of segmenter.segment(string)) { const codePoint = character.codePointAt(0); // Ignore control characters if (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f)) { continue; } // Ignore combining characters if (codePoint >= 0x3_00 && codePoint <= 0x3_6f) { continue; } if (emojiRegex().test(character)) { width += 2; continue; } width += eastAsianWidth(codePoint, eastAsianWidthOptions); } return width; } function getIndexOfNearestSpace(string, wantedIndex, shouldSearchRight) { if (string.charAt(wantedIndex) === ' ') { return wantedIndex; } const direction = shouldSearchRight ? 1 : -1; for (let index = 0; index <= 3; index++) { const finalIndex = wantedIndex + index * direction; if (string.charAt(finalIndex) === ' ') { return finalIndex; } } return wantedIndex; } function cliTruncate(text, columns, options = {}) { const { position = 'end', space = false, preferTruncationOnSpace = false } = options; let { truncationCharacter = '…' } = options; if (typeof text !== 'string') { throw new TypeError(`Expected \`input\` to be a string, got ${typeof text}`); } if (typeof columns !== 'number') { throw new TypeError(`Expected \`columns\` to be a number, got ${typeof columns}`); } if (columns < 1) { return ''; } if (columns === 1) { return truncationCharacter; } const length = stringWidth(text); if (length <= columns) { return text; } if (position === 'start') { if (preferTruncationOnSpace) { const nearestSpace = getIndexOfNearestSpace(text, length - columns + 1, true); return truncationCharacter + sliceAnsi(text, nearestSpace, length).trim(); } if (space === true) { truncationCharacter += ' '; } return ( truncationCharacter + sliceAnsi(text, length - columns + stringWidth(truncationCharacter), length) ); } if (position === 'middle') { if (space === true) { truncationCharacter = ` ${truncationCharacter} `; } const half = Math.floor(columns / 2); if (preferTruncationOnSpace) { const spaceNearFirstBreakPoint = getIndexOfNearestSpace(text, half); const spaceNearSecondBreakPoint = getIndexOfNearestSpace( text, length - (columns - half) + 1, true ); return ( sliceAnsi(text, 0, spaceNearFirstBreakPoint) + truncationCharacter + sliceAnsi(text, spaceNearSecondBreakPoint, length).trim() ); } return ( sliceAnsi(text, 0, half) + truncationCharacter + sliceAnsi(text, length - (columns - half) + stringWidth(truncationCharacter), length) ); } if (position === 'end') { if (preferTruncationOnSpace) { const nearestSpace = getIndexOfNearestSpace(text, columns - 1); return sliceAnsi(text, 0, nearestSpace) + truncationCharacter; } if (space === true) { truncationCharacter = ` ${truncationCharacter}`; } return sliceAnsi(text, 0, columns - stringWidth(truncationCharacter)) + truncationCharacter; } throw new Error( `Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${position}` ); } const cliSymbols = { arrowUp: '↑', arrowRight: '→', arrowBottom: '↓', enter: '↳', cross: '×', longDash: '─', longArrowRight: '⇢', more: '…', pointer: '❯', pointerSmall: '›', pointerSmallDouble: '»' }; const cliColumns = process.stdout.columns || 80; // eslint-disable-next-line @typescript-eslint/prefer-includes const getNewLineLength = source => (/\r\n/.test(source) ? 2 : 1); function getPointerOffset(source, lineNumber, columnNumber) { const lines = source.split(newlineRe); if (lineNumber > lines.length) { return source.length; } const newLineLength = getNewLineLength(source); return sum(fromLength(lineNumber - 1, no => lines[no].length + newLineLength)) + columnNumber; } const newlineRe = /\r?\n/; function printCodeFrame({ colors: colors$1 = colors, indent = 0, columnNumber, lineNumber, source, overscan = 2 }) { const newLineLength = getNewLineLength(source); const pointerOffset = getPointerOffset(source, lineNumber, columnNumber); const lines = source.split(newlineRe); const lineOffset = sum(lines.slice(0, lineNumber).map(line => line.length + newLineLength)); const startIndex = Math.max(0, lineNumber - 1 - overscan); const printedLines = lines.slice(startIndex, lineNumber + overscan); if (printedLines.length === 0 || printedLines.some(isMinifiedCodeLike)) return ''; const printUnderline = (line, offset) => fillSpace(offset) + colors$1.red('^'.repeat(Math.max(1, line.length - offset))); const printLineNo = (no = '') => colors$1.gray(`${no.padStart(3, ' ')}| `); return printedLines .flatMap((line, index) => { const lineNo = startIndex + index + 1; const isCurrentLine = lineNo === lineNumber; const color = isCurrentLine ? colors$1.yellowBright : colors$1.yellow; return [ cliTruncate( printLineNo(String(lineNo)) + color(line.replace(/\t/g, ' ')), cliColumns - indent ), isCurrentLine && printLineNo() + printUnderline(line, pointerOffset - (lineOffset - line.length)) ]; }) .filter(Boolean) .map(line => (indent ? fillSpace(indent) + line : line)) .join('\n'); } // to long, maybe it's a minified file, skip for codeframe const isMinifiedCodeLike = code => code.length > 240; const fillSpace = length => ' '.repeat(Math.max(length, 0)); /** * Serialize an error into a plain object that can be serialized into JSON then. */ function serializeError(error) { if (!(error instanceof Error)) return error; const result = { name: error.name, stack: error.stack, message: error.message, ...(getErrorCustomProperties(error) ?? {}) }; if (error.cause instanceof Error) { result.cause = serializeError(error.cause); } return result; } function getErrorCustomProperties(error) { const errorProperties = omit(Object.fromEntries(Object.entries(error)), builtInErrorProps); return isEmptyObject(errorProperties) ? null : errorProperties; } const builtInErrorProps = ['stack', 'cause', 'name', 'message']; const parseStackTraces = (originalTrace, filter = notInternals) => originalTrace .split('\n') .map(parseSingleStack) .filter(stack => stack !== null && filter(stack)); // Based on https://github.com/stacktracejs/error-stack-parser // Credit to stacktracejs function parseSingleStack(raw) { let line = raw.trim(); if (line.includes('(eval ')) { line = line.replace(/eval code/g, 'eval').replace(/(\(eval at [^()]*)|(,.*$)/g, ''); } let sanitizedLine = line .replace(/^\s+/, '') .replace(/\(eval code/g, '(') .replace(/^.*?\s+/, ''); // capture and preserve the parenthesized location "(/foo/my bar.js:12:87)" in // case it has spaces in it, as the string is split on \s+ later on const location = sanitizedLine.match(/ (\(.+\)$)/); if (location) { // remove the parenthesized location from the line, if it was matched sanitizedLine = sanitizedLine.replace(location[0], ''); } // if a location was matched, pass it to extractLocation() otherwise pass all sanitizedLine // because this line doesn't have function name const [url, lineNumber, columnNumber] = parseTraceLocation( location ? location[1] : sanitizedLine ); let method = (location && sanitizedLine) || ''; let file = url && ['eval', '<anonymous>'].includes(url) ? undefined : url; if (!file || !lineNumber || !columnNumber) return null; if (method.startsWith('async ')) method = method.slice(6); if (file.startsWith('file://')) file = file.slice(7); return { // normalize Windows path (\ -> /) file: resolve(file), line: toInt(lineNumber), column: toInt(columnNumber), method }; } function parseTraceLocation(urlLike) { // Fail-fast but return locations like "(native)" if (!urlLike.includes(':')) return [urlLike]; return LOCATIONS_RE.exec(urlLike.replace(/^\(|\)$/g, ''))?.slice(1, 4) ?? [urlLike]; } const LOCATIONS_RE = /(.+?)(?::(\d+))?(?::(\d+))?$/; const notInternals = stack => !stack.file.match('node:internal'); function printPrettyError(originalError, options = {}) { const { cwd = process.cwd(), indent = 0, codeFrame = true, fullStack = false, stringify = value => serializeJSON(value, 2), filterStack, colors: colors$1 = colors } = options; const getHighlightedStacks = codeFrame ? toCodeFrameCondition(codeFrame) : null; const error = toError(originalError); const stacks = parseStackTraces(error.stack || '', fullStack ? True : filterStack); const errorProperties = getErrorCustomProperties(error); const highlightedStacks = toArray(getHighlightedStacks?.(stacks) ?? []); const prefix = (value = indent) => (value ? ' '.repeat(value) : ''); const messageParts = stacks.flatMap(stack => { const { file, column, line, method } = stack; const highlighted = highlightedStacks.includes(stack); const color = highlighted ? colors$1.cyan : colors$1.gray; const path = relative(cwd, file); return [ color( `${prefix()} ${colors$1.dim(highlighted ? cliSymbols.pointerSmallDouble : cliSymbols.pointerSmall)} ${[ method, `${prefix()}${path}:${colors$1.dim(`${line}:${column}`)}` ] .filter(Boolean) .join(' ')}` ), highlighted && colors$1.yellow( printCodeFrame({ lineNumber: line, columnNumber: column, source: readFileSync(file, 'utf-8'), indent: indent + 3, colors: colors$1 }) ) ]; }); if (errorProperties) { messageParts.push( `${prefix()}${colors$1.red(`${cliSymbols.longArrowRight} serialized error properties:`)}`, `${colors$1.gray( stringify(errorProperties) .split(newlineRe) .map(line => `${prefix()}${line}`) .slice(1, -1) .join('\n') )}` ); } if (error.cause && typeof error.cause === 'object' && 'name' in error.cause) { error.cause.name = `${cliSymbols.enter} caused by ${error.cause.name}`; messageParts.push( ' ', printPrettyError(error.cause, { ...options, indent: indent + 2, codeFrame: false }) ); } return [ colors$1.red(`${prefix()}${colors$1.bold(error.name || 'Unknown Error')}: ${error.message}`), ...messageParts ] .filter(Boolean) .join('\n'); } const toCodeFrameCondition = codeFrame => typeof codeFrame === 'function' ? codeFrame : stacks => stacks.find(stack => existsSync(stack.file)); const toError = error => { if (!error) { return pick(new Error('unknown error'), ['message', 'stack']); } if (isPrimitive(error)) { const stack = String(error); return { message: stack.split(/\n/g)[0], stack }; } return error; }; // TODO https://linear.app/secundant/issue/SEC-42/neodxlog-top-level-serializers-api function serializeMeta(meta, serializers) { if (!serializers) return meta; const result = {}; for (const [key, value] of Object.entries(meta)) { result[key] = hasOwn(serializers, key) ? serializers[key](value) : value; } return result; } const DEFAULT_SERIALIZERS = { req: serializeHttpRequest, res: serializeHttpResponse, err: serializeError }; function file(filename, options) { return json({ target: createWriteStream(filename), ...options }); } function json({ target = process.stdout, dateKey = 'time', errorKey = 'err', messageKey = 'msg', serializers = DEFAULT_SERIALIZERS, levelValueKey = 'level' } = {}) { const write = 'writable' in target ? target.write.bind(target) : target; return function handleLog({ msg, error, meta, level, name, date, __: { levels } }) { const info = Object.assign( { [levelValueKey]: levels[level], [dateKey]: date.getTime(), [errorKey]: error && serializeError(error), [messageKey]: msg }, name && { name }, serializeMeta(meta, serializers) ); write(serializeJSON(info) + '\n'); }; } /** * Creates a pretty log handler for development mode in node. */ function pretty({ // eslint-disable-next-line no-console log = console.log, logError = console.error, colors: colors$1 = colors, displayMs = false, serializers = DEFAULT_SERIALIZERS, displayTime = true, displayLevel = true, prettyErrors = true, levelColors = defaultLevelColors, levelBadges = defaultLevelBadges } = {}) { const getLevelSetting = (settings, level) => settings && hasOwn(settings, level) ? settings[level] : null; const maxBadgesLength = levelBadges ? Math.max(...values(levelBadges).map(b => String(b).length)) : 0; const prettyError