Skip to content

Commit

Permalink
feat: expose suggestions on swc error handler
Browse files Browse the repository at this point in the history
  • Loading branch information
arlyon committed Dec 25, 2022
1 parent e038cd3 commit b14872c
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 31 deletions.
2 changes: 1 addition & 1 deletion crates/tailwind-parse/src/directive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl<'a> Directive<'a> {
/// Attempts to parse a literal from the given directive,
pub fn to_literal(
self,
config: &TailwindConfig,
config: &'a TailwindConfig,
) -> (ObjectLit, Vec<ExpressionConversionError<'a>>) {
self.exps
.into_iter()
Expand Down
2 changes: 1 addition & 1 deletion crates/tailwind-parse/src/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ impl<'a> Expression<'a> {
pub fn to_literal(
self,
span: Span,
config: &TailwindConfig,
config: &'a TailwindConfig,
) -> Result<ObjectLit, ExpressionConversionError<'a>> {
let mut object: ObjectLit = self
.subject
Expand Down
20 changes: 7 additions & 13 deletions crates/tailwind-parse/src/literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ use tailwind_config::TailwindTheme;
use crate::eval::{plugin, prose};
use crate::NomSpan;
use crate::Plugin;
use crate::Subject;

/// The core 'rule' of a tailwind directive.
///
Expand All @@ -36,16 +35,7 @@ pub enum LiteralConversionError<'a> {
#[error("missing argument for `{0:?}`")]
MissingArguments(Plugin),
#[error("invalid argument for `{0:?}` - `{1}`")]
InvalidArguments(Plugin, SubjectValue<'a>),
}

impl<'a> LiteralConversionError<'a> {
pub fn new<'b: 'a>(cmd: Plugin, value: Option<SubjectValue<'a>>) -> Self {
match value {
Some(value) => Self::InvalidArguments(cmd, value),
None => Self::MissingArguments(cmd),
}
}
InvalidArguments(Plugin, SubjectValue<'a>, Vec<&'a str>),
}

pub type PluginResult<'a> = Result<ObjectLit, Vec<&'a str>>;
Expand All @@ -63,7 +53,7 @@ impl<'a> Literal<'a> {
pub fn to_object_lit(
self,
_span: Span,
theme: &TailwindTheme,
theme: &'a TailwindTheme,
) -> Result<ObjectLit, LiteralConversionError<'a>> {
use crate::Gap;
use crate::Inset;
Expand Down Expand Up @@ -191,9 +181,13 @@ impl<'a> Literal<'a> {
(RequiredArbitrary(p), Some(value)) => p(value, theme),
(Singular(p), None) => Ok(p()),
(RequiredBox(p), Some(SubjectValue::Value(value))) => p(value, theme),
(OptionalAbitraryBox(p), value) => p(value, theme),
_ => Err(vec![]),
}
.map_err(|e| LiteralConversionError::new(self.cmd, self.value))
.map_err(|e| match self.value {
Some(v) => LiteralConversionError::InvalidArguments(self.cmd, v, e),
None => LiteralConversionError::MissingArguments(self.cmd),
})
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/tailwind-parse/src/subject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl<'a> Subject<'a> {
pub fn to_literal(
self,
span: Span,
config: &TailwindConfig,
config: &'a TailwindConfig,
) -> Result<ObjectLit, SubjectConversionError<'a>> {
match self {
Subject::Literal(lit) => lit
Expand Down
64 changes: 49 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod engine;
mod test;

use depth_stack::DepthStack;

use nom_locate::LocatedSpan;
use serde::Deserialize;
use swc_core::{
Expand All @@ -34,7 +35,9 @@ use swc_core::{
plugin::{errors::HANDLER, plugin_transform, proxies::TransformPluginProgramMetadata},
};
use tailwind_config::TailwindConfig;
use tailwind_parse::Directive;
use tailwind_parse::{
Directive, ExpressionConversionError, LiteralConversionError, SubjectConversionError,
};

#[derive(serde::Deserialize, Debug)]
pub struct AppConfig<'a> {
Expand Down Expand Up @@ -92,12 +95,30 @@ impl<'a> TransformVisitor<'a> {
}
}

fn report<'s>(&self, h: &'s Handler, span: Span, msg: &'s str) -> DiagnosticBuilder<'s> {
if self.strict {
fn report<'s>(
&self,
h: &'s Handler,
span: Span,
msg: &'s str,
suggestions: Option<&[&str]>,
) -> DiagnosticBuilder<'s> {
let mut b = if self.strict {
h.struct_span_err(span, msg)
} else {
h.struct_span_warn(span, msg)
};

if let Some(s) = suggestions {
b.allow_suggestions(true)
.help(&format!("maybe you meant {:?}", s))
.span_suggestions(
span,
"maybe you meant",
s.iter().map(|s| s.to_string()).collect(),
);
}

b
}
}

Expand Down Expand Up @@ -129,7 +150,7 @@ impl<'a> VisitMut for TransformVisitor<'a> {
Ok((_, d)) => d,
Err(e) => {
HANDLER.with(|h| {
self.report(h, *span, &e.to_string())
self.report(h, *span, &e.to_string(), None)
.note("unknown plugin")
.emit()
});
Expand All @@ -141,15 +162,24 @@ impl<'a> VisitMut for TransformVisitor<'a> {

for e in errs {
HANDLER.with(|h| {
self.report(h, *span, &e.to_string())
.note("when evaluating plugin")
.emit()
match e {
ExpressionConversionError::UnknownSubject(SubjectConversionError::InvalidLiteral(LiteralConversionError::InvalidArguments(_p, _v, s)), span) => {
self
.report(h, span, "unknown parameter", Some(&s))
.emit()
}
_ => {
self.report(h, *span, &e.to_string(), None)
.emit()
}
}

});
}

if let Some((span, _val)) = self.tw_attr_stack.push((*span, x)) {
HANDLER.with(|h| {
self.report(h, n.span, "tw attribute already exists, ignoring")
self.report(h, n.span, "tw attribute already exists, ignoring", None)
.span_note(
span,
"previous encountered here",
Expand All @@ -164,7 +194,7 @@ impl<'a> VisitMut for TransformVisitor<'a> {
..
})) => {
HANDLER.with(|h| {
self.report(h, *span, "variables are not supported")
self.report(h, *span, "variables are not supported", None)
.emit()
});
}
Expand Down Expand Up @@ -285,7 +315,7 @@ impl<'a> VisitMut for TransformVisitor<'a> {
Ok((_, d)) => d,
Err(e) => {
HANDLER.with(|h| {
self.report(h, *span, "invalid syntax")
self.report(h, *span, "invalid syntax", None)
.note(&e.to_string())
.emit()
});
Expand All @@ -295,11 +325,15 @@ impl<'a> VisitMut for TransformVisitor<'a> {

let (lit, errs) = d.to_literal(&self.config);

for e in &errs {
HANDLER.with(|h| {
self.report(h, e.span(), &e.to_string())
.note("when evaluating plugin")
.emit()
for e in errs {
HANDLER.with(|h| match e {
ExpressionConversionError::UnknownSubject(
SubjectConversionError::InvalidLiteral(
LiteralConversionError::InvalidArguments(_p, _v, s),
),
span,
) => self.report(h, span, "unknown parameter", Some(&s)).emit(),
_ => self.report(h, *span, &e.to_string(), None).emit(),
});
}

Expand Down

0 comments on commit b14872c

Please sign in to comment.