Core: concentrate search API utils

This commit is contained in:
Fuma Nama
2025-09-21 16:59:17 +08:00
parent f9e1f10e9e
commit d1ae3e8b87
19 changed files with 56 additions and 38 deletions
+9
View File
@@ -0,0 +1,9 @@
---
'fumadocs-core': minor
---
**Move `SortedResult` and other search-related types to `fumadocs-core/search`**
This also exposed the search result highlighter API, you may now use it for highlighting results of your own search integration
Old export will be kept until the next major release.
+2 -1
View File
@@ -1,11 +1,12 @@
import type * as Breadcrumb from 'fumadocs-core/breadcrumb';
import type * as TOC from 'fumadocs-core/toc';
import type * as Server from 'fumadocs-core/server';
import type * as Search from 'fumadocs-core/search';
import type * as Sidebar from 'fumadocs-core/sidebar';
import type { ElementType } from 'react';
import type * as MDX from 'fumadocs-core/mdx-plugins';
export type SortedResult = Server.SortedResult;
export type SortedResult = Search.SortedResult;
export type StructureOptions = MDX.StructureOptions;
+4
View File
@@ -32,6 +32,10 @@
"import": "./dist/hide-if-empty.js",
"types": "./dist/hide-if-empty.d.ts"
},
"./search": {
"import": "./dist/search/index.js",
"types": "./dist/search/index.d.ts"
},
"./search/*": {
"import": "./dist/search/*.js",
"types": "./dist/search/*.d.ts"
+1 -1
View File
@@ -6,7 +6,7 @@ import { type StaticOptions } from '@/search/client/static';
import { type AlgoliaOptions } from '@/search/client/algolia';
import { type OramaCloudOptions } from '@/search/client/orama-cloud';
import { type MixedbreadOptions } from '@/search/client/mixedbread';
import type { SortedResult } from '@/search/shared';
import type { SortedResult } from '@/search';
interface UseDocsSearch {
search: string;
+1 -1
View File
@@ -1,6 +1,6 @@
import type { BaseIndex } from '@/search/algolia';
import type { Hit, LiteClient, SearchResponse } from 'algoliasearch/lite';
import { createContentHighlighter, type SortedResult } from '@/search/shared';
import { createContentHighlighter, type SortedResult } from '@/search';
export interface AlgoliaOptions {
indexName: string;
+1 -1
View File
@@ -1,4 +1,4 @@
import type { SortedResult } from '@/server';
import type { SortedResult } from '@/search';
export interface FetchOptions {
/**
@@ -1,4 +1,4 @@
import { SortedResult } from '@/server';
import type { SortedResult } from '@/search';
import Mixedbread from '@mixedbread/sdk';
import { VectorStoreSearchResponse } from '@mixedbread/sdk/resources/vector-stores';
import removeMd from 'remove-markdown';
@@ -1,8 +1,7 @@
import type { SortedResult } from '@/server';
import type { ClientSearchParams, OramaClient } from '@oramacloud/client';
import { removeUndefined } from '@/utils/remove-undefined';
import type { OramaIndex } from '@/search/orama-cloud';
import { createContentHighlighter } from '@/search/shared';
import { createContentHighlighter, type SortedResult } from '@/search';
interface CrawlerIndex {
path: string;
@@ -1,18 +1,27 @@
export interface SortedResult {
import type { ReactNode } from 'react';
export interface SortedResult<Content = string> {
id: string;
url: string;
type: 'page' | 'heading' | 'text';
content: string;
contentWithHighlights?: HighlightedText[];
content: Content;
/**
* breadcrumbs to be displayed on UI
*/
breadcrumbs?: Content[];
contentWithHighlights?: HighlightedText<Content>[];
}
export type HighlightedText = {
export type ReactSortedResult = SortedResult<ReactNode>;
export interface HighlightedText<Content = string> {
type: 'text';
content: string;
content: Content;
styles?: {
highlight?: boolean;
};
};
}
function escapeRegExp(input: string): string {
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
@@ -4,8 +4,7 @@ import {
type advancedSchema,
} from '@/search/orama/create-db';
import { removeUndefined } from '@/utils/remove-undefined';
import type { SortedResult } from '@/server';
import { createContentHighlighter } from '@/search/shared';
import { createContentHighlighter, type SortedResult } from '@/search';
export async function searchAdvanced(
db: Orama<typeof advancedSchema>,
@@ -1,10 +1,9 @@
import { type Orama, search, type SearchParams } from '@orama/orama';
import type { SortedResult } from '@/server';
import {
type SimpleDocument,
type simpleSchema,
} from '@/search/orama/create-db';
import { createContentHighlighter } from '@/search/shared';
import { createContentHighlighter, type SortedResult } from '@/search';
export async function searchSimple(
db: Orama<typeof simpleSchema>,
+2 -2
View File
@@ -17,7 +17,7 @@ import {
} from '@/search/orama/create-db';
import { searchSimple } from '@/search/orama/search/simple';
import { searchAdvanced } from '@/search/orama/search/advanced';
import type { SortedResult } from '@/search/shared';
import type { SortedResult } from '@/search';
type SearchType = 'simple' | 'advanced';
@@ -181,4 +181,4 @@ export function initAdvancedSearch(options: AdvancedOptions): SearchServer {
export { createFromSource } from './orama/create-from-source';
export { createI18nSearchAPI } from './orama/create-i18n';
export * from './shared';
export * from './index';
+2 -2
View File
@@ -4,5 +4,5 @@ export * as PageTree from '../source/page-tree/definitions';
export * from './git-api';
export * from './metadata';
// backward compat
export type { SortedResult } from '../search/shared';
// TODO: replace this with `fumadocs-core/search`
export type { SortedResult } from '../search';
+1 -1
View File
@@ -1,5 +1,5 @@
import { expect, test } from 'vitest';
import { createContentHighlighter } from '@/search/shared';
import { createContentHighlighter } from '@/search';
test('highlight search results', () => {
const highlighter = createContentHighlighter('hello world helloworld');
+1 -4
View File
@@ -12,10 +12,7 @@ export default defineConfig({
entry: [
'src/{toc,link,breadcrumb,sidebar,dynamic-link,hide-if-empty}.tsx',
'src/{server,source,mdx-plugins,content}/index.ts',
'src/search/client.ts',
'src/search/server.ts',
'src/search/algolia.ts',
'src/search/orama-cloud.ts',
'src/search/{index,client,server,algolia,orama-cloud}.ts',
'src/utils/use-on-change.ts',
'src/utils/use-effect-event.ts',
'src/utils/use-media-query.ts',
@@ -16,11 +16,11 @@ import {
SearchDialogInput,
SearchDialogList,
SearchDialogOverlay,
type SharedProps,
TagsList,
TagsListItem,
type SharedProps,
} from './search';
import type { SortedResult } from 'fumadocs-core/server';
import type { SortedResult } from 'fumadocs-core/search';
import type { SearchLink, TagItem } from '@/contexts/search';
import { useI18n } from '@/contexts/i18n';
@@ -14,11 +14,11 @@ import {
SearchDialogInput,
SearchDialogList,
SearchDialogOverlay,
type SharedProps,
TagsList,
TagsListItem,
type SharedProps,
} from './search';
import type { SortedResult } from 'fumadocs-core/server';
import type { SortedResult } from 'fumadocs-core/search';
import type { SearchLink, TagItem } from '@/contexts/search';
export interface DefaultSearchDialogProps extends SharedProps {
@@ -16,11 +16,11 @@ import {
SearchDialogInput,
SearchDialogList,
SearchDialogOverlay,
type SharedProps,
TagsList,
TagsListItem,
type SharedProps,
} from './search';
import type { SortedResult } from 'fumadocs-core/server';
import type { SortedResult } from 'fumadocs-core/search';
import type { SearchLink, TagItem } from '@/contexts/search';
import { useI18n } from '@/contexts/i18n';
+7 -6
View File
@@ -21,7 +21,10 @@ import {
DialogOverlay,
DialogTitle,
} from '@radix-ui/react-dialog';
import type { SortedResult } from 'fumadocs-core/server';
import type {
HighlightedText,
ReactSortedResult as BaseResultType,
} from 'fumadocs-core/search';
import { cva } from 'class-variance-authority';
import { useEffectEvent } from 'fumadocs-core/utils/use-effect-event';
import { useRouter } from 'fumadocs-core/framework';
@@ -29,12 +32,10 @@ import type { SharedProps } from '@/contexts/search';
import { useOnChange } from 'fumadocs-core/utils/use-on-change';
import scrollIntoView from 'scroll-into-view-if-needed';
import { buttonVariants } from '@/components/ui/button';
import type { HighlightedText } from 'fumadocs-core/search/server';
type ReactSortedResult = Omit<SortedResult, 'content'> & {
interface ReactSortedResult extends BaseResultType {
external?: boolean;
content: ReactNode;
};
}
// needed for backward compatible since some previous guides referenced it
export type { SharedProps };
@@ -469,7 +470,7 @@ export function TagsListItem({
);
}
function renderHighlights(highlights: HighlightedText[]): ReactNode {
function renderHighlights(highlights: HighlightedText<ReactNode>[]): ReactNode {
return highlights.map((node, i) => {
if (node.styles?.highlight) {
return (