@logtape/logtape 0.11.0 → 0.12.0-dev.182

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 (171) hide show
  1. package/config.test.ts +591 -0
  2. package/config.ts +421 -0
  3. package/context.test.ts +187 -0
  4. package/context.ts +55 -0
  5. package/deno.json +36 -0
  6. package/dist/_virtual/rolldown_runtime.cjs +30 -0
  7. package/dist/config.cjs +247 -0
  8. package/dist/config.d.cts +189 -0
  9. package/dist/config.d.cts.map +1 -0
  10. package/dist/config.d.ts +189 -0
  11. package/dist/config.d.ts.map +1 -0
  12. package/dist/config.js +241 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/context.cjs +30 -0
  15. package/dist/context.d.cts +39 -0
  16. package/dist/context.d.cts.map +1 -0
  17. package/dist/context.d.ts +39 -0
  18. package/dist/context.d.ts.map +1 -0
  19. package/dist/context.js +31 -0
  20. package/dist/context.js.map +1 -0
  21. package/dist/filter.cjs +32 -0
  22. package/dist/filter.d.cts +37 -0
  23. package/dist/filter.d.cts.map +1 -0
  24. package/{types → dist}/filter.d.ts +12 -6
  25. package/dist/filter.d.ts.map +1 -0
  26. package/dist/filter.js +31 -0
  27. package/dist/filter.js.map +1 -0
  28. package/dist/formatter.cjs +281 -0
  29. package/dist/formatter.d.cts +338 -0
  30. package/dist/formatter.d.cts.map +1 -0
  31. package/dist/formatter.d.ts +338 -0
  32. package/dist/formatter.d.ts.map +1 -0
  33. package/dist/formatter.js +275 -0
  34. package/dist/formatter.js.map +1 -0
  35. package/dist/level.cjs +64 -0
  36. package/dist/level.d.cts +34 -0
  37. package/dist/level.d.cts.map +1 -0
  38. package/{types → dist}/level.d.ts +7 -5
  39. package/dist/level.d.ts.map +1 -0
  40. package/dist/level.js +62 -0
  41. package/dist/level.js.map +1 -0
  42. package/dist/logger.cjs +351 -0
  43. package/dist/logger.d.cts +501 -0
  44. package/dist/logger.d.cts.map +1 -0
  45. package/dist/logger.d.ts +501 -0
  46. package/dist/logger.d.ts.map +1 -0
  47. package/dist/logger.js +351 -0
  48. package/dist/logger.js.map +1 -0
  49. package/dist/mod.cjs +33 -0
  50. package/dist/mod.d.cts +9 -0
  51. package/dist/mod.d.ts +9 -0
  52. package/dist/mod.js +9 -0
  53. package/dist/record.d.cts +50 -0
  54. package/dist/record.d.cts.map +1 -0
  55. package/dist/record.d.ts +50 -0
  56. package/dist/record.d.ts.map +1 -0
  57. package/dist/sink.cjs +95 -0
  58. package/dist/sink.d.cts +112 -0
  59. package/dist/sink.d.cts.map +1 -0
  60. package/{types → dist}/sink.d.ts +49 -45
  61. package/dist/sink.d.ts.map +1 -0
  62. package/dist/sink.js +94 -0
  63. package/dist/sink.js.map +1 -0
  64. package/dist/util.cjs +9 -0
  65. package/dist/util.d.cts +12 -0
  66. package/dist/util.d.cts.map +1 -0
  67. package/dist/util.d.ts +12 -0
  68. package/dist/util.d.ts.map +1 -0
  69. package/dist/util.deno.cjs +16 -0
  70. package/dist/util.deno.d.cts +12 -0
  71. package/dist/util.deno.d.cts.map +1 -0
  72. package/dist/util.deno.d.ts +12 -0
  73. package/dist/util.deno.d.ts.map +1 -0
  74. package/dist/util.deno.js +16 -0
  75. package/dist/util.deno.js.map +1 -0
  76. package/dist/util.js +9 -0
  77. package/dist/util.js.map +1 -0
  78. package/dist/util.node.cjs +10 -0
  79. package/dist/util.node.d.cts +12 -0
  80. package/dist/util.node.d.cts.map +1 -0
  81. package/dist/util.node.d.ts +12 -0
  82. package/dist/util.node.d.ts.map +1 -0
  83. package/dist/util.node.js +10 -0
  84. package/dist/util.node.js.map +1 -0
  85. package/filter.test.ts +70 -0
  86. package/filter.ts +57 -0
  87. package/fixtures.ts +30 -0
  88. package/formatter.test.ts +530 -0
  89. package/formatter.ts +724 -0
  90. package/level.test.ts +47 -0
  91. package/level.ts +67 -0
  92. package/logger.test.ts +823 -0
  93. package/logger.ts +1124 -0
  94. package/mod.ts +54 -0
  95. package/package.json +35 -23
  96. package/record.ts +49 -0
  97. package/sink.test.ts +219 -0
  98. package/sink.ts +167 -0
  99. package/tsdown.config.ts +24 -0
  100. package/util.deno.ts +19 -0
  101. package/util.node.ts +12 -0
  102. package/util.ts +11 -0
  103. package/esm/_dnt.shims.js +0 -57
  104. package/esm/config.js +0 -297
  105. package/esm/context.js +0 -23
  106. package/esm/filter.js +0 -42
  107. package/esm/formatter.js +0 -370
  108. package/esm/level.js +0 -59
  109. package/esm/logger.js +0 -517
  110. package/esm/mod.js +0 -8
  111. package/esm/nodeUtil.cjs +0 -20
  112. package/esm/nodeUtil.js +0 -2
  113. package/esm/package.json +0 -3
  114. package/esm/record.js +0 -1
  115. package/esm/sink.js +0 -96
  116. package/script/_dnt.shims.js +0 -60
  117. package/script/config.js +0 -331
  118. package/script/context.js +0 -26
  119. package/script/filter.js +0 -46
  120. package/script/formatter.js +0 -380
  121. package/script/level.js +0 -64
  122. package/script/logger.js +0 -548
  123. package/script/mod.js +0 -36
  124. package/script/nodeUtil.js +0 -20
  125. package/script/package.json +0 -3
  126. package/script/record.js +0 -2
  127. package/script/sink.js +0 -101
  128. package/types/_dnt.shims.d.ts +0 -2
  129. package/types/_dnt.shims.d.ts.map +0 -1
  130. package/types/_dnt.test_shims.d.ts.map +0 -1
  131. package/types/config.d.ts +0 -183
  132. package/types/config.d.ts.map +0 -1
  133. package/types/config.test.d.ts.map +0 -1
  134. package/types/context.d.ts +0 -35
  135. package/types/context.d.ts.map +0 -1
  136. package/types/context.test.d.ts.map +0 -1
  137. package/types/deps/jsr.io/@std/assert/0.222.1/_constants.d.ts.map +0 -1
  138. package/types/deps/jsr.io/@std/assert/0.222.1/_diff.d.ts.map +0 -1
  139. package/types/deps/jsr.io/@std/assert/0.222.1/_format.d.ts.map +0 -1
  140. package/types/deps/jsr.io/@std/assert/0.222.1/assert.d.ts.map +0 -1
  141. package/types/deps/jsr.io/@std/assert/0.222.1/assert_equals.d.ts.map +0 -1
  142. package/types/deps/jsr.io/@std/assert/0.222.1/assert_false.d.ts.map +0 -1
  143. package/types/deps/jsr.io/@std/assert/0.222.1/assert_greater_or_equal.d.ts.map +0 -1
  144. package/types/deps/jsr.io/@std/assert/0.222.1/assert_is_error.d.ts.map +0 -1
  145. package/types/deps/jsr.io/@std/assert/0.222.1/assert_less_or_equal.d.ts.map +0 -1
  146. package/types/deps/jsr.io/@std/assert/0.222.1/assert_rejects.d.ts.map +0 -1
  147. package/types/deps/jsr.io/@std/assert/0.222.1/assert_strict_equals.d.ts.map +0 -1
  148. package/types/deps/jsr.io/@std/assert/0.222.1/assert_throws.d.ts.map +0 -1
  149. package/types/deps/jsr.io/@std/assert/0.222.1/assertion_error.d.ts.map +0 -1
  150. package/types/deps/jsr.io/@std/assert/0.222.1/equal.d.ts.map +0 -1
  151. package/types/deps/jsr.io/@std/async/0.222.1/delay.d.ts.map +0 -1
  152. package/types/deps/jsr.io/@std/fmt/0.222.1/colors.d.ts.map +0 -1
  153. package/types/filter.d.ts.map +0 -1
  154. package/types/filter.test.d.ts.map +0 -1
  155. package/types/fixtures.d.ts.map +0 -1
  156. package/types/formatter.d.ts +0 -332
  157. package/types/formatter.d.ts.map +0 -1
  158. package/types/formatter.test.d.ts.map +0 -1
  159. package/types/level.d.ts.map +0 -1
  160. package/types/level.test.d.ts.map +0 -1
  161. package/types/logger.d.ts +0 -573
  162. package/types/logger.d.ts.map +0 -1
  163. package/types/logger.test.d.ts.map +0 -1
  164. package/types/mod.d.ts +0 -9
  165. package/types/mod.d.ts.map +0 -1
  166. package/types/nodeUtil.d.ts +0 -12
  167. package/types/nodeUtil.d.ts.map +0 -1
  168. package/types/record.d.ts +0 -44
  169. package/types/record.d.ts.map +0 -1
  170. package/types/sink.d.ts.map +0 -1
  171. package/types/sink.test.d.ts.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.js","names":["levelAbbreviations: Record<LogLevel, string>","inspect: (value: unknown, options?: { colors?: boolean }) => string","options: TextFormatterOptions","ts: number","level: LogLevel","formatter: (values: FormattedValues) => string","record: LogRecord","values: FormattedValues","defaultTextFormatter: TextFormatter","ansiColors: Record<AnsiColor, string>","ansiStyles: Record<AnsiStyle, string>","defaultLevelColors: Record<LogLevel, AnsiColor | null>","options: AnsiColorFormatterOptions","value: unknown","ansiColorFormatter: TextFormatter","options: JsonLinesFormatterOptions","joinCategory: (category: readonly string[]) => string | readonly string[]","category: readonly string[]","getMessage: TextFormatter","getProperties: (\n properties: Record<string, unknown>,\n ) => Record<string, unknown>","result: Record<string, unknown>","jsonLinesFormatter: TextFormatter","logLevelStyles: Record<LogLevel, string>","values: unknown[]"],"sources":["../formatter.ts"],"sourcesContent":["import * as util from \"#util\";\nimport type { LogLevel } from \"./level.ts\";\nimport type { LogRecord } from \"./record.ts\";\n\n/**\n * A text formatter is a function that accepts a log record and returns\n * a string.\n *\n * @param record The log record to format.\n * @returns The formatted log record.\n */\nexport type TextFormatter = (record: LogRecord) => string;\n\n/**\n * The severity level abbreviations.\n */\nconst levelAbbreviations: Record<LogLevel, string> = {\n \"debug\": \"DBG\",\n \"info\": \"INF\",\n \"warning\": \"WRN\",\n \"error\": \"ERR\",\n \"fatal\": \"FTL\",\n};\n\n/**\n * A platform-specific inspect function. In Deno, this is {@link Deno.inspect},\n * and in Node.js/Bun it is `util.inspect()`. If neither is available, it\n * falls back to {@link JSON.stringify}.\n *\n * @param value The value to inspect.\n * @param options The options for inspecting the value.\n * If `colors` is `true`, the output will be ANSI-colored.\n * @returns The string representation of the value.\n */\nconst inspect: (value: unknown, options?: { colors?: boolean }) => string =\n // @ts-ignore: Browser detection\n // dnt-shim-ignore\n typeof document !== \"undefined\" ||\n // @ts-ignore: React Native detection\n // dnt-shim-ignore\n typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\"\n ? (v) => JSON.stringify(v)\n // @ts-ignore: Deno global\n // dnt-shim-ignore\n : \"Deno\" in globalThis && \"inspect\" in globalThis.Deno &&\n // @ts-ignore: Deno global\n // dnt-shim-ignore\n typeof globalThis.Deno.inspect === \"function\"\n ? (v, opts) =>\n // @ts-ignore: Deno global\n // dnt-shim-ignore\n globalThis.Deno.inspect(v, {\n strAbbreviateSize: Infinity,\n iterableLimit: Infinity,\n ...opts,\n })\n // @ts-ignore: Node.js global\n // dnt-shim-ignore\n : util != null && \"inspect\" in util && typeof util.inspect === \"function\"\n ? (v, opts) =>\n // @ts-ignore: Node.js global\n // dnt-shim-ignore\n util.inspect(v, {\n maxArrayLength: Infinity,\n maxStringLength: Infinity,\n ...opts,\n })\n : (v) => JSON.stringify(v);\n\n/**\n * The formatted values for a log record.\n * @since 0.6.0\n */\nexport interface FormattedValues {\n /**\n * The formatted timestamp.\n */\n timestamp: string | null;\n\n /**\n * The formatted log level.\n */\n level: string;\n\n /**\n * The formatted category.\n */\n category: string;\n\n /**\n * The formatted message.\n */\n message: string;\n\n /**\n * The unformatted log record.\n */\n record: LogRecord;\n}\n\n/**\n * The various options for the built-in text formatters.\n * @since 0.6.0\n */\nexport interface TextFormatterOptions {\n /**\n * The timestamp format. This can be one of the following:\n *\n * - `\"date-time-timezone\"`: The date and time with the full timezone offset\n * (e.g., `\"2023-11-14 22:13:20.000 +00:00\"`).\n * - `\"date-time-tz\"`: The date and time with the short timezone offset\n * (e.g., `\"2023-11-14 22:13:20.000 +00\"`).\n * - `\"date-time\"`: The date and time without the timezone offset\n * (e.g., `\"2023-11-14 22:13:20.000\"`).\n * - `\"time-timezone\"`: The time with the full timezone offset but without\n * the date (e.g., `\"22:13:20.000 +00:00\"`).\n * - `\"time-tz\"`: The time with the short timezone offset but without the date\n * (e.g., `\"22:13:20.000 +00\"`).\n * - `\"time\"`: The time without the date or timezone offset\n * (e.g., `\"22:13:20.000\"`).\n * - `\"date\"`: The date without the time or timezone offset\n * (e.g., `\"2023-11-14\"`).\n * - `\"rfc3339\"`: The date and time in RFC 3339 format\n * (e.g., `\"2023-11-14T22:13:20.000Z\"`).\n * - `\"none\"` or `\"disabled\"`: No display\n *\n * Alternatively, this can be a function that accepts a timestamp and returns\n * a string.\n *\n * The default is `\"date-time-timezone\"`.\n */\n timestamp?:\n | \"date-time-timezone\"\n | \"date-time-tz\"\n | \"date-time\"\n | \"time-timezone\"\n | \"time-tz\"\n | \"time\"\n | \"date\"\n | \"rfc3339\"\n | \"none\"\n | \"disabled\"\n | ((ts: number) => string | null);\n\n /**\n * The log level format. This can be one of the following:\n *\n * - `\"ABBR\"`: The log level abbreviation in uppercase (e.g., `\"INF\"`).\n * - `\"FULL\"`: The full log level name in uppercase (e.g., `\"INFO\"`).\n * - `\"L\"`: The first letter of the log level in uppercase (e.g., `\"I\"`).\n * - `\"abbr\"`: The log level abbreviation in lowercase (e.g., `\"inf\"`).\n * - `\"full\"`: The full log level name in lowercase (e.g., `\"info\"`).\n * - `\"l\"`: The first letter of the log level in lowercase (e.g., `\"i\"`).\n *\n * Alternatively, this can be a function that accepts a log level and returns\n * a string.\n *\n * The default is `\"ABBR\"`.\n */\n level?:\n | \"ABBR\"\n | \"FULL\"\n | \"L\"\n | \"abbr\"\n | \"full\"\n | \"l\"\n | ((level: LogLevel) => string);\n\n /**\n * The separator between category names. For example, if the separator is\n * `\"·\"`, the category `[\"a\", \"b\", \"c\"]` will be formatted as `\"a·b·c\"`.\n * The default separator is `\"·\"`.\n *\n * If this is a function, it will be called with the category array and\n * should return a string, which will be used for rendering the category.\n */\n category?: string | ((category: readonly string[]) => string);\n\n /**\n * The format of the embedded values.\n *\n * A function that renders a value to a string. This function is used to\n * render the values in the log record. The default is [`util.inspect()`] in\n * Node.js/Bun and [`Deno.inspect()`] in Deno.\n *\n * [`util.inspect()`]: https://nodejs.org/api/util.html#utilinspectobject-options\n * [`Deno.inspect()`]: https://docs.deno.com/api/deno/~/Deno.inspect\n * @param value The value to render.\n * @returns The string representation of the value.\n */\n value?: (value: unknown) => string;\n\n /**\n * How those formatted parts are concatenated.\n *\n * A function that formats the log record. This function is called with the\n * formatted values and should return a string. Note that the formatted\n * *should not* include a newline character at the end.\n *\n * By default, this is a function that formats the log record as follows:\n *\n * ```\n * 2023-11-14 22:13:20.000 +00:00 [INF] category·subcategory: Hello, world!\n * ```\n * @param values The formatted values.\n * @returns The formatted log record.\n */\n format?: (values: FormattedValues) => string;\n}\n\n/**\n * Get a text formatter with the specified options. Although it's flexible\n * enough to create a custom formatter, if you want more control, you can\n * create a custom formatter that satisfies the {@link TextFormatter} type\n * instead.\n *\n * For more information on the options, see {@link TextFormatterOptions}.\n *\n * By default, the formatter formats log records as follows:\n *\n * ```\n * 2023-11-14 22:13:20.000 +00:00 [INF] category·subcategory: Hello, world!\n * ```\n * @param options The options for the text formatter.\n * @returns The text formatter.\n * @since 0.6.0\n */\nexport function getTextFormatter(\n options: TextFormatterOptions = {},\n): TextFormatter {\n const timestampRenderer =\n options.timestamp == null || options.timestamp === \"date-time-timezone\"\n ? (ts: number): string =>\n new Date(ts).toISOString().replace(\"T\", \" \").replace(\"Z\", \" +00:00\")\n : options.timestamp === \"date-time-tz\"\n ? (ts: number): string =>\n new Date(ts).toISOString().replace(\"T\", \" \").replace(\"Z\", \" +00\")\n : options.timestamp === \"date-time\"\n ? (ts: number): string =>\n new Date(ts).toISOString().replace(\"T\", \" \").replace(\"Z\", \"\")\n : options.timestamp === \"time-timezone\"\n ? (ts: number): string =>\n new Date(ts).toISOString().replace(/.*T/, \"\").replace(\"Z\", \" +00:00\")\n : options.timestamp === \"time-tz\"\n ? (ts: number): string =>\n new Date(ts).toISOString().replace(/.*T/, \"\").replace(\"Z\", \" +00\")\n : options.timestamp === \"time\"\n ? (ts: number): string =>\n new Date(ts).toISOString().replace(/.*T/, \"\").replace(\"Z\", \"\")\n : options.timestamp === \"date\"\n ? (ts: number): string => new Date(ts).toISOString().replace(/T.*/, \"\")\n : options.timestamp === \"rfc3339\"\n ? (ts: number): string => new Date(ts).toISOString()\n : options.timestamp === \"none\" || options.timestamp === \"disabled\"\n ? () => null\n : options.timestamp;\n const categorySeparator = options.category ?? \"·\";\n const valueRenderer = options.value ?? inspect;\n const levelRenderer = options.level == null || options.level === \"ABBR\"\n ? (level: LogLevel): string => levelAbbreviations[level]\n : options.level === \"abbr\"\n ? (level: LogLevel): string => levelAbbreviations[level].toLowerCase()\n : options.level === \"FULL\"\n ? (level: LogLevel): string => level.toUpperCase()\n : options.level === \"full\"\n ? (level: LogLevel): string => level\n : options.level === \"L\"\n ? (level: LogLevel): string => level.charAt(0).toUpperCase()\n : options.level === \"l\"\n ? (level: LogLevel): string => level.charAt(0)\n : options.level;\n const formatter: (values: FormattedValues) => string = options.format ??\n (({ timestamp, level, category, message }: FormattedValues) =>\n `${timestamp ? `${timestamp} ` : \"\"}[${level}] ${category}: ${message}`);\n return (record: LogRecord): string => {\n let message = \"\";\n for (let i = 0; i < record.message.length; i++) {\n if (i % 2 === 0) message += record.message[i];\n else message += valueRenderer(record.message[i]);\n }\n const timestamp = timestampRenderer(record.timestamp);\n const level = levelRenderer(record.level);\n const category = typeof categorySeparator === \"function\"\n ? categorySeparator(record.category)\n : record.category.join(categorySeparator);\n const values: FormattedValues = {\n timestamp,\n level,\n category,\n message,\n record,\n };\n return `${formatter(values)}\\n`;\n };\n}\n\n/**\n * The default text formatter. This formatter formats log records as follows:\n *\n * ```\n * 2023-11-14 22:13:20.000 +00:00 [INF] category·subcategory: Hello, world!\n * ```\n *\n * @param record The log record to format.\n * @returns The formatted log record.\n */\nexport const defaultTextFormatter: TextFormatter = getTextFormatter();\n\nconst RESET = \"\\x1b[0m\";\n\n/**\n * The ANSI colors. These can be used to colorize text in the console.\n * @since 0.6.0\n */\nexport type AnsiColor =\n | \"black\"\n | \"red\"\n | \"green\"\n | \"yellow\"\n | \"blue\"\n | \"magenta\"\n | \"cyan\"\n | \"white\";\n\nconst ansiColors: Record<AnsiColor, string> = {\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};\n\n/**\n * The ANSI text styles.\n * @since 0.6.0\n */\nexport type AnsiStyle =\n | \"bold\"\n | \"dim\"\n | \"italic\"\n | \"underline\"\n | \"strikethrough\";\n\nconst ansiStyles: Record<AnsiStyle, string> = {\n bold: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n italic: \"\\x1b[3m\",\n underline: \"\\x1b[4m\",\n strikethrough: \"\\x1b[9m\",\n};\n\nconst defaultLevelColors: Record<LogLevel, AnsiColor | null> = {\n debug: \"blue\",\n info: \"green\",\n warning: \"yellow\",\n error: \"red\",\n fatal: \"magenta\",\n};\n\n/**\n * The various options for the ANSI color formatter.\n * @since 0.6.0\n */\nexport interface AnsiColorFormatterOptions extends TextFormatterOptions {\n /**\n * The timestamp format. This can be one of the following:\n *\n * - `\"date-time-timezone\"`: The date and time with the full timezone offset\n * (e.g., `\"2023-11-14 22:13:20.000 +00:00\"`).\n * - `\"date-time-tz\"`: The date and time with the short timezone offset\n * (e.g., `\"2023-11-14 22:13:20.000 +00\"`).\n * - `\"date-time\"`: The date and time without the timezone offset\n * (e.g., `\"2023-11-14 22:13:20.000\"`).\n * - `\"time-timezone\"`: The time with the full timezone offset but without\n * the date (e.g., `\"22:13:20.000 +00:00\"`).\n * - `\"time-tz\"`: The time with the short timezone offset but without the date\n * (e.g., `\"22:13:20.000 +00\"`).\n * - `\"time\"`: The time without the date or timezone offset\n * (e.g., `\"22:13:20.000\"`).\n * - `\"date\"`: The date without the time or timezone offset\n * (e.g., `\"2023-11-14\"`).\n * - `\"rfc3339\"`: The date and time in RFC 3339 format\n * (e.g., `\"2023-11-14T22:13:20.000Z\"`).\n *\n * Alternatively, this can be a function that accepts a timestamp and returns\n * a string.\n *\n * The default is `\"date-time-tz\"`.\n */\n timestamp?:\n | \"date-time-timezone\"\n | \"date-time-tz\"\n | \"date-time\"\n | \"time-timezone\"\n | \"time-tz\"\n | \"time\"\n | \"date\"\n | \"rfc3339\"\n | ((ts: number) => string);\n\n /**\n * The ANSI style for the timestamp. `\"dim\"` is used by default.\n */\n timestampStyle?: AnsiStyle | null;\n\n /**\n * The ANSI color for the timestamp. No color is used by default.\n */\n timestampColor?: AnsiColor | null;\n\n /**\n * The ANSI style for the log level. `\"bold\"` is used by default.\n */\n levelStyle?: AnsiStyle | null;\n\n /**\n * The ANSI colors for the log levels. The default colors are as follows:\n *\n * - `\"debug\"`: `\"blue\"`\n * - `\"info\"`: `\"green\"`\n * - `\"warning\"`: `\"yellow\"`\n * - `\"error\"`: `\"red\"`\n * - `\"fatal\"`: `\"magenta\"`\n */\n levelColors?: Record<LogLevel, AnsiColor | null>;\n\n /**\n * The ANSI style for the category. `\"dim\"` is used by default.\n */\n categoryStyle?: AnsiStyle | null;\n\n /**\n * The ANSI color for the category. No color is used by default.\n */\n categoryColor?: AnsiColor | null;\n}\n\n/**\n * Get an ANSI color formatter with the specified options.\n *\n * ![A preview of an ANSI color formatter.](https://i.imgur.com/I8LlBUf.png)\n * @param option The options for the ANSI color formatter.\n * @returns The ANSI color formatter.\n * @since 0.6.0\n */\nexport function getAnsiColorFormatter(\n options: AnsiColorFormatterOptions = {},\n): TextFormatter {\n const format = options.format;\n const timestampStyle = typeof options.timestampStyle === \"undefined\"\n ? \"dim\"\n : options.timestampStyle;\n const timestampColor = options.timestampColor ?? null;\n const timestampPrefix = `${\n timestampStyle == null ? \"\" : ansiStyles[timestampStyle]\n }${timestampColor == null ? \"\" : ansiColors[timestampColor]}`;\n const timestampSuffix = timestampStyle == null && timestampColor == null\n ? \"\"\n : RESET;\n const levelStyle = typeof options.levelStyle === \"undefined\"\n ? \"bold\"\n : options.levelStyle;\n const levelColors = options.levelColors ?? defaultLevelColors;\n const categoryStyle = typeof options.categoryStyle === \"undefined\"\n ? \"dim\"\n : options.categoryStyle;\n const categoryColor = options.categoryColor ?? null;\n const categoryPrefix = `${\n categoryStyle == null ? \"\" : ansiStyles[categoryStyle]\n }${categoryColor == null ? \"\" : ansiColors[categoryColor]}`;\n const categorySuffix = categoryStyle == null && categoryColor == null\n ? \"\"\n : RESET;\n return getTextFormatter({\n timestamp: \"date-time-tz\",\n value(value: unknown): string {\n return inspect(value, { colors: true });\n },\n ...options,\n format({ timestamp, level, category, message, record }): string {\n const levelColor = levelColors[record.level];\n timestamp = `${timestampPrefix}${timestamp}${timestampSuffix}`;\n level = `${levelStyle == null ? \"\" : ansiStyles[levelStyle]}${\n levelColor == null ? \"\" : ansiColors[levelColor]\n }${level}${levelStyle == null && levelColor == null ? \"\" : RESET}`;\n return format == null\n ? `${timestamp} ${level} ${categoryPrefix}${category}:${categorySuffix} ${message}`\n : format({\n timestamp,\n level,\n category: `${categoryPrefix}${category}${categorySuffix}`,\n message,\n record,\n });\n },\n });\n}\n\n/**\n * A text formatter that uses ANSI colors to format log records.\n *\n * ![A preview of ansiColorFormatter.](https://i.imgur.com/I8LlBUf.png)\n *\n * @param record The log record to format.\n * @returns The formatted log record.\n * @since 0.5.0\n */\nexport const ansiColorFormatter: TextFormatter = getAnsiColorFormatter();\n\n/**\n * Options for the {@link getJsonLinesFormatter} function.\n * @since 0.11.0\n */\nexport interface JsonLinesFormatterOptions {\n /**\n * The separator between category names. For example, if the separator is\n * `\".\"`, the category `[\"a\", \"b\", \"c\"]` will be formatted as `\"a.b.c\"`.\n * If this is a function, it will be called with the category array and\n * should return a string or an array of strings, which will be used\n * for rendering the category.\n *\n * @default `\".\"`\n */\n readonly categorySeparator?:\n | string\n | ((category: readonly string[]) => string | readonly string[]);\n\n /**\n * The message format. This can be one of the following:\n *\n * - `\"template\"`: The raw message template is used as the message.\n * - `\"rendered\"`: The message is rendered with the values.\n *\n * @default `\"rendered\"`\n */\n readonly message?: \"template\" | \"rendered\";\n\n /**\n * The properties format. This can be one of the following:\n *\n * - `\"flatten\"`: The properties are flattened into the root object.\n * - `\"prepend:<prefix>\"`: The properties are prepended with the given prefix\n * (e.g., `\"prepend:ctx_\"` will prepend `ctx_` to each property key).\n * - `\"nest:<key>\"`: The properties are nested under the given key\n * (e.g., `\"nest:properties\"` will nest the properties under the\n * `properties` key).\n *\n * @default `\"nest:properties\"`\n */\n readonly properties?: \"flatten\" | `prepend:${string}` | `nest:${string}`;\n}\n\n/**\n * Get a [JSON Lines] formatter with the specified options. The log records\n * will be rendered as JSON objects, one per line, which is a common format\n * for log files. This format is also known as Newline-Delimited JSON (NDJSON).\n * It looks like this:\n *\n * ```json\n * {\"@timestamp\":\"2023-11-14T22:13:20.000Z\",\"level\":\"INFO\",\"message\":\"Hello, world!\",\"logger\":\"my.logger\",\"properties\":{\"key\":\"value\"}}\n * ```\n *\n * [JSON Lines]: https://jsonlines.org/\n * @param options The options for the JSON Lines formatter.\n * @returns The JSON Lines formatter.\n * @since 0.11.0\n */\nexport function getJsonLinesFormatter(\n options: JsonLinesFormatterOptions = {},\n): TextFormatter {\n let joinCategory: (category: readonly string[]) => string | readonly string[];\n if (typeof options.categorySeparator === \"function\") {\n joinCategory = options.categorySeparator;\n } else {\n const separator = options.categorySeparator ?? \".\";\n joinCategory = (category: readonly string[]): string =>\n category.join(separator);\n }\n\n let getMessage: TextFormatter;\n if (options.message === \"template\") {\n getMessage = (record: LogRecord): string => {\n if (typeof record.rawMessage === \"string\") {\n return record.rawMessage;\n }\n let msg = \"\";\n for (let i = 0; i < record.rawMessage.length; i++) {\n msg += i % 2 < 1 ? record.rawMessage[i] : \"{}\";\n }\n return msg;\n };\n } else {\n getMessage = (record: LogRecord): string => {\n let msg = \"\";\n for (let i = 0; i < record.message.length; i++) {\n msg += i % 2 < 1\n ? record.message[i]\n : JSON.stringify(record.message[i]);\n }\n return msg;\n };\n }\n\n const propertiesOption = options.properties ?? \"nest:properties\";\n let getProperties: (\n properties: Record<string, unknown>,\n ) => Record<string, unknown>;\n if (propertiesOption === \"flatten\") {\n getProperties = (properties) => properties;\n } else if (propertiesOption.startsWith(\"prepend:\")) {\n const prefix = propertiesOption.substring(8);\n if (prefix === \"\") {\n throw new TypeError(\n `Invalid properties option: ${\n JSON.stringify(propertiesOption)\n }. It must be of the form \"prepend:<prefix>\" where <prefix> is a non-empty string.`,\n );\n }\n getProperties = (properties) => {\n const result: Record<string, unknown> = {};\n for (const key in properties) {\n result[`${prefix}${key}`] = properties[key];\n }\n return result;\n };\n } else if (propertiesOption.startsWith(\"nest:\")) {\n const key = propertiesOption.substring(5);\n getProperties = (properties) => ({ [key]: properties });\n } else {\n throw new TypeError(\n `Invalid properties option: ${\n JSON.stringify(propertiesOption)\n }. It must be \"flatten\", \"prepend:<prefix>\", or \"nest:<key>\".`,\n );\n }\n\n return (record: LogRecord): string => {\n return JSON.stringify({\n \"@timestamp\": new Date(record.timestamp).toISOString(),\n level: record.level === \"warning\" ? \"WARN\" : record.level.toUpperCase(),\n message: getMessage(record),\n logger: joinCategory(record.category),\n ...getProperties(record.properties),\n });\n };\n}\n\n/**\n * The default [JSON Lines] formatter. This formatter formats log records\n * as JSON objects, one per line, which is a common format for log files.\n * It looks like this:\n *\n * ```json\n * {\"@timestamp\":\"2023-11-14T22:13:20.000Z\",\"level\":\"INFO\",\"message\":\"Hello, world!\",\"logger\":\"my.logger\",\"properties\":{\"key\":\"value\"}}\n * ```\n *\n * You can customize the output by passing options to\n * {@link getJsonLinesFormatter}. For example, you can change the category\n * separator, the message format, and how the properties are formatted.\n *\n * [JSON Lines]: https://jsonlines.org/\n * @since 0.11.0\n */\nexport const jsonLinesFormatter: TextFormatter = getJsonLinesFormatter();\n\n/**\n * A console formatter is a function that accepts a log record and returns\n * an array of arguments to pass to {@link console.log}.\n *\n * @param record The log record to format.\n * @returns The formatted log record, as an array of arguments for\n * {@link console.log}.\n */\nexport type ConsoleFormatter = (record: LogRecord) => readonly unknown[];\n\n/**\n * The styles for the log level in the console.\n */\nconst logLevelStyles: Record<LogLevel, string> = {\n \"debug\": \"background-color: gray; color: white;\",\n \"info\": \"background-color: white; color: black;\",\n \"warning\": \"background-color: orange; color: black;\",\n \"error\": \"background-color: red; color: white;\",\n \"fatal\": \"background-color: maroon; color: white;\",\n};\n\n/**\n * The default console formatter.\n *\n * @param record The log record to format.\n * @returns The formatted log record, as an array of arguments for\n * {@link console.log}.\n */\nexport function defaultConsoleFormatter(record: LogRecord): readonly unknown[] {\n let msg = \"\";\n const values: unknown[] = [];\n for (let i = 0; i < record.message.length; i++) {\n if (i % 2 === 0) msg += record.message[i];\n else {\n msg += \"%o\";\n values.push(record.message[i]);\n }\n }\n const date = new Date(record.timestamp);\n const time = `${date.getUTCHours().toString().padStart(2, \"0\")}:${\n date.getUTCMinutes().toString().padStart(2, \"0\")\n }:${date.getUTCSeconds().toString().padStart(2, \"0\")}.${\n date.getUTCMilliseconds().toString().padStart(3, \"0\")\n }`;\n return [\n `%c${time} %c${levelAbbreviations[record.level]}%c %c${\n record.category.join(\"\\xb7\")\n } %c${msg}`,\n \"color: gray;\",\n logLevelStyles[record.level],\n \"background-color: default;\",\n \"color: gray;\",\n \"color: default;\",\n ...values,\n ];\n}\n"],"mappings":";;;;;;AAgBA,MAAMA,qBAA+C;CACnD,SAAS;CACT,QAAQ;CACR,WAAW;CACX,SAAS;CACT,SAAS;AACV;;;;;;;;;;;AAYD,MAAMC,iBAGG,aAAa,sBAGX,cAAc,eAAe,UAAU,YAAY,gBACxD,CAAC,MAAM,KAAK,UAAU,EAAE,GAGxB,UAAU,cAAc,aAAa,WAAW,eAGvC,WAAW,KAAK,YAAY,aACrC,CAAC,GAAG,SAGJ,WAAW,KAAK,QAAQ,GAAG;CACzB,mBAAmB;CACnB,eAAe;CACf,GAAG;AACJ,EAAC,GAGF,QAAQ,QAAQ,aAAa,eAAe,KAAK,YAAY,aAC7D,CAAC,GAAG,SAGJ,KAAK,QAAQ,GAAG;CACd,gBAAgB;CAChB,iBAAiB;CACjB,GAAG;AACJ,EAAC,GACF,CAAC,MAAM,KAAK,UAAU,EAAE;;;;;;;;;;;;;;;;;;AAgK9B,SAAgB,iBACdC,UAAgC,CAAE,GACnB;CACf,MAAM,oBACJ,QAAQ,aAAa,QAAQ,QAAQ,cAAc,uBAC/C,CAACC,OACD,IAAI,KAAK,IAAI,aAAa,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,KAAK,UAAU,GACpE,QAAQ,cAAc,iBACtB,CAACA,OACD,IAAI,KAAK,IAAI,aAAa,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,KAAK,OAAO,GACjE,QAAQ,cAAc,cACtB,CAACA,OACD,IAAI,KAAK,IAAI,aAAa,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,KAAK,GAAG,GAC7D,QAAQ,cAAc,kBACtB,CAACA,OACD,IAAI,KAAK,IAAI,aAAa,CAAC,QAAQ,OAAO,GAAG,CAAC,QAAQ,KAAK,UAAU,GACrE,QAAQ,cAAc,YACtB,CAACA,OACD,IAAI,KAAK,IAAI,aAAa,CAAC,QAAQ,OAAO,GAAG,CAAC,QAAQ,KAAK,OAAO,GAClE,QAAQ,cAAc,SACtB,CAACA,OACD,IAAI,KAAK,IAAI,aAAa,CAAC,QAAQ,OAAO,GAAG,CAAC,QAAQ,KAAK,GAAG,GAC9D,QAAQ,cAAc,SACtB,CAACA,OAAuB,IAAI,KAAK,IAAI,aAAa,CAAC,QAAQ,OAAO,GAAG,GACrE,QAAQ,cAAc,YACtB,CAACA,OAAuB,IAAI,KAAK,IAAI,aAAa,GAClD,QAAQ,cAAc,UAAU,QAAQ,cAAc,aACtD,MAAM,OACN,QAAQ;CACd,MAAM,oBAAoB,QAAQ,YAAY;CAC9C,MAAM,gBAAgB,QAAQ,SAAS;CACvC,MAAM,gBAAgB,QAAQ,SAAS,QAAQ,QAAQ,UAAU,SAC7D,CAACC,UAA4B,mBAAmB,SAChD,QAAQ,UAAU,SAClB,CAACA,UAA4B,mBAAmB,OAAO,aAAa,GACpE,QAAQ,UAAU,SAClB,CAACA,UAA4B,MAAM,aAAa,GAChD,QAAQ,UAAU,SAClB,CAACA,UAA4B,QAC7B,QAAQ,UAAU,MAClB,CAACA,UAA4B,MAAM,OAAO,EAAE,CAAC,aAAa,GAC1D,QAAQ,UAAU,MAClB,CAACA,UAA4B,MAAM,OAAO,EAAE,GAC5C,QAAQ;CACZ,MAAMC,YAAiD,QAAQ,WAC5D,CAAC,EAAE,WAAW,OAAO,UAAU,SAA0B,MACvD,EAAE,aAAa,EAAE,UAAU,KAAK,GAAG,GAAG,MAAM,IAAI,SAAS,IAAI,QAAQ;AAC1E,QAAO,CAACC,WAA8B;EACpC,IAAI,UAAU;AACd,OAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,QAAQ,IACzC,KAAI,IAAI,MAAM,EAAG,YAAW,OAAO,QAAQ;MACtC,YAAW,cAAc,OAAO,QAAQ,GAAG;EAElD,MAAM,YAAY,kBAAkB,OAAO,UAAU;EACrD,MAAM,QAAQ,cAAc,OAAO,MAAM;EACzC,MAAM,kBAAkB,sBAAsB,aAC1C,kBAAkB,OAAO,SAAS,GAClC,OAAO,SAAS,KAAK,kBAAkB;EAC3C,MAAMC,SAA0B;GAC9B;GACA;GACA;GACA;GACA;EACD;AACD,UAAQ,EAAE,UAAU,OAAO,CAAC;CAC7B;AACF;;;;;;;;;;;AAYD,MAAaC,uBAAsC,kBAAkB;AAErE,MAAM,QAAQ;AAgBd,MAAMC,aAAwC;CAC5C,OAAO;CACP,KAAK;CACL,OAAO;CACP,QAAQ;CACR,MAAM;CACN,SAAS;CACT,MAAM;CACN,OAAO;AACR;AAaD,MAAMC,aAAwC;CAC5C,MAAM;CACN,KAAK;CACL,QAAQ;CACR,WAAW;CACX,eAAe;AAChB;AAED,MAAMC,qBAAyD;CAC7D,OAAO;CACP,MAAM;CACN,SAAS;CACT,OAAO;CACP,OAAO;AACR;;;;;;;;;AAwFD,SAAgB,sBACdC,UAAqC,CAAE,GACxB;CACf,MAAM,SAAS,QAAQ;CACvB,MAAM,wBAAwB,QAAQ,mBAAmB,cACrD,QACA,QAAQ;CACZ,MAAM,iBAAiB,QAAQ,kBAAkB;CACjD,MAAM,mBAAmB,EACvB,kBAAkB,OAAO,KAAK,WAAW,gBAC1C,EAAE,kBAAkB,OAAO,KAAK,WAAW,gBAAgB;CAC5D,MAAM,kBAAkB,kBAAkB,QAAQ,kBAAkB,OAChE,KACA;CACJ,MAAM,oBAAoB,QAAQ,eAAe,cAC7C,SACA,QAAQ;CACZ,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,uBAAuB,QAAQ,kBAAkB,cACnD,QACA,QAAQ;CACZ,MAAM,gBAAgB,QAAQ,iBAAiB;CAC/C,MAAM,kBAAkB,EACtB,iBAAiB,OAAO,KAAK,WAAW,eACzC,EAAE,iBAAiB,OAAO,KAAK,WAAW,eAAe;CAC1D,MAAM,iBAAiB,iBAAiB,QAAQ,iBAAiB,OAC7D,KACA;AACJ,QAAO,iBAAiB;EACtB,WAAW;EACX,MAAMC,OAAwB;AAC5B,UAAO,QAAQ,OAAO,EAAE,QAAQ,KAAM,EAAC;EACxC;EACD,GAAG;EACH,OAAO,EAAE,WAAW,OAAO,UAAU,SAAS,QAAQ,EAAU;GAC9D,MAAM,aAAa,YAAY,OAAO;AACtC,gBAAa,EAAE,gBAAgB,EAAE,UAAU,EAAE,gBAAgB;AAC7D,YAAS,EAAE,cAAc,OAAO,KAAK,WAAW,YAAY,EAC1D,cAAc,OAAO,KAAK,WAAW,YACtC,EAAE,MAAM,EAAE,cAAc,QAAQ,cAAc,OAAO,KAAK,MAAM;AACjE,UAAO,UAAU,QACZ,EAAE,UAAU,GAAG,MAAM,GAAG,eAAe,EAAE,SAAS,GAAG,eAAe,GAAG,QAAQ,IAChF,OAAO;IACP;IACA;IACA,WAAW,EAAE,eAAe,EAAE,SAAS,EAAE,eAAe;IACxD;IACA;GACD,EAAC;EACL;CACF,EAAC;AACH;;;;;;;;;;AAWD,MAAaC,qBAAoC,uBAAuB;;;;;;;;;;;;;;;;AA4DxE,SAAgB,sBACdC,UAAqC,CAAE,GACxB;CACf,IAAIC;AACJ,YAAW,QAAQ,sBAAsB,WACvC,gBAAe,QAAQ;MAClB;EACL,MAAM,YAAY,QAAQ,qBAAqB;AAC/C,iBAAe,CAACC,aACd,SAAS,KAAK,UAAU;CAC3B;CAED,IAAIC;AACJ,KAAI,QAAQ,YAAY,WACtB,cAAa,CAACZ,WAA8B;AAC1C,aAAW,OAAO,eAAe,SAC/B,QAAO,OAAO;EAEhB,IAAI,MAAM;AACV,OAAK,IAAI,IAAI,GAAG,IAAI,OAAO,WAAW,QAAQ,IAC5C,QAAO,IAAI,IAAI,IAAI,OAAO,WAAW,KAAK;AAE5C,SAAO;CACR;KAED,cAAa,CAACA,WAA8B;EAC1C,IAAI,MAAM;AACV,OAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,QAAQ,IACzC,QAAO,IAAI,IAAI,IACX,OAAO,QAAQ,KACf,KAAK,UAAU,OAAO,QAAQ,GAAG;AAEvC,SAAO;CACR;CAGH,MAAM,mBAAmB,QAAQ,cAAc;CAC/C,IAAIa;AAGJ,KAAI,qBAAqB,UACvB,iBAAgB,CAAC,eAAe;UACvB,iBAAiB,WAAW,WAAW,EAAE;EAClD,MAAM,SAAS,iBAAiB,UAAU,EAAE;AAC5C,MAAI,WAAW,GACb,OAAM,IAAI,WACP,6BACC,KAAK,UAAU,iBAAiB,CACjC;AAGL,kBAAgB,CAAC,eAAe;GAC9B,MAAMC,SAAkC,CAAE;AAC1C,QAAK,MAAM,OAAO,WAChB,SAAQ,EAAE,OAAO,EAAE,IAAI,KAAK,WAAW;AAEzC,UAAO;EACR;CACF,WAAU,iBAAiB,WAAW,QAAQ,EAAE;EAC/C,MAAM,MAAM,iBAAiB,UAAU,EAAE;AACzC,kBAAgB,CAAC,gBAAgB,GAAG,MAAM,WAAY;CACvD,MACC,OAAM,IAAI,WACP,6BACC,KAAK,UAAU,iBAAiB,CACjC;AAIL,QAAO,CAACd,WAA8B;AACpC,SAAO,KAAK,UAAU;GACpB,cAAc,IAAI,KAAK,OAAO,WAAW,aAAa;GACtD,OAAO,OAAO,UAAU,YAAY,SAAS,OAAO,MAAM,aAAa;GACvE,SAAS,WAAW,OAAO;GAC3B,QAAQ,aAAa,OAAO,SAAS;GACrC,GAAG,cAAc,OAAO,WAAW;EACpC,EAAC;CACH;AACF;;;;;;;;;;;;;;;;;AAkBD,MAAae,qBAAoC,uBAAuB;;;;AAexE,MAAMC,iBAA2C;CAC/C,SAAS;CACT,QAAQ;CACR,WAAW;CACX,SAAS;CACT,SAAS;AACV;;;;;;;;AASD,SAAgB,wBAAwBhB,QAAuC;CAC7E,IAAI,MAAM;CACV,MAAMiB,SAAoB,CAAE;AAC5B,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,QAAQ,IACzC,KAAI,IAAI,MAAM,EAAG,QAAO,OAAO,QAAQ;MAClC;AACH,SAAO;AACP,SAAO,KAAK,OAAO,QAAQ,GAAG;CAC/B;CAEH,MAAM,OAAO,IAAI,KAAK,OAAO;CAC7B,MAAM,QAAQ,EAAE,KAAK,aAAa,CAAC,UAAU,CAAC,SAAS,GAAG,IAAI,CAAC,GAC7D,KAAK,eAAe,CAAC,UAAU,CAAC,SAAS,GAAG,IAAI,CACjD,GAAG,KAAK,eAAe,CAAC,UAAU,CAAC,SAAS,GAAG,IAAI,CAAC,GACnD,KAAK,oBAAoB,CAAC,UAAU,CAAC,SAAS,GAAG,IAAI,CACtD;AACD,QAAO;GACJ,IAAI,KAAK,KAAK,mBAAmB,OAAO,OAAO,OAC9C,OAAO,SAAS,KAAK,IAAO,CAC7B,KAAK,IAAI;EACV;EACA,eAAe,OAAO;EACtB;EACA;EACA;EACA,GAAG;CACJ;AACF"}
