1use std::borrow::Cow;
2
3use swc_atoms::Atom;
4use swc_common::{
5 errors::{DiagnosticBuilder, Handler},
6 Span,
7};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct Error {
12 inner: Box<(Span, ErrorKind)>,
13}
14
15impl Error {
16 pub fn kind(&self) -> &ErrorKind {
17 &self.inner.1
18 }
19
20 pub fn into_inner(self) -> Box<(Span, ErrorKind)> {
21 self.inner
22 }
23
24 pub fn new(span: Span, kind: ErrorKind) -> Self {
25 Error {
26 inner: Box::new((span, kind)),
27 }
28 }
29
30 pub fn message(&self) -> Cow<'static, str> {
31 match &self.inner.1 {
32 ErrorKind::Eof => "Unexpected end of file".into(),
33
34 ErrorKind::AbruptClosingOfEmptyComment => "Abrupt closing of empty comment".into(),
36 ErrorKind::AbruptDoctypePublicIdentifier => "Abrupt doctype public identifier".into(),
37 ErrorKind::AbruptDoctypeSystemIdentifier => "Abrupt doctype system identifier".into(),
38 ErrorKind::AbsenceOfDigitsInNumericCharacterReference => {
39 "Absence of digits in numeric character reference".into()
40 }
41 ErrorKind::CdataInHtmlContent => "Cdata in html content".into(),
42 ErrorKind::CharacterReferenceOutsideUnicodeRange => {
43 "Character reference outside unicode range".into()
44 }
45 ErrorKind::ControlCharacterInInputStream => "Control character in input stream".into(),
46 ErrorKind::ControlCharacterReference => "Control character reference".into(),
47 ErrorKind::EndTagWithAttributes => "End tag with attributes".into(),
48 ErrorKind::DuplicateAttribute => "Duplicate attribute".into(),
49 ErrorKind::EndTagWithTrailingSolidus => "End tag with trailing solidus".into(),
50 ErrorKind::EofBeforeTagName => "Eof before tag name".into(),
51 ErrorKind::EofInCdata => "Eof in cdata".into(),
52 ErrorKind::EofInComment => "Eof in comment".into(),
53 ErrorKind::EofInDoctype => "Eof in doctype".into(),
54 ErrorKind::EofInScriptHtmlCommentLikeText => {
55 "Eof in script html comment like text".into()
56 }
57 ErrorKind::EofInTag => "Eof in tag".into(),
58 ErrorKind::IncorrectlyClosedComment => "Incorrectly closed comment".into(),
59 ErrorKind::IncorrectlyOpenedComment => "Incorrectly opened comment".into(),
60 ErrorKind::InvalidCharacterSequenceAfterDoctypeName => {
61 "Invalid character sequence after doctype name".into()
62 }
63 ErrorKind::InvalidFirstCharacterOfTagName => {
64 "Invalid first character of tag name".into()
65 }
66 ErrorKind::MissingAttributeValue => "Missing attribute value".into(),
67 ErrorKind::MissingDoctypeName => "Missing doctype name".into(),
68 ErrorKind::MissingDoctypePublicIdentifier => "Missing doctype public identifier".into(),
69 ErrorKind::MissingDoctypeSystemIdentifier => "Missing doctype system identifier".into(),
70 ErrorKind::MissingEndTagName => "Missing end tag name".into(),
71 ErrorKind::MissingQuoteBeforeDoctypePublicIdentifier => {
72 "Missing quote before doctype public identifier".into()
73 }
74 ErrorKind::MissingQuoteBeforeDoctypeSystemIdentifier => {
75 "Missing quote before doctype system identifier".into()
76 }
77 ErrorKind::MissingSemicolonAfterCharacterReference => {
78 "Missing semicolon after character reference".into()
79 }
80 ErrorKind::MissingWhitespaceAfterDoctypePublicKeyword => {
81 "Missing whitespace after doctype public keyword".into()
82 }
83 ErrorKind::MissingWhitespaceAfterDoctypeSystemKeyword => {
84 "Missing whitespace after doctype system keyword".into()
85 }
86 ErrorKind::MissingWhitespaceBeforeDoctypeName => {
87 "Missing whitespace before doctype name".into()
88 }
89 ErrorKind::MissingWhitespaceBetweenAttributes => {
90 "Missing whitespace between attributes".into()
91 }
92 ErrorKind::MissingWhitespaceBetweenDoctypePublicAndSystemIdentifiers => {
93 "Missing whitespace between doctype public and system identifiers".into()
94 }
95 ErrorKind::NestedComment => "Nested comment".into(),
96 ErrorKind::NoncharacterCharacterReference => "Noncharacter character reference".into(),
97 ErrorKind::NoncharacterInInputStream => "Noncharacter in input stream".into(),
98 ErrorKind::NonVoidHtmlElementStartTagWithTrailingSolidus => {
99 "Non void html element start tag with trailing solidus".into()
100 }
101 ErrorKind::NullCharacterReference => "Null character reference".into(),
102 ErrorKind::SurrogateCharacterReference => "Surrogate character reference".into(),
103 ErrorKind::SurrogateInInputStream => "Surrogate in input stream".into(),
104 ErrorKind::UnexpectedCharacterAfterDoctypeSystemIdentifier => {
105 "Unexpected character after doctype system identifier".into()
106 }
107 ErrorKind::UnexpectedCharacterInAttributeName => {
108 "Unexpected character in attribute name".into()
109 }
110 ErrorKind::UnexpectedCharacterInUnquotedAttributeValue => {
111 "Unexpected character in unquoted attribute value".into()
112 }
113 ErrorKind::UnexpectedEqualsSignBeforeAttributeName => {
114 "Unexpected equals sign before attribute name".into()
115 }
116 ErrorKind::UnexpectedNullCharacter => "Unexpected null character".into(),
117 ErrorKind::UnexpectedQuestionMarkInsteadOfTagName => {
118 "Unexpected question mark instead of tag name".into()
119 }
120 ErrorKind::UnexpectedSolidusInTag => "Unexpected solidus in tag".into(),
121 ErrorKind::UnknownNamedCharacterReference => "Unknown named character reference".into(),
122
123 ErrorKind::StrayStartTag(tag_name) => format!("Stray start tag \"{tag_name}\"").into(),
125 ErrorKind::StrayEndTag(tag_name) => format!("Stray end tag \"{tag_name}\"").into(),
126 ErrorKind::UnclosedElements(tag_name) => {
127 format!("End tag \"{tag_name}\" seen, but there were open elements").into()
128 }
129 ErrorKind::UnclosedElementsImplied(tag_name) => {
130 format!("End tag \"{tag_name}\" implied, but there were open elements").into()
131 }
132 ErrorKind::UnclosedElementsCell => {
133 "A table cell was implicitly closed, but there were open elements".into()
134 }
135 ErrorKind::StrayDoctype => "Stray doctype".into(),
136 ErrorKind::NonConformingDoctype => "Non conforming doctype".into(),
137 ErrorKind::NonSpaceCharacterInTrailer => "Non-space character in page trailer".into(),
138 ErrorKind::NonSpaceCharacterAfterFrameset => {
139 "Non-space character after \"frameset\"".into()
140 }
141 ErrorKind::NonSpaceCharacterInFrameset => "Non-space character in \"frameset\"".into(),
142 ErrorKind::NonSpaceCharacterAfterBody => "Non-space character after body".into(),
143 ErrorKind::NonSpaceCharacterInColumnGroup => {
144 "Non-space character in \"colgroup\" element".into()
145 }
146 ErrorKind::NonSpaceCharacterInNoscriptInHead => {
147 "Non-space character inside \"noscript\" inside \"head\"".into()
148 }
149 ErrorKind::SomethingBetweenHeadAndBody(tag_name) => {
150 format!("\"{tag_name}\" element between \"head\" and \"body\"").into()
151 }
152 ErrorKind::StartTagWithoutDoctype => {
153 "Start tag seen without seeing a doctype first, expected \"<!DOCTYPE html>\"".into()
154 }
155 ErrorKind::StartSelectWhereEndSelectExpected => {
156 "\"select\" start tag where end tag expected".into()
157 }
158 ErrorKind::StartTagWithSelectOpen(tag_name) => {
159 format!("\"{tag_name}\" start tag with \"select\" open").into()
160 }
161 ErrorKind::BadStartTagInNoscriptInHead(tag_name) => {
162 format!("Bad start tag in \"{tag_name}\" in \"noscript\" in \"head\"").into()
163 }
164 ErrorKind::UnexpectedImageStartTag => {
165 "Saw a start tag \"image\", \"img\" element is outdated".into()
166 }
167 ErrorKind::SomethingSeenWhenSomethingOpen(tag_name) => format!(
168 "Start tag \"{tag_name}\" seen but an element of the same type was already open"
169 )
170 .into(),
171 ErrorKind::HeadingWhenHeadingOpen => {
172 "Heading cannot be a child of another heading".into()
173 }
174 ErrorKind::NoCellToClose => "No cell to close".into(),
175 ErrorKind::StartTagInTable(tag_name) => {
176 format!("Start tag \"{tag_name}\" seen in \"table\"").into()
177 }
178 ErrorKind::FormWhenFormOpen => "Saw a \"form\" start tag, but there was already an \
179 active \"form\" element, nested forms are not allowed"
180 .into(),
181 ErrorKind::TableSeenWhileTableOpen => {
182 "Start tag for \"table\" seen but the previous \"table\" is still open".into()
183 }
184 ErrorKind::StartTagInTableBody(tag_name) => {
185 format!("Start tag \"{tag_name}\" seen in \"table\" body").into()
186 }
187 ErrorKind::EndTagSeenWithoutDoctype => {
188 "End tag seen without seeing a doctype first, expected \"<!DOCTYPE html>\"".into()
189 }
190 ErrorKind::EndTagAfterBody => "Saw an end tag after \"body\" had been closed".into(),
191 ErrorKind::EndTagSeenWithSelectOpen(tag_name) => {
192 format!("\"{tag_name}\" end tag with \"select\" open").into()
193 }
194 ErrorKind::GarbageInColumnGroup => "Garbage in \"colgroup\" element".into(),
195 ErrorKind::EndTagBr => "End tag \"br\"".into(),
196 ErrorKind::NoElementToCloseButEndTagSeen(tag_name) => {
197 format!("No \"{tag_name}\" element in scope but a \"{tag_name}\" end tag seen")
198 .into()
199 }
200 ErrorKind::HtmlStartTagInForeignContext(tag_name) => {
201 format!("HTML start tag \"{tag_name}\" in a foreign namespace context").into()
202 }
203 ErrorKind::NoTableRowToClose => "No table row to close".into(),
204 ErrorKind::NonSpaceCharacterInTable => {
205 "Misplaced non-space characters inside a table".into()
206 }
207 ErrorKind::UnclosedChildrenInRuby => "Unclosed children in \"ruby\"".into(),
208 ErrorKind::StartTagSeenWithoutRuby(tag_name) => {
209 format!("Start tag \"{tag_name}\" seen without a \"ruby\" element being open")
210 .into()
211 }
212 ErrorKind::UnclosedElementsOnStack => "Unclosed elements on stack".into(),
213 ErrorKind::EndTagDidNotMatchCurrentOpenElement(
214 end_tag_name,
215 current_element_tag_name,
216 ) => format!(
217 "End tag \"{end_tag_name}\" did not match the name of the current open element \
218 (\"{current_element_tag_name}\")"
219 )
220 .into(),
221 ErrorKind::EndTagViolatesNestingRules(tag_name) => {
222 format!("End tag \"{tag_name}\" violates nesting rules").into()
223 }
224 ErrorKind::EofWithUnclosedElements => {
225 "End of file seen and there were open elements".into()
226 }
227 ErrorKind::EndTagWithUnclosedElements(tag_name) => {
228 format!("Unexpected end tag for \"{tag_name}\", but there were unclosed elements")
229 .into()
230 }
231 ErrorKind::NonSpaceCharacterWithoutDoctype => "Non-space characters found without \
232 seeing a doctype first, expected \
233 \"<!DOCTYPE html>\""
234 .into(),
235 ErrorKind::EofWithoutDoctype => "End of file seen without seeing a doctype first, \
236 expected \"<!DOCTYPE html>\""
237 .into(),
238 ErrorKind::EofInText => "End of file seen when expecting text or an end tag".into(),
239 }
240 }
241
242 pub fn to_diagnostics<'a>(&self, handler: &'a Handler) -> DiagnosticBuilder<'a> {
243 handler.struct_span_err(self.inner.0, &self.message())
244 }
245}
246
247#[derive(Debug, Clone, PartialEq, Eq)]
248#[non_exhaustive]
249pub enum ErrorKind {
250 Eof,
251
252 AbruptClosingOfEmptyComment,
254 AbruptDoctypePublicIdentifier,
255 AbruptDoctypeSystemIdentifier,
256 AbsenceOfDigitsInNumericCharacterReference,
257 CdataInHtmlContent,
258 CharacterReferenceOutsideUnicodeRange,
259 ControlCharacterInInputStream,
260 ControlCharacterReference,
261 EndTagWithAttributes,
262 DuplicateAttribute,
263 EndTagWithTrailingSolidus,
264 EofBeforeTagName,
265 EofInCdata,
266 EofInComment,
267 EofInDoctype,
268 EofInScriptHtmlCommentLikeText,
269 EofInTag,
270 IncorrectlyClosedComment,
271 IncorrectlyOpenedComment,
272 InvalidCharacterSequenceAfterDoctypeName,
273 InvalidFirstCharacterOfTagName,
274 MissingAttributeValue,
275 MissingDoctypeName,
276 MissingDoctypePublicIdentifier,
277 MissingDoctypeSystemIdentifier,
278 MissingEndTagName,
279 MissingQuoteBeforeDoctypePublicIdentifier,
280 MissingQuoteBeforeDoctypeSystemIdentifier,
281 MissingSemicolonAfterCharacterReference,
282 MissingWhitespaceAfterDoctypePublicKeyword,
283 MissingWhitespaceAfterDoctypeSystemKeyword,
284 MissingWhitespaceBeforeDoctypeName,
285 MissingWhitespaceBetweenAttributes,
286 MissingWhitespaceBetweenDoctypePublicAndSystemIdentifiers,
287 NestedComment,
288 NoncharacterCharacterReference,
289 NoncharacterInInputStream,
290 NonVoidHtmlElementStartTagWithTrailingSolidus,
291 NullCharacterReference,
292 SurrogateCharacterReference,
293 SurrogateInInputStream,
294 UnexpectedCharacterAfterDoctypeSystemIdentifier,
295 UnexpectedCharacterInAttributeName,
296 UnexpectedCharacterInUnquotedAttributeValue,
297 UnexpectedEqualsSignBeforeAttributeName,
298 UnexpectedNullCharacter,
299 UnexpectedQuestionMarkInsteadOfTagName,
300 UnexpectedSolidusInTag,
301 UnknownNamedCharacterReference,
302
303 StrayStartTag(Atom),
305 StrayEndTag(Atom),
306 UnclosedElements(Atom),
307 UnclosedElementsImplied(Atom),
308 UnclosedElementsCell,
309 StrayDoctype,
310 NonConformingDoctype,
311 NonSpaceCharacterInTrailer,
312 NonSpaceCharacterAfterFrameset,
313 NonSpaceCharacterInFrameset,
314 NonSpaceCharacterAfterBody,
315 NonSpaceCharacterInColumnGroup,
316 NonSpaceCharacterInNoscriptInHead,
317 SomethingBetweenHeadAndBody(Atom),
318 StartTagWithoutDoctype,
319 StartSelectWhereEndSelectExpected,
320 StartTagWithSelectOpen(Atom),
321 BadStartTagInNoscriptInHead(Atom),
322 UnexpectedImageStartTag,
323 SomethingSeenWhenSomethingOpen(Atom),
324 HeadingWhenHeadingOpen,
325 NoCellToClose,
326 StartTagInTable(Atom),
327 FormWhenFormOpen,
328 TableSeenWhileTableOpen,
329 StartTagInTableBody(Atom),
330 EndTagSeenWithoutDoctype,
331 EndTagAfterBody,
332 EndTagSeenWithSelectOpen(Atom),
333 GarbageInColumnGroup,
334 EndTagBr,
335 NoElementToCloseButEndTagSeen(Atom),
336 HtmlStartTagInForeignContext(Atom),
337 NoTableRowToClose,
338 NonSpaceCharacterInTable,
339 UnclosedChildrenInRuby,
340 StartTagSeenWithoutRuby(Atom),
341 UnclosedElementsOnStack,
342 EndTagDidNotMatchCurrentOpenElement(Atom, Atom),
343 EndTagViolatesNestingRules(Atom),
344 EofWithUnclosedElements,
345 EndTagWithUnclosedElements(Atom),
346 NonSpaceCharacterWithoutDoctype,
347 EofWithoutDoctype,
348 EofInText,
349}