@logtape/pretty 1.0.0-dev.231 → 1.0.0-dev.234
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +167 -92
- package/deno.json +1 -1
- package/dist/formatter.cjs +78 -84
- package/dist/formatter.d.cts +25 -35
- package/dist/formatter.d.cts.map +1 -1
- package/dist/formatter.d.ts +25 -35
- package/dist/formatter.d.ts.map +1 -1
- package/dist/formatter.js +78 -84
- package/dist/formatter.js.map +1 -1
- package/dist/wcwidth.cjs +193 -2
- package/dist/wcwidth.js +193 -2
- package/dist/wcwidth.js.map +1 -1
- package/formatter.test.ts +24 -2
- package/formatter.ts +121 -143
- package/package.json +3 -3
- package/wcwidth.ts +210 -179
package/dist/wcwidth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wcwidth.js","names":["text: string","code: number"],"sources":["../wcwidth.ts"],"sourcesContent":["/**\n * @fileoverview\n * wcwidth implementation for JavaScript/TypeScript\n *\n * This module provides functions to calculate the display width of Unicode\n * characters and strings in terminal/monospace contexts, compatible with\n * the Python wcwidth library and POSIX wcwidth() standard.\n *\n * Based on Unicode 15.1.0 character width tables.\n */\n\n/**\n * Remove all ANSI escape sequences from a string.\n *\n * @param text The string to clean\n * @returns String with ANSI escape sequences removed\n */\nexport function stripAnsi(text: string): string {\n return text.replace(/\\[[0-9;]*m/g, \"\");\n}\n\n/**\n * Calculate the display width of a string, ignoring ANSI escape codes\n * and accounting for Unicode character widths using wcwidth-compatible logic.\n *\n * @param text The string to measure\n * @returns The display width in terminal columns\n */\nexport function getDisplayWidth(text: string): number {\n // Remove all ANSI escape sequences first\n const cleanText = stripAnsi(text);\n\n if (cleanText.length === 0) return 0;\n\n let width = 0;\n let i = 0;\n\n // Process character by character, handling surrogate pairs and combining characters\n while (i < cleanText.length) {\n const code = cleanText.codePointAt(i);\n if (code === undefined) {\n i++;\n continue;\n }\n\n const charWidth = wcwidth(code);\n if (charWidth >= 0) {\n width += charWidth;\n }\n\n // Move to next code point (handles surrogate pairs)\n i += (code > 0xFFFF) ? 2 : 1;\n }\n\n return width;\n}\n\n/**\n * Get the display width of a single Unicode code point.\n * Based on wcwidth implementation - returns:\n * -1: Non-printable/control character\n * 0: Zero-width character (combining marks, etc.)\n * 1: Normal width character\n * 2: Wide character (East Asian, emoji, etc.)\n *\n * @param code Unicode code point\n * @returns Display width (-1, 0, 1, or 2)\n */\nexport function wcwidth(code: number): number {\n // C0 and C1 control characters\n if (code < 32 || (code >= 0x7F && code < 0xA0)) {\n return -1;\n }\n\n // Zero-width characters (based on wcwidth table_zero.py)\n if (isZeroWidth(code)) {\n return 0;\n }\n\n // Wide characters (based on wcwidth table_wide.py)\n if (isWideCharacter(code)) {\n return 2;\n }\n\n return 1;\n}\n\n/**\n * Check if a character is zero-width (combining marks, etc.)\n * Based on wcwidth's zero-width table.\n *\n * @param code Unicode code point\n * @returns True if the character has zero display width\n */\nfunction isZeroWidth(code: number): boolean {\n return (\n // Combining Diacritical Marks\n (code >= 0x0300 && code <= 0x036F) ||\n // Hebrew combining marks\n (code >= 0x0483 && code <= 0x0489) ||\n // Arabic combining marks\n (code >= 0x0591 && code <= 0x05BD) ||\n code === 0x05BF ||\n (code >= 0x05C1 && code <= 0x05C2) ||\n (code >= 0x05C4 && code <= 0x05C5) ||\n code === 0x05C7 ||\n // More Arabic combining marks\n (code >= 0x0610 && code <= 0x061A) ||\n (code >= 0x064B && code <= 0x065F) ||\n code === 0x0670 ||\n (code >= 0x06D6 && code <= 0x06DC) ||\n (code >= 0x06DF && code <= 0x06E4) ||\n (code >= 0x06E7 && code <= 0x06E8) ||\n (code >= 0x06EA && code <= 0x06ED) ||\n code === 0x0711 ||\n (code >= 0x0730 && code <= 0x074A) ||\n (code >= 0x07A6 && code <= 0x07B0) ||\n (code >= 0x07EB && code <= 0x07F3) ||\n code === 0x07FD ||\n // Various other combining marks\n (code >= 0x0816 && code <= 0x0819) ||\n (code >= 0x081B && code <= 0x0823) ||\n (code >= 0x0825 && code <= 0x0827) ||\n (code >= 0x0829 && code <= 0x082D) ||\n (code >= 0x0859 && code <= 0x085B) ||\n (code >= 0x08D3 && code <= 0x08E1) ||\n (code >= 0x08E3 && code <= 0x0902) ||\n code === 0x093A ||\n code === 0x093C ||\n (code >= 0x0941 && code <= 0x0948) ||\n code === 0x094D ||\n (code >= 0x0951 && code <= 0x0957) ||\n (code >= 0x0962 && code <= 0x0963) ||\n code === 0x0981 ||\n code === 0x09BC ||\n (code >= 0x09C1 && code <= 0x09C4) ||\n code === 0x09CD ||\n (code >= 0x09E2 && code <= 0x09E3) ||\n (code >= 0x09FE && code <= 0x09FE) ||\n (code >= 0x0A01 && code <= 0x0A02) ||\n code === 0x0A3C ||\n (code >= 0x0A41 && code <= 0x0A42) ||\n (code >= 0x0A47 && code <= 0x0A48) ||\n (code >= 0x0A4B && code <= 0x0A4D) ||\n code === 0x0A51 ||\n (code >= 0x0A70 && code <= 0x0A71) ||\n code === 0x0A75 ||\n (code >= 0x0A81 && code <= 0x0A82) ||\n code === 0x0ABC ||\n (code >= 0x0AC1 && code <= 0x0AC5) ||\n (code >= 0x0AC7 && code <= 0x0AC8) ||\n code === 0x0ACD ||\n (code >= 0x0AE2 && code <= 0x0AE3) ||\n (code >= 0x0AFA && code <= 0x0AFF) ||\n code === 0x0B01 ||\n code === 0x0B3C ||\n code === 0x0B3F ||\n (code >= 0x0B41 && code <= 0x0B44) ||\n code === 0x0B4D ||\n (code >= 0x0B55 && code <= 0x0B56) ||\n (code >= 0x0B62 && code <= 0x0B63) ||\n code === 0x0B82 ||\n code === 0x0BC0 ||\n code === 0x0BCD ||\n code === 0x0C00 ||\n code === 0x0C04 ||\n (code >= 0x0C3E && code <= 0x0C40) ||\n (code >= 0x0C46 && code <= 0x0C48) ||\n (code >= 0x0C4A && code <= 0x0C4D) ||\n (code >= 0x0C55 && code <= 0x0C56) ||\n (code >= 0x0C62 && code <= 0x0C63) ||\n code === 0x0C81 ||\n code === 0x0CBC ||\n code === 0x0CBF ||\n code === 0x0CC6 ||\n (code >= 0x0CCC && code <= 0x0CCD) ||\n (code >= 0x0CE2 && code <= 0x0CE3) ||\n (code >= 0x0D00 && code <= 0x0D01) ||\n (code >= 0x0D3B && code <= 0x0D3C) ||\n code === 0x0D41 ||\n (code >= 0x0D44 && code <= 0x0D44) ||\n code === 0x0D4D ||\n (code >= 0x0D62 && code <= 0x0D63) ||\n code === 0x0D81 ||\n code === 0x0DCA ||\n (code >= 0x0DD2 && code <= 0x0DD4) ||\n code === 0x0DD6 ||\n code === 0x0E31 ||\n (code >= 0x0E34 && code <= 0x0E3A) ||\n (code >= 0x0E47 && code <= 0x0E4E) ||\n code === 0x0EB1 ||\n (code >= 0x0EB4 && code <= 0x0EBC) ||\n (code >= 0x0EC8 && code <= 0x0ECD) ||\n (code >= 0x0F18 && code <= 0x0F19) ||\n code === 0x0F35 ||\n code === 0x0F37 ||\n code === 0x0F39 ||\n (code >= 0x0F71 && code <= 0x0F7E) ||\n (code >= 0x0F80 && code <= 0x0F84) ||\n (code >= 0x0F86 && code <= 0x0F87) ||\n (code >= 0x0F8D && code <= 0x0F97) ||\n (code >= 0x0F99 && code <= 0x0FBC) ||\n code === 0x0FC6 ||\n (code >= 0x102D && code <= 0x1030) ||\n (code >= 0x1032 && code <= 0x1037) ||\n (code >= 0x1039 && code <= 0x103A) ||\n (code >= 0x103D && code <= 0x103E) ||\n (code >= 0x1058 && code <= 0x1059) ||\n (code >= 0x105E && code <= 0x1060) ||\n (code >= 0x1071 && code <= 0x1074) ||\n code === 0x1082 ||\n (code >= 0x1085 && code <= 0x1086) ||\n code === 0x108D ||\n code === 0x109D ||\n (code >= 0x135D && code <= 0x135F) ||\n (code >= 0x1712 && code <= 0x1714) ||\n (code >= 0x1732 && code <= 0x1734) ||\n (code >= 0x1752 && code <= 0x1753) ||\n (code >= 0x1772 && code <= 0x1773) ||\n (code >= 0x17B4 && code <= 0x17B5) ||\n (code >= 0x17B7 && code <= 0x17BD) ||\n code === 0x17C6 ||\n (code >= 0x17C9 && code <= 0x17D3) ||\n code === 0x17DD ||\n (code >= 0x180B && code <= 0x180D) ||\n (code >= 0x1885 && code <= 0x1886) ||\n code === 0x18A9 ||\n (code >= 0x1920 && code <= 0x1922) ||\n (code >= 0x1927 && code <= 0x1928) ||\n code === 0x1932 ||\n (code >= 0x1939 && code <= 0x193B) ||\n (code >= 0x1A17 && code <= 0x1A18) ||\n code === 0x1A1B ||\n code === 0x1A56 ||\n (code >= 0x1A58 && code <= 0x1A5E) ||\n code === 0x1A60 ||\n code === 0x1A62 ||\n (code >= 0x1A65 && code <= 0x1A6C) ||\n (code >= 0x1A73 && code <= 0x1A7C) ||\n code === 0x1A7F ||\n (code >= 0x1AB0 && code <= 0x1ABE) ||\n (code >= 0x1B00 && code <= 0x1B03) ||\n code === 0x1B34 ||\n (code >= 0x1B36 && code <= 0x1B3A) ||\n code === 0x1B3C ||\n code === 0x1B42 ||\n (code >= 0x1B6B && code <= 0x1B73) ||\n (code >= 0x1B80 && code <= 0x1B81) ||\n (code >= 0x1BA2 && code <= 0x1BA5) ||\n (code >= 0x1BA8 && code <= 0x1BA9) ||\n (code >= 0x1BAB && code <= 0x1BAD) ||\n code === 0x1BE6 ||\n (code >= 0x1BE8 && code <= 0x1BE9) ||\n code === 0x1BED ||\n (code >= 0x1BEF && code <= 0x1BF1) ||\n (code >= 0x1C2C && code <= 0x1C33) ||\n (code >= 0x1C36 && code <= 0x1C37) ||\n (code >= 0x1CD0 && code <= 0x1CD2) ||\n (code >= 0x1CD4 && code <= 0x1CE0) ||\n (code >= 0x1CE2 && code <= 0x1CE8) ||\n code === 0x1CED ||\n code === 0x1CF4 ||\n (code >= 0x1CF8 && code <= 0x1CF9) ||\n (code >= 0x1DC0 && code <= 0x1DF9) ||\n (code >= 0x1DFB && code <= 0x1DFF) ||\n (code >= 0x200B && code <= 0x200F) || // Zero-width spaces\n (code >= 0x202A && code <= 0x202E) || // Bidirectional format characters\n (code >= 0x2060 && code <= 0x2064) || // Word joiner, etc.\n (code >= 0x2066 && code <= 0x206F) || // More bidirectional\n code === 0xFEFF || // Zero-width no-break space\n (code >= 0xFE00 && code <= 0xFE0F) || // Variation selectors\n (code >= 0xFE20 && code <= 0xFE2F) // Combining half marks\n );\n}\n\n/**\n * Check if a character code point represents a wide character.\n * Based on wcwidth's wide character table (selected ranges from Unicode 15.1.0).\n *\n * @param code Unicode code point\n * @returns True if the character has width 2\n */\nfunction isWideCharacter(code: number): boolean {\n return (\n // Based on wcwidth table_wide.py for Unicode 15.1.0\n (code >= 0x1100 && code <= 0x115F) || // Hangul Jamo\n (code >= 0x231A && code <= 0x231B) || // Watch, Hourglass\n (code >= 0x2329 && code <= 0x232A) || // Angle brackets\n (code >= 0x23E9 && code <= 0x23EC) || // Media controls\n code === 0x23F0 || code === 0x23F3 || // Alarm clock, hourglass\n (code >= 0x25FD && code <= 0x25FE) || // Small squares\n (code >= 0x2614 && code <= 0x2615) || // Umbrella, coffee\n (code >= 0x2648 && code <= 0x2653) || // Zodiac signs\n code === 0x267F || code === 0x2693 || // Wheelchair, anchor\n code === 0x26A0 || code === 0x26A1 || code === 0x26AA || code === 0x26AB || // Warning, lightning, circles\n (code >= 0x26BD && code <= 0x26BE) || // Sports balls\n (code >= 0x26C4 && code <= 0x26C5) || // Weather\n code === 0x26CE || code === 0x26D4 || // Ophiuchus, no entry\n (code >= 0x26EA && code <= 0x26EA) || // Church\n (code >= 0x26F2 && code <= 0x26F3) || // Fountain, golf\n code === 0x26F5 || code === 0x26FA || // Sailboat, tent\n code === 0x26FD || // Gas pump\n (code >= 0x2705 && code <= 0x2705) || // Check mark\n (code >= 0x270A && code <= 0x270B) || // Raised fists\n code === 0x2728 || // Sparkles (✨)\n code === 0x274C || // Cross mark (❌)\n code === 0x274E || // Cross mark button\n (code >= 0x2753 && code <= 0x2755) || // Question marks\n code === 0x2757 || // Exclamation\n (code >= 0x2795 && code <= 0x2797) || // Plus signs\n code === 0x27B0 || code === 0x27BF || // Curly loop, double curly loop\n (code >= 0x2B1B && code <= 0x2B1C) || // Large squares\n code === 0x2B50 || code === 0x2B55 || // Star, circle\n (code >= 0x2E80 && code <= 0x2E99) || // CJK Radicals Supplement\n (code >= 0x2E9B && code <= 0x2EF3) ||\n (code >= 0x2F00 && code <= 0x2FD5) || // Kangxi Radicals\n (code >= 0x2FF0 && code <= 0x2FFB) || // Ideographic Description Characters\n (code >= 0x3000 && code <= 0x303E) || // CJK Symbols and Punctuation\n (code >= 0x3041 && code <= 0x3096) || // Hiragana\n (code >= 0x3099 && code <= 0x30FF) || // Katakana\n (code >= 0x3105 && code <= 0x312F) || // Bopomofo\n (code >= 0x3131 && code <= 0x318E) || // Hangul Compatibility Jamo\n (code >= 0x3190 && code <= 0x31E3) || // Various CJK\n (code >= 0x31F0 && code <= 0x321E) || // Katakana Phonetic Extensions\n (code >= 0x3220 && code <= 0x3247) || // Enclosed CJK Letters and Months\n (code >= 0x3250 && code <= 0x4DBF) || // Various CJK\n (code >= 0x4E00 && code <= 0x9FFF) || // CJK Unified Ideographs\n (code >= 0xA960 && code <= 0xA97F) || // Hangul Jamo Extended-A\n (code >= 0xAC00 && code <= 0xD7A3) || // Hangul Syllables\n (code >= 0xD7B0 && code <= 0xD7C6) || // Hangul Jamo Extended-B\n (code >= 0xF900 && code <= 0xFAFF) || // CJK Compatibility Ideographs\n (code >= 0xFE10 && code <= 0xFE19) || // Vertical Forms\n (code >= 0xFE30 && code <= 0xFE6F) || // CJK Compatibility Forms\n (code >= 0xFF00 && code <= 0xFF60) || // Fullwidth Forms\n (code >= 0xFFE0 && code <= 0xFFE6) || // Fullwidth Forms\n (code >= 0x16FE0 && code <= 0x16FE4) || // Tangut\n (code >= 0x16FF0 && code <= 0x16FF1) ||\n (code >= 0x17000 && code <= 0x187F7) || // Tangut\n (code >= 0x18800 && code <= 0x18CD5) || // Tangut Components\n (code >= 0x18D00 && code <= 0x18D08) || // Tangut Supplement\n (code >= 0x1AFF0 && code <= 0x1AFF3) ||\n (code >= 0x1AFF5 && code <= 0x1AFFB) ||\n (code >= 0x1AFFD && code <= 0x1AFFE) ||\n (code >= 0x1B000 && code <= 0x1B122) || // Kana Extended-A/Supplement\n (code >= 0x1B150 && code <= 0x1B152) ||\n (code >= 0x1B164 && code <= 0x1B167) ||\n (code >= 0x1B170 && code <= 0x1B2FB) ||\n code === 0x1F004 || // Mahjong Red Dragon\n code === 0x1F0CF || // Playing Card Black Joker\n (code >= 0x1F18E && code <= 0x1F18E) || // AB Button\n (code >= 0x1F191 && code <= 0x1F19A) || // Various squared symbols\n (code >= 0x1F1E6 && code <= 0x1F1FF) || // Regional Indicator Symbols (flags)\n (code >= 0x1F200 && code <= 0x1F202) || // Squared symbols\n (code >= 0x1F210 && code <= 0x1F23B) || // Squared CJK\n (code >= 0x1F240 && code <= 0x1F248) || // Tortoise shell bracketed\n (code >= 0x1F250 && code <= 0x1F251) || // Circled ideographs\n (code >= 0x1F260 && code <= 0x1F265) ||\n (code >= 0x1F300 && code <= 0x1F6D7) || // Large emoji block\n (code >= 0x1F6E0 && code <= 0x1F6EC) ||\n (code >= 0x1F6F0 && code <= 0x1F6FC) ||\n (code >= 0x1F700 && code <= 0x1F773) ||\n (code >= 0x1F780 && code <= 0x1F7D8) ||\n (code >= 0x1F7E0 && code <= 0x1F7EB) ||\n (code >= 0x1F7F0 && code <= 0x1F7F0) ||\n (code >= 0x1F800 && code <= 0x1F80B) ||\n (code >= 0x1F810 && code <= 0x1F847) ||\n (code >= 0x1F850 && code <= 0x1F859) ||\n (code >= 0x1F860 && code <= 0x1F887) ||\n (code >= 0x1F890 && code <= 0x1F8AD) ||\n (code >= 0x1F8B0 && code <= 0x1F8B1) ||\n (code >= 0x1F900 && code <= 0x1FA53) || // Supplemental symbols and pictographs\n (code >= 0x1FA60 && code <= 0x1FA6D) ||\n (code >= 0x1FA70 && code <= 0x1FA7C) ||\n (code >= 0x1FA80 && code <= 0x1FA88) ||\n (code >= 0x1FA90 && code <= 0x1FABD) ||\n (code >= 0x1FABF && code <= 0x1FAC5) ||\n (code >= 0x1FACE && code <= 0x1FADB) ||\n (code >= 0x1FAE0 && code <= 0x1FAE8) ||\n (code >= 0x1FAF0 && code <= 0x1FAF8) ||\n (code >= 0x20000 && code <= 0x2FFFD) || // CJK Extension B\n (code >= 0x30000 && code <= 0x3FFFD) // CJK Extension C\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,SAAgB,UAAUA,MAAsB;AAC9C,QAAO,KAAK,QAAQ,eAAe,GAAG;AACvC;;;;;;;;AASD,SAAgB,gBAAgBA,MAAsB;CAEpD,MAAM,YAAY,UAAU,KAAK;AAEjC,KAAI,UAAU,WAAW,EAAG,QAAO;CAEnC,IAAI,QAAQ;CACZ,IAAI,IAAI;AAGR,QAAO,IAAI,UAAU,QAAQ;EAC3B,MAAM,OAAO,UAAU,YAAY,EAAE;AACrC,MAAI,iBAAoB;AACtB;AACA;EACD;EAED,MAAM,YAAY,QAAQ,KAAK;AAC/B,MAAI,aAAa,EACf,UAAS;AAIX,OAAM,OAAO,QAAU,IAAI;CAC5B;AAED,QAAO;AACR;;;;;;;;;;;;AAaD,SAAgB,QAAQC,MAAsB;AAE5C,KAAI,OAAO,MAAO,QAAQ,OAAQ,OAAO,IACvC,QAAO;AAIT,KAAI,YAAY,KAAK,CACnB,QAAO;AAIT,KAAI,gBAAgB,KAAK,CACvB,QAAO;AAGT,QAAO;AACR;;;;;;;;AASD,SAAS,YAAYA,MAAuB;AAC1C,QAEG,QAAQ,OAAU,QAAQ,OAE1B,QAAQ,QAAU,QAAQ,QAE1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QAER,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QAER,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACT,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACT,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACT,SAAS,QACT,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACT,SAAS,QACT,SAAS,QACT,SAAS,QACT,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACT,SAAS,QACT,SAAS,QACT,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACT,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACT,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACT,SAAS,QACT,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC3B,SAAS,QACR,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAAU,QAAQ,QAC1B,QAAQ,QAA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C3B,QAAQ,UAAW,QAAQ,UAC5B,SAAS,UACT,SAAS,UACR,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ;AAE/B"}
|
|
1
|
+
{"version":3,"file":"wcwidth.js","names":["text: string","code: number","ZERO_WIDTH_RANGES: Array<[number, number]>","ranges: Array<[number, number]>"],"sources":["../wcwidth.ts"],"sourcesContent":["/**\n * @fileoverview\n * wcwidth implementation for JavaScript/TypeScript\n *\n * This module provides functions to calculate the display width of Unicode\n * characters and strings in terminal/monospace contexts, compatible with\n * the Python wcwidth library and POSIX wcwidth() standard.\n *\n * Based on Unicode 15.1.0 character width tables.\n */\n\n// Pre-compiled regex for ANSI escape sequences\n// deno-lint-ignore no-control-regex\nconst ANSI_PATTERN = /\\x1b\\[[0-9;]*m/g;\n\n/**\n * Remove all ANSI escape sequences from a string.\n *\n * @param text The string to clean\n * @returns String with ANSI escape sequences removed\n */\nexport function stripAnsi(text: string): string {\n return text.replace(ANSI_PATTERN, \"\");\n}\n\n/**\n * Calculate the display width of a string, ignoring ANSI escape codes\n * and accounting for Unicode character widths using wcwidth-compatible logic.\n *\n * @param text The string to measure\n * @returns The display width in terminal columns\n */\nexport function getDisplayWidth(text: string): number {\n // Remove all ANSI escape sequences first\n const cleanText = stripAnsi(text);\n\n if (cleanText.length === 0) return 0;\n\n let width = 0;\n let i = 0;\n\n // Process character by character, handling surrogate pairs and combining characters\n while (i < cleanText.length) {\n const code = cleanText.codePointAt(i);\n if (code === undefined) {\n i++;\n continue;\n }\n\n const charWidth = wcwidth(code);\n if (charWidth >= 0) {\n width += charWidth;\n }\n\n // Move to next code point (handles surrogate pairs)\n i += (code > 0xFFFF) ? 2 : 1;\n }\n\n return width;\n}\n\n/**\n * Get the display width of a single Unicode code point.\n * Based on wcwidth implementation - returns:\n * -1: Non-printable/control character\n * 0: Zero-width character (combining marks, etc.)\n * 1: Normal width character\n * 2: Wide character (East Asian, emoji, etc.)\n *\n * @param code Unicode code point\n * @returns Display width (-1, 0, 1, or 2)\n */\nexport function wcwidth(code: number): number {\n // C0 and C1 control characters\n if (code < 32 || (code >= 0x7F && code < 0xA0)) {\n return -1;\n }\n\n // Zero-width characters (based on wcwidth table_zero.py)\n if (isZeroWidth(code)) {\n return 0;\n }\n\n // Wide characters (based on wcwidth table_wide.py)\n if (isWideCharacter(code)) {\n return 2;\n }\n\n return 1;\n}\n\n// Zero-width character ranges (sorted for binary search)\nconst ZERO_WIDTH_RANGES: Array<[number, number]> = [\n [0x0300, 0x036F], // Combining Diacritical Marks\n [0x0483, 0x0489], // Hebrew combining marks\n [0x0591, 0x05BD], // Arabic combining marks\n [0x05C1, 0x05C2],\n [0x05C4, 0x05C5],\n [0x0610, 0x061A], // More Arabic combining marks\n [0x064B, 0x065F],\n [0x06D6, 0x06DC],\n [0x06DF, 0x06E4],\n [0x06E7, 0x06E8],\n [0x06EA, 0x06ED],\n [0x0730, 0x074A],\n [0x07A6, 0x07B0],\n [0x07EB, 0x07F3],\n [0x0816, 0x0819],\n [0x081B, 0x0823],\n [0x0825, 0x0827],\n [0x0829, 0x082D],\n [0x0859, 0x085B],\n [0x08D3, 0x08E1],\n [0x08E3, 0x0902],\n [0x0941, 0x0948],\n [0x0951, 0x0957],\n [0x0962, 0x0963],\n [0x09C1, 0x09C4],\n [0x09E2, 0x09E3],\n [0x0A01, 0x0A02],\n [0x0A41, 0x0A42],\n [0x0A47, 0x0A48],\n [0x0A4B, 0x0A4D],\n [0x0A70, 0x0A71],\n [0x0A81, 0x0A82],\n [0x0AC1, 0x0AC5],\n [0x0AC7, 0x0AC8],\n [0x0AE2, 0x0AE3],\n [0x0AFA, 0x0AFF],\n [0x0B41, 0x0B44],\n [0x0B55, 0x0B56],\n [0x0B62, 0x0B63],\n [0x0C3E, 0x0C40],\n [0x0C46, 0x0C48],\n [0x0C4A, 0x0C4D],\n [0x0C55, 0x0C56],\n [0x0C62, 0x0C63],\n [0x0CCC, 0x0CCD],\n [0x0CE2, 0x0CE3],\n [0x0D00, 0x0D01],\n [0x0D3B, 0x0D3C],\n [0x0D62, 0x0D63],\n [0x0DD2, 0x0DD4],\n [0x0E34, 0x0E3A],\n [0x0E47, 0x0E4E],\n [0x0EB4, 0x0EBC],\n [0x0EC8, 0x0ECD],\n [0x0F18, 0x0F19],\n [0x0F71, 0x0F7E],\n [0x0F80, 0x0F84],\n [0x0F86, 0x0F87],\n [0x0F8D, 0x0F97],\n [0x0F99, 0x0FBC],\n [0x102D, 0x1030],\n [0x1032, 0x1037],\n [0x1039, 0x103A],\n [0x103D, 0x103E],\n [0x1058, 0x1059],\n [0x105E, 0x1060],\n [0x1071, 0x1074],\n [0x1085, 0x1086],\n [0x135D, 0x135F],\n [0x1712, 0x1714],\n [0x1732, 0x1734],\n [0x1752, 0x1753],\n [0x1772, 0x1773],\n [0x17B4, 0x17B5],\n [0x17B7, 0x17BD],\n [0x17C9, 0x17D3],\n [0x180B, 0x180D],\n [0x1885, 0x1886],\n [0x1920, 0x1922],\n [0x1927, 0x1928],\n [0x1939, 0x193B],\n [0x1A17, 0x1A18],\n [0x1A58, 0x1A5E],\n [0x1A65, 0x1A6C],\n [0x1A73, 0x1A7C],\n [0x1AB0, 0x1ABE],\n [0x1B00, 0x1B03],\n [0x1B36, 0x1B3A],\n [0x1B6B, 0x1B73],\n [0x1B80, 0x1B81],\n [0x1BA2, 0x1BA5],\n [0x1BA8, 0x1BA9],\n [0x1BAB, 0x1BAD],\n [0x1BE8, 0x1BE9],\n [0x1BEF, 0x1BF1],\n [0x1C2C, 0x1C33],\n [0x1C36, 0x1C37],\n [0x1CD0, 0x1CD2],\n [0x1CD4, 0x1CE0],\n [0x1CE2, 0x1CE8],\n [0x1CF8, 0x1CF9],\n [0x1DC0, 0x1DF9],\n [0x1DFB, 0x1DFF],\n [0x200B, 0x200F], // Zero-width spaces\n [0x202A, 0x202E], // Bidirectional format characters\n [0x2060, 0x2064], // Word joiner, etc.\n [0x2066, 0x206F], // More bidirectional\n [0xFE00, 0xFE0F], // Variation selectors\n [0xFE20, 0xFE2F], // Combining half marks\n];\n\n// Single zero-width characters\nconst ZERO_WIDTH_SINGLES = new Set([\n 0x05BF,\n 0x05C7,\n 0x0670,\n 0x0711,\n 0x07FD,\n 0x093A,\n 0x093C,\n 0x094D,\n 0x0981,\n 0x09BC,\n 0x09CD,\n 0x09FE,\n 0x0A3C,\n 0x0A51,\n 0x0A75,\n 0x0ABC,\n 0x0ACD,\n 0x0B01,\n 0x0B3C,\n 0x0B3F,\n 0x0B4D,\n 0x0B82,\n 0x0BC0,\n 0x0BCD,\n 0x0C00,\n 0x0C04,\n 0x0C81,\n 0x0CBC,\n 0x0CBF,\n 0x0CC6,\n 0x0D41,\n 0x0D44,\n 0x0D4D,\n 0x0D81,\n 0x0DCA,\n 0x0DD6,\n 0x0E31,\n 0x0EB1,\n 0x0F35,\n 0x0F37,\n 0x0F39,\n 0x0FC6,\n 0x1082,\n 0x108D,\n 0x109D,\n 0x17C6,\n 0x17DD,\n 0x18A9,\n 0x1932,\n 0x1A1B,\n 0x1A56,\n 0x1A60,\n 0x1A62,\n 0x1A7F,\n 0x1B34,\n 0x1B3C,\n 0x1B42,\n 0x1BE6,\n 0x1BED,\n 0x1CED,\n 0x1CF4,\n 0xFEFF,\n]);\n\n/**\n * Binary search to check if a value is within any range\n */\nfunction isInRanges(code: number, ranges: Array<[number, number]>): boolean {\n let left = 0;\n let right = ranges.length - 1;\n\n while (left <= right) {\n const mid = Math.floor((left + right) / 2);\n const [start, end] = ranges[mid];\n\n if (code >= start && code <= end) {\n return true;\n } else if (code < start) {\n right = mid - 1;\n } else {\n left = mid + 1;\n }\n }\n\n return false;\n}\n\n/**\n * Check if a character is zero-width (combining marks, etc.)\n * Based on wcwidth's zero-width table.\n *\n * @param code Unicode code point\n * @returns True if the character has zero display width\n */\nfunction isZeroWidth(code: number): boolean {\n return ZERO_WIDTH_SINGLES.has(code) || isInRanges(code, ZERO_WIDTH_RANGES);\n}\n\n/**\n * Check if a character code point represents a wide character.\n * Based on wcwidth's wide character table (selected ranges from Unicode 15.1.0).\n *\n * @param code Unicode code point\n * @returns True if the character has width 2\n */\nfunction isWideCharacter(code: number): boolean {\n // cSpell: disable\n return (\n // Based on wcwidth table_wide.py for Unicode 15.1.0\n (code >= 0x1100 && code <= 0x115F) || // Hangul Jamo\n (code >= 0x231A && code <= 0x231B) || // Watch, Hourglass\n (code >= 0x2329 && code <= 0x232A) || // Angle brackets\n (code >= 0x23E9 && code <= 0x23EC) || // Media controls\n code === 0x23F0 || code === 0x23F3 || // Alarm clock, hourglass\n (code >= 0x25FD && code <= 0x25FE) || // Small squares\n (code >= 0x2614 && code <= 0x2615) || // Umbrella, coffee\n (code >= 0x2648 && code <= 0x2653) || // Zodiac signs\n code === 0x267F || code === 0x2693 || // Wheelchair, anchor\n code === 0x26A0 || code === 0x26A1 || code === 0x26AA || code === 0x26AB || // Warning, lightning, circles\n (code >= 0x26BD && code <= 0x26BE) || // Sports balls\n (code >= 0x26C4 && code <= 0x26C5) || // Weather\n code === 0x26CE || code === 0x26D4 || // Ophiuchus, no entry\n (code >= 0x26EA && code <= 0x26EA) || // Church\n (code >= 0x26F2 && code <= 0x26F3) || // Fountain, golf\n code === 0x26F5 || code === 0x26FA || // Sailboat, tent\n code === 0x26FD || // Gas pump\n (code >= 0x2705 && code <= 0x2705) || // Check mark\n (code >= 0x270A && code <= 0x270B) || // Raised fists\n code === 0x2728 || // Sparkles (✨)\n code === 0x274C || // Cross mark (❌)\n code === 0x274E || // Cross mark button\n (code >= 0x2753 && code <= 0x2755) || // Question marks\n code === 0x2757 || // Exclamation\n (code >= 0x2795 && code <= 0x2797) || // Plus signs\n code === 0x27B0 || code === 0x27BF || // Curly loop, double curly loop\n (code >= 0x2B1B && code <= 0x2B1C) || // Large squares\n code === 0x2B50 || code === 0x2B55 || // Star, circle\n (code >= 0x2E80 && code <= 0x2E99) || // CJK Radicals Supplement\n (code >= 0x2E9B && code <= 0x2EF3) ||\n (code >= 0x2F00 && code <= 0x2FD5) || // Kangxi Radicals\n (code >= 0x2FF0 && code <= 0x2FFB) || // Ideographic Description Characters\n (code >= 0x3000 && code <= 0x303E) || // CJK Symbols and Punctuation\n (code >= 0x3041 && code <= 0x3096) || // Hiragana\n (code >= 0x3099 && code <= 0x30FF) || // Katakana\n (code >= 0x3105 && code <= 0x312F) || // Bopomofo\n (code >= 0x3131 && code <= 0x318E) || // Hangul Compatibility Jamo\n (code >= 0x3190 && code <= 0x31E3) || // Various CJK\n (code >= 0x31F0 && code <= 0x321E) || // Katakana Phonetic Extensions\n (code >= 0x3220 && code <= 0x3247) || // Enclosed CJK Letters and Months\n (code >= 0x3250 && code <= 0x4DBF) || // Various CJK\n (code >= 0x4E00 && code <= 0x9FFF) || // CJK Unified Ideographs\n (code >= 0xA960 && code <= 0xA97F) || // Hangul Jamo Extended-A\n (code >= 0xAC00 && code <= 0xD7A3) || // Hangul Syllables\n (code >= 0xD7B0 && code <= 0xD7C6) || // Hangul Jamo Extended-B\n (code >= 0xF900 && code <= 0xFAFF) || // CJK Compatibility Ideographs\n (code >= 0xFE10 && code <= 0xFE19) || // Vertical Forms\n (code >= 0xFE30 && code <= 0xFE6F) || // CJK Compatibility Forms\n (code >= 0xFF00 && code <= 0xFF60) || // Fullwidth Forms\n (code >= 0xFFE0 && code <= 0xFFE6) || // Fullwidth Forms\n (code >= 0x16FE0 && code <= 0x16FE4) || // Tangut\n (code >= 0x16FF0 && code <= 0x16FF1) ||\n (code >= 0x17000 && code <= 0x187F7) || // Tangut\n (code >= 0x18800 && code <= 0x18CD5) || // Tangut Components\n (code >= 0x18D00 && code <= 0x18D08) || // Tangut Supplement\n (code >= 0x1AFF0 && code <= 0x1AFF3) ||\n (code >= 0x1AFF5 && code <= 0x1AFFB) ||\n (code >= 0x1AFFD && code <= 0x1AFFE) ||\n (code >= 0x1B000 && code <= 0x1B122) || // Kana Extended-A/Supplement\n (code >= 0x1B150 && code <= 0x1B152) ||\n (code >= 0x1B164 && code <= 0x1B167) ||\n (code >= 0x1B170 && code <= 0x1B2FB) ||\n code === 0x1F004 || // Mahjong Red Dragon\n code === 0x1F0CF || // Playing Card Black Joker\n (code >= 0x1F18E && code <= 0x1F18E) || // AB Button\n (code >= 0x1F191 && code <= 0x1F19A) || // Various squared symbols\n (code >= 0x1F1E6 && code <= 0x1F1FF) || // Regional Indicator Symbols (flags)\n (code >= 0x1F200 && code <= 0x1F202) || // Squared symbols\n (code >= 0x1F210 && code <= 0x1F23B) || // Squared CJK\n (code >= 0x1F240 && code <= 0x1F248) || // Tortoise shell bracketed\n (code >= 0x1F250 && code <= 0x1F251) || // Circled ideographs\n (code >= 0x1F260 && code <= 0x1F265) ||\n (code >= 0x1F300 && code <= 0x1F6D7) || // Large emoji block\n (code >= 0x1F6E0 && code <= 0x1F6EC) ||\n (code >= 0x1F6F0 && code <= 0x1F6FC) ||\n (code >= 0x1F700 && code <= 0x1F773) ||\n (code >= 0x1F780 && code <= 0x1F7D8) ||\n (code >= 0x1F7E0 && code <= 0x1F7EB) ||\n (code >= 0x1F7F0 && code <= 0x1F7F0) ||\n (code >= 0x1F800 && code <= 0x1F80B) ||\n (code >= 0x1F810 && code <= 0x1F847) ||\n (code >= 0x1F850 && code <= 0x1F859) ||\n (code >= 0x1F860 && code <= 0x1F887) ||\n (code >= 0x1F890 && code <= 0x1F8AD) ||\n (code >= 0x1F8B0 && code <= 0x1F8B1) ||\n (code >= 0x1F900 && code <= 0x1FA53) || // Supplemental symbols and pictographs\n (code >= 0x1FA60 && code <= 0x1FA6D) ||\n (code >= 0x1FA70 && code <= 0x1FA7C) ||\n (code >= 0x1FA80 && code <= 0x1FA88) ||\n (code >= 0x1FA90 && code <= 0x1FABD) ||\n (code >= 0x1FABF && code <= 0x1FAC5) ||\n (code >= 0x1FACE && code <= 0x1FADB) ||\n (code >= 0x1FAE0 && code <= 0x1FAE8) ||\n (code >= 0x1FAF0 && code <= 0x1FAF8) ||\n (code >= 0x20000 && code <= 0x2FFFD) || // CJK Extension B\n (code >= 0x30000 && code <= 0x3FFFD) // CJK Extension C\n );\n // cSpell: enable\n}\n"],"mappings":";;;;;;;;;;;AAaA,MAAM,eAAe;;;;;;;AAQrB,SAAgB,UAAUA,MAAsB;AAC9C,QAAO,KAAK,QAAQ,cAAc,GAAG;AACtC;;;;;;;;AASD,SAAgB,gBAAgBA,MAAsB;CAEpD,MAAM,YAAY,UAAU,KAAK;AAEjC,KAAI,UAAU,WAAW,EAAG,QAAO;CAEnC,IAAI,QAAQ;CACZ,IAAI,IAAI;AAGR,QAAO,IAAI,UAAU,QAAQ;EAC3B,MAAM,OAAO,UAAU,YAAY,EAAE;AACrC,MAAI,iBAAoB;AACtB;AACA;EACD;EAED,MAAM,YAAY,QAAQ,KAAK;AAC/B,MAAI,aAAa,EACf,UAAS;AAIX,OAAM,OAAO,QAAU,IAAI;CAC5B;AAED,QAAO;AACR;;;;;;;;;;;;AAaD,SAAgB,QAAQC,MAAsB;AAE5C,KAAI,OAAO,MAAO,QAAQ,OAAQ,OAAO,IACvC,QAAO;AAIT,KAAI,YAAY,KAAK,CACnB,QAAO;AAIT,KAAI,gBAAgB,KAAK,CACvB,QAAO;AAGT,QAAO;AACR;AAGD,MAAMC,oBAA6C;CACjD,CAAC,KAAQ,GAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,IAAO;CAChB,CAAC,MAAQ,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UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC5B,SAAS,UACT,SAAS,UACR,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ,UAC3B,QAAQ,UAAW,QAAQ;AAG/B"}
|
package/formatter.test.ts
CHANGED
|
@@ -509,13 +509,35 @@ test("Multiple styles combination", () => {
|
|
|
509
509
|
assertStringIncludes(result, "\x1b[9m"); // strikethrough
|
|
510
510
|
});
|
|
511
511
|
|
|
512
|
-
|
|
512
|
+
("Bun" in globalThis ? test.skip : test)(
|
|
513
|
+
"Word wrapping enabled by default",
|
|
514
|
+
() => {
|
|
515
|
+
const formatter = getPrettyFormatter({
|
|
516
|
+
colors: false,
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
const longMessage =
|
|
520
|
+
"This is a very long message that would normally exceed the typical console width and should be wrapped when word wrapping is enabled by default.";
|
|
521
|
+
const record = createLogRecord("info", ["test"], [longMessage]);
|
|
522
|
+
const result = formatter(record);
|
|
523
|
+
|
|
524
|
+
// Should contain multiple line breaks due to wrapping
|
|
525
|
+
const lines = result.split("\n");
|
|
526
|
+
assert(lines.length > 2); // More than just content + trailing newline due to wrapping
|
|
527
|
+
|
|
528
|
+
// First line should contain the beginning of the message
|
|
529
|
+
assert(lines[0].includes("This is a very long message"));
|
|
530
|
+
},
|
|
531
|
+
);
|
|
532
|
+
|
|
533
|
+
test("Word wrapping can be disabled", () => {
|
|
513
534
|
const formatter = getPrettyFormatter({
|
|
514
535
|
colors: false,
|
|
536
|
+
wordWrap: false,
|
|
515
537
|
});
|
|
516
538
|
|
|
517
539
|
const longMessage =
|
|
518
|
-
"This is a very long message that would normally exceed the typical console width
|
|
540
|
+
"This is a very long message that would normally exceed the typical console width but should not be wrapped when word wrapping is explicitly disabled.";
|
|
519
541
|
const record = createLogRecord("info", ["test"], [longMessage]);
|
|
520
542
|
const result = formatter(record);
|
|
521
543
|
|
package/formatter.ts
CHANGED
|
@@ -96,6 +96,10 @@ type CategoryPattern = {
|
|
|
96
96
|
*/
|
|
97
97
|
export type Style = keyof typeof styles | (keyof typeof styles)[] | null;
|
|
98
98
|
|
|
99
|
+
// Pre-compiled regex patterns for color parsing
|
|
100
|
+
const RGB_PATTERN = /^rgb\((\d+),(\d+),(\d+)\)$/;
|
|
101
|
+
const HEX_PATTERN = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
|
102
|
+
|
|
99
103
|
/**
|
|
100
104
|
* Helper function to convert color to ANSI escape code
|
|
101
105
|
*/
|
|
@@ -104,14 +108,16 @@ function colorToAnsi(color: Color): string {
|
|
|
104
108
|
if (color in ansiColors) {
|
|
105
109
|
return ansiColors[color as keyof typeof ansiColors];
|
|
106
110
|
}
|
|
111
|
+
|
|
107
112
|
// Handle rgb() format
|
|
108
|
-
const rgbMatch = color.match(
|
|
113
|
+
const rgbMatch = color.match(RGB_PATTERN);
|
|
109
114
|
if (rgbMatch) {
|
|
110
115
|
const [, r, g, b] = rgbMatch;
|
|
111
116
|
return `\x1b[38;2;${r};${g};${b}m`;
|
|
112
117
|
}
|
|
118
|
+
|
|
113
119
|
// Handle hex format (#rrggbb or #rgb)
|
|
114
|
-
const hexMatch = color.match(
|
|
120
|
+
const hexMatch = color.match(HEX_PATTERN);
|
|
115
121
|
if (hexMatch) {
|
|
116
122
|
let hex = hexMatch[1];
|
|
117
123
|
// Convert 3-digit hex to 6-digit
|
|
@@ -123,6 +129,7 @@ function colorToAnsi(color: Color): string {
|
|
|
123
129
|
const b = parseInt(hex.substr(4, 2), 16);
|
|
124
130
|
return `\x1b[38;2;${r};${g};${b}m`;
|
|
125
131
|
}
|
|
132
|
+
|
|
126
133
|
return "";
|
|
127
134
|
}
|
|
128
135
|
|
|
@@ -215,25 +222,17 @@ const defaultIcons: Record<LogLevel, string> = {
|
|
|
215
222
|
function normalizeIconSpacing(
|
|
216
223
|
iconMap: Record<LogLevel, string>,
|
|
217
224
|
): Record<LogLevel, string> {
|
|
218
|
-
|
|
225
|
+
const entries = Object.entries(iconMap) as Array<[LogLevel, string]>;
|
|
219
226
|
const maxWidth = Math.max(
|
|
220
|
-
...
|
|
227
|
+
...entries.map(([, icon]) => getDisplayWidth(icon)),
|
|
221
228
|
);
|
|
222
229
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const [level, icon] of Object.entries(iconMap) as Array<[LogLevel, string]>
|
|
230
|
-
) {
|
|
231
|
-
const currentWidth = getDisplayWidth(icon);
|
|
232
|
-
const spacesToAdd = maxWidth - currentWidth;
|
|
233
|
-
normalizedMap[level] = icon + " ".repeat(spacesToAdd);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
return normalizedMap;
|
|
230
|
+
return Object.fromEntries(
|
|
231
|
+
entries.map(([level, icon]) => [
|
|
232
|
+
level,
|
|
233
|
+
icon + " ".repeat(maxWidth - getDisplayWidth(icon)),
|
|
234
|
+
]),
|
|
235
|
+
) as Record<LogLevel, string>;
|
|
237
236
|
}
|
|
238
237
|
|
|
239
238
|
/**
|
|
@@ -287,7 +286,7 @@ export interface PrettyFormatterOptions
|
|
|
287
286
|
*
|
|
288
287
|
* @default `"rgb(100,116,139)"` (slate gray)
|
|
289
288
|
*/
|
|
290
|
-
timestampColor?: Color;
|
|
289
|
+
readonly timestampColor?: Color;
|
|
291
290
|
|
|
292
291
|
/**
|
|
293
292
|
* Visual style applied to timestamp text.
|
|
@@ -307,7 +306,7 @@ export interface PrettyFormatterOptions
|
|
|
307
306
|
*
|
|
308
307
|
* @default `"dim"`
|
|
309
308
|
*/
|
|
310
|
-
timestampStyle?: Style;
|
|
309
|
+
readonly timestampStyle?: Style;
|
|
311
310
|
|
|
312
311
|
/**
|
|
313
312
|
* Custom colors for each log level.
|
|
@@ -328,7 +327,7 @@ export interface PrettyFormatterOptions
|
|
|
328
327
|
*
|
|
329
328
|
* @default Built-in color scheme (purple trace, blue debug, green info, amber warning, red error, dark red fatal)
|
|
330
329
|
*/
|
|
331
|
-
levelColors?: Partial<Record<LogLevel, Color>>;
|
|
330
|
+
readonly levelColors?: Partial<Record<LogLevel, Color>>;
|
|
332
331
|
|
|
333
332
|
/**
|
|
334
333
|
* Visual style applied to log level text.
|
|
@@ -346,9 +345,9 @@ export interface PrettyFormatterOptions
|
|
|
346
345
|
* levelStyle: null // No additional styling
|
|
347
346
|
* ```
|
|
348
347
|
*
|
|
349
|
-
* @default `
|
|
348
|
+
* @default `"underline"`
|
|
350
349
|
*/
|
|
351
|
-
levelStyle?: Style;
|
|
350
|
+
readonly levelStyle?: Style;
|
|
352
351
|
|
|
353
352
|
/**
|
|
354
353
|
* Icon configuration for each log level.
|
|
@@ -373,7 +372,7 @@ export interface PrettyFormatterOptions
|
|
|
373
372
|
*
|
|
374
373
|
* @default `true` (use default emoji icons)
|
|
375
374
|
*/
|
|
376
|
-
icons?: boolean | Partial<Record<LogLevel, string>>;
|
|
375
|
+
readonly icons?: boolean | Partial<Record<LogLevel, string>>;
|
|
377
376
|
|
|
378
377
|
/**
|
|
379
378
|
* Character(s) used to separate category hierarchy levels.
|
|
@@ -392,7 +391,7 @@ export interface PrettyFormatterOptions
|
|
|
392
391
|
*
|
|
393
392
|
* @default `"·"` (interpunct)
|
|
394
393
|
*/
|
|
395
|
-
categorySeparator?: string;
|
|
394
|
+
readonly categorySeparator?: string;
|
|
396
395
|
|
|
397
396
|
/**
|
|
398
397
|
* Default color for category display.
|
|
@@ -410,7 +409,7 @@ export interface PrettyFormatterOptions
|
|
|
410
409
|
*
|
|
411
410
|
* @default `"rgb(100,116,139)"` (slate gray)
|
|
412
411
|
*/
|
|
413
|
-
categoryColor?: Color;
|
|
412
|
+
readonly categoryColor?: Color;
|
|
414
413
|
|
|
415
414
|
/**
|
|
416
415
|
* Category-specific color mapping based on prefixes.
|
|
@@ -429,7 +428,7 @@ export interface PrettyFormatterOptions
|
|
|
429
428
|
* ])
|
|
430
429
|
* ```
|
|
431
430
|
*/
|
|
432
|
-
categoryColorMap?: CategoryColorMap;
|
|
431
|
+
readonly categoryColorMap?: CategoryColorMap;
|
|
433
432
|
|
|
434
433
|
/**
|
|
435
434
|
* Visual style applied to category text.
|
|
@@ -449,7 +448,7 @@ export interface PrettyFormatterOptions
|
|
|
449
448
|
*
|
|
450
449
|
* @default `["dim", "italic"]` (dimmed for subtle appearance)
|
|
451
450
|
*/
|
|
452
|
-
categoryStyle?: Style;
|
|
451
|
+
readonly categoryStyle?: Style;
|
|
453
452
|
|
|
454
453
|
/**
|
|
455
454
|
* Maximum display width for category names.
|
|
@@ -457,19 +456,9 @@ export interface PrettyFormatterOptions
|
|
|
457
456
|
* Controls layout consistency by limiting category width.
|
|
458
457
|
* Long categories are truncated according to `categoryTruncate` strategy.
|
|
459
458
|
*
|
|
460
|
-
*
|
|
461
|
-
* - `"auto"`: No width limit, categories display at full length
|
|
462
|
-
*
|
|
463
|
-
* @example
|
|
464
|
-
* ```typescript
|
|
465
|
-
* categoryWidth: 20 // Limit to 20 characters
|
|
466
|
-
* categoryWidth: 30 // Limit to 30 characters
|
|
467
|
-
* categoryWidth: "auto" // No limit
|
|
468
|
-
* ```
|
|
469
|
-
*
|
|
470
|
-
* @default `20` (20 character limit)
|
|
459
|
+
* @default `20`
|
|
471
460
|
*/
|
|
472
|
-
categoryWidth?: number
|
|
461
|
+
readonly categoryWidth?: number;
|
|
473
462
|
|
|
474
463
|
/**
|
|
475
464
|
* Strategy for truncating long category names.
|
|
@@ -490,7 +479,7 @@ export interface PrettyFormatterOptions
|
|
|
490
479
|
*
|
|
491
480
|
* @default `"middle"` (smart context-preserving truncation)
|
|
492
481
|
*/
|
|
493
|
-
categoryTruncate?: TruncationStrategy;
|
|
482
|
+
readonly categoryTruncate?: TruncationStrategy;
|
|
494
483
|
|
|
495
484
|
/**
|
|
496
485
|
* Color for log message text content.
|
|
@@ -508,7 +497,7 @@ export interface PrettyFormatterOptions
|
|
|
508
497
|
*
|
|
509
498
|
* @default `"rgb(148,163,184)"` (light slate gray)
|
|
510
499
|
*/
|
|
511
|
-
messageColor?: Color;
|
|
500
|
+
readonly messageColor?: Color;
|
|
512
501
|
|
|
513
502
|
/**
|
|
514
503
|
* Visual style applied to log message text.
|
|
@@ -528,7 +517,7 @@ export interface PrettyFormatterOptions
|
|
|
528
517
|
*
|
|
529
518
|
* @default `"dim"` (dimmed for subtle readability)
|
|
530
519
|
*/
|
|
531
|
-
messageStyle?: Style;
|
|
520
|
+
readonly messageStyle?: Style;
|
|
532
521
|
|
|
533
522
|
/**
|
|
534
523
|
* Global color control for the entire formatter.
|
|
@@ -545,7 +534,7 @@ export interface PrettyFormatterOptions
|
|
|
545
534
|
*
|
|
546
535
|
* @default `true` (colors enabled)
|
|
547
536
|
*/
|
|
548
|
-
colors?: boolean;
|
|
537
|
+
readonly colors?: boolean;
|
|
549
538
|
|
|
550
539
|
/**
|
|
551
540
|
* Column alignment for consistent visual layout.
|
|
@@ -562,7 +551,7 @@ export interface PrettyFormatterOptions
|
|
|
562
551
|
*
|
|
563
552
|
* @default `true` (alignment enabled)
|
|
564
553
|
*/
|
|
565
|
-
align?: boolean;
|
|
554
|
+
readonly align?: boolean;
|
|
566
555
|
|
|
567
556
|
/**
|
|
568
557
|
* Configuration for structured value inspection and rendering.
|
|
@@ -581,22 +570,24 @@ export interface PrettyFormatterOptions
|
|
|
581
570
|
*
|
|
582
571
|
* @default `{}` (use built-in defaults: depth=unlimited, colors=auto, compact=true)
|
|
583
572
|
*/
|
|
584
|
-
inspectOptions?: {
|
|
573
|
+
readonly inspectOptions?: {
|
|
585
574
|
/**
|
|
586
575
|
* Maximum depth to traverse when inspecting nested objects.
|
|
587
576
|
* @default Infinity (no depth limit)
|
|
588
577
|
*/
|
|
589
|
-
depth?: number;
|
|
578
|
+
readonly depth?: number;
|
|
579
|
+
|
|
590
580
|
/**
|
|
591
581
|
* Whether to use syntax highlighting colors for inspected values.
|
|
592
582
|
* @default Inherited from global `colors` setting
|
|
593
583
|
*/
|
|
594
|
-
colors?: boolean;
|
|
584
|
+
readonly colors?: boolean;
|
|
585
|
+
|
|
595
586
|
/**
|
|
596
587
|
* Whether to use compact formatting for objects and arrays.
|
|
597
588
|
* @default `true` (compact formatting)
|
|
598
589
|
*/
|
|
599
|
-
compact?: boolean;
|
|
590
|
+
readonly compact?: boolean;
|
|
600
591
|
};
|
|
601
592
|
|
|
602
593
|
/**
|
|
@@ -622,10 +613,10 @@ export interface PrettyFormatterOptions
|
|
|
622
613
|
* wordWrap: false
|
|
623
614
|
* ```
|
|
624
615
|
*
|
|
625
|
-
* @default `
|
|
616
|
+
* @default `true` (auto-detect terminal width)
|
|
626
617
|
* @since 1.0.0
|
|
627
618
|
*/
|
|
628
|
-
wordWrap?: boolean | number;
|
|
619
|
+
readonly wordWrap?: boolean | number;
|
|
629
620
|
}
|
|
630
621
|
|
|
631
622
|
/**
|
|
@@ -650,7 +641,7 @@ export interface PrettyFormatterOptions
|
|
|
650
641
|
* @example
|
|
651
642
|
* ```typescript
|
|
652
643
|
* import { configure } from "@logtape/logtape";
|
|
653
|
-
* import { getConsoleSink } from "@logtape/logtape";
|
|
644
|
+
* import { getConsoleSink } from "@logtape/logtape/sink";
|
|
654
645
|
* import { getPrettyFormatter } from "@logtape/pretty";
|
|
655
646
|
*
|
|
656
647
|
* await configure({
|
|
@@ -694,7 +685,7 @@ export function getPrettyFormatter(
|
|
|
694
685
|
colors: useColors = true,
|
|
695
686
|
align = true,
|
|
696
687
|
inspectOptions = {},
|
|
697
|
-
wordWrap =
|
|
688
|
+
wordWrap = true,
|
|
698
689
|
} = options;
|
|
699
690
|
|
|
700
691
|
// Resolve icons
|
|
@@ -718,103 +709,91 @@ export function getPrettyFormatter(
|
|
|
718
709
|
...levelColors,
|
|
719
710
|
};
|
|
720
711
|
|
|
721
|
-
// Level formatter function
|
|
712
|
+
// Level formatter function with optimized mappings
|
|
713
|
+
const levelMappings: Record<string, Record<LogLevel, string>> = {
|
|
714
|
+
"ABBR": {
|
|
715
|
+
trace: "TRC",
|
|
716
|
+
debug: "DBG",
|
|
717
|
+
info: "INF",
|
|
718
|
+
warning: "WRN",
|
|
719
|
+
error: "ERR",
|
|
720
|
+
fatal: "FTL",
|
|
721
|
+
},
|
|
722
|
+
"L": {
|
|
723
|
+
trace: "T",
|
|
724
|
+
debug: "D",
|
|
725
|
+
info: "I",
|
|
726
|
+
warning: "W",
|
|
727
|
+
error: "E",
|
|
728
|
+
fatal: "F",
|
|
729
|
+
},
|
|
730
|
+
"abbr": {
|
|
731
|
+
trace: "trc",
|
|
732
|
+
debug: "dbg",
|
|
733
|
+
info: "inf",
|
|
734
|
+
warning: "wrn",
|
|
735
|
+
error: "err",
|
|
736
|
+
fatal: "ftl",
|
|
737
|
+
},
|
|
738
|
+
"l": {
|
|
739
|
+
trace: "t",
|
|
740
|
+
debug: "d",
|
|
741
|
+
info: "i",
|
|
742
|
+
warning: "w",
|
|
743
|
+
error: "e",
|
|
744
|
+
fatal: "f",
|
|
745
|
+
},
|
|
746
|
+
};
|
|
747
|
+
|
|
722
748
|
const formatLevel = (level: LogLevel): string => {
|
|
723
749
|
if (typeof levelFormat === "function") {
|
|
724
750
|
return levelFormat(level);
|
|
725
751
|
}
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
info: "INF",
|
|
732
|
-
warning: "WRN",
|
|
733
|
-
error: "ERR",
|
|
734
|
-
fatal: "FTL",
|
|
735
|
-
}[level];
|
|
736
|
-
case "FULL":
|
|
737
|
-
return level.toUpperCase();
|
|
738
|
-
case "L":
|
|
739
|
-
return {
|
|
740
|
-
trace: "T",
|
|
741
|
-
debug: "D",
|
|
742
|
-
info: "I",
|
|
743
|
-
warning: "W",
|
|
744
|
-
error: "E",
|
|
745
|
-
fatal: "F",
|
|
746
|
-
}[level];
|
|
747
|
-
case "abbr":
|
|
748
|
-
return {
|
|
749
|
-
trace: "trc",
|
|
750
|
-
debug: "dbg",
|
|
751
|
-
info: "inf",
|
|
752
|
-
warning: "wrn",
|
|
753
|
-
error: "err",
|
|
754
|
-
fatal: "ftl",
|
|
755
|
-
}[level];
|
|
756
|
-
case "full":
|
|
757
|
-
return level;
|
|
758
|
-
case "l":
|
|
759
|
-
return {
|
|
760
|
-
trace: "t",
|
|
761
|
-
debug: "d",
|
|
762
|
-
info: "i",
|
|
763
|
-
warning: "w",
|
|
764
|
-
error: "e",
|
|
765
|
-
fatal: "f",
|
|
766
|
-
}[level];
|
|
767
|
-
default:
|
|
768
|
-
return level;
|
|
769
|
-
}
|
|
752
|
+
|
|
753
|
+
if (levelFormat === "FULL") return level.toUpperCase();
|
|
754
|
+
if (levelFormat === "full") return level;
|
|
755
|
+
|
|
756
|
+
return levelMappings[levelFormat]?.[level] ?? level;
|
|
770
757
|
};
|
|
771
758
|
|
|
772
|
-
//
|
|
759
|
+
// Timestamp formatters lookup table
|
|
760
|
+
const timestampFormatters: Record<string, (ts: number) => string> = {
|
|
761
|
+
"date-time-timezone": (ts) => {
|
|
762
|
+
const iso = new Date(ts).toISOString();
|
|
763
|
+
return iso.replace("T", " ").replace("Z", " +00:00");
|
|
764
|
+
},
|
|
765
|
+
"date-time-tz": (ts) => {
|
|
766
|
+
const iso = new Date(ts).toISOString();
|
|
767
|
+
return iso.replace("T", " ").replace("Z", " +00");
|
|
768
|
+
},
|
|
769
|
+
"date-time": (ts) => {
|
|
770
|
+
const iso = new Date(ts).toISOString();
|
|
771
|
+
return iso.replace("T", " ").replace("Z", "");
|
|
772
|
+
},
|
|
773
|
+
"time-timezone": (ts) => {
|
|
774
|
+
const iso = new Date(ts).toISOString();
|
|
775
|
+
return iso.replace(/.*T/, "").replace("Z", " +00:00");
|
|
776
|
+
},
|
|
777
|
+
"time-tz": (ts) => {
|
|
778
|
+
const iso = new Date(ts).toISOString();
|
|
779
|
+
return iso.replace(/.*T/, "").replace("Z", " +00");
|
|
780
|
+
},
|
|
781
|
+
"time": (ts) => {
|
|
782
|
+
const iso = new Date(ts).toISOString();
|
|
783
|
+
return iso.replace(/.*T/, "").replace("Z", "");
|
|
784
|
+
},
|
|
785
|
+
"date": (ts) => new Date(ts).toISOString().replace(/T.*/, ""),
|
|
786
|
+
"rfc3339": (ts) => new Date(ts).toISOString(),
|
|
787
|
+
};
|
|
788
|
+
|
|
789
|
+
// Resolve timestamp formatter
|
|
773
790
|
let timestampFn: ((ts: number) => string | null) | null = null;
|
|
774
791
|
if (timestamp === "none" || timestamp === "disabled") {
|
|
775
792
|
timestampFn = null;
|
|
776
|
-
} else if (timestamp === "date-time-timezone") {
|
|
777
|
-
timestampFn = (ts: number) => {
|
|
778
|
-
const date = new Date(ts);
|
|
779
|
-
return date.toISOString().replace("T", " ").replace("Z", " +00:00");
|
|
780
|
-
};
|
|
781
|
-
} else if (timestamp === "date-time-tz") {
|
|
782
|
-
timestampFn = (ts: number) => {
|
|
783
|
-
const date = new Date(ts);
|
|
784
|
-
return date.toISOString().replace("T", " ").replace("Z", " +00");
|
|
785
|
-
};
|
|
786
|
-
} else if (timestamp === "date-time") {
|
|
787
|
-
timestampFn = (ts: number) => {
|
|
788
|
-
const date = new Date(ts);
|
|
789
|
-
return date.toISOString().replace("T", " ").replace("Z", "");
|
|
790
|
-
};
|
|
791
|
-
} else if (timestamp === "time-timezone") {
|
|
792
|
-
timestampFn = (ts: number) => {
|
|
793
|
-
const date = new Date(ts);
|
|
794
|
-
return date.toISOString().replace(/.*T/, "").replace("Z", " +00:00");
|
|
795
|
-
};
|
|
796
|
-
} else if (timestamp === "time-tz") {
|
|
797
|
-
timestampFn = (ts: number) => {
|
|
798
|
-
const date = new Date(ts);
|
|
799
|
-
return date.toISOString().replace(/.*T/, "").replace("Z", " +00");
|
|
800
|
-
};
|
|
801
|
-
} else if (timestamp === "time") {
|
|
802
|
-
timestampFn = (ts: number) => {
|
|
803
|
-
const date = new Date(ts);
|
|
804
|
-
return date.toISOString().replace(/.*T/, "").replace("Z", "");
|
|
805
|
-
};
|
|
806
|
-
} else if (timestamp === "date") {
|
|
807
|
-
timestampFn = (ts: number) => {
|
|
808
|
-
const date = new Date(ts);
|
|
809
|
-
return date.toISOString().replace(/T.*/, "");
|
|
810
|
-
};
|
|
811
|
-
} else if (timestamp === "rfc3339") {
|
|
812
|
-
timestampFn = (ts: number) => {
|
|
813
|
-
const date = new Date(ts);
|
|
814
|
-
return date.toISOString();
|
|
815
|
-
};
|
|
816
793
|
} else if (typeof timestamp === "function") {
|
|
817
794
|
timestampFn = timestamp;
|
|
795
|
+
} else {
|
|
796
|
+
timestampFn = timestampFormatters[timestamp as string] ?? null;
|
|
818
797
|
}
|
|
819
798
|
|
|
820
799
|
// Configure word wrap settings
|
|
@@ -850,7 +829,7 @@ export function getPrettyFormatter(
|
|
|
850
829
|
const level = formatLevel(record.level);
|
|
851
830
|
const categoryStr = truncateCategory(
|
|
852
831
|
record.category,
|
|
853
|
-
|
|
832
|
+
categoryWidth,
|
|
854
833
|
categorySeparator,
|
|
855
834
|
categoryTruncate,
|
|
856
835
|
);
|
|
@@ -965,8 +944,7 @@ export function getPrettyFormatter(
|
|
|
965
944
|
|
|
966
945
|
const paddedLevel = formattedLevel.padEnd(levelWidth + levelColorLength);
|
|
967
946
|
const paddedCategory = formattedCategory.padEnd(
|
|
968
|
-
|
|
969
|
-
categoryColorLength,
|
|
947
|
+
categoryWidth + categoryColorLength,
|
|
970
948
|
);
|
|
971
949
|
|
|
972
950
|
let result =
|
|
@@ -1020,7 +998,7 @@ export function getPrettyFormatter(
|
|
|
1020
998
|
* @example
|
|
1021
999
|
* ```typescript
|
|
1022
1000
|
* import { configure } from "@logtape/logtape";
|
|
1023
|
-
* import { getConsoleSink } from "@logtape/logtape";
|
|
1001
|
+
* import { getConsoleSink } from "@logtape/logtape/sink";
|
|
1024
1002
|
* import { prettyFormatter } from "@logtape/pretty";
|
|
1025
1003
|
*
|
|
1026
1004
|
* await configure({
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logtape/pretty",
|
|
3
|
-
"version": "1.0.0-dev.
|
|
4
|
-
"description": "Beautiful
|
|
3
|
+
"version": "1.0.0-dev.234+3fd3473b",
|
|
4
|
+
"description": "Beautiful text formatter for LogTape—perfect for local development",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"logging",
|
|
7
7
|
"log",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"./package.json": "./package.json"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@logtape/logtape": "1.0.0-dev.
|
|
50
|
+
"@logtape/logtape": "1.0.0-dev.234+3fd3473b"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@alinea/suite": "^0.6.3",
|