tree-sitter-css/grammar.js

367 lines
7.1 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-30 22:54:37 +00:00
conflicts: $ => [
[$._selector, $.declaration],
],
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-10-30 22:54:37 +00:00
$.declaration,
2018-09-30 22:59:56 +00:00
$.rule_set,
$.import_statement,
2018-10-18 16:59:09 +00:00
$.media_statement,
$.charset_statement,
2018-10-26 18:46:10 +00:00
$.namespace_statement,
2018-10-26 18:56:10 +00:00
$.keyframes_statement,
2018-10-26 21:01:52 +00:00
$.supports_statement,
2018-10-18 16:59:09 +00:00
$.at_rule
),
2018-09-30 22:59:56 +00:00
// Statements
import_statement: $ => seq(
2018-10-18 16:59:09 +00:00
'@import',
$._value,
sep(',', $._query),
2018-10-18 16:59:09 +00:00
';'
),
media_statement: $ => seq(
'@media',
sep1(',', $._query),
2018-10-18 16:59:09 +00:00
$.block
),
charset_statement: $ => seq(
'@charset',
$._value,
';'
),
2018-10-26 18:46:10 +00:00
namespace_statement: $ => seq(
'@namespace',
optional(alias($.identifier, $.namespace_name)),
choice($.string_value, $.call_expression),
';'
),
2018-10-26 18:56:10 +00:00
keyframes_statement: $ => seq(
choice(
'@keyframes',
alias(/@[-a-z]+keyframes/, $.at_keyword)
),
2018-10-26 18:56:10 +00:00
alias($.identifier, $.keyframes_name),
$.keyframe_block_list,
),
keyframe_block_list: $ => seq(
'{',
repeat($.keyframe_block),
'}'
),
keyframe_block: $ => seq(
choice($.from, $.to, $.integer_value),
$.block
),
from: $ => 'from',
to: $ => 'to',
2018-10-26 21:01:52 +00:00
supports_statement: $ => seq(
'@supports',
$._query,
$.block
),
2018-10-18 16:59:09 +00:00
at_rule: $ => seq(
$.at_keyword,
sep(',', $._query),
2018-10-18 16:59:09 +00:00
choice(';', $.block)
2018-09-30 22:59:56 +00:00
),
// Rule sets
rule_set: $ => seq(
$.selectors,
$.block
),
selectors: $ => sep1(',', $._selector),
2018-09-30 22:59:56 +00:00
block: $ => seq('{',
repeat($._block_item),
optional(alias($.last_declaration, $.declaration)),
'}'
),
2018-10-18 16:59:09 +00:00
_block_item: $ => choice(
$.declaration,
2018-10-30 22:54:37 +00:00
$.rule_set,
$.import_statement,
$.media_statement,
$.charset_statement,
$.namespace_statement,
$.keyframes_statement,
$.supports_statement,
$.at_rule
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,
2018-10-26 21:13:39 +00:00
$.descendant_selector,
$.sibling_selector,
$.adjacent_sibling_selector
2018-09-30 22:59:56 +00:00
),
2018-10-18 06:14:21 +00:00
nesting_selector: $ => '&',
2018-09-30 22:59:56 +00:00
universal_selector: $ => '*',
2018-10-26 21:13:39 +00:00
class_selector: $ => prec(1, seq(
2018-10-18 06:14:21 +00:00
optional($._selector),
'.',
alias($.identifier, $.class_name),
2018-10-26 21:13:39 +00:00
)),
2018-10-18 06:14:21 +00:00
pseudo_class_selector: $ => seq(
optional($._selector),
':',
alias($.identifier, $.class_name),
2018-10-26 21:23:46 +00:00
optional(alias($.pseudo_class_arguments, $.arguments))
2018-10-18 06:14:21 +00:00
),
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
2018-10-26 21:13:39 +00:00
sibling_selector: $ => prec.left(seq($._selector, '~', $._selector)),
adjacent_sibling_selector: $ => prec.left(seq($._selector, '+', $._selector)),
2018-10-26 21:23:46 +00:00
pseudo_class_arguments: $ => seq(
token.immediate('('),
sep(',', choice($._selector, repeat1($._value))),
2018-10-26 21:23:46 +00:00
')'
),
2018-09-30 22:59:56 +00:00
// Declarations
2018-10-30 22:54:37 +00:00
declaration: $ => seq(
2018-10-18 06:14:21 +00:00
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-30 22:54:37 +00:00
),
2018-10-18 06:14:21 +00:00
last_declaration: $ => prec(1, seq(
alias($.identifier, $.property_name),
':',
$._value,
repeat(seq(
optional(','),
$._value
)),
optional($.important)
)),
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,
2018-10-29 22:46:58 +00:00
$.unary_query,
2018-10-26 21:01:52 +00:00
$.selector_query,
2018-10-18 16:59:09 +00:00
$.parenthesized_query
),
feature_query: $ => seq(
'(',
alias($.identifier, $.feature_name),
':',
repeat1($._value),
2018-10-18 16:59:09 +00:00
')'
),
parenthesized_query: $ => seq(
'(',
$._query,
')'
),
binary_query: $ => prec.left(seq(
$._query,
choice('and', 'or'),
$._query
)),
2018-10-29 22:46:58 +00:00
unary_query: $ => prec(1, seq(
choice('not', 'only'),
2018-10-18 16:59:09 +00:00
$._query
)),
2018-10-26 21:01:52 +00:00
selector_query: $ => seq(
'selector',
'(',
$._selector,
')'
),
2018-10-18 06:14:21 +00:00
// Property Values
2018-10-26 21:23:46 +00:00
_value: $ => prec(-1, 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-29 22:35:49 +00:00
$.parenthesized_value,
2018-10-18 16:59:09 +00:00
$.call_expression
2018-10-26 21:23:46 +00:00
)),
2018-10-18 06:14:21 +00:00
2018-10-29 22:35:49 +00:00
parenthesized_value: $ => seq(
'(',
$._value,
')'
),
color_value: $ => seq('#', token.immediate(/[0-9a-fA-F]{3,8}/)),
2018-10-18 16:59:09 +00:00
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('('),
sep(choice(',', ';'), repeat1($._value)),
2018-10-18 06:14:21 +00:00
')'
2018-09-30 22:59:56 +00:00
),
identifier: $ => /(--|-?[a-zA-Z_])[a-zA-Z0-9-_]*/,
2018-09-30 22:59:56 +00:00
2018-10-18 16:59:09 +00:00
at_keyword: $ => /@[a-zA-Z-_]+/,
2018-10-28 21:21:26 +00:00
comment: $ => token(seq(
'/*',
/[^*]*\*+([^/*][^*]*\*+)*/,
'/'
)),
plain_value: $ => token(seq(
repeat(choice(
/[-_]/,
/\/[^\*\s,;!{}()\[\]]/ // Slash not followed by a '*' (which would be a comment)
)),
/[a-zA-Z]/,
repeat(choice(
/[^/\s,;!{}()\[\]]/, // Not a slash, not a delimiter character
/\/[^\*\s,;!{}()\[\]]/ // Slash not followed by a '*' (which would be a comment)
))
))
2018-09-30 22:59:56 +00:00
}
})
function sep (separator, rule) {
return optional(sep1(separator, rule))
2018-10-18 06:14:21 +00:00
}
function sep1 (separator, rule) {
return seq(rule, repeat(seq(separator, rule)))
2018-09-30 22:59:56 +00:00
}