/** * @typedef {import('../types.js').Handle} Handle * @typedef {import('../types.js').Info} Info * @typedef {import('../types.js').PhrasingParents} PhrasingParents * @typedef {import('../types.js').State} State */ /** * Serialize the children of a parent that contains phrasing children. * * These children will be joined flush together. * * @param {PhrasingParents} parent * Parent of flow nodes. * @param {State} state * Info passed around about the current state. * @param {Info} info * Info on where we are in the document we are generating. * @returns {string} * Serialized children, joined together. */ export function containerPhrasing(parent, state, info) { const indexStack = state.indexStack const children = parent.children || [] /** @type {Array} */ const results = [] let index = -1 let before = info.before indexStack.push(-1) let tracker = state.createTracker(info) while (++index < children.length) { const child = children[index] /** @type {string} */ let after indexStack[indexStack.length - 1] = index if (index + 1 < children.length) { /** @type {Handle} */ // @ts-expect-error: hush, it’s actually a `zwitch`. let handle = state.handle.handlers[children[index + 1].type] /** @type {Handle} */ // @ts-expect-error: hush, it’s actually a `zwitch`. if (handle && handle.peek) handle = handle.peek after = handle ? handle(children[index + 1], parent, state, { before: '', after: '', ...tracker.current() }).charAt(0) : '' } else { after = info.after } // In some cases, html (text) can be found in phrasing right after an eol. // When we’d serialize that, in most cases that would be seen as html // (flow). // As we can’t escape or so to prevent it from happening, we take a somewhat // reasonable approach: replace that eol with a space. // See: if ( results.length > 0 && (before === '\r' || before === '\n') && child.type === 'html' ) { results[results.length - 1] = results[results.length - 1].replace( /(\r?\n|\r)$/, ' ' ) before = ' ' // To do: does this work to reset tracker? tracker = state.createTracker(info) tracker.move(results.join('')) } results.push( tracker.move( state.handle(child, parent, state, { ...tracker.current(), before, after }) ) ) before = results[results.length - 1].slice(-1) } indexStack.pop() return results.join('') }