@@ -44,56 +44,91 @@ export function init(blocks: Block[]) {
44
44
inited = true ;
45
45
}
46
46
47
+ const CURRENT_SECTION_BOOST = 2 ;
48
+ const EXACT_MATCH_BOOST = 10 ;
49
+ const WORD_MATCH_BOOST = 4 ;
50
+ const NEAR_MATCH_BOOST = 2 ;
51
+ const BREADCRUMB_LENGTH_BOOST = 0.2 ;
52
+
53
+ interface Entry {
54
+ block : Block ;
55
+ score : number ;
56
+ rank : number ;
57
+ }
58
+
47
59
/**
48
60
* Search for a given query in the existing index
49
61
*/
50
- export function search ( query : string ) : BlockGroup [ ] {
62
+ export function search ( query : string , path : string ) : BlockGroup [ ] {
51
63
const escaped = query . replace ( / [ - [ \] { } ( ) * + ? . , \\ ^ $ | # \s ] / g, '\\$&' ) ;
52
- const regex = new RegExp ( `(^|\\b)${ escaped } ` , 'i' ) ;
64
+ const exact_match = new RegExp ( `^${ escaped } $` , 'i' ) ;
65
+ const word_match = new RegExp ( `(^|\\b)${ escaped } ($|\\b)` , 'i' ) ;
66
+ const near_match = new RegExp ( `(^|\\b)${ escaped } ` , 'i' ) ;
67
+
68
+ const parts = path . split ( '/' ) ;
53
69
54
70
const blocks = indexes
55
71
. flatMap ( ( index ) => index . search ( query ) )
56
72
// @ts -expect-error flexsearch types are wrong i think?
57
73
. map ( lookup )
58
- . map ( ( block , rank ) => ( { block : block as Block , rank } ) )
59
- . sort ( ( a , b ) => {
60
- // If rank is way lower, give that priority
61
- if ( Math . abs ( a . rank - b . rank ) > 3 ) {
62
- return a . rank - b . rank ;
74
+ . map ( ( block , rank ) => {
75
+ const block_parts = block . href . split ( '/' ) ;
76
+
77
+ // prioritise current section
78
+ let score = block_parts . findIndex ( ( part , i ) => part !== parts [ i ] ) ;
79
+ if ( score === - 1 ) score = block_parts . length ;
80
+ score *= CURRENT_SECTION_BOOST ;
81
+
82
+ if ( block . breadcrumbs . some ( ( text ) => exact_match . test ( text ) ) ) {
83
+ console . log ( 'EXACT MATCH' , block . breadcrumbs ) ;
84
+ score += EXACT_MATCH_BOOST ;
85
+ } else if ( block . breadcrumbs . some ( ( text ) => word_match . test ( text ) ) ) {
86
+ score += WORD_MATCH_BOOST ;
87
+ } else if ( block . breadcrumbs . some ( ( text ) => near_match . test ( text ) ) ) {
88
+ score += NEAR_MATCH_BOOST ;
63
89
}
64
90
65
- const a_title_matches = regex . test ( a . block . breadcrumbs . at ( - 1 ) ! ) ;
66
- const b_title_matches = regex . test ( b . block . breadcrumbs . at ( - 1 ) ! ) ;
91
+ // prioritise branches over leaves
92
+ score -= block . breadcrumbs . length * BREADCRUMB_LENGTH_BOOST ;
67
93
68
- // massage the order a bit, so that title matches
69
- // are given higher priority
70
- if ( a_title_matches !== b_title_matches ) {
71
- return a_title_matches ? - 1 : 1 ;
72
- }
94
+ const entry : Entry = { block, score, rank } ;
73
95
74
- return a . block . breadcrumbs . length - b . block . breadcrumbs . length || a . rank - b . rank ;
75
- } )
76
- . map ( ( { block } ) => block ) ;
96
+ return entry ;
97
+ } ) ;
77
98
78
- const groups : Record < string , BlockGroup > = { } ;
99
+ const grouped : Record < string , { breadcrumbs : string [ ] ; entries : Entry [ ] } > = { } ;
79
100
80
- for ( const block of blocks ) {
81
- const breadcrumbs = block . breadcrumbs . slice ( 0 , 2 ) ;
82
-
83
- const group = ( groups [ breadcrumbs . join ( '::' ) ] ??= {
101
+ for ( const entry of blocks ) {
102
+ const breadcrumbs = entry . block . breadcrumbs . slice ( 0 , 2 ) ;
103
+ const group = ( grouped [ breadcrumbs . join ( '::' ) ] ??= {
84
104
breadcrumbs,
85
- blocks : [ ]
105
+ entries : [ ]
86
106
} ) ;
87
107
88
- group . blocks . push ( block ) ;
108
+ group . entries . push ( entry ) ;
89
109
}
90
110
91
- return Object . values ( groups ) ;
111
+ const sorted = Object . values ( grouped ) ;
112
+
113
+ // sort blocks within groups...
114
+ for ( const group of sorted ) {
115
+ group . entries . sort ( ( a , b ) => b . score - a . score || a . rank - b . rank ) ;
116
+ }
117
+
118
+ // ...then sort groups
119
+ sorted . sort ( ( a , b ) => b . entries [ 0 ] . score - a . entries [ 0 ] . score ) ;
120
+
121
+ return sorted . map ( ( group ) => {
122
+ return {
123
+ breadcrumbs : group . breadcrumbs ,
124
+ blocks : group . entries . map ( ( entry ) => entry . block )
125
+ } ;
126
+ } ) ;
92
127
}
93
128
94
129
/**
95
130
* Get a block with details by its href
96
131
*/
97
132
export function lookup ( href : string ) {
98
- return map . get ( href ) ;
133
+ return map . get ( href ) ! ;
99
134
}
0 commit comments