@@ -18,7 +18,7 @@ type Section = {
1818}
1919
2020const HEADING = / ^ h ( [ 1 - 6 ] ) $ /
21- const isHeading = ( tag : string ) => HEADING . test ( tag )
21+ const headingLevel = ( tag : string ) => Number ( tag . match ( HEADING ) ?. [ 1 ] ?? 0 )
2222
2323interface SectionablePage {
2424 path : string
@@ -27,18 +27,20 @@ interface SectionablePage {
2727 body : MDCRoot | MinimarkTree
2828}
2929
30- export async function generateSearchSections < T extends PageCollectionItemBase > ( queryBuilder : CollectionQueryBuilder < T > , opts ?: { ignoredTags ?: string [ ] , extraFields ?: Array < keyof T > } ) {
31- const { ignoredTags = [ ] , extraFields = [ ] } = opts || { }
30+ export async function generateSearchSections < T extends PageCollectionItemBase > ( queryBuilder : CollectionQueryBuilder < T > , opts ?: { ignoredTags ?: string [ ] , extraFields ?: Array < keyof T > , minHeading ?: `h${1 | 2 | 3 | 4 | 5 | 6 } `, maxHeading ?: `h${1 | 2 | 3 | 4 | 5 | 6 } ` } ) {
31+ const { ignoredTags = [ ] , extraFields = [ ] , minHeading = 'h1' , maxHeading = 'h6' } = opts || { }
32+ const minLevel = headingLevel ( minHeading )
33+ const maxLevel = headingLevel ( maxHeading )
3234
3335 const documents = await queryBuilder
3436 . where ( 'extension' , '=' , 'md' )
3537 . select ( 'path' , 'body' , 'description' , 'title' , ...( extraFields || [ ] ) )
3638 . all ( )
3739
38- return documents . flatMap ( doc => splitPageIntoSections ( doc , { ignoredTags, extraFields : extraFields as string [ ] } ) )
40+ return documents . flatMap ( doc => splitPageIntoSections ( doc , { ignoredTags, extraFields : extraFields as string [ ] , minLevel , maxLevel } ) )
3941}
4042
41- function splitPageIntoSections ( page : SectionablePage , { ignoredTags, extraFields } : { ignoredTags : string [ ] , extraFields : Array < string > } ) {
43+ function splitPageIntoSections ( page : SectionablePage , { ignoredTags, extraFields, minLevel , maxLevel } : { ignoredTags : string [ ] , extraFields : Array < string > , minLevel : number , maxLevel : number } ) {
4244 const body = ( ! page . body || page . body ?. type === 'root' ) ? page . body : toHast ( page . body as unknown as MinimarkTree ) as MDCRoot
4345 const path = ( page . path ?? '' )
4446 const extraFieldsData = pick ( extraFields ) ( page as unknown as Record < string , unknown > )
@@ -57,27 +59,22 @@ function splitPageIntoSections(page: SectionablePage, { ignoredTags, extraFields
5759 return sections
5860 }
5961
60- // No section
6162 let section = 1
6263 let previousHeadingLevel = 0
6364 const titles = [ page . title ?? '' ]
6465 for ( const item of body . children ) {
6566 const tag = ( item as MDCElement ) . tag || ''
66- if ( isHeading ( tag ) ) {
67- const currentHeadingLevel : number = Number ( tag . match ( HEADING ) ?. [ 1 ] ?? 0 )
68-
67+ const level = headingLevel ( tag )
68+ if ( level >= minLevel && level <= maxLevel ) {
6969 const title = extractTextFromAst ( item ) . trim ( )
7070
71- if ( currentHeadingLevel === 1 ) {
72- // Reset the titles
71+ if ( level === 1 ) {
7372 titles . splice ( 0 , titles . length )
7473 }
75- else if ( currentHeadingLevel < previousHeadingLevel ) {
76- // Go up tree, remove every title after the current level
77- titles . splice ( currentHeadingLevel - 1 , titles . length - 1 )
74+ else if ( level < previousHeadingLevel ) {
75+ titles . splice ( level - 1 , titles . length - 1 )
7876 }
79- else if ( currentHeadingLevel === previousHeadingLevel ) {
80- // Same level, remove the last title (add title later to avoid to it in titles)
77+ else if ( level === previousHeadingLevel ) {
8178 titles . pop ( )
8279 }
8380
@@ -87,13 +84,11 @@ function splitPageIntoSections(page: SectionablePage, { ignoredTags, extraFields
8784 title,
8885 titles : [ ...titles ] ,
8986 content : '' ,
90- level : currentHeadingLevel ,
87+ level,
9188 } )
9289
9390 titles . push ( title )
94-
95- // Swap to a new section
96- previousHeadingLevel = currentHeadingLevel
91+ previousHeadingLevel = level
9792 section += 1
9893 }
9994 else {
0 commit comments