UNPKG

@speckle/shared

Version:

Shared code between various Speckle JS packages

116 lines (101 loc) 3.05 kB
/* eslint-disable @typescript-eslint/no-explicit-any */ import { trim, isNumber } from '#lodash' import type { Optional } from '../../core/helpers/utilityTypes.js' // TODO: had to copy out of tiptap/core, because of a build issue w/ a type-only import from CJS type JSONContent = { [key: string]: any type?: string | undefined attrs?: Record<string, any> | undefined content?: JSONContent[] marks?: { type: string attrs?: Record<string, any> [key: string]: any }[] text?: string } /** * Used to match URLs that can appear anywhere in a string, not perfect, but crafting a perfect * URL regex is quite complex and we only need this for legacy comments */ const MID_STRING_URL_RGX = /https?:\/\/\S+/gi /** * Check whether a doc is empty */ export function isDocEmpty(doc: JSONContent | null | undefined): boolean { if (!doc) return true return trim(documentToBasicString(doc, 1)).length < 1 } /** * Convert document to a basic string without all of the formatting, HTML tags, attributes etc. * Useful for previews or text analysis. * @param stopAtLength If set, will stop further parsing when the resulting string length * reaches this length. Useful when you're only interested in the first few characters of the document. */ export function documentToBasicString( doc: JSONContent | null | undefined, stopAtLength: Optional<number> = undefined ): string { if (!doc) return '' const recursiveStringBuilder = (doc: JSONContent, currentString: string) => { if (isNumber(stopAtLength) && currentString.length >= stopAtLength) { return currentString } if (doc.text) { currentString += doc.text } // if mention, add it as text as well if (doc.type === 'mention' && doc.attrs?.label && doc.attrs.id) { currentString += '@' + doc.attrs.label } for (const contentDoc of doc.content || []) { currentString = recursiveStringBuilder(contentDoc, currentString) } return currentString } return recursiveStringBuilder(doc, '') } /** * Build a rich text document out of a basic string */ export function convertBasicStringToDocument(text: string) { // Extract URLs and convert to text with link marks const urlMatches = [...text.matchAll(MID_STRING_URL_RGX)].map((m) => m[0]) const splitTexts = text.split(MID_STRING_URL_RGX) const textNodes = [] for (const textPart of splitTexts) { // Build text node, if text part not empty if (trim(textPart)) { textNodes.push({ type: 'text', text: textPart }) } // Get url node to append, if any remaining const url = urlMatches.shift() if (url) { textNodes.push({ type: 'text', text: url, marks: [ { attrs: { href: url, target: '_blank' }, type: 'link' } ] }) } } return <JSONContent>{ type: 'doc', content: [ { type: 'paragraph', content: textNodes } ] } }