import { Link } from './types'; const Entities = require('html-entities').AllHtmlEntities; const htmlparser2 = require('@joplin/fork-htmlparser2'); const selfClosingElements = [ 'area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame', 'hr', 'img', 'input', 'isindex', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr', ]; const entitiesInstance = new Entities(); export const htmlentities = entitiesInstance.encode; export const htmlentitiesDecode = entitiesInstance.decode; export const attributesHtml = (attr: Record<string, any>) => { const output = []; for (const n in attr) { if (!attr.hasOwnProperty(n)) continue; output.push(`${n}="${htmlentities(attr[n])}"`); } return output.join(' '); }; export const isSelfClosingTag = (tagName: string) => { return selfClosingElements.includes(tagName.toLowerCase()); }; export const extractUrls = (html: string) => { if (!html || !html.trim()) return []; const output: Link[] = []; let currentLink: Link|null = null; const parser = new htmlparser2.Parser({ onopentag: (name: string, attrs: Record<string, string>) => { if (name === 'a') { currentLink = { url: attrs && attrs.href ? attrs.href : '', title: '', }; } }, ontext: (text: string) => { if (currentLink) currentLink.title += text; }, onclosetag: (name: string) => { if (name === 'a') { if (!currentLink) throw new Error('Found a closing anchor tag without an opening one'); output.push(currentLink); currentLink = null; } }, }, { decodeEntities: true }); parser.write(html); parser.end(); return output; };