diff --git a/package-lock.json b/package-lock.json index 9da1be264..be431304d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { + "markdown-to-txt": "^2.0.1", "medium-zoom": "^1.1.0", "opencollective-postinstall": "^2.0.2", "prismjs": "^1.29.0", @@ -10792,6 +10793,11 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, + "node_modules/lodash.escape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz", + "integrity": "sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw==" + }, "node_modules/lodash.isfinite": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", @@ -10816,6 +10822,11 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.unescape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", + "integrity": "sha512-DhhGRshNS1aX6s5YdBE3njCCouPgnG29ebyHvImlZzXZf2SHgt+J08DHgytTPnpywNbO1Y8mNUFyQuIDBq2JZg==" + }, "node_modules/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -11029,6 +11040,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/markdown-to-txt": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/markdown-to-txt/-/markdown-to-txt-2.0.1.tgz", + "integrity": "sha512-Hsj7KTN8k1gutlLum3vosHwVZGnv8/cbYKWVkUyo/D1rzOYddbDesILebRfOsaVfjIBJank/AVOySBlHAYqfZw==", + "dependencies": { + "lodash.escape": "^4.0.1", + "lodash.unescape": "^4.0.1", + "marked": "^4.0.14" + } + }, + "node_modules/markdown-to-txt/node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/marked": { "version": "12.0.2", "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", diff --git a/package.json b/package.json index 91b865f23..b38c441ac 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "*.js": "eslint --fix" }, "dependencies": { + "markdown-to-txt": "^2.0.1", "medium-zoom": "^1.1.0", "opencollective-postinstall": "^2.0.2", "prismjs": "^1.29.0", diff --git a/src/plugins/search/search.js b/src/plugins/search/search.js index 0428f69af..659440161 100644 --- a/src/plugins/search/search.js +++ b/src/plugins/search/search.js @@ -1,3 +1,4 @@ +import markdownToTxt from 'markdown-to-txt'; import { getAndRemoveConfig, getAndRemoveDocsifyIgnoreConfig, @@ -34,6 +35,17 @@ function escapeHtml(string) { return String(string).replace(/[&<>"']/g, s => entityMap[s]); } +function formatContent(text) { + return escapeHtml(cleanMarkdown(ignoreDiacriticalMarks(text))); +} + +function cleanMarkdown(text) { + if (text) { + text = markdownToTxt(text); + } + return text; +} + function getAllPaths(router) { const paths = []; @@ -175,19 +187,14 @@ export function search(query) { keywords.forEach(keyword => { // From https://github.com/sindresorhus/escape-string-regexp const regEx = new RegExp( - escapeHtml(ignoreDiacriticalMarks(keyword)).replace( - /[|\\{}()[\]^$+*?.]/g, - '\\$&', - ), + formatContent(keyword).replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'), 'gi', ); let indexTitle = -1; let indexContent = -1; - handlePostTitle = postTitle - ? escapeHtml(ignoreDiacriticalMarks(postTitle)) - : postTitle; + handlePostTitle = postTitle ? formatContent(postTitle) : postTitle; handlePostContent = postContent - ? escapeHtml(ignoreDiacriticalMarks(postContent)) + ? formatContent(postContent) : postContent; indexTitle = postTitle ? handlePostTitle.search(regEx) : -1; @@ -221,8 +228,8 @@ export function search(query) { if (matchesScore > 0) { const matchingPost = { - title: handlePostTitle, - content: postContent ? resultStr : '', + title: formatContent(handlePostTitle), + content: formatContent(postContent ? resultStr : ''), url: postUrl, score: matchesScore, }; diff --git a/test/e2e/search.test.js b/test/e2e/search.test.js index 6d0d2c1cf..ed73e6c2a 100644 --- a/test/e2e/search.test.js +++ b/test/e2e/search.test.js @@ -232,4 +232,23 @@ test.describe('Search Plugin Tests', () => { await page.keyboard.press('z'); await expect(searchFieldElm).toBeFocused(); }); + test('search result should remove markdown', async ({ page }) => { + const docsifyInitConfig = { + markdown: { + homepage: ` + # The [mock](example.com) link + There is lots of words. + `, + }, + scriptURLs: ['/dist/plugins/search.js'], + }; + + const searchFieldElm = page.locator('input[type=search]'); + const resultsHeadingElm = page.locator('.results-panel h2'); + + await docsifyInit(docsifyInitConfig); + + await searchFieldElm.fill('There'); + await expect(resultsHeadingElm).toHaveText('The mock link'); + }); });