1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use nom::character::complete::char;
use nom::combinator::opt;
use nom::sequence::preceded;
use nom::IResult;
use nom::{sequence::delimited, Parser};
use swc_core::common::{BytePos, Span};
use swc_core::ecma::ast::ObjectLit;
use tailwind_config::TailwindConfig;
use crate::{
directive::Directive,
literal::{Literal, SubjectValue},
};
use crate::{ExpressionConversionError, LiteralConversionError, NomSpan, Plugin};
#[derive(Debug, PartialEq)]
pub enum Subject<'a> {
Literal(Literal<'a>),
Group(Directive<'a>),
}
#[derive(thiserror::Error, Debug)]
pub enum SubjectConversionError<'a> {
#[error("{0}")]
InvalidExpression(Box<ExpressionConversionError<'a>>),
#[error("{0}")]
InvalidLiteral(LiteralConversionError<'a>),
}
impl<'a> Subject<'a> {
pub fn parse(s: NomSpan<'a>) -> IResult<NomSpan<'a>, Self, nom::error::Error<NomSpan<'a>>> {
let plugin = Plugin::parse;
let subject_value = opt(preceded(char('-'), SubjectValue::parse_with_span));
let group = delimited(char('('), Directive::parse_inner, char(')')).map(Subject::Group);
let literal = plugin.and(subject_value).map(|(cmd, value)| {
let (span, value) = value.unzip();
Subject::Literal(Literal {
cmd,
value,
span: Some(
s.extra
.with_lo(s.extra.lo() + BytePos(s.location_offset() as u32))
.with_hi(
s.extra.lo()
+ BytePos(span.map(|s| s.location_offset() as u32).unwrap_or(0)),
),
),
})
});
literal.or(group).parse(s)
}
pub fn to_literal(
self,
span: Span,
config: &TailwindConfig,
) -> Result<ObjectLit, SubjectConversionError<'a>> {
match self {
Subject::Literal(lit) => lit
.to_object_lit(span, &config.theme)
.map_err(SubjectConversionError::InvalidLiteral),
Subject::Group(dir) => dir
.to_literal(span, config)
.map_err(|e| SubjectConversionError::InvalidExpression(Box::new(e))),
}
}
}