File size: 9,107 Bytes
bc20498
1
{"version":3,"file":"index.cjs","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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"}