2019-07-27 11:42:08 +09:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
class SearchQueryParser < Parslet::Parser
|
2023-04-06 03:24:44 +09:00
|
|
|
rule(:term) { match('[^\s"]').repeat(1).as(:term) }
|
2019-08-16 20:00:30 +09:00
|
|
|
rule(:quote) { str('"') }
|
|
|
|
rule(:colon) { str(':') }
|
2023-04-06 03:24:44 +09:00
|
|
|
rule(:hash) { str('#') }
|
2019-08-16 20:00:30 +09:00
|
|
|
rule(:space) { match('\s').repeat(1) }
|
|
|
|
rule(:operator) { (str('+') | str('-')).as(:operator) }
|
2023-04-06 03:24:44 +09:00
|
|
|
# See SearchQueryTransformer::PrefixClause::initialize for list of legal prefix operators.
|
|
|
|
# These are explictly enumerated here so they don't get mistaken for URLs.
|
|
|
|
rule(:prefix) { ((str('domain') | str('is') | str('has') | str('lang') | str('before') | str('after') | str('from') | str('mentions') | str('to') | str('scope') | str('sort')).as(:prefix) >> colon) }
|
|
|
|
# See CustomEmoji::SHORTCODE_RE_FRAGMENT and SCAN_RE for emoji grammar.
|
|
|
|
rule(:shortcode) { (colon >> match('[a-zA-Z0-9_]').repeat(2).as(:shortcode) >> colon) }
|
|
|
|
rule(:hashtag) { (hash >> match('[^\s#]').repeat(1).as(:hashtag)) }
|
|
|
|
rule(:phrase) { (quote >> match('[^"]').repeat(1).as(:phrase) >> quote) }
|
|
|
|
rule(:clause) { (operator.maybe >> prefix.maybe >> (phrase | shortcode | hashtag | term)).as(:clause) }
|
2019-08-16 20:00:30 +09:00
|
|
|
rule(:query) { (clause >> space.maybe).repeat.as(:query) }
|
2019-07-27 11:42:08 +09:00
|
|
|
root(:query)
|
|
|
|
end
|