package/dist/level.cjs ADDED
@@ -0,0 +1,64 @@
1
+
2
+ //#region level.ts
3
+ const logLevels = [
4
+ "debug",
5
+ "info",
6
+ "warning",
7
+ "error",
8
+ "fatal"
9
+ ];
10
+ /**
11
+ * Parses a log level from a string.
12
+ *
13
+ * @param level The log level as a string. This is case-insensitive.
14
+ * @returns The log level.
15
+ * @throws {TypeError} If the log level is invalid.
16
+ */
17
+ function parseLogLevel(level) {
18
+ level = level.toLowerCase();
19
+ switch (level) {
20
+ case "debug":
21
+ case "info":
22
+ case "warning":
23
+ case "error":
24
+ case "fatal": return level;
25
+ default: throw new TypeError(`Invalid log level: ${level}.`);
26
+ }
27
+ }
28
+ /**
29
+ * Checks if a string is a valid log level. This function can be used as
30
+ * as a type guard to narrow the type of a string to a {@link LogLevel}.
31
+ *
32
+ * @param level The log level as a string. This is case-sensitive.
33
+ * @returns `true` if the string is a valid log level.
34
+ */
35
+ function isLogLevel(level) {
36
+ switch (level) {
37
+ case "debug":
38
+ case "info":
39
+ case "warning":
40
+ case "error":
41
+ case "fatal": return true;
42
+ default: return false;
43
+ }
44
+ }
45
+ /**
46
+ * Compares two log levels.
47
+ * @param a The first log level.
48
+ * @param b The second log level.
49
+ * @returns A negative number if `a` is less than `b`, a positive number if `a`
50
+ * is greater than `b`, or zero if they are equal.
51
+ * @since 0.8.0
52
+ */
53
+ function compareLogLevel(a, b) {
54
+ const aIndex = logLevels.indexOf(a);
55
+ if (aIndex < 0) throw new TypeError(`Invalid log level: ${JSON.stringify(a)}.`);
56
+ const bIndex = logLevels.indexOf(b);
57
+ if (bIndex < 0) throw new TypeError(`Invalid log level: ${JSON.stringify(b)}.`);
58
+ return aIndex - bIndex;
59
+ }
60
+
61
+ //#endregion
62
+ exports.compareLogLevel = compareLogLevel;
63
+ exports.isLogLevel = isLogLevel;
64
+ exports.parseLogLevel = parseLogLevel;
@@ -0,0 +1,34 @@
1
+ //#region level.d.ts
2
+ declare const logLevels: readonly ["debug", "info", "warning", "error", "fatal"];
3
+ /**
4
+ * The severity level of a {@link LogRecord}.
5
+ */
6
+ type LogLevel = typeof logLevels[number];
7
+ /**
8
+ * Parses a log level from a string.
9
+ *
10
+ * @param level The log level as a string. This is case-insensitive.
11
+ * @returns The log level.
12
+ * @throws {TypeError} If the log level is invalid.
13
+ */
14
+ declare function parseLogLevel(level: string): LogLevel;
15
+ /**
16
+ * Checks if a string is a valid log level. This function can be used as
17
+ * as a type guard to narrow the type of a string to a {@link LogLevel}.
18
+ *
19
+ * @param level The log level as a string. This is case-sensitive.
20
+ * @returns `true` if the string is a valid log level.
21
+ */
22
+ declare function isLogLevel(level: string): level is LogLevel;
23
+ /**
24
+ * Compares two log levels.
25
+ * @param a The first log level.
26
+ * @param b The second log level.
27
+ * @returns A negative number if `a` is less than `b`, a positive number if `a`
28
+ * is greater than `b`, or zero if they are equal.
29
+ * @since 0.8.0
30
+ */
31
+ declare function compareLogLevel(a: LogLevel, b: LogLevel): number;
32
+ //#endregion
33
+ export { LogLevel, compareLogLevel, isLogLevel, parseLogLevel };
34
+ //# sourceMappingURL=level.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"level.d.cts","names":[],"sources":["../level.ts"],"sourcesContent":[],"mappings":";cAAM;;AAKN;AASA;AAqBgB,KA9BJ,QAAA,GA8Bc,OA9BI,SA8B8B,CAAA,MAAA,CAAA;AAqB5D;;;;AAAwD;;;iBA1CxC,aAAA,iBAA8B;;;;;;;;iBAqB9B,UAAA,0BAAoC;;;;;;;;;iBAqBpC,eAAA,IAAmB,aAAa"}
@@ -1,8 +1,9 @@
1
+ //#region level.d.ts
1
2
  declare const logLevels: readonly ["debug", "info", "warning", "error", "fatal"];
