98 lines
1.7 KiB
JavaScript
98 lines
1.7 KiB
JavaScript
module.exports = grammar({
|
|
name: 'css',
|
|
|
|
extras: $ => [
|
|
/\s/,
|
|
$.comment,
|
|
],
|
|
|
|
rules: {
|
|
stylesheet: $ => repeat(choice(
|
|
$.rule_set,
|
|
$.import_statement,
|
|
)),
|
|
|
|
// Statements
|
|
|
|
import_statement: $ => seq(
|
|
'@import'
|
|
),
|
|
|
|
// Rule sets
|
|
|
|
rule_set: $ => seq(
|
|
$.selectors,
|
|
$.block
|
|
),
|
|
|
|
selectors: $ => commaSep1($._selector),
|
|
|
|
block: $ => seq('{', repeat($.declaration), '}'),
|
|
|
|
// Selectors
|
|
|
|
_selector: $ => choice(
|
|
$.universal_selector,
|
|
$.type_selector,
|
|
$.class_selector,
|
|
$.id_selector,
|
|
$.attribute_selector,
|
|
$.child_selector,
|
|
$.descendant_selector
|
|
),
|
|
|
|
universal_selector: $ => '*',
|
|
|
|
type_selector: $ => $.identifier,
|
|
|
|
class_selector: $ => seq('.', $.identifier),
|
|
|
|
id_selector: $ => seq('#', $.identifier),
|
|
|
|
attribute_selector: $ => seq(
|
|
choice(
|
|
'[',
|
|
seq($._selector, token.immediate('['))
|
|
),
|
|
$.property_name,
|
|
optional(seq(
|
|
choice('=', '~=', '^=', '|=', '*=', '$='),
|
|
$.property_value
|
|
)),
|
|
']'
|
|
),
|
|
|
|
child_selector: $ => prec.left(seq($._selector, '>', $._selector)),
|
|
|
|
descendant_selector: $ => prec.left(seq($._selector, $._selector)),
|
|
|
|
// Declarations
|
|
|
|
declaration: $ => seq(
|
|
$.property_name,
|
|
':',
|
|
$.property_value,
|
|
';'
|
|
),
|
|
|
|
property_name: $ => $.identifier,
|
|
|
|
identifier: $ => /[a-zA-Z-_]+/,
|
|
|
|
property_value: $ => /[^;()\[\]]+/,
|
|
|
|
comment: $ => token(choice(
|
|
seq('//', /.*/),
|
|
seq(
|
|
'/*',
|
|
/[^*]*\*+([^/*][^*]*\*+)*/,
|
|
'/'
|
|
)
|
|
))
|
|
}
|
|
})
|
|
|
|
function commaSep1 (rule) {
|
|
return seq(rule, repeat(seq(',', rule)))
|
|
}
|