1- import { assertNever } from "../assert"
21import type { IndexCollectionItemEntry , IndexEntry , IndexNodeEntry } from "../indexer/types"
32import { findRanges } from "./ranges"
4- import { type Filter , FilterType , type Result , ResultType , type RootNodesFilter , type TextFilter } from "./types"
3+ import { type Filter , type Matcher , type Result , ResultType , type RootNodesFilter , type TextMatcher } from "./types"
54
65/** Execute a list of filters on a list of entries and return the results. */
7- export function executeFilters ( filters : readonly Filter [ ] , index : readonly IndexEntry [ ] ) : Result [ ] {
6+ export function executeFilters (
7+ /** The matchers to execute on the index. */
8+ matchers : readonly Matcher [ ] ,
9+ /** A filter to narrow down the results. */
10+ filters : readonly Filter [ ] ,
11+ /** The index to search on */
12+ index : readonly IndexEntry [ ]
13+ ) : Result [ ] {
814 const results : Result [ ] = [ ]
915
1016 for ( const entry of index ) {
1117 let include = true
1218 let result : Result | undefined
1319
14- for ( const filter of filters ) {
15- const filterResult = executeFilter ( filter , entry )
20+ for ( const matcher of matchers ) {
21+ const matchResult = executeMatcher ( matcher , entry )
1622
17- if ( typeof filterResult !== "boolean" ) {
18- result = filterResult
19- }
20-
21- if ( filterResult === false ) {
23+ if ( matchResult === undefined ) {
2224 include = false
2325 break
2426 }
27+
28+ if ( filters . some ( filter => executeFilter ( filter , matchResult ) ) ) {
29+ result = matchResult
30+ }
2531 }
2632
2733 if ( include && result ) {
@@ -32,30 +38,21 @@ export function executeFilters(filters: readonly Filter[], index: readonly Index
3238 return results
3339}
3440
35- /** Execute a filter on a single entry and routes to the appropriate filter function. */
36- function executeFilter ( filter : Filter , entry : IndexEntry ) : FilterResult {
37- switch ( filter . type ) {
38- case FilterType . Text :
39- if ( entry . type === "CollectionItem" ) {
40- return executeTextFilterForCollectionItems ( filter , entry )
41- }
42- return executeTextFilterForNodes ( filter , entry )
43- case FilterType . RootNodes :
44- return executeRootNodesFilter ( filter , entry )
45- default :
46- assertNever ( filter )
41+ /** Execute a matcher on a single entry and routes to the appropriate matcher function. */
42+ function executeMatcher ( matcher : Matcher , entry : IndexEntry ) : Result | undefined {
43+ // When more matchers are added, we can add more matcher functions here and use this as a router
44+ if ( entry . type === "CollectionItem" ) {
45+ return executeTextMatcherForCollectionItems ( matcher , entry )
4746 }
47+ return executeTextMatcherForNodes ( matcher , entry )
4848}
4949
50- /** Internal type for filter execution. When result is `false`, the entry is excluded. When result is `true` or `Result`, the entry is included. */
51- type FilterResult = Result | boolean
52-
53- function executeTextFilterForNodes ( filter : TextFilter , entry : IndexNodeEntry ) : FilterResult {
50+ function executeTextMatcherForNodes ( matcher : TextMatcher , entry : IndexNodeEntry ) : Result | undefined {
5451 const text = entry . text ?? entry . name
55- if ( ! text ) return false
52+ if ( ! text ) return undefined
5653
57- const ranges = findRanges ( text , filter . query , filter . caseSensitive )
58- if ( ! ranges . length ) return false
54+ const ranges = findRanges ( text , matcher . query , matcher . caseSensitive )
55+ if ( ! ranges . length ) return undefined
5956
6057 return {
6158 id : entry . id ,
@@ -66,11 +63,14 @@ function executeTextFilterForNodes(filter: TextFilter, entry: IndexNodeEntry): F
6663 }
6764}
6865
69- function executeTextFilterForCollectionItems ( filter : TextFilter , entry : IndexCollectionItemEntry ) : FilterResult {
66+ function executeTextMatcherForCollectionItems (
67+ matcher : TextMatcher ,
68+ entry : IndexCollectionItemEntry
69+ ) : Result | undefined {
7070 // FIXME: This only returns the first matching field
7171 // Instead of having multiple fields in the index, we should have a single entry per field in the index
7272 for ( const [ field , text ] of Object . entries ( entry . fields ) ) {
73- const ranges = findRanges ( text , filter . query , filter . caseSensitive )
73+ const ranges = findRanges ( text , matcher . query , matcher . caseSensitive )
7474 if ( ranges . length ) {
7575 return {
7676 id : `${ entry . id } -${ field } ` ,
@@ -83,9 +83,15 @@ function executeTextFilterForCollectionItems(filter: TextFilter, entry: IndexCol
8383 }
8484 }
8585
86- return false
86+ return undefined
87+ }
88+
89+ /** Execute a filter on a result and return true if the result should be included. */
90+ function executeFilter ( filter : Filter , result : Result ) : boolean {
91+ // When more filters are added, we can add more filter functions here and use this as a router
92+ return executeRootNodesFilter ( filter , result )
8793}
8894
89- function executeRootNodesFilter ( filter : RootNodesFilter , entry : IndexEntry ) : FilterResult {
90- return filter . rootNodes . includes ( entry . rootNodeType )
95+ function executeRootNodesFilter ( filter : RootNodesFilter , result : Result ) : boolean {
96+ return filter . rootNodes . includes ( result . entry . rootNodeType )
9197}
0 commit comments