lognal 0.1.0

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 (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +99 -0
  3. package/dist/core/filter.d.ts +29 -0
  4. package/dist/core/filter.js +82 -0
  5. package/dist/core/layout/entry-lines.d.ts +16 -0
  6. package/dist/core/layout/entry-lines.js +120 -0
  7. package/dist/core/layout/layout.d.ts +152 -0
  8. package/dist/core/layout/layout.js +784 -0
  9. package/dist/core/layout/row-index.d.ts +33 -0
  10. package/dist/core/layout/row-index.js +99 -0
  11. package/dist/core/layout/types.d.ts +128 -0
  12. package/dist/core/layout/types.js +8 -0
  13. package/dist/core/store.d.ts +96 -0
  14. package/dist/core/store.js +204 -0
  15. package/dist/core/text/ansi.d.ts +20 -0
  16. package/dist/core/text/ansi.js +187 -0
  17. package/dist/core/text/graphemes.d.ts +17 -0
  18. package/dist/core/text/graphemes.js +70 -0
  19. package/dist/core/text/line-splitter.d.ts +18 -0
  20. package/dist/core/text/line-splitter.js +56 -0
  21. package/dist/core/text/measure.d.ts +10 -0
  22. package/dist/core/text/measure.js +38 -0
  23. package/dist/core/text/shape.d.ts +24 -0
  24. package/dist/core/text/shape.js +220 -0
  25. package/dist/core/text/unicode-width-data.d.ts +54 -0
  26. package/dist/core/text/unicode-width-data.js +227 -0
  27. package/dist/core/text/width.d.ts +20 -0
  28. package/dist/core/text/width.js +157 -0
  29. package/dist/core/text/wrap.d.ts +14 -0
  30. package/dist/core/text/wrap.js +94 -0
  31. package/dist/core/time.d.ts +10 -0
  32. package/dist/core/time.js +24 -0
  33. package/dist/core/types.d.ts +131 -0
  34. package/dist/core/types.js +9 -0
  35. package/dist/core/value/preview.d.ts +16 -0
  36. package/dist/core/value/preview.js +207 -0
  37. package/dist/index.d.ts +27 -0
  38. package/dist/index.js +24 -0
  39. package/dist/lognal.css +589 -0
  40. package/dist/react/LogViewer.d.ts +32 -0
  41. package/dist/react/LogViewer.js +183 -0
  42. package/dist/react/index.d.ts +1 -0
  43. package/dist/react/index.js +2 -0
  44. package/dist/renderer/canvas/canvas-renderer.d.ts +45 -0
  45. package/dist/renderer/canvas/canvas-renderer.js +464 -0
  46. package/dist/renderer/canvas/palette.d.ts +6 -0
  47. package/dist/renderer/canvas/palette.js +25 -0
  48. package/dist/renderer/theme.d.ts +3 -0
  49. package/dist/renderer/theme.js +52 -0
  50. package/dist/renderer/types.d.ts +82 -0
  51. package/dist/renderer/types.js +1 -0
  52. package/dist/sources/console/format.d.ts +32 -0
  53. package/dist/sources/console/format.js +189 -0
  54. package/dist/sources/console/hook.d.ts +27 -0
  55. package/dist/sources/console/hook.js +94 -0
  56. package/dist/sources/console/recorder.d.ts +41 -0
  57. package/dist/sources/console/recorder.js +239 -0
  58. package/dist/sources/console/snapshot.d.ts +22 -0
  59. package/dist/sources/console/snapshot.js +547 -0
  60. package/dist/sources/console/table.d.ts +9 -0
  61. package/dist/sources/console/table.js +87 -0
  62. package/dist/sources/text/encoding.d.ts +11 -0
  63. package/dist/sources/text/encoding.js +59 -0
  64. package/dist/sources/text/follow-file.d.ts +49 -0
  65. package/dist/sources/text/follow-file.js +109 -0
  66. package/dist/sources/text/read-file.d.ts +63 -0
  67. package/dist/sources/text/read-file.js +82 -0
  68. package/dist/viewer/icons.d.ts +14 -0
  69. package/dist/viewer/icons.js +30 -0
  70. package/dist/viewer/input-line.d.ts +46 -0
  71. package/dist/viewer/input-line.js +144 -0
  72. package/dist/viewer/labels.d.ts +35 -0
  73. package/dist/viewer/labels.js +61 -0
  74. package/dist/viewer/scrollbar.d.ts +27 -0
  75. package/dist/viewer/scrollbar.js +143 -0
  76. package/dist/viewer/theme.d.ts +15 -0
  77. package/dist/viewer/theme.js +105 -0
  78. package/dist/viewer/viewer.d.ts +217 -0
  79. package/dist/viewer/viewer.js +1201 -0
  80. package/package.json +92 -0
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Character width data generated from the Unicode Character Database 17.0.0
3
+ * (EastAsianWidth.txt and DerivedGeneralCategory.txt) by
4
+ * `scripts/generate-unicode-width.mjs`. Do not edit this file by hand.
5
+ *
6
+ * Every list holds inclusive `[start, end]` pairs, flattened and sorted.
7
+ *
8
+ * UNICODE LICENSE V3
9
+ *
10
+ * COPYRIGHT AND PERMISSION NOTICE
11
+ *
12
+ * Copyright © 1991-2026 Unicode, Inc.
13
+ *
14
+ * NOTICE TO USER: Carefully read the following legal agreement. BY
15
+ * DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
16
+ * SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
17
+ * TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT
18
+ * DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
19
+ *
20
+ * Permission is hereby granted, free of charge, to any person obtaining a
21
+ * copy of data files and any associated documentation (the "Data Files") or
22
+ * software and any associated documentation (the "Software") to deal in the
23
+ * Data Files or Software without restriction, including without limitation
24
+ * the rights to use, copy, modify, merge, publish, distribute, and/or sell
25
+ * copies of the Data Files or Software, and to permit persons to whom the
26
+ * Data Files or Software are furnished to do so, provided that either (a)
27
+ * this copyright and permission notice appear with all copies of the Data
28
+ * Files or Software, or (b) this copyright and permission notice appear in
29
+ * associated Documentation.
30
+ *
31
+ * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
32
+ * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
34
+ * THIRD PARTY RIGHTS.
35
+ *
36
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE
37
+ * BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
38
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA
41
+ * FILES OR SOFTWARE.
42
+ *
43
+ * Except as contained in this notice, the name of a copyright holder shall
44
+ * not be used in advertising or otherwise to promote the sale, use or other
45
+ * dealings in these Data Files or Software without prior written
46
+ * authorization of the copyright holder.
47
+ */
48
+ export declare const UNICODE_VERSION = "17.0.0";
49
+ /** East Asian Wide and Fullwidth code points, drawn two cells wide. */
50
+ export declare const WIDE_RANGES: readonly number[];
51
+ /** East Asian Ambiguous code points, one or two cells wide depending on the option. */
52
+ export declare const AMBIGUOUS_RANGES: readonly number[];
53
+ /** Combining marks, format characters and Hangul jamo that attach to the previous character. */
54
+ export declare const ZERO_WIDTH_RANGES: readonly number[];
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Character width data generated from the Unicode Character Database 17.0.0
3
+ * (EastAsianWidth.txt and DerivedGeneralCategory.txt) by
4
+ * `scripts/generate-unicode-width.mjs`. Do not edit this file by hand.
5
+ *
6
+ * Every list holds inclusive `[start, end]` pairs, flattened and sorted.
7
+ *
8
+ * UNICODE LICENSE V3
9
+ *
10
+ * COPYRIGHT AND PERMISSION NOTICE
11
+ *
12
+ * Copyright © 1991-2026 Unicode, Inc.
13
+ *
14
+ * NOTICE TO USER: Carefully read the following legal agreement. BY
15
+ * DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR
16
+ * SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
17
+ * TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT
18
+ * DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
19
+ *
20
+ * Permission is hereby granted, free of charge, to any person obtaining a
21
+ * copy of data files and any associated documentation (the "Data Files") or
22
+ * software and any associated documentation (the "Software") to deal in the
23
+ * Data Files or Software without restriction, including without limitation
24
+ * the rights to use, copy, modify, merge, publish, distribute, and/or sell
25
+ * copies of the Data Files or Software, and to permit persons to whom the
26
+ * Data Files or Software are furnished to do so, provided that either (a)
27
+ * this copyright and permission notice appear with all copies of the Data
28
+ * Files or Software, or (b) this copyright and permission notice appear in
29
+ * associated Documentation.
30
+ *
31
+ * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
32
+ * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
34
+ * THIRD PARTY RIGHTS.
35
+ *
36
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE
37
+ * BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,
38
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA
41
+ * FILES OR SOFTWARE.
42
+ *
43
+ * Except as contained in this notice, the name of a copyright holder shall
44
+ * not be used in advertising or otherwise to promote the sale, use or other
45
+ * dealings in these Data Files or Software without prior written
46
+ * authorization of the copyright holder.
47
+ */
48
+ export const UNICODE_VERSION = '17.0.0';
49
+ /** East Asian Wide and Fullwidth code points, drawn two cells wide. */
50
+ export const WIDE_RANGES = [
51
+ 0x1100, 0x115f, 0x231a, 0x231b, 0x2329, 0x232a, 0x23e9, 0x23ec,
52
+ 0x23f0, 0x23f0, 0x23f3, 0x23f3, 0x25fd, 0x25fe, 0x2614, 0x2615,
53
+ 0x2630, 0x2637, 0x2648, 0x2653, 0x267f, 0x267f, 0x268a, 0x268f,
54
+ 0x2693, 0x2693, 0x26a1, 0x26a1, 0x26aa, 0x26ab, 0x26bd, 0x26be,
55
+ 0x26c4, 0x26c5, 0x26ce, 0x26ce, 0x26d4, 0x26d4, 0x26ea, 0x26ea,
56
+ 0x26f2, 0x26f3, 0x26f5, 0x26f5, 0x26fa, 0x26fa, 0x26fd, 0x26fd,
57
+ 0x2705, 0x2705, 0x270a, 0x270b, 0x2728, 0x2728, 0x274c, 0x274c,
58
+ 0x274e, 0x274e, 0x2753, 0x2755, 0x2757, 0x2757, 0x2795, 0x2797,
59
+ 0x27b0, 0x27b0, 0x27bf, 0x27bf, 0x2b1b, 0x2b1c, 0x2b50, 0x2b50,
60
+ 0x2b55, 0x2b55, 0x2e80, 0x2e99, 0x2e9b, 0x2ef3, 0x2f00, 0x2fd5,
61
+ 0x2ff0, 0x3029, 0x302e, 0x303e, 0x3041, 0x3096, 0x309b, 0x30ff,
62
+ 0x3105, 0x312f, 0x3131, 0x318e, 0x3190, 0x31e5, 0x31ef, 0x321e,
63
+ 0x3220, 0x3247, 0x3250, 0xa48c, 0xa490, 0xa4c6, 0xa960, 0xa97c,
64
+ 0xac00, 0xd7a3, 0xf900, 0xfaff, 0xfe10, 0xfe19, 0xfe30, 0xfe52,
65
+ 0xfe54, 0xfe66, 0xfe68, 0xfe6b, 0xff01, 0xff60, 0xffe0, 0xffe6,
66
+ 0x16fe0, 0x16fe3, 0x16ff0, 0x16ff6, 0x17000, 0x18cd5, 0x18cff, 0x18d1e,
67
+ 0x18d80, 0x18df2, 0x1aff0, 0x1aff3, 0x1aff5, 0x1affb, 0x1affd, 0x1affe,
68
+ 0x1b000, 0x1b122, 0x1b132, 0x1b132, 0x1b150, 0x1b152, 0x1b155, 0x1b155,
69
+ 0x1b164, 0x1b167, 0x1b170, 0x1b2fb, 0x1d300, 0x1d356, 0x1d360, 0x1d376,
70
+ 0x1f004, 0x1f004, 0x1f0cf, 0x1f0cf, 0x1f18e, 0x1f18e, 0x1f191, 0x1f19a,
71
+ 0x1f200, 0x1f202, 0x1f210, 0x1f23b, 0x1f240, 0x1f248, 0x1f250, 0x1f251,
72
+ 0x1f260, 0x1f265, 0x1f300, 0x1f320, 0x1f32d, 0x1f335, 0x1f337, 0x1f37c,
73
+ 0x1f37e, 0x1f393, 0x1f3a0, 0x1f3ca, 0x1f3cf, 0x1f3d3, 0x1f3e0, 0x1f3f0,
74
+ 0x1f3f4, 0x1f3f4, 0x1f3f8, 0x1f43e, 0x1f440, 0x1f440, 0x1f442, 0x1f4fc,
75
+ 0x1f4ff, 0x1f53d, 0x1f54b, 0x1f54e, 0x1f550, 0x1f567, 0x1f57a, 0x1f57a,
76
+ 0x1f595, 0x1f596, 0x1f5a4, 0x1f5a4, 0x1f5fb, 0x1f64f, 0x1f680, 0x1f6c5,
77
+ 0x1f6cc, 0x1f6cc, 0x1f6d0, 0x1f6d2, 0x1f6d5, 0x1f6d8, 0x1f6dc, 0x1f6df,
78
+ 0x1f6eb, 0x1f6ec, 0x1f6f4, 0x1f6fc, 0x1f7e0, 0x1f7eb, 0x1f7f0, 0x1f7f0,
79
+ 0x1f90c, 0x1f93a, 0x1f93c, 0x1f945, 0x1f947, 0x1f9ff, 0x1fa70, 0x1fa7c,
80
+ 0x1fa80, 0x1fa8a, 0x1fa8e, 0x1fac6, 0x1fac8, 0x1fac8, 0x1facd, 0x1fadc,
81
+ 0x1fadf, 0x1faea, 0x1faef, 0x1faf8, 0x20000, 0x2fffd, 0x30000, 0x3fffd
82
+ ];
83
+ /** East Asian Ambiguous code points, one or two cells wide depending on the option. */
84
+ export const AMBIGUOUS_RANGES = [
85
+ 0xa1, 0xa1, 0xa4, 0xa4, 0xa7, 0xa8, 0xaa, 0xaa,
86
+ 0xae, 0xae, 0xb0, 0xb4, 0xb6, 0xba, 0xbc, 0xbf,
87
+ 0xc6, 0xc6, 0xd0, 0xd0, 0xd7, 0xd8, 0xde, 0xe1,
88
+ 0xe6, 0xe6, 0xe8, 0xea, 0xec, 0xed, 0xf0, 0xf0,
89
+ 0xf2, 0xf3, 0xf7, 0xfa, 0xfc, 0xfc, 0xfe, 0xfe,
90
+ 0x101, 0x101, 0x111, 0x111, 0x113, 0x113, 0x11b, 0x11b,
91
+ 0x126, 0x127, 0x12b, 0x12b, 0x131, 0x133, 0x138, 0x138,
92
+ 0x13f, 0x142, 0x144, 0x144, 0x148, 0x14b, 0x14d, 0x14d,
93
+ 0x152, 0x153, 0x166, 0x167, 0x16b, 0x16b, 0x1ce, 0x1ce,
94
+ 0x1d0, 0x1d0, 0x1d2, 0x1d2, 0x1d4, 0x1d4, 0x1d6, 0x1d6,
95
+ 0x1d8, 0x1d8, 0x1da, 0x1da, 0x1dc, 0x1dc, 0x251, 0x251,
96
+ 0x261, 0x261, 0x2c4, 0x2c4, 0x2c7, 0x2c7, 0x2c9, 0x2cb,
97
+ 0x2cd, 0x2cd, 0x2d0, 0x2d0, 0x2d8, 0x2db, 0x2dd, 0x2dd,
98
+ 0x2df, 0x2df, 0x391, 0x3a1, 0x3a3, 0x3a9, 0x3b1, 0x3c1,
99
+ 0x3c3, 0x3c9, 0x401, 0x401, 0x410, 0x44f, 0x451, 0x451,
100
+ 0x2010, 0x2010, 0x2013, 0x2016, 0x2018, 0x2019, 0x201c, 0x201d,
101
+ 0x2020, 0x2022, 0x2024, 0x2027, 0x2030, 0x2030, 0x2032, 0x2033,
102
+ 0x2035, 0x2035, 0x203b, 0x203b, 0x203e, 0x203e, 0x2074, 0x2074,
103
+ 0x207f, 0x207f, 0x2081, 0x2084, 0x20ac, 0x20ac, 0x2103, 0x2103,
104
+ 0x2105, 0x2105, 0x2109, 0x2109, 0x2113, 0x2113, 0x2116, 0x2116,
105
+ 0x2121, 0x2122, 0x2126, 0x2126, 0x212b, 0x212b, 0x2153, 0x2154,
106
+ 0x215b, 0x215e, 0x2160, 0x216b, 0x2170, 0x2179, 0x2189, 0x2189,
107
+ 0x2190, 0x2199, 0x21b8, 0x21b9, 0x21d2, 0x21d2, 0x21d4, 0x21d4,
108
+ 0x21e7, 0x21e7, 0x2200, 0x2200, 0x2202, 0x2203, 0x2207, 0x2208,
109
+ 0x220b, 0x220b, 0x220f, 0x220f, 0x2211, 0x2211, 0x2215, 0x2215,
110
+ 0x221a, 0x221a, 0x221d, 0x2220, 0x2223, 0x2223, 0x2225, 0x2225,
111
+ 0x2227, 0x222c, 0x222e, 0x222e, 0x2234, 0x2237, 0x223c, 0x223d,
112
+ 0x2248, 0x2248, 0x224c, 0x224c, 0x2252, 0x2252, 0x2260, 0x2261,
113
+ 0x2264, 0x2267, 0x226a, 0x226b, 0x226e, 0x226f, 0x2282, 0x2283,
114
+ 0x2286, 0x2287, 0x2295, 0x2295, 0x2299, 0x2299, 0x22a5, 0x22a5,
115
+ 0x22bf, 0x22bf, 0x2312, 0x2312, 0x2460, 0x24e9, 0x24eb, 0x254b,
116
+ 0x2550, 0x2573, 0x2580, 0x258f, 0x2592, 0x2595, 0x25a0, 0x25a1,
117
+ 0x25a3, 0x25a9, 0x25b2, 0x25b3, 0x25b6, 0x25b7, 0x25bc, 0x25bd,
118
+ 0x25c0, 0x25c1, 0x25c6, 0x25c8, 0x25cb, 0x25cb, 0x25ce, 0x25d1,
119
+ 0x25e2, 0x25e5, 0x25ef, 0x25ef, 0x2605, 0x2606, 0x2609, 0x2609,
120
+ 0x260e, 0x260f, 0x261c, 0x261c, 0x261e, 0x261e, 0x2640, 0x2640,
121
+ 0x2642, 0x2642, 0x2660, 0x2661, 0x2663, 0x2665, 0x2667, 0x266a,
122
+ 0x266c, 0x266d, 0x266f, 0x266f, 0x269e, 0x269f, 0x26bf, 0x26bf,
123
+ 0x26c6, 0x26cd, 0x26cf, 0x26d3, 0x26d5, 0x26e1, 0x26e3, 0x26e3,
124
+ 0x26e8, 0x26e9, 0x26eb, 0x26f1, 0x26f4, 0x26f4, 0x26f6, 0x26f9,
125
+ 0x26fb, 0x26fc, 0x26fe, 0x26ff, 0x273d, 0x273d, 0x2776, 0x277f,
126
+ 0x2b56, 0x2b59, 0x3248, 0x324f, 0xe000, 0xf8ff, 0xfffd, 0xfffd,
127
+ 0x1f100, 0x1f10a, 0x1f110, 0x1f12d, 0x1f130, 0x1f169, 0x1f170, 0x1f18d,
128
+ 0x1f18f, 0x1f190, 0x1f19b, 0x1f1ac, 0xf0000, 0xffffd, 0x100000, 0x10fffd
129
+ ];
130
+ /** Combining marks, format characters and Hangul jamo that attach to the previous character. */
131
+ export const ZERO_WIDTH_RANGES = [
132
+ 0xad, 0xad, 0x300, 0x36f, 0x483, 0x489, 0x591, 0x5bd,
133
+ 0x5bf, 0x5bf, 0x5c1, 0x5c2, 0x5c4, 0x5c5, 0x5c7, 0x5c7,
134
+ 0x600, 0x605, 0x610, 0x61a, 0x61c, 0x61c, 0x64b, 0x65f,
135
+ 0x670, 0x670, 0x6d6, 0x6dd, 0x6df, 0x6e4, 0x6e7, 0x6e8,
136
+ 0x6ea, 0x6ed, 0x70f, 0x70f, 0x711, 0x711, 0x730, 0x74a,
137
+ 0x7a6, 0x7b0, 0x7eb, 0x7f3, 0x7fd, 0x7fd, 0x816, 0x819,
138
+ 0x81b, 0x823, 0x825, 0x827, 0x829, 0x82d, 0x859, 0x85b,
139
+ 0x890, 0x891, 0x897, 0x89f, 0x8ca, 0x902, 0x93a, 0x93a,
140
+ 0x93c, 0x93c, 0x941, 0x948, 0x94d, 0x94d, 0x951, 0x957,
141
+ 0x962, 0x963, 0x981, 0x981, 0x9bc, 0x9bc, 0x9c1, 0x9c4,
142
+ 0x9cd, 0x9cd, 0x9e2, 0x9e3, 0x9fe, 0x9fe, 0xa01, 0xa02,
143
+ 0xa3c, 0xa3c, 0xa41, 0xa42, 0xa47, 0xa48, 0xa4b, 0xa4d,
144
+ 0xa51, 0xa51, 0xa70, 0xa71, 0xa75, 0xa75, 0xa81, 0xa82,
145
+ 0xabc, 0xabc, 0xac1, 0xac5, 0xac7, 0xac8, 0xacd, 0xacd,
146
+ 0xae2, 0xae3, 0xafa, 0xaff, 0xb01, 0xb01, 0xb3c, 0xb3c,
147
+ 0xb3f, 0xb3f, 0xb41, 0xb44, 0xb4d, 0xb4d, 0xb55, 0xb56,
148
+ 0xb62, 0xb63, 0xb82, 0xb82, 0xbc0, 0xbc0, 0xbcd, 0xbcd,
149
+ 0xc00, 0xc00, 0xc04, 0xc04, 0xc3c, 0xc3c, 0xc3e, 0xc40,
150
+ 0xc46, 0xc48, 0xc4a, 0xc4d, 0xc55, 0xc56, 0xc62, 0xc63,
151
+ 0xc81, 0xc81, 0xcbc, 0xcbc, 0xcbf, 0xcbf, 0xcc6, 0xcc6,
152
+ 0xccc, 0xccd, 0xce2, 0xce3, 0xd00, 0xd01, 0xd3b, 0xd3c,
153
+ 0xd41, 0xd44, 0xd4d, 0xd4d, 0xd62, 0xd63, 0xd81, 0xd81,
154
+ 0xdca, 0xdca, 0xdd2, 0xdd4, 0xdd6, 0xdd6, 0xe31, 0xe31,
155
+ 0xe34, 0xe3a, 0xe47, 0xe4e, 0xeb1, 0xeb1, 0xeb4, 0xebc,
156
+ 0xec8, 0xece, 0xf18, 0xf19, 0xf35, 0xf35, 0xf37, 0xf37,
157
+ 0xf39, 0xf39, 0xf71, 0xf7e, 0xf80, 0xf84, 0xf86, 0xf87,
158
+ 0xf8d, 0xf97, 0xf99, 0xfbc, 0xfc6, 0xfc6, 0x102d, 0x1030,
159
+ 0x1032, 0x1037, 0x1039, 0x103a, 0x103d, 0x103e, 0x1058, 0x1059,
160
+ 0x105e, 0x1060, 0x1071, 0x1074, 0x1082, 0x1082, 0x1085, 0x1086,
161
+ 0x108d, 0x108d, 0x109d, 0x109d, 0x1160, 0x11ff, 0x135d, 0x135f,
162
+ 0x1712, 0x1714, 0x1732, 0x1733, 0x1752, 0x1753, 0x1772, 0x1773,
163
+ 0x17b4, 0x17b5, 0x17b7, 0x17bd, 0x17c6, 0x17c6, 0x17c9, 0x17d3,
164
+ 0x17dd, 0x17dd, 0x180b, 0x180f, 0x1885, 0x1886, 0x18a9, 0x18a9,
165
+ 0x1920, 0x1922, 0x1927, 0x1928, 0x1932, 0x1932, 0x1939, 0x193b,
166
+ 0x1a17, 0x1a18, 0x1a1b, 0x1a1b, 0x1a56, 0x1a56, 0x1a58, 0x1a5e,
167
+ 0x1a60, 0x1a60, 0x1a62, 0x1a62, 0x1a65, 0x1a6c, 0x1a73, 0x1a7c,
168
+ 0x1a7f, 0x1a7f, 0x1ab0, 0x1add, 0x1ae0, 0x1aeb, 0x1b00, 0x1b03,
169
+ 0x1b34, 0x1b34, 0x1b36, 0x1b3a, 0x1b3c, 0x1b3c, 0x1b42, 0x1b42,
170
+ 0x1b6b, 0x1b73, 0x1b80, 0x1b81, 0x1ba2, 0x1ba5, 0x1ba8, 0x1ba9,
171
+ 0x1bab, 0x1bad, 0x1be6, 0x1be6, 0x1be8, 0x1be9, 0x1bed, 0x1bed,
172
+ 0x1bef, 0x1bf1, 0x1c2c, 0x1c33, 0x1c36, 0x1c37, 0x1cd0, 0x1cd2,
173
+ 0x1cd4, 0x1ce0, 0x1ce2, 0x1ce8, 0x1ced, 0x1ced, 0x1cf4, 0x1cf4,
174
+ 0x1cf8, 0x1cf9, 0x1dc0, 0x1dff, 0x200b, 0x200f, 0x202a, 0x202e,
175
+ 0x2060, 0x2064, 0x2066, 0x206f, 0x20d0, 0x20f0, 0x2cef, 0x2cf1,
176
+ 0x2d7f, 0x2d7f, 0x2de0, 0x2dff, 0x302a, 0x302d, 0x3099, 0x309a,
177
+ 0xa66f, 0xa672, 0xa674, 0xa67d, 0xa69e, 0xa69f, 0xa6f0, 0xa6f1,
178
+ 0xa802, 0xa802, 0xa806, 0xa806, 0xa80b, 0xa80b, 0xa825, 0xa826,
179
+ 0xa82c, 0xa82c, 0xa8c4, 0xa8c5, 0xa8e0, 0xa8f1, 0xa8ff, 0xa8ff,
180
+ 0xa926, 0xa92d, 0xa947, 0xa951, 0xa980, 0xa982, 0xa9b3, 0xa9b3,
181
+ 0xa9b6, 0xa9b9, 0xa9bc, 0xa9bd, 0xa9e5, 0xa9e5, 0xaa29, 0xaa2e,
182
+ 0xaa31, 0xaa32, 0xaa35, 0xaa36, 0xaa43, 0xaa43, 0xaa4c, 0xaa4c,
183
+ 0xaa7c, 0xaa7c, 0xaab0, 0xaab0, 0xaab2, 0xaab4, 0xaab7, 0xaab8,
184
+ 0xaabe, 0xaabf, 0xaac1, 0xaac1, 0xaaec, 0xaaed, 0xaaf6, 0xaaf6,
185
+ 0xabe5, 0xabe5, 0xabe8, 0xabe8, 0xabed, 0xabed, 0xd7b0, 0xd7ff,
186
+ 0xfb1e, 0xfb1e, 0xfe00, 0xfe0f, 0xfe20, 0xfe2f, 0xfeff, 0xfeff,
187
+ 0xfff9, 0xfffb, 0x101fd, 0x101fd, 0x102e0, 0x102e0, 0x10376, 0x1037a,
188
+ 0x10a01, 0x10a03, 0x10a05, 0x10a06, 0x10a0c, 0x10a0f, 0x10a38, 0x10a3a,
189
+ 0x10a3f, 0x10a3f, 0x10ae5, 0x10ae6, 0x10d24, 0x10d27, 0x10d69, 0x10d6d,
190
+ 0x10eab, 0x10eac, 0x10efa, 0x10eff, 0x10f46, 0x10f50, 0x10f82, 0x10f85,
191
+ 0x11001, 0x11001, 0x11038, 0x11046, 0x11070, 0x11070, 0x11073, 0x11074,
192
+ 0x1107f, 0x11081, 0x110b3, 0x110b6, 0x110b9, 0x110ba, 0x110bd, 0x110bd,
193
+ 0x110c2, 0x110c2, 0x110cd, 0x110cd, 0x11100, 0x11102, 0x11127, 0x1112b,
194
+ 0x1112d, 0x11134, 0x11173, 0x11173, 0x11180, 0x11181, 0x111b6, 0x111be,
195
+ 0x111c9, 0x111cc, 0x111cf, 0x111cf, 0x1122f, 0x11231, 0x11234, 0x11234,
196
+ 0x11236, 0x11237, 0x1123e, 0x1123e, 0x11241, 0x11241, 0x112df, 0x112df,
197
+ 0x112e3, 0x112ea, 0x11300, 0x11301, 0x1133b, 0x1133c, 0x11340, 0x11340,
198
+ 0x11366, 0x1136c, 0x11370, 0x11374, 0x113bb, 0x113c0, 0x113ce, 0x113ce,
199
+ 0x113d0, 0x113d0, 0x113d2, 0x113d2, 0x113e1, 0x113e2, 0x11438, 0x1143f,
200
+ 0x11442, 0x11444, 0x11446, 0x11446, 0x1145e, 0x1145e, 0x114b3, 0x114b8,
201
+ 0x114ba, 0x114ba, 0x114bf, 0x114c0, 0x114c2, 0x114c3, 0x115b2, 0x115b5,
202
+ 0x115bc, 0x115bd, 0x115bf, 0x115c0, 0x115dc, 0x115dd, 0x11633, 0x1163a,
203
+ 0x1163d, 0x1163d, 0x1163f, 0x11640, 0x116ab, 0x116ab, 0x116ad, 0x116ad,
204
+ 0x116b0, 0x116b5, 0x116b7, 0x116b7, 0x1171d, 0x1171d, 0x1171f, 0x1171f,
205
+ 0x11722, 0x11725, 0x11727, 0x1172b, 0x1182f, 0x11837, 0x11839, 0x1183a,
206
+ 0x1193b, 0x1193c, 0x1193e, 0x1193e, 0x11943, 0x11943, 0x119d4, 0x119d7,
207
+ 0x119da, 0x119db, 0x119e0, 0x119e0, 0x11a01, 0x11a0a, 0x11a33, 0x11a38,
208
+ 0x11a3b, 0x11a3e, 0x11a47, 0x11a47, 0x11a51, 0x11a56, 0x11a59, 0x11a5b,
209
+ 0x11a8a, 0x11a96, 0x11a98, 0x11a99, 0x11b60, 0x11b60, 0x11b62, 0x11b64,
210
+ 0x11b66, 0x11b66, 0x11c30, 0x11c36, 0x11c38, 0x11c3d, 0x11c3f, 0x11c3f,
211
+ 0x11c92, 0x11ca7, 0x11caa, 0x11cb0, 0x11cb2, 0x11cb3, 0x11cb5, 0x11cb6,
212
+ 0x11d31, 0x11d36, 0x11d3a, 0x11d3a, 0x11d3c, 0x11d3d, 0x11d3f, 0x11d45,
213
+ 0x11d47, 0x11d47, 0x11d90, 0x11d91, 0x11d95, 0x11d95, 0x11d97, 0x11d97,
214
+ 0x11ef3, 0x11ef4, 0x11f00, 0x11f01, 0x11f36, 0x11f3a, 0x11f40, 0x11f40,
215
+ 0x11f42, 0x11f42, 0x11f5a, 0x11f5a, 0x13430, 0x13440, 0x13447, 0x13455,
216
+ 0x1611e, 0x16129, 0x1612d, 0x1612f, 0x16af0, 0x16af4, 0x16b30, 0x16b36,
217
+ 0x16f4f, 0x16f4f, 0x16f8f, 0x16f92, 0x16fe4, 0x16fe4, 0x1bc9d, 0x1bc9e,
218
+ 0x1bca0, 0x1bca3, 0x1cf00, 0x1cf2d, 0x1cf30, 0x1cf46, 0x1d167, 0x1d169,
219
+ 0x1d173, 0x1d182, 0x1d185, 0x1d18b, 0x1d1aa, 0x1d1ad, 0x1d242, 0x1d244,
220
+ 0x1da00, 0x1da36, 0x1da3b, 0x1da6c, 0x1da75, 0x1da75, 0x1da84, 0x1da84,
221
+ 0x1da9b, 0x1da9f, 0x1daa1, 0x1daaf, 0x1e000, 0x1e006, 0x1e008, 0x1e018,
222
+ 0x1e01b, 0x1e021, 0x1e023, 0x1e024, 0x1e026, 0x1e02a, 0x1e08f, 0x1e08f,
223
+ 0x1e130, 0x1e136, 0x1e2ae, 0x1e2ae, 0x1e2ec, 0x1e2ef, 0x1e4ec, 0x1e4ef,
224
+ 0x1e5ee, 0x1e5ef, 0x1e6e3, 0x1e6e3, 0x1e6e6, 0x1e6e6, 0x1e6ee, 0x1e6ef,
225
+ 0x1e6f5, 0x1e6f5, 0x1e8d0, 0x1e8d6, 0x1e944, 0x1e94a, 0xe0001, 0xe0001,
226
+ 0xe0020, 0xe007f, 0xe0100, 0xe01ef
227
+ ];
@@ -0,0 +1,20 @@
1
+ /** How many cells an East Asian Ambiguous character takes. */
2
+ export type AmbiguousWidth = 1 | 2;
3
+ /**
4
+ * Returns how many cells a single code point takes: 0 for combining marks and format
5
+ * characters, 2 for wide characters, and 1 otherwise.
6
+ *
7
+ * Control characters return 1. Callers are expected to replace them with a visible notation
8
+ * before measuring.
9
+ */
10
+ export declare const codePointWidth: (codePoint: number, ambiguousWidth?: AmbiguousWidth) => number;
11
+ /** Returns whether a code point is a Hangul syllable or jamo, where words break at spaces only. */
12
+ export declare const isHangul: (codePoint: number) => boolean;
13
+ /**
14
+ * Returns how many cells a grapheme cluster takes.
15
+ *
16
+ * The widest code point decides, with the rules emoji add on top: a cluster with the emoji
17
+ * variation selector or a pair of regional indicators (a flag) is two cells, and one with the
18
+ * text variation selector is one cell.
19
+ */
20
+ export declare const clusterWidth: (cluster: string, ambiguousWidth?: AmbiguousWidth) => number;
@@ -0,0 +1,157 @@
1
+ import { AMBIGUOUS_RANGES, WIDE_RANGES, ZERO_WIDTH_RANGES } from './unicode-width-data.js';
2
+ const BMP_SIZE = 0x10000;
3
+ // Values stored in `bmpCache`. Zero means the code point has not been looked up yet.
4
+ const CACHE_ZERO = 1;
5
+ const CACHE_NARROW = 2;
6
+ const CACHE_WIDE = 3;
7
+ const CACHE_AMBIGUOUS = 4;
8
+ const REGIONAL_INDICATOR_FIRST = 0x1f1e6;
9
+ const REGIONAL_INDICATOR_LAST = 0x1f1ff;
10
+ const VARIATION_SELECTOR_TEXT = 0xfe0e;
11
+ const VARIATION_SELECTOR_EMOJI = 0xfe0f;
12
+ const bmpCache = new Uint8Array(BMP_SIZE);
13
+ const isInRanges = (ranges, codePoint) => {
14
+ let low = 0;
15
+ let high = ranges.length / 2 - 1;
16
+ if (high < 0 || codePoint < ranges[0] || codePoint > ranges[ranges.length - 1]) {
17
+ return false;
18
+ }
19
+ while (low <= high) {
20
+ const middle = (low + high) >> 1;
21
+ const start = ranges[middle * 2];
22
+ const end = ranges[middle * 2 + 1];
23
+ if (codePoint < start) {
24
+ high = middle - 1;
25
+ }
26
+ else if (codePoint > end) {
27
+ low = middle + 1;
28
+ }
29
+ else {
30
+ return true;
31
+ }
32
+ }
33
+ return false;
34
+ };
35
+ const classify = (codePoint) => {
36
+ // Box drawing and block elements are ambiguous in the data, but monospace fonts draw them
37
+ // one cell wide, and tables drawn with them only line up that way.
38
+ if (codePoint >= 0x2500 && codePoint <= 0x259f) {
39
+ return CACHE_NARROW;
40
+ }
41
+ if (isInRanges(ZERO_WIDTH_RANGES, codePoint)) {
42
+ return CACHE_ZERO;
43
+ }
44
+ if (isInRanges(WIDE_RANGES, codePoint)) {
45
+ return CACHE_WIDE;
46
+ }
47
+ if (isInRanges(AMBIGUOUS_RANGES, codePoint)) {
48
+ return CACHE_AMBIGUOUS;
49
+ }
50
+ return CACHE_NARROW;
51
+ };
52
+ /**
53
+ * Returns how many cells a single code point takes: 0 for combining marks and format
54
+ * characters, 2 for wide characters, and 1 otherwise.
55
+ *
56
+ * Control characters return 1. Callers are expected to replace them with a visible notation
57
+ * before measuring.
58
+ */
59
+ export const codePointWidth = (codePoint, ambiguousWidth = 1) => {
60
+ // Printable ASCII and the Latin-1 range before the first ambiguous character.
61
+ if (codePoint < 0xa1) {
62
+ return 1;
63
+ }
64
+ let kind;
65
+ if (codePoint < BMP_SIZE) {
66
+ kind = bmpCache[codePoint];
67
+ if (kind === 0) {
68
+ kind = classify(codePoint);
69
+ bmpCache[codePoint] = kind;
70
+ }
71
+ }
72
+ else {
73
+ kind = classify(codePoint);
74
+ }
75
+ if (kind === CACHE_ZERO) {
76
+ return 0;
77
+ }
78
+ if (kind === CACHE_WIDE) {
79
+ return 2;
80
+ }
81
+ if (kind === CACHE_AMBIGUOUS) {
82
+ return ambiguousWidth;
83
+ }
84
+ return 1;
85
+ };
86
+ /** Returns whether a code point is a Hangul syllable or jamo, where words break at spaces only. */
87
+ export const isHangul = (codePoint) => {
88
+ return ((codePoint >= 0xac00 && codePoint <= 0xd7a3) ||
89
+ (codePoint >= 0x1100 && codePoint <= 0x11ff) ||
90
+ (codePoint >= 0x3130 && codePoint <= 0x318f) ||
91
+ (codePoint >= 0xa960 && codePoint <= 0xa97f) ||
92
+ (codePoint >= 0xd7b0 && codePoint <= 0xd7ff));
93
+ };
94
+ /**
95
+ * Returns how many cells a grapheme cluster takes.
96
+ *
97
+ * The widest code point decides, with the rules emoji add on top: a cluster with the emoji
98
+ * variation selector or a pair of regional indicators (a flag) is two cells, and one with the
99
+ * text variation selector is one cell.
100
+ */
101
+ export const clusterWidth = (cluster, ambiguousWidth = 1) => {
102
+ if (cluster.length === 1) {
103
+ const code = cluster.charCodeAt(0);
104
+ if (code < 0xa1) {
105
+ return 1;
106
+ }
107
+ return Math.max(codePointWidth(code, ambiguousWidth), isZeroOnly(code) ? 0 : 1);
108
+ }
109
+ let width = 0;
110
+ let hasEmojiSelector = false;
111
+ let hasTextSelector = false;
112
+ let hasRegionalIndicator = false;
113
+ let hasVisible = false;
114
+ for (const character of cluster) {
115
+ const codePoint = character.codePointAt(0) ?? 0;
116
+ if (codePoint === VARIATION_SELECTOR_EMOJI) {
117
+ hasEmojiSelector = true;
118
+ continue;
119
+ }
120
+ if (codePoint === VARIATION_SELECTOR_TEXT) {
121
+ hasTextSelector = true;
122
+ continue;
123
+ }
124
+ if (codePoint >= REGIONAL_INDICATOR_FIRST && codePoint <= REGIONAL_INDICATOR_LAST) {
125
+ hasRegionalIndicator = true;
126
+ }
127
+ const codeWidth = codePointWidth(codePoint, ambiguousWidth);
128
+ if (codeWidth > 0 || !isZeroOnly(codePoint)) {
129
+ hasVisible = true;
130
+ }
131
+ if (codeWidth > width) {
132
+ width = codeWidth;
133
+ }
134
+ }
135
+ if (hasEmojiSelector || hasRegionalIndicator) {
136
+ return 2;
137
+ }
138
+ if (hasTextSelector) {
139
+ return 1;
140
+ }
141
+ if (width === 0) {
142
+ return hasVisible ? 1 : 0;
143
+ }
144
+ return width;
145
+ };
146
+ /**
147
+ * Invisible format characters, such as the zero width space, that take no cell even when they
148
+ * stand alone. A combining mark on its own still takes one cell so it stays visible.
149
+ */
150
+ const isZeroOnly = (codePoint) => {
151
+ return (codePoint === 0x200b ||
152
+ codePoint === 0x200c ||
153
+ codePoint === 0x200d ||
154
+ codePoint === 0x2060 ||
155
+ codePoint === 0xfeff ||
156
+ codePoint === 0x00ad);
157
+ };
@@ -0,0 +1,14 @@
1
+ import { type ShapedLine, type WrapMode } from '../layout/types.js';
2
+ /**
3
+ * Returns the index of the first cluster of every row a line wraps into.
4
+ *
5
+ * - `none` keeps the line on one row.
6
+ * - `char` fills every row and breaks between any two clusters.
7
+ * - `word` breaks after a space, or on either side of a wide character such as a Han
8
+ * ideograph. Hangul syllables keep words together, so Korean text breaks at spaces. A word
9
+ * longer than the row is broken between characters.
10
+ *
11
+ * A space that does not fit at the end of a row hangs past the edge, so a row never starts
12
+ * with the space that ended the word before it.
13
+ */
14
+ export declare const wrapLine: (line: ShapedLine, columns: number, mode: WrapMode) => number[];
@@ -0,0 +1,94 @@
1
+ import { BREAK_SPACE, BREAK_WIDE } from '../layout/types.js';
2
+ import { breakAt, widthAt } from './shape.js';
3
+ /**
4
+ * Returns the index of the first cluster of every row a line wraps into.
5
+ *
6
+ * - `none` keeps the line on one row.
7
+ * - `char` fills every row and breaks between any two clusters.
8
+ * - `word` breaks after a space, or on either side of a wide character such as a Han
9
+ * ideograph. Hangul syllables keep words together, so Korean text breaks at spaces. A word
10
+ * longer than the row is broken between characters.
11
+ *
12
+ * A space that does not fit at the end of a row hangs past the edge, so a row never starts
13
+ * with the space that ended the word before it.
14
+ */
15
+ export const wrapLine = (line, columns, mode) => {
16
+ const count = line.length;
17
+ if (mode === 'none' || count === 0 || line.cells <= columns) {
18
+ return [0];
19
+ }
20
+ const width = Math.max(1, columns);
21
+ const isWord = mode === 'word';
22
+ if (line.simple) {
23
+ return wrapAscii(line.text, width, isWord);
24
+ }
25
+ const rows = [0];
26
+ let rowStart = 0;
27
+ let rowCells = 0;
28
+ let breakIndex = -1;
29
+ for (let index = 0; index < count; index++) {
30
+ const clusterCells = widthAt(line, index);
31
+ const breakClass = breakAt(line, index);
32
+ if (isWord && index > rowStart) {
33
+ const previous = breakAt(line, index - 1);
34
+ if ((previous === BREAK_SPACE && breakClass !== BREAK_SPACE) ||
35
+ previous === BREAK_WIDE ||
36
+ breakClass === BREAK_WIDE) {
37
+ breakIndex = index;
38
+ }
39
+ }
40
+ if (rowCells > 0 && rowCells + clusterCells > width) {
41
+ if (breakClass === BREAK_SPACE) {
42
+ rowCells += clusterCells;
43
+ continue;
44
+ }
45
+ const start = isWord && breakIndex > rowStart ? breakIndex : index;
46
+ rows.push(start);
47
+ rowStart = start;
48
+ rowCells = 0;
49
+ breakIndex = -1;
50
+ for (let cluster = start; cluster < index; cluster++) {
51
+ rowCells += widthAt(line, cluster);
52
+ }
53
+ // The carried-over part of a word can still leave no room for a wide character.
54
+ if (rowCells > 0 && rowCells + clusterCells > width) {
55
+ rows.push(index);
56
+ rowStart = index;
57
+ rowCells = 0;
58
+ }
59
+ }
60
+ rowCells += clusterCells;
61
+ }
62
+ return rows;
63
+ };
64
+ /**
65
+ * `wrapLine` for a line where every character is one cell and only spaces allow a break. It
66
+ * follows the same rules without looking up widths and break classes, which makes laying out
67
+ * a large plain-text log several times faster.
68
+ */
69
+ const wrapAscii = (text, width, isWord) => {
70
+ const rows = [0];
71
+ const count = text.length;
72
+ let rowStart = 0;
73
+ let rowCells = 0;
74
+ let breakIndex = -1;
75
+ for (let index = 0; index < count; index++) {
76
+ const isSpace = text.charCodeAt(index) === 0x20;
77
+ if (isWord && index > rowStart && !isSpace && text.charCodeAt(index - 1) === 0x20) {
78
+ breakIndex = index;
79
+ }
80
+ if (rowCells > 0 && rowCells + 1 > width) {
81
+ if (isSpace) {
82
+ rowCells++;
83
+ continue;
84
+ }
85
+ const start = isWord && breakIndex > rowStart ? breakIndex : index;
86
+ rows.push(start);
87
+ rowStart = start;
88
+ rowCells = index - start;
89
+ breakIndex = -1;
90
+ }
91
+ rowCells++;
92
+ }
93
+ return rows;
94
+ };
@@ -0,0 +1,10 @@
1
+ /** How the timestamp of an entry is written. */
2
+ export type TimestampFormat = 'time' | 'datetime' | 'iso' | ((time: number) => string);
3
+ /**
4
+ * Formats an epoch time in local time.
5
+ *
6
+ * - `time`: `14:03:09.120`
7
+ * - `datetime`: `2026-09-13 14:03:09.120`
8
+ * - `iso`: `2026-09-13T05:03:09.120Z`, in UTC
9
+ */
10
+ export declare const formatTimestamp: (time: number, format?: TimestampFormat) => string;
@@ -0,0 +1,24 @@
1
+ const pad = (value, length = 2) => {
2
+ return String(value).padStart(length, '0');
3
+ };
4
+ /**
5
+ * Formats an epoch time in local time.
6
+ *
7
+ * - `time`: `14:03:09.120`
8
+ * - `datetime`: `2026-09-13 14:03:09.120`
9
+ * - `iso`: `2026-09-13T05:03:09.120Z`, in UTC
10
+ */
11
+ export const formatTimestamp = (time, format = 'time') => {
12
+ if (typeof format === 'function') {
13
+ return format(time);
14
+ }
15
+ const date = new Date(time);
16
+ if (format === 'iso') {
17
+ return date.toISOString();
18
+ }
19
+ const clock = `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}.${pad(date.getMilliseconds(), 3)}`;
20
+ if (format === 'datetime') {
21
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${clock}`;
22
+ }
23
+ return clock;
24
+ };