@taicode/common-base 3.7.7 → 3.7.8

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 (166) hide show
  1. package/output/batching-buffer/batching-buffer.d.ts +133 -0
  2. package/output/batching-buffer/batching-buffer.d.ts.map +1 -0
  3. package/output/batching-buffer/batching-buffer.js +264 -0
  4. package/output/batching-buffer/batching-buffer.test.d.ts +2 -0
  5. package/output/batching-buffer/batching-buffer.test.d.ts.map +1 -0
  6. package/output/batching-buffer/batching-buffer.test.js +358 -0
  7. package/output/batching-buffer/index.d.ts +3 -0
  8. package/output/batching-buffer/index.d.ts.map +1 -0
  9. package/output/batching-buffer/index.js +1 -0
  10. package/output/catch/catch.d.ts +46 -0
  11. package/output/catch/catch.d.ts.map +1 -0
  12. package/output/catch/catch.js +48 -0
  13. package/output/catch/catch.test.d.ts +2 -0
  14. package/output/catch/catch.test.d.ts.map +1 -0
  15. package/output/catch/catch.test.js +43 -0
  16. package/output/catch/index.d.ts +2 -0
  17. package/output/catch/index.d.ts.map +1 -0
  18. package/output/catch/index.js +1 -0
  19. package/output/color/color.d.ts +6 -0
  20. package/output/color/color.d.ts.map +1 -0
  21. package/output/color/color.js +56 -0
  22. package/output/color/color.test.d.ts +2 -0
  23. package/output/color/color.test.d.ts.map +1 -0
  24. package/output/color/color.test.js +110 -0
  25. package/output/color/index.d.ts +2 -0
  26. package/output/color/index.d.ts.map +1 -0
  27. package/output/color/index.js +1 -0
  28. package/output/debounce/debounce.d.ts +7 -0
  29. package/output/debounce/debounce.d.ts.map +1 -0
  30. package/output/debounce/debounce.js +36 -0
  31. package/output/debounce/debounce.test.d.ts +2 -0
  32. package/output/debounce/debounce.test.d.ts.map +1 -0
  33. package/output/debounce/debounce.test.js +135 -0
  34. package/output/debounce/index.d.ts +2 -0
  35. package/output/debounce/index.d.ts.map +1 -0
  36. package/output/debounce/index.js +1 -0
  37. package/output/disposer/disposer.d.ts +8 -0
  38. package/output/disposer/disposer.d.ts.map +1 -0
  39. package/output/disposer/disposer.js +21 -0
  40. package/output/disposer/disposer.test.d.ts +2 -0
  41. package/output/disposer/disposer.test.d.ts.map +1 -0
  42. package/output/disposer/disposer.test.js +216 -0
  43. package/output/disposer/index.d.ts +2 -0
  44. package/output/disposer/index.d.ts.map +1 -0
  45. package/output/disposer/index.js +1 -0
  46. package/output/error/error.d.ts +128 -0
  47. package/output/error/error.d.ts.map +1 -0
  48. package/output/error/error.js +141 -0
  49. package/output/error/error.test.d.ts +2 -0
  50. package/output/error/error.test.d.ts.map +1 -0
  51. package/output/error/error.test.js +420 -0
  52. package/output/error/index.d.ts +3 -0
  53. package/output/error/index.d.ts.map +1 -0
  54. package/output/error/index.js +1 -0
  55. package/output/event-emitter/event-emitter.d.ts +33 -0
  56. package/output/event-emitter/event-emitter.d.ts.map +1 -0
  57. package/output/event-emitter/event-emitter.js +66 -0
  58. package/output/event-emitter/event-emitter.test.d.ts +2 -0
  59. package/output/event-emitter/event-emitter.test.d.ts.map +1 -0
  60. package/output/event-emitter/event-emitter.test.js +177 -0
  61. package/output/event-emitter/index.d.ts +2 -0
  62. package/output/event-emitter/index.d.ts.map +1 -0
  63. package/output/event-emitter/index.js +1 -0
  64. package/output/flow-queue/flow-queue.d.ts +486 -0
  65. package/output/flow-queue/flow-queue.d.ts.map +1 -0
  66. package/output/flow-queue/flow-queue.js +654 -0
  67. package/output/flow-queue/flow-queue.test.d.ts +2 -0
  68. package/output/flow-queue/flow-queue.test.d.ts.map +1 -0
  69. package/output/flow-queue/flow-queue.test.js +1205 -0
  70. package/output/flow-queue/index.d.ts +3 -0
  71. package/output/flow-queue/index.d.ts.map +1 -0
  72. package/output/flow-queue/index.js +3 -0
  73. package/output/index.d.ts +18 -0
  74. package/output/index.d.ts.map +1 -0
  75. package/output/index.js +26 -0
  76. package/output/logger/formatter.d.ts +70 -0
  77. package/output/logger/formatter.d.ts.map +1 -0
  78. package/output/logger/formatter.js +206 -0
  79. package/output/logger/formatter.test.d.ts +2 -0
  80. package/output/logger/formatter.test.d.ts.map +1 -0
  81. package/output/logger/formatter.test.js +296 -0
  82. package/output/logger/index.d.ts +4 -0
  83. package/output/logger/index.d.ts.map +1 -0
  84. package/output/logger/index.js +3 -0
  85. package/output/logger/logger.d.ts +64 -0
  86. package/output/logger/logger.d.ts.map +1 -0
  87. package/output/logger/logger.js +179 -0
  88. package/output/logger/logger.test.d.ts +2 -0
  89. package/output/logger/logger.test.d.ts.map +1 -0
  90. package/output/logger/logger.test.js +299 -0
  91. package/output/logger/transport.d.ts +124 -0
  92. package/output/logger/transport.d.ts.map +1 -0
  93. package/output/logger/transport.js +153 -0
  94. package/output/logger/transport.test.d.ts +2 -0
  95. package/output/logger/transport.test.d.ts.map +1 -0
  96. package/output/logger/transport.test.js +309 -0
  97. package/output/lru-cache/index.d.ts +2 -0
  98. package/output/lru-cache/index.d.ts.map +1 -0
  99. package/output/lru-cache/index.js +1 -0
  100. package/output/lru-cache/lru-cache.d.ts +22 -0
  101. package/output/lru-cache/lru-cache.d.ts.map +1 -0
  102. package/output/lru-cache/lru-cache.js +147 -0
  103. package/output/lru-cache/lru-cache.test.d.ts +2 -0
  104. package/output/lru-cache/lru-cache.test.d.ts.map +1 -0
  105. package/output/lru-cache/lru-cache.test.js +239 -0
  106. package/output/number/index.d.ts +2 -0
  107. package/output/number/index.d.ts.map +1 -0
  108. package/output/number/index.js +1 -0
  109. package/output/number/number.d.ts +2 -0
  110. package/output/number/number.d.ts.map +1 -0
  111. package/output/number/number.js +23 -0
  112. package/output/number/number.test.d.ts +2 -0
  113. package/output/number/number.test.d.ts.map +1 -0
  114. package/output/number/number.test.js +50 -0
  115. package/output/object/index.d.ts +2 -0
  116. package/output/object/index.d.ts.map +1 -0
  117. package/output/object/index.js +1 -0
  118. package/output/object/object.d.ts +7 -0
  119. package/output/object/object.d.ts.map +1 -0
  120. package/output/object/object.js +27 -0
  121. package/output/object/object.test.d.ts +2 -0
  122. package/output/object/object.test.d.ts.map +1 -0
  123. package/output/object/object.test.js +42 -0
  124. package/output/ring-cache/index.d.ts +6 -0
  125. package/output/ring-cache/index.d.ts.map +1 -0
  126. package/output/ring-cache/index.js +5 -0
  127. package/output/ring-cache/ring-cache.d.ts +125 -0
  128. package/output/ring-cache/ring-cache.d.ts.map +1 -0
  129. package/output/ring-cache/ring-cache.js +197 -0
  130. package/output/ring-cache/ring-cache.test.d.ts +2 -0
  131. package/output/ring-cache/ring-cache.test.d.ts.map +1 -0
  132. package/output/ring-cache/ring-cache.test.js +196 -0
  133. package/output/service/index.d.ts +2 -0
  134. package/output/service/index.d.ts.map +1 -0
  135. package/output/service/index.js +1 -0
  136. package/output/service/service.d.ts +6 -0
  137. package/output/service/service.d.ts.map +1 -0
  138. package/output/service/service.js +3 -0
  139. package/output/string/index.d.ts +2 -0
  140. package/output/string/index.d.ts.map +1 -0
  141. package/output/string/index.js +1 -0
  142. package/output/string/string.d.ts +3 -0
  143. package/output/string/string.d.ts.map +1 -0
  144. package/output/string/string.js +9 -0
  145. package/output/string/string.test.d.ts +2 -0
  146. package/output/string/string.test.d.ts.map +1 -0
  147. package/output/string/string.test.js +77 -0
  148. package/output/throttle/index.d.ts +2 -0
  149. package/output/throttle/index.d.ts.map +1 -0
  150. package/output/throttle/index.js +1 -0
  151. package/output/throttle/throttle.d.ts +12 -0
  152. package/output/throttle/throttle.d.ts.map +1 -0
  153. package/output/throttle/throttle.js +55 -0
  154. package/output/throttle/throttle.test.d.ts +2 -0
  155. package/output/throttle/throttle.test.d.ts.map +1 -0
  156. package/output/throttle/throttle.test.js +177 -0
  157. package/output/ttl-cache/index.d.ts +2 -0
  158. package/output/ttl-cache/index.d.ts.map +1 -0
  159. package/output/ttl-cache/index.js +1 -0
  160. package/output/ttl-cache/ttl-cache.d.ts +148 -0
  161. package/output/ttl-cache/ttl-cache.d.ts.map +1 -0
  162. package/output/ttl-cache/ttl-cache.js +313 -0
  163. package/output/ttl-cache/ttl-cache.test.d.ts +2 -0
  164. package/output/ttl-cache/ttl-cache.test.d.ts.map +1 -0
  165. package/output/ttl-cache/ttl-cache.test.js +222 -0
  166. package/package.json +1 -1
