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
Hide 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
/**
import
type
{
Annotation
}
from
'../../types/api'
;
* @typedef {import('../../types/api').Annotation} Annotation
import
type
{
Facet
}
from
'../util/search-filter'
;
* @typedef {import('../util/search-filter').Facet} Facet
*/
import
*
as
unicodeUtils
from
'../util/unicode'
;
import
*
as
unicodeUtils
from
'../util/unicode'
;
import
{
quote
}
from
'./annotation-metadata'
;
import
{
quote
}
from
'./annotation-metadata'
;
/**
type
Filter
=
{
* @typedef Filter
matches
:
(
ann
:
Annotation
)
=>
boolean
;
* @prop {(ann: Annotation) => boolean} matches
};
*/
/**
/**
* A Matcher specifies how to test whether an annotation matches a query term
* A Matcher specifies how to test whether an annotation matches a query term
* for a specific field.
* 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.
* 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
();
return
unicodeUtils
.
fold
(
unicodeUtils
.
normalize
(
val
)).
toLowerCase
();
}
}
...
@@ -40,22 +38,19 @@ function normalizeStr(val) {
...
@@ -40,22 +38,19 @@ function normalizeStr(val) {
* @template TermType
* @template TermType
* @implements {Filter}
* @implements {Filter}
*/
*/
class
TermFilter
{
class
TermFilter
<
TermType
extends
string
>
implements
Filter
{
/**
public
term
:
TermType
;
* @param {TermType} term
public
matcher
:
Matcher
<
TermType
>
;
* @param {Matcher<TermType>} matcher
*/
constructor
(
term
:
TermType
,
matcher
:
Matcher
<
TermType
>
)
{
constructor
(
term
,
matcher
)
{
this
.
term
=
matcher
.
normalize
(
term
);
this
.
term
=
matcher
.
normalize
(
term
);
this
.
matcher
=
matcher
;
this
.
matcher
=
matcher
;
}
}
/**
/**
* Return true if an annotation matches this filter.
* Return true if an annotation matches this filter.
*
* @param {Annotation} ann
*/
*/
matches
(
ann
)
{
matches
(
ann
:
Annotation
):
boolean
{
const
matcher
=
this
.
matcher
;
const
matcher
=
this
.
matcher
;
return
matcher
return
matcher
.
fieldValues
(
ann
)
.
fieldValues
(
ann
)
...
@@ -65,25 +60,24 @@ class TermFilter {
...
@@ -65,25 +60,24 @@ class TermFilter {
/**
/**
* Filter that combines other filters using AND or OR combinators.
* 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 op - Boolean operator
* @param
{Filter[]}
filters - Array of filters to test against
* @param filters - Array of filters to test against
*/
*/
constructor
(
op
,
filters
)
{
constructor
(
op
:
'and'
|
'or'
,
filters
:
Filter
[]
)
{
this
.
operator
=
op
;
this
.
operator
=
op
;
this
.
filters
=
filters
;
this
.
filters
=
filters
;
}
}
/**
/**
* Return true if an annotation matches this filter.
* Return true if an annotation matches this filter.
*
* @param {Annotation} ann
*/
*/
matches
(
ann
)
{
matches
(
ann
:
Annotation
):
boolean
{
if
(
this
.
operator
===
'and'
)
{
if
(
this
.
operator
===
'and'
)
{
return
this
.
filters
.
every
(
filter
=>
filter
.
matches
(
ann
));
return
this
.
filters
.
every
(
filter
=>
filter
.
matches
(
ann
));
}
else
{
}
else
{
...
@@ -95,11 +89,10 @@ class BooleanOpFilter {
...
@@ -95,11 +89,10 @@ class BooleanOpFilter {
/**
/**
* Create a matcher that tests whether a query term appears anywhere in a
* Create a matcher that tests whether a query term appears anywhere in a
* string field value.
* string field value.
*
* @param {(ann: Annotation) => string[]} fieldValues
* @return {Matcher}
*/
*/
function
stringFieldMatcher
(
fieldValues
)
{
function
stringFieldMatcher
(
fieldValues
:
(
ann
:
Annotation
)
=>
string
[]
):
Matcher
{
return
{
return
{
fieldValues
,
fieldValues
,
matches
:
(
value
,
term
)
=>
value
.
includes
(
term
),
matches
:
(
value
,
term
)
=>
value
.
includes
(
term
),
...
@@ -109,20 +102,17 @@ function stringFieldMatcher(fieldValues) {
...
@@ -109,20 +102,17 @@ function stringFieldMatcher(fieldValues) {
/**
/**
* Map of field name (from a parsed query) to matcher for that field.
* 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
)
??
''
]),
quote
:
stringFieldMatcher
(
ann
=>
[
quote
(
ann
)
??
''
]),
/** @type {Matcher<number>} */
since
:
{
since
:
{
fieldValues
:
ann
=>
[
new
Date
(
ann
.
updated
).
valueOf
()],
fieldValues
:
ann
=>
[
new
Date
(
ann
.
updated
).
valueOf
()],
matches
:
(
updatedTime
,
age
)
=>
{
matches
:
(
updatedTime
:
number
,
age
:
number
)
=>
{
const
delta
=
(
Date
.
now
()
-
updatedTime
)
/
1000
;
const
delta
=
(
Date
.
now
()
-
updatedTime
)
/
1000
;
return
delta
<=
age
;
return
delta
<=
age
;
},
},
normalize
:
timestamp
=>
timestamp
,
normalize
:
(
timestamp
:
number
)
=>
timestamp
,
},
},
tag
:
stringFieldMatcher
(
ann
=>
ann
.
tags
),
tag
:
stringFieldMatcher
(
ann
=>
ann
.
tags
),
...
@@ -137,22 +127,18 @@ const fieldMatchers = {
...
@@ -137,22 +127,18 @@ const fieldMatchers = {
/**
/**
* Filter a set of annotations against a parsed query.
* Filter a set of annotations against a parsed query.
*
*
* @param {Annotation[]} annotations
* @return IDs of matching annotations.
* @param {Record<string, Facet>} filters
* @return {string[]} IDs of matching annotations.
*/
*/
export
function
filterAnnotations
(
annotations
,
filters
)
{
export
function
filterAnnotations
(
/**
annotations
:
Annotation
[],
* @template TermType
filters
:
Record
<
string
,
Facet
>
* @param {string} field
):
string
[]
{
* @param {TermType} term
const
makeTermFilter
=
<
TermType
>
(
field
:
string
,
term
:
TermType
)
=>
*/
const
makeTermFilter
=
(
field
,
term
)
=>
new
TermFilter
(
new
TermFilter
(
term
,
term
,
// Suppress error about potential mismatch of query term type
// Suppress error about potential mismatch of query term type
// and what the matcher expects. We assume these match up.
// 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"
// Convert the input filter object into a filter tree, expanding "any"
...
@@ -182,5 +168,5 @@ export function filterAnnotations(annotations, filters) {
...
@@ -182,5 +168,5 @@ export function filterAnnotations(annotations, filters) {
.
filter
(
ann
=>
{
.
filter
(
ann
=>
{
return
ann
.
id
&&
rootFilter
.
matches
(
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