@limetech/lime-elements
Version:
114 lines (113 loc) • 3.56 kB
JavaScript
/**
* Extracts metadata from a ProseMirror document node
*
* This function traverses the entire document tree and collects information about
* special elements like images and links.
*
* @param doc - The ProseMirror document node to extract metadata from
* @returns A metadata object containing arrays of images and links found in the document
*/
export function getMetadataFromDoc(doc) {
const metadata = { images: [], links: [] };
doc.descendants((node) => {
if (isImageNode(node)) {
metadata.images.push(extractImageMetadata(node));
}
else if (isTextNodeWithMarks(node)) {
for (const link of extractLinkMetadata(node))
metadata.links.push(link);
}
return true;
});
return metadata;
}
function isImageNode(node) {
return node.type.name === 'image' && !!node.attrs;
}
function extractImageMetadata(node) {
return {
src: node.attrs.src,
state: node.attrs.state,
fileInfoId: node.attrs.fileInfoId,
};
}
function isTextNodeWithMarks(node) {
var _a;
return node.isText && ((_a = node.marks) === null || _a === void 0 ? void 0 : _a.length) > 0;
}
function extractLinkMetadata(node) {
return node.marks
.filter((mark) => mark.type.name === 'link' && mark.attrs)
.map((mark) => ({
href: mark.attrs.href,
text: node.text,
}));
}
/**
* Determines if metadata has changed between two states
* Handles duplicates correctly but is order-insensitive
*
* @param oldMetadata - The previous metadata state to compare against
* @param newMetadata - The current metadata state
* @returns True if there are any differences between the metadata objects, false otherwise
*/
export function hasMetadataChanged(oldMetadata, newMetadata) {
return (hasDifferentLengths(oldMetadata, newMetadata) ||
hasDifferentLinks(oldMetadata.links, newMetadata.links) ||
hasDifferentImages(oldMetadata.images, newMetadata.images));
}
function hasDifferentLengths(oldMetadata, newMetadata) {
return (oldMetadata.images.length !== newMetadata.images.length ||
oldMetadata.links.length !== newMetadata.links.length);
}
function hasDifferentLinks(oldLinks, newLinks) {
const oldLinkCounts = getLinkFrequencyMap(oldLinks);
const newLinkCounts = getLinkFrequencyMap(newLinks);
return !areFrequencyMapsEqual(oldLinkCounts, newLinkCounts);
}
function hasDifferentImages(oldImages, newImages) {
const oldImageCounts = getImageFrequencyMap(oldImages);
const newImageCounts = getImageFrequencyMap(newImages);
return !areFrequencyMapsEqual(oldImageCounts, newImageCounts);
}
/**
* Creates a frequency map for images based on their key properties
* @param images
*/
function getImageFrequencyMap(images) {
const countMap = new Map();
for (const image of images) {
const key = `${image.fileInfoId}|${image.state}|${image.src}`;
countMap.set(key, (countMap.get(key) || 0) + 1);
}
return countMap;
}
/**
* Creates a frequency map for links based on their key properties
* @param links
*/
function getLinkFrequencyMap(links) {
const countMap = new Map();
for (const link of links) {
const key = `${link.href}|${link.text}`;
countMap.set(key, (countMap.get(key) || 0) + 1);
}
return countMap;
}
/**
* Compares two frequency maps for equality
* @param map1
* @param map2
*/
function areFrequencyMapsEqual(map1, map2) {
if (map1.size !== map2.size) {
return false;
}
for (const [key, count] of map1.entries()) {
if (map2.get(key) !== count) {
return false;
}
}
return true;
}
//# sourceMappingURL=metadata-utils.js.map