@logtape/pretty 1.1.0-dev.315 → 1.1.0-dev.323

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.
Files changed (61) hide show
  1. package/deno.json +3 -3
  2. package/dist/formatter.cjs +1 -1
  3. package/dist/formatter.d.cts +1 -1
  4. package/dist/formatter.d.cts.map +1 -1
  5. package/dist/formatter.d.ts +1 -1
  6. package/dist/formatter.d.ts.map +1 -1
  7. package/dist/formatter.js +1 -1
  8. package/dist/formatter.js.map +1 -1
  9. package/dist/terminal.cjs +1 -1
  10. package/dist/terminal.js +1 -1
  11. package/dist/terminal.js.map +1 -1
  12. package/dist/truncate.cjs +1 -1
  13. package/dist/truncate.d.cts +1 -1
  14. package/dist/truncate.d.cts.map +1 -1
  15. package/dist/truncate.d.ts +1 -1
  16. package/dist/truncate.d.ts.map +1 -1
  17. package/dist/truncate.js +1 -1
  18. package/dist/truncate.js.map +1 -1
  19. package/dist/util.cjs +1 -1
  20. package/dist/util.d.cts +1 -1
  21. package/dist/util.d.cts.map +1 -1
  22. package/dist/util.d.ts +1 -1
  23. package/dist/util.d.ts.map +1 -1
  24. package/dist/util.deno.cjs +1 -1
  25. package/dist/util.deno.d.cts +1 -1
  26. package/dist/util.deno.d.cts.map +1 -1
  27. package/dist/util.deno.d.ts +1 -1
  28. package/dist/util.deno.d.ts.map +1 -1
  29. package/dist/util.deno.js +1 -1
  30. package/dist/util.deno.js.map +1 -1
  31. package/dist/util.js +1 -1
  32. package/dist/util.js.map +1 -1
  33. package/dist/util.node.cjs +1 -1
  34. package/dist/util.node.d.cts +1 -1
  35. package/dist/util.node.d.cts.map +1 -1
  36. package/dist/util.node.d.ts +1 -1
  37. package/dist/util.node.d.ts.map +1 -1
  38. package/dist/util.node.js +1 -1
  39. package/dist/util.node.js.map +1 -1
  40. package/dist/wcwidth.cjs +1 -1
  41. package/dist/wcwidth.js +1 -1
  42. package/dist/wcwidth.js.map +1 -1
  43. package/dist/wordwrap.cjs +1 -1
  44. package/dist/wordwrap.js +1 -1
  45. package/dist/wordwrap.js.map +1 -1
  46. package/package.json +3 -3
  47. package/tsdown.config.ts +1 -1
  48. /package/{formatter.test.ts → src/formatter.test.ts} +0 -0
  49. /package/{formatter.ts → src/formatter.ts} +0 -0
  50. /package/{mod.ts → src/mod.ts} +0 -0
  51. /package/{terminal.test.ts → src/terminal.test.ts} +0 -0
  52. /package/{terminal.ts → src/terminal.ts} +0 -0
  53. /package/{truncate.test.ts → src/truncate.test.ts} +0 -0
  54. /package/{truncate.ts → src/truncate.ts} +0 -0
  55. /package/{util.deno.ts → src/util.deno.ts} +0 -0
  56. /package/{util.node.ts → src/util.node.ts} +0 -0
  57. /package/{util.ts → src/util.ts} +0 -0
  58. /package/{wcwidth.test.ts → src/wcwidth.test.ts} +0 -0
  59. /package/{wcwidth.ts → src/wcwidth.ts} +0 -0
  60. /package/{wordwrap.test.ts → src/wordwrap.test.ts} +0 -0
  61. /package/{wordwrap.ts → src/wordwrap.ts} +0 -0
package/deno.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@logtape/pretty",
3
- "version": "1.1.0-dev.315+fc46f65c",
3
+ "version": "1.1.0-dev.323+146f8194",
4
4
  "license": "MIT",
5
- "exports": "./mod.ts",
5
+ "exports": "./src/mod.ts",
6
6
  "imports": {
7
- "#util": "util.deno.ts",
7
+ "#util": "src/util.deno.ts",
8
8
  "@types/node": "npm:@types/node@24.0.7"
9
9
  },
