Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
6eb06b24
Commit
6eb06b24
authored
Mar 13, 2023
by
Alejandro Celaya
Committed by
Alejandro Celaya
Mar 15, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Migrate view-filter to TypeScript
parent
cf33fdc3
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
47 additions
and
61 deletions
+47
-61
view-filter.ts
src/sidebar/helpers/view-filter.ts
+47
-61
No files found.
src/sidebar/helpers/view-filter.
j
s
→
src/sidebar/helpers/view-filter.
t
s
View file @
6eb06b24
/**
* @typedef {import('../../types/api').Annotation} Annotation
* @typedef {import('../util/search-filter').Facet} Facet
*/
import
type
{
Annotation
}
from
'../../types/api'
;
import
type
{
Facet
}
from
'../util/search-filter'
;
import
*
as
unicodeUtils
from
'../util/unicode'
;
import
{
quote
}
from
'./annotation-metadata'
;
/**
* @typedef Filter
* @prop {(ann: Annotation) => boolean} matches
*/
type
Filter
=
{
matches
:
(
ann
:
Annotation
)
=>
boolean
;
};
/**
* A Matcher specifies how to test whether an annotation matches a query term
* for a specific field.
*
* @template [T=string] - Type of parsed query terms and field values
* @typedef Matcher
* @prop {(ann: Annotation) => T[]} fieldValues - Extract the field values to be
* matched against a query term
* @prop {(value: T, term: T) => boolean} matches - Test whether a query term
* matches a field value. Both value and term will have been normalized using
* `normalize`.
* @prop {(val: T) => T} normalize - Normalize a parsed term or field value for
* comparison
*/
type
Matcher
<
T
=
string
>
=
{
/** Extract the field values to be matched against a query term */
fieldValues
:
(
ann
:
Annotation
)
=>
T
[];
/**
* Test whether a query term matches a field value. Both value and term will
* have been normalized using `normalize`.
*/
matches
:
(
value
:
T
,
term
:
T
)
=>
boolean
;
/** Normalize a parsed term or field value for comparison */
normalize
:
(
val
:
T
)
=>
T
;
};
/**
* Normalize a string query term or field value.
*
* @param {string} val
*/
function
normalizeStr
(
val
)
{
function
normalizeStr
(
val
:
string
):
string
{
return
unicodeUtils
.
fold
(
unicodeUtils
.
normalize
(
val
)).
toLowerCase
();
}
...
...
@@ -40,22 +38,19 @@ function normalizeStr(val) {
* @template TermType
* @implements {Filter}
*/
class
TermFilter
{
/**
* @param {TermType} term
* @param {Matcher<TermType>} matcher
*/
constructor
(
term
,
matcher
)
{
class
TermFilter
<
TermType
extends
string
>
implements
Filter
{
public
term
:
TermType
;
public
matcher
:
Matcher
<
TermType
>
;
constructor
(
term
:
TermType
,
matcher
:
Matcher
<
TermType
>
)
{
this
.
term
=
matcher
.
normalize
(
term
);
this
.
matcher
=
matcher
;
}
/**
* Return true if an annotation matches this filter.
*
* @param {Annotation} ann
*/
matches
(
ann
)
{
matches
(
ann
:
Annotation
):
boolean
{
const
matcher
=
this
.
matcher
;
return
matcher
.
fieldValues
(
ann
)
...
...
@@ -65,25 +60,24 @@ class TermFilter {
/**
* Filter that combines other filters using AND or OR combinators.
*
* @implements {Filter}
*/
class
BooleanOpFilter
{
class
BooleanOpFilter
implements
Filter
{
public
operator
:
'and'
|
'or'
;
public
filters
:
Filter
[];
/**
* @param
{'and'|'or'}
op - Boolean operator
* @param
{Filter[]}
filters - Array of filters to test against
* @param op - Boolean operator
* @param filters - Array of filters to test against
*/
constructor
(
op
,
filters
)
{
constructor
(
op
:
'and'
|
'or'
,
filters
:
Filter
[]
)
{
this
.
operator
=
op
;
this
.
filters
=
filters
;
}
/**
* Return true if an annotation matches this filter.
*
* @param {Annotation} ann
*/
matches
(
ann
)
{
matches
(
ann
:
Annotation
):
boolean
{
if
(
this
.
operator
===
'and'
)
{
return
this
.
filters
.
every
(
filter
=>
filter
.
matches
(
ann
));
}
else
{
...
...
@@ -95,11 +89,10 @@ class BooleanOpFilter {
/**
* Create a matcher that tests whether a query term appears anywhere in a
* string field value.
*
* @param {(ann: Annotation) => string[]} fieldValues
* @return {Matcher}
*/
function
stringFieldMatcher
(
fieldValues
)
{
function
stringFieldMatcher
(
fieldValues
:
(
ann
:
Annotation
)
=>
string
[]
):
Matcher
{
return
{
fieldValues
,
matches
:
(
value
,
term
)
=>
value
.
includes
(
term
),
...
...
@@ -109,20 +102,17 @@ function stringFieldMatcher(fieldValues) {
/**
* Map of field name (from a parsed query) to matcher for that field.
*
* @type {Record<string, Matcher|Matcher<number>>}
*/
const
fieldMatchers
=
{
const
fieldMatchers
:
Record
<
string
,
Matcher
|
Matcher
<
number
>>
=
{
quote
:
stringFieldMatcher
(
ann
=>
[
quote
(
ann
)
??
''
]),
/** @type {Matcher<number>} */
since
:
{
fieldValues
:
ann
=>
[
new
Date
(
ann
.
updated
).
valueOf
()],
matches
:
(
updatedTime
,
age
)
=>
{
matches
:
(
updatedTime
:
number
,
age
:
number
)
=>
{
const
delta
=
(
Date
.
now
()
-
updatedTime
)
/
1000
;
return
delta
<=
age
;
},
normalize
:
timestamp
=>
timestamp
,
normalize
:
(
timestamp
:
number
)
=>
timestamp
,
},
tag
:
stringFieldMatcher
(
ann
=>
ann
.
tags
),
...
...
@@ -137,22 +127,18 @@ const fieldMatchers = {
/**
* Filter a set of annotations against a parsed query.
*
* @param {Annotation[]} annotations
* @param {Record<string, Facet>} filters
* @return {string[]} IDs of matching annotations.
*/
export
function
filterAnnotations
(
annotations
,
filters
)
{
/**
* @template TermType
* @param {string} field
* @param {TermType} term
* @return IDs of matching annotations.
*/
const
makeTermFilter
=
(
field
,
term
)
=>
export
function
filterAnnotations
(
annotations
:
Annotation
[],
filters
:
Record
<
string
,
Facet
>
):
string
[]
{
const
makeTermFilter
=
<
TermType
>
(
field
:
string
,
term
:
TermType
)
=>
new
TermFilter
(
term
,
// Suppress error about potential mismatch of query term type
// and what the matcher expects. We assume these match up.
/** @type {Matcher<any>} */
(
fieldMatchers
[
field
])
fieldMatchers
[
field
]
as
Matcher
<
any
>
);
// Convert the input filter object into a filter tree, expanding "any"
...
...
@@ -182,5 +168,5 @@ export function filterAnnotations(annotations, filters) {
.
filter
(
ann
=>
{
return
ann
.
id
&&
rootFilter
.
matches
(
ann
);
})
.
map
(
ann
=>
/** @type {string} */
(
ann
.
id
)
);
.
map
(
ann
=>
ann
.
id
as
string
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment