Changeset View
Changeset View
Standalone View
Standalone View
query_language/grammar.js
// Copyright (C) 2019-2021 The Software Heritage developers | // Copyright (C) 2019-2021 The Software Heritage developers | ||||
// See the AUTHORS file at the top-level directory of this distribution | // See the AUTHORS file at the top-level directory of this distribution | ||||
// License: GNU General Public License version 3, or any later version | // License: GNU General Public License version 3, or any later version | ||||
// See top-level LICENSE file for more information | // See top-level LICENSE file for more information | ||||
const PRECEDENCE = { | const PRECEDENCE = { | ||||
or: 2, | or: 2, | ||||
and: 3, | and: 3, | ||||
bracket: 4, | bracket: 4, | ||||
} | } | ||||
module.exports = grammar({ | module.exports = grammar({ | ||||
name: 'swh_search_ql', | name: 'swh_search_ql', | ||||
rules: { | rules: { | ||||
query: $ => $.filters, | query: $ => seq($.filters, optional($.sortBy) ,optional($.limit)), | ||||
filters: $ => choice( | filters: $ => choice( | ||||
prec.left(PRECEDENCE.and, | prec.left(PRECEDENCE.and, | ||||
seq( | seq( | ||||
field('left', $.filters), | field('left', $.filters), | ||||
field('operator', $.and), | field('operator', $.and), | ||||
field('right', $.filters), | field('right', $.filters), | ||||
) | ) | ||||
), | ), | ||||
prec.left(PRECEDENCE.or, | prec.left(PRECEDENCE.or, | ||||
seq( | seq( | ||||
field('left', $.filters), | field('left', $.filters), | ||||
field('operator', $.or), | field('operator', $.or), | ||||
field('right', $.filters), | field('right', $.filters), | ||||
) | ) | ||||
), | ), | ||||
prec.left(PRECEDENCE.bracket, | prec.left(PRECEDENCE.bracket, | ||||
seq("(", $.filters, ")"), | seq("(", $.filters, ")"), | ||||
), | ), | ||||
$.filter | $.filter | ||||
), | ), | ||||
sortBy: $ => seq($.sortByField, $.sortByOp, $.sortByVal), | |||||
sortByField: $ => token('sort_by'), | |||||
sortByOp: $ => $.equalOp, | |||||
sortByVal: $ => createArray(optionalWrapWith($.sortByOptions, ["'", '"'])), | |||||
sortByOptions: $ => seq(optional(token.immediate('-')) ,choice( | |||||
'visits', | |||||
'last_visit', | |||||
'last_eventful_visit', | |||||
'last_revision', | |||||
'last_release', | |||||
'created', | |||||
'modified', | |||||
'published' | |||||
)), | |||||
limit: $ => seq('limit', $.equalOp, $.number), | |||||
filter: $ => choice( | filter: $ => choice( | ||||
$.patternFilter, | $.patternFilter, | ||||
$.booleanFilter, | $.booleanFilter, | ||||
$.numericFilter, | $.numericFilter, | ||||
$.boundedListFilter, | $.boundedListFilter, | ||||
$.unboundedListFilter, | $.unboundedListFilter, | ||||
$.dateFilter, | $.dateFilter | ||||
$.limitFilter | |||||
), | ), | ||||
patternFilter: $ => seq($.patternField, $.patternOp, $.patternVal), | patternFilter: $ => seq($.patternField, $.patternOp, $.patternVal), | ||||
patternField: $ => token(choice('origin', 'metadata')), | patternField: $ => token(choice('origin', 'metadata')), | ||||
patternOp: $ => $.equalOp, | patternOp: $ => $.equalOp, | ||||
patternVal: $ => $.string, | patternVal: $ => $.string, | ||||
booleanFilter: $ => seq($.booleanField, $.booleanOp, $.booleanVal), | booleanFilter: $ => seq($.booleanField, $.booleanOp, $.booleanVal), | ||||
booleanField: $ => token(choice('visited')), | booleanField: $ => token(choice('visited')), | ||||
booleanOp: $ => $.equalOp, | booleanOp: $ => $.equalOp, | ||||
booleanVal: $ => choice($.booleanTrue, $.booleanFalse), | booleanVal: $ => choice($.booleanTrue, $.booleanFalse), | ||||
numericFilter: $ => seq($.numericField, $.numericOp, $.numberVal), | numericFilter: $ => seq($.numericField, $.numericOp, $.numberVal), | ||||
numericField: $ => token(choice('visits')), | numericField: $ => token(choice('visits')), | ||||
numericOp: $ => $.rangeOp, | numericOp: $ => $.rangeOp, | ||||
numberVal: $ => $.number, | numberVal: $ => $.number, | ||||
boundedListFilter: $ => choice($.visitTypeFilter, $.sortByFilter), | boundedListFilter: $ => choice($.visitTypeFilter), | ||||
visitTypeFilter: $ => seq($.visitTypeField, $.visitTypeOp, $.visitTypeVal), | visitTypeFilter: $ => seq($.visitTypeField, $.visitTypeOp, $.visitTypeVal), | ||||
visitTypeField: $ => token(choice('visit_type')), | visitTypeField: $ => token(choice('visit_type')), | ||||
visitTypeOp: $ => $.equalOp, | visitTypeOp: $ => $.equalOp, | ||||
visitTypeVal: $ => createArray(optionalWrapWith($.visitTypeOptions, ["'", '"'])), | visitTypeVal: $ => createArray(optionalWrapWith($.visitTypeOptions, ["'", '"'])), | ||||
visitTypeOptions: $ => choice( | visitTypeOptions: $ => choice( | ||||
"any", | "any", | ||||
"cran", | "cran", | ||||
"deb", | "deb", | ||||
"deposit", | "deposit", | ||||
"ftp", | "ftp", | ||||
"hg", | "hg", | ||||
"git", | "git", | ||||
"nixguix", | "nixguix", | ||||
"npm", | "npm", | ||||
"pypi", | "pypi", | ||||
"svn", | "svn", | ||||
"tar" | "tar" | ||||
), // TODO: fetch this list dynamically from other swh services? | ), // TODO: fetch this list dynamically from other swh services? | ||||
sortByFilter: $ => seq($.sortByField, $.sortByOp, $.sortByVal), | sortBy: $ => seq($.sortByField, $.sortByOp, $.sortByVal), | ||||
sortByField: $ => token(choice('sort_by')), | sortByField: $ => token(choice('sort_by')), | ||||
sortByOp: $ => $.equalOp, | sortByOp: $ => $.equalOp, | ||||
sortByVal: $ => createArray(optionalWrapWith($.sortByOptions, ["'", '"'])), | sortByVal: $ => createArray(optionalWrapWith($.sortByOptions, ["'", '"'])), | ||||
sortByOptions: $ => seq( | sortByOptions: $ => seq( | ||||
optional(token.immediate('-')), | optional(token.immediate('-')), | ||||
choice( | choice( | ||||
'visits', | 'visits', | ||||
'last_visit', | 'last_visit', | ||||
Show All 19 Lines | rules: { | ||||
'last_release', | 'last_release', | ||||
'created', | 'created', | ||||
'modified', | 'modified', | ||||
'published' | 'published' | ||||
)), | )), | ||||
dateOp: $ => $.rangeOp, | dateOp: $ => $.rangeOp, | ||||
dateVal: $ => $.isoDateTime, | dateVal: $ => $.isoDateTime, | ||||
limitFilter: $ => seq('limit', $.equalOp, $.number), | limit: $ => seq('limit', $.equalOp, $.number), | ||||
rangeOp: $ => token(choice('<', '<=', '=', '!=', '>=', '>')), | rangeOp: $ => token(choice('<', '<=', '=', '!=', '>=', '>')), | ||||
equalOp: $ => token('='), | equalOp: $ => token('='), | ||||
choiceOp: $ => token(choice('in', 'not in')), | choiceOp: $ => token(choice('in', 'not in')), | ||||
isoDateTime: $ => /\d{4}[-]\d{2}[-]\d{2}(\s|T)*(\d{2}:\d{2}(:\d{2})?)?(Z)?/, | isoDateTime: $ => /\d{4}[-]\d{2}[-]\d{2}(\s|T)*(\d{2}:\d{2}(:\d{2})?)?(Z)?/, | ||||
▲ Show 20 Lines • Show All 54 Lines • Show Last 20 Lines |