@@ -0,0 +1,153 @@
1
+ import { RingCache } from '../ring-cache/index.js';
2
+ /**
3
+ * 内存 LogTransport 实现
4
+ * 将结构化日志数据存储在内存中,支持查询和分析
5
+ * 使用RingCache实现高效的FIFO行为
6
+ */
7
+ export class MemoryTransport {
8
+ name = 'memory';
9
+ level;
10
+ enabled = true;
11
+ cache;
12
+ static LOG_LEVELS = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];
13
+ constructor(options = {}) {
14
+ this.level = options.level;
15
+ this.enabled = options.enabled ?? true;
16
+ this.cache = new RingCache({
17
+ capacity: options.maxRecords ?? 1000
18
+ });
19
+ }
20
+ /**
21
+ * 检查是否应该处理此级别的日志
22
+ */
23
+ shouldLog(level) {
24
+ if (!this.enabled) {
25
+ return false;
26
+ }
27
+ if (!this.level) {
28
+ return true;
29
+ }
30
+ const currentIndex = MemoryTransport.LOG_LEVELS.indexOf(level);
31
+ const minIndex = MemoryTransport.LOG_LEVELS.indexOf(this.level);
32
+ return currentIndex >= minIndex;
33
+ }
34
+ log(record) {
35
+ if (!this.shouldLog(record.level)) {
36
+ return;
37
+ }
38
+ this.cache.add(record);
39
+ }
40
+ /**
41
+ * 获取所有日志记录
42
+ */
43
+ getRecords() {
44
+ return this.cache.getAll().map(entry => ({
45
+ ...entry.data,
46
+ id: entry.id
47
+ }));
48
+ }
49
+ /**
50
+ * 根据级别获取日志记录
51
+ */
52
+ getRecordsByLevel(level) {
53
+ return this.cache.search(entry => entry.data.level === level)
54
+ .map(entry => ({
55
+ ...entry.data,
56
+ id: entry.id
57
+ }));
58
+ }
59
+ /**
60
+ * 根据时间范围获取日志记录
61
+ */
62
+ getRecordsByTimeRange(start, end) {
63
+ return this.cache.getByTimeRange(start, end)
64
+ .map(entry => ({
65
+ ...entry.data,
66
+ id: entry.id
67
+ }));
68
+ }
69
+ /**
70
+ * 搜索日志记录
71
+ * @param predicate 搜索条件函数
72
+ */
73
+ searchRecords(predicate) {
74
+ return this.getRecords().filter(predicate);
75
+ }
76
+ /**
77
+ * 根据参数内容搜索
78
+ * @param searchText 搜索文本
79
+ */
80
+ searchByContent(searchText) {
81
+ const lowerSearchText = searchText.toLowerCase();
82
+ return this.cache.search(entry => entry.data.args.some(arg => {
83
+ if (typeof arg === 'string') {
84
+ return arg.toLowerCase().includes(lowerSearchText);
85
+ }
86
+ if (typeof arg === 'object' && arg !== null) {
87
+ try {
88
+ return JSON.stringify(arg).toLowerCase().includes(lowerSearchText);
89
+ }
90
+ catch {
91
+ return false;
92
+ }
93
+ }
94
+ return false;
95
+ })).map(entry => ({
96
+ ...entry.data,
97
+ id: entry.id
98
+ }));
99
+ }
100
+ /**
101
+ * 获取最近的 N 条记录
102
+ */
103
+ getRecentRecords(count) {
104
+ return this.cache.getRecent(count).map(entry => ({
105
+ ...entry.data,
106
+ id: entry.id
107
+ }));
108
+ }
109
+ /**
110
+ * 获取统计信息
111
+ */
112
+ getStats() {
113
+ const cacheStats = this.cache.getStats();
114
+ const all = this.cache.getAll();
115
+ const stats = {
116
+ total: cacheStats.size,
117
+ byLevel: {
118
+ debug: 0,
119
+ info: 0,
120
+ warn: 0,
121
+ error: 0
122
+ },
123
+ oldestTimestamp: cacheStats.oldestTimestamp,
124
+ newestTimestamp: cacheStats.newestTimestamp
125
+ };
126
+ if (all.length === 0) {
127
+ return stats;
128
+ }
129
+ // 统计各级别数量
130
+ all.forEach(entry => {
131
+ stats.byLevel[entry.data.level]++;
132
+ });
133
+ return stats;
134
+ }
135
+ /**
136
+ * 清空所有记录
137
+ */
138
+ clear() {
139
+ this.cache.clear();
140
+ }
141
+ /**
142
+ * 导出为 JSON 格式
143
+ */
144
+ exportToJSON() {
145
+ return JSON.stringify(this.getRecords(), null, 2);
146
+ }
147
+ /**
148
+ * 关闭 LogTransport
149
+ */
150
+ close() {
151
+ this.clear();
152
+ }
153
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=transport.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.test.d.ts","sourceRoot":"","sources":["../../source/logger/transport.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,309 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { MemoryTransport } from './transport.js';
3
+ // 创建一个测试用的 Transport 实现
4
+ class TestTransport {
5
+ name;
6
+ level;
7
+ enabled = true;
8
+ loggedRecords = [];
9
+ static LOG_LEVELS = ['debug', 'info', 'warn', 'error'];
10
+ constructor(name = 'test', options = {}) {
11
+ this.name = name;
12
+ this.level = options.level;
13
+ this.enabled = options.enabled ?? true;
14
+ }
15
+ shouldLog(level) {
16
+ if (!this.enabled) {
17
+ return false;
18
+ }
19
+ if (!this.level) {
20
+ return true;
21
+ }
22
+ const currentIndex = TestTransport.LOG_LEVELS.indexOf(level);
23
+ const minIndex = TestTransport.LOG_LEVELS.indexOf(this.level);
24
+ return currentIndex >= minIndex;
25
+ }
26
+ log(record) {
27
+ if (!this.shouldLog(record.level)) {
28
+ return;
29
+ }
30
+ this.loggedRecords.push(record);
31
+ }
32
+ clear() {
33
+ this.loggedRecords = [];
34
+ }
35
+ }
36
+ describe('TestTransport', () => {
37
+ let transport;
38
+ beforeEach(() => {
39
+ transport = new TestTransport();
40
+ });
41
+ describe('基本功能', () => {
42
+ it('应该有正确的名称', () => {
43
+ expect(transport.name).toBe('test');
44
+ });
45
+ it('应该默认启用', () => {
46
+ expect(transport.enabled).toBe(true);
47
+ });
48
+ it('应该记录日志', () => {
49
+ const record = {
50
+ level: 'info',
51
+ timestamp: new Date(),
52
+ args: ['测试消息']
53
+ };
54
+ transport.log(record);
55
+ expect(transport.loggedRecords).toHaveLength(1);
56
+ expect(transport.loggedRecords[0]).toEqual(record);
57
+ });
58
+ });
59
+ describe('日志级别控制', () => {
60
+ it('应该遵守最低日志级别', () => {
61
+ transport = new TestTransport('test', { level: 'warn' });
62
+ const debugRecord = {
63
+ level: 'debug',
64
+ timestamp: new Date(),
65
+ args: ['debug消息']
66
+ };
67
+ const warnRecord = {
68
+ level: 'warn',
69
+ timestamp: new Date(),
70
+ args: ['warn消息']
71
+ };
72
+ transport.log(debugRecord);
73
+ transport.log(warnRecord);
74
+ expect(transport.loggedRecords).toHaveLength(1);
75
+ expect(transport.loggedRecords[0].level).toBe('warn');
76
+ });
77
+ it('应该记录等于或高于最低级别的日志', () => {
78
+ transport = new TestTransport('test', { level: 'info' });
79
+ const levels = ['debug', 'info', 'warn', 'error'];
80
+ levels.forEach(level => {
81
+ transport.log({
82
+ level,
83
+ timestamp: new Date(),
84
+ args: [`${level}消息`]
85
+ });
86
+ });
87
+ expect(transport.loggedRecords).toHaveLength(3); // info, warn, error
88
+ expect(transport.loggedRecords.map(r => r.level)).toEqual(['info', 'warn', 'error']);
89
+ });
90
+ });
91
+ describe('启用状态控制', () => {
92
+ it('应该在禁用时不记录日志', () => {
93
+ transport = new TestTransport('test', { enabled: false });
94
+ transport.log({
95
+ level: 'error',
96
+ timestamp: new Date(),
97
+ args: ['错误消息']
98
+ });
99
+ expect(transport.loggedRecords).toHaveLength(0);
100
+ });
101
+ it('应该支持动态启用/禁用', () => {
102
+ const record = {
103
+ level: 'info',
104
+ timestamp: new Date(),
105
+ args: ['测试消息']
106
+ };
107
+ transport.enabled = false;
108
+ transport.log(record);
109
+ expect(transport.loggedRecords).toHaveLength(0);
110
+ transport.enabled = true;
111
+ transport.log(record);
112
+ expect(transport.loggedRecords).toHaveLength(1);
113
+ });
114
+ });
115
+ });
116
+ describe('MemoryTransport', () => {
117
+ let memoryTransport;
118
+ beforeEach(() => {
119
+ memoryTransport = new MemoryTransport();
120
+ });
121
+ describe('基本功能', () => {
122
+ it('应该有正确的名称', () => {
123
+ expect(memoryTransport.name).toBe('memory');
124
+ });
125
+ it('应该存储日志记录', () => {
126
+ const record = {
127
+ level: 'info',
128
+ timestamp: new Date(),
129
+ args: ['测试消息', { data: 'value' }],
130
+ metadata: { source: 'test' }
131
+ };
132
+ memoryTransport.log(record);
133
+ const records = memoryTransport.getRecords();
134
+ expect(records).toHaveLength(1);
135
+ expect(records[0].level).toBe('info');
136
+ expect(records[0].args).toEqual(['测试消息', { data: 'value' }]);
137
+ expect(records[0].metadata).toEqual({ source: 'test' });
138
+ expect(records[0].id).toBeDefined();
139
+ });
140
+ it('应该生成唯一ID', () => {
141
+ const record1 = {
142
+ level: 'info',
143
+ timestamp: new Date(),
144
+ args: ['消息1']
145
+ };
146
+ const record2 = {
147
+ level: 'info',
148
+ timestamp: new Date(),
149
+ args: ['消息2']
150
+ };
151
+ memoryTransport.log(record1);
152
+ memoryTransport.log(record2);
153
+ const records = memoryTransport.getRecords();
154
+ expect(records[0].id).not.toBe(records[1].id);
155
+ });
156
+ });
157
+ describe('容量管理', () => {
158
+ it('应该遵守最大记录数限制', () => {
159
+ memoryTransport = new MemoryTransport({ maxRecords: 3 });
160
+ // 添加4条记录
161
+ for (let i = 0; i < 4; i++) {
162
+ memoryTransport.log({
163
+ level: 'info',
164
+ timestamp: new Date(),
165
+ args: [`消息${i}`]
166
+ });
167
+ }
168
+ const records = memoryTransport.getRecords();
169
+ expect(records).toHaveLength(3);
170
+ // 应该保留最新的3条记录
171
+ expect(records.map(r => r.args[0])).toEqual(['消息1', '消息2', '消息3']);
172
+ });
173
+ it('应该支持自定义最大记录数', () => {
174
+ memoryTransport = new MemoryTransport({ maxRecords: 1 });
175
+ memoryTransport.log({
176
+ level: 'info',
177
+ timestamp: new Date(),
178
+ args: ['第一条']
179
+ });
180
+ memoryTransport.log({
181
+ level: 'info',
182
+ timestamp: new Date(),
183
+ args: ['第二条']
184
+ });
185
+ const records = memoryTransport.getRecords();
186
+ expect(records).toHaveLength(1);
187
+ expect(records[0].args[0]).toBe('第二条');
188
+ });
189
+ });
190
+ describe('查询功能', () => {
191
+ beforeEach(() => {
192
+ // 添加测试数据
193
+ const testData = [
194
+ { level: 'debug', args: ['调试消息'] },
195
+ { level: 'info', args: ['信息消息', { type: 'user' }] },
196
+ { level: 'warn', args: ['警告消息'] },
197
+ { level: 'error', args: ['错误消息', new Error('测试错误')] },
198
+ { level: 'info', args: ['另一条信息'] }
199
+ ];
200
+ testData.forEach(data => {
201
+ memoryTransport.log({
202
+ level: data.level,
203
+ timestamp: new Date(),
204
+ args: data.args
205
+ });
206
+ });
207
+ });
208
+ it('应该根据级别筛选记录', () => {
209
+ const infoRecords = memoryTransport.getRecordsByLevel('info');
210
+ expect(infoRecords).toHaveLength(2);
211
+ expect(infoRecords.every(r => r.level === 'info')).toBe(true);
212
+ const errorRecords = memoryTransport.getRecordsByLevel('error');
213
+ expect(errorRecords).toHaveLength(1);
214
+ expect(errorRecords[0].level).toBe('error');
215
+ });
216
+ it('应该根据时间范围筛选记录', () => {
217
+ const now = new Date();
218
+ const oneMinuteAgo = new Date(now.getTime() - 60000);
219
+ const oneMinuteLater = new Date(now.getTime() + 60000);
220
+ const records = memoryTransport.getRecordsByTimeRange(oneMinuteAgo, oneMinuteLater);
221
+ expect(records.length).toBeGreaterThan(0);
222
+ });
223
+ it('应该支持内容搜索', () => {
224
+ const results = memoryTransport.searchByContent('调试');
225
+ expect(results).toHaveLength(1);
226
+ expect(results[0].args[0]).toContain('调试');
227
+ const typeResults = memoryTransport.searchByContent('user');
228
+ expect(typeResults).toHaveLength(1);
229
+ expect(typeResults[0].args[1]).toEqual({ type: 'user' });
230
+ });
231
+ it('应该支持自定义搜索条件', () => {
232
+ const errorResults = memoryTransport.searchRecords(record => record.args.some(arg => arg instanceof Error));
233
+ expect(errorResults).toHaveLength(1);
234
+ expect(errorResults[0].level).toBe('error');
235
+ });
236
+ it('应该获取最近的记录', () => {
237
+ const recent = memoryTransport.getRecentRecords(2);
238
+ expect(recent).toHaveLength(2);
239
+ expect(recent[0].args[0]).toContain('错误消息');
240
+ expect(recent[1].args[0]).toContain('另一条信息');
241
+ });
242
+ });
243
+ describe('统计功能', () => {
244
+ beforeEach(() => {
245
+ // 添加不同级别的日志
246
+ memoryTransport.log({ level: 'debug', timestamp: new Date(), args: ['debug1'] });
247
+ memoryTransport.log({ level: 'debug', timestamp: new Date(), args: ['debug2'] });
248
+ memoryTransport.log({ level: 'info', timestamp: new Date(), args: ['info1'] });
249
+ memoryTransport.log({ level: 'warn', timestamp: new Date(), args: ['warn1'] });
250
+ memoryTransport.log({ level: 'error', timestamp: new Date(), args: ['error1'] });
251
+ });
252
+ it('应该提供正确的统计信息', () => {
253
+ const stats = memoryTransport.getStats();
254
+ expect(stats.total).toBe(5);
255
+ expect(stats.byLevel.debug).toBe(2);
256
+ expect(stats.byLevel.info).toBe(1);
257
+ expect(stats.byLevel.warn).toBe(1);
258
+ expect(stats.byLevel.error).toBe(1);
259
+ expect(stats.oldestTimestamp).toBeDefined();
260
+ expect(stats.newestTimestamp).toBeDefined();
261
+ });
262
+ it('应该处理空记录的统计', () => {
263
+ memoryTransport.clear();
264
+ const stats = memoryTransport.getStats();
265
+ expect(stats.total).toBe(0);
266
+ expect(stats.byLevel.debug).toBe(0);
267
+ expect(stats.oldestTimestamp).toBeUndefined();
268
+ expect(stats.newestTimestamp).toBeUndefined();
269
+ });
270
+ });
271
+ describe('导出功能', () => {
272
+ beforeEach(() => {
273
+ memoryTransport.log({
274
+ level: 'info',
275
+ timestamp: new Date('2023-01-01T00:00:00.000Z'),
276
+ args: ['测试消息', { data: 'value' }]
277
+ });
278
+ });
279
+ it('应该导出为 JSON 格式', () => {
280
+ const json = memoryTransport.exportToJSON();
281
+ const parsed = JSON.parse(json);
282
+ expect(Array.isArray(parsed)).toBe(true);
283
+ expect(parsed).toHaveLength(1);
284
+ expect(parsed[0].level).toBe('info');
285
+ expect(parsed[0].args).toEqual(['测试消息', { data: 'value' }]);
286
+ });
287
+ });
288
+ describe('清理功能', () => {
289
+ it('应该清空所有记录', () => {
290
+ memoryTransport.log({
291
+ level: 'info',
292
+ timestamp: new Date(),
293
+ args: ['测试消息']
294
+ });
295
+ expect(memoryTransport.getRecords()).toHaveLength(1);
296
+ memoryTransport.clear();
297
+ expect(memoryTransport.getRecords()).toHaveLength(0);
298
+ });
299
+ it('应该在关闭时清理资源', () => {
300
+ memoryTransport.log({
301
+ level: 'info',
302
+ timestamp: new Date(),
303
+ args: ['测试消息']
304
+ });
305
+ memoryTransport.close();
306
+ expect(memoryTransport.getRecords()).toHaveLength(0);
307
+ });
308
+ });
309
+ });
@@ -0,0 +1,2 @@
1
+ export { LruCache } from './lru-cache.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/lru-cache/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1 @@
1
+ export { LruCache } from './lru-cache.js';
@@ -0,0 +1,22 @@
1
+ export declare class LruCache<T> {
2
+ private cache;
3
+ private maxSize;
4
+ private head;
5
+ private tail;
6
+ constructor(maxSize?: number);
7
+ get(key: string): T | undefined;
8
+ set(key: string, value: T): void;
9
+ has(key: string): boolean;
10
+ delete(key: string): boolean;
11
+ get size(): number;
12
+ get capacity(): number;
13
+ clear(): void;
14
+ keys(): string[];
15
+ values(): T[];
16
+ entries(): Array<[string, T]>;
17
+ private addToHead;
18
+ private removeNode;
19
+ private moveToHead;
20
+ private removeTail;
21
+ }
22
+ //# sourceMappingURL=lru-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lru-cache.d.ts","sourceRoot":"","sources":["../../source/lru-cache/lru-cache.ts"],"names":[],"mappings":"AAOA,qBAAa,QAAQ,CAAC,CAAC;IACrB,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,IAAI,CAAY;IACxB,OAAO,CAAC,IAAI,CAAY;gBAEZ,OAAO,GAAE,MAAY;IAgBjC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAY/B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAgChC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAKzB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAY5B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAGD,IAAI,QAAQ,IAAI,MAAM,CAErB;IAGD,KAAK,IAAI,IAAI;IAOb,IAAI,IAAI,MAAM,EAAE;IAWhB,MAAM,IAAI,CAAC,EAAE;IAWb,OAAO,IAAI,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAW7B,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,UAAU;CAQnB"}
@@ -0,0 +1,147 @@
1
+ export class LruCache {
2
+ cache;
3
+ maxSize;
4
+ head;
5
+ tail;
6
+ constructor(maxSize = 100) {
7
+ if (maxSize <= 0) {
8
+ throw new Error('maxSize must be greater than 0');
9
+ }
10
+ this.maxSize = maxSize;
11
+ this.cache = new Map();
12
+ // 创建虚拟头尾节点
13
+ this.head = { key: '', value: null, prev: null, next: null };
14
+ this.tail = { key: '', value: null, prev: null, next: null };
15
+ this.head.next = this.tail;
16
+ this.tail.prev = this.head;
17
+ }
18
+ // 获取缓存中的数据
19
+ get(key) {
20
+ const node = this.cache.get(key);
21
+ if (!node) {
22
+ return undefined;
23
+ }
24
+ // 移动到头部(最近使用)
25
+ this.moveToHead(node);
26
+ return node.value;
27
+ }
28
+ // 设置缓存数据
29
+ set(key, value) {
30
+ const existingNode = this.cache.get(key);
31
+ if (existingNode) {
32
+ // 更新现有节点的值并移动到头部
33
+ existingNode.value = value;
34
+ this.moveToHead(existingNode);
35
+ }
36
+ else {
37
+ // 创建新节点
38
+ const newNode = {
39
+ key,
40
+ value,
41
+ prev: null,
42
+ next: null
43
+ };
44
+ // 检查是否超过容量
45
+ if (this.cache.size >= this.maxSize) {
46
+ // 移除最少使用的节点(尾部)
47
+ const tail = this.removeTail();
48
+ if (tail) {
49
+ this.cache.delete(tail.key);
50
+ }
51
+ }
52
+ // 添加到头部
53
+ this.cache.set(key, newNode);
54
+ this.addToHead(newNode);
55
+ }
56
+ }
57
+ // 检查键是否存在
58
+ has(key) {
59
+ return this.cache.has(key);
60
+ }
61
+ // 删除指定键
62
+ delete(key) {
63
+ const node = this.cache.get(key);
64
+ if (!node) {
65
+ return false;
66
+ }
67
+ this.removeNode(node);
68
+ this.cache.delete(key);
69
+ return true;
70
+ }
71
+ // 获取当前缓存大小
72
+ get size() {
73
+ return this.cache.size;
74
+ }
75
+ // 获取最大容量
76
+ get capacity() {
77
+ return this.maxSize;
78
+ }
79
+ // 清空缓存
80
+ clear() {
81
+ this.cache.clear();
82
+ this.head.next = this.tail;
83
+ this.tail.prev = this.head;
84
+ }
85
+ // 获取所有键(按使用频率排序,最近使用的在前)
86
+ keys() {
87
+ const keys = [];
88
+ let current = this.head.next;
89
+ while (current && current !== this.tail) {
90
+ keys.push(current.key);
91
+ current = current.next;
92
+ }
93
+ return keys;
94
+ }
95
+ // 获取所有值(按使用频率排序,最近使用的在前)
96
+ values() {
97
+ const values = [];
98
+ let current = this.head.next;
99
+ while (current && current !== this.tail) {
100
+ values.push(current.value);
101
+ current = current.next;
102
+ }
103
+ return values;
104
+ }
105
+ // 获取所有键值对
106
+ entries() {
107
+ const entries = [];
108
+ let current = this.head.next;
109
+ while (current && current !== this.tail) {
110
+ entries.push([current.key, current.value]);
111
+ current = current.next;
112
+ }
113
+ return entries;
114
+ }
115
+ // 私有方法:添加节点到头部
116
+ addToHead(node) {
117
+ node.prev = this.head;
118
+ node.next = this.head.next;
119
+ if (this.head.next) {
120
+ this.head.next.prev = node;
121
+ }
122
+ this.head.next = node;
123
+ }
124
+ // 私有方法:移除节点
125
+ removeNode(node) {
126
+ if (node.prev) {
127
+ node.prev.next = node.next;
128
+ }
129
+ if (node.next) {
130
+ node.next.prev = node.prev;
131
+ }
132
+ }
133
+ // 私有方法:移动节点到头部
134
+ moveToHead(node) {
135
+ this.removeNode(node);
136
+ this.addToHead(node);
137
+ }
138
+ // 私有方法:移除尾部节点
139
+ removeTail() {
140
+ const lastNode = this.tail.prev;
141
+ if (lastNode && lastNode !== this.head) {
142
+ this.removeNode(lastNode);
143
+ return lastNode;
144
+ }
145
+ return null;
146
+ }
147
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=lru-cache.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lru-cache.test.d.ts","sourceRoot":"","sources":["../../source/lru-cache/lru-cache.test.ts"],"names":[],"mappings":""}