From 8d5f3f66bab9a5ffb728d03e7d6dbb086d612c76 Mon Sep 17 00:00:00 2001 From: buqiyuan <1743369777@qq.com> Date: Sat, 30 Sep 2023 17:29:19 +0800 Subject: [PATCH 1/4] feat(node): localSearchPlugin support interpolation --- src/node/plugins/localSearchPlugin.ts | 32 ++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/node/plugins/localSearchPlugin.ts b/src/node/plugins/localSearchPlugin.ts index dc7ca8da7b29..398efc074c61 100644 --- a/src/node/plugins/localSearchPlugin.ts +++ b/src/node/plugins/localSearchPlugin.ts @@ -2,6 +2,7 @@ import _debug from 'debug' import fs from 'fs-extra' import MiniSearch from 'minisearch' import path from 'path' +import { toDisplayString } from 'vue' import type { Plugin, ViteDevServer } from 'vite' import type { SiteConfig } from '../config' import { createMarkdownRenderer } from '../markdown/markdown' @@ -24,7 +25,7 @@ interface IndexObject { title: string titles: string[] } - +let mdEnv: MarkdownEnv export async function localSearchPlugin( siteConfig: SiteConfig ): Promise { @@ -56,12 +57,12 @@ export async function localSearchPlugin( function render(file: string) { const { srcDir, cleanUrls = false } = siteConfig const relativePath = slash(path.relative(srcDir, file)) - const env: MarkdownEnv = { path: file, relativePath, cleanUrls } + mdEnv = { path: file, relativePath, cleanUrls } let src = fs.readFileSync(file, 'utf-8') src = processIncludes(srcDir, src, file, []) - if (options._render) return options._render(src, env, md) - const html = md.render(src, env) - return env.frontmatter?.search === false ? '' : html + if (options._render) return options._render(src, mdEnv, md) + const html = md.render(src, mdEnv) + return mdEnv.frontmatter?.search === false ? '' : html } const indexByLocales = new Map>() @@ -260,7 +261,9 @@ function splitPageIntoSections(html: string) { const level = parseInt(result[i]) - 1 const heading = result[i + 1] const headingResult = headingContentRegex.exec(heading) - const title = clearHtmlTags(headingResult?.[1] ?? '').trim() + const title = replaceInterpolation( + clearHtmlTags(headingResult?.[1] ?? '').trim() + ) const anchor = headingResult?.[2] ?? '' const content = result[i + 2] if (!title || !content) continue @@ -284,3 +287,20 @@ function getSearchableText(content: string) { function clearHtmlTags(str: string) { return str.replace(/<[^>]*>/g, '') } + +function replaceInterpolation(str: string) { + if (!mdEnv.frontmatter) { + return str + } + + return str.replace(/{{\s*([^}]+)\s*}}/g, (_, expression: string) => { + const properties = expression.trim().split('.') + let value: Record = { $frontmatter: { ...mdEnv.frontmatter } } + + for (let prop of properties) { + value = value?.[prop] + } + + return value ? toDisplayString(value) : str + }) +} From 3479d5a0ceb6eee476473a1c24c04a766750a0f9 Mon Sep 17 00:00:00 2001 From: buqiyuan <1743369777@qq.com> Date: Sat, 30 Sep 2023 20:41:38 +0800 Subject: [PATCH 2/4] update code --- src/node/plugins/localSearchPlugin.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/node/plugins/localSearchPlugin.ts b/src/node/plugins/localSearchPlugin.ts index 398efc074c61..9b01cf6a4a3b 100644 --- a/src/node/plugins/localSearchPlugin.ts +++ b/src/node/plugins/localSearchPlugin.ts @@ -25,7 +25,7 @@ interface IndexObject { title: string titles: string[] } -let mdEnv: MarkdownEnv +let mdEnv: MarkdownEnv | null export async function localSearchPlugin( siteConfig: SiteConfig ): Promise { @@ -276,6 +276,7 @@ function splitPageIntoSections(html: string) { parentTitles[level] = title } } + mdEnv = null return sections } @@ -289,13 +290,13 @@ function clearHtmlTags(str: string) { } function replaceInterpolation(str: string) { - if (!mdEnv.frontmatter) { + if (!mdEnv?.frontmatter) { return str } return str.replace(/{{\s*([^}]+)\s*}}/g, (_, expression: string) => { const properties = expression.trim().split('.') - let value: Record = { $frontmatter: { ...mdEnv.frontmatter } } + let value: Record = { $frontmatter: { ...mdEnv?.frontmatter } } for (let prop of properties) { value = value?.[prop] From ef70739d1749d2d789a4d757feb4fc4f68536605 Mon Sep 17 00:00:00 2001 From: buqiyuan <1743369777@qq.com> Date: Mon, 9 Oct 2023 16:04:32 +0800 Subject: [PATCH 3/4] test: add test case --- __tests__/e2e/local-search/index.md | 7 ++++- .../e2e/local-search/local-search.test.ts | 31 ++++++++++++++----- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/__tests__/e2e/local-search/index.md b/__tests__/e2e/local-search/index.md index 08d8b31a860f..6364f605097b 100644 --- a/__tests__/e2e/local-search/index.md +++ b/__tests__/e2e/local-search/index.md @@ -1 +1,6 @@ -# Local search included \ No newline at end of file +--- +title: Local search frontmatter title +--- +# Local search included + +# {{ $frontmatter.title }} \ No newline at end of file diff --git a/__tests__/e2e/local-search/local-search.test.ts b/__tests__/e2e/local-search/local-search.test.ts index 492136b68ab7..6e19a4232c3e 100644 --- a/__tests__/e2e/local-search/local-search.test.ts +++ b/__tests__/e2e/local-search/local-search.test.ts @@ -1,18 +1,23 @@ +const getSearchResults = async (text: string) => { + await page.locator('#local-search button').click() + + const input = await page.waitForSelector('input#localsearch-input') + await input.fill(text) + + await page.waitForSelector('ul#localsearch-list', { state: 'visible' }) + + return page.locator('#localsearch-list') +} + describe('local search', () => { beforeEach(async () => { await goto('/') }) test('exclude content from search results', async () => { - await page.locator('#local-search button').click() + const searchResults = await getSearchResults('local') - const input = await page.waitForSelector('input#localsearch-input') - await input.type('local') - - await page.waitForSelector('ul#localsearch-list', { state: 'visible' }) - - const searchResults = page.locator('#localsearch-list') - expect(await searchResults.locator('li[role=option]').count()).toBe(1) + expect(await searchResults.locator('li[role=option]').count()).toBe(2) expect( await searchResults.filter({ hasText: 'Local search included' }).count() @@ -28,4 +33,14 @@ describe('local search', () => { .count() ).toBe(0) }) + + test('frontmatter content from search results', async () => { + const searchResults = await getSearchResults('local') + + expect( + await searchResults + .filter({ hasText: 'Local search frontmatter title' }) + .count() + ).toBe(1) + }) }) From 585bacfe068852fb8a3b1a3c1222f0ca357c02e0 Mon Sep 17 00:00:00 2001 From: buqiyuan <1743369777@qq.com> Date: Sat, 14 Oct 2023 08:59:58 +0800 Subject: [PATCH 4/4] fix: callback return value --- src/node/plugins/localSearchPlugin.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node/plugins/localSearchPlugin.ts b/src/node/plugins/localSearchPlugin.ts index 9b01cf6a4a3b..d686606090dd 100644 --- a/src/node/plugins/localSearchPlugin.ts +++ b/src/node/plugins/localSearchPlugin.ts @@ -294,7 +294,7 @@ function replaceInterpolation(str: string) { return str } - return str.replace(/{{\s*([^}]+)\s*}}/g, (_, expression: string) => { + return str.replace(/{{\s*([^}]+)\s*}}/g, (match, expression: string) => { const properties = expression.trim().split('.') let value: Record = { $frontmatter: { ...mdEnv?.frontmatter } } @@ -302,6 +302,6 @@ function replaceInterpolation(str: string) { value = value?.[prop] } - return value ? toDisplayString(value) : str + return value ? toDisplayString(value) : match }) }