UNPKG

@fastly/esi

Version:

ESI implementation for JavaScript, using the modern fetch and streaming APIs.

60 lines (59 loc) 3 kB
/* * Copyright Fastly, Inc. * Licensed under the MIT license. See LICENSE file for details. */ // XML Transformation Stream // Base class for applying transformation to streaming XML. // As items stream in, we check for completed top level items. // Whenever one of the items in this gets "completed", it is dispatched. When it is dispatched, it is // removed from the array. import { XmlStreamerContext } from "./XmlStreamer.js"; import { XmlElement } from "./XmlModel.js"; const textEncoder = new TextEncoder(); const textDecoder = new TextDecoder(); export default class XmlTransformStream extends TransformStream { constructor(document, xmlTransformer, ignoreDefaultTags = false) { const xmlStreamerContext = new XmlStreamerContext(document, { ignoreDefaultTags, beforeProcess: xmlTransformer.xmlStreamerBeforeProcess }); async function dispatchCompleteTopLevelChildren(enqueueFunc) { while (xmlStreamerContext.children.length > 0) { const firstChild = xmlStreamerContext.children.shift(); if (firstChild instanceof XmlElement && xmlStreamerContext.openElements.includes(firstChild)) { // If the item is an open element, we will not dispatch this one yet, // and break the loop xmlStreamerContext.children.unshift(firstChild); break; } // Dispatch the item const transformResult = await xmlTransformer.transformElementNode(firstChild); const transformResultString = XmlElement.serialize(transformResult); const chunk = textEncoder.encode(transformResultString); enqueueFunc(chunk); } } const transformer = { async transform(chunk, controller) { // noinspection SuspiciousTypeOfGuard if (!(chunk instanceof Uint8Array)) { // Guard anyway in case someone uses this TransformStream with an unexpected stream type throw new Error('Received non-Uint8Array chunk'); } let chunkAsString = textDecoder.decode(chunk); // Whenever a chunk is added, it is added to the currently processing chunk, and an attempt is made to // parse it. // Whenever one of the items in this gets "completed", it is dispatched. When it is dispatched, it is // removed from the array. xmlStreamerContext.append(chunkAsString); await dispatchCompleteTopLevelChildren(chunk => { controller.enqueue(chunk); }); }, async flush(controller) { xmlStreamerContext.flush(true); await dispatchCompleteTopLevelChildren(chunk => { controller.enqueue(chunk); }); }, }; super(transformer); } }