swc_ecma_regexp/
diagnostics.rs

1use std::{
2    borrow::Cow,
3    fmt::{self, Display},
4};
5
6use swc_common::Span;
7
8type Either<T, E> = std::result::Result<T, E>;
9
10#[derive(Debug)]
11pub struct RegexpDiagnostic {
12    message: Cow<'static, str>,
13    label: Option<Either<Span, Vec<Span>>>,
14    help: Option<Cow<'static, str>>,
15}
16
17impl RegexpDiagnostic {
18    pub fn error<T: Into<Cow<'static, str>>>(message: T) -> Self {
19        RegexpDiagnostic {
20            message: message.into(),
21            label: None,
22            help: None,
23        }
24    }
25
26    pub fn with_label(mut self, span: Span) -> Self {
27        self.label = Some(Ok(span));
28        self
29    }
30
31    pub fn with_labels(mut self, spans: Vec<Span>) -> Self {
32        self.label = Some(Err(spans));
33        self
34    }
35
36    pub fn with_help<T: Into<Cow<'static, str>>>(mut self, help: T) -> Self {
37        self.help = Some(help.into());
38        self
39    }
40}
41
42impl Display for RegexpDiagnostic {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
44        self.message.fmt(f)
45    }
46}
47
48pub type Result<T> = std::result::Result<T, RegexpDiagnostic>;
49
50const PREFIX: &str = "Invalid regular expression:";
51
52#[cold]
53pub fn invalid_input(span: Span) -> RegexpDiagnostic {
54    RegexpDiagnostic::error(format!("{PREFIX} Invalid input string literal")).with_label(span)
55}
56
57// ---
58
59#[cold]
60pub fn unknown_flag(span: Span, flag: &str) -> RegexpDiagnostic {
61    RegexpDiagnostic::error(format!("{PREFIX} Unknown flag: `{flag}` found")).with_label(span)
62}
63
64#[cold]
65pub fn duplicated_flags(span: Span, flag: &str) -> RegexpDiagnostic {
66    RegexpDiagnostic::error(format!("{PREFIX} Duplicated flag: `{flag}` found")).with_label(span)
67}
68
69#[cold]
70pub fn invalid_unicode_flags(span: Span) -> RegexpDiagnostic {
71    RegexpDiagnostic::error(format!(
72        "{PREFIX} Invalid unicode flags combination `u` and `v`"
73    ))
74    .with_label(span)
75}
76
77// ---
78
79#[cold]
80pub fn duplicated_capturing_group_names(spans: Vec<Span>) -> RegexpDiagnostic {
81    RegexpDiagnostic::error(format!("{PREFIX} Duplicated capturing group names")).with_labels(spans)
82}
83
84#[cold]
85pub fn too_may_capturing_groups(span: Span) -> RegexpDiagnostic {
86    RegexpDiagnostic::error(format!("{PREFIX} Too many capturing groups")).with_label(span)
87}
88
89#[cold]
90pub fn parse_pattern_incomplete(span: Span) -> RegexpDiagnostic {
91    RegexpDiagnostic::error(format!("{PREFIX} Could not parse the entire pattern")).with_label(span)
92}
93
94#[cold]
95pub fn lone_quantifier(span: Span, kind: &str) -> RegexpDiagnostic {
96    RegexpDiagnostic::error(format!(
97        "{PREFIX} Lone quantifier found, expected with `{kind}`"
98    ))
99    .with_label(span)
100}
101
102#[cold]
103pub fn unterminated_pattern(span: Span, kind: &str) -> RegexpDiagnostic {
104    RegexpDiagnostic::error(format!("{PREFIX} Unterminated {kind}")).with_label(span)
105}
106
107#[cold]
108pub fn invalid_extended_atom_escape(span: Span) -> RegexpDiagnostic {
109    RegexpDiagnostic::error(format!("{PREFIX} Invalid extended atom escape")).with_label(span)
110}
111
112#[cold]
113pub fn invalid_braced_quantifier(span: Span) -> RegexpDiagnostic {
114    RegexpDiagnostic::error(format!("{PREFIX} Invalid braced quantifier")).with_label(span)
115}
116
117#[cold]
118pub fn invalid_indexed_reference(span: Span) -> RegexpDiagnostic {
119    RegexpDiagnostic::error(format!("{PREFIX} Invalid indexed reference")).with_label(span)
120}
121
122#[cold]
123pub fn empty_group_specifier(span: Span) -> RegexpDiagnostic {
124    RegexpDiagnostic::error(format!("{PREFIX} Group specifier is empty")).with_label(span)
125}
126
127#[cold]
128pub fn invalid_named_reference(span: Span) -> RegexpDiagnostic {
129    RegexpDiagnostic::error(format!("{PREFIX} Invalid named reference")).with_label(span)
130}
131
132#[cold]
133pub fn invalid_unicode_property_name_negative_strings(span: Span, name: &str) -> RegexpDiagnostic {
134    RegexpDiagnostic::error(format!(
135        "{PREFIX} Invalid property name `{name}`(negative + property of strings)"
136    ))
137    .with_label(span)
138}
139
140#[cold]
141pub fn invalid_character_class(span: Span) -> RegexpDiagnostic {
142    RegexpDiagnostic::error(format!(
143        "{PREFIX} Invalid character class with strings unicode property"
144    ))
145    .with_label(span)
146}
147
148#[cold]
149pub fn character_class_range_out_of_order(span: Span, kind: &str) -> RegexpDiagnostic {
150    RegexpDiagnostic::error(format!("{PREFIX} Character {kind} range out of order"))
151        .with_label(span)
152}
153
154#[cold]
155pub fn character_class_range_invalid_atom(span: Span) -> RegexpDiagnostic {
156    RegexpDiagnostic::error(format!("{PREFIX} Character class range with invalid atom"))
157        .with_label(span)
158}
159
160#[cold]
161pub fn invalid_class_atom(span: Span) -> RegexpDiagnostic {
162    RegexpDiagnostic::error(format!("{PREFIX} Invalid class atom")).with_label(span)
163}
164
165#[cold]
166pub fn empty_class_set_expression(span: Span) -> RegexpDiagnostic {
167    RegexpDiagnostic::error(format!("{PREFIX} Expected nonempty class set expression"))
168        .with_label(span)
169}
170
171#[cold]
172pub fn class_intersection_unexpected_ampersand(span: Span) -> RegexpDiagnostic {
173    RegexpDiagnostic::error(format!(
174        "{PREFIX} Unexpected `&` inside of class intersection"
175    ))
176    .with_label(span)
177}
178
179#[cold]
180pub fn class_set_expression_invalid_character(span: Span, kind: &str) -> RegexpDiagnostic {
181    RegexpDiagnostic::error(format!("{PREFIX} Unexpected character inside of {kind}"))
182        .with_label(span)
183}
184
185#[cold]
186pub fn character_class_contents_invalid_operands(span: Span) -> RegexpDiagnostic {
187    RegexpDiagnostic::error(format!(
188        "{PREFIX} Invalid class operands inside of character class contents"
189    ))
190    .with_label(span)
191}
192
193#[cold]
194pub fn too_large_number_in_braced_quantifier(span: Span) -> RegexpDiagnostic {
195    RegexpDiagnostic::error(format!("{PREFIX} Number is too large in braced quantifier"))
196        .with_label(span)
197}
198
199#[cold]
200pub fn braced_quantifier_out_of_order(span: Span) -> RegexpDiagnostic {
201    RegexpDiagnostic::error(format!(
202        "{PREFIX} Numbers out of order in braced quantifier"
203    ))
204    .with_label(span)
205}
206
207#[cold]
208pub fn too_large_number_digits(span: Span, kind: &str) -> RegexpDiagnostic {
209    RegexpDiagnostic::error(format!("{PREFIX} Number is too large in {kind} digits"))
210        .with_label(span)
211}
212
213#[cold]
214pub fn invalid_unicode_property(span: Span, kind: &str) -> RegexpDiagnostic {
215    RegexpDiagnostic::error(format!("{PREFIX} Invalid unicode property {kind}")).with_label(span)
216}
217
218#[cold]
219pub fn invalid_unicode_property_of_strings(span: Span, name: &str) -> RegexpDiagnostic {
220    RegexpDiagnostic::error(format!("{PREFIX} Invalid unicode property `{name}`"))
221        .with_help("Enable `UnicodeSetsMode` to use this property")
222        .with_label(span)
223}
224
225#[cold]
226pub fn invalid_unicode_escape_sequence(span: Span) -> RegexpDiagnostic {
227    RegexpDiagnostic::error(format!("{PREFIX} Invalid unicode escape sequence")).with_label(span)
228}
229
230#[cold]
231pub fn invalid_surrogate_pair(span: Span) -> RegexpDiagnostic {
232    RegexpDiagnostic::error(format!("{PREFIX} Invalid surrogate pair")).with_label(span)
233}
234
235#[cold]
236pub fn invalid_modifiers(span: Span) -> RegexpDiagnostic {
237    RegexpDiagnostic::error(format!("{PREFIX} Invalid modifiers")).with_label(span)
238}
239
240#[cold]
241pub fn unknown_modifiers(span: Span) -> RegexpDiagnostic {
242    RegexpDiagnostic::error(format!("{PREFIX} Unknown modifiers")).with_label(span)
243}