| class ParseError extends Error { |
| constructor(message, options) { |
| super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line; |
| } |
| } |
| function noop(_arg) { |
| } |
| function createParser(callbacks) { |
| if (typeof callbacks == "function") |
| throw new TypeError( |
| "`callbacks` must be an object, got a function instead. Did you mean `{onEvent: fn}`?" |
| ); |
| const { onEvent = noop, onError = noop, onRetry = noop, onComment } = callbacks; |
| let incompleteLine = "", isFirstChunk = !0, id, data = "", eventType = ""; |
| function feed(newChunk) { |
| const chunk = isFirstChunk ? newChunk.replace(/^\xEF\xBB\xBF/, "") : newChunk, [complete, incomplete] = splitLines(`${incompleteLine}${chunk}`); |
| for (const line of complete) |
| parseLine(line); |
| incompleteLine = incomplete, isFirstChunk = !1; |
| } |
| function parseLine(line) { |
| if (line === "") { |
| dispatchEvent(); |
| return; |
| } |
| if (line.startsWith(":")) { |
| onComment && onComment(line.slice(line.startsWith(": ") ? 2 : 1)); |
| return; |
| } |
| const fieldSeparatorIndex = line.indexOf(":"); |
| if (fieldSeparatorIndex !== -1) { |
| const field = line.slice(0, fieldSeparatorIndex), offset = line[fieldSeparatorIndex + 1] === " " ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset); |
| processField(field, value, line); |
| return; |
| } |
| processField(line, "", line); |
| } |
| function processField(field, value, line) { |
| switch (field) { |
| case "event": |
| eventType = value; |
| break; |
| case "data": |
| data = `${data}${value} |
| `; |
| break; |
| case "id": |
| id = value.includes("\0") ? void 0 : value; |
| break; |
| case "retry": |
| /^\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError( |
| new ParseError(`Invalid \`retry\` value: "${value}"`, { |
| type: "invalid-retry", |
| value, |
| line |
| }) |
| ); |
| break; |
| default: |
| onError( |
| new ParseError( |
| `Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`, |
| { type: "unknown-field", field, value, line } |
| ) |
| ); |
| break; |
| } |
| } |
| function dispatchEvent() { |
| data.length > 0 && onEvent({ |
| id, |
| event: eventType || void 0, |
| |
| |
| data: data.endsWith(` |
| `) ? data.slice(0, -1) : data |
| }), id = void 0, data = "", eventType = ""; |
| } |
| function reset(options = {}) { |
| incompleteLine && options.consume && parseLine(incompleteLine), isFirstChunk = !0, id = void 0, data = "", eventType = "", incompleteLine = ""; |
| } |
| return { feed, reset }; |
| } |
| function splitLines(chunk) { |
| const lines = []; |
| let incompleteLine = "", searchIndex = 0; |
| for (; searchIndex < chunk.length; ) { |
| const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(` |
| `, searchIndex); |
| let lineEnd = -1; |
| if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = Math.min(crIndex, lfIndex) : crIndex !== -1 ? lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1) { |
| incompleteLine = chunk.slice(searchIndex); |
| break; |
| } else { |
| const line = chunk.slice(searchIndex, lineEnd); |
| lines.push(line), searchIndex = lineEnd + 1, chunk[searchIndex - 1] === "\r" && chunk[searchIndex] === ` |
| ` && searchIndex++; |
| } |
| } |
| return [lines, incompleteLine]; |
| } |
| export { |
| ParseError, |
| createParser |
| }; |
| |
|
|