"use strict"; const anyIntersection = require("./anyIntersection"); const fill = require("./fill"); let Object_assign = Object.assign; if (typeof Object_assign !== "function") { Object_assign = function(target) { Array.prototype.slice.call(arguments, 1).forEach(function(obj) { Object.keys(obj).forEach(function(key) { target[key] = obj[key]; }); }); return target; }; } // Merge text part information within a styling fragment function assign(textPart, fragment) { const fragStart = fragment.start; const start = Math.max(fragment.start, textPart.start); const end = Math.min(fragment.end, textPart.end); return Object_assign({}, fragment, { start: start, end: end, text: fragment.text.slice(start - fragStart, end - fragStart), }); } // Merge the style fragments withing the text parts, taking into account // boundaries and text sections that have not matched to links or channels. // For example, given a string "foobar" where "foo" and "bar" have been // identified as parts (channels, links, etc.) and "fo", "ob" and "ar" have 3 // different styles, the first resulting part will contain fragments "fo" and // "o", and the second resulting part will contain "b" and "ar". "o" and "b" // fragments will contain duplicate styling attributes. function merge(textParts, styleFragments) { // Re-build the overall text (without control codes) from the style fragments const cleanText = styleFragments.reduce((acc, frag) => acc + frag.text, ""); // Every section of the original text that has not been captured in a "part" // is filled with "text" parts, dummy objects with start/end but no extra // metadata. const allParts = textParts .concat(fill(textParts, cleanText)) .sort((a, b) => a.start - b.start); // Distribute the style fragments within the text parts return allParts.map((textPart) => { textPart.fragments = styleFragments .filter((fragment) => anyIntersection(textPart, fragment)) .map((fragment) => assign(textPart, fragment)); return textPart; }); } module.exports = merge;