2
3
  /**
3
4
  * The severity level of a {@link LogRecord}.
4
5
  */
5
- export type LogLevel = typeof logLevels[number];
6
+ type LogLevel = typeof logLevels[number];
6
7
  /**
7
8
  * Parses a log level from a string.
8
9
  *
@@ -10,7 +11,7 @@ export type LogLevel = typeof logLevels[number];
10
11
  * @returns The log level.
11
12
  * @throws {TypeError} If the log level is invalid.
12
13
  */
13
- export declare function parseLogLevel(level: string): LogLevel;
14
+ declare function parseLogLevel(level: string): LogLevel;
14
15
  /**
15
16
  * Checks if a string is a valid log level. This function can be used as
16
17
  * as a type guard to narrow the type of a string to a {@link LogLevel}.
@@ -18,7 +19,7 @@ export declare function parseLogLevel(level: string): LogLevel;
18
19
  * @param level The log level as a string. This is case-sensitive.
19
20
  * @returns `true` if the string is a valid log level.
20
21
  */
21
- export declare function isLogLevel(level: string): level is LogLevel;
22
+ declare function isLogLevel(level: string): level is LogLevel;
22
23
  /**
23
24
  * Compares two log levels.
24
25
  * @param a The first log level.
@@ -27,6 +28,7 @@ export declare function isLogLevel(level: string): level is LogLevel;
27
28
  * is greater than `b`, or zero if they are equal.
28
29
  * @since 0.8.0
29
30
  */
