{"version":3,"file":"index.js","sources":["../src/parse.ts"],"sourcesContent":["/**\n * EventSource/Server-Sent Events parser\n * @see https://html.spec.whatwg.org/multipage/server-sent-events.html\n *\n * Based on code from the {@link https://github.com/EventSource/eventsource | EventSource module},\n * which is licensed under the MIT license. And copyrighted the EventSource GitHub organisation.\n */\nimport type {EventSourceParseCallback, EventSourceParser} from './types.js'\n\n/**\n * Creates a new EventSource parser.\n *\n * @param onParse - Callback to invoke when a new event is parsed, or a new reconnection interval\n * has been sent from the server\n *\n * @returns A new EventSource parser, with `parse` and `reset` methods.\n * @public\n */\nexport function createParser(onParse: EventSourceParseCallback): EventSourceParser {\n // Processing state\n let isFirstChunk: boolean\n let buffer: string\n let startingPosition: number\n let startingFieldLength: number\n\n // Event state\n let eventId: string | undefined\n let eventName: string | undefined\n let data: string\n\n reset()\n return {feed, reset}\n\n function reset(): void {\n isFirstChunk = true\n buffer = ''\n startingPosition = 0\n startingFieldLength = -1\n\n eventId = undefined\n eventName = undefined\n data = ''\n }\n\n function feed(chunk: string): void {\n buffer = buffer ? buffer + chunk : chunk\n\n // Strip any UTF8 byte order mark (BOM) at the start of the stream.\n // Note that we do not strip any non - UTF8 BOM, as eventsource streams are\n // always decoded as UTF8 as per the specification.\n if (isFirstChunk && hasBom(buffer)) {\n buffer = buffer.slice(BOM.length)\n }\n\n isFirstChunk = false\n\n // Set up chunk-specific processing state\n const length = buffer.length\n let position = 0\n let discardTrailingNewline = false\n\n // Read the current buffer byte by byte\n while (position < length) {\n // EventSource allows for carriage return + line feed, which means we\n // need to ignore a linefeed character if the previous character was a\n // carriage return\n // @todo refactor to reduce nesting, consider checking previous byte?\n // @todo but consider multiple chunks etc\n if (discardTrailingNewline) {\n if (buffer[position] === '\\n') {\n ++position\n }\n discardTrailingNewline = false\n }\n\n let lineLength = -1\n let fieldLength = startingFieldLength\n let character: string\n\n for (let index = startingPosition; lineLength < 0 && index < length; ++index) {\n character = buffer[index]\n if (character === ':' && fieldLength < 0) {\n fieldLength = index - position\n } else if (character === '\\r') {\n discardTrailingNewline = true\n lineLength = index - position\n } else if (character === '\\n') {\n lineLength = index - position\n }\n }\n\n if (lineLength < 0) {\n startingPosition = length - position\n startingFieldLength = fieldLength\n break\n } else {\n startingPosition = 0\n startingFieldLength = -1\n }\n\n parseEventStreamLine(buffer, position, fieldLength, lineLength)\n\n position += lineLength + 1\n }\n\n if (position === length) {\n // If we consumed the entire buffer to read the event, reset the buffer\n buffer = ''\n } else if (position > 0) {\n // If there are bytes left to process, set the buffer to the unprocessed\n // portion of the buffer only\n buffer = buffer.slice(position)\n }\n }\n\n function parseEventStreamLine(\n lineBuffer: string,\n index: number,\n fieldLength: number,\n lineLength: number,\n ) {\n if (lineLength === 0) {\n // We reached the last line of this event\n if (data.length > 0) {\n onParse({\n type: 'event',\n id: eventId,\n event: eventName || undefined,\n data: data.slice(0, -1), // remove trailing newline\n })\n\n data = ''\n eventId = undefined\n }\n eventName = undefined\n return\n }\n\n const noValue = fieldLength < 0\n const field = lineBuffer.slice(index, index + (noValue ? lineLength : fieldLength))\n let step = 0\n\n if (noValue) {\n step = lineLength\n } else if (lineBuffer[index + fieldLength + 1] === ' ') {\n step = fieldLength + 2\n } else {\n step = fieldLength + 1\n }\n\n const position = index + step\n const valueLength = lineLength - step\n const value = lineBuffer.slice(position, position + valueLength).toString()\n\n if (field === 'data') {\n data += value ? `${value}\\n` : '\\n'\n } else if (field === 'event') {\n eventName = value\n } else if (field === 'id' && !value.includes('\\u0000')) {\n eventId = value\n } else if (field === 'retry') {\n const retry = parseInt(value, 10)\n if (!Number.isNaN(retry)) {\n onParse({type: 'reconnect-interval', value: retry})\n }\n }\n }\n}\n\nconst BOM = [239, 187, 191]\n\nfunction hasBom(buffer: string) {\n return BOM.every((charCode: number, index: number) => buffer.charCodeAt(index) === charCode)\n}\n"],"names":["createParser","onParse","isFirstChunk","buffer","startingPosition","startingFieldLength","eventId","eventName","data","reset","feed","chunk","hasBom","slice","BOM","length","position","discardTrailingNewline","lineLength","fieldLength","character","index","parseEventStreamLine","lineBuffer","type","id","event","noValue","field","step","valueLength","value","toString","concat","includes","retry","parseInt","Number","isNaN","every","charCode","charCodeAt"],"mappings":"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"}