diff --git a/plugins/search/plugin-slimsearch/src/client/helpers/search.ts b/plugins/search/plugin-slimsearch/src/client/helpers/search.ts index 2b546ee51b..c9c7b68aff 100644 --- a/plugins/search/plugin-slimsearch/src/client/helpers/search.ts +++ b/plugins/search/plugin-slimsearch/src/client/helpers/search.ts @@ -5,6 +5,7 @@ import { useRouteLocale } from 'vuepress/client' import { isFunction } from 'vuepress/shared' import type { SearchResult, WorkerSearchOptions } from '../typings/index.js' +import { defaultQuerySplitter } from '../utils/index.js' declare const __VUEPRESS_DEV__: boolean @@ -33,7 +34,9 @@ export interface SearchOptions extends SearchLocaleOptions { locales?: Record } -const searchOptions: Ref = ref({}) +const searchOptions: Ref = ref({ + querySplitter: (query) => Promise.resolve(defaultQuerySplitter(query)), +}) const slimsearchSymbol: InjectionKey> = Symbol( __VUEPRESS_DEV__ ? 'slimsearch' : '', diff --git a/plugins/search/plugin-slimsearch/src/client/utils/index.ts b/plugins/search/plugin-slimsearch/src/client/utils/index.ts index c8acdd3099..b4fc9924a3 100644 --- a/plugins/search/plugin-slimsearch/src/client/utils/index.ts +++ b/plugins/search/plugin-slimsearch/src/client/utils/index.ts @@ -2,3 +2,4 @@ export * from './createSearchWorker.js' export * from './getResultPath.js' export * from './isFocusingTextControl.js' export * from './isKeyMatched.js' +export * from './querySplitter.js' diff --git a/plugins/search/plugin-slimsearch/src/client/utils/querySplitter.ts b/plugins/search/plugin-slimsearch/src/client/utils/querySplitter.ts new file mode 100644 index 0000000000..724fae9aea --- /dev/null +++ b/plugins/search/plugin-slimsearch/src/client/utils/querySplitter.ts @@ -0,0 +1,16 @@ +const CJK_REGEXP = + /[\u4e00-\u9fff\u3400-\u4dbf\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/ + +export const defaultQuerySplitter = (query: string): string[] => + query + .split(/\s+/) + .map((word) => { + if (word.length > 3) { + const chars = word.split('') + + if (chars.every((char) => CJK_REGEXP.test(char))) return chars + } + + return word + }) + .flat() diff --git a/plugins/search/plugin-slimsearch/tests/querySliptter.spec.ts b/plugins/search/plugin-slimsearch/tests/querySliptter.spec.ts new file mode 100644 index 0000000000..6df69c2d9e --- /dev/null +++ b/plugins/search/plugin-slimsearch/tests/querySliptter.spec.ts @@ -0,0 +1,18 @@ +import { expect, it } from 'vitest' +import { defaultQuerySplitter } from '../src/client/utils/querySplitter.js' + +it('defaultQuerySplitter', () => { + const testCases: [string, string[]][] = [ + ['你好世界', ['你', '好', '世', '界']], + ['你好 世界', ['你好', '世界']], + ['hello world', ['hello', 'world']], + ['hello 你好 world 世界', ['hello', '你好', 'world', '世界']], + ['hi hello 你好 世界', ['hi', 'hello', '你好', '世界']], + ['', ['']], + ] + + for (const [query, expected] of testCases) { + const result = defaultQuerySplitter(query) + expect(result).toEqual(expected) + } +})