@@ -87,7 +87,57 @@ export function matchesMetadataKeys(
8787 keys : string [ ] ,
8888) : boolean {
8989 if ( ! metadata || metadata . length === 0 || keys . length === 0 ) return false ;
90- return keys . every ( ( key ) => metadata . some ( ( m ) => m . name . toLowerCase ( ) . includes ( key ) ) ) ;
90+ return keys . every ( ( key ) =>
91+ metadata . some (
92+ ( m ) =>
93+ m . name . toLowerCase ( ) . includes ( key ) ||
94+ ( m . value != null && m . value . toLowerCase ( ) . includes ( key ) ) ,
95+ ) ,
96+ ) ;
97+ }
98+
99+ interface HasNameAndMetadata {
100+ name : string ;
101+ metadata ?: api . SchemaMetadataEntry [ ] ;
102+ }
103+
104+ export function filterItems < T extends HasNameAndMetadata > (
105+ items : T [ ] ,
106+ parsed : ParsedSearch ,
107+ declarationName : string ,
108+ collapseNonMatching : boolean ,
109+ extraMatch ?: ( item : T ) => boolean ,
110+ ) : { visible : T [ ] ; highlighted : Set < T > ; hiddenCount : number } {
111+ const { nameWords, metadataKeys } = parsed ;
112+ // Words not already matched by the declaration name must match at the field level
113+ const declLower = declarationName . toLowerCase ( ) ;
114+ const remainingWords = nameWords . filter ( ( w ) => ! declLower . includes ( w ) ) ;
115+
116+ function isMatch ( item : T ) : boolean {
117+ return (
118+ ( remainingWords . length === 0 ||
119+ matchesWords ( item . name , remainingWords ) ||
120+ matchesMetadataKeys ( item . metadata , remainingWords ) ) &&
121+ ( metadataKeys . length === 0 || matchesMetadataKeys ( item . metadata , metadataKeys ) ) &&
122+ ( extraMatch == null || extraMatch ( item ) )
123+ ) ;
124+ }
125+
126+ const isSearching = nameWords . length > 0 || metadataKeys . length > 0 || parsed . offsets . size > 0 ;
127+
128+ if ( ! collapseNonMatching ) {
129+ return {
130+ visible : items ,
131+ highlighted : isSearching ? new Set ( items . filter ( isMatch ) ) : new Set ( ) ,
132+ hiddenCount : 0 ,
133+ } ;
134+ }
135+ const matching = items . filter ( isMatch ) ;
136+ return {
137+ visible : matching ,
138+ highlighted : new Set ( matching ) ,
139+ hiddenCount : items . length - matching . length ,
140+ } ;
91141}
92142
93143function doSearch ( declarations : api . Declaration [ ] , parsed : ParsedSearch ) : api . Declaration [ ] {
@@ -99,53 +149,61 @@ function doSearch(declarations: api.Declaration[], parsed: ParsedSearch): api.De
99149 return moduleWords . some ( ( w ) => module . includes ( w ) ) ;
100150 }
101151
102- function matchesName ( name : string ) : boolean {
103- const lower = name . toLowerCase ( ) ;
104- return nameWords . every ( ( word ) => lower . includes ( word ) ) ;
105- }
152+ function matchesNameWords ( declaration : api . Declaration ) : boolean {
153+ function wordMatchesScope (
154+ word : string ,
155+ name : string ,
156+ metadata ?: api . SchemaMetadataEntry [ ] ,
157+ ) : boolean {
158+ return (
159+ name . includes ( word ) ||
160+ ( metadata ?. some (
161+ ( m ) =>
162+ m . name . toLowerCase ( ) . includes ( word ) ||
163+ ( m . value != null && m . value . toLowerCase ( ) . includes ( word ) ) ,
164+ ) ??
165+ false )
166+ ) ;
167+ }
106168
107- function matchesOffset ( declaration : api . Declaration ) : boolean {
108- if ( declaration . kind !== "class" ) return false ;
109- return declaration . fields . some ( ( f ) => offsetSet . has ( f . offset ) ) ;
169+ const declLower = declaration . name . toLowerCase ( ) ;
170+ let items : { name : string ; metadata ?: api . SchemaMetadataEntry [ ] } [ ] = [ ] ;
171+ if ( declaration . kind === "class" ) items = declaration . fields ;
172+ else if ( declaration . kind === "enum" ) items = declaration . members ;
173+
174+ return nameWords . every (
175+ ( word ) =>
176+ wordMatchesScope ( word , declLower , declaration . metadata ) ||
177+ items . some ( ( item ) => wordMatchesScope ( word , item . name . toLowerCase ( ) , item . metadata ) ) ,
178+ ) ;
110179 }
111180
112181 function matchesMetadata ( declaration : api . Declaration ) : boolean {
113182 if ( matchesMetadataKeys ( declaration . metadata , metadataKeys ) ) return true ;
114- if ( declaration . kind === "class" ) {
183+ if ( declaration . kind === "class" )
115184 return declaration . fields . some ( ( f ) => matchesMetadataKeys ( f . metadata , metadataKeys ) ) ;
116- }
117- if ( declaration . kind === "enum" ) {
185+ if ( declaration . kind === "enum" )
118186 return declaration . members . some ( ( m ) => matchesMetadataKeys ( m . metadata , metadataKeys ) ) ;
119- }
120187 return false ;
121188 }
122189
190+ function matchesOffset ( declaration : api . Declaration ) : boolean {
191+ if ( declaration . kind !== "class" ) return false ;
192+ return declaration . fields . some ( ( f ) => offsetSet . has ( f . offset ) ) ;
193+ }
194+
123195 const hasNameFilter = nameWords . length > 0 ;
124196 const hasOffsetFilter = offsetSet . size > 0 ;
125197 const hasMetadataFilter = metadataKeys . length > 0 ;
126198
127199 return declarations . filter ( ( declaration ) => {
128200 if ( ! filterModule ( declaration ) ) return false ;
129201
130- let nameMatch = false ;
131- if ( hasNameFilter ) {
132- nameMatch =
133- matchesName ( declaration . name ) ||
134- ( declaration . kind === "class" && declaration . fields . some ( ( f ) => matchesName ( f . name ) ) ) ||
135- ( declaration . kind === "enum" && declaration . members . some ( ( m ) => matchesName ( m . name ) ) ) ;
136- }
137-
138- const offsetMatch = hasOffsetFilter && matchesOffset ( declaration ) ;
139- const metadataMatch = hasMetadataFilter && matchesMetadata ( declaration ) ;
140-
141- // AND all active filters together
142- const filters : boolean [ ] = [ ] ;
143- if ( hasNameFilter ) filters . push ( nameMatch ) ;
144- if ( hasOffsetFilter ) filters . push ( offsetMatch ) ;
145- if ( hasMetadataFilter ) filters . push ( metadataMatch ) ;
202+ const nameMatch = ! hasNameFilter || matchesNameWords ( declaration ) ;
203+ const metadataMatch = ! hasMetadataFilter || matchesMetadata ( declaration ) ;
204+ const offsetMatch = ! hasOffsetFilter || matchesOffset ( declaration ) ;
146205
147- if ( filters . length > 0 ) return filters . every ( Boolean ) ;
148- // Module-only filter: already passed filterModule() above
149- return moduleWords . length > 0 ;
206+ if ( ! hasNameFilter && ! hasOffsetFilter && ! hasMetadataFilter ) return moduleWords . length > 0 ;
207+ return nameMatch && metadataMatch && offsetMatch ;
150208 } ) ;
151209}
0 commit comments