tree-sitter-css/grammar.js

267 lines
4.8 KiB
JavaScript
Raw Normal View History

2018-09-30 22:59:56 +00:00
module.exports = grammar({
name: 'css',
extras: $ => [
/\s/,
$.comment,
],
2018-10-18 06:14:21 +00:00
externals: $ => [
$._descendant_operator,
],
2018-10-18 16:59:09 +00:00
inline: $ => [
$._top_level_item,
$._block_item,
],
2018-09-30 22:59:56 +00:00
rules: {
2018-10-18 16:59:09 +00:00
stylesheet: $ => repeat($._top_level_item),
_top_level_item: $ => choice(
2018-09-30 22:59:56 +00:00
$.rule_set,
$.import_statement,
2018-10-18 16:59:09 +00:00
$.media_statement,
$.charset_statement,
$.at_rule
),
2018-09-30 22:59:56 +00:00
// Statements
import_statement: $ => seq(
2018-10-18 16:59:09 +00:00
'@import',
$._value,
commaSep($._query),
';'
),
media_statement: $ => seq(
'@media',
commaSep1($._query),
$.block
),
charset_statement: $ => seq(
'@charset',
$._value,
';'
),
at_rule: $ => seq(
$.at_keyword,
commaSep($._query),
choice(';', $.block)
2018-09-30 22:59:56 +00:00
),
// Rule sets
rule_set: $ => seq(
$.selectors,
$.block
),
selectors: $ => commaSep1($._selector),
2018-10-18 16:59:09 +00:00
block: $ => seq('{', repeat($._block_item), '}'),
_block_item: $ => choice(
$.declaration,
$._top_level_item
2018-10-18 06:14:21 +00:00
),
2018-09-30 22:59:56 +00:00
// Selectors
_selector: $ => choice(
$.universal_selector,
2018-10-18 06:14:21 +00:00
alias($.identifier, $.tag_name),
2018-09-30 22:59:56 +00:00
$.class_selector,
2018-10-18 06:14:21 +00:00
$.nesting_selector,
$.pseudo_class_selector,
$.pseudo_element_selector,
2018-09-30 22:59:56 +00:00
$.id_selector,
$.attribute_selector,
2018-10-19 03:37:59 +00:00
$.string_value,
2018-09-30 22:59:56 +00:00
$.child_selector,
$.descendant_selector
),
2018-10-18 06:14:21 +00:00
nesting_selector: $ => '&',
2018-09-30 22:59:56 +00:00
universal_selector: $ => '*',
2018-10-18 06:14:21 +00:00
class_selector: $ => seq(
optional($._selector),
'.',
alias($.identifier, $.class_name),
),
pseudo_class_selector: $ => seq(
optional($._selector),
':',
alias($.identifier, $.class_name),
optional($.arguments)
),
2018-09-30 22:59:56 +00:00
2018-10-18 06:14:21 +00:00
pseudo_element_selector: $ => seq(
optional($._selector),
'::',
alias($.identifier, $.tag_name)
),
2018-09-30 22:59:56 +00:00
2018-10-18 06:14:21 +00:00
id_selector: $ => seq(
optional($._selector),
'#',
alias($.identifier, $.id_name)
),
2018-09-30 22:59:56 +00:00
attribute_selector: $ => seq(
2018-10-18 06:14:21 +00:00
optional($._selector),
'[',
alias($.identifier, $.attribute_name),
2018-09-30 22:59:56 +00:00
optional(seq(
choice('=', '~=', '^=', '|=', '*=', '$='),
2018-10-18 06:14:21 +00:00
$._value
2018-09-30 22:59:56 +00:00
)),
']'
),
child_selector: $ => prec.left(seq($._selector, '>', $._selector)),
2018-10-18 06:14:21 +00:00
descendant_selector: $ => prec.left(seq($._selector, $._descendant_operator, $._selector)),
2018-09-30 22:59:56 +00:00
// Declarations
2018-10-18 06:14:21 +00:00
declaration: $ => prec(1, seq(
alias($.identifier, $.property_name),
2018-09-30 22:59:56 +00:00
':',
2018-10-18 16:59:09 +00:00
$._value,
repeat(seq(
optional(','),
$._value
)),
2018-10-26 18:42:36 +00:00
optional($.important),
2018-09-30 22:59:56 +00:00
';'
2018-10-18 06:14:21 +00:00
)),
2018-10-26 18:42:36 +00:00
important: $ => '!important',
2018-10-18 16:59:09 +00:00
// Media queries
_query: $ => choice(
alias($.identifier, $.keyword_query),
$.feature_query,
$.binary_query,
$.negated_query,
$.parenthesized_query
),
feature_query: $ => seq(
'(',
alias($.identifier, $.feature_name),
':',
$._value,
')'
),
parenthesized_query: $ => seq(
'(',
$._query,
')'
),
binary_query: $ => prec.left(seq(
$._query,
choice('and', 'or'),
$._query
)),
negated_query: $ => prec(1, seq(
'not',
$._query
)),
2018-10-18 06:14:21 +00:00
// Property Values
_value: $ => choice(
alias($.identifier, $.plain_value),
$.plain_value,
2018-10-18 06:14:21 +00:00
$.color_value,
$.integer_value,
$.float_value,
2018-10-18 16:59:09 +00:00
$.string_value,
2018-10-26 16:44:27 +00:00
$.binary_expression,
2018-10-18 16:59:09 +00:00
$.call_expression
2018-10-18 06:14:21 +00:00
),
2018-10-18 16:59:09 +00:00
color_value: $ => /#[0-9a-fA-F]{3,8}/,
string_value: $ => token(choice(
2018-10-23 03:20:36 +00:00
seq("'", /([^'\n]|\\(.|\n))*/, "'"),
seq('"', /([^"\n]|\\(.|\n))*/, '"')
2018-10-18 16:59:09 +00:00
)),
2018-10-18 06:14:21 +00:00
integer_value: $ => seq(
token(seq(
optional(choice('+', '-')),
/\d+/
)),
optional($.unit)
),
float_value: $ => seq(
token(seq(
optional(choice('+', '-')),
/\d*/,
choice(
seq('.', /\d+/),
2018-10-26 16:46:25 +00:00
seq(/[eE]/, optional('-'), /\d+/),
seq('.', /\d+/, /[eE]/, optional('-'), /\d+/)
2018-10-18 06:14:21 +00:00
)
)),
optional($.unit)
),
2018-10-26 16:37:10 +00:00
unit: $ => token.immediate(/[a-zA-Z%]+/),
2018-10-18 06:14:21 +00:00
2018-10-18 16:59:09 +00:00
call_expression: $ => seq(
2018-10-18 06:14:21 +00:00
alias($.identifier, $.function_name),
$.arguments
),
2018-10-26 16:44:27 +00:00
binary_expression: $ => prec.left(seq(
$._value,
choice('+', '-', '*', '/'),
$._value
)),
2018-10-18 06:14:21 +00:00
arguments: $ => seq(
2018-10-18 16:59:09 +00:00
token.immediate('('),
2018-10-18 06:14:21 +00:00
commaSep($._value),
')'
2018-09-30 22:59:56 +00:00
),
2018-10-26 16:34:07 +00:00
identifier: $ => /[a-zA-Z-_][a-zA-Z0-9-_]*/,
2018-09-30 22:59:56 +00:00
plain_value: $ => /[a-zA-Z-_][^;()\[\]\s]*/,
2018-10-18 16:59:09 +00:00
at_keyword: $ => /@[a-zA-Z-_]+/,
2018-09-30 22:59:56 +00:00
comment: $ => token(choice(
seq('//', /.*/),
seq(
'/*',
/[^*]*\*+([^/*][^*]*\*+)*/,
'/'
)
))
}
})
2018-10-18 06:14:21 +00:00
function commaSep (rule) {
return optional(commaSep1(rule))
}
2018-09-30 22:59:56 +00:00
function commaSep1 (rule) {
return seq(rule, repeat(seq(',', rule)))
}