(chunk: string)
| 11 | |
| 12 | // 解析输入的文本块,返回完整的事件列表 |
| 13 | parse(chunk: string): SSEEvent[] { |
| 14 | this.buffer += chunk; |
| 15 | const events: SSEEvent[] = []; |
| 16 | const lines = this.buffer.split("\n"); |
| 17 | // 保留最后一个不完整的行 |
| 18 | this.buffer = lines.pop() || ""; |
| 19 | |
| 20 | for (const line of lines) { |
| 21 | if (line === "" || line === "\r") { |
| 22 | // 空行表示事件结束 |
| 23 | if (this.currentData.length > 0) { |
| 24 | events.push({ |
| 25 | event: this.currentEvent || "message", |
| 26 | data: this.currentData.join("\n"), |
| 27 | }); |
| 28 | } |
| 29 | // 无条件重置,防止 currentEvent 残留污染下一条事件 |
| 30 | this.currentEvent = ""; |
| 31 | this.currentData = []; |
| 32 | continue; |
| 33 | } |
| 34 | |
| 35 | const cleanLine = line.endsWith("\r") ? line.slice(0, -1) : line; |
| 36 | |
| 37 | if (cleanLine.startsWith(":")) { |
| 38 | // 注释行,忽略 |
| 39 | continue; |
| 40 | } |
| 41 | |
| 42 | const colonIndex = cleanLine.indexOf(":"); |
| 43 | if (colonIndex === -1) { |
| 44 | // 没有冒号,整行作为字段名 |
| 45 | continue; |
| 46 | } |
| 47 | |
| 48 | const field = cleanLine.slice(0, colonIndex); |
| 49 | // 冒号后如果有空格则跳过 |
| 50 | const value = |
| 51 | cleanLine[colonIndex + 1] === " " ? cleanLine.slice(colonIndex + 2) : cleanLine.slice(colonIndex + 1); |
| 52 | |
| 53 | switch (field) { |
| 54 | case "event": |
| 55 | this.currentEvent = value; |
| 56 | break; |
| 57 | case "data": |
| 58 | this.currentData.push(value); |
| 59 | break; |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | return events; |
| 64 | } |
| 65 | |
| 66 | // 重置解析器状态 |
| 67 | reset(): void { |
no test coverage detected