107 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			107 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 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,
 | |
|       // If the data buffer's last character is a U+000A LINE FEED (LF) character,
 | |
|       // then remove the last character from the data buffer.
 | |
|       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 ? crIndex === chunk.length - 1 ? lineEnd = -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
 | |
| };
 | |
| //# sourceMappingURL=index.js.map
 |