UNPKG

@atlaskit/adf-utils

Version:

Set of utilities to traverse, modify and create ADF documents.

87 lines 3 kB
import { traverse } from '../traverse/traverse'; // This is the set of marks that we wont allow in duplicate to // exist on a given node, regardless of their attributes. We do // not include annotations here, because we do allow duplicate // annotations as long as they have unique id attributes (valid scenario) const markDuplicatesDisallowed = new Set(['strong', 'underline', 'textColor', 'link', 'em', 'subsup', 'strike', 'backgroundColor']); const maybeHasDisallowedDuplicateMarks = node => { var _node$marks, _node$marks$map; const markTypes = (_node$marks = node.marks) === null || _node$marks === void 0 ? void 0 : (_node$marks$map = _node$marks.map(mark => mark.type)) === null || _node$marks$map === void 0 ? void 0 : _node$marks$map.filter(markType => // For annotations, we are performing the same cheap check // for duplicates by type, without considering IDs, to quickly determine // whether there may be potential deduping targets. // In the actual deduping logic in maybeRemoveDisallowedDuplicateMarks, // we correctly/safely dedupe annotations by their unique IDs. markDuplicatesDisallowed.has(markType) || markType === 'annotation'); if (!(markTypes !== null && markTypes !== void 0 && markTypes.length)) { return false; } return new Set(markTypes).size !== markTypes.length; }; const maybeRemoveDisallowedDuplicateMarks = node => { const quota = new Map(); const annotationsQuota = new Map(); const discardedMarks = []; markDuplicatesDisallowed.forEach(mark => { quota.set(mark, false); }); if (!node.marks) { return { discardedMarks }; } const dedupedMarks = node.marks.filter(mark => { const markType = mark.type; if (markType === 'annotation') { var _mark$attrs; const id = (_mark$attrs = mark.attrs) === null || _mark$attrs === void 0 ? void 0 : _mark$attrs.id; if (annotationsQuota.has(id)) { discardedMarks.push(mark); return false; } else { annotationsQuota.set(id, true); return true; } } if (quota.has(markType)) { if (!quota.get(markType)) { quota.set(markType, true); return true; } else { discardedMarks.push(mark); return false; } } return true; }); return { node: { ...node, marks: dedupedMarks }, discardedMarks }; }; export const transformDedupeMarks = adf => { let isTransformed = false; const discardedMarks = []; const transformedAdf = traverse(adf, { text: node => { if (maybeHasDisallowedDuplicateMarks(node)) { const result = maybeRemoveDisallowedDuplicateMarks(node); const resultDiscardedMarks = result.discardedMarks; if (resultDiscardedMarks.length) { discardedMarks.push(...resultDiscardedMarks); isTransformed = true; return result.node; } } return; } }); return { transformedAdf, isTransformed, discardedMarks }; };