From 7dfd51a62bce4b3f1983ce29332fe873b25354f6 Mon Sep 17 00:00:00 2001 From: DonIsaac <22823424+DonIsaac@users.noreply.github.com> Date: Sun, 25 Aug 2024 01:02:49 +0000 Subject: [PATCH] feat(parser): report class properties that are both definite and optional (#5181) --- crates/oxc_parser/src/diagnostics.rs | 8 ++++++++ crates/oxc_parser/src/js/class.rs | 4 ++++ tasks/coverage/parser_babel.snap | 12 ++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/crates/oxc_parser/src/diagnostics.rs b/crates/oxc_parser/src/diagnostics.rs index 0a3a13487c38c..55aa7dcfd08af 100644 --- a/crates/oxc_parser/src/diagnostics.rs +++ b/crates/oxc_parser/src/diagnostics.rs @@ -254,6 +254,14 @@ pub fn optional_accessor_property(span: Span) -> OxcDiagnostic { ts_error("1276", "An 'accessor' property cannot be declared optional.").with_label(span) } +#[cold] +pub fn optional_definite_property(span: Span) -> OxcDiagnostic { + // NOTE: could not find an error code when tsc parses this; its parser panics. + OxcDiagnostic::error("A property cannot be both optional and definite.") + .with_label(span) + .with_help("Remove either the `?` or the `!`") +} + #[cold] pub fn identifier_async(x0: &str, span1: Span) -> OxcDiagnostic { OxcDiagnostic::error(format!("Cannot use `{x0}` as an identifier in an async context")) diff --git a/crates/oxc_parser/src/js/class.rs b/crates/oxc_parser/src/js/class.rs index f32e457767628..50477a9849cb1 100644 --- a/crates/oxc_parser/src/js/class.rs +++ b/crates/oxc_parser/src/js/class.rs @@ -272,6 +272,10 @@ impl<'a> ParserImpl<'a> { }; let definite = self.eat(Kind::Bang); + if optional && definite { + self.error(diagnostics::optional_definite_property(optional_span.expand_right(1))); + } + if let PropertyKey::PrivateIdentifier(private_ident) = &key { // `private #foo`, etc. is illegal if self.ts_enabled() { diff --git a/tasks/coverage/parser_babel.snap b/tasks/coverage/parser_babel.snap index 490c721250f17..a16a0a46226ac 100644 --- a/tasks/coverage/parser_babel.snap +++ b/tasks/coverage/parser_babel.snap @@ -3,7 +3,7 @@ commit: 12619ffe parser_babel Summary: AST Parsed : 2092/2100 (99.62%) Positive Passed: 2082/2100 (99.14%) -Negative Passed: 1379/1492 (92.43%) +Negative Passed: 1380/1492 (92.49%) Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/annex-b/enabled/3.1-sloppy-labeled-functions-if-body/input.js Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/core/categorized/invalid-fn-decl-labeled-inside-if/input.js Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/core/categorized/invalid-fn-decl-labeled-inside-loop/input.js @@ -53,7 +53,6 @@ Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/ty Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/class/modifiers-override-errors/input.ts Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/class/parameter-properties-binding-patterns/input.ts Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/class/private-fields-modifier-abstract/input.ts -Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/class/property-optional-definite-assignment-not-allowed/input.ts Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/declare/function/input.ts Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/declare/module-class/input.ts Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/declare/module-function/input.ts @@ -10264,6 +10263,15 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc 3 │ } ╰──── + × A property cannot be both optional and definite. + ╭─[babel/packages/babel-parser/test/fixtures/typescript/class/property-optional-definite-assignment-not-allowed/input.ts:2:4] + 1 │ class C { + 2 │ x?!: number; + · ── + 3 │ } + ╰──── + help: Remove either the `?` or the `!` + × Unexpected token ╭─[babel/packages/babel-parser/test/fixtures/typescript/const/invalid-initializer-ambient-context/input.ts:2:35] 1 │ declare module N {