123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- {
- const {TokenConverter, TermOperator, FilterType, config} = options;
- const tc = new TokenConverter({text, location, config});
- const opDefault = TermOperator.Default;
- }
- search
- = space:spaces terms:term* {
- return [space, ...terms.flat()];
- }
- term
- = (boolean_operator / paren_group / filter / free_text) spaces
- boolean_operator
- = (or_operator / and_operator) {
- return tc.tokenLogicBoolean(text().toUpperCase());
- }
- paren_group
- = open_paren spaces:spaces inner:term+ closed_paren {
- return tc.tokenLogicGroup([spaces, ...inner].flat());
- }
- free_text
- = free_text_quoted / free_text_unquoted
- free_text_unquoted
- = (!filter !boolean_operator (free_parens / [^()\n ]+) spaces)+ {
- return tc.tokenFreeText(text(), false);
- }
- free_text_quoted
- = value:quoted_value {
- return tc.tokenFreeText(value.value, true);
- }
- free_parens
- = open_paren free_text? closed_paren
- // All key:value filter types
- filter
- = date_filter
- / specific_date_filter
- / rel_date_filter
- / duration_filter
- / size_filter
- / boolean_filter
- / numeric_in_filter
- / numeric_filter
- / aggregate_duration_filter
- / aggregate_size_filter
- / aggregate_numeric_filter
- / aggregate_percentage_filter
- / aggregate_date_filter
- / aggregate_rel_date_filter
- / has_filter
- / is_filter
- / text_in_filter
- / text_filter
- // filter for dates
- date_filter
- = key:search_key sep op:operator value:iso_8601_date_format &{
- return tc.predicateFilter(FilterType.Date, key, value, op)
- } {
- return tc.tokenFilter(FilterType.Date, key, value, op, false);
- }
- // filter for exact dates
- specific_date_filter
- = key:search_key sep value:iso_8601_date_format &{
- return tc.predicateFilter(FilterType.SpecificDate, key)
- } {
- return tc.tokenFilter(FilterType.SpecificDate, key, value, opDefault, false);
- }
- // filter for relative dates
- rel_date_filter
- = key:search_key sep value:rel_date_format &{
- return tc.predicateFilter(FilterType.RelativeDate, key)
- } {
- return tc.tokenFilter(FilterType.RelativeDate, key, value, opDefault, false);
- }
- // filter for durations
- duration_filter
- = negation:negation? key:search_key sep op:operator? value:duration_format &{
- return tc.predicateFilter(FilterType.Duration, key)
- } {
- return tc.tokenFilter(FilterType.Duration, key, value, op, !!negation);
- }
- // filter for file size
- size_filter
- = negation:negation? key:search_key sep op:operator? value:size_format &{
- return tc.predicateFilter(FilterType.Size, key)
- } {
- return tc.tokenFilter(FilterType.Size, key, value, op, !!negation);
- }
- // boolean comparison filter
- boolean_filter
- = negation:negation? key:search_key sep value:boolean_value &{
- return tc.predicateFilter(FilterType.Boolean, key)
- } {
- return tc.tokenFilter(FilterType.Boolean, key, value, opDefault, !!negation);
- }
- // numeric in filter
- numeric_in_filter
- = negation:negation? key:search_key sep value:numeric_in_list &{
- return tc.predicateFilter(FilterType.NumericIn, key)
- } {
- return tc.tokenFilter(FilterType.NumericIn, key, value, opDefault, !!negation);
- }
- // numeric comparison filter
- numeric_filter
- = negation:negation? key:search_key sep op:operator? value:numeric_value &{
- return tc.predicateFilter(FilterType.Numeric, key)
- } {
- return tc.tokenFilter(FilterType.Numeric, key, value, op, !!negation);
- }
- // aggregate duration filter
- aggregate_duration_filter
- = negation:negation? key:aggregate_key sep op:operator? value:duration_format &{
- return tc.predicateFilter(FilterType.AggregateDuration, key)
- } {
- return tc.tokenFilter(FilterType.AggregateDuration, key, value, op, !!negation);
- }
- // aggregate file size filter
- aggregate_size_filter
- = negation:negation? key:aggregate_key sep op:operator? value:size_format &{
- return tc.predicateFilter(FilterType.AggregateSize, key)
- } {
- return tc.tokenFilter(FilterType.AggregateSize, key, value, op, !!negation);
- }
- // aggregate percentage filter
- aggregate_percentage_filter
- = negation:negation? key:aggregate_key sep op:operator? value:percentage_format &{
- return tc.predicateFilter(FilterType.AggregatePercentage, key)
- } {
- return tc.tokenFilter(FilterType.AggregatePercentage, key, value, op, !!negation);
- }
- // aggregate numeric filter
- aggregate_numeric_filter
- = negation:negation? key:aggregate_key sep op:operator? value:numeric_value &{
- return tc.predicateFilter(FilterType.AggregateNumeric, key)
- } {
- return tc.tokenFilter(FilterType.AggregateNumeric, key, value, op, !!negation);
- }
- // aggregate date filter
- aggregate_date_filter
- = negation:negation? key:aggregate_key sep op:operator? value:iso_8601_date_format &{
- return tc.predicateFilter(FilterType.AggregateDate, key)
- } {
- return tc.tokenFilter(FilterType.AggregateDate, key, value, op, !!negation);
- }
- // filter for relative dates
- aggregate_rel_date_filter
- = negation:negation? key:aggregate_key sep op:operator? value:rel_date_format &{
- return tc.predicateFilter(FilterType.AggregateRelativeDate, key)
- } {
- return tc.tokenFilter(FilterType.AggregateRelativeDate, key, value, op, !!negation);
- }
- // has filter for not null type checks
- has_filter
- = negation:negation? &"has:" key:search_key sep value:(search_key / search_value) &{
- return tc.predicateFilter(FilterType.Has, key)
- } {
- return tc.tokenFilter(FilterType.Has, key, value, opDefault, !!negation);
- }
- // is filter. Specific to issue search
- is_filter
- = negation:negation? &"is:" key:search_key sep value:search_value &{
- return tc.predicateFilter(FilterType.Is, key)
- } {
- return tc.tokenFilter(FilterType.Is, key, value, opDefault, !!negation);
- }
- // in filter key:[val1, val2]
- text_in_filter
- = negation:negation? key:text_key sep value:text_in_list &{
- return tc.predicateFilter(FilterType.TextIn, key)
- } {
- return tc.tokenFilter(FilterType.TextIn, key, value, opDefault, !!negation);
- }
- // standard key:val filter
- //
- // The text_filter is a little special since it may not have an operator
- // depending on the configuration of the search parser, thus we have a
- // predicate for the operator.
- text_filter
- = negation:negation?
- key:text_key
- sep
- op:(operator &{ return tc.predicateTextOperator(key); })?
- value:search_value &{
- return tc.predicateFilter(FilterType.Text, key)
- } {
- return tc.tokenFilter(FilterType.Text, key, value, op ? op[0] : opDefault, !!negation);
- }
- // Filter keys
- key
- = value:[a-zA-Z0-9_.-]+ {
- return tc.tokenKeySimple(value.join(''), false);
- }
- quoted_key
- = '"' key:[a-zA-Z0-9_.:-]+ '"' {
- return tc.tokenKeySimple(key.join(''), true);
- }
- explicit_tag_key
- = prefix:"tags" open_bracket key:search_key closed_bracket {
- return tc.tokenKeyExplicitTag(prefix, key);
- }
- aggregate_key
- = name:key open_paren s1:spaces args:function_args? s2:spaces closed_paren {
- return tc.tokenKeyAggregate(name, args, s1, s2);
- }
- function_args
- = arg1:aggregate_param
- args:(spaces comma spaces !comma aggregate_param?)* {
- return tc.tokenKeyAggregateArgs(arg1, args);
- }
- aggregate_param
- = quoted_aggregate_param / raw_aggregate_param
- raw_aggregate_param
- = param:[^()\t\n, \"]+ {
- return tc.tokenKeyAggregateParam(param.join(''), false);
- }
- quoted_aggregate_param
- = '"' param:('\\"' / [^\t\n\"])* '"' {
- return tc.tokenKeyAggregateParam(`"${param.join('')}"`, true);
- }
- search_key
- = key / quoted_key
- text_key
- = explicit_tag_key / search_key
- // Filter values
- value
- = value:[^()\t\n ]* {
- return tc.tokenValueText(value.join(''), false);
- }
- quoted_value
- = '"' value:('\\"' / [^"])* '"' {
- return tc.tokenValueText(value.join(''), true);
- }
- in_value
- = (&in_value_termination in_value_char)+ {
- return tc.tokenValueText(text(), false);
- }
- text_in_value
- = quoted_value / in_value
- search_value
- = quoted_value / value
- numeric_value
- = value:("-"? numeric) unit:[kmb]? &(end_value / comma / closed_bracket) {
- return tc.tokenValueNumber(value.join(''), unit);
- }
- boolean_value
- = value:("true"i / "1" / "false"i / "0") &end_value {
- return tc.tokenValueBoolean(value);
- }
- text_in_list
- = open_bracket
- item1:text_in_value
- items:(spaces comma spaces !comma text_in_value?)*
- closed_bracket
- &end_value {
- return tc.tokenValueTextList(item1, items);
- }
- numeric_in_list
- = open_bracket
- item1:numeric_value
- items:(spaces comma spaces !comma numeric_value?)*
- closed_bracket
- &end_value {
- return tc.tokenValueNumberList(item1, items);
- }
- // See: https://stackoverflow.com/a/39617181/790169
- in_value_termination
- = in_value_char (!in_value_end in_value_char)* in_value_end
- in_value_char
- = [^(), ]
- in_value_end
- = closed_bracket / (spaces comma)
- // Format values
- // XXX: Since pegjs does not support regex there is no easy way to repeat
- // groups n times. So we have some dumb tokens here to handle that. We don't do
- // this in the backend grammar since we just use regex there.
- num2 = [0-9] [0-9]
- num4 = [0-9] [0-9] [0-9] [0-9]
- date_format = num4 "-" num2 "-" num2
- time_format = "T" num2 ":" num2 ":" num2 ("." ms_format)?
- ms_format = [0-9] [0-9]? [0-9]? [0-9]? [0-9]? [0-9]?
- tz_format = [+-] num2 ":" num2
- iso_8601_date_format
- = date_format time_format? ("Z" / tz_format)? &end_value {
- return tc.tokenValueIso8601Date(text());
- }
- rel_date_format
- = sign:[+-] value:[0-9]+ unit:[wdhm] &end_value {
- return tc.tokenValueRelativeDate(value.join(''), sign, unit);
- }
- duration_format
- = value:numeric
- unit:("ms"/"s"/"min"/"m"/"hr"/"h"/"day"/"d"/"wk"/"w")
- &end_value {
- return tc.tokenValueDuration(value, unit);
- }
- size_format
- = value:numeric
- unit:("bit"/"nb"/"bytes"/"kb"/"mb"/"gb"/"tb"/"pb"/"eb"/"zb"/"yb"/"kib"/"mib"/"gib"/"tib"/"pib"/"eib"/"zib"/"yib")
- &end_value {
- return tc.tokenValueSize(value, unit);
- }
- percentage_format
- = value:numeric "%" {
- return tc.tokenValuePercentage(value);
- }
- // NOTE: the order in which these operators are listed matters because for
- // example, if < comes before <= it will match that even if the operator is <=
- operator = ">=" / "<=" / ">" / "<" / "=" / "!="
- or_operator = "OR"i &end_value
- and_operator = "AND"i &end_value
- numeric = [0-9]+ ("." [0-9]*)? { return text(); }
- open_paren = "("
- closed_paren = ")"
- open_bracket = "["
- closed_bracket = "]"
- sep = ":"
- negation = "!"
- comma = ","
- spaces = " "* { return tc.tokenSpaces(text()) }
- end_value = [\t\n )] / !.
|