@@ -23,6 +23,8 @@ interface RawIndexItem {
2323 type : SearchResult [ "type" ] ;
2424 keywords ?: string [ ] ;
2525 body ?: string ;
26+ headings ?: string [ ] ;
27+ code ?: string [ ] ;
2628}
2729
2830interface GitTreeItem {
@@ -47,6 +49,8 @@ function ensureOrama() {
4749 title : "string" ,
4850 excerpt : "string" ,
4951 body : "string" ,
52+ headings : "string" ,
53+ code : "string" ,
5054 type : "string" ,
5155 url : "string" ,
5256 label : "string" ,
@@ -89,6 +93,9 @@ async function buildIndex(): Promise<SearchResult[]> {
8993 console . warn ( "Failed to build docs index:" , err ) ;
9094 }
9195
96+ const mdHeadingRegex = / ^ # { 1 , 6 } \s + ( .* ) $ / gm;
97+ const codeFenceRegex = / ` ` ` (?: [ a - z A - Z 0 - 9 _ - ] + ) ? \n ( [ \s \S ] * ?) \n ` ` ` / g;
98+
9299 try {
93100 for await ( const entry of Deno . readDir ( "static/content/blog" ) ) {
94101 if ( ! entry . isFile ) continue ;
@@ -112,8 +119,45 @@ async function buildIndex(): Promise<SearchResult[]> {
112119 console . warn ( "Failed to read blog post:" , entry . name , e ) ;
113120 }
114121 }
115- } catch ( _e ) {
116- // no blog dir - ignore
122+ } catch {
123+ // ignore
124+ }
125+ try {
126+ for await ( const file of Deno . readDir ( "content/docs" ) ) {
127+ if ( ! file . isFile || ! file . name . endsWith ( ".md" ) ) continue ;
128+ try {
129+ const path = `content/docs/${ file . name } ` ;
130+ const text = await Deno . readTextFile ( path ) ;
131+ const titleMatch = text . match ( / ^ # \s + ( .* ) $ / m) ;
132+ const title = titleMatch
133+ ? titleMatch [ 1 ] . trim ( )
134+ : file . name . replace ( / \. m d $ / , "" ) ;
135+ const url = `/docs/${ file . name . replace ( / \. m d $ / , "" ) } ` ;
136+ const excerpt = text . split ( / \n \n / ) [ 1 ] || text . slice ( 0 , 200 ) ;
137+ const headings : string [ ] = [ ] ;
138+ const code : string [ ] = [ ] ;
139+ let m ;
140+ while ( ( m = mdHeadingRegex . exec ( text ) ) !== null ) {
141+ headings . push ( m [ 1 ] . trim ( ) ) ;
142+ }
143+ while ( ( m = codeFenceRegex . exec ( text ) ) !== null ) {
144+ code . push ( m [ 1 ] . trim ( ) ) ;
145+ }
146+ items . push ( {
147+ title,
148+ url,
149+ excerpt,
150+ type : "doc" ,
151+ body : text ,
152+ headings,
153+ code,
154+ } ) ;
155+ } catch {
156+ // ignore
157+ }
158+ }
159+ } catch {
160+ // ignore
117161 }
118162 try {
119163 const OWNER = "tryandromeda" ;
@@ -223,6 +267,8 @@ async function buildIndex(): Promise<SearchResult[]> {
223267 title : it . title ,
224268 excerpt : it . excerpt || "" ,
225269 body : it . body || "" ,
270+ headings : ( it . headings || [ ] ) . join ( " " ) ,
271+ code : ( it . code || [ ] ) . join ( " " ) ,
226272 type : it . type ,
227273 url : it . url ,
228274 label : ( ( ) => {
@@ -394,27 +440,81 @@ export const handler = {
394440 const hits =
395441 ( oramaRes as unknown as { hits : Array < unknown > } ) . hits ;
396442 const mapped : SearchResult [ ] = hits . map ( ( h ) => {
397- const hit = h as unknown as {
398- id ?: string ;
399- score ?: number ;
400- document ?: Record < string , unknown > ;
401- } ;
402- const doc = hit . document || { } ;
403- const title = ( doc . title as string ) || ( doc . name as string ) ||
404- "" ;
405- const urlVal = ( doc . url as string ) || hit . id || "" ;
406- const excerpt = ( doc . excerpt as string ) || "" ;
407- const typeVal = ( doc . type as string ) ||
408- ( doc . label as string ) || "doc" ;
409- const labelVal = ( doc . label as string ) || "Docs" ;
443+ const hitObj = h as unknown as Record < string , unknown > ;
444+ const doc = ( hitObj . document as Record < string , unknown > ) ||
445+ { } ;
446+
447+ const title = typeof doc . title === "string"
448+ ? doc . title
449+ : ( typeof doc . name === "string" ? doc . name : "" ) ;
450+ const urlVal = typeof doc . url === "string"
451+ ? doc . url
452+ : ( typeof hitObj . id === "string" ? hitObj . id : "" ) ;
453+ const excerpt = typeof doc . excerpt === "string"
454+ ? doc . excerpt
455+ : "" ;
456+ const typeVal = typeof doc . type === "string"
457+ ? doc . type
458+ : ( typeof doc . label === "string" ? doc . label : "doc" ) ;
459+ const labelVal = typeof doc . label === "string"
460+ ? doc . label
461+ : "Docs" ;
462+
463+ const highlights : string [ ] = [ ] ;
464+ const matches = Array . isArray ( hitObj . matches )
465+ ? hitObj . matches as unknown [ ]
466+ : undefined ;
467+ if ( matches ) {
468+ for ( const m of matches ) {
469+ if ( ! m || typeof m !== "object" ) continue ;
470+ const mo = m as Record < string , unknown > ;
471+ const frag = typeof mo . match === "string"
472+ ? mo . match
473+ : ( typeof mo . fragment === "string"
474+ ? mo . fragment
475+ : undefined ) ;
476+ if ( typeof frag === "string" ) {
477+ highlights . push ( frag . slice ( 0 , 300 ) ) ;
478+ continue ;
479+ }
480+ if ( typeof mo . field === "string" ) {
481+ const f = mo . field ;
482+ const fv = doc [ f ] ;
483+ if ( typeof fv === "string" ) {
484+ highlights . push ( fv . slice ( 0 , 300 ) ) ;
485+ }
486+ }
487+ }
488+ } else if ( Array . isArray ( hitObj . highlights ) ) {
489+ const hh = hitObj . highlights as unknown [ ] ;
490+ for ( const item of hh . slice ( 0 , 3 ) ) {
491+ if ( typeof item === "string" ) highlights . push ( item ) ;
492+ }
493+ } else {
494+ const raw = rawIndexCache &&
495+ rawIndexCache . find ( ( r ) => r . url === urlVal ) ;
496+ if ( raw && raw . body ) {
497+ const bodyLower = raw . body . toLowerCase ( ) ;
498+ const qLower = q . toLowerCase ( ) ;
499+ const pos = bodyLower . indexOf ( qLower ) ;
500+ if ( pos >= 0 ) {
501+ highlights . push ( makeSnippet ( raw . body , pos , 80 ) ) ;
502+ } else if ( raw . headings && raw . headings . length ) {
503+ highlights . push ( raw . headings . slice ( 0 , 3 ) . join ( " — " ) ) ;
504+ }
505+ }
506+ }
507+
410508 return {
411509 title,
412510 url : urlVal ,
413511 excerpt,
414512 type : ( typeVal as string ) as SearchResult [ "type" ] ,
415513 label : labelVal ,
416- score : typeof hit . score === "number" ? hit . score : 0 ,
417- highlights : [ ] ,
514+ score : typeof hitObj . score === "number"
515+ ? ( hitObj . score as number )
516+ : 0 ,
517+ highlights,
418518 } ;
419519 } ) ;
420520
0 commit comments