Skip to content

Commit c4a8232

Browse files
committed
fix(search): clean markdown elements in search contents
1 parent 4ad3e36 commit c4a8232

File tree

3 files changed

+90
-2
lines changed

3 files changed

+90
-2
lines changed

src/plugins/search/markdown-to-txt.js

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* This is a modified version of the
3+
* [markdown-to-txt](https://www.npmjs.com/package/markdown-to-txt) library.
4+
*/
5+
import { marked } from 'marked';
6+
import { escape, unescape } from 'lodash';
7+
const block = text => text + '\n\n';
8+
const escapeBlock = text => escape(text) + '\n\n';
9+
const line = text => text + '\n';
10+
const inline = text => text;
11+
const newline = () => '\n';
12+
const empty = () => '';
13+
14+
const TxtRenderer = {
15+
// Block elements
16+
code: escapeBlock,
17+
blockquote: block,
18+
html: empty,
19+
heading: block,
20+
hr: newline,
21+
list: text => block(text.trim()),
22+
listitem: line,
23+
checkbox: empty,
24+
paragraph: block,
25+
table: (header, body) => line(header + body),
26+
tablerow: text => line(text.trim()),
27+
tablecell: text => text + ' ',
28+
// Inline elements
29+
strong: inline,
30+
em: inline,
31+
codespan: inline,
32+
br: newline,
33+
del: inline,
34+
link: (_0, _1, text) => text,
35+
image: (_0, _1, text) => text,
36+
text: inline,
37+
// etc.
38+
options: {},
39+
};
40+
41+
/**
42+
* Converts markdown to plaintext using the marked Markdown library.
43+
* Accepts [MarkedOptions](https://marked.js.org/using_advanced#options) as
44+
* the second argument.
45+
*
46+
* NOTE: The output of markdownToTxt is NOT sanitized. The output may contain
47+
* valid HTML, JavaScript, etc. Be sure to sanitize if the output is intended
48+
* for web use.
49+
*
50+
* @param markdown the markdown text to txtify
51+
* @param options the marked options
52+
* @returns the unmarked text
53+
*/
54+
export function markdownToTxt(markdown, options) {
55+
const unmarked = marked(markdown, { ...options, renderer: TxtRenderer });
56+
const unescaped = unescape(unmarked);
57+
const trimmed = unescaped.trim();
58+
return trimmed;
59+
}
60+
61+
export default markdownToTxt;

src/plugins/search/search.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
getAndRemoveConfig,
33
getAndRemoveDocisfyIgnoreConfig,
44
} from '../../core/render/utils.js';
5+
import { markdownToTxt } from './markdown-to-txt.js';
56

67
let INDEXS = {};
78

@@ -34,6 +35,13 @@ function escapeHtml(string) {
3435
return String(string).replace(/[&<>"']/g, s => entityMap[s]);
3536
}
3637

38+
function cleanMarkdown(text) {
39+
if (text) {
40+
text = markdownToTxt(text);
41+
}
42+
return text;
43+
}
44+
3745
function getAllPaths(router) {
3846
const paths = [];
3947

@@ -226,8 +234,8 @@ export function search(query) {
226234

227235
if (matchesScore > 0) {
228236
const matchingPost = {
229-
title: handlePostTitle,
230-
content: postContent ? resultStr : '',
237+
title: cleanMarkdown(handlePostTitle),
238+
content: cleanMarkdown(postContent ? resultStr : ''),
231239
url: postUrl,
232240
score: matchesScore,
233241
};

test/e2e/search.test.js

+19
Original file line numberDiff line numberDiff line change
@@ -232,4 +232,23 @@ test.describe('Search Plugin Tests', () => {
232232
await page.keyboard.press('z');
233233
await expect(searchFieldElm).toBeFocused();
234234
});
235+
test('search result should remove markdown', async ({ page }) => {
236+
const docsifyInitConfig = {
237+
markdown: {
238+
homepage: `
239+
# The [mock](example.com) link
240+
There is lots of words.
241+
`,
242+
},
243+
scriptURLs: ['/dist/plugins/search.js'],
244+
};
245+
246+
const searchFieldElm = page.locator('input[type=search]');
247+
const resultsHeadingElm = page.locator('.results-panel h2');
248+
249+
await docsifyInit(docsifyInitConfig);
250+
251+
await searchFieldElm.fill('There');
252+
await expect(resultsHeadingElm).toHaveText('The mock link');
253+
});
235254
});

0 commit comments

Comments
 (0)