10
10
  "exclude": [
@@ -6,7 +6,7 @@ const require_wordwrap = require('./wordwrap.cjs');
6
6
  const __logtape_logtape = require_rolldown_runtime.__toESM(require("@logtape/logtape"));
7
7
  const __util = require_rolldown_runtime.__toESM(require("#util"));
8
8
 
9
- //#region formatter.ts
9
+ //#region src/formatter.ts
10
10
  /**
11
11
  * ANSI escape codes for styling
12
12
  */
@@ -1,7 +1,7 @@
1
1
  import { TruncationStrategy } from "./truncate.cjs";
2
2
  import { LogLevel, TextFormatter, TextFormatterOptions } from "@logtape/logtape";
3
3
 
4
- //#region formatter.d.ts
4
+ //#region src/formatter.d.ts
5
5
 
6
6
  /**
7
7
  * ANSI style codes
@@ -1 +1 @@
1
- {"version":3,"file":"formatter.d.cts","names":[],"sources":["../formatter.ts"],"sourcesContent":[],"mappings":";;;;;;;AAS0E;AAiChE,cAPJ,MAqBI,EAAA;EAKE,SAAK,KAAA,EAAA,WACA;EAsBL,SAAA,IAAA,EAAA,WAAgB;EAAA,SAAA,GAAA,EAAA,WAAA;EAAA,SAA0B,MAAA,EAAA,WAAA;EAAK,SAA5B,SAAA,EAAA,WAAA;EAAG,SAAA,aAAA,EAAA,WAAA;AAalC,CAAA;;;;AAA8D,cAlDxD,UAkDwD,EAAA;EAuJ7C,SAAA,KAAA,EAAA,YACf;EAAA,SAAA,GAAA,EAAA,YAAA;EAAA,SAAa,KAAA,EAAA,YAAA;EAAoB,SAiBP,MAAA,EAAA,YAAA;EAAK,SAoBL,IAAA,EAAA,YAAA;EAAK,SAqBO,OAAA,EAAA,YAAA;EAAQ,SAAE,IAAA,EAAA,YAAA;EAAK,SAAtB,KAAA,EAAA,YAAA;CAAM;;;;AA6CV,KAnSjB,KAAA,GAmSiB,MAAA,OAlSZ,UAkSY,GAAA,OAAA,MAAA,IAAA,MAAA,IAAA,MAAA,GAAA,GAAA,IAAA,MAAA,EAAA,GAAA,IAAA;;;;;;;;AAvGf;AAqZd;;;;AAEgB;AA0YhB;;;;KAt8BY,gBAAA,GAAmB,uBAAuB;;;;KAa1C,KAAA,gBAAqB,uBAAuB;;;;;;;;;;;UAuJvC,sBAAA,SACP,KAAK;;;;;;;;;;;;;;;;;4BAiBa;;;;;;;;;;;;;;;;;;;4BAoBA;;;;;;;;;;;;;;;;;;;;yBAqBH,QAAQ,OAAO,UAAU;;;;;;;;;;;;;;;;;;;wBAoB1B;;;;;;;;;;;;;;;;;;;;;;;;6BAyBK,QAAQ,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAqCjB;;;;;;;;;;;;;;;;;;8BAmBG;;;;;;;;;;;;;;;;;;;2BAoBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BA+BG;;;;;;;;;;;;;;;;;0BAkBJ;;;;;;;;;;;;;;;;;;;0BAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6JV,kBAAA,WACL,yBACR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA0YU,iBAAiB"}
1
+ {"version":3,"file":"formatter.d.cts","names":[],"sources":["../src/formatter.ts"],"sourcesContent":[],"mappings":";;;;;;;AAS0E;AAiChE,cAPJ,MAqBI,EAAA;EAKE,SAAK,KAAA,EAAA,WACA;EAsBL,SAAA,IAAA,EAAA,WAAgB;EAAA,SAAA,GAAA,EAAA,WAAA;EAAA,SAA0B,MAAA,EAAA,WAAA;EAAK,SAA5B,SAAA,EAAA,WAAA;EAAG,SAAA,aAAA,EAAA,WAAA;AAalC,CAAA;;;;AAA8D,cAlDxD,UAkDwD,EAAA;EAuJ7C,SAAA,KAAA,EAAA,YACf;EAAA,SAAA,GAAA,EAAA,YAAA;EAAA,SAAa,KAAA,EAAA,YAAA;EAAoB,SAiBP,MAAA,EAAA,YAAA;EAAK,SAoBL,IAAA,EAAA,YAAA;EAAK,SAqBO,OAAA,EAAA,YAAA;EAAQ,SAAE,IAAA,EAAA,YAAA;EAAK,SAAtB,KAAA,EAAA,YAAA;CAAM;;;;AA6CV,KAnSjB,KAAA,GAmSiB,MAAA,OAlSZ,UAkSY,GAAA,OAAA,MAAA,IAAA,MAAA,IAAA,MAAA,GAAA,GAAA,IAAA,MAAA,EAAA,GAAA,IAAA;;;;;;;;AAvGf;AAqZd;;;;AAEgB;AA0YhB;;;;KAt8BY,gBAAA,GAAmB,uBAAuB;;;;KAa1C,KAAA,gBAAqB,uBAAuB;;;;;;;;;;;UAuJvC,sBAAA,SACP,KAAK;;;;;;;;;;;;;;;;;4BAiBa;;;;;;;;;;;;;;;;;;;4BAoBA;;;;;;;;;;;;;;;;;;;;yBAqBH,QAAQ,OAAO,UAAU;;;;;;;;;;;;;;;;;;;wBAoB1B;;;;;;;;;;;;;;;;;;;;;;;;6BAyBK,QAAQ,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAqCjB;;;;;;;;;;;;;;;;;;8BAmBG;;;;;;;;;;;;;;;;;;;2BAoBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BA+BG;;;;;;;;;;;;;;;;;0BAkBJ;;;;;;;;;;;;;;;;;;;0BAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6JV,kBAAA,WACL,yBACR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA0YU,iBAAiB"}
@@ -1,7 +1,7 @@
1
1
  import { TruncationStrategy } from "./truncate.js";
2
2
  import { LogLevel, TextFormatter, TextFormatterOptions } from "@logtape/logtape";
3
3
 
4
- //#region formatter.d.ts
4
+ //#region src/formatter.d.ts
5
5
 
6
6
  /**
7
7
  * ANSI style codes
@@ -1 +1 @@
1
- {"version":3,"file":"formatter.d.ts","names":[],"sources":["../formatter.ts"],"sourcesContent":[],"mappings":";;;;;;;AAS0E;AAiChE,cAPJ,MAqBI,EAAA;EAKE,SAAK,KAAA,EAAA,WACA;EAsBL,SAAA,IAAA,EAAA,WAAgB;EAAA,SAAA,GAAA,EAAA,WAAA;EAAA,SAA0B,MAAA,EAAA,WAAA;EAAK,SAA5B,SAAA,EAAA,WAAA;EAAG,SAAA,aAAA,EAAA,WAAA;AAalC,CAAA;;;;AAA8D,cAlDxD,UAkDwD,EAAA;EAuJ7C,SAAA,KAAA,EAAA,YACf;EAAA,SAAA,GAAA,EAAA,YAAA;EAAA,SAAa,KAAA,EAAA,YAAA;EAAoB,SAiBP,MAAA,EAAA,YAAA;EAAK,SAoBL,IAAA,EAAA,YAAA;EAAK,SAqBO,OAAA,EAAA,YAAA;EAAQ,SAAE,IAAA,EAAA,YAAA;EAAK,SAAtB,KAAA,EAAA,YAAA;CAAM;;;;AA6CV,KAnSjB,KAAA,GAmSiB,MAAA,OAlSZ,UAkSY,GAAA,OAAA,MAAA,IAAA,MAAA,IAAA,MAAA,GAAA,GAAA,IAAA,MAAA,EAAA,GAAA,IAAA;;;;;;;;AAvGf;AAqZd;;;;AAEgB;AA0YhB;;;;KAt8BY,gBAAA,GAAmB,uBAAuB;;;;KAa1C,KAAA,gBAAqB,uBAAuB;;;;;;;;;;;UAuJvC,sBAAA,SACP,KAAK;;;;;;;;;;;;;;;;;4BAiBa;;;;;;;;;;;;;;;;;;;4BAoBA;;;;;;;;;;;;;;;;;;;;yBAqBH,QAAQ,OAAO,UAAU;;;;;;;;;;;;;;;;;;;wBAoB1B;;;;;;;;;;;;;;;;;;;;;;;;6BAyBK,QAAQ,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAqCjB;;;;;;;;;;;;;;;;;;8BAmBG;;;;;;;;;;;;;;;;;;;2BAoBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BA+BG;;;;;;;;;;;;;;;;;0BAkBJ;;;;;;;;;;;;;;;;;;;0BAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6JV,kBAAA,WACL,yBACR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA0YU,iBAAiB"}
1
+ {"version":3,"file":"formatter.d.ts","names":[],"sources":["../src/formatter.ts"],"sourcesContent":[],"mappings":";;;;;;;AAS0E;AAiChE,cAPJ,MAqBI,EAAA;EAKE,SAAK,KAAA,EAAA,WACA;EAsBL,SAAA,IAAA,EAAA,WAAgB;EAAA,SAAA,GAAA,EAAA,WAAA;EAAA,SAA0B,MAAA,EAAA,WAAA;EAAK,SAA5B,SAAA,EAAA,WAAA;EAAG,SAAA,aAAA,EAAA,WAAA;AAalC,CAAA;;;;AAA8D,cAlDxD,UAkDwD,EAAA;EAuJ7C,SAAA,KAAA,EAAA,YACf;EAAA,SAAA,GAAA,EAAA,YAAA;EAAA,SAAa,KAAA,EAAA,YAAA;EAAoB,SAiBP,MAAA,EAAA,YAAA;EAAK,SAoBL,IAAA,EAAA,YAAA;EAAK,SAqBO,OAAA,EAAA,YAAA;EAAQ,SAAE,IAAA,EAAA,YAAA;EAAK,SAAtB,KAAA,EAAA,YAAA;CAAM;;;;AA6CV,KAnSjB,KAAA,GAmSiB,MAAA,OAlSZ,UAkSY,GAAA,OAAA,MAAA,IAAA,MAAA,IAAA,MAAA,GAAA,GAAA,IAAA,MAAA,EAAA,GAAA,IAAA;;;;;;;;AAvGf;AAqZd;;;;AAEgB;AA0YhB;;;;KAt8BY,gBAAA,GAAmB,uBAAuB;;;;KAa1C,KAAA,gBAAqB,uBAAuB;;;;;;;;;;;UAuJvC,sBAAA,SACP,KAAK;;;;;;;;;;;;;;;;;4BAiBa;;;;;;;;;;;;;;;;;;;4BAoBA;;;;;;;;;;;;;;;;;;;;yBAqBH,QAAQ,OAAO,UAAU;;;;;;;;;;;;;;;;;;;wBAoB1B;;;;;;;;;;;;;;;;;;;;;;;;6BAyBK,QAAQ,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAqCjB;;;;;;;;;;;;;;;;;;8BAmBG;;;;;;;;;;;;;;;;;;;2BAoBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BA+BG;;;;;;;;;;;;;;;;;0BAkBJ;;;;;;;;;;;;;;;;;;;0BAoBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6JV,kBAAA,WACL,yBACR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA0YU,iBAAiB"}
package/dist/formatter.js CHANGED
@@ -5,7 +5,7 @@ import { wrapText } from "./wordwrap.js";
5
5
  import { getLogLevels } from "@logtape/logtape";
6
6
  import { inspect } from "#util";
7
7
 
8
- //#region formatter.ts
8
+ //#region src/formatter.ts
9
9
  /**
10
10
  * ANSI escape codes for styling
11
11
  */
@@ -1 +1 @@
1
- {"version":3,"file":"formatter.js","names":["color: Color","style: Style","categoryColorMap: CategoryColorMap","patterns: CategoryPattern[]","category: readonly string[]","prefix: readonly string[]","defaultIcons: Record<LogLevel, string>","iconMap: Record<LogLevel, string>","options: PrettyFormatterOptions","baseIconMap: Record<LogLevel, string>","resolvedLevelColors: Record<LogLevel, Color>","levelMappings: Record<string, Record<LogLevel, string>>","level: LogLevel","timestampFormatters: Record<string, (ts: number) => string>","timestampFn: ((ts: number) => string | null) | null","wordWrapWidth: number","allLevels: LogLevel[]","record: LogRecord","indentWidth: number","maxWidth: number","useColors: boolean","inspectOptions: InspectOptions","prettyFormatter: TextFormatter"],"sources":["../formatter.ts"],"sourcesContent":["import {\n getLogLevels,\n type LogLevel,\n type LogRecord,\n type TextFormatter,\n type TextFormatterOptions,\n} from \"@logtape/logtape\";\nimport { inspect, type InspectOptions } from \"#util\";\nimport { getOptimalWordWrapWidth } from \"./terminal.ts\";\nimport { truncateCategory, type TruncationStrategy } from \"./truncate.ts\";\nimport { getDisplayWidth, stripAnsi } from \"./wcwidth.ts\";\nimport { wrapText } from \"./wordwrap.ts\";\n\n/**\n * ANSI escape codes for styling\n */\nconst RESET = \"\\x1b[0m\";\nconst DIM = \"\\x1b[2m\";\n\n// Default true color values (referenced in JSDoc)\nconst defaultColors = {\n trace: \"rgb(167,139,250)\", // Light purple\n debug: \"rgb(96,165,250)\", // Light blue\n info: \"rgb(52,211,153)\", // Emerald\n warning: \"rgb(251,191,36)\", // Amber\n error: \"rgb(248,113,113)\", // Light red\n fatal: \"rgb(220,38,38)\", // Dark red\n category: \"rgb(100,116,139)\", // Slate\n message: \"rgb(148,163,184)\", // Light slate\n timestamp: \"rgb(100,116,139)\", // Slate\n} as const;\n\n/**\n * ANSI style codes\n */\nconst styles = {\n reset: RESET,\n bold: \"\\x1b[1m\",\n dim: DIM,\n italic: \"\\x1b[3m\",\n underline: \"\\x1b[4m\",\n strikethrough: \"\\x1b[9m\",\n} as const;\n\n/**\n * Standard ANSI colors (16-color)\n */\nconst ansiColors = {\n black: \"\\x1b[30m\",\n red: \"\\x1b[31m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n blue: \"\\x1b[34m\",\n magenta: \"\\x1b[35m\",\n cyan: \"\\x1b[36m\",\n white: \"\\x1b[37m\",\n} as const;\n\n/**\n * Color type definition\n */\nexport type Color =\n | keyof typeof ansiColors\n | `rgb(${number},${number},${number})`\n | `#${string}`\n | null;\n\n/**\n * Category color mapping for prefix-based coloring.\n *\n * Maps category prefixes (as arrays) to colors. The formatter will match\n * categories against these prefixes and use the corresponding color.\n * Longer/more specific prefixes take precedence over shorter ones.\n *\n * @example\n * ```typescript\n * new Map([\n * [[\"app\", \"auth\"], \"#ff6b6b\"], // app.auth.* -> red\n * [[\"app\", \"db\"], \"#4ecdc4\"], // app.db.* -> teal\n * [[\"app\"], \"#45b7d1\"], // app.* (fallback) -> blue\n * [[\"lib\"], \"#96ceb4\"], // lib.* -> green\n * ])\n * ```\n */\nexport type CategoryColorMap = Map<readonly string[], Color>;\n\n/**\n * Internal representation of category prefix patterns\n */\ntype CategoryPattern = {\n prefix: readonly string[];\n color: Color;\n};\n\n/**\n * Style type definition - supports single styles, arrays of styles, or null\n */\nexport type Style = keyof typeof styles | (keyof typeof styles)[] | null;\n\n// Pre-compiled regex patterns for color parsing\nconst RGB_PATTERN = /^rgb\\((\\d+),(\\d+),(\\d+)\\)$/;\nconst HEX_PATTERN = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;\n\n/**\n * Helper function to convert color to ANSI escape code\n */\nfunction colorToAnsi(color: Color): string {\n if (color === null) return \"\";\n if (color in ansiColors) {\n return ansiColors[color as keyof typeof ansiColors];\n }\n\n // Handle rgb() format\n const rgbMatch = color.match(RGB_PATTERN);\n if (rgbMatch) {\n const [, r, g, b] = rgbMatch;\n return `\\x1b[38;2;${r};${g};${b}m`;\n }\n\n // Handle hex format (#rrggbb or #rgb)\n const hexMatch = color.match(HEX_PATTERN);\n if (hexMatch) {\n let hex = hexMatch[1];\n // Convert 3-digit hex to 6-digit\n if (hex.length === 3) {\n hex = hex.split(\"\").map((c) => c + c).join(\"\");\n }\n const r = parseInt(hex.substr(0, 2), 16);\n const g = parseInt(hex.substr(2, 2), 16);\n const b = parseInt(hex.substr(4, 2), 16);\n return `\\x1b[38;2;${r};${g};${b}m`;\n }\n\n return \"\";\n}\n\n/**\n * Helper function to convert style to ANSI escape code\n */\nfunction styleToAnsi(style: Style): string {\n if (style === null) return \"\";\n if (Array.isArray(style)) {\n return style.map((s) => styles[s] || \"\").join(\"\");\n }\n return styles[style] || \"\";\n}\n\n/**\n * Converts a category color map to internal patterns and sorts them by specificity.\n * More specific (longer) prefixes come first for proper matching precedence.\n */\nfunction prepareCategoryPatterns(\n categoryColorMap: CategoryColorMap,\n): CategoryPattern[] {\n const patterns: CategoryPattern[] = [];\n\n for (const [prefix, color] of categoryColorMap) {\n patterns.push({ prefix, color });\n }\n\n // Sort by prefix length (descending) for most-specific-first matching\n return patterns.sort((a, b) => b.prefix.length - a.prefix.length);\n}\n\n/**\n * Matches a category against category color patterns.\n * Returns the color of the first matching pattern, or null if no match.\n */\nfunction matchCategoryColor(\n category: readonly string[],\n patterns: CategoryPattern[],\n): Color {\n for (const pattern of patterns) {\n if (categoryMatches(category, pattern.prefix)) {\n return pattern.color;\n }\n }\n return null;\n}\n\n/**\n * Checks if a category matches a prefix pattern.\n * A category matches if it starts with all segments of the prefix.\n */\nfunction categoryMatches(\n category: readonly string[],\n prefix: readonly string[],\n): boolean {\n if (prefix.length > category.length) {\n return false;\n }\n\n for (let i = 0; i < prefix.length; i++) {\n if (category[i] !== prefix[i]) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Default icons for each log level\n */\nconst defaultIcons: Record<LogLevel, string> = {\n trace: \"🔍\",\n debug: \"🐛\",\n info: \"✨\",\n warning: \"⚡\",\n error: \"❌\",\n fatal: \"💀\",\n};\n\n/**\n * Normalize icon spacing to ensure consistent column alignment.\n *\n * All icons will be padded with spaces to match the width of the widest icon,\n * ensuring consistent prefix alignment across all log levels.\n *\n * @param iconMap The icon mapping to normalize\n * @returns A new icon map with consistent spacing\n */\nfunction normalizeIconSpacing(\n iconMap: Record<LogLevel, string>,\n): Record<LogLevel, string> {\n const entries = Object.entries(iconMap) as Array<[LogLevel, string]>;\n const maxWidth = Math.max(\n ...entries.map(([, icon]) => getDisplayWidth(icon)),\n );\n\n return Object.fromEntries(\n entries.map(([level, icon]) => [\n level,\n icon + \" \".repeat(maxWidth - getDisplayWidth(icon)),\n ]),\n ) as Record<LogLevel, string>;\n}\n\n/**\n * Configuration options for the pretty formatter.\n *\n * This interface extends the base text formatter options while providing\n * extensive customization options for visual styling, layout control, and\n * development-focused features. It offers granular control over colors,\n * styles, and formatting similar to the ANSI color formatter.\n *\n * @since 1.0.0\n */\nexport interface PrettyFormatterOptions\n extends Omit<TextFormatterOptions, \"category\" | \"value\" | \"format\"> {\n /**\n * Color for timestamp display when timestamps are enabled.\n *\n * Supports true color RGB values, hex colors, or ANSI color names.\n * Set to `null` to disable timestamp coloring.\n *\n * @example\n * ```typescript\n * timestampColor: \"#888888\" // Hex color\n * timestampColor: \"rgb(128,128,128)\" // RGB color\n * timestampColor: \"cyan\" // ANSI color name\n * timestampColor: null // No color\n * ```\n *\n * @default `\"rgb(100,116,139)\"` (slate gray)\n */\n readonly timestampColor?: Color;\n\n /**\n * Visual style applied to timestamp text.\n *\n * Controls text appearance like boldness, dimming, etc.\n * Supports single styles, multiple styles combined, or no styling.\n * Combines with `timestampColor` for full styling control.\n *\n * @example\n * ```typescript\n * timestampStyle: \"dim\" // Single style: dimmed text\n * timestampStyle: \"bold\" // Single style: bold text\n * timestampStyle: [\"bold\", \"underline\"] // Multiple styles: bold + underlined\n * timestampStyle: [\"dim\", \"italic\"] // Multiple styles: dimmed + italic\n * timestampStyle: null // No styling\n * ```\n *\n * @default `\"dim\"`\n */\n readonly timestampStyle?: Style;\n\n /**\n * Custom colors for each log level.\n *\n * Allows fine-grained control over level appearance. Each level can have\n * its own color scheme. Unspecified levels use built-in defaults.\n * Set individual levels to `null` to disable coloring for that level.\n *\n * @example\n * ```typescript\n * levelColors: {\n * info: \"#00ff00\", // Bright green for info\n * error: \"#ff0000\", // Bright red for errors\n * warning: \"orange\", // ANSI orange for warnings\n * debug: null, // No color for debug\n * }\n * ```\n *\n * @default Built-in color scheme (purple trace, blue debug, green info, amber warning, red error, dark red fatal)\n */\n readonly levelColors?: Partial<Record<LogLevel, Color>>;\n\n /**\n * Visual style applied to log level text.\n *\n * Controls the appearance of the level indicator (e.g., \"info\", \"error\").\n * Supports single styles, multiple styles combined, or no styling.\n * Applied in addition to level-specific colors.\n *\n * @example\n * ```typescript\n * levelStyle: \"bold\" // Single style: bold level text\n * levelStyle: \"underline\" // Single style: underlined level text\n * levelStyle: [\"bold\", \"underline\"] // Multiple styles: bold + underlined\n * levelStyle: [\"dim\", \"italic\"] // Multiple styles: dimmed + italic\n * levelStyle: null // No additional styling\n * ```\n *\n * @default `\"underline\"`\n */\n readonly levelStyle?: Style;\n\n /**\n * Icon configuration for each log level.\n *\n * Controls the emoji/symbol displayed before each log entry.\n * Provides visual quick-identification of log severity.\n *\n * - `true`: Use built-in emoji set (🔍 trace, 🐛 debug, ✨ info, ⚠️ warning, ❌ error, 💀 fatal)\n * - `false`: Disable all icons for clean text-only output\n * - Object: Custom icon mapping, falls back to defaults for unspecified levels\n *\n * @example\n * ```typescript\n * icons: true // Use default emoji set\n * icons: false // No icons\n * icons: {\n * info: \"ℹ️\", // Custom info icon\n * error: \"🔥\", // Custom error icon\n * warning: \"⚡\", // Custom warning icon\n * }\n * ```\n *\n * @default `true` (use default emoji icons)\n */\n readonly icons?: boolean | Partial<Record<LogLevel, string>>;\n\n /**\n * Character(s) used to separate category hierarchy levels.\n *\n * Categories are hierarchical (e.g., [\"app\", \"auth\", \"jwt\"]) and this\n * separator joins them for display (e.g., \"app.auth.jwt\").\n *\n * @example\n * ```typescript\n * categorySeparator: \"·\" // app·auth·jwt\n * categorySeparator: \".\" // app.auth.jwt\n * categorySeparator: \":\" // app:auth:jwt\n * categorySeparator: \" > \" // app > auth > jwt\n * categorySeparator: \"::\" // app::auth::jwt\n * ```\n *\n * @default `\"·\"` (interpunct)\n */\n readonly categorySeparator?: string;\n\n /**\n * Default color for category display.\n *\n * Used as fallback when no specific color is found in `categoryColorMap`.\n * Controls the visual appearance of the category hierarchy display.\n *\n * @example\n * ```typescript\n * categoryColor: \"#666666\" // Gray categories\n * categoryColor: \"blue\" // Blue categories\n * categoryColor: \"rgb(100,150,200)\" // Light blue categories\n * categoryColor: null // No coloring\n * ```\n *\n * @default `\"rgb(100,116,139)\"` (slate gray)\n */\n readonly categoryColor?: Color;\n\n /**\n * Category-specific color mapping based on prefixes.\n *\n * Maps category prefixes (as arrays) to colors for visual grouping.\n * More specific (longer) prefixes take precedence over shorter ones.\n * If no prefix matches, falls back to the default `categoryColor`.\n *\n * @example\n * ```typescript\n * new Map([\n * [[\"app\", \"auth\"], \"#ff6b6b\"], // app.auth.* -> red\n * [[\"app\", \"db\"], \"#4ecdc4\"], // app.db.* -> teal\n * [[\"app\"], \"#45b7d1\"], // app.* (fallback) -> blue\n * [[\"lib\"], \"#96ceb4\"], // lib.* -> green\n * ])\n * ```\n */\n readonly categoryColorMap?: CategoryColorMap;\n\n /**\n * Visual style applied to category text.\n *\n * Controls the appearance of the category hierarchy display.\n * Supports single styles, multiple styles combined, or no styling.\n * Applied in addition to category colors from `categoryColor` or `categoryColorMap`.\n *\n * @example\n * ```typescript\n * categoryStyle: \"dim\" // Single style: dimmed category text\n * categoryStyle: \"italic\" // Single style: italic category text\n * categoryStyle: [\"dim\", \"italic\"] // Multiple styles: dimmed + italic\n * categoryStyle: [\"bold\", \"underline\"] // Multiple styles: bold + underlined\n * categoryStyle: null // No additional styling\n * ```\n *\n * @default `[\"dim\", \"italic\"]` (dimmed for subtle appearance)\n */\n readonly categoryStyle?: Style;\n\n /**\n * Maximum display width for category names.\n *\n * Controls layout consistency by limiting category width.\n * Long categories are truncated according to `categoryTruncate` strategy.\n *\n * @default `20`\n */\n readonly categoryWidth?: number;\n\n /**\n * Strategy for truncating long category names.\n *\n * When categories exceed `categoryWidth`, this controls how truncation works.\n * Smart truncation preserves important context while maintaining layout.\n *\n * - `\"middle\"`: Keep first and last parts (e.g., \"app.server…auth.jwt\")\n * - `\"end\"`: Truncate at the end (e.g., \"app.server.middleware…\")\n * - `false`: No truncation (ignores `categoryWidth`)\n *\n * @example\n * ```typescript\n * categoryTruncate: \"middle\" // app.server…jwt (preserves context)\n * categoryTruncate: \"end\" // app.server.midd… (linear truncation)\n * categoryTruncate: false // app.server.middleware.auth.jwt (full)\n * ```\n *\n * @default `\"middle\"` (smart context-preserving truncation)\n */\n readonly categoryTruncate?: TruncationStrategy;\n\n /**\n * Color for log message text content.\n *\n * Controls the visual appearance of the actual log message content.\n * Does not affect structured values, which use syntax highlighting.\n *\n * @example\n * ```typescript\n * messageColor: \"#ffffff\" // White message text\n * messageColor: \"green\" // Green message text\n * messageColor: \"rgb(200,200,200)\" // Light gray message text\n * messageColor: null // No coloring\n * ```\n *\n * @default `\"rgb(148,163,184)\"` (light slate gray)\n */\n readonly messageColor?: Color;\n\n /**\n * Visual style applied to log message text.\n *\n * Controls the appearance of the log message content.\n * Supports single styles, multiple styles combined, or no styling.\n * Applied in addition to `messageColor`.\n *\n * @example\n * ```typescript\n * messageStyle: \"dim\" // Single style: dimmed message text\n * messageStyle: \"italic\" // Single style: italic message text\n * messageStyle: [\"dim\", \"italic\"] // Multiple styles: dimmed + italic\n * messageStyle: [\"bold\", \"underline\"] // Multiple styles: bold + underlined\n * messageStyle: null // No additional styling\n * ```\n *\n * @default `\"dim\"` (dimmed for subtle readability)\n */\n readonly messageStyle?: Style;\n\n /**\n * Global color control for the entire formatter.\n *\n * Master switch to enable/disable all color output.\n * When disabled, produces clean monochrome output suitable for\n * non-color terminals or when colors are not desired.\n *\n * @example\n * ```typescript\n * colors: true // Full color output (default)\n * colors: false // Monochrome output only\n * ```\n *\n * @default `true` (colors enabled)\n */\n readonly colors?: boolean;\n\n /**\n * Column alignment for consistent visual layout.\n *\n * When enabled, ensures all log components (icons, levels, categories)\n * align consistently across multiple log entries, creating a clean\n * tabular appearance.\n *\n * @example\n * ```typescript\n * align: true // Aligned columns (default)\n * align: false // Compact, non-aligned output\n * ```\n *\n * @default `true` (alignment enabled)\n */\n readonly align?: boolean;\n\n /**\n * Configuration for structured value inspection and rendering.\n *\n * Controls how objects, arrays, and other complex values are displayed\n * within log messages. Uses Node.js `util.inspect()` style options.\n *\n * @example\n * ```typescript\n * inspectOptions: {\n * depth: 3, // Show 3 levels of nesting\n * colors: false, // Disable value syntax highlighting\n * compact: true, // Use compact object display\n * }\n * ```\n *\n * @default `{}` (use built-in defaults: depth=unlimited, colors=auto, compact=true)\n */\n readonly inspectOptions?: {\n /**\n * Maximum depth to traverse when inspecting nested objects.\n * @default Infinity (no depth limit)\n */\n readonly depth?: number;\n\n /**\n * Whether to use syntax highlighting colors for inspected values.\n * @default Inherited from global `colors` setting\n */\n readonly colors?: boolean;\n\n /**\n * Whether to use compact formatting for objects and arrays.\n * @default `true` (compact formatting)\n */\n readonly compact?: boolean;\n };\n\n /**\n * Configuration to always render structured data.\n *\n * If set to `true`, any structured data that is logged will\n * always be rendered. This can be very verbose. Make sure\n * to configure `inspectOptions` properly for your usecase.\n *\n * @default `false`\n * @since 1.1.0\n */\n readonly properties?: boolean;\n\n /**\n * Enable word wrapping for long messages.\n *\n * When enabled, long messages will be wrapped at the specified width,\n * with continuation lines aligned to the message column position.\n *\n * - `true`: Auto-detect terminal width when attached to a terminal,\n * fallback to 80 columns when not in a terminal or detection fails\n * - `number`: Use the specified width in columns\n * - `false`: Disable word wrapping\n *\n * @example\n * ```typescript\n * // Auto-detect terminal width (recommended)\n * wordWrap: true\n *\n * // Custom wrap width\n * wordWrap: 120\n *\n * // Disable word wrapping (default)\n * wordWrap: false\n * ```\n *\n * @default `true` (auto-detect terminal width)\n * @since 1.0.0\n */\n readonly wordWrap?: boolean | number;\n}\n\n/**\n * Creates a beautiful console formatter optimized for local development.\n *\n * This formatter provides a Signale-inspired visual design with colorful icons,\n * smart category truncation, dimmed styling, and perfect column alignment.\n * It's specifically designed for development environments that support true colors\n * and Unicode characters.\n *\n * The formatter features:\n * - Emoji icons for each log level (🔍 trace, 🐛 debug, ✨ info, etc.)\n * - True color support with rich color schemes\n * - Intelligent category truncation for long hierarchical categories\n * - Optional timestamp display with multiple formats\n * - Configurable alignment and styling options\n * - Enhanced value rendering with syntax highlighting\n *\n * @param options Configuration options for customizing the formatter behavior.\n * @returns A text formatter function that can be used with LogTape sinks.\n *\n * @example\n * ```typescript\n * import { configure } from \"@logtape/logtape\";\n * import { getConsoleSink } from \"@logtape/logtape/sink\";\n * import { getPrettyFormatter } from \"@logtape/pretty\";\n *\n * await configure({\n * sinks: {\n * console: getConsoleSink({\n * formatter: getPrettyFormatter({\n * timestamp: \"time\",\n * categoryWidth: 25,\n * icons: {\n * info: \"📘\",\n * error: \"🔥\"\n * }\n * })\n * })\n * }\n * });\n * ```\n *\n * @since 1.0.0\n */\nexport function getPrettyFormatter(\n options: PrettyFormatterOptions = {},\n): TextFormatter {\n // Extract options with defaults\n const {\n timestamp = \"none\",\n timestampColor = \"rgb(100,116,139)\",\n timestampStyle = \"dim\",\n level: levelFormat = \"full\",\n levelColors = {},\n levelStyle = \"underline\",\n icons = true,\n categorySeparator = \"·\",\n categoryColor = \"rgb(100,116,139)\",\n categoryColorMap = new Map(),\n categoryStyle = [\"dim\", \"italic\"],\n categoryWidth = 20,\n categoryTruncate = \"middle\",\n messageColor = \"rgb(148,163,184)\",\n messageStyle = \"dim\",\n colors: useColors = true,\n align = true,\n inspectOptions = {},\n properties = false,\n wordWrap = true,\n } = options;\n\n // Resolve icons\n const baseIconMap: Record<LogLevel, string> = icons === false\n ? { trace: \"\", debug: \"\", info: \"\", warning: \"\", error: \"\", fatal: \"\" }\n : icons === true\n ? defaultIcons\n : { ...defaultIcons, ...(icons as Partial<Record<LogLevel, string>>) };\n\n // Normalize icon spacing for consistent alignment\n const iconMap = normalizeIconSpacing(baseIconMap);\n\n // Resolve level colors with defaults\n const resolvedLevelColors: Record<LogLevel, Color> = {\n trace: defaultColors.trace,\n debug: defaultColors.debug,\n info: defaultColors.info,\n warning: defaultColors.warning,\n error: defaultColors.error,\n fatal: defaultColors.fatal,\n ...levelColors,\n };\n\n // Level formatter function with optimized mappings\n const levelMappings: Record<string, Record<LogLevel, string>> = {\n \"ABBR\": {\n trace: \"TRC\",\n debug: \"DBG\",\n info: \"INF\",\n warning: \"WRN\",\n error: \"ERR\",\n fatal: \"FTL\",\n },\n \"L\": {\n trace: \"T\",\n debug: \"D\",\n info: \"I\",\n warning: \"W\",\n error: \"E\",\n fatal: \"F\",\n },\n \"abbr\": {\n trace: \"trc\",\n debug: \"dbg\",\n info: \"inf\",\n warning: \"wrn\",\n error: \"err\",\n fatal: \"ftl\",\n },\n \"l\": {\n trace: \"t\",\n debug: \"d\",\n info: \"i\",\n warning: \"w\",\n error: \"e\",\n fatal: \"f\",\n },\n };\n\n const formatLevel = (level: LogLevel): string => {\n if (typeof levelFormat === \"function\") {\n return levelFormat(level);\n }\n\n if (levelFormat === \"FULL\") return level.toUpperCase();\n if (levelFormat === \"full\") return level;\n\n return levelMappings[levelFormat]?.[level] ?? level;\n };\n\n // Timestamp formatters lookup table\n const timestampFormatters: Record<string, (ts: number) => string> = {\n \"date-time-timezone\": (ts) => {\n const iso = new Date(ts).toISOString();\n return iso.replace(\"T\", \" \").replace(\"Z\", \" +00:00\");\n },\n \"date-time-tz\": (ts) => {\n const iso = new Date(ts).toISOString();\n return iso.replace(\"T\", \" \").replace(\"Z\", \" +00\");\n },\n \"date-time\": (ts) => {\n const iso = new Date(ts).toISOString();\n return iso.replace(\"T\", \" \").replace(\"Z\", \"\");\n },\n \"time-timezone\": (ts) => {\n const iso = new Date(ts).toISOString();\n return iso.replace(/.*T/, \"\").replace(\"Z\", \" +00:00\");\n },\n \"time-tz\": (ts) => {\n const iso = new Date(ts).toISOString();\n return iso.replace(/.*T/, \"\").replace(\"Z\", \" +00\");\n },\n \"time\": (ts) => {\n const iso = new Date(ts).toISOString();\n return iso.replace(/.*T/, \"\").replace(\"Z\", \"\");\n },\n \"date\": (ts) => new Date(ts).toISOString().replace(/T.*/, \"\"),\n \"rfc3339\": (ts) => new Date(ts).toISOString(),\n };\n\n // Resolve timestamp formatter\n let timestampFn: ((ts: number) => string | null) | null = null;\n if (timestamp === \"none\" || timestamp === \"disabled\") {\n timestampFn = null;\n } else if (typeof timestamp === \"function\") {\n timestampFn = timestamp;\n } else {\n timestampFn = timestampFormatters[timestamp as string] ?? null;\n }\n\n // Configure word wrap settings\n const wordWrapEnabled = wordWrap !== false;\n let wordWrapWidth: number;\n\n if (typeof wordWrap === \"number\") {\n wordWrapWidth = wordWrap;\n } else if (wordWrap === true) {\n // Auto-detect terminal width\n wordWrapWidth = getOptimalWordWrapWidth(80);\n } else {\n wordWrapWidth = 80; // Default fallback\n }\n\n // Prepare category color patterns for matching\n const categoryPatterns = prepareCategoryPatterns(categoryColorMap);\n\n // Calculate level width based on format\n const allLevels: LogLevel[] = [...getLogLevels()];\n const levelWidth = Math.max(...allLevels.map((l) => formatLevel(l).length));\n\n return (record: LogRecord): string => {\n // Calculate the prefix parts first to determine message column position\n const icon = iconMap[record.level] || \"\";\n const level = formatLevel(record.level);\n const categoryStr = truncateCategory(\n record.category,\n categoryWidth,\n categorySeparator,\n categoryTruncate,\n );\n\n // Format message with values - handle color reset/reapply for interpolated values\n let message = \"\";\n const messageColorCode = useColors ? colorToAnsi(messageColor) : \"\";\n const messageStyleCode = useColors ? styleToAnsi(messageStyle) : \"\";\n const messagePrefix = useColors\n ? `${messageStyleCode}${messageColorCode}`\n : \"\";\n\n for (let i = 0; i < record.message.length; i++) {\n if (i % 2 === 0) {\n message += record.message[i];\n } else {\n const value = record.message[i];\n const inspected = inspect(value, {\n colors: useColors,\n ...inspectOptions,\n });\n\n // Handle multiline interpolated values properly\n if (inspected.includes(\"\\n\")) {\n const lines = inspected.split(\"\\n\");\n\n const formattedLines = lines.map((line, index) => {\n if (index === 0) {\n // First line: reset formatting, add the line, then reapply\n if (useColors && (messageColorCode || messageStyleCode)) {\n return `${RESET}${line}${messagePrefix}`;\n } else {\n return line;\n }\n } else {\n // Continuation lines: just apply formatting, let wrapText handle indentation\n if (useColors && (messageColorCode || messageStyleCode)) {\n return `${line}${messagePrefix}`;\n } else {\n return line;\n }\n }\n });\n message += formattedLines.join(\"\\n\");\n } else {\n // Single line - handle normally\n if (useColors && (messageColorCode || messageStyleCode)) {\n message += `${RESET}${inspected}${messagePrefix}`;\n } else {\n message += inspected;\n }\n }\n }\n }\n\n // Parts are already calculated above\n\n // Determine category color (with prefix matching)\n const finalCategoryColor = useColors\n ? (matchCategoryColor(record.category, categoryPatterns) || categoryColor)\n : null;\n\n // Apply colors and styling\n const formattedIcon = icon;\n let formattedLevel = level;\n let formattedCategory = categoryStr;\n let formattedMessage = message;\n let formattedTimestamp = \"\";\n\n if (useColors) {\n // Apply level color and style\n const levelColorCode = colorToAnsi(resolvedLevelColors[record.level]);\n const levelStyleCode = styleToAnsi(levelStyle);\n formattedLevel = `${levelStyleCode}${levelColorCode}${level}${RESET}`;\n\n // Apply category color and style (with prefix matching)\n const categoryColorCode = colorToAnsi(finalCategoryColor);\n const categoryStyleCode = styleToAnsi(categoryStyle);\n formattedCategory =\n `${categoryStyleCode}${categoryColorCode}${categoryStr}${RESET}`;\n\n // Apply message color and style (already handled in message building above)\n formattedMessage = `${messagePrefix}${message}${RESET}`;\n }\n\n // Format timestamp if needed\n if (timestampFn) {\n const ts = timestampFn(record.timestamp);\n if (ts !== null) {\n if (useColors) {\n const timestampColorCode = colorToAnsi(timestampColor);\n const timestampStyleCode = styleToAnsi(timestampStyle);\n formattedTimestamp =\n `${timestampStyleCode}${timestampColorCode}${ts}${RESET} `;\n } else {\n formattedTimestamp = `${ts} `;\n }\n }\n }\n\n // Build the final output with alignment\n if (align) {\n // Calculate padding accounting for ANSI escape sequences\n const levelColorLength = useColors\n ? (colorToAnsi(resolvedLevelColors[record.level]).length +\n styleToAnsi(levelStyle).length + RESET.length)\n : 0;\n const categoryColorLength = useColors\n ? (colorToAnsi(finalCategoryColor).length +\n styleToAnsi(categoryStyle).length + RESET.length)\n : 0;\n\n const paddedLevel = formattedLevel.padEnd(levelWidth + levelColorLength);\n const paddedCategory = formattedCategory.padEnd(\n categoryWidth + categoryColorLength,\n );\n\n let result =\n `${formattedTimestamp}${formattedIcon} ${paddedLevel} ${paddedCategory} ${formattedMessage}`;\n const indentWidth = getDisplayWidth(\n stripAnsi(\n `${formattedTimestamp}${formattedIcon} ${paddedLevel} ${paddedCategory} `,\n ),\n );\n\n // Apply word wrapping if enabled, or if there are multiline interpolated values\n if (wordWrapEnabled || message.includes(\"\\n\")) {\n result = wrapText(\n result,\n wordWrapEnabled ? wordWrapWidth : Infinity,\n indentWidth,\n );\n }\n\n if (properties) {\n result += formatProperties(\n record,\n indentWidth,\n wordWrapEnabled ? wordWrapWidth : Infinity,\n useColors,\n inspectOptions,\n );\n }\n\n return result + \"\\n\";\n } else {\n let result =\n `${formattedTimestamp}${formattedIcon} ${formattedLevel} ${formattedCategory} ${formattedMessage}`;\n const indentWidth = getDisplayWidth(\n stripAnsi(\n `${formattedTimestamp}${formattedIcon} ${formattedLevel} ${formattedCategory} `,\n ),\n );\n\n // Apply word wrapping if enabled, or if there are multiline interpolated values\n if (wordWrapEnabled || message.includes(\"\\n\")) {\n result = wrapText(\n result,\n wordWrapEnabled ? wordWrapWidth : Infinity,\n indentWidth,\n );\n }\n\n if (properties) {\n result += formatProperties(\n record,\n indentWidth,\n wordWrapEnabled ? wordWrapWidth : Infinity,\n useColors,\n inspectOptions,\n );\n }\n\n return result + \"\\n\";\n }\n };\n}\n\nfunction formatProperties(\n record: LogRecord,\n indentWidth: number,\n maxWidth: number,\n useColors: boolean,\n inspectOptions: InspectOptions,\n): string {\n let result = \"\";\n for (const prop in record.properties) {\n const propValue = record.properties[prop];\n const pad = indentWidth - getDisplayWidth(prop) - 2;\n result += \"\\n\" + wrapText(\n `${\" \".repeat(pad)}${useColors ? DIM : \"\"}${prop}:${\n useColors ? RESET : \"\"\n } ${inspect(propValue, { colors: useColors, ...inspectOptions })}`,\n maxWidth,\n indentWidth,\n );\n }\n return result;\n}\n\n/**\n * A pre-configured beautiful console formatter for local development.\n *\n * This is a ready-to-use instance of the pretty formatter with sensible defaults\n * for most development scenarios. It provides immediate visual enhancement to\n * your logs without requiring any configuration.\n *\n * Features enabled by default:\n * - Emoji icons for all log levels\n * - True color support with rich color schemes\n * - Dimmed text styling for better readability\n * - Smart category truncation (20 characters max)\n * - Perfect column alignment\n * - No timestamp display (cleaner for development)\n *\n * For custom configuration, use {@link getPrettyFormatter} instead.\n *\n * @example\n * ```typescript\n * import { configure } from \"@logtape/logtape\";\n * import { getConsoleSink } from \"@logtape/logtape/sink\";\n * import { prettyFormatter } from \"@logtape/pretty\";\n *\n * await configure({\n * sinks: {\n * console: getConsoleSink({\n * formatter: prettyFormatter\n * })\n * }\n * });\n * ```\n *\n * @since 1.0.0\n */\nexport const prettyFormatter: TextFormatter = getPrettyFormatter();\n"],"mappings":"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"}
1
+ {"version":3,"file":"formatter.js","names":["color: Color","style: Style","categoryColorMap: CategoryColorMap","patterns: CategoryPattern[]","category: readonly string[]","prefix: readonly string[]","defaultIcons: Record<LogLevel, string>","iconMap: Record<LogLevel, string>","options: PrettyFormatterOptions","baseIconMap: Record<LogLevel, string>","resolvedLevelColors: Record<LogLevel, Color>","levelMappings: Record<string, Record<LogLevel, string>>","level: LogLevel","timestampFormatters: Record<string, (ts: number) => string>","timestampFn: ((ts: number) => string | null) | null","wordWrapWidth: number","allLevels: LogLevel[]","record: LogRecord","indentWidth: number","maxWidth: number","useColors: boolean","inspectOptions: InspectOptions","prettyFormatter: TextFormatter"],"sources":["../src/formatter.ts"],"sourcesContent":["import {\n getLogLevels,\n type LogLevel,\n type LogRecord,\n type TextFormatter,\n type TextFormatterOptions,\n} from \"@logtape/logtape\";\nimport { inspect, type InspectOptions } from \"#util\";\nimport { getOptimalWordWrapWidth } from \"./terminal.ts\";\nimport { truncateCategory, type TruncationStrategy } from \"./truncate.ts\";\nimport { getDisplayWidth, stripAnsi } from \"./wcwidth.ts\";\nimport { wrapText } from \"./wordwrap.ts\";\n\n/**\n * ANSI escape codes for styling\n */\nconst RESET = \"\\x1b[0m\";\nconst DIM = \"\\x1b[2m\";\n\n// Default true color values (referenced in JSDoc)\nconst defaultColors = {\n trace: \"rgb(167,139,250)\", // Light purple\n debug: \"rgb(96,165,250)\", // Light blue\n info: \"rgb(52,211,153)\", // Emerald\n warning: \"rgb(251,191,36)\", // Amber\n error: \"rgb(248,113,113)\", // Light red\n fatal: \"rgb(220,38,38)\", // Dark red\n category: \"rgb(100,116,139)\", // Slate\n message: \"rgb(148,163,184)\", // Light slate\n timestamp: \"rgb(100,116,139)\", // Slate\n} as const;\n\n/**\n * ANSI style codes\n */\nconst styles = {\n reset: RESET,\n bold: \"\\x1b[1m\",\n dim: DIM,\n italic: \"\\x1b[3m\",\n underline: \"\\x1b[4m\",\n strikethrough: \"\\x1b[9m\",\n} as const;\n\n/**\n * Standard ANSI colors (16-color)\n */\nconst ansiColors = {\n black: \"\\x1b[30m\",\n red: \"\\x1b[31m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n blue: \"\\x1b[34m\",\n magenta: \"\\x1b[35m\",\n cyan: \"\\x1b[36m\",\n white: \"\\x1b[37m\",\n} as const;\n\n/**\n * Color type definition\n */\nexport type Color =\n | keyof typeof ansiColors\n | `rgb(${number},${number},${number})`\n | `#${string}`\n | null;\n\n/**\n * Category color mapping for prefix-based coloring.\n *\n * Maps category prefixes (as arrays) to colors. The formatter will match\n * categories against these prefixes and use the corresponding color.\n * Longer/more specific prefixes take precedence over shorter ones.\n *\n * @example\n * ```typescript\n * new Map([\n * [[\"app\", \"auth\"], \"#ff6b6b\"], // app.auth.* -> red\n * [[\"app\", \"db\"], \"#4ecdc4\"], // app.db.* -> teal\n * [[\"app\"], \"#45b7d1\"], // app.* (fallback) -> blue\n * [[\"lib\"], \"#96ceb4\"], // lib.* -> green\n * ])\n * ```\n */\nexport type CategoryColorMap = Map<readonly string[], Color>;\n\n/**\n * Internal representation of category prefix patterns\n */\ntype CategoryPattern = {\n prefix: readonly string[];\n color: Color;\n};\n\n/**\n * Style type definition - supports single styles, arrays of styles, or null\n */\nexport type Style = keyof typeof styles | (keyof typeof styles)[] | null;\n\n// Pre-compiled regex patterns for color parsing\nconst RGB_PATTERN = /^rgb\\((\\d+),(\\d+),(\\d+)\\)$/;\nconst HEX_PATTERN = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;\n\n/**\n * Helper function to convert color to ANSI escape code\n */\nfunction colorToAnsi(color: Color): string {\n if (color === null) return \"\";\n if (color in ansiColors) {\n return ansiColors[color as keyof typeof ansiColors];\n }\n\n // Handle rgb() format\n const rgbMatch = color.match(RGB_PATTERN);\n if (rgbMatch) {\n const [, r, g, b] = rgbMatch;\n return `\\x1b[38;2;${r};${g};${b}m`;\n }\n\n // Handle hex format (#rrggbb or #rgb)\n const hexMatch = color.match(HEX_PATTERN);\n if (hexMatch) {\n let hex = hexMatch[1];\n // Convert 3-digit hex to 6-digit\n if (hex.length === 3) {\n hex = hex.split(\"\").map((c) => c + c).join(\"\");\n }\n const r = parseInt(hex.substr(0, 2), 16);\n const g = parseInt(hex.substr(2, 2), 16);\n const b = parseInt(hex.substr(4, 2), 16);\n return `\\x1b[38;2;${r};${g};${b}m`;\n }\n\n return \"\";\n}\n\n/**\n * Helper function to convert style to ANSI escape code\n */\nfunction styleToAnsi(style: Style): string {\n if (style === null) return \"\";\n if (Array.isArray(style)) {\n return style.map((s) => styles[s] || \"\").join(\"\");\n }\n return styles[style] || \"\";\n}\n\n/**\n * Converts a category color map to internal patterns and sorts them by specificity.\n * More specific (longer) prefixes come first for proper matching precedence.\n */\nfunction prepareCategoryPatterns(\n categoryColorMap: CategoryColorMap,\n): CategoryPattern[] {\n const patterns: CategoryPattern[] = [];\n\n for (const [prefix, color] of categoryColorMap) {\n patterns.push({ prefix, color });\n }\n\n // Sort by prefix length (descending) for most-specific-first matching\n return patterns.sort((a, b) => b.prefix.length - a.prefix.length);\n}\n\n/**\n * Matches a category against category color patterns.\n * Returns the color of the first matching pattern, or null if no match.\n */\nfunction matchCategoryColor(\n category: readonly string[],\n patterns: CategoryPattern[],\n): Color {\n for (const pattern of patterns) {\n if (categoryMatches(category, pattern.prefix)) {\n return pattern.color;\n }\n }\n return null;\n}\n\n/**\n * Checks if a category matches a prefix pattern.\n * A category matches if it starts with all segments of the prefix.\n */\nfunction categoryMatches(\n category: readonly string[],\n prefix: readonly string[],\n): boolean {\n if (prefix.length > category.length) {\n return false;\n }\n\n for (let i = 0; i < prefix.length; i++) {\n if (category[i] !== prefix[i]) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Default icons for each log level\n */\nconst defaultIcons: Record<LogLevel, string> = {\n trace: \"🔍\",\n debug: \"🐛\",\n info: \"✨\",\n warning: \"⚡\",\n error: \"❌\",\n fatal: \"💀\",\n};\n\n/**\n * Normalize icon spacing to ensure consistent column alignment.\n *\n * All icons will be padded with spaces to match the width of the widest icon,\n * ensuring consistent prefix alignment across all log levels.\n *\n * @param iconMap The icon mapping to normalize\n * @returns A new icon map with consistent spacing\n */\nfunction normalizeIconSpacing(\n iconMap: Record<LogLevel, string>,\n): Record<LogLevel, string> {\n const entries = Object.entries(iconMap) as Array<[LogLevel, string]>;\n const maxWidth = Math.max(\n ...entries.map(([, icon]) => getDisplayWidth(icon)),\n );\n\n return Object.fromEntries(\n entries.map(([level, icon]) => [\n level,\n icon + \" \".repeat(maxWidth - getDisplayWidth(icon)),\n ]),\n ) as Record<LogLevel, string>;\n}\n\n/**\n * Configuration options for the pretty formatter.\n *\n * This interface extends the base text formatter options while providing\n * extensive customization options for visual styling, layout control, and\n * development-focused features. It offers granular control over colors,\n * styles, and formatting similar to the ANSI color formatter.\n *\n * @since 1.0.0\n */\nexport interface PrettyFormatterOptions\n extends Omit<TextFormatterOptions, \"category\" | \"value\" | \"format\"> {\n /**\n * Color for timestamp display when timestamps are enabled.\n *\n * Supports true color RGB values, hex colors, or ANSI color names.\n * Set to `null` to disable timestamp coloring.\n *\n * @example\n * ```typescript\n * timestampColor: \"#888888\" // Hex color\n * timestampColor: \"rgb(128,128,128)\" // RGB color\n * timestampColor: \"cyan\" // ANSI color name\n * timestampColor: null // No color\n * ```\n *\n * @default `\"rgb(100,116,139)\"` (slate gray)\n */\n readonly timestampColor?: Color;\n\n /**\n * Visual style applied to timestamp text.\n *\n * Controls text appearance like boldness, dimming, etc.\n * Supports single styles, multiple styles combined, or no styling.\n * Combines with `timestampColor` for full styling control.\n *\n * @example\n * ```typescript\n * timestampStyle: \"dim\" // Single style: dimmed text\n * timestampStyle: \"bold\" // Single style: bold text\n * timestampStyle: [\"bold\", \"underline\"] // Multiple styles: bold + underlined\n * timestampStyle: [\"dim\", \"italic\"] // Multiple styles: dimmed + italic\n * timestampStyle: null // No styling\n * ```\n *\n * @default `\"dim\"`\n */\n readonly timestampStyle?: Style;\n\n /**\n * Custom colors for each log level.\n *\n * Allows fine-grained control over level appearance. Each level can have\n * its own color scheme. Unspecified levels use built-in defaults.\n * Set individual levels to `null` to disable coloring for that level.\n *\n * @example\n * ```typescript\n * levelColors: {\n * info: \"#00ff00\", // Bright green for info\n * error: \"#ff0000\", // Bright red for errors\n * warning: \"orange\", // ANSI orange for warnings\n * debug: null, // No color for debug\n * }\n * ```\n *\n * @default Built-in color scheme (purple trace, blue debug, green info, amber warning, red error, dark red fatal)\n */\n readonly levelColors?: Partial<Record<LogLevel, Color>>;\n\n /**\n * Visual style applied to log level text.\n *\n * Controls the appearance of the level indicator (e.g., \"info\", \"error\").\n * Supports single styles, multiple styles combined, or no styling.\n * Applied in addition to level-specific colors.\n *\n * @example\n * ```typescript\n * levelStyle: \"bold\" // Single style: bold level text\n * levelStyle: \"underline\" // Single style: underlined level text\n * levelStyle: [\"bold\", \"underline\"] // Multiple styles: bold + underlined\n * levelStyle: [\"dim\", \"italic\"] // Multiple styles: dimmed + italic\n * levelStyle: null // No additional styling\n * ```\n *\n * @default `\"underline\"`\n */\n readonly levelStyle?: Style;\n\n /**\n * Icon configuration for each log level.\n *\n * Controls the emoji/symbol displayed before each log entry.\n * Provides visual quick-identification of log severity.\n *\n * - `true`: Use built-in emoji set (🔍 trace, 🐛 debug, ✨ info, ⚠️ warning, ❌ error, 💀 fatal)\n * - `false`: Disable all icons for clean text-only output\n * - Object: Custom icon mapping, falls back to defaults for unspecified levels\n *\n * @example\n * ```typescript\n * icons: true // Use default emoji set\n * icons: false // No icons\n * icons: {\n * info: \"ℹ️\", // Custom info icon\n * error: \"🔥\", // Custom error icon\n * warning: \"⚡\", // Custom warning icon\n * }\n * ```\n *\n * @default `true` (use default emoji icons)\n */\n readonly icons?: boolean | Partial<Record<LogLevel, string>>;\n\n /**\n * Character(s) used to separate category hierarchy levels.\n *\n * Categories are hierarchical (e.g., [\"app\", \"auth\", \"jwt\"]) and this\n * separator joins them for display (e.g., \"app.auth.jwt\").\n *\n * @example\n * ```typescript\n * categorySeparator: \"·\" // app·auth·jwt\n * categorySeparator: \".\" // app.auth.jwt\n * categorySeparator: \":\" // app:auth:jwt\n * categorySeparator: \" > \" // app > auth > jwt\n * categorySeparator: \"::\" // app::auth::jwt\n * ```\n *\n * @default `\"·\"` (interpunct)\n */\n readonly categorySeparator?: string;\n\n /**\n * Default color for category display.\n *\n * Used as fallback when no specific color is found in `categoryColorMap`.\n * Controls the visual appearance of the category hierarchy display.\n *\n * @example\n * ```typescript\n * categoryColor: \"#666666\" // Gray categories\n * categoryColor: \"blue\" // Blue categories\n * categoryColor: \"rgb(100,150,200)\" // Light blue categories\n * categoryColor: null // No coloring\n * ```\n *\n * @default `\"rgb(100,116,139)\"` (slate gray)\n */\n readonly categoryColor?: Color;\n\n /**\n * Category-specific color mapping based on prefixes.\n *\n * Maps category prefixes (as arrays) to colors for visual grouping.\n * More specific (longer) prefixes take precedence over shorter ones.\n * If no prefix matches, falls back to the default `categoryColor`.\n *\n * @example\n * ```typescript\n * new Map([\n * [[\"app\", \"auth\"], \"#ff6b6b\"], // app.auth.* -> red\n * [[\"app\", \"db\"], \"#4ecdc4\"], // app.db.* -> teal\n * [[\"app\"], \"#45b7d1\"], // app.* (fallback) -> blue\n * [[\"lib\"], \"#96ceb4\"], // lib.* -> green\n * ])\n * ```\n */\n readonly categoryColorMap?: CategoryColorMap;\n\n /**\n * Visual style applied to category text.\n *\n * Controls the appearance of the category hierarchy display.\n * Supports single styles, multiple styles combined, or no styling.\n * Applied in addition to category colors from `categoryColor` or `categoryColorMap`.\n *\n * @example\n * ```typescript\n * categoryStyle: \"dim\" // Single style: dimmed category text\n * categoryStyle: \"italic\" // Single style: italic category text\n * categoryStyle: [\"dim\", \"italic\"] // Multiple styles: dimmed + italic\n * categoryStyle: [\"bold\", \"underline\"] // Multiple styles: bold + underlined\n * categoryStyle: null // No additional styling\n * ```\n *\n * @default `[\"dim\", \"italic\"]` (dimmed for subtle appearance)\n */\n readonly categoryStyle?: Style;\n\n /**\n * Maximum display width for category names.\n *\n * Controls layout consistency by limiting category width.\n * Long categories are truncated according to `categoryTruncate` strategy.\n *\n * @default `20`\n */\n readonly categoryWidth?: number;\n\n /**\n * Strategy for truncating long category names.\n *\n * When categories exceed `categoryWidth`, this controls how truncation works.\n * Smart truncation preserves important context while maintaining layout.\n *\n * - `\"middle\"`: Keep first and last parts (e.g., \"app.server…auth.jwt\")\n * - `\"end\"`: Truncate at the end (e.g., \"app.server.middleware…\")\n * - `false`: No truncation (ignores `categoryWidth`)\n *\n * @example\n * ```typescript\n * categoryTruncate: \"middle\" // app.server…jwt (preserves context)\n * categoryTruncate: \"end\" // app.server.midd… (linear truncation)\n * categoryTruncate: false // app.server.middleware.auth.jwt (full)\n * ```\n *\n * @default `\"middle\"` (smart context-preserving truncation)\n */\n readonly categoryTruncate?: TruncationStrategy;\n\n /**\n * Color for log message text content.\n *\n * Controls the visual appearance of the actual log message content.\n * Does not affect structured values, which use syntax highlighting.\n *\n * @example\n * ```typescript\n * messageColor: \"#ffffff\" // White message text\n * messageColor: \"green\" // Green message text\n * messageColor: \"rgb(200,200,200)\" // Light gray message text\n * messageColor: null // No coloring\n * ```\n *\n * @default `\"rgb(148,163,184)\"` (light slate gray)\n */\n readonly messageColor?: Color;\n\n /**\n * Visual style applied to log message text.\n *\n * Controls the appearance of the log message content.\n * Supports single styles, multiple styles combined, or no styling.\n * Applied in addition to `messageColor`.\n *\n * @example\n * ```typescript\n * messageStyle: \"dim\" // Single style: dimmed message text\n * messageStyle: \"italic\" // Single style: italic message text\n * messageStyle: [\"dim\", \"italic\"] // Multiple styles: dimmed + italic\n * messageStyle: [\"bold\", \"underline\"] // Multiple styles: bold + underlined\n * messageStyle: null // No additional styling\n * ```\n *\n * @default `\"dim\"` (dimmed for subtle readability)\n */\n readonly messageStyle?: Style;\n\n /**\n * Global color control for the entire formatter.\n *\n * Master switch to enable/disable all color output.\n * When disabled, produces clean monochrome output suitable for\n * non-color terminals or when colors are not desired.\n *\n * @example\n * ```typescript\n * colors: true // Full color output (default)\n * colors: false // Monochrome output only\n * ```\n *\n * @default `true` (colors enabled)\n */\n readonly colors?: boolean;\n\n /**\n * Column alignment for consistent visual layout.\n *\n * When enabled, ensures all log components (icons, levels, categories)\n * align consistently across multiple log entries, creating a clean\n * tabular appearance.\n *\n * @example\n * ```typescript\n * align: true // Aligned columns (default)\n * align: false // Compact, non-aligned output\n * ```\n *\n * @default `true` (alignment enabled)\n */\n readonly align?: boolean;\n\n /**\n * Configuration for structured value inspection and rendering.\n *\n * Controls how objects, arrays, and other complex values are displayed\n * within log messages. Uses Node.js `util.inspect()` style options.\n *\n * @example\n * ```typescript\n * inspectOptions: {\n * depth: 3, // Show 3 levels of nesting\n * colors: false, // Disable value syntax highlighting\n * compact: true, // Use compact object display\n * }\n * ```\n *\n * @default `{}` (use built-in defaults: depth=unlimited, colors=auto, compact=true)\n */\n readonly inspectOptions?: {\n /**\n * Maximum depth to traverse when inspecting nested objects.\n * @default Infinity (no depth limit)\n */\n readonly depth?: number;\n\n /**\n * Whether to use syntax highlighting colors for inspected values.\n * @default Inherited from global `colors` setting\n */\n readonly colors?: boolean;\n\n /**\n * Whether to use compact formatting for objects and arrays.\n * @default `true` (compact formatting)\n */\n readonly compact?: boolean;\n };\n\n /**\n * Configuration to always render structured data.\n *\n * If set to `true`, any structured data that is logged will\n * always be rendered. This can be very verbose. Make sure\n * to configure `inspectOptions` properly for your usecase.\n *\n * @default `false`\n * @since 1.1.0\n */\n readonly properties?: boolean;\n\n /**\n * Enable word wrapping for long messages.\n *\n * When enabled, long messages will be wrapped at the specified width,\n * with continuation lines aligned to the message column position.\n *\n * - `true`: Auto-detect terminal width when attached to a terminal,\n * fallback to 80 columns when not in a terminal or detection fails\n * - `number`: Use the specified width in columns\n * - `false`: Disable word wrapping\n *\n * @example\n * ```typescript\n * // Auto-detect terminal width (recommended)\n * wordWrap: true\n *\n * // Custom wrap width\n * wordWrap: 120\n *\n * // Disable word wrapping (default)\n * wordWrap: false\n * ```\n *\n * @default `true` (auto-detect terminal width)\n * @since 1.0.0\n */\n readonly wordWrap?: boolean | number;\n}\n\n/**\n * Creates a beautiful console formatter optimized for local development.\n *\n * This formatter provides a Signale-inspired visual design with colorful icons,\n * smart category truncation, dimmed styling, and perfect column alignment.\n * It's specifically designed for development environments that support true colors\n * and Unicode characters.\n *\n * The formatter features:\n * - Emoji icons for each log level (🔍 trace, 🐛 debug, ✨ info, etc.)\n * - True color support with rich color schemes\n * - Intelligent category truncation for long hierarchical categories\n * - Optional timestamp display with multiple formats\n * - Configurable alignment and styling options\n * - Enhanced value rendering with syntax highlighting\n *\n * @param options Configuration options for customizing the formatter behavior.\n * @returns A text formatter function that can be used with LogTape sinks.\n *\n * @example\n * ```typescript\n * import { configure } from \"@logtape/logtape\";\n * import { getConsoleSink } from \"@logtape/logtape/sink\";\n * import { getPrettyFormatter } from \"@logtape/pretty\";\n *\n * await configure({\n * sinks: {\n * console: getConsoleSink({\n * formatter: getPrettyFormatter({\n * timestamp: \"time\",\n * categoryWidth: 25,\n * icons: {\n * info: \"📘\",\n * error: \"🔥\"\n * }\n * })\n * })\n * }\n * });\n * ```\n *\n * @since 1.0.0\n */\nexport function getPrettyFormatter(\n options: PrettyFormatterOptions = {},\n): TextFormatter {\n // Extract options with defaults\n const {\n timestamp = \"none\",\n timestampColor = \"rgb(100,116,139)\",\n timestampStyle = \"dim\",\n level: levelFormat = \"full\",\n levelColors = {},\n levelStyle = \"underline\",\n icons = true,\n categorySeparator = \"·\",\n categoryColor = \"rgb(100,116,139)\",\n categoryColorMap = new Map(),\n categoryStyle = [\"dim\", \"italic\"],\n categoryWidth = 20,\n categoryTruncate = \"middle\",\n messageColor = \"rgb(148,163,184)\",\n messageStyle = \"dim\",\n colors: useColors = true,\n align = true,\n inspectOptions = {},\n properties = false,\n wordWrap = true,\n } = options;\n\n // Resolve icons\n const baseIconMap: Record<LogLevel, string> = icons === false\n ? { trace: \"\", debug: \"\", info: \"\", warning: \"\", error: \"\", fatal: \"\" }\n : icons === true\n ? defaultIcons\n : { ...defaultIcons, ...(icons as Partial<Record<LogLevel, string>>) };\n\n // Normalize icon spacing for consistent alignment\n const iconMap = normalizeIconSpacing(baseIconMap);\n\n // Resolve level colors with defaults\n const resolvedLevelColors: Record<LogLevel, Color> = {\n trace: defaultColors.trace,\n debug: defaultColors.debug,\n info: defaultColors.info,\n warning: defaultColors.warning,\n error: defaultColors.error,\n fatal: defaultColors.fatal,\n ...levelColors,\n };\n\n // Level formatter function with optimized mappings\n const levelMappings: Record<string, Record<LogLevel, string>> = {\n \"ABBR\": {\n trace: \"TRC\",\n debug: \"DBG\",\n info: \"INF\",\n warning: \"WRN\",\n error: \"ERR\",\n fatal: \"FTL\",\n },\n \"L\": {\n trace: \"T\",\n debug: \"D\",\n info: \"I\",\n warning: \"W\",\n error: \"E\",\n fatal: \"F\",\n },\n \"abbr\": {\n trace: \"trc\",\n debug: \"dbg\",\n info: \"inf\",\n warning: \"wrn\",\n error: \"err\",\n fatal: \"ftl\",\n },\n \"l\": {\n trace: \"t\",\n debug: \"d\",\n info: \"i\",\n warning: \"w\",\n error: \"e\",\n fatal: \"f\",\n },\n };\n\n const formatLevel = (level: LogLevel): string => {\n if (typeof levelFormat === \"function\") {\n return levelFormat(level);\n }\n\n if (levelFormat === \"FULL\") return level.toUpperCase();\n if (levelFormat === \"full\") return level;\n\n return levelMappings[levelFormat]?.[level] ?? level;\n };\n\n // Timestamp formatters lookup table\n const timestampFormatters: Record<string, (ts: number) => string> = {\n \"date-time-timezone\": (ts) => {\n const iso = new Date(ts).toISOString();\n return iso.replace(\"T\", \" \").replace(\"Z\", \" +00:00\");\n },\n \"date-time-tz\": (ts) => {\n const iso = new Date(ts).toISOString();\n return iso.replace(\"T\", \" \").replace(\"Z\", \" +00\");\n },\n \"date-time\": (ts) => {\n const iso = new Date(ts).toISOString();\n return iso.replace(\"T\", \" \").replace(\"Z\", \"\");\n },\n \"time-timezone\": (ts) => {\n const iso = new Date(ts).toISOString();\n return iso.replace(/.*T/, \"\").replace(\"Z\", \" +00:00\");\n },\n \"time-tz\": (ts) => {\n const iso = new Date(ts).toISOString();\n return iso.replace(/.*T/, \"\").replace(\"Z\", \" +00\");\n },\n \"time\": (ts) => {\n const iso = new Date(ts).toISOString();\n return iso.replace(/.*T/, \"\").replace(\"Z\", \"\");\n },\n \"date\": (ts) => new Date(ts).toISOString().replace(/T.*/, \"\"),\n \"rfc3339\": (ts) => new Date(ts).toISOString(),\n };\n\n // Resolve timestamp formatter\n let timestampFn: ((ts: number) => string | null) | null = null;\n if (timestamp === \"none\" || timestamp === \"disabled\") {\n timestampFn = null;\n } else if (typeof timestamp === \"function\") {\n timestampFn = timestamp;\n } else {\n timestampFn = timestampFormatters[timestamp as string] ?? null;\n }\n\n // Configure word wrap settings\n const wordWrapEnabled = wordWrap !== false;\n let wordWrapWidth: number;\n\n if (typeof wordWrap === \"number\") {\n wordWrapWidth = wordWrap;\n } else if (wordWrap === true) {\n // Auto-detect terminal width\n wordWrapWidth = getOptimalWordWrapWidth(80);\n } else {\n wordWrapWidth = 80; // Default fallback\n }\n\n // Prepare category color patterns for matching\n const categoryPatterns = prepareCategoryPatterns(categoryColorMap);\n\n // Calculate level width based on format\n const allLevels: LogLevel[] = [...getLogLevels()];\n const levelWidth = Math.max(...allLevels.map((l) => formatLevel(l).length));\n\n return (record: LogRecord): string => {\n // Calculate the prefix parts first to determine message column position\n const icon = iconMap[record.level] || \"\";\n const level = formatLevel(record.level);\n const categoryStr = truncateCategory(\n record.category,\n categoryWidth,\n categorySeparator,\n categoryTruncate,\n );\n\n // Format message with values - handle color reset/reapply for interpolated values\n let message = \"\";\n const messageColorCode = useColors ? colorToAnsi(messageColor) : \"\";\n const messageStyleCode = useColors ? styleToAnsi(messageStyle) : \"\";\n const messagePrefix = useColors\n ? `${messageStyleCode}${messageColorCode}`\n : \"\";\n\n for (let i = 0; i < record.message.length; i++) {\n if (i % 2 === 0) {\n message += record.message[i];\n } else {\n const value = record.message[i];\n const inspected = inspect(value, {\n colors: useColors,\n ...inspectOptions,\n });\n\n // Handle multiline interpolated values properly\n if (inspected.includes(\"\\n\")) {\n const lines = inspected.split(\"\\n\");\n\n const formattedLines = lines.map((line, index) => {\n if (index === 0) {\n // First line: reset formatting, add the line, then reapply\n if (useColors && (messageColorCode || messageStyleCode)) {\n return `${RESET}${line}${messagePrefix}`;\n } else {\n return line;\n }\n } else {\n // Continuation lines: just apply formatting, let wrapText handle indentation\n if (useColors && (messageColorCode || messageStyleCode)) {\n return `${line}${messagePrefix}`;\n } else {\n return line;\n }\n }\n });\n message += formattedLines.join(\"\\n\");\n } else {\n // Single line - handle normally\n if (useColors && (messageColorCode || messageStyleCode)) {\n message += `${RESET}${inspected}${messagePrefix}`;\n } else {\n message += inspected;\n }\n }\n }\n }\n\n // Parts are already calculated above\n\n // Determine category color (with prefix matching)\n const finalCategoryColor = useColors\n ? (matchCategoryColor(record.category, categoryPatterns) || categoryColor)\n : null;\n\n // Apply colors and styling\n const formattedIcon = icon;\n let formattedLevel = level;\n let formattedCategory = categoryStr;\n let formattedMessage = message;\n let formattedTimestamp = \"\";\n\n if (useColors) {\n // Apply level color and style\n const levelColorCode = colorToAnsi(resolvedLevelColors[record.level]);\n const levelStyleCode = styleToAnsi(levelStyle);\n formattedLevel = `${levelStyleCode}${levelColorCode}${level}${RESET}`;\n\n // Apply category color and style (with prefix matching)\n const categoryColorCode = colorToAnsi(finalCategoryColor);\n const categoryStyleCode = styleToAnsi(categoryStyle);\n formattedCategory =\n `${categoryStyleCode}${categoryColorCode}${categoryStr}${RESET}`;\n\n // Apply message color and style (already handled in message building above)\n formattedMessage = `${messagePrefix}${message}${RESET}`;\n }\n\n // Format timestamp if needed\n if (timestampFn) {\n const ts = timestampFn(record.timestamp);\n if (ts !== null) {\n if (useColors) {\n const timestampColorCode = colorToAnsi(timestampColor);\n const timestampStyleCode = styleToAnsi(timestampStyle);\n formattedTimestamp =\n `${timestampStyleCode}${timestampColorCode}${ts}${RESET} `;\n } else {\n formattedTimestamp = `${ts} `;\n }\n }\n }\n\n // Build the final output with alignment\n if (align) {\n // Calculate padding accounting for ANSI escape sequences\n const levelColorLength = useColors\n ? (colorToAnsi(resolvedLevelColors[record.level]).length +\n styleToAnsi(levelStyle).length + RESET.length)\n : 0;\n const categoryColorLength = useColors\n ? (colorToAnsi(finalCategoryColor).length +\n styleToAnsi(categoryStyle).length + RESET.length)\n : 0;\n\n const paddedLevel = formattedLevel.padEnd(levelWidth + levelColorLength);\n const paddedCategory = formattedCategory.padEnd(\n categoryWidth + categoryColorLength,\n );\n\n let result =\n `${formattedTimestamp}${formattedIcon} ${paddedLevel} ${paddedCategory} ${formattedMessage}`;\n const indentWidth = getDisplayWidth(\n stripAnsi(\n `${formattedTimestamp}${formattedIcon} ${paddedLevel} ${paddedCategory} `,\n ),\n );\n\n // Apply word wrapping if enabled, or if there are multiline interpolated values\n if (wordWrapEnabled || message.includes(\"\\n\")) {\n result = wrapText(\n result,\n wordWrapEnabled ? wordWrapWidth : Infinity,\n indentWidth,\n );\n }\n\n if (properties) {\n result += formatProperties(\n record,\n indentWidth,\n wordWrapEnabled ? wordWrapWidth : Infinity,\n useColors,\n inspectOptions,\n );\n }\n\n return result + \"\\n\";\n } else {\n let result =\n `${formattedTimestamp}${formattedIcon} ${formattedLevel} ${formattedCategory} ${formattedMessage}`;\n const indentWidth = getDisplayWidth(\n stripAnsi(\n `${formattedTimestamp}${formattedIcon} ${formattedLevel} ${formattedCategory} `,\n ),\n );\n\n // Apply word wrapping if enabled, or if there are multiline interpolated values\n if (wordWrapEnabled || message.includes(\"\\n\")) {\n result = wrapText(\n result,\n wordWrapEnabled ? wordWrapWidth : Infinity,\n indentWidth,\n );\n }\n\n if (properties) {\n result += formatProperties(\n record,\n indentWidth,\n wordWrapEnabled ? wordWrapWidth : Infinity,\n useColors,\n inspectOptions,\n );\n }\n\n return result + \"\\n\";\n }\n };\n}\n\nfunction formatProperties(\n record: LogRecord,\n indentWidth: number,\n maxWidth: number,\n useColors: boolean,\n inspectOptions: InspectOptions,\n): string {\n let result = \"\";\n for (const prop in record.properties) {\n const propValue = record.properties[prop];\n const pad = indentWidth - getDisplayWidth(prop) - 2;\n result += \"\\n\" + wrapText(\n `${\" \".repeat(pad)}${useColors ? DIM : \"\"}${prop}:${\n useColors ? RESET : \"\"\n } ${inspect(propValue, { colors: useColors, ...inspectOptions })}`,\n maxWidth,\n indentWidth,\n );\n }\n return result;\n}\n\n/**\n * A pre-configured beautiful console formatter for local development.\n *\n * This is a ready-to-use instance of the pretty formatter with sensible defaults\n * for most development scenarios. It provides immediate visual enhancement to\n * your logs without requiring any configuration.\n *\n * Features enabled by default:\n * - Emoji icons for all log levels\n * - True color support with rich color schemes\n * - Dimmed text styling for better readability\n * - Smart category truncation (20 characters max)\n * - Perfect column alignment\n * - No timestamp display (cleaner for development)\n *\n * For custom configuration, use {@link getPrettyFormatter} instead.\n *\n * @example\n * ```typescript\n * import { configure } from \"@logtape/logtape\";\n * import { getConsoleSink } from \"@logtape/logtape/sink\";\n * import { prettyFormatter } from \"@logtape/pretty\";\n *\n * await configure({\n * sinks: {\n * console: getConsoleSink({\n * formatter: prettyFormatter\n * })\n * }\n * });\n * ```\n *\n * @since 1.0.0\n */\nexport const prettyFormatter: TextFormatter = getPrettyFormatter();\n"],"mappings":"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"}
package/dist/terminal.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- //#region terminal.ts
2
+ //#region src/terminal.ts
3
3
  /**
4
4
  * @fileoverview
5
5
  * Terminal detection and width calculation utilities
package/dist/terminal.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region terminal.ts
1
+ //#region src/terminal.ts
2
2
  /**
3
3
  * @fileoverview
4
4
  * Terminal detection and width calculation utilities
@@ -1 +1 @@
1
- {"version":3,"file":"terminal.js","names":["defaultWidth: number"],"sources":["../terminal.ts"],"sourcesContent":["// deno-lint-ignore-file no-process-global\n/// <reference types=\"@types/node\" />\n/**\n * @fileoverview\n * Terminal detection and width calculation utilities\n *\n * Provides cross-runtime compatible functions to detect if the process\n * is attached to a terminal and get the terminal width.\n */\n\n/**\n * Detect if the current process is attached to a terminal (TTY).\n *\n * @returns True if stdout is connected to a terminal\n */\nexport function isTerminal(): boolean {\n try {\n // Deno runtime\n if (typeof Deno !== \"undefined\") {\n // Use modern Deno API\n if (Deno.stdout.isTerminal) {\n return Deno.stdout.isTerminal();\n }\n }\n\n // Node.js/Bun runtime\n if (typeof process !== \"undefined\" && process.stdout) {\n return Boolean(process.stdout.isTTY);\n }\n\n // Browser environment - never a terminal\n if (typeof window !== \"undefined\") {\n return false;\n }\n\n // Unknown environment - assume not a terminal\n return false;\n } catch {\n // If any detection method fails, assume not a terminal\n return false;\n }\n}\n\n/**\n * Get the current terminal width in columns.\n *\n * @returns Terminal width in columns, or null if not available\n */\nexport function getTerminalWidth(): number | null {\n try {\n // Deno runtime\n if (typeof Deno !== \"undefined\") {\n // Try to get console size\n if (Deno.consoleSize) {\n const size = Deno.consoleSize();\n return size?.columns || null;\n }\n }\n\n // Node.js/Bun runtime\n if (typeof process !== \"undefined\" && process.stdout) {\n return process.stdout.columns || null;\n }\n\n // Fallback to environment variable\n const envColumns = typeof Deno !== \"undefined\"\n ? Deno.env.get(\"COLUMNS\")\n : process?.env?.COLUMNS;\n\n if (envColumns) {\n const parsed = parseInt(envColumns, 10);\n return isNaN(parsed) ? null : parsed;\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the optimal word wrap width based on terminal detection.\n *\n * @param defaultWidth Default width to use when not in a terminal\n * @returns The optimal width\n */\nexport function getOptimalWordWrapWidth(defaultWidth: number = 80): number {\n if (!isTerminal()) {\n return defaultWidth;\n }\n\n const terminalWidth = getTerminalWidth();\n return terminalWidth || defaultWidth;\n}\n"],"mappings":";;;;;;;;;;;;;AAeA,SAAgB,aAAsB;AACpC,KAAI;AAEF,aAAW,SAAS,aAElB;OAAI,KAAK,OAAO,WACd,QAAO,KAAK,OAAO,YAAY;EAChC;AAIH,aAAW,YAAY,eAAe,QAAQ,OAC5C,QAAO,QAAQ,QAAQ,OAAO,MAAM;AAItC,aAAW,WAAW,YACpB,QAAO;AAIT,SAAO;CACR,QAAO;AAEN,SAAO;CACR;AACF;;;;;;AAOD,SAAgB,mBAAkC;AAChD,KAAI;AAEF,aAAW,SAAS,aAElB;OAAI,KAAK,aAAa;IACpB,MAAM,OAAO,KAAK,aAAa;AAC/B,WAAO,MAAM,WAAW;GACzB;;AAIH,aAAW,YAAY,eAAe,QAAQ,OAC5C,QAAO,QAAQ,OAAO,WAAW;EAInC,MAAM,oBAAoB,SAAS,cAC/B,KAAK,IAAI,IAAI,UAAU,GACvB,SAAS,KAAK;AAElB,MAAI,YAAY;GACd,MAAM,SAAS,SAAS,YAAY,GAAG;AACvC,UAAO,MAAM,OAAO,GAAG,OAAO;EAC/B;AAED,SAAO;CACR,QAAO;AACN,SAAO;CACR;AACF;;;;;;;AAQD,SAAgB,wBAAwBA,eAAuB,IAAY;AACzE,MAAK,YAAY,CACf,QAAO;CAGT,MAAM,gBAAgB,kBAAkB;AACxC,QAAO,iBAAiB;AACzB"}
1
+ {"version":3,"file":"terminal.js","names":["defaultWidth: number"],"sources":["../src/terminal.ts"],"sourcesContent":["// deno-lint-ignore-file no-process-global\n/// <reference types=\"@types/node\" />\n/**\n * @fileoverview\n * Terminal detection and width calculation utilities\n *\n * Provides cross-runtime compatible functions to detect if the process\n * is attached to a terminal and get the terminal width.\n */\n\n/**\n * Detect if the current process is attached to a terminal (TTY).\n *\n * @returns True if stdout is connected to a terminal\n */\nexport function isTerminal(): boolean {\n try {\n // Deno runtime\n if (typeof Deno !== \"undefined\") {\n // Use modern Deno API\n if (Deno.stdout.isTerminal) {\n return Deno.stdout.isTerminal();\n }\n }\n\n // Node.js/Bun runtime\n if (typeof process !== \"undefined\" && process.stdout) {\n return Boolean(process.stdout.isTTY);\n }\n\n // Browser environment - never a terminal\n if (typeof window !== \"undefined\") {\n return false;\n }\n\n // Unknown environment - assume not a terminal\n return false;\n } catch {\n // If any detection method fails, assume not a terminal\n return false;\n }\n}\n\n/**\n * Get the current terminal width in columns.\n *\n * @returns Terminal width in columns, or null if not available\n */\nexport function getTerminalWidth(): number | null {\n try {\n // Deno runtime\n if (typeof Deno !== \"undefined\") {\n // Try to get console size\n if (Deno.consoleSize) {\n const size = Deno.consoleSize();\n return size?.columns || null;\n }\n }\n\n // Node.js/Bun runtime\n if (typeof process !== \"undefined\" && process.stdout) {\n return process.stdout.columns || null;\n }\n\n // Fallback to environment variable\n const envColumns = typeof Deno !== \"undefined\"\n ? Deno.env.get(\"COLUMNS\")\n : process?.env?.COLUMNS;\n\n if (envColumns) {\n const parsed = parseInt(envColumns, 10);\n return isNaN(parsed) ? null : parsed;\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the optimal word wrap width based on terminal detection.\n *\n * @param defaultWidth Default width to use when not in a terminal\n * @returns The optimal width\n */\nexport function getOptimalWordWrapWidth(defaultWidth: number = 80): number {\n if (!isTerminal()) {\n return defaultWidth;\n }\n\n const terminalWidth = getTerminalWidth();\n return terminalWidth || defaultWidth;\n}\n"],"mappings":";;;;;;;;;;;;;AAeA,SAAgB,aAAsB;AACpC,KAAI;AAEF,aAAW,SAAS,aAElB;OAAI,KAAK,OAAO,WACd,QAAO,KAAK,OAAO,YAAY;EAChC;AAIH,aAAW,YAAY,eAAe,QAAQ,OAC5C,QAAO,QAAQ,QAAQ,OAAO,MAAM;AAItC,aAAW,WAAW,YACpB,QAAO;AAIT,SAAO;CACR,QAAO;AAEN,SAAO;CACR;AACF;;;;;;AAOD,SAAgB,mBAAkC;AAChD,KAAI;AAEF,aAAW,SAAS,aAElB;OAAI,KAAK,aAAa;IACpB,MAAM,OAAO,KAAK,aAAa;AAC/B,WAAO,MAAM,WAAW;GACzB;;AAIH,aAAW,YAAY,eAAe,QAAQ,OAC5C,QAAO,QAAQ,OAAO,WAAW;EAInC,MAAM,oBAAoB,SAAS,cAC/B,KAAK,IAAI,IAAI,UAAU,GACvB,SAAS,KAAK;AAElB,MAAI,YAAY;GACd,MAAM,SAAS,SAAS,YAAY,GAAG;AACvC,UAAO,MAAM,OAAO,GAAG,OAAO;EAC/B;AAED,SAAO;CACR,QAAO;AACN,SAAO;CACR;AACF;;;;;;;AAQD,SAAgB,wBAAwBA,eAAuB,IAAY;AACzE,MAAK,YAAY,CACf,QAAO;CAGT,MAAM,gBAAgB,kBAAkB;AACxC,QAAO,iBAAiB;AACzB"}
package/dist/truncate.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- //#region truncate.ts
2
+ //#region src/truncate.ts
3
3
  /**
4
4
  * Truncates a category array to fit within a maximum width using the specified strategy.
5
5
  *
@@ -1,4 +1,4 @@
1
- //#region truncate.d.ts
1
+ //#region src/truncate.d.ts
2
2
  /**
3
3
  * Truncation strategies for category names.
4
4
  *
@@ -1 +1 @@
1
- {"version":3,"file":"truncate.d.cts","names":[],"sources":["../truncate.ts"],"sourcesContent":[],"mappings":";;AAKA;;;;KAAY,kBAAA"}
1
+ {"version":3,"file":"truncate.d.cts","names":[],"sources":["../src/truncate.ts"],"sourcesContent":[],"mappings":";;AAKA;;;;KAAY,kBAAA"}
@@ -1,4 +1,4 @@
1
- //#region truncate.d.ts
1
+ //#region src/truncate.d.ts
2
2
  /**
3
3
  * Truncation strategies for category names.
4
4
  *
@@ -1 +1 @@
1
- {"version":3,"file":"truncate.d.ts","names":[],"sources":["../truncate.ts"],"sourcesContent":[],"mappings":";;AAKA;;;;KAAY,kBAAA"}
1
+ {"version":3,"file":"truncate.d.ts","names":[],"sources":["../src/truncate.ts"],"sourcesContent":[],"mappings":";;AAKA;;;;KAAY,kBAAA"}
package/dist/truncate.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region truncate.ts
1
+ //#region src/truncate.ts
2
2
  /**
3
3
  * Truncates a category array to fit within a maximum width using the specified strategy.
4
4
  *
@@ -1 +1 @@
1
- {"version":3,"file":"truncate.js","names":["category: readonly string[]","maxWidth: number","separator: string","strategy: TruncationStrategy"],"sources":["../truncate.ts"],"sourcesContent":["/**\n * Truncation strategies for category names.\n *\n * @since 1.0.0\n */\nexport type TruncationStrategy = \"middle\" | \"end\" | false;\n\n/**\n * Truncates a category array to fit within a maximum width using the specified strategy.\n *\n * This function intelligently shortens long hierarchical category names while\n * preserving important context. The truncation behavior depends on the chosen\n * strategy:\n *\n * - `\"middle\"`: Keeps the first and last segments with \"…\" in between\n * - `\"end\"`: Truncates at the end with \"…\" suffix\n * - `false`: No truncation (returns full category string)\n *\n * When the category is too long even for middle truncation (first + \"…\" + last\n * exceeds maxWidth), it falls back to end truncation.\n *\n * @param category The category segments to truncate.\n * @param maxWidth Maximum width for the category string.\n * @param separator Category separator (default: \".\").\n * @param strategy Truncation strategy to use (default: \"middle\").\n * @returns The truncated category string.\n *\n * @example\n * ```typescript\n * // Middle truncation\n * truncateCategory([\"app\", \"server\", \"http\", \"auth\"], 15, \".\", \"middle\");\n * // Returns: \"app…auth\"\n *\n * // End truncation\n * truncateCategory([\"app\", \"server\", \"http\", \"auth\"], 15, \".\", \"end\");\n * // Returns: \"app.server.h…\"\n *\n * // No truncation\n * truncateCategory([\"app\", \"auth\"], 20, \".\", false);\n * // Returns: \"app.auth\"\n * ```\n *\n * @since 1.0.0\n */\nexport function truncateCategory(\n category: readonly string[],\n maxWidth: number,\n separator: string = \".\",\n strategy: TruncationStrategy = \"middle\",\n): string {\n if (!strategy || maxWidth <= 0) {\n return category.join(separator);\n }\n\n const full = category.join(separator);\n if (full.length <= maxWidth) {\n return full;\n }\n\n // Minimum width needed for truncation with ellipsis\n const minWidth = 5; // e.g., \"a…z\"\n if (maxWidth < minWidth) {\n return \"…\";\n }\n\n if (strategy === \"end\") {\n return full.substring(0, maxWidth - 1) + \"…\";\n }\n\n // Middle truncation strategy\n if (category.length <= 2) {\n // For short categories, just truncate the end\n return full.substring(0, maxWidth - 1) + \"…\";\n }\n\n // Try to keep first and last segments\n const first = category[0];\n const last = category[category.length - 1];\n const ellipsis = \"…\";\n\n // Check if we can at least fit first…last\n const minimalLength = first.length + ellipsis.length + last.length;\n if (minimalLength > maxWidth) {\n // Even minimal format is too long, fallback to end truncation\n return full.substring(0, maxWidth - 1) + \"…\";\n }\n\n // For simple case with limited space, just do first…last\n return `${first}${ellipsis}${last}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,SAAgB,iBACdA,UACAC,UACAC,YAAoB,KACpBC,WAA+B,UACvB;AACR,MAAK,YAAY,YAAY,EAC3B,QAAO,SAAS,KAAK,UAAU;CAGjC,MAAM,OAAO,SAAS,KAAK,UAAU;AACrC,KAAI,KAAK,UAAU,SACjB,QAAO;CAIT,MAAM,WAAW;AACjB,KAAI,WAAW,SACb,QAAO;AAGT,KAAI,aAAa,MACf,QAAO,KAAK,UAAU,GAAG,WAAW,EAAE,GAAG;AAI3C,KAAI,SAAS,UAAU,EAErB,QAAO,KAAK,UAAU,GAAG,WAAW,EAAE,GAAG;CAI3C,MAAM,QAAQ,SAAS;CACvB,MAAM,OAAO,SAAS,SAAS,SAAS;CACxC,MAAM,WAAW;CAGjB,MAAM,gBAAgB,MAAM,SAAS,SAAS,SAAS,KAAK;AAC5D,KAAI,gBAAgB,SAElB,QAAO,KAAK,UAAU,GAAG,WAAW,EAAE,GAAG;AAI3C,SAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK;AACnC"}
1
+ {"version":3,"file":"truncate.js","names":["category: readonly string[]","maxWidth: number","separator: string","strategy: TruncationStrategy"],"sources":["../src/truncate.ts"],"sourcesContent":["/**\n * Truncation strategies for category names.\n *\n * @since 1.0.0\n */\nexport type TruncationStrategy = \"middle\" | \"end\" | false;\n\n/**\n * Truncates a category array to fit within a maximum width using the specified strategy.\n *\n * This function intelligently shortens long hierarchical category names while\n * preserving important context. The truncation behavior depends on the chosen\n * strategy:\n *\n * - `\"middle\"`: Keeps the first and last segments with \"…\" in between\n * - `\"end\"`: Truncates at the end with \"…\" suffix\n * - `false`: No truncation (returns full category string)\n *\n * When the category is too long even for middle truncation (first + \"…\" + last\n * exceeds maxWidth), it falls back to end truncation.\n *\n * @param category The category segments to truncate.\n * @param maxWidth Maximum width for the category string.\n * @param separator Category separator (default: \".\").\n * @param strategy Truncation strategy to use (default: \"middle\").\n * @returns The truncated category string.\n *\n * @example\n * ```typescript\n * // Middle truncation\n * truncateCategory([\"app\", \"server\", \"http\", \"auth\"], 15, \".\", \"middle\");\n * // Returns: \"app…auth\"\n *\n * // End truncation\n * truncateCategory([\"app\", \"server\", \"http\", \"auth\"], 15, \".\", \"end\");\n * // Returns: \"app.server.h…\"\n *\n * // No truncation\n * truncateCategory([\"app\", \"auth\"], 20, \".\", false);\n * // Returns: \"app.auth\"\n * ```\n *\n * @since 1.0.0\n */\nexport function truncateCategory(\n category: readonly string[],\n maxWidth: number,\n separator: string = \".\",\n strategy: TruncationStrategy = \"middle\",\n): string {\n if (!strategy || maxWidth <= 0) {\n return category.join(separator);\n }\n\n const full = category.join(separator);\n if (full.length <= maxWidth) {\n return full;\n }\n\n // Minimum width needed for truncation with ellipsis\n const minWidth = 5; // e.g., \"a…z\"\n if (maxWidth < minWidth) {\n return \"…\";\n }\n\n if (strategy === \"end\") {\n return full.substring(0, maxWidth - 1) + \"…\";\n }\n\n // Middle truncation strategy\n if (category.length <= 2) {\n // For short categories, just truncate the end\n return full.substring(0, maxWidth - 1) + \"…\";\n }\n\n // Try to keep first and last segments\n const first = category[0];\n const last = category[category.length - 1];\n const ellipsis = \"…\";\n\n // Check if we can at least fit first…last\n const minimalLength = first.length + ellipsis.length + last.length;\n if (minimalLength > maxWidth) {\n // Even minimal format is too long, fallback to end truncation\n return full.substring(0, maxWidth - 1) + \"…\";\n }\n\n // For simple case with limited space, just do first…last\n return `${first}${ellipsis}${last}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,SAAgB,iBACdA,UACAC,UACAC,YAAoB,KACpBC,WAA+B,UACvB;AACR,MAAK,YAAY,YAAY,EAC3B,QAAO,SAAS,KAAK,UAAU;CAGjC,MAAM,OAAO,SAAS,KAAK,UAAU;AACrC,KAAI,KAAK,UAAU,SACjB,QAAO;CAIT,MAAM,WAAW;AACjB,KAAI,WAAW,SACb,QAAO;AAGT,KAAI,aAAa,MACf,QAAO,KAAK,UAAU,GAAG,WAAW,EAAE,GAAG;AAI3C,KAAI,SAAS,UAAU,EAErB,QAAO,KAAK,UAAU,GAAG,WAAW,EAAE,GAAG;CAI3C,MAAM,QAAQ,SAAS;CACvB,MAAM,OAAO,SAAS,SAAS,SAAS;CACxC,MAAM,WAAW;CAGjB,MAAM,gBAAgB,MAAM,SAAS,SAAS,SAAS,KAAK;AAC5D,KAAI,gBAAgB,SAElB,QAAO,KAAK,UAAU,GAAG,WAAW,EAAE,GAAG;AAI3C,SAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK;AACnC"}
package/dist/util.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- //#region util.ts
2
+ //#region src/util.ts
3
3
  function inspect(obj, options) {
4
4
  const indent = options?.compact === true ? void 0 : 2;
5
5
  return JSON.stringify(obj, null, indent);
package/dist/util.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- //#region util.d.ts
1
+ //#region src/util.d.ts
2
2
  interface InspectOptions {
3
3
  colors?: boolean;
4
4
  depth?: number | null;
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.cts","names":[],"sources":["../util.ts"],"sourcesContent":[],"mappings":";UAAiB,cAAA;EAAA,MAAA,CAAA,EAAA,OAAA;EAOD,KAAA,CAAA,EAAA,MAAO,GAAA,IAAyB;;;;iBAAhC,OAAA,yBAAgC"}
1
+ {"version":3,"file":"util.d.cts","names":[],"sources":["../src/util.ts"],"sourcesContent":[],"mappings":";UAAiB,cAAA;EAAA,MAAA,CAAA,EAAA,OAAA;EAOD,KAAA,CAAA,EAAA,MAAO,GAAA,IAAyB;;;;iBAAhC,OAAA,yBAAgC"}
package/dist/util.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- //#region util.d.ts
1
+ //#region src/util.d.ts
2
2
  interface InspectOptions {
3
3
  colors?: boolean;
4
4
  depth?: number | null;
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","names":[],"sources":["../util.ts"],"sourcesContent":[],"mappings":";UAAiB,cAAA;EAAA,MAAA,CAAA,EAAA,OAAA;EAOD,KAAA,CAAA,EAAA,MAAO,GAAA,IAAyB;;;;iBAAhC,OAAA,yBAAgC"}
1
+ {"version":3,"file":"util.d.ts","names":[],"sources":["../src/util.ts"],"sourcesContent":[],"mappings":";UAAiB,cAAA;EAAA,MAAA,CAAA,EAAA,OAAA;EAOD,KAAA,CAAA,EAAA,MAAO,GAAA,IAAyB;;;;iBAAhC,OAAA,yBAAgC"}
@@ -1,5 +1,5 @@
1
1
 
2
- //#region util.deno.ts
2
+ //#region src/util.deno.ts
3
3
  function inspect(obj, options) {
4
4
  if ("Deno" in globalThis) return Deno.inspect(obj, {
5
5
  colors: options?.colors,
@@ -1,4 +1,4 @@
1
- //#region util.deno.d.ts
1
+ //#region src/util.deno.d.ts
2
2
  interface InspectOptions {
3
3
  colors?: boolean;
4
4
  depth?: number | null;
@@ -1 +1 @@
1
- {"version":3,"file":"util.deno.d.cts","names":[],"sources":["../util.deno.ts"],"sourcesContent":[],"mappings":";UAAiB,cAAA;EAAA,MAAA,CAAA,EAAA,OAAA;EAOD,KAAA,CAAA,EAAA,MAAO,GAAA,IAAyB;;;;iBAAhC,OAAA,yBAAgC"}
1
+ {"version":3,"file":"util.deno.d.cts","names":[],"sources":["../src/util.deno.ts"],"sourcesContent":[],"mappings":";UAAiB,cAAA;EAAA,MAAA,CAAA,EAAA,OAAA;EAOD,KAAA,CAAA,EAAA,MAAO,GAAA,IAAyB;;;;iBAAhC,OAAA,yBAAgC"}
@@ -1,4 +1,4 @@
1
- //#region util.deno.d.ts
1
+ //#region src/util.deno.d.ts
2
2
  interface InspectOptions {
3
3
  colors?: boolean;
4
4
  depth?: number | null;
@@ -1 +1 @@
1
- {"version":3,"file":"util.deno.d.ts","names":[],"sources":["../util.deno.ts"],"sourcesContent":[],"mappings":";UAAiB,cAAA;EAAA,MAAA,CAAA,EAAA,OAAA;EAOD,KAAA,CAAA,EAAA,MAAO,GAAA,IAAyB;;;;iBAAhC,OAAA,yBAAgC"}
1
+ {"version":3,"file":"util.deno.d.ts","names":[],"sources":["../src/util.deno.ts"],"sourcesContent":[],"mappings":";UAAiB,cAAA;EAAA,MAAA,CAAA,EAAA,OAAA;EAOD,KAAA,CAAA,EAAA,MAAO,GAAA,IAAyB;;;;iBAAhC,OAAA,yBAAgC"}
package/dist/util.deno.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region util.deno.ts
1
+ //#region src/util.deno.ts
2
2
  function inspect(obj, options) {
3
3
  if ("Deno" in globalThis) return Deno.inspect(obj, {
4
4
  colors: options?.colors,
@@ -1 +1 @@
1
- {"version":3,"file":"util.deno.js","names":["obj: unknown","options?: InspectOptions"],"sources":["../util.deno.ts"],"sourcesContent":["export interface InspectOptions {\n colors?: boolean;\n depth?: number | null;\n compact?: boolean;\n [key: string]: unknown;\n}\n\nexport function inspect(obj: unknown, options?: InspectOptions): string {\n if (\"Deno\" in globalThis) {\n return Deno.inspect(obj, {\n colors: options?.colors,\n depth: options?.depth ?? undefined,\n compact: options?.compact ?? true,\n });\n } else {\n const indent = options?.compact === true ? undefined : 2;\n return JSON.stringify(obj, null, indent);\n }\n}\n"],"mappings":";AAOA,SAAgB,QAAQA,KAAcC,SAAkC;AACtE,KAAI,UAAU,WACZ,QAAO,KAAK,QAAQ,KAAK;EACvB,QAAQ,SAAS;EACjB,OAAO,SAAS;EAChB,SAAS,SAAS,WAAW;CAC9B,EAAC;MACG;EACL,MAAM,SAAS,SAAS,YAAY,gBAAmB;AACvD,SAAO,KAAK,UAAU,KAAK,MAAM,OAAO;CACzC;AACF"}
1
+ {"version":3,"file":"util.deno.js","names":["obj: unknown","options?: InspectOptions"],"sources":["../src/util.deno.ts"],"sourcesContent":["export interface InspectOptions {\n colors?: boolean;\n depth?: number | null;\n compact?: boolean;\n [key: string]: unknown;\n}\n\nexport function inspect(obj: unknown, options?: InspectOptions): string {\n if (\"Deno\" in globalThis) {\n return Deno.inspect(obj, {\n colors: options?.colors,\n depth: options?.depth ?? undefined,\n compact: options?.compact ?? true,\n });\n } else {\n const indent = options?.compact === true ? undefined : 2;\n return JSON.stringify(obj, null, indent);\n }\n}\n"],"mappings":";AAOA,SAAgB,QAAQA,KAAcC,SAAkC;AACtE,KAAI,UAAU,WACZ,QAAO,KAAK,QAAQ,KAAK;EACvB,QAAQ,SAAS;EACjB,OAAO,SAAS;EAChB,SAAS,SAAS,WAAW;CAC9B,EAAC;MACG;EACL,MAAM,SAAS,SAAS,YAAY,gBAAmB;AACvD,SAAO,KAAK,UAAU,KAAK,MAAM,OAAO;CACzC;AACF"}
package/dist/util.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region util.ts
1
+ //#region src/util.ts
2
2
  function inspect(obj, options) {
3
3
  const indent = options?.compact === true ? void 0 : 2;
4
4
  return JSON.stringify(obj, null, indent);
package/dist/util.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"util.js","names":["obj: unknown","options?: InspectOptions"],"sources":["../util.ts"],"sourcesContent":["export interface InspectOptions {\n colors?: boolean;\n depth?: number | null;\n compact?: boolean;\n [key: string]: unknown;\n}\n\nexport function inspect(obj: unknown, options?: InspectOptions): string {\n const indent = options?.compact === true ? undefined : 2;\n return JSON.stringify(obj, null, indent);\n}\n"],"mappings":";AAOA,SAAgB,QAAQA,KAAcC,SAAkC;CACtE,MAAM,SAAS,SAAS,YAAY,gBAAmB;AACvD,QAAO,KAAK,UAAU,KAAK,MAAM,OAAO;AACzC"}
1
+ {"version":3,"file":"util.js","names":["obj: unknown","options?: InspectOptions"],"sources":["../src/util.ts"],"sourcesContent":["export interface InspectOptions {\n colors?: boolean;\n depth?: number | null;\n compact?: boolean;\n [key: string]: unknown;\n}\n\nexport function inspect(obj: unknown, options?: InspectOptions): string {\n const indent = options?.compact === true ? undefined : 2;\n return JSON.stringify(obj, null, indent);\n}\n"],"mappings":";AAOA,SAAgB,QAAQA,KAAcC,SAAkC;CACtE,MAAM,SAAS,SAAS,YAAY,gBAAmB;AACvD,QAAO,KAAK,UAAU,KAAK,MAAM,OAAO;AACzC"}
@@ -1,7 +1,7 @@
1
1
  const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
2
  const node_util = require_rolldown_runtime.__toESM(require("node:util"));
3
3
 
4
- //#region util.node.ts
4
+ //#region src/util.node.ts
5
5
  function inspect(obj, options) {
6
6
  return node_util.default.inspect(obj, options);
7
7
  }
@@ -1,4 +1,4 @@
1
- //#region util.node.d.ts
1
+ //#region src/util.node.d.ts
2
2
  interface InspectOptions {
3
3
  colors?: boolean;
4
4
  depth?: number | null;
@@ -1 +1 @@
1
- {"version":3,"file":"util.node.d.cts","names":[],"sources":["../util.node.ts"],"sourcesContent":[],"mappings":";UAEiB,cAAA;EAAA,MAAA,CAAA,EAAA,OAAA;EAOD,KAAA,CAAA,EAAA,MAAO,GAAA,IAAyB;;;;iBAAhC,OAAA,yBAAgC"}
1
+ {"version":3,"file":"util.node.d.cts","names":[],"sources":["../src/util.node.ts"],"sourcesContent":[],"mappings":";UAEiB,cAAA;EAAA,MAAA,CAAA,EAAA,OAAA;EAOD,KAAA,CAAA,EAAA,MAAO,GAAA,IAAyB;;;;iBAAhC,OAAA,yBAAgC"}
@@ -1,4 +1,4 @@
1
- //#region util.node.d.ts
1
+ //#region src/util.node.d.ts
2
2
  interface InspectOptions {
3
3
  colors?: boolean;
4
4
  depth?: number | null;
@@ -1 +1 @@
1
- {"version":3,"file":"util.node.d.ts","names":[],"sources":["../util.node.ts"],"sourcesContent":[],"mappings":";UAEiB,cAAA;EAAA,MAAA,CAAA,EAAA,OAAA;EAOD,KAAA,CAAA,EAAA,MAAO,GAAA,IAAyB;;;;iBAAhC,OAAA,yBAAgC"}
1
+ {"version":3,"file":"util.node.d.ts","names":[],"sources":["../src/util.node.ts"],"sourcesContent":[],"mappings":";UAEiB,cAAA;EAAA,MAAA,CAAA,EAAA,OAAA;EAOD,KAAA,CAAA,EAAA,MAAO,GAAA,IAAyB;;;;iBAAhC,OAAA,yBAAgC"}
package/dist/util.node.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import util from "node:util";
2
2
 
3
- //#region util.node.ts
3
+ //#region src/util.node.ts
4
4
  function inspect(obj, options) {
5
5
  return util.inspect(obj, options);
6
6
  }
@@ -1 +1 @@
1
- {"version":3,"file":"util.node.js","names":["obj: unknown","options?: InspectOptions"],"sources":["../util.node.ts"],"sourcesContent":["import util from \"node:util\";\n\nexport interface InspectOptions {\n colors?: boolean;\n depth?: number | null;\n compact?: boolean;\n [key: string]: unknown;\n}\n\nexport function inspect(obj: unknown, options?: InspectOptions): string {\n return util.inspect(obj, options);\n}\n"],"mappings":";;;AASA,SAAgB,QAAQA,KAAcC,SAAkC;AACtE,QAAO,KAAK,QAAQ,KAAK,QAAQ;AAClC"}
1
+ {"version":3,"file":"util.node.js","names":["obj: unknown","options?: InspectOptions"],"sources":["../src/util.node.ts"],"sourcesContent":["import util from \"node:util\";\n\nexport interface InspectOptions {\n colors?: boolean;\n depth?: number | null;\n compact?: boolean;\n [key: string]: unknown;\n}\n\nexport function inspect(obj: unknown, options?: InspectOptions): string {\n return util.inspect(obj, options);\n}\n"],"mappings":";;;AASA,SAAgB,QAAQA,KAAcC,SAAkC;AACtE,QAAO,KAAK,QAAQ,KAAK,QAAQ;AAClC"}
package/dist/wcwidth.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- //#region wcwidth.ts
2
+ //#region src/wcwidth.ts
3
3
  /**
4
4
  * @fileoverview
5
5
  * wcwidth implementation for JavaScript/TypeScript
package/dist/wcwidth.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region wcwidth.ts
1
+ //#region src/wcwidth.ts
2
2
  /**
3
3
  * @fileoverview
4
4
  * wcwidth implementation for JavaScript/TypeScript
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"wcwidth.js","names":["text: string","code: number","ZERO_WIDTH_RANGES: Array<[number, number]>","ranges: Array<[number, number]>"],"sources":["../src/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/dist/wordwrap.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  const require_wcwidth = require('./wcwidth.cjs');
2
2
 
3
- //#region wordwrap.ts
3
+ //#region src/wordwrap.ts
4
4
  /**
5
5
  * Wrap text at specified width with proper indentation for continuation lines.
6
6
  * Automatically detects the message start position from the first line.
package/dist/wordwrap.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { getDisplayWidth } from "./wcwidth.js";
2
2
 
3
- //#region wordwrap.ts
3
+ //#region src/wordwrap.ts
4
4
  /**
5
5
  * Wrap text at specified width with proper indentation for continuation lines.
6
6
  * Automatically detects the message start position from the first line.
@@ -1 +1 @@
1
- {"version":3,"file":"wordwrap.js","names":["text: string","maxWidth: number","indentWidth: number","wrappedLines: string[]","indent: string","lines: string[]"],"sources":["../wordwrap.ts"],"sourcesContent":["/**\n * @fileoverview\n * Word wrapping utilities for terminal output\n *\n * This module provides functions for wrapping text at specified widths\n * while preserving proper indentation and handling Unicode characters\n * correctly.\n */\n\nimport { getDisplayWidth } from \"./wcwidth.ts\";\n\n/**\n * Wrap text at specified width with proper indentation for continuation lines.\n * Automatically detects the message start position from the first line.\n *\n * @param text The text to wrap (may contain ANSI escape codes)\n * @param maxWidth Maximum width in terminal columns\n * @param indentWidth Indentation width for continuation lines\n * @returns Wrapped text with proper indentation\n */\nexport function wrapText(\n text: string,\n maxWidth: number,\n indentWidth: number,\n): string {\n if (maxWidth <= 0) return text;\n\n const displayWidth = getDisplayWidth(text);\n // If text has newlines (multiline interpolated values), always process it\n // even if it fits within the width\n if (displayWidth <= maxWidth && !text.includes(\"\\n\")) return text;\n\n const indent = \" \".repeat(Math.max(0, indentWidth));\n\n // Check if text contains newlines (from interpolated values like Error objects)\n if (text.includes(\"\\n\")) {\n // Split by existing newlines and process each line\n const lines = text.split(\"\\n\");\n const wrappedLines: string[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const lineDisplayWidth = getDisplayWidth(line);\n\n if (lineDisplayWidth <= maxWidth) {\n // Line doesn't need wrapping, but add indentation if it's not the first line\n if (i === 0) {\n wrappedLines.push(line);\n } else {\n wrappedLines.push(indent + line);\n }\n } else {\n // Line needs wrapping\n const wrappedLine = wrapSingleLine(line, maxWidth, indent);\n if (i === 0) {\n wrappedLines.push(wrappedLine);\n } else {\n // For continuation lines from interpolated values, add proper indentation\n const subLines = wrappedLine.split(\"\\n\");\n for (let j = 0; j < subLines.length; j++) {\n if (j === 0) {\n wrappedLines.push(indent + subLines[j]);\n } else {\n wrappedLines.push(subLines[j]);\n }\n }\n }\n }\n }\n\n return wrappedLines.join(\"\\n\");\n }\n\n // Process as a single line since log records should not have newlines in the formatted output\n return wrapSingleLine(text, maxWidth, indent);\n}\n\n/**\n * Wrap a single line of text (without existing newlines) at word boundaries.\n * Preserves ANSI escape codes and handles Unicode character widths correctly.\n *\n * @param text The text to wrap (single line, may contain ANSI codes)\n * @param maxWidth Maximum width in terminal columns\n * @param indent Indentation string for continuation lines\n * @returns Wrapped text with newlines and proper indentation\n */\nexport function wrapSingleLine(\n text: string,\n maxWidth: number,\n indent: string,\n): string {\n // Split text into chunks while preserving ANSI codes\n const lines: string[] = [];\n let currentLine = \"\";\n let currentDisplayWidth = 0;\n let i = 0;\n\n while (i < text.length) {\n // Check for ANSI escape sequence\n if (text[i] === \"\\x1b\" && text[i + 1] === \"[\") {\n // Find the end of the ANSI sequence\n let j = i + 2;\n while (j < text.length && text[j] !== \"m\") {\n j++;\n }\n if (j < text.length) {\n j++; // Include the 'm'\n currentLine += text.slice(i, j);\n i = j;\n continue;\n }\n }\n\n const char = text[i];\n\n // Check if adding this character would exceed the width\n if (currentDisplayWidth >= maxWidth && char !== \" \") {\n // Try to find a good break point (space) before the current position\n const breakPoint = currentLine.lastIndexOf(\" \");\n if (breakPoint > 0) {\n // Break at the space\n lines.push(currentLine.slice(0, breakPoint));\n currentLine = indent + currentLine.slice(breakPoint + 1) + char;\n currentDisplayWidth = getDisplayWidth(currentLine);\n } else {\n // No space found, hard break\n lines.push(currentLine);\n currentLine = indent + char;\n currentDisplayWidth = getDisplayWidth(currentLine);\n }\n } else {\n currentLine += char;\n // Recalculate display width properly for Unicode characters\n currentDisplayWidth = getDisplayWidth(currentLine);\n }\n\n i++;\n }\n\n if (currentLine.trim()) {\n lines.push(currentLine);\n }\n\n // Filter out empty lines (lines with only indentation/spaces)\n const filteredLines = lines.filter((line) => line.trim().length > 0);\n\n return filteredLines.join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;;AAoBA,SAAgB,SACdA,MACAC,UACAC,aACQ;AACR,KAAI,YAAY,EAAG,QAAO;CAE1B,MAAM,eAAe,gBAAgB,KAAK;AAG1C,KAAI,gBAAgB,aAAa,KAAK,SAAS,KAAK,CAAE,QAAO;CAE7D,MAAM,SAAS,IAAI,OAAO,KAAK,IAAI,GAAG,YAAY,CAAC;AAGnD,KAAI,KAAK,SAAS,KAAK,EAAE;EAEvB,MAAM,QAAQ,KAAK,MAAM,KAAK;EAC9B,MAAMC,eAAyB,CAAE;AAEjC,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,OAAO,MAAM;GACnB,MAAM,mBAAmB,gBAAgB,KAAK;AAE9C,OAAI,oBAAoB,SAEtB,KAAI,MAAM,EACR,cAAa,KAAK,KAAK;OAEvB,cAAa,KAAK,SAAS,KAAK;QAE7B;IAEL,MAAM,cAAc,eAAe,MAAM,UAAU,OAAO;AAC1D,QAAI,MAAM,EACR,cAAa,KAAK,YAAY;SACzB;KAEL,MAAM,WAAW,YAAY,MAAM,KAAK;AACxC,UAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,IACnC,KAAI,MAAM,EACR,cAAa,KAAK,SAAS,SAAS,GAAG;SAEvC,cAAa,KAAK,SAAS,GAAG;IAGnC;GACF;EACF;AAED,SAAO,aAAa,KAAK,KAAK;CAC/B;AAGD,QAAO,eAAe,MAAM,UAAU,OAAO;AAC9C;;;;;;;;;;AAWD,SAAgB,eACdH,MACAC,UACAG,QACQ;CAER,MAAMC,QAAkB,CAAE;CAC1B,IAAI,cAAc;CAClB,IAAI,sBAAsB;CAC1B,IAAI,IAAI;AAER,QAAO,IAAI,KAAK,QAAQ;AAEtB,MAAI,KAAK,OAAO,UAAU,KAAK,IAAI,OAAO,KAAK;GAE7C,IAAI,IAAI,IAAI;AACZ,UAAO,IAAI,KAAK,UAAU,KAAK,OAAO,IACpC;AAEF,OAAI,IAAI,KAAK,QAAQ;AACnB;AACA,mBAAe,KAAK,MAAM,GAAG,EAAE;AAC/B,QAAI;AACJ;GACD;EACF;EAED,MAAM,OAAO,KAAK;AAGlB,MAAI,uBAAuB,YAAY,SAAS,KAAK;GAEnD,MAAM,aAAa,YAAY,YAAY,IAAI;AAC/C,OAAI,aAAa,GAAG;AAElB,UAAM,KAAK,YAAY,MAAM,GAAG,WAAW,CAAC;AAC5C,kBAAc,SAAS,YAAY,MAAM,aAAa,EAAE,GAAG;AAC3D,0BAAsB,gBAAgB,YAAY;GACnD,OAAM;AAEL,UAAM,KAAK,YAAY;AACvB,kBAAc,SAAS;AACvB,0BAAsB,gBAAgB,YAAY;GACnD;EACF,OAAM;AACL,kBAAe;AAEf,yBAAsB,gBAAgB,YAAY;EACnD;AAED;CACD;AAED,KAAI,YAAY,MAAM,CACpB,OAAM,KAAK,YAAY;CAIzB,MAAM,gBAAgB,MAAM,OAAO,CAAC,SAAS,KAAK,MAAM,CAAC,SAAS,EAAE;AAEpE,QAAO,cAAc,KAAK,KAAK;AAChC"}
1
+ {"version":3,"file":"wordwrap.js","names":["text: string","maxWidth: number","indentWidth: number","wrappedLines: string[]","indent: string","lines: string[]"],"sources":["../src/wordwrap.ts"],"sourcesContent":["/**\n * @fileoverview\n * Word wrapping utilities for terminal output\n *\n * This module provides functions for wrapping text at specified widths\n * while preserving proper indentation and handling Unicode characters\n * correctly.\n */\n\nimport { getDisplayWidth } from \"./wcwidth.ts\";\n\n/**\n * Wrap text at specified width with proper indentation for continuation lines.\n * Automatically detects the message start position from the first line.\n *\n * @param text The text to wrap (may contain ANSI escape codes)\n * @param maxWidth Maximum width in terminal columns\n * @param indentWidth Indentation width for continuation lines\n * @returns Wrapped text with proper indentation\n */\nexport function wrapText(\n text: string,\n maxWidth: number,\n indentWidth: number,\n): string {\n if (maxWidth <= 0) return text;\n\n const displayWidth = getDisplayWidth(text);\n // If text has newlines (multiline interpolated values), always process it\n // even if it fits within the width\n if (displayWidth <= maxWidth && !text.includes(\"\\n\")) return text;\n\n const indent = \" \".repeat(Math.max(0, indentWidth));\n\n // Check if text contains newlines (from interpolated values like Error objects)\n if (text.includes(\"\\n\")) {\n // Split by existing newlines and process each line\n const lines = text.split(\"\\n\");\n const wrappedLines: string[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n const lineDisplayWidth = getDisplayWidth(line);\n\n if (lineDisplayWidth <= maxWidth) {\n // Line doesn't need wrapping, but add indentation if it's not the first line\n if (i === 0) {\n wrappedLines.push(line);\n } else {\n wrappedLines.push(indent + line);\n }\n } else {\n // Line needs wrapping\n const wrappedLine = wrapSingleLine(line, maxWidth, indent);\n if (i === 0) {\n wrappedLines.push(wrappedLine);\n } else {\n // For continuation lines from interpolated values, add proper indentation\n const subLines = wrappedLine.split(\"\\n\");\n for (let j = 0; j < subLines.length; j++) {\n if (j === 0) {\n wrappedLines.push(indent + subLines[j]);\n } else {\n wrappedLines.push(subLines[j]);\n }\n }\n }\n }\n }\n\n return wrappedLines.join(\"\\n\");\n }\n\n // Process as a single line since log records should not have newlines in the formatted output\n return wrapSingleLine(text, maxWidth, indent);\n}\n\n/**\n * Wrap a single line of text (without existing newlines) at word boundaries.\n * Preserves ANSI escape codes and handles Unicode character widths correctly.\n *\n * @param text The text to wrap (single line, may contain ANSI codes)\n * @param maxWidth Maximum width in terminal columns\n * @param indent Indentation string for continuation lines\n * @returns Wrapped text with newlines and proper indentation\n */\nexport function wrapSingleLine(\n text: string,\n maxWidth: number,\n indent: string,\n): string {\n // Split text into chunks while preserving ANSI codes\n const lines: string[] = [];\n let currentLine = \"\";\n let currentDisplayWidth = 0;\n let i = 0;\n\n while (i < text.length) {\n // Check for ANSI escape sequence\n if (text[i] === \"\\x1b\" && text[i + 1] === \"[\") {\n // Find the end of the ANSI sequence\n let j = i + 2;\n while (j < text.length && text[j] !== \"m\") {\n j++;\n }\n if (j < text.length) {\n j++; // Include the 'm'\n currentLine += text.slice(i, j);\n i = j;\n continue;\n }\n }\n\n const char = text[i];\n\n // Check if adding this character would exceed the width\n if (currentDisplayWidth >= maxWidth && char !== \" \") {\n // Try to find a good break point (space) before the current position\n const breakPoint = currentLine.lastIndexOf(\" \");\n if (breakPoint > 0) {\n // Break at the space\n lines.push(currentLine.slice(0, breakPoint));\n currentLine = indent + currentLine.slice(breakPoint + 1) + char;\n currentDisplayWidth = getDisplayWidth(currentLine);\n } else {\n // No space found, hard break\n lines.push(currentLine);\n currentLine = indent + char;\n currentDisplayWidth = getDisplayWidth(currentLine);\n }\n } else {\n currentLine += char;\n // Recalculate display width properly for Unicode characters\n currentDisplayWidth = getDisplayWidth(currentLine);\n }\n\n i++;\n }\n\n if (currentLine.trim()) {\n lines.push(currentLine);\n }\n\n // Filter out empty lines (lines with only indentation/spaces)\n const filteredLines = lines.filter((line) => line.trim().length > 0);\n\n return filteredLines.join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;;AAoBA,SAAgB,SACdA,MACAC,UACAC,aACQ;AACR,KAAI,YAAY,EAAG,QAAO;CAE1B,MAAM,eAAe,gBAAgB,KAAK;AAG1C,KAAI,gBAAgB,aAAa,KAAK,SAAS,KAAK,CAAE,QAAO;CAE7D,MAAM,SAAS,IAAI,OAAO,KAAK,IAAI,GAAG,YAAY,CAAC;AAGnD,KAAI,KAAK,SAAS,KAAK,EAAE;EAEvB,MAAM,QAAQ,KAAK,MAAM,KAAK;EAC9B,MAAMC,eAAyB,CAAE;AAEjC,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,OAAO,MAAM;GACnB,MAAM,mBAAmB,gBAAgB,KAAK;AAE9C,OAAI,oBAAoB,SAEtB,KAAI,MAAM,EACR,cAAa,KAAK,KAAK;OAEvB,cAAa,KAAK,SAAS,KAAK;QAE7B;IAEL,MAAM,cAAc,eAAe,MAAM,UAAU,OAAO;AAC1D,QAAI,MAAM,EACR,cAAa,KAAK,YAAY;SACzB;KAEL,MAAM,WAAW,YAAY,MAAM,KAAK;AACxC,UAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,IACnC,KAAI,MAAM,EACR,cAAa,KAAK,SAAS,SAAS,GAAG;SAEvC,cAAa,KAAK,SAAS,GAAG;IAGnC;GACF;EACF;AAED,SAAO,aAAa,KAAK,KAAK;CAC/B;AAGD,QAAO,eAAe,MAAM,UAAU,OAAO;AAC9C;;;;;;;;;;AAWD,SAAgB,eACdH,MACAC,UACAG,QACQ;CAER,MAAMC,QAAkB,CAAE;CAC1B,IAAI,cAAc;CAClB,IAAI,sBAAsB;CAC1B,IAAI,IAAI;AAER,QAAO,IAAI,KAAK,QAAQ;AAEtB,MAAI,KAAK,OAAO,UAAU,KAAK,IAAI,OAAO,KAAK;GAE7C,IAAI,IAAI,IAAI;AACZ,UAAO,IAAI,KAAK,UAAU,KAAK,OAAO,IACpC;AAEF,OAAI,IAAI,KAAK,QAAQ;AACnB;AACA,mBAAe,KAAK,MAAM,GAAG,EAAE;AAC/B,QAAI;AACJ;GACD;EACF;EAED,MAAM,OAAO,KAAK;AAGlB,MAAI,uBAAuB,YAAY,SAAS,KAAK;GAEnD,MAAM,aAAa,YAAY,YAAY,IAAI;AAC/C,OAAI,aAAa,GAAG;AAElB,UAAM,KAAK,YAAY,MAAM,GAAG,WAAW,CAAC;AAC5C,kBAAc,SAAS,YAAY,MAAM,aAAa,EAAE,GAAG;AAC3D,0BAAsB,gBAAgB,YAAY;GACnD,OAAM;AAEL,UAAM,KAAK,YAAY;AACvB,kBAAc,SAAS;AACvB,0BAAsB,gBAAgB,YAAY;GACnD;EACF,OAAM;AACL,kBAAe;AAEf,yBAAsB,gBAAgB,YAAY;EACnD;AAED;CACD;AAED,KAAI,YAAY,MAAM,CACpB,OAAM,KAAK,YAAY;CAIzB,MAAM,gBAAgB,MAAM,OAAO,CAAC,SAAS,KAAK,MAAM,CAAC,SAAS,EAAE;AAEpE,QAAO,cAAc,KAAK,KAAK;AAChC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logtape/pretty",
3
- "version": "1.1.0-dev.315+fc46f65c",
3
+ "version": "1.1.0-dev.323+146f8194",
4
4
  "description": "Beautiful text formatter for LogTape—perfect for local development",
5
5
  "keywords": [
6
6
  "logging",
@@ -26,7 +26,7 @@
26
26
  "repository": {
27
27
  "type": "git",
28
28
  "url": "git+https://github.com/dahlia/logtape.git",
29
- "directory": "pretty/"
29
+ "directory": "packages/pretty/"
30
30
  },
31
31
  "bugs": {
32
32
  "url": "https://github.com/dahlia/logtape/issues"
@@ -75,7 +75,7 @@
75
75
  },
76
76
  "sideEffects": false,
77
77
  "peerDependencies": {
78
- "@logtape/logtape": "1.1.0-dev.315+fc46f65c"
78
+ "@logtape/logtape": "1.1.0-dev.323+146f8194"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@alinea/suite": "^0.6.3",
package/tsdown.config.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { defineConfig } from "tsdown";
2
2
 
3
3
  export default defineConfig({
4
- entry: ["mod.ts", "util.ts", "util.deno.ts", "util.node.ts"],
4
+ entry: ["src/mod.ts", "src/util.ts", "src/util.deno.ts", "src/util.node.ts"],
5
5
  dts: {
6
6
  sourcemap: true,
7
7
  },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes