diff --git a/src/runtime/client.ts b/src/runtime/client.ts index 6f9708005..c1989a453 100644 --- a/src/runtime/client.ts +++ b/src/runtime/client.ts @@ -27,8 +27,14 @@ export function queryCollectionItemSurroundings return chainablePromise(collection, qb => generateItemSurround(qb, path, opts)) } -export function queryCollectionSearchSections(collection: T, opts?: GenerateSearchSectionsOptions) { - return chainablePromise(collection, qb => generateSearchSections(qb, opts)) +export function queryCollectionSearchSections< + T extends keyof PageCollections, + K extends keyof PageCollections[T] = never, +>( + collection: T, + opts?: GenerateSearchSectionsOptions, +) { + return chainablePromise(collection, qb => generateSearchSections(qb, opts)) } async function executeContentQuery(event: H3Event | undefined, collection: T, sql: string) { diff --git a/src/runtime/internal/search.ts b/src/runtime/internal/search.ts index d7eb1918f..e0ef1c0d5 100644 --- a/src/runtime/internal/search.ts +++ b/src/runtime/internal/search.ts @@ -27,27 +27,39 @@ interface SectionablePage { body: MDCRoot | MinimarkTree } -export type GenerateSearchSectionsOptions = { +export type GenerateSearchSectionsOptions = { ignoredTags?: string[] - extraFields?: (string | symbol | number)[] + extraFields?: K[] minHeading?: `h${1 | 2 | 3 | 4 | 5 | 6}` maxHeading?: `h${1 | 2 | 3 | 4 | 5 | 6}` } -export async function generateSearchSections(queryBuilder: CollectionQueryBuilder, opts?: GenerateSearchSectionsOptions) { +export async function generateSearchSections( + queryBuilder: CollectionQueryBuilder, + opts?: GenerateSearchSectionsOptions, +): Promise>> { const { ignoredTags = [], extraFields = [], minHeading = 'h1', maxHeading = 'h6' } = opts || {} const minLevel = headingLevel(minHeading) const maxLevel = headingLevel(maxHeading) const documents = await queryBuilder .where('extension', '=', 'md') - .select('path', 'body', 'description', 'title', ...(extraFields as Array || [])) + .select('path' as keyof T, 'body' as keyof T, 'description' as keyof T, 'title' as keyof T, ...(extraFields as K[])) .all() - return documents.flatMap(doc => splitPageIntoSections(doc, { ignoredTags, extraFields: extraFields as string[], minLevel, maxLevel })) + return documents.flatMap(doc => splitPageIntoSections(doc, { + ignoredTags, + extraFields: extraFields as string[], + minLevel, + maxLevel, + }), + ) as Array
> } -function splitPageIntoSections(page: SectionablePage, { ignoredTags, extraFields, minLevel, maxLevel }: { ignoredTags: string[], extraFields: Array, minLevel: number, maxLevel: number }) { +function splitPageIntoSections>( + page: SectionablePage & T, + { ignoredTags, extraFields, minLevel, maxLevel }: { ignoredTags: string[], extraFields: Array, minLevel: number, maxLevel: number }, +): Array
{ const body = (!page.body || page.body?.type === 'root') ? page.body : toHast(page.body as unknown as MinimarkTree) as MDCRoot const path = (page.path ?? '') const extraFieldsData = pick(extraFields)(page as unknown as Record) @@ -63,7 +75,7 @@ function splitPageIntoSections(page: SectionablePage, { ignoredTags, extraFields }] if (!body?.children) { - return sections + return sections as Array
} let section = 1 @@ -109,7 +121,7 @@ function splitPageIntoSections(page: SectionablePage, { ignoredTags, extraFields } } - return sections + return sections as Array
} function extractTextFromAst(node: MDCNode, ignoredTags: string[] = []) { diff --git a/src/runtime/server.ts b/src/runtime/server.ts index 3e98af8ca..a051e7f7b 100644 --- a/src/runtime/server.ts +++ b/src/runtime/server.ts @@ -25,8 +25,15 @@ export function queryCollectionItemSurroundings return chainablePromise(event, collection, qb => generateItemSurround(qb, path, opts)) } -export function queryCollectionSearchSections(event: H3Event, collection: T, opts?: GenerateSearchSectionsOptions) { - return chainablePromise(event, collection, qb => generateSearchSections(qb, opts)) +export function queryCollectionSearchSections< + T extends keyof PageCollections, + K extends keyof PageCollections[T] = never, +>( + event: H3Event, + collection: T, + opts?: GenerateSearchSectionsOptions, +) { + return chainablePromise(event, collection, qb => generateSearchSections(qb, opts)) } function chainablePromise(event: H3Event, collection: T, fn: (qb: CollectionQueryBuilder) => Promise) {