Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
at main 78 lines 1.9 kB view raw
1import type { Element, Node, Parent, Root } from "hast"; 2 3import type { Plugin } from "unified"; 4import { visitParents } from "unist-util-visit-parents"; 5 6const isParent = (node: Node): node is Parent => { 7 return "children" in node && Array.isArray(node.children); 8}; 9 10interface Paragraph extends Element { 11 tagName: "p"; 12} 13 14const isElement = (node: Node): node is Element => { 15 return node.type === "element"; 16}; 17 18const isParagraph = (node: Node): node is Paragraph => { 19 return isElement(node) && node.tagName.toLowerCase() === "p"; 20}; 21 22const isParagraphEmpty = (node: Paragraph): boolean => { 23 return node.children.length === 0; 24}; 25 26const joinParagraphs = (a: Paragraph, b: Paragraph): Paragraph => { 27 const br: Element = { 28 children: [], 29 properties: {}, 30 tagName: "br", 31 type: "element" 32 }; 33 34 return { 35 ...a, 36 ...b, 37 children: [...a.children, br, ...b.children], 38 properties: { ...a.properties, ...b.properties } 39 }; 40}; 41 42const joinChildren = <T extends Node>(children: T[]): T[] => { 43 const result: T[] = []; 44 45 for (const child of children) { 46 const previous = result.at(-1); 47 if ( 48 previous && 49 isParagraph(previous) && 50 isParagraph(child) && 51 !isParagraphEmpty(previous) && 52 !isParagraphEmpty(child) 53 ) { 54 result[result.length - 1] = joinParagraphs(previous, child) as Node as T; 55 } else { 56 result.push(child); 57 } 58 } 59 60 return result; 61}; 62 63const rehypeJoinParagraphTransformer = (root: Root): Root => { 64 visitParents(root, (node) => { 65 if (isParent(node)) { 66 node.children = joinChildren(node.children); 67 } 68 }); 69 70 return root; 71}; 72 73/** 74 * A rehype (HTML) plugin that joins adjacent non-empty <p> elements into a 75 * single <p> element with a <br> element between them. 76 */ 77export const rehypeJoinParagraph: Plugin<[], Root> = () => 78 rehypeJoinParagraphTransformer;