diff --git a/crates/oxc_diagnostics/src/lib.rs b/crates/oxc_diagnostics/src/lib.rs index be5dbb7608647..08a666e91bd6c 100644 --- a/crates/oxc_diagnostics/src/lib.rs +++ b/crates/oxc_diagnostics/src/lib.rs @@ -20,10 +20,12 @@ pub use crate::{ pub type Error = miette::Error; pub type Severity = miette::Severity; pub type Report = miette::Report; +pub type OxcDiagnostic = miette::MietteDiagnostic; pub type Result = std::result::Result; use miette::Diagnostic; +pub use miette::LabeledSpan; use thiserror::Error; #[derive(Debug, Error, Diagnostic)] diff --git a/crates/oxc_parser/src/cursor.rs b/crates/oxc_parser/src/cursor.rs index 35f910e572091..134d863e9cd31 100644 --- a/crates/oxc_parser/src/cursor.rs +++ b/crates/oxc_parser/src/cursor.rs @@ -107,7 +107,7 @@ impl<'a> ParserImpl<'a> { fn test_escaped_keyword(&mut self, kind: Kind) { if self.cur_token().escaped() && kind.is_all_keyword() { let span = self.cur_token().span(); - self.error(diagnostics::EscapedKeyword(span)); + self.error(diagnostics::escaped_keyword(span)); } } @@ -158,7 +158,7 @@ impl<'a> ParserImpl<'a> { pub(crate) fn asi(&mut self) -> Result<()> { if !self.can_insert_semicolon() { let span = Span::new(self.prev_token_end, self.cur_token().start); - return Err(diagnostics::AutoSemicolonInsertion(span).into()); + return Err(diagnostics::auto_semicolon_insertion(span).into()); } if self.at(Kind::Semicolon) { self.advance(Kind::Semicolon); @@ -179,7 +179,7 @@ impl<'a> ParserImpl<'a> { if !self.at(kind) { let range = self.cur_token().span(); return Err( - diagnostics::ExpectToken(kind.to_str(), self.cur_kind().to_str(), range).into() + diagnostics::expect_token(kind.to_str(), self.cur_kind().to_str(), range).into() ); } Ok(()) diff --git a/crates/oxc_parser/src/diagnostics.rs b/crates/oxc_parser/src/diagnostics.rs index 9e09e2450ec09..484dac18dc576 100644 --- a/crates/oxc_parser/src/diagnostics.rs +++ b/crates/oxc_parser/src/diagnostics.rs @@ -1,338 +1,330 @@ -use oxc_diagnostics::{ - miette::{self, Diagnostic}, - thiserror::{self, Error}, -}; +use oxc_diagnostics::{LabeledSpan, OxcDiagnostic}; use oxc_span::Span; -#[derive(Debug, Error, Diagnostic)] -#[error("Source length exceeds 4 GiB limit")] -#[diagnostic()] -pub struct OverlongSource; - -#[derive(Debug, Error, Diagnostic)] -#[error("Flow is not supported")] -#[diagnostic()] -pub struct Flow(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Unexpected token")] -#[diagnostic()] -pub struct UnexpectedToken(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Expected `{0}` but found `{1}`")] -#[diagnostic()] -pub struct ExpectToken(pub &'static str, pub &'static str, #[label("`{0}` expected")] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Invalid escape sequence")] -pub struct InvalidEscapeSequence(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Invalid Unicode escape sequence")] -pub struct UnicodeEscapeSequence(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Invalid Character `{0}`")] -pub struct InvalidCharacter(pub char, #[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Invalid characters after number")] -pub struct InvalidNumberEnd(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Unterminated multiline comment")] -pub struct UnterminatedMultiLineComment(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Unterminated string")] -pub struct UnterminatedString(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Unexpected flag {0} in regular expression literal")] -pub struct RegExpFlag(pub char, #[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Flag {0} is mentioned twice in regular expression literal")] -pub struct RegExpFlagTwice(pub char, #[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Unexpected end of file")] -pub struct UnexpectedEnd(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Unterminated regular expression")] -pub struct UnterminatedRegExp(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Invalid Number {0}")] -pub struct InvalidNumber(pub &'static str, #[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Keywords cannot contain escape characters")] -#[diagnostic()] -pub struct EscapedKeyword(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Expected a semicolon or an implicit semicolon after a statement, but found none")] -#[diagnostic(help("Try insert a semicolon here"))] -pub struct AutoSemicolonInsertion(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Line terminator not permitted before arrow")] -#[diagnostic()] -pub struct LineterminatorBeforeArrow(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Missing initializer in destructuring declaration")] -#[diagnostic()] -pub struct InvalidDestrucuringDeclaration(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Missing initializer in const declaration")] -#[diagnostic()] -pub struct MissinginitializerInConst(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Lexical declaration cannot appear in a single-statement context")] -#[diagnostic(help("Wrap this declaration in a block statement"))] -pub struct LexicalDeclarationSingleStatement(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Async functions can only be declared at the top level or inside a block")] -#[diagnostic()] -pub struct AsyncFunctionDeclaration(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Generators can only be declared at the top level or inside a block")] -#[diagnostic()] -pub struct GeneratorFunctionDeclaration(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("`await` is only allowed within async functions and at the top levels of modules")] -#[diagnostic()] -pub struct AwaitExpression(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("A 'yield' expression is only allowed in a generator body.")] -#[diagnostic()] -pub struct YieldExpression(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Invalid class declaration")] -#[diagnostic(help("Classes can only be declared at top level or inside a block"))] -pub struct ClassDeclaration(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("A rest element must be last in a destructuring pattern")] -#[diagnostic()] -pub struct BindingRestElementLast(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("A rest parameter must be last in a parameter list")] -#[diagnostic()] -pub struct RestParameterLast(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Spread must be last element")] -#[diagnostic()] -pub struct SpreadLastElement(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Unexpected trailing comma after rest element")] -#[diagnostic()] -pub struct BindingRestElementTrailingComma(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Invalid rest element")] -#[diagnostic(help("Expected identifier in rest element"))] -pub struct InvalidBindingRestElement(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("A rest parameter cannot be optional")] -#[diagnostic()] -pub struct ARestParameterCannotBeOptional(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Cannot assign to this expression")] -#[diagnostic()] -pub struct InvalidAssignment(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Optional chaining cannot appear in the callee of new expressions")] -#[diagnostic()] -pub struct NewOptionalChain(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("The left-hand side of a `for...of` statement may not be `async`")] -#[diagnostic()] -pub struct ForLoopAsyncOf(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("await can only be used in conjunction with `for...of` statements")] -#[diagnostic()] -pub struct ForAwait(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Cannot use new with dynamic import")] -#[diagnostic()] -pub struct NewDynamicImport(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Classes can't have an element named '#constructor'")] -#[diagnostic()] -pub struct PrivateNameConstructor(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Classes may not have a static property named prototype")] -#[diagnostic()] -pub struct StaticPrototype(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Constructor can't have get/set modifier")] -#[diagnostic()] -pub struct ConstructorGetterSetter(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Constructor can't be an async method")] -#[diagnostic()] -pub struct ConstructorAsync(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Cannot use `{0}` as an identifier in an async context")] -#[diagnostic()] -pub struct IdentifierAsync(pub &'static str, #[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Cannot use `{0}` as an identifier in a generator context")] -#[diagnostic()] -pub struct IdentifierGenerator(pub &'static str, #[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Constructor can't be a generator")] -#[diagnostic()] -pub struct ConstructorGenerator(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Classes can't have a field named 'constructor'")] -#[diagnostic()] -pub struct FieldConstructor(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("An export name cannot include a unicode lone surrogate")] -#[diagnostic()] -pub struct ExportLoneSurrogate(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("A string literal cannot be used as an exported binding without `from`")] -#[diagnostic(help("Did you mean `export {{ {0} as {1} }} from 'some-module'`?"))] -pub struct ExportNamedString(pub String, pub String, #[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("A reserved word cannot be used as an exported binding without `from`")] -#[diagnostic(help("Did you mean `export {{ {0} as {1} }} from 'some-module'`?"))] -pub struct ExportReservedWord(pub String, pub String, #[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Bad escape sequence in untagged template literal")] -#[diagnostic()] -pub struct TemplateLiteral(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Empty parenthesized expression")] -#[diagnostic()] -pub struct EmptyParenthesizedExpression(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Illegal newline after {0}")] -#[diagnostic()] -pub struct IllegalNewline( - pub &'static str, - #[label("{0} starts here")] pub Span, - #[label("A newline is not expected here")] pub Span, -); - -#[derive(Debug, Error, Diagnostic)] -#[error("Tagged template expressions are not permitted in an optional chain")] -#[diagnostic()] -pub struct OptionalChainTaggedTemplate(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("TS2681: A constructor cannot have a `this` parameter.")] -#[diagnostic()] -pub struct TSConstructorThisParameter(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("TS2730: An arrow function cannot have a `this` parameter.")] -#[diagnostic()] -pub struct TSArrowFunctionThisParameter(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("'super' can only be used with function calls or in property accesses")] -#[diagnostic(help("replace with `super()` or `super.prop` or `super[prop]`"))] -pub struct UnexpectedSuper(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Expected function name")] -#[diagnostic(help("Function name is required in function declaration or named export"))] -pub struct ExpectFunctionName(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Missing catch or finally clause")] -#[diagnostic()] -pub struct ExpectCatchFinally(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("TS1095: A 'set' accessor cannot have a return type annotation")] -#[diagnostic()] -pub struct ASetAccessorCannotHaveAReturnTypeAnnotation(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("TS1108: A 'return' statement can only be used within a function body")] -#[diagnostic()] -pub struct ReturnStatementOnlyInFunctionBody(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("TS18007: JSX expressions may not use the comma operator.")] -#[diagnostic(help("Did you mean to write an array?"))] -pub struct JSXExpressionsMayNotUseTheCommaOperator(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Line terminator not permitted before using declaration.")] -#[diagnostic()] -pub struct LineTerminatorBeforeUsingDeclaration(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Await is not allowed in using declarations.")] -#[diagnostic()] -pub struct AwaitInUsingDeclaration(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Using declarations may not have binding patterns.")] -#[diagnostic()] -pub struct InvalidIdentifierInUsingDeclaration(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("The left-hand side of a for...in statement cannot be an await using declaration.")] -#[diagnostic()] -pub struct AwaitUsingDeclarationNotAllowedInForInStatement(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("The left-hand side of a for...in statement cannot be an using declaration.")] -#[diagnostic()] -pub struct UsingDeclarationNotAllowedInForInStatement(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("Using declarations must have an initializer.")] -#[diagnostic()] -pub struct UsingDeclarationsMustBeInitialized(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("TS1089: `static` modifier cannot appear on a constructor declaration.")] -#[diagnostic()] -pub struct StaticConstructor(#[label] pub Span); - -#[derive(Debug, Error, Diagnostic)] -#[error("No line break is allowed before '=>'.")] -#[diagnostic()] -pub struct NoLineBreakIsAllowedBeforeArrow(#[label] pub Span); +pub fn overlong_source() -> OxcDiagnostic { + OxcDiagnostic::new("Source length exceeds 4 GiB limit") +} + +pub fn flow(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Flow is not supported").with_labels([span0.into()]) +} + +pub fn unexpected_token(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Unexpected token").with_labels([span0.into()]) +} + +pub fn expect_token(x0: &str, x1: &str, span2: Span) -> OxcDiagnostic { + OxcDiagnostic::new(format!("Expected `{x0}` but found `{x1}`")) + .with_labels([LabeledSpan::new_with_span(Some(format!("`{x0}` expected")), span2)]) +} + +pub fn invalid_escape_sequence(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Invalid escape sequence").with_labels([span0.into()]) +} + +pub fn unicode_escape_sequence(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Invalid Unicode escape sequence").with_labels([span0.into()]) +} + +pub fn invalid_character(x0: char, span1: Span) -> OxcDiagnostic { + OxcDiagnostic::new(format!("Invalid Character `{x0}`")).with_labels([span1.into()]) +} + +pub fn invalid_number_end(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Invalid characters after number").with_labels([span0.into()]) +} + +pub fn unterminated_multi_line_comment(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Unterminated multiline comment").with_labels([span0.into()]) +} + +pub fn unterminated_string(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Unterminated string").with_labels([span0.into()]) +} + +pub fn reg_exp_flag(x0: char, span1: Span) -> OxcDiagnostic { + OxcDiagnostic::new(format!("Unexpected flag {x0} in regular expression literal")) + .with_labels([span1.into()]) +} + +pub fn reg_exp_flag_twice(x0: char, span1: Span) -> OxcDiagnostic { + OxcDiagnostic::new(format!("Flag {x0} is mentioned twice in regular expression literal")) + .with_labels([span1.into()]) +} + +pub fn unexpected_end(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Unexpected end of file").with_labels([span0.into()]) +} + +pub fn unterminated_reg_exp(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Unterminated regular expression").with_labels([span0.into()]) +} + +pub fn invalid_number(x0: &str, span1: Span) -> OxcDiagnostic { + OxcDiagnostic::new(format!("Invalid Number {x0}")).with_labels([span1.into()]) +} + +pub fn escaped_keyword(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Keywords cannot contain escape characters").with_labels([span0.into()]) +} + +pub fn auto_semicolon_insertion(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new( + "Expected a semicolon or an implicit semicolon after a statement, but found none", + ) + .with_help("Try insert a semicolon here") + .with_labels([span0.into()]) +} + +pub fn lineterminator_before_arrow(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Line terminator not permitted before arrow").with_labels([span0.into()]) +} + +pub fn invalid_destrucuring_declaration(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Missing initializer in destructuring declaration") + .with_labels([span0.into()]) +} + +pub fn missinginitializer_in_const(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Missing initializer in const declaration").with_labels([span0.into()]) +} + +pub fn lexical_declaration_single_statement(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Lexical declaration cannot appear in a single-statement context") + .with_help("Wrap this declaration in a block statement") + .with_labels([span0.into()]) +} + +pub fn async_function_declaration(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Async functions can only be declared at the top level or inside a block") + .with_labels([span0.into()]) +} + +pub fn generator_function_declaration(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Generators can only be declared at the top level or inside a block") + .with_labels([span0.into()]) +} + +pub fn await_expression(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new( + "`await` is only allowed within async functions and at the top levels of modules", + ) + .with_labels([span0.into()]) +} + +pub fn yield_expression(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("A 'yield' expression is only allowed in a generator body.") + .with_labels([span0.into()]) +} + +pub fn class_declaration(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Invalid class declaration") + .with_help("Classes can only be declared at top level or inside a block") + .with_labels([span0.into()]) +} + +pub fn binding_rest_element_last(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("A rest element must be last in a destructuring pattern") + .with_labels([span0.into()]) +} + +pub fn rest_parameter_last(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("A rest parameter must be last in a parameter list") + .with_labels([span0.into()]) +} + +pub fn spread_last_element(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Spread must be last element").with_labels([span0.into()]) +} + +pub fn binding_rest_element_trailing_comma(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Unexpected trailing comma after rest element").with_labels([span0.into()]) +} + +pub fn invalid_binding_rest_element(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Invalid rest element") + .with_help("Expected identifier in rest element") + .with_labels([span0.into()]) +} + +pub fn a_rest_parameter_cannot_be_optional(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("A rest parameter cannot be optional").with_labels([span0.into()]) +} + +pub fn invalid_assignment(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Cannot assign to this expression").with_labels([span0.into()]) +} + +pub fn new_optional_chain(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Optional chaining cannot appear in the callee of new expressions") + .with_labels([span0.into()]) +} + +pub fn for_loop_async_of(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("The left-hand side of a `for...of` statement may not be `async`") + .with_labels([span0.into()]) +} + +pub fn for_await(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("await can only be used in conjunction with `for...of` statements") + .with_labels([span0.into()]) +} + +pub fn new_dynamic_import(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Cannot use new with dynamic import").with_labels([span0.into()]) +} + +pub fn private_name_constructor(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Classes can't have an element named '#constructor'") + .with_labels([span0.into()]) +} + +pub fn static_prototype(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Classes may not have a static property named prototype") + .with_labels([span0.into()]) +} + +pub fn constructor_getter_setter(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Constructor can't have get/set modifier").with_labels([span0.into()]) +} + +pub fn constructor_async(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Constructor can't be an async method").with_labels([span0.into()]) +} + +pub fn identifier_async(x0: &str, span1: Span) -> OxcDiagnostic { + OxcDiagnostic::new(format!("Cannot use `{x0}` as an identifier in an async context")) + .with_labels([span1.into()]) +} + +pub fn identifier_generator(x0: &str, span1: Span) -> OxcDiagnostic { + OxcDiagnostic::new(format!("Cannot use `{x0}` as an identifier in a generator context")) + .with_labels([span1.into()]) +} + +pub fn constructor_generator(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Constructor can't be a generator").with_labels([span0.into()]) +} + +pub fn field_constructor(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Classes can't have a field named 'constructor'").with_labels([span0.into()]) +} + +pub fn export_lone_surrogate(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("An export name cannot include a unicode lone surrogate") + .with_labels([span0.into()]) +} + +pub fn export_named_string(x0: &str, x1: &str, span2: Span) -> OxcDiagnostic { + OxcDiagnostic::new("A string literal cannot be used as an exported binding without `from`") + .with_help(format!("Did you mean `export {{ {x0} as {x1} }} from 'some-module'`?")) + .with_labels([span2.into()]) +} + +pub fn export_reserved_word(x0: &str, x1: &str, span2: Span) -> OxcDiagnostic { + OxcDiagnostic::new("A reserved word cannot be used as an exported binding without `from`") + .with_help(format!("Did you mean `export {{ {x0} as {x1} }} from 'some-module'`?")) + .with_labels([span2.into()]) +} + +pub fn template_literal(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Bad escape sequence in untagged template literal") + .with_labels([span0.into()]) +} + +pub fn empty_parenthesized_expression(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Empty parenthesized expression").with_labels([span0.into()]) +} + +pub fn illegal_newline(x0: &str, span1: Span, span2: Span) -> OxcDiagnostic { + OxcDiagnostic::new(format!("Illegal newline after {x0}")).with_labels([ + LabeledSpan::new_with_span(Some(format!("{x0} starts here")), span1), + LabeledSpan::new_with_span(Some("A newline is not expected here".to_string()), span2), + ]) +} + +pub fn optional_chain_tagged_template(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Tagged template expressions are not permitted in an optional chain") + .with_labels([span0.into()]) +} + +pub fn ts_constructor_this_parameter(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("TS2681: A constructor cannot have a `this` parameter.") + .with_labels([span0.into()]) +} + +pub fn ts_arrow_function_this_parameter(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("TS2730: An arrow function cannot have a `this` parameter.") + .with_labels([span0.into()]) +} + +pub fn unexpected_super(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("'super' can only be used with function calls or in property accesses") + .with_help("replace with `super()` or `super.prop` or `super[prop]`") + .with_labels([span0.into()]) +} + +pub fn expect_function_name(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Expected function name") + .with_help("Function name is required in function declaration or named export") + .with_labels([span0.into()]) +} + +pub fn expect_catch_finally(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Missing catch or finally clause").with_labels([span0.into()]) +} + +pub fn a_set_accessor_cannot_have_a_return_type_annotation(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("TS1095: A 'set' accessor cannot have a return type annotation") + .with_labels([span0.into()]) +} + +pub fn return_statement_only_in_function_body(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("TS1108: A 'return' statement can only be used within a function body") + .with_labels([span0.into()]) +} + +pub fn jsx_expressions_may_not_use_the_comma_operator(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("TS18007: JSX expressions may not use the comma operator.") + .with_help("Did you mean to write an array?") + .with_labels([span0.into()]) +} + +pub fn line_terminator_before_using_declaration(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Line terminator not permitted before using declaration.") + .with_labels([span0.into()]) +} + +pub fn await_in_using_declaration(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Await is not allowed in using declarations.").with_labels([span0.into()]) +} + +pub fn invalid_identifier_in_using_declaration(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Using declarations may not have binding patterns.") + .with_labels([span0.into()]) +} + +pub fn await_using_declaration_not_allowed_in_for_in_statement(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new( + "The left-hand side of a for...in statement cannot be an await using declaration.", + ) + .with_labels([span0.into()]) +} + +pub fn using_declaration_not_allowed_in_for_in_statement(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("The left-hand side of a for...in statement cannot be an using declaration.") + .with_labels([span0.into()]) +} + +pub fn using_declarations_must_be_initialized(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("Using declarations must have an initializer.").with_labels([span0.into()]) +} + +pub fn static_constructor(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("TS1089: `static` modifier cannot appear on a constructor declaration.") + .with_labels([span0.into()]) +} + +pub fn no_line_break_is_allowed_before_arrow(span0: Span) -> OxcDiagnostic { + OxcDiagnostic::new("No line break is allowed before '=>'.").with_labels([span0.into()]) +} diff --git a/crates/oxc_parser/src/js/binding.rs b/crates/oxc_parser/src/js/binding.rs index f284409113d22..96ff6ae464a30 100644 --- a/crates/oxc_parser/src/js/binding.rs +++ b/crates/oxc_parser/src/js/binding.rs @@ -68,7 +68,7 @@ impl<'a> ParserImpl<'a> { if self.at(Kind::Question) && self.ts_enabled() { let span = self.cur_token().span(); self.bump_any(); - self.error(diagnostics::ARestParameterCannotBeOptional(span)); + self.error(diagnostics::a_rest_parameter_cannot_be_optional(span)); } // The span is not extended to its type_annotation let type_annotation = self.parse_ts_type_annotation()?; @@ -80,9 +80,11 @@ impl<'a> ParserImpl<'a> { if self.at(Kind::Comma) { if self.peek_at(Kind::RBrack) { - self.error(diagnostics::BindingRestElementTrailingComma(self.cur_token().span())); + self.error(diagnostics::binding_rest_element_trailing_comma( + self.cur_token().span(), + )); } else if !self.ctx.has_ambient() { - self.error(diagnostics::BindingRestElementLast(span)); + self.error(diagnostics::binding_rest_element_last(span)); } } diff --git a/crates/oxc_parser/src/js/class.rs b/crates/oxc_parser/src/js/class.rs index 806d799e9204e..5c06a80b84d69 100644 --- a/crates/oxc_parser/src/js/class.rs +++ b/crates/oxc_parser/src/js/class.rs @@ -22,7 +22,7 @@ impl<'a> ParserImpl<'a> { let decl = self.parse_class_declaration(start_span, Modifiers::empty())?; if stmt_ctx.is_single_statement() { - self.error(diagnostics::ClassDeclaration(Span::new( + self.error(diagnostics::class_declaration(Span::new( decl.span.start, decl.body.span.start, ))); @@ -253,7 +253,7 @@ impl<'a> ParserImpl<'a> { if let PropertyKey::PrivateIdentifier(private_ident) = &key { if private_ident.name == "constructor" { - self.error(diagnostics::PrivateNameConstructor(private_ident.span)); + self.error(diagnostics::private_name_constructor(private_ident.span)); } } @@ -281,17 +281,17 @@ impl<'a> ParserImpl<'a> { )?; if let Some((name, span)) = definition.prop_name() { if r#static && name == "prototype" && !self.ctx.has_ambient() { - self.error(diagnostics::StaticPrototype(span)); + self.error(diagnostics::static_prototype(span)); } if !r#static && name == "constructor" { if kind == MethodDefinitionKind::Get || kind == MethodDefinitionKind::Set { - self.error(diagnostics::ConstructorGetterSetter(span)); + self.error(diagnostics::constructor_getter_setter(span)); } if r#async { - self.error(diagnostics::ConstructorAsync(span)); + self.error(diagnostics::constructor_async(span)); } if generator { - self.error(diagnostics::ConstructorGenerator(span)); + self.error(diagnostics::constructor_generator(span)); } } } @@ -316,10 +316,10 @@ impl<'a> ParserImpl<'a> { )?; if let Some((name, span)) = definition.prop_name() { if name == "constructor" { - self.error(diagnostics::FieldConstructor(span)); + self.error(diagnostics::field_constructor(span)); } if r#static && name == "prototype" && !self.ctx.has_ambient() { - self.error(diagnostics::StaticPrototype(span)); + self.error(diagnostics::static_prototype(span)); } } Ok(definition) @@ -367,11 +367,11 @@ impl<'a> ParserImpl<'a> { if kind == MethodDefinitionKind::Constructor { if let Some(this_param) = &value.this_param { // class Foo { constructor(this: number) {} } - self.error(diagnostics::TSConstructorThisParameter(this_param.span)); + self.error(diagnostics::ts_constructor_this_parameter(this_param.span)); } if r#static { - self.error(diagnostics::StaticConstructor(key.span())); + self.error(diagnostics::static_constructor(key.span())); } } diff --git a/crates/oxc_parser/src/js/declaration.rs b/crates/oxc_parser/src/js/declaration.rs index e2ffb5f60786d..2fb984d4f796f 100644 --- a/crates/oxc_parser/src/js/declaration.rs +++ b/crates/oxc_parser/src/js/declaration.rs @@ -126,10 +126,10 @@ impl<'a> ParserImpl<'a> { // BindingPattern[?Yield, ?Await] Initializer[?In, ?Yield, ?Await] // the grammar forbids `let []`, `let {}` if !matches!(id.kind, BindingPatternKind::BindingIdentifier(_)) { - self.error(diagnostics::InvalidDestrucuringDeclaration(id.span())); + self.error(diagnostics::invalid_destrucuring_declaration(id.span())); } else if kind == VariableDeclarationKind::Const && !self.ctx.has_ambient() { // It is a Syntax Error if Initializer is not present and IsConstantDeclaration of the LexicalDeclaration containing this LexicalBinding is true. - self.error(diagnostics::MissinginitializerInConst(id.span())); + self.error(diagnostics::missinginitializer_in_const(id.span())); } } @@ -151,12 +151,14 @@ impl<'a> ParserImpl<'a> { // `[no LineTerminator here]` if self.cur_token().is_on_new_line { - self.error(diagnostics::LineTerminatorBeforeUsingDeclaration(self.cur_token().span())); + self.error(diagnostics::line_terminator_before_using_declaration( + self.cur_token().span(), + )); } // [lookahead ≠ await] if self.cur_kind() == Kind::Await { - self.error(diagnostics::AwaitInUsingDeclaration(self.cur_token().span())); + self.error(diagnostics::await_in_using_declaration(self.cur_token().span())); self.eat(Kind::Await); } @@ -171,7 +173,7 @@ impl<'a> ParserImpl<'a> { match declaration.id.kind { BindingPatternKind::BindingIdentifier(_) => {} _ => { - self.error(diagnostics::InvalidIdentifierInUsingDeclaration( + self.error(diagnostics::invalid_identifier_in_using_declaration( declaration.id.span(), )); } @@ -179,7 +181,9 @@ impl<'a> ParserImpl<'a> { // Excluding `for` loops, an initializer is required in a UsingDeclaration. if declaration.init.is_none() && !matches!(statement_ctx, StatementContext::For) { - self.error(diagnostics::UsingDeclarationsMustBeInitialized(declaration.id.span())); + self.error(diagnostics::using_declarations_must_be_initialized( + declaration.id.span(), + )); } declarations.push(declaration); diff --git a/crates/oxc_parser/src/js/expression.rs b/crates/oxc_parser/src/js/expression.rs index 7d90b6a261a16..67ebbe586bd28 100644 --- a/crates/oxc_parser/src/js/expression.rs +++ b/crates/oxc_parser/src/js/expression.rs @@ -117,11 +117,11 @@ impl<'a> ParserImpl<'a> { pub(crate) fn check_identifier(&mut self, span: Span, name: &Atom) { // It is a Syntax Error if this production has an [Await] parameter. if self.ctx.has_await() && *name == "await" { - self.error(diagnostics::IdentifierAsync("await", span)); + self.error(diagnostics::identifier_async("await", span)); } // It is a Syntax Error if this production has a [Yield] parameter. if self.ctx.has_yield() && *name == "yield" { - self.error(diagnostics::IdentifierGenerator("yield", span)); + self.error(diagnostics::identifier_generator("yield", span)); } } @@ -214,7 +214,7 @@ impl<'a> ParserImpl<'a> { let paren_span = self.end_span(span); if expressions.is_empty() { - return Err(diagnostics::EmptyParenthesizedExpression(paren_span).into()); + return Err(diagnostics::empty_parenthesized_expression(paren_span).into()); } // ParenthesizedExpression is from acorn --preserveParens @@ -294,7 +294,7 @@ impl<'a> ParserImpl<'a> { Kind::Float | Kind::PositiveExponential | Kind::NegativeExponential => parse_float(src), _ => unreachable!(), } - .map_err(|err| diagnostics::InvalidNumber(err, token.span()))?; + .map_err(|err| diagnostics::invalid_number(err, token.span()))?; let base = match token.kind { Kind::Decimal => NumberBase::Decimal, Kind::Float => NumberBase::Float, @@ -327,7 +327,7 @@ impl<'a> ParserImpl<'a> { let raw = self.cur_src(); let src = raw.strip_suffix('n').unwrap(); let _value = parse_big_int(src, token.kind) - .map_err(|err| diagnostics::InvalidNumber(err, token.span()))?; + .map_err(|err| diagnostics::invalid_number(err, token.span()))?; self.bump_any(); Ok(self.ast.bigint_literal(self.end_span(span), Atom::from(raw), base)) } @@ -437,7 +437,7 @@ impl<'a> ParserImpl<'a> { // It is a Syntax Error if any source text is matched by this production. // if in_optional_chain { - self.error(diagnostics::OptionalChainTaggedTemplate(quasi.span)); + self.error(diagnostics::optional_chain_tagged_template(quasi.span)); } Ok(self.ast.tagged_template_expression(span, lhs, quasi, type_parameters)) } @@ -470,7 +470,7 @@ impl<'a> ParserImpl<'a> { span.end -= end_offset; if !tagged && cooked.is_none() { - self.error(diagnostics::TemplateLiteral(span)); + self.error(diagnostics::template_literal(span)); } let tail = matches!(cur_kind, Kind::TemplateTail | Kind::NoSubstitutionTemplate); @@ -547,7 +547,7 @@ impl<'a> ParserImpl<'a> { // SuperCall: // super ( Arguments ) if !matches!(self.cur_kind(), Kind::Dot | Kind::LBrack | Kind::LParen) { - self.error(diagnostics::UnexpectedSuper(span)); + self.error(diagnostics::unexpected_super(span)); } self.ast.super_(span) @@ -689,13 +689,13 @@ impl<'a> ParserImpl<'a> { }; if matches!(callee, Expression::ImportExpression(_)) { - self.error(diagnostics::NewDynamicImport(self.end_span(rhs_span))); + self.error(diagnostics::new_dynamic_import(self.end_span(rhs_span))); } let span = self.end_span(span); if optional { - self.error(diagnostics::NewOptionalChain(span)); + self.error(diagnostics::new_optional_chain(span)); } Ok(self.ast.new_expression(span, callee, arguments, type_parameter)) @@ -975,7 +975,7 @@ impl<'a> ParserImpl<'a> { self.bump_any(); // bump async let arrow_token = self.peek_token(); if arrow_token.is_on_new_line { - self.error(diagnostics::NoLineBreakIsAllowedBeforeArrow(arrow_token.span())); + self.error(diagnostics::no_line_break_is_allowed_before_arrow(arrow_token.span())); } self.parse_single_param_function_expression(span, true, false) } else { @@ -1042,7 +1042,7 @@ impl<'a> ParserImpl<'a> { self.bump_any(); let has_await = self.ctx.has_await(); if !has_await { - self.error(diagnostics::AwaitExpression(Span::new(span.start, span.start + 5))); + self.error(diagnostics::await_expression(Span::new(span.start, span.start + 5))); } self.ctx = self.ctx.and_await(true); let argument = self.parse_unary_expression_base(lhs_span)?; diff --git a/crates/oxc_parser/src/js/function.rs b/crates/oxc_parser/src/js/function.rs index 572eb6c753ded..023b91aa6e80e 100644 --- a/crates/oxc_parser/src/js/function.rs +++ b/crates/oxc_parser/src/js/function.rs @@ -154,12 +154,12 @@ impl<'a> ParserImpl<'a> { let decl = self.parse_function_impl(func_kind)?; if stmt_ctx.is_single_statement() { if decl.r#async { - self.error(diagnostics::AsyncFunctionDeclaration(Span::new( + self.error(diagnostics::async_function_declaration(Span::new( decl.span.start, decl.params.span.end, ))); } else if decl.generator { - self.error(diagnostics::GeneratorFunctionDeclaration(Span::new( + self.error(diagnostics::generator_function_declaration(Span::new( decl.span.start, decl.params.span.end, ))); @@ -304,7 +304,7 @@ impl<'a> ParserImpl<'a> { let has_yield = self.ctx.has_yield(); if !has_yield { - self.error(diagnostics::YieldExpression(Span::new(span.start, span.start + 5))); + self.error(diagnostics::yield_expression(Span::new(span.start, span.start + 5))); } let mut delegate = false; @@ -351,7 +351,7 @@ impl<'a> ParserImpl<'a> { self.ctx = ctx; if kind.is_id_required() && id.is_none() { - self.error(diagnostics::ExpectFunctionName(self.cur_token().span())); + self.error(diagnostics::expect_function_name(self.cur_token().span())); } id @@ -479,7 +479,7 @@ impl<'a> ParserImpl<'a> { if let Some(this_param) = this_param { // const x = (this: number) => {}; - self.error(diagnostics::TSArrowFunctionThisParameter(this_param.span)); + self.error(diagnostics::ts_arrow_function_this_parameter(this_param.span)); } let return_type = self.parse_ts_return_type_annotation()?; @@ -487,7 +487,7 @@ impl<'a> ParserImpl<'a> { self.ctx = self.ctx.and_await(has_await); if self.cur_token().is_on_new_line { - self.error(diagnostics::LineterminatorBeforeArrow(self.cur_token().span())); + self.error(diagnostics::lineterminator_before_arrow(self.cur_token().span())); } self.expect(Kind::Arrow)?; diff --git a/crates/oxc_parser/src/js/grammar.rs b/crates/oxc_parser/src/js/grammar.rs index e14b500795e5b..ca0482339fca5 100644 --- a/crates/oxc_parser/src/js/grammar.rs +++ b/crates/oxc_parser/src/js/grammar.rs @@ -43,7 +43,7 @@ impl<'a> CoverGrammar<'a, Expression<'a>> for SimpleAssignmentTarget<'a> { let span = expr.span; match expr.unbox().expression { Expression::ObjectExpression(_) | Expression::ArrayExpression(_) => { - Err(diagnostics::InvalidAssignment(span).into()) + Err(diagnostics::invalid_assignment(span).into()) } expr => SimpleAssignmentTarget::cover(expr, p), } @@ -59,7 +59,7 @@ impl<'a> CoverGrammar<'a, Expression<'a>> for SimpleAssignmentTarget<'a> { Expression::TSInstantiationExpression(expr) => { Ok(SimpleAssignmentTarget::TSInstantiationExpression(expr)) } - expr => Err(diagnostics::InvalidAssignment(expr.span()).into()), + expr => Err(diagnostics::invalid_assignment(expr.span()).into()), } } } @@ -84,10 +84,10 @@ impl<'a> CoverGrammar<'a, ArrayExpression<'a>> for ArrayAssignmentTarget<'a> { target: AssignmentTarget::cover(elem.unbox().argument, p)?, }); if let Some(span) = expr.trailing_comma { - p.error(diagnostics::BindingRestElementTrailingComma(span)); + p.error(diagnostics::binding_rest_element_trailing_comma(span)); } } else { - return Err(diagnostics::SpreadLastElement(elem.span).into()); + return Err(diagnostics::spread_last_element(elem.span).into()); } } ArrayExpressionElement::Elision(_) => elements.push(None), @@ -143,7 +143,7 @@ impl<'a> CoverGrammar<'a, ObjectExpression<'a>> for ObjectAssignmentTarget<'a> { target: AssignmentTarget::cover(spread.unbox().argument, p)?, }); } else { - return Err(diagnostics::SpreadLastElement(spread.span).into()); + return Err(diagnostics::spread_last_element(spread.span).into()); } } } diff --git a/crates/oxc_parser/src/js/list.rs b/crates/oxc_parser/src/js/list.rs index d3c75956ab488..47618648bd48c 100644 --- a/crates/oxc_parser/src/js/list.rs +++ b/crates/oxc_parser/src/js/list.rs @@ -83,10 +83,10 @@ impl<'a> SeparatedList<'a> for ObjectPatternProperties<'a> { if p.cur_kind() == Kind::Dot3 { let rest = p.parse_rest_element()?; if !matches!(&rest.argument.kind, BindingPatternKind::BindingIdentifier(_)) { - p.error(diagnostics::InvalidBindingRestElement(rest.argument.span())); + p.error(diagnostics::invalid_binding_rest_element(rest.argument.span())); } if let Some(r) = self.rest.replace(rest) { - p.error(diagnostics::BindingRestElementLast(r.span)); + p.error(diagnostics::binding_rest_element_last(r.span)); } } else { let prop = p.parse_binding_property()?; @@ -160,7 +160,7 @@ impl<'a> SeparatedList<'a> for ArrayPatternList<'a> { Kind::Dot3 => { let rest = p.parse_rest_element()?; if let Some(r) = self.rest.replace(rest) { - p.error(diagnostics::BindingRestElementLast(r.span)); + p.error(diagnostics::binding_rest_element_last(r.span)); } } _ => { @@ -272,7 +272,7 @@ impl<'a> SeparatedList<'a> for FormalParameterList<'a> { Kind::Dot3 => { let rest = p.parse_rest_element()?; if let Some(r) = self.rest.replace(rest) { - p.error(diagnostics::RestParameterLast(r.span)); + p.error(diagnostics::rest_parameter_last(r.span)); } } _ => { diff --git a/crates/oxc_parser/src/js/module.rs b/crates/oxc_parser/src/js/module.rs index 53447faaa3bfe..c0b3ff4bb7551 100644 --- a/crates/oxc_parser/src/js/module.rs +++ b/crates/oxc_parser/src/js/module.rs @@ -244,9 +244,9 @@ impl<'a> ParserImpl<'a> { match &specifier.local { // It is a Syntax Error if ReferencedBindings of NamedExports contains any StringLiterals. ModuleExportName::StringLiteral(literal) => { - self.error(diagnostics::ExportNamedString( - specifier.local.to_string(), - specifier.exported.to_string(), + self.error(diagnostics::export_named_string( + &specifier.local.to_string(), + &specifier.exported.to_string(), literal.span, )); } @@ -258,9 +258,9 @@ impl<'a> ParserImpl<'a> { if match_result.is_reserved_keyword() || match_result.is_future_reserved_keyword() { - self.error(diagnostics::ExportReservedWord( - specifier.local.to_string(), - specifier.exported.to_string(), + self.error(diagnostics::export_reserved_word( + &specifier.local.to_string(), + &specifier.exported.to_string(), id.span, )); } @@ -431,7 +431,7 @@ impl<'a> ParserImpl<'a> { // ModuleExportName : StringLiteral // It is a Syntax Error if IsStringWellFormedUnicode(the SV of StringLiteral) is false. if !literal.is_string_well_formed_unicode() { - self.error(diagnostics::ExportLoneSurrogate(literal.span)); + self.error(diagnostics::export_lone_surrogate(literal.span)); }; Ok(ModuleExportName::StringLiteral(literal)) } diff --git a/crates/oxc_parser/src/js/statement.rs b/crates/oxc_parser/src/js/statement.rs index 8a4eff9e5f588..17c2f835b40b6 100644 --- a/crates/oxc_parser/src/js/statement.rs +++ b/crates/oxc_parser/src/js/statement.rs @@ -188,7 +188,7 @@ impl<'a> ParserImpl<'a> { )?; if stmt_ctx.is_single_statement() && decl.kind.is_lexical() { - self.error(diagnostics::LexicalDeclarationSingleStatement(decl.span)); + self.error(diagnostics::lexical_declaration_single_statement(decl.span)); } Ok(Statement::VariableDeclaration(decl)) @@ -288,13 +288,13 @@ impl<'a> ParserImpl<'a> { // for (a.b in ...), for ([a] in ..), for ({a} in ..) if self.at(Kind::In) || self.at(Kind::Of) { let target = AssignmentTarget::cover(init_expression, self) - .map_err(|_| diagnostics::UnexpectedToken(self.end_span(expr_span)))?; + .map_err(|_| diagnostics::unexpected_token(self.end_span(expr_span)))?; let for_stmt_left = ForStatementLeft::from(target); if !r#await && is_async_of { - self.error(diagnostics::ForLoopAsyncOf(self.end_span(expr_span))); + self.error(diagnostics::for_loop_async_of(self.end_span(expr_span))); } if is_let_of { - self.error(diagnostics::UnexpectedToken(self.end_span(expr_span))); + self.error(diagnostics::unexpected_token(self.end_span(expr_span))); } return self.parse_for_in_or_of_loop(span, r#await, for_stmt_left); } @@ -332,11 +332,11 @@ impl<'a> ParserImpl<'a> { if matches!(self.cur_kind(), Kind::In) { if using_decl.is_await { - self.error(diagnostics::AwaitUsingDeclarationNotAllowedInForInStatement( + self.error(diagnostics::await_using_declaration_not_allowed_in_for_in_statement( using_decl.span, )); } else { - self.error(diagnostics::UsingDeclarationNotAllowedInForInStatement( + self.error(diagnostics::using_declaration_not_allowed_in_for_in_statement( using_decl.span, )); } @@ -371,7 +371,7 @@ impl<'a> ParserImpl<'a> { }; self.expect(Kind::RParen)?; if r#await { - self.error(diagnostics::ForAwait(self.end_span(span))); + self.error(diagnostics::for_await(self.end_span(span))); } let body = self.parse_statement_list_item(StatementContext::For)?; Ok(self.ast.for_statement(self.end_span(span), init, test, update, body)) @@ -393,7 +393,7 @@ impl<'a> ParserImpl<'a> { self.expect(Kind::RParen)?; if r#await && is_for_in { - self.error(diagnostics::ForAwait(self.end_span(span))); + self.error(diagnostics::for_await(self.end_span(span))); } let body = self.parse_statement_list_item(StatementContext::For)?; @@ -438,7 +438,7 @@ impl<'a> ParserImpl<'a> { Some(expr) }; if !self.ctx.has_return() { - self.error(diagnostics::ReturnStatementOnlyInFunctionBody(Span::new( + self.error(diagnostics::return_statement_only_in_function_body(Span::new( span.start, span.start + 6, ))); @@ -497,7 +497,7 @@ impl<'a> ParserImpl<'a> { let span = self.start_span(); self.bump_any(); // advance `throw` if self.cur_token().is_on_new_line { - self.error(diagnostics::IllegalNewline( + self.error(diagnostics::illegal_newline( "throw", self.end_span(span), self.cur_token().span(), @@ -521,7 +521,7 @@ impl<'a> ParserImpl<'a> { if handler.is_none() && finalizer.is_none() { let range = Span::new(block.span.end, block.span.end); - self.error(diagnostics::ExpectCatchFinally(range)); + self.error(diagnostics::expect_catch_finally(range)); } Ok(self.ast.try_statement(self.end_span(span), block, handler, finalizer)) diff --git a/crates/oxc_parser/src/jsx/mod.rs b/crates/oxc_parser/src/jsx/mod.rs index a8a4faa649a65..1fda0e396d613 100644 --- a/crates/oxc_parser/src/jsx/mod.rs +++ b/crates/oxc_parser/src/jsx/mod.rs @@ -262,7 +262,9 @@ impl<'a> ParserImpl<'a> { self.ctx = Context::default().and_await(ctx.has_await()); let expr = self.parse_expression(); if let Ok(Expression::SequenceExpression(seq)) = &expr { - return Err(diagnostics::JSXExpressionsMayNotUseTheCommaOperator(seq.span).into()); + return Err( + diagnostics::jsx_expressions_may_not_use_the_comma_operator(seq.span).into() + ); } self.ctx = ctx; expr diff --git a/crates/oxc_parser/src/lexer/byte_handlers.rs b/crates/oxc_parser/src/lexer/byte_handlers.rs index 415f7255ed26c..dad9f010d844c 100644 --- a/crates/oxc_parser/src/lexer/byte_handlers.rs +++ b/crates/oxc_parser/src/lexer/byte_handlers.rs @@ -183,7 +183,7 @@ macro_rules! ascii_identifier_handler { // `\0` `\1` etc ascii_byte_handler!(ERR(lexer) { let c = lexer.consume_char(); - lexer.error(diagnostics::InvalidCharacter(c, lexer.unterminated_range())); + lexer.error(diagnostics::invalid_character(c, lexer.unterminated_range())); Kind::Undetermined }); diff --git a/crates/oxc_parser/src/lexer/comment.rs b/crates/oxc_parser/src/lexer/comment.rs index 8122dfd1e6dab..7fa0368a0f24a 100644 --- a/crates/oxc_parser/src/lexer/comment.rs +++ b/crates/oxc_parser/src/lexer/comment.rs @@ -145,7 +145,7 @@ impl<'a> Lexer<'a> { } }, handle_eof: { - self.error(diagnostics::UnterminatedMultiLineComment(self.unterminated_range())); + self.error(diagnostics::unterminated_multi_line_comment(self.unterminated_range())); return Kind::Eof; }, }; @@ -174,7 +174,7 @@ impl<'a> Lexer<'a> { Kind::Skip } else { self.source.advance_to_end(); - self.error(diagnostics::UnterminatedMultiLineComment(self.unterminated_range())); + self.error(diagnostics::unterminated_multi_line_comment(self.unterminated_range())); Kind::Eof } } diff --git a/crates/oxc_parser/src/lexer/identifier.rs b/crates/oxc_parser/src/lexer/identifier.rs index 312fa92ca06ff..ac1c8324021f1 100644 --- a/crates/oxc_parser/src/lexer/identifier.rs +++ b/crates/oxc_parser/src/lexer/identifier.rs @@ -216,7 +216,7 @@ impl<'a> Lexer<'a> { if start_pos.addr() == self.source.end_addr() { return cold_branch(|| { let start = self.offset(); - self.error(diagnostics::UnexpectedEnd(Span::new(start, start))); + self.error(diagnostics::unexpected_end(Span::new(start, start))); Kind::Undetermined }); } @@ -290,7 +290,7 @@ impl<'a> Lexer<'a> { // No identifier found let start = self.offset(); let c = self.consume_char(); - self.error(diagnostics::InvalidCharacter(c, Span::new(start, self.offset()))); + self.error(diagnostics::invalid_character(c, Span::new(start, self.offset()))); Kind::Undetermined } } diff --git a/crates/oxc_parser/src/lexer/jsx.rs b/crates/oxc_parser/src/lexer/jsx.rs index 1d0221d3818f4..8a460b503a124 100644 --- a/crates/oxc_parser/src/lexer/jsx.rs +++ b/crates/oxc_parser/src/lexer/jsx.rs @@ -43,7 +43,7 @@ impl<'a> Lexer<'a> { Kind::Str } else { self.source.advance_to_end(); - self.error(diagnostics::UnterminatedString(self.unterminated_range())); + self.error(diagnostics::unterminated_string(self.unterminated_range())); Kind::Undetermined } } diff --git a/crates/oxc_parser/src/lexer/mod.rs b/crates/oxc_parser/src/lexer/mod.rs index dd0502228a003..84859f20cb089 100644 --- a/crates/oxc_parser/src/lexer/mod.rs +++ b/crates/oxc_parser/src/lexer/mod.rs @@ -282,8 +282,8 @@ impl<'a> Lexer<'a> { fn unexpected_err(&mut self) { let offset = self.current_offset(); match self.peek() { - Some(c) => self.error(diagnostics::InvalidCharacter(c, offset)), - None => self.error(diagnostics::UnexpectedEnd(offset)), + Some(c) => self.error(diagnostics::invalid_character(c, offset)), + None => self.error(diagnostics::unexpected_end(offset)), } } diff --git a/crates/oxc_parser/src/lexer/numeric.rs b/crates/oxc_parser/src/lexer/numeric.rs index 560bab2fdca8c..963bc063e40e6 100644 --- a/crates/oxc_parser/src/lexer/numeric.rs +++ b/crates/oxc_parser/src/lexer/numeric.rs @@ -193,7 +193,7 @@ impl<'a> Lexer<'a> { break; } } - self.error(diagnostics::InvalidNumberEnd(Span::new(offset, self.offset()))); + self.error(diagnostics::invalid_number_end(Span::new(offset, self.offset()))); Kind::Undetermined } } diff --git a/crates/oxc_parser/src/lexer/regex.rs b/crates/oxc_parser/src/lexer/regex.rs index e161ff163a5f5..de3f3867eeb2e 100644 --- a/crates/oxc_parser/src/lexer/regex.rs +++ b/crates/oxc_parser/src/lexer/regex.rs @@ -30,11 +30,11 @@ impl<'a> Lexer<'a> { loop { match self.next_char() { None => { - self.error(diagnostics::UnterminatedRegExp(self.unterminated_range())); + self.error(diagnostics::unterminated_reg_exp(self.unterminated_range())); return (self.offset(), RegExpFlags::empty()); } Some(c) if is_line_terminator(c) => { - self.error(diagnostics::UnterminatedRegExp(self.unterminated_range())); + self.error(diagnostics::unterminated_reg_exp(self.unterminated_range())); #[allow(clippy::cast_possible_truncation)] let pattern_end = self.offset() - c.len_utf8() as u32; return (pattern_end, RegExpFlags::empty()); @@ -61,11 +61,11 @@ impl<'a> Lexer<'a> { while let Some(ch @ ('$' | '_' | 'a'..='z' | 'A'..='Z' | '0'..='9')) = self.peek() { self.consume_char(); let Ok(flag) = RegExpFlags::try_from(ch) else { - self.error(diagnostics::RegExpFlag(ch, self.current_offset())); + self.error(diagnostics::reg_exp_flag(ch, self.current_offset())); continue; }; if flags.contains(flag) { - self.error(diagnostics::RegExpFlagTwice(ch, self.current_offset())); + self.error(diagnostics::reg_exp_flag_twice(ch, self.current_offset())); continue; } flags |= flag; diff --git a/crates/oxc_parser/src/lexer/source.rs b/crates/oxc_parser/src/lexer/source.rs index 8f1396be81c60..8de5635bbdc7c 100644 --- a/crates/oxc_parser/src/lexer/source.rs +++ b/crates/oxc_parser/src/lexer/source.rs @@ -83,7 +83,7 @@ impl<'a> Source<'a> { #[allow(clippy::needless_pass_by_value)] pub(super) fn new(mut source_text: &'a str, _unique: UniquePromise) -> Self { // If source text exceeds size limit, substitute a short source text which will fail to parse. - // `Parser::parse` will convert error to `diagnostics::OverlongSource`. + // `Parser::parse` will convert error to `diagnostics::overlong_source()`. if source_text.len() > MAX_LEN { source_text = "\0"; } diff --git a/crates/oxc_parser/src/lexer/string.rs b/crates/oxc_parser/src/lexer/string.rs index 0af68bf4a8549..23ff04eca42b5 100644 --- a/crates/oxc_parser/src/lexer/string.rs +++ b/crates/oxc_parser/src/lexer/string.rs @@ -42,7 +42,7 @@ macro_rules! handle_string_literal { table: $table, start: after_opening_quote, handle_eof: { - $lexer.error(diagnostics::UnterminatedString($lexer.unterminated_range())); + $lexer.error(diagnostics::unterminated_string($lexer.unterminated_range())); return Kind::Undetermined; }, }; @@ -64,7 +64,7 @@ macro_rules! handle_string_literal { cold_branch(|| { debug_assert!(matches!(next_byte, b'\r' | b'\n')); $lexer.consume_char(); - $lexer.error(diagnostics::UnterminatedString($lexer.unterminated_range())); + $lexer.error(diagnostics::unterminated_string($lexer.unterminated_range())); Kind::Undetermined }) } @@ -94,7 +94,7 @@ macro_rules! handle_string_literal_escape { $lexer.read_string_escape_sequence(&mut str, false, &mut is_valid_escape_sequence); if !is_valid_escape_sequence { let range = Span::new(escape_start_offset, $lexer.offset()); - $lexer.error(diagnostics::InvalidEscapeSequence(range)); + $lexer.error(diagnostics::invalid_escape_sequence(range)); } // Consume bytes until reach end of string, line break, or another escape @@ -127,12 +127,12 @@ macro_rules! handle_string_literal_escape { str.push_str(chunk); continue 'outer; } - _ => { + _ => { // Line break. This is impossible in valid JS, so cold path. return cold_branch(|| { debug_assert!(matches!(b, b'\r' | b'\n')); $lexer.consume_char(); - $lexer.error(diagnostics::UnterminatedString($lexer.unterminated_range())); + $lexer.error(diagnostics::unterminated_string($lexer.unterminated_range())); Kind::Undetermined }); } @@ -140,7 +140,7 @@ macro_rules! handle_string_literal_escape { } // EOF - $lexer.error(diagnostics::UnterminatedString($lexer.unterminated_range())); + $lexer.error(diagnostics::unterminated_string($lexer.unterminated_range())); return Kind::Undetermined; } @@ -148,7 +148,7 @@ macro_rules! handle_string_literal_escape { $lexer.save_string(true, str.into_bump_str()); Kind::Str - }} + }}; } impl<'a> Lexer<'a> { diff --git a/crates/oxc_parser/src/lexer/template.rs b/crates/oxc_parser/src/lexer/template.rs index 462d7b81b1315..86c8867361465 100644 --- a/crates/oxc_parser/src/lexer/template.rs +++ b/crates/oxc_parser/src/lexer/template.rs @@ -74,7 +74,7 @@ impl<'a> Lexer<'a> { } }, handle_eof: { - self.error(diagnostics::UnterminatedString(self.unterminated_range())); + self.error(diagnostics::unterminated_string(self.unterminated_range())); return Kind::Undetermined; }, }; @@ -105,7 +105,7 @@ impl<'a> Lexer<'a> { if pos.addr() == self.source.end_addr() { return cold_branch(|| { self.source.advance_to_end(); - self.error(diagnostics::UnterminatedString(self.unterminated_range())); + self.error(diagnostics::unterminated_string(self.unterminated_range())); Kind::Undetermined }); } @@ -295,7 +295,7 @@ impl<'a> Lexer<'a> { } }, handle_eof: { - self.error(diagnostics::UnterminatedString(self.unterminated_range())); + self.error(diagnostics::unterminated_string(self.unterminated_range())); return Kind::Undetermined; }, }; diff --git a/crates/oxc_parser/src/lexer/unicode.rs b/crates/oxc_parser/src/lexer/unicode.rs index 651adffec0c1a..94ef31fb3a43b 100644 --- a/crates/oxc_parser/src/lexer/unicode.rs +++ b/crates/oxc_parser/src/lexer/unicode.rs @@ -39,7 +39,7 @@ impl<'a> Lexer<'a> { } _ => { self.consume_char(); - self.error(diagnostics::InvalidCharacter(c, self.unterminated_range())); + self.error(diagnostics::invalid_character(c, self.unterminated_range())); Kind::Undetermined } } @@ -56,7 +56,7 @@ impl<'a> Lexer<'a> { let start = self.offset(); if self.next_char() != Some('u') { let range = Span::new(start, self.offset()); - self.error(diagnostics::UnicodeEscapeSequence(range)); + self.error(diagnostics::unicode_escape_sequence(range)); return; } @@ -67,7 +67,7 @@ impl<'a> Lexer<'a> { let Some(value) = value else { let range = Span::new(start, self.offset()); - self.error(diagnostics::UnicodeEscapeSequence(range)); + self.error(diagnostics::unicode_escape_sequence(range)); return; }; @@ -75,7 +75,7 @@ impl<'a> Lexer<'a> { let ch = match value { SurrogatePair::Astral(..) | SurrogatePair::HighLow(..) => { let range = Span::new(start, self.offset()); - self.error(diagnostics::UnicodeEscapeSequence(range)); + self.error(diagnostics::unicode_escape_sequence(range)); return; } SurrogatePair::CodePoint(code_point) => { @@ -83,7 +83,7 @@ impl<'a> Lexer<'a> { ch } else { let range = Span::new(start, self.offset()); - self.error(diagnostics::UnicodeEscapeSequence(range)); + self.error(diagnostics::unicode_escape_sequence(range)); return; } } @@ -93,7 +93,7 @@ impl<'a> Lexer<'a> { if check_identifier_start { is_identifier_start(ch) } else { is_identifier_part(ch) }; if !is_valid { - self.error(diagnostics::InvalidCharacter(ch, self.current_offset())); + self.error(diagnostics::invalid_character(ch, self.current_offset())); return; } @@ -115,7 +115,7 @@ impl<'a> Lexer<'a> { }; let Some(value) = value else { - // error raised within the parser by `diagnostics::TemplateLiteral` + // error raised within the parser by `diagnostics::template_literal` *is_valid_escape_sequence = false; return; }; @@ -220,7 +220,7 @@ impl<'a> Lexer<'a> { ) { match self.next_char() { None => { - self.error(diagnostics::UnterminatedString(self.unterminated_range())); + self.error(diagnostics::unterminated_string(self.unterminated_range())); } Some(c) => match c { // \ LineTerminatorSequence @@ -299,12 +299,12 @@ impl<'a> Lexer<'a> { } '0' if in_template && self.peek().is_some_and(|c| c.is_ascii_digit()) => { self.consume_char(); - // error raised within the parser by `diagnostics::TemplateLiteral` + // error raised within the parser by `diagnostics::template_literal` *is_valid_escape_sequence = false; } // NotEscapeSequence :: DecimalDigit but not 0 '1'..='9' if in_template => { - // error raised within the parser by `diagnostics::TemplateLiteral` + // error raised within the parser by `diagnostics::template_literal` *is_valid_escape_sequence = false; } other => { diff --git a/crates/oxc_parser/src/lib.rs b/crates/oxc_parser/src/lib.rs index 7ca123f481d36..c1ed6b76114a1 100644 --- a/crates/oxc_parser/src/lib.rs +++ b/crates/oxc_parser/src/lib.rs @@ -366,7 +366,7 @@ impl<'a> ParserImpl<'a> { && (self.source_text.starts_with("// @flow") || self.source_text.starts_with("/* @flow */")) { - return Some(diagnostics::Flow(Span::new(0, 8)).into()); + return Some(diagnostics::flow(Span::new(0, 8)).into()); } None } @@ -375,7 +375,7 @@ impl<'a> ParserImpl<'a> { /// Original parsing error is not real - `Lexer::new` substituted "\0" as the source text. fn overlong_error(&self) -> Option { if self.source_text.len() > MAX_LEN { - return Some(diagnostics::OverlongSource.into()); + return Some(diagnostics::overlong_source().into()); } None } @@ -391,7 +391,7 @@ impl<'a> ParserImpl<'a> { return error; } } - diagnostics::UnexpectedToken(self.cur_token().span()).into() + diagnostics::unexpected_token(self.cur_token().span()).into() } /// Push a Syntax Error @@ -465,11 +465,7 @@ mod test { fn comments() { let allocator = Allocator::default(); let source_type = SourceType::default().with_typescript(true); - let sources = [ - ("// line comment", CommentKind::SingleLine), - ("/* line comment */", CommentKind::MultiLine), - ("type Foo = ( /* Require properties which are not generated automatically. */ 'bar')", CommentKind::MultiLine), - ]; + let sources = [("// line comment", CommentKind::SingleLine), ("/* line comment */", CommentKind::MultiLine), ("type Foo = ( /* Require properties which are not generated automatically. */ 'bar')", CommentKind::MultiLine)]; for (source, kind) in sources { let ret = Parser::new(&allocator, source, source_type).parse(); let comments = ret.trivias.comments().collect::>(); diff --git a/crates/oxc_parser/src/ts/types.rs b/crates/oxc_parser/src/ts/types.rs index 31d21e6dbe9f8..cd23044de6f91 100644 --- a/crates/oxc_parser/src/ts/types.rs +++ b/crates/oxc_parser/src/ts/types.rs @@ -813,7 +813,7 @@ impl<'a> ParserImpl<'a> { if let Some(this_param) = this_param { // type Foo = new (this: number) => any; - self.error(diagnostics::TSConstructorThisParameter(this_param.span)); + self.error(diagnostics::ts_constructor_this_parameter(this_param.span)); } self.expect(Kind::Arrow)?; @@ -994,7 +994,9 @@ impl<'a> ParserImpl<'a> { self.bump(Kind::Comma); self.bump(Kind::Semicolon); if let Some(return_type) = return_type.as_ref() { - self.error(diagnostics::ASetAccessorCannotHaveAReturnTypeAnnotation(return_type.span)); + self.error(diagnostics::a_set_accessor_cannot_have_a_return_type_annotation( + return_type.span, + )); } Ok(self.ast.ts_method_signature( self.end_span(span), @@ -1066,7 +1068,7 @@ impl<'a> ParserImpl<'a> { if let Some(this_param) = this_param { // interface Foo { new(this: number): Foo } - self.error(diagnostics::TSConstructorThisParameter(this_param.span)); + self.error(diagnostics::ts_constructor_this_parameter(this_param.span)); } let return_type = self.parse_ts_return_type_annotation()?; diff --git a/crates/oxc_span/src/span.rs b/crates/oxc_span/src/span.rs index 736b7a6fc066c..333df42e80db1 100644 --- a/crates/oxc_span/src/span.rs +++ b/crates/oxc_span/src/span.rs @@ -3,7 +3,7 @@ use std::hash::{Hash, Hasher}; -use miette::{SourceOffset, SourceSpan}; +use miette::{LabeledSpan, SourceOffset, SourceSpan}; #[cfg(feature = "serialize")] use serde::Serialize; @@ -59,6 +59,12 @@ impl From for SourceSpan { } } +impl From for LabeledSpan { + fn from(val: Span) -> Self { + LabeledSpan::underline(val) + } +} + /// Get the span for an AST node pub trait GetSpan { fn span(&self) -> Span;