use crate::lexer::CssLexContext;
use crate::parser::CssParser;
use crate::syntax::value::function::{is_at_function, is_nth_at_function, parse_function};
use crate::syntax::value::parse_error::expected_url_modifier;
use crate::syntax::{is_at_identifier, is_at_string, parse_regular_identifier, parse_string};
use biome_css_syntax::CssSyntaxKind::*;
use biome_css_syntax::{CssSyntaxKind, T};
use biome_parser::parse_lists::ParseNodeList;
use biome_parser::parse_recovery::{ParseRecovery, RecoveryResult};
use biome_parser::parsed_syntax::ParsedSyntax;
use biome_parser::parsed_syntax::ParsedSyntax::{Absent, Present};
use biome_parser::{token_set, Parser, TokenSet};
const URL_SET: TokenSet<CssSyntaxKind> = token_set![T![url], T![src]];
pub(crate) fn is_at_url_function(p: &mut CssParser) -> bool {
p.at_ts(URL_SET) && p.nth_at(1, T!['('])
}
pub(crate) fn parse_url_function(p: &mut CssParser) -> ParsedSyntax {
if !is_at_url_function(p) {
return Absent;
}
let m = p.start();
p.bump_ts(URL_SET);
if is_nth_at_function(p, 1) {
p.bump(T!['(']);
} else {
p.bump_with_context(T!['('], CssLexContext::UrlRawValue);
parse_url_value(p).ok();
}
UrlModifierList.parse_list(p);
p.expect(T![')']);
Present(m.complete(p, CSS_URL_FUNCTION))
}
#[inline]
pub(crate) fn is_at_url_value(p: &mut CssParser) -> bool {
is_at_url_value_raw(p) || is_at_string(p)
}
#[inline]
pub(crate) fn parse_url_value(p: &mut CssParser) -> ParsedSyntax {
if !is_at_url_value(p) {
return Absent;
}
if is_at_string(p) {
parse_string(p)
} else {
parse_url_value_raw(p)
}
}
#[inline]
pub(crate) fn is_at_url_value_raw(p: &mut CssParser) -> bool {
p.at(CSS_URL_VALUE_RAW_LITERAL)
}
#[inline]
pub(crate) fn parse_url_value_raw(p: &mut CssParser) -> ParsedSyntax {
if !is_at_url_value_raw(p) {
return Absent;
}
let m = p.start();
p.expect(CSS_URL_VALUE_RAW_LITERAL);
Present(m.complete(p, CSS_URL_VALUE_RAW))
}
struct UrlModifierListParseRecovery;
impl ParseRecovery for UrlModifierListParseRecovery {
type Kind = CssSyntaxKind;
type Parser<'source> = CssParser<'source>;
const RECOVERED_KIND: Self::Kind = CSS_BOGUS_URL_MODIFIER;
fn is_at_recovered(&self, p: &mut Self::Parser<'_>) -> bool {
p.at(T![')']) || is_at_url_modifier(p)
}
}
struct UrlModifierList;
impl ParseNodeList for UrlModifierList {
type Kind = CssSyntaxKind;
type Parser<'source> = CssParser<'source>;
const LIST_KIND: Self::Kind = CSS_URL_MODIFIER_LIST;
fn parse_element(&mut self, p: &mut Self::Parser<'_>) -> ParsedSyntax {
parse_url_modifier(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, &UrlModifierListParseRecovery, expected_url_modifier)
}
}
#[inline]
pub(crate) fn is_at_url_modifier(p: &mut CssParser) -> bool {
is_at_identifier(p) || is_at_function(p)
}
#[inline]
pub(crate) fn parse_url_modifier(p: &mut CssParser) -> ParsedSyntax {
if !is_at_url_modifier(p) {
return Absent;
}
if is_at_function(p) {
parse_function(p)
} else {
parse_regular_identifier(p)
}
}