30
- export declare function compareLogLevel(a: LogLevel, b: LogLevel): number;
31
- export {};
31
+ declare function compareLogLevel(a: LogLevel, b: LogLevel): number;
32
+ //#endregion
33
+ export { LogLevel, compareLogLevel, isLogLevel, parseLogLevel };
32
34
  //# sourceMappingURL=level.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"level.d.ts","names":[],"sources":["../level.ts"],"sourcesContent":[],"mappings":";cAAM;;AAKN;AASA;AAqBgB,KA9BJ,QAAA,GA8Bc,OA9BI,SA8B8B,CAAA,MAAA,CAAA;AAqB5D;;;;AAAwD;;;iBA1CxC,aAAA,iBAA8B;;;;;;;;iBAqB9B,UAAA,0BAAoC;;;;;;;;;iBAqBpC,eAAA,IAAmB,aAAa"}
package/dist/level.js ADDED
@@ -0,0 +1,62 @@
1
+ //#region level.ts
2
+ const logLevels = [
3
+ "debug",
4
+ "info",
5
+ "warning",
6
+ "error",
7
+ "fatal"
8
+ ];
9
+ /**
10
+ * Parses a log level from a string.
11
+ *
12
+ * @param level The log level as a string. This is case-insensitive.
13
+ * @returns The log level.
14
+ * @throws {TypeError} If the log level is invalid.
15
+ */
16
+ function parseLogLevel(level) {
17
+ level = level.toLowerCase();
18
+ switch (level) {
19
+ case "debug":
20
+ case "info":
21
+ case "warning":
22
+ case "error":
23
+ case "fatal": return level;
24
+ default: throw new TypeError(`Invalid log level: ${level}.`);
25
+ }
26
+ }
27
+ /**
28
+ * Checks if a string is a valid log level. This function can be used as
29
+ * as a type guard to narrow the type of a string to a {@link LogLevel}.
30
+ *
31
+ * @param level The log level as a string. This is case-sensitive.
32
+ * @returns `true` if the string is a valid log level.
33
+ */
34
+ function isLogLevel(level) {
35
+ switch (level) {
36
+ case "debug":
37
+ case "info":
38
+ case "warning":
39
+ case "error":
40
+ case "fatal": return true;
41
+ default: return false;
42
+ }
43
+ }
44
+ /**
45
+ * Compares two log levels.
46
+ * @param a The first log level.
47
+ * @param b The second log level.
48
+ * @returns A negative number if `a` is less than `b`, a positive number if `a`
49
+ * is greater than `b`, or zero if they are equal.
50
+ * @since 0.8.0
51
+ */
52
+ function compareLogLevel(a, b) {
53
+ const aIndex = logLevels.indexOf(a);
54
+ if (aIndex < 0) throw new TypeError(`Invalid log level: ${JSON.stringify(a)}.`);
55
+ const bIndex = logLevels.indexOf(b);
56
+ if (bIndex < 0) throw new TypeError(`Invalid log level: ${JSON.stringify(b)}.`);
57
+ return aIndex - bIndex;
58
+ }
59
+
60
+ //#endregion
61
+ export { compareLogLevel, isLogLevel, parseLogLevel };
62
+ //# sourceMappingURL=level.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"level.js","names":["level: string","a: LogLevel","b: LogLevel"],"sources":["../level.ts"],"sourcesContent":["const logLevels = [\"debug\", \"info\", \"warning\", \"error\", \"fatal\"] as const;\n\n/**\n * The severity level of a {@link LogRecord}.\n */\nexport type LogLevel = typeof logLevels[number];\n\n/**\n * Parses a log level from a string.\n *\n * @param level The log level as a string. This is case-insensitive.\n * @returns The log level.\n * @throws {TypeError} If the log level is invalid.\n */\nexport function parseLogLevel(level: string): LogLevel {\n level = level.toLowerCase();\n switch (level) {\n case \"debug\":\n case \"info\":\n case \"warning\":\n case \"error\":\n case \"fatal\":\n return level;\n default:\n throw new TypeError(`Invalid log level: ${level}.`);\n }\n}\n\n/**\n * Checks if a string is a valid log level. This function can be used as\n * as a type guard to narrow the type of a string to a {@link LogLevel}.\n *\n * @param level The log level as a string. This is case-sensitive.\n * @returns `true` if the string is a valid log level.\n */\nexport function isLogLevel(level: string): level is LogLevel {\n switch (level) {\n case \"debug\":\n case \"info\":\n case \"warning\":\n case \"error\":\n case \"fatal\":\n return true;\n default:\n return false;\n }\n}\n\n/**\n * Compares two log levels.\n * @param a The first log level.\n * @param b The second log level.\n * @returns A negative number if `a` is less than `b`, a positive number if `a`\n * is greater than `b`, or zero if they are equal.\n * @since 0.8.0\n */\nexport function compareLogLevel(a: LogLevel, b: LogLevel): number {\n const aIndex = logLevels.indexOf(a);\n if (aIndex < 0) {\n throw new TypeError(`Invalid log level: ${JSON.stringify(a)}.`);\n }\n const bIndex = logLevels.indexOf(b);\n if (bIndex < 0) {\n throw new TypeError(`Invalid log level: ${JSON.stringify(b)}.`);\n }\n return aIndex - bIndex;\n}\n"],"mappings":";AAAA,MAAM,YAAY;CAAC;CAAS;CAAQ;CAAW;CAAS;AAAQ;;;;;;;;AAchE,SAAgB,cAAcA,OAAyB;AACrD,SAAQ,MAAM,aAAa;AAC3B,SAAQ,OAAR;EACE,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,QACH,QAAO;EACT,QACE,OAAM,IAAI,WAAW,qBAAqB,MAAM;CACnD;AACF;;;;;;;;AASD,SAAgB,WAAWA,OAAkC;AAC3D,SAAQ,OAAR;EACE,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,QACH,QAAO;EACT,QACE,QAAO;CACV;AACF;;;;;;;;;AAUD,SAAgB,gBAAgBC,GAAaC,GAAqB;CAChE,MAAM,SAAS,UAAU,QAAQ,EAAE;AACnC,KAAI,SAAS,EACX,OAAM,IAAI,WAAW,qBAAqB,KAAK,UAAU,EAAE,CAAC;CAE9D,MAAM,SAAS,UAAU,QAAQ,EAAE;AACnC,KAAI,SAAS,EACX,OAAM,IAAI,WAAW,qBAAqB,KAAK,UAAU,EAAE,CAAC;AAE9D,QAAO,SAAS;AACjB"}
@@ -0,0 +1,351 @@
1
+ const require_level = require('./level.cjs');
2
+
3
+ //#region logger.ts
4
+ /**
5
+ * Get a logger with the given category.
6
+ *
7
+ * ```typescript
8
+ * const logger = getLogger(["my-app"]);
9
+ * ```
10
+ *
11
+ * @param category The category of the logger. It can be a string or an array
12
+ * of strings. If it is a string, it is equivalent to an array
13
+ * with a single element.
14
+ * @returns The logger.
15
+ */
16
+ function getLogger(category = []) {
17
+ return LoggerImpl.getLogger(category);
18
+ }
19
+ /**
20
+ * The symbol for the global root logger.
21
+ */
22
+ const globalRootLoggerSymbol = Symbol.for("logtape.rootLogger");
23
+ /**
24
+ * A logger implementation. Do not use this directly; use {@link getLogger}
25
+ * instead. This class is exported for testing purposes.
26
+ */
27
+ var LoggerImpl = class LoggerImpl {
28
+ parent;
29
+ children;
30
+ category;
31
+ sinks;
32
+ parentSinks = "inherit";
33
+ filters;
34
+ lowestLevel = "debug";
35
+ contextLocalStorage;
36
+ static getLogger(category = []) {
37
+ let rootLogger = globalRootLoggerSymbol in globalThis ? globalThis[globalRootLoggerSymbol] ?? null : null;
38
+ if (rootLogger == null) {
39
+ rootLogger = new LoggerImpl(null, []);
40
+ globalThis[globalRootLoggerSymbol] = rootLogger;
41
+ }
42
+ if (typeof category === "string") return rootLogger.getChild(category);
43
+ if (category.length === 0) return rootLogger;
44
+ return rootLogger.getChild(category);
45
+ }
46
+ constructor(parent, category) {
47
+ this.parent = parent;
48
+ this.children = {};
49
+ this.category = category;
50
+ this.sinks = [];
51
+ this.filters = [];
52
+ }
53
+ getChild(subcategory) {
54
+ const name = typeof subcategory === "string" ? subcategory : subcategory[0];
55
+ const childRef = this.children[name];
56
+ let child = childRef instanceof LoggerImpl ? childRef : childRef?.deref();
57
+ if (child == null) {
58
+ child = new LoggerImpl(this, [...this.category, name]);
59
+ this.children[name] = "WeakRef" in globalThis ? new WeakRef(child) : child;
60
+ }
61
+ if (typeof subcategory === "string" || subcategory.length === 1) return child;
62
+ return child.getChild(subcategory.slice(1));
63
+ }
64
+ /**
65
+ * Reset the logger. This removes all sinks and filters from the logger.
66
+ */
67
+ reset() {
68
+ while (this.sinks.length > 0) this.sinks.shift();
69
+ this.parentSinks = "inherit";
70
+ while (this.filters.length > 0) this.filters.shift();
71
+ this.lowestLevel = "debug";
72
+ }
73
+ /**
74
+ * Reset the logger and all its descendants. This removes all sinks and
75
+ * filters from the logger and all its descendants.
76
+ */
77
+ resetDescendants() {
78
+ for (const child of Object.values(this.children)) {
79
+ const logger = child instanceof LoggerImpl ? child : child.deref();
80
+ if (logger != null) logger.resetDescendants();
81
+ }
82
+ this.reset();
83
+ }
84
+ with(properties) {
85
+ return new LoggerCtx(this, { ...properties });
86
+ }
87
+ filter(record) {
88
+ for (const filter of this.filters) if (!filter(record)) return false;
89
+ if (this.filters.length < 1) return this.parent?.filter(record) ?? true;
90
+ return true;
91
+ }
92
+ *getSinks(level) {
93
+ if (this.lowestLevel === null || require_level.compareLogLevel(level, this.lowestLevel) < 0) return;
94
+ if (this.parent != null && this.parentSinks === "inherit") for (const sink of this.parent.getSinks(level)) yield sink;
95
+ for (const sink of this.sinks) yield sink;
96
+ }
97
+ emit(record, bypassSinks) {
98
+ if (this.lowestLevel === null || require_level.compareLogLevel(record.level, this.lowestLevel) < 0 || !this.filter(record)) return;
99
+ for (const sink of this.getSinks(record.level)) {
100
+ if (bypassSinks?.has(sink)) continue;
101
+ try {
102
+ sink(record);
103
+ } catch (error) {
104
+ const bypassSinks2 = new Set(bypassSinks);
105
+ bypassSinks2.add(sink);
106
+ metaLogger.log("fatal", "Failed to emit a log record to sink {sink}: {error}", {
107
+ sink,
108
+ error,
109
+ record
110
+ }, bypassSinks2);
111
+ }
112
+ }
113
+ }
114
+ log(level, rawMessage, properties, bypassSinks) {
115
+ const implicitContext = LoggerImpl.getLogger().contextLocalStorage?.getStore() ?? {};
116
+ let cachedProps = void 0;
117
+ const record = typeof properties === "function" ? {
118
+ category: this.category,
119
+ level,
120
+ timestamp: Date.now(),
121
+ get message() {
122
+ return parseMessageTemplate(rawMessage, this.properties);
123
+ },
124
+ rawMessage,
125
+ get properties() {
126
+ if (cachedProps == null) cachedProps = {
127
+ ...implicitContext,
128
+ ...properties()
129
+ };
130
+ return cachedProps;
131
+ }
132
+ } : {
133
+ category: this.category,
134
+ level,
135
+ timestamp: Date.now(),
136
+ message: parseMessageTemplate(rawMessage, {
137
+ ...implicitContext,
138
+ ...properties
139
+ }),
140
+ rawMessage,
141
+ properties: {
142
+ ...implicitContext,
143
+ ...properties
144
+ }
145
+ };
146
+ this.emit(record, bypassSinks);
147
+ }
148
+ logLazily(level, callback, properties = {}) {
149
+ const implicitContext = LoggerImpl.getLogger().contextLocalStorage?.getStore() ?? {};
150
+ let rawMessage = void 0;
151
+ let msg = void 0;
152
+ function realizeMessage() {
153
+ if (msg == null || rawMessage == null) {
154
+ msg = callback((tpl, ...values) => {
155
+ rawMessage = tpl;
156
+ return renderMessage(tpl, values);
157
+ });
158
+ if (rawMessage == null) throw new TypeError("No log record was made.");
159
+ }
160
+ return [msg, rawMessage];
161
+ }
162
+ this.emit({
163
+ category: this.category,
164
+ level,
165
+ get message() {
166
+ return realizeMessage()[0];
167
+ },
168
+ get rawMessage() {
169
+ return realizeMessage()[1];
170
+ },
171
+ timestamp: Date.now(),
172
+ properties: {
173
+ ...implicitContext,
174
+ ...properties
175
+ }
176
+ });
177
+ }
178
+ logTemplate(level, messageTemplate, values, properties = {}) {
179
+ const implicitContext = LoggerImpl.getLogger().contextLocalStorage?.getStore() ?? {};
180
+ this.emit({
181
+ category: this.category,
182
+ level,
183
+ message: renderMessage(messageTemplate, values),
184
+ rawMessage: messageTemplate,
185
+ timestamp: Date.now(),
186
+ properties: {
187
+ ...implicitContext,
188
+ ...properties
189
+ }
190
+ });
191
+ }
192
+ debug(message, ...values) {
193
+ if (typeof message === "string") this.log("debug", message, values[0] ?? {});
194
+ else if (typeof message === "function") this.logLazily("debug", message);
195
+ else if (!Array.isArray(message)) this.log("debug", "{*}", message);
196
+ else this.logTemplate("debug", message, values);
197
+ }
198
+ info(message, ...values) {
199
+ if (typeof message === "string") this.log("info", message, values[0] ?? {});
200
+ else if (typeof message === "function") this.logLazily("info", message);
201
+ else if (!Array.isArray(message)) this.log("info", "{*}", message);
202
+ else this.logTemplate("info", message, values);
203
+ }
204
+ warn(message, ...values) {
205
+ if (typeof message === "string") this.log("warning", message, values[0] ?? {});
206
+ else if (typeof message === "function") this.logLazily("warning", message);
207
+ else if (!Array.isArray(message)) this.log("warning", "{*}", message);
208
+ else this.logTemplate("warning", message, values);
209
+ }
210
+ error(message, ...values) {
211
+ if (typeof message === "string") this.log("error", message, values[0] ?? {});
212
+ else if (typeof message === "function") this.logLazily("error", message);
213
+ else if (!Array.isArray(message)) this.log("error", "{*}", message);
214
+ else this.logTemplate("error", message, values);
215
+ }
216
+ fatal(message, ...values) {
217
+ if (typeof message === "string") this.log("fatal", message, values[0] ?? {});
218
+ else if (typeof message === "function") this.logLazily("fatal", message);
219
+ else if (!Array.isArray(message)) this.log("fatal", "{*}", message);
220
+ else this.logTemplate("fatal", message, values);
221
+ }
222
+ };
223
+ /**
224
+ * A logger implementation with contextual properties. Do not use this
225
+ * directly; use {@link Logger.with} instead. This class is exported
226
+ * for testing purposes.
227
+ */
228
+ var LoggerCtx = class LoggerCtx {
229
+ logger;
230
+ properties;
231
+ constructor(logger, properties) {
232
+ this.logger = logger;
233
+ this.properties = properties;
234
+ }
235
+ get category() {
236
+ return this.logger.category;
237
+ }
238
+ get parent() {
239
+ return this.logger.parent;
240
+ }
241
+ getChild(subcategory) {
242
+ return this.logger.getChild(subcategory).with(this.properties);
243
+ }
244
+ with(properties) {
245
+ return new LoggerCtx(this.logger, {
246
+ ...this.properties,
247
+ ...properties
248
+ });
249
+ }
250
+ log(level, message, properties, bypassSinks) {
251
+ this.logger.log(level, message, typeof properties === "function" ? () => ({
252
+ ...this.properties,
253
+ ...properties()
254
+ }) : {
255
+ ...this.properties,
256
+ ...properties
257
+ }, bypassSinks);
258
+ }
259
+ logLazily(level, callback) {
260
+ this.logger.logLazily(level, callback, this.properties);
261
+ }
262
+ logTemplate(level, messageTemplate, values) {
263
+ this.logger.logTemplate(level, messageTemplate, values, this.properties);
264
+ }
265
+ debug(message, ...values) {
266
+ if (typeof message === "string") this.log("debug", message, values[0] ?? {});
267
+ else if (typeof message === "function") this.logLazily("debug", message);
268
+ else if (!Array.isArray(message)) this.log("debug", "{*}", message);
269
+ else this.logTemplate("debug", message, values);
270
+ }
271
+ info(message, ...values) {
272
+ if (typeof message === "string") this.log("info", message, values[0] ?? {});
273
+ else if (typeof message === "function") this.logLazily("info", message);
274
+ else if (!Array.isArray(message)) this.log("info", "{*}", message);
275
+ else this.logTemplate("info", message, values);
276
+ }
277
+ warn(message, ...values) {
278
+ if (typeof message === "string") this.log("warning", message, values[0] ?? {});
279
+ else if (typeof message === "function") this.logLazily("warning", message);
280
+ else if (!Array.isArray(message)) this.log("warning", "{*}", message);
281
+ else this.logTemplate("warning", message, values);
282
+ }
283
+ error(message, ...values) {
284
+ if (typeof message === "string") this.log("error", message, values[0] ?? {});
285
+ else if (typeof message === "function") this.logLazily("error", message);
286
+ else if (!Array.isArray(message)) this.log("error", "{*}", message);
287
+ else this.logTemplate("error", message, values);
288
+ }
289
+ fatal(message, ...values) {
290
+ if (typeof message === "string") this.log("fatal", message, values[0] ?? {});
291
+ else if (typeof message === "function") this.logLazily("fatal", message);
292
+ else if (!Array.isArray(message)) this.log("fatal", "{*}", message);
293
+ else this.logTemplate("fatal", message, values);
294
+ }
295
+ };
296
+ /**
297
+ * The meta logger. It is a logger with the category `["logtape", "meta"]`.
298
+ */
299
+ const metaLogger = LoggerImpl.getLogger(["logtape", "meta"]);
300
+ /**
301
+ * Parse a message template into a message template array and a values array.
302
+ * @param template The message template.
303
+ * @param properties The values to replace placeholders with.
304
+ * @returns The message template array and the values array.
305
+ */
306
+ function parseMessageTemplate(template, properties) {
307
+ const message = [];
308
+ let part = "";
309
+ for (let i = 0; i < template.length; i++) {
310
+ const char = template.charAt(i);
311
+ const nextChar = template.charAt(i + 1);
312
+ if (char === "{" && nextChar === "{") {
313
+ part = part + char;
314
+ i++;
315
+ } else if (char === "}" && nextChar === "}") {
316
+ part = part + char;
317
+ i++;
318
+ } else if (char === "{") {
319
+ message.push(part);
320
+ part = "";
321
+ } else if (char === "}") {
322
+ let prop;
323
+ if (part.match(/^\s*\*\s*$/)) prop = part in properties ? properties[part] : "*" in properties ? properties["*"] : properties;
324
+ else if (part.match(/^\s|\s$/)) prop = part in properties ? properties[part] : properties[part.trim()];
325
+ else prop = properties[part];
326
+ message.push(prop);
327
+ part = "";
328
+ } else part = part + char;
329
+ }
330
+ message.push(part);
331
+ return message;
332
+ }
333
+ /**
334
+ * Render a message template with values.
335
+ * @param template The message template.
336
+ * @param values The message template values.
337
+ * @returns The message template values interleaved between the substitution
338
+ * values.
339
+ */
340
+ function renderMessage(template, values) {
341
+ const args = [];
342
+ for (let i = 0; i < template.length; i++) {
343
+ args.push(template[i]);
344
+ if (i < values.length) args.push(values[i]);
345
+ }
346
+ return args;
347
+ }
348
+
349
+ //#endregion
350
+ exports.LoggerImpl = LoggerImpl;
351
+ exports.getLogger = getLogger;