use crate::lexer::CssLexContext;
use crate::parser::CssParser;
use crate::syntax::at_rule::parse_error::expected_any_document_matcher;
use crate::syntax::block::parse_rule_block;
use crate::syntax::parse_error::expected_string;
use crate::syntax::parse_string;
use crate::syntax::value::url::{is_at_url_function, parse_url_function, parse_url_value};
use biome_css_syntax::CssSyntaxKind::*;
use biome_css_syntax::{CssSyntaxKind, T};
use biome_parser::parse_lists::ParseSeparatedList;
use biome_parser::parse_recovery::{ParseRecovery, RecoveryResult};
use biome_parser::parsed_syntax::ParsedSyntax::Present;
use biome_parser::prelude::ParsedSyntax::Absent;
use biome_parser::prelude::*;
#[inline]
pub(crate) fn is_at_document_at_rule(p: &mut CssParser) -> bool {
p.at(T![document])
}
#[inline]
pub(crate) fn parse_document_at_rule(p: &mut CssParser) -> ParsedSyntax {
if !is_at_document_at_rule(p) {
return Absent;
}
let m = p.start();
p.bump(T![document]);
DocumentMatcherList.parse_list(p);
parse_rule_block(p);
Present(m.complete(p, CSS_DOCUMENT_AT_RULE))
}
struct DocumentMatcherListParseRecovery;
impl ParseRecovery for DocumentMatcherListParseRecovery {
type Kind = CssSyntaxKind;
type Parser<'source> = CssParser<'source>;
const RECOVERED_KIND: Self::Kind = CSS_BOGUS_DOCUMENT_MATCHER;
fn is_at_recovered(&self, p: &mut Self::Parser<'_>) -> bool {
p.at(T!['{']) || p.at(T![,]) || is_at_document_matcher(p)
}
}
pub(crate) struct DocumentMatcherList;
impl ParseSeparatedList for DocumentMatcherList {
type Kind = CssSyntaxKind;
type Parser<'source> = CssParser<'source>;
const LIST_KIND: Self::Kind = CSS_DOCUMENT_MATCHER_LIST;
fn parse_element(&mut self, p: &mut Self::Parser<'_>) -> ParsedSyntax {
parse_document_matcher(p)
}
fn is_at_list_end(&self, p: &mut Self::Parser<'_>) -> bool {
p.at(T!['{'])
}
fn recover(
&mut self,
p: &mut Self::Parser<'_>,
parsed_element: ParsedSyntax,
) -> RecoveryResult {
parsed_element.or_recover(
p,
&DocumentMatcherListParseRecovery,
expected_any_document_matcher,
)
}
fn separating_element_kind(&mut self) -> Self::Kind {
T![,]
}
}
#[inline]
pub(crate) fn is_at_document_matcher(p: &mut CssParser) -> bool {
is_at_document_custom_matcher(p) || is_at_url_function(p)
}
#[inline]
pub(crate) fn parse_document_matcher(p: &mut CssParser) -> ParsedSyntax {
if !is_at_document_matcher(p) {
return Absent;
}
if is_at_url_function(p) {
parse_url_function(p)
} else {
parse_document_custom_matcher(p)
}
}
const DOCUMENT_CUSTOM_MATCHER_SET: TokenSet<CssSyntaxKind> =
token_set!(T![url_prefix], T![domain], T![media_document], T![regexp]);
pub(crate) fn is_at_document_custom_matcher(p: &mut CssParser) -> bool {
p.at_ts(DOCUMENT_CUSTOM_MATCHER_SET) && p.nth_at(1, T!['('])
}
const URL_PREFIX_SET: TokenSet<CssSyntaxKind> =
token_set!(T![url_prefix], T![domain], T![media_document]);
pub(crate) fn is_at_url_prefix(p: &mut CssParser) -> bool {
p.at_ts(URL_PREFIX_SET) && p.nth_at(1, T!['('])
}
#[inline]
pub(crate) fn parse_document_custom_matcher(p: &mut CssParser) -> ParsedSyntax {
if !is_at_document_custom_matcher(p) {
return Absent;
}
let m = p.start();
if is_at_url_prefix(p) {
p.bump_ts(URL_PREFIX_SET);
p.bump_with_context(T!['('], CssLexContext::UrlRawValue);
parse_url_value(p).ok();
p.expect(T![')']);
return Present(m.complete(p, CSS_DOCUMENT_CUSTOM_MATCHER));
}
p.bump_ts(DOCUMENT_CUSTOM_MATCHER_SET);
p.bump(T!['(']);
parse_string(p).or_add_diagnostic(p, expected_string);
p.expect(T![')']);
Present(m.complete(p, CSS_DOCUMENT_CUSTOM_MATCHER))
}