/* eslint-disable @typescript-eslint/no-unsafe-enum-comparison */ import { isHTMLTag } from '@vue/shared'; import { load } from 'cheerio'; import {} from 'vuepress/shared'; import { isArray } from '../../shared/index.js'; const MEDIA_WITH_ALT = ['img']; const REMOVED_TAGS = [ // non content 'title', 'base', 'meta', 'template', 'script', 'style', 'canvas', 'slot', // not main content 'nav', 'aside', 'footer', // deleted 'del', 's', // rich media 'audio', 'video', 'canvas', 'iframe', 'map', 'area', 'track', 'object', // input 'input', 'textarea', 'select', 'option', 'optgroup', 'datalist', ]; const handleNode = (node, { base, removedTags }) => { if (node.type === 'tag') { // toc should be dropped if ([node.attribs.class, node.attribs.id].some((item) => ['table-of-contents', 'toc'].includes(item))) return ''; // return alt text if (MEDIA_WITH_ALT.includes(node.tagName)) { return node.attribs.alt || ''; } // html tags can be returned if (!REMOVED_TAGS.includes(node.tagName) && !removedTags.includes(node.tagName) && isHTMLTag(node.tagName)) { // eslint-disable-next-line @typescript-eslint/no-use-before-define return handleNodes(node.children, { base, removedTags }); } return ''; } if (node.type === 'text') return node.data; return ''; }; const handleNodes = (nodes, { base, removedTags }) => isArray(nodes) ? nodes.map((node) => handleNode(node, { base, removedTags })).join('') : ''; const $ = load(''); /** * Get plain text from html content * * 从 HTML 内容中获取纯文本 * * @param html - HTML content / HTML 内容 * @param base - Base url of site / 站点的基础 URL * @param options - Options for getting text / 获取文本的选项 * * @returns Plain text content / 纯文本内容 */ export const getText = (html, base, { length = 300, singleLine, removedTags = ['table', 'pre'], } = {}) => { let result = ''; const rootNodes = html ? $.parseHTML(html) : []; for (const node of rootNodes) { const text = handleNode(node, { base, removedTags }); if (text) { result += text; if (text.length >= length) break; } } return (singleLine ? result.replace(/\n/g, ' ').replace(/\s+/g, ' ') : result).trim(); }; /** * Get plain text of page content * * 获取页面内容的纯文本 * * @param app - VuePress App / VuePress 应用 * @param page - VuePress Page / VuePress 页面 * @param options - Options for getting text / 获取文本的选项 * * @returns Plain text of page content / 页面内容的纯文本 */ export const getPageText = ({ options: { base } }, { contentRendered, // eslint-disable-next-line @typescript-eslint/no-explicit-any }, options = {}) => getText(contentRendered, base, options);