From c9ecdacc4e6283aff4350470e9c6aae6a4f1bf9c Mon Sep 17 00:00:00 2001 From: "Arend van Beelen jr." Date: Wed, 31 Jul 2024 20:19:12 +0200 Subject: [PATCH] feat(js_parser): support metavariables (#3548) --- .../src/generated/node_factory.rs | 12 +- .../src/generated/syntax_factory.rs | 38 +- .../src/css/any/declaration_or_rule.rs | 2 +- .../src/css/any/media_query.rs | 2 +- .../src/css/any/selector.rs | 2 +- .../biome_css_formatter/src/css/any/value.rs | 2 +- .../src/css/auxiliary/grit_metavariable.rs | 12 - .../src/css/auxiliary/metavariable.rs | 10 + .../src/css/auxiliary/mod.rs | 2 +- crates/biome_css_formatter/src/generated.rs | 80 +-- crates/biome_css_parser/src/lexer/mod.rs | 58 +- crates/biome_css_parser/src/parser.rs | 10 +- .../src/syntax/at_rule/media.rs | 6 +- .../block/declaration_or_rule_list_block.rs | 11 +- crates/biome_css_parser/src/syntax/mod.rs | 16 +- .../src/syntax/selector/mod.rs | 8 +- .../ok/grit_metavariable/metavar.css.snap | 20 +- crates/biome_css_parser/tests/spec_test.rs | 4 +- crates/biome_css_syntax/src/generated/kind.rs | 2 +- .../biome_css_syntax/src/generated/macros.rs | 8 +- .../biome_css_syntax/src/generated/nodes.rs | 297 +++++------ .../src/generated/nodes_mut.rs | 16 +- crates/biome_formatter/src/diagnostics.rs | 4 +- crates/biome_grit_patterns/src/errors.rs | 7 + .../js_target_language.rs | 2 +- .../lint/complexity/no_static_only_class.rs | 5 +- .../no_invalid_constructor_super.rs | 1 + .../src/lint/style/use_const.rs | 4 +- .../src/lint/style/use_naming_convention.rs | 1 + .../suspicious/no_duplicate_parameters.rs | 11 +- .../suspicious/no_misleading_instantiator.rs | 7 +- .../src/lint/suspicious/no_then_property.rs | 1 + .../no_unsafe_declaration_merging.rs | 5 +- .../src/generated/node_factory.rs | 48 +- .../src/generated/syntax_factory.rs | 41 +- crates/biome_js_formatter/src/generated.rs | 90 ++++ .../biome_js_formatter/src/js/any/binding.rs | 1 + .../src/js/any/class_member.rs | 1 + .../src/js/any/class_member_name.rs | 1 + .../src/js/any/expression.rs | 1 + crates/biome_js_formatter/src/js/any/mod.rs | 1 + .../src/js/any/module_source.rs | 15 + .../js/any/object_binding_pattern_member.rs | 1 + .../src/js/any/object_member_name.rs | 1 + .../src/js/auxiliary/metavariable.rs | 10 + .../src/js/auxiliary/mod.rs | 1 + .../src/js/bindings/parameters.rs | 5 +- .../src/js/classes/property_class_member.rs | 5 +- .../src/ts/any/identifier_binding.rs | 15 + crates/biome_js_formatter/src/ts/any/mod.rs | 1 + .../src/ts/any/module_name.rs | 2 +- .../biome_js_formatter/src/ts/any/ts_type.rs | 1 + .../src/ts/lists/union_type_variant_list.rs | 3 +- .../src/utils/assignment_like.rs | 17 +- .../src/utils/format_node_without_comments.rs | 2 + crates/biome_js_parser/src/lexer/mod.rs | 18 +- crates/biome_js_parser/src/options.rs | 16 + crates/biome_js_parser/src/parser.rs | 2 +- crates/biome_js_parser/src/syntax.rs | 1 + .../biome_js_parser/src/syntax/assignment.rs | 6 +- crates/biome_js_parser/src/syntax/binding.rs | 16 +- crates/biome_js_parser/src/syntax/class.rs | 5 + crates/biome_js_parser/src/syntax/expr.rs | 11 + .../src/syntax/metavariable.rs | 24 + crates/biome_js_parser/src/syntax/module.rs | 12 +- crates/biome_js_parser/src/syntax/object.rs | 7 + crates/biome_js_parser/src/syntax/stmt.rs | 8 +- .../biome_js_parser/src/syntax/typescript.rs | 2 +- .../src/syntax/typescript/types.rs | 2 + crates/biome_js_parser/src/token_source.rs | 6 +- .../test_data/inline/ok/metavar.options.json | 1 + .../test_data/inline/ok/metavar.rast | 364 +++++++++++++ .../test_data/inline/ok/metavar.ts | 19 + crates/biome_js_syntax/src/binding_ext.rs | 4 +- crates/biome_js_syntax/src/expr_ext.rs | 6 +- crates/biome_js_syntax/src/generated/kind.rs | 3 +- .../biome_js_syntax/src/generated/macros.rs | 4 + crates/biome_js_syntax/src/generated/nodes.rs | 496 ++++++++++++++++-- .../src/generated/nodes_mut.rs | 30 +- crates/biome_js_syntax/src/import_ext.rs | 38 +- crates/biome_js_syntax/src/lib.rs | 9 + .../src/parentheses/expression.rs | 9 +- crates/biome_js_syntax/src/union_ext.rs | 2 +- crates/biome_parser/src/lexer.rs | 52 ++ crates/biome_rowan/src/ast/mod.rs | 5 + crates/biome_service/src/file_handlers/css.rs | 2 +- .../src/file_handlers/javascript.rs | 1 + crates/biome_service/src/workspace_types.rs | 4 +- xtask/codegen/css.ungram | 10 +- xtask/codegen/js.ungram | 44 +- xtask/codegen/src/css_kinds_src.rs | 2 +- xtask/codegen/src/generate_bindings.rs | 6 +- xtask/codegen/src/js_kinds_src.rs | 3 +- 93 files changed, 1656 insertions(+), 523 deletions(-) delete mode 100644 crates/biome_css_formatter/src/css/auxiliary/grit_metavariable.rs create mode 100644 crates/biome_css_formatter/src/css/auxiliary/metavariable.rs create mode 100644 crates/biome_js_formatter/src/js/any/module_source.rs create mode 100644 crates/biome_js_formatter/src/js/auxiliary/metavariable.rs create mode 100644 crates/biome_js_formatter/src/ts/any/identifier_binding.rs create mode 100644 crates/biome_js_parser/src/syntax/metavariable.rs create mode 100644 crates/biome_js_parser/test_data/inline/ok/metavar.options.json create mode 100644 crates/biome_js_parser/test_data/inline/ok/metavar.rast create mode 100644 crates/biome_js_parser/test_data/inline/ok/metavar.ts diff --git a/crates/biome_css_factory/src/generated/node_factory.rs b/crates/biome_css_factory/src/generated/node_factory.rs index 429a5759eeba..c40ae44dbdc3 100644 --- a/crates/biome_css_factory/src/generated/node_factory.rs +++ b/crates/biome_css_factory/src/generated/node_factory.rs @@ -737,12 +737,6 @@ pub fn css_generic_property( ], )) } -pub fn css_grit_metavariable(value_token: SyntaxToken) -> CssGritMetavariable { - CssGritMetavariable::unwrap_cast(SyntaxNode::new_detached( - CssSyntaxKind::CSS_GRIT_METAVARIABLE, - [Some(SyntaxElement::Token(value_token))], - )) -} pub fn css_id_selector(hash_token: SyntaxToken, name: CssCustomIdentifier) -> CssIdSelector { CssIdSelector::unwrap_cast(SyntaxNode::new_detached( CssSyntaxKind::CSS_ID_SELECTOR, @@ -1128,6 +1122,12 @@ impl CssMediaTypeQueryBuilder { )) } } +pub fn css_metavariable(value_token: SyntaxToken) -> CssMetavariable { + CssMetavariable::unwrap_cast(SyntaxNode::new_detached( + CssSyntaxKind::CSS_METAVARIABLE, + [Some(SyntaxElement::Token(value_token))], + )) +} pub fn css_named_namespace_prefix(name: CssIdentifier) -> CssNamedNamespacePrefix { CssNamedNamespacePrefix::unwrap_cast(SyntaxNode::new_detached( CssSyntaxKind::CSS_NAMED_NAMESPACE_PREFIX, diff --git a/crates/biome_css_factory/src/generated/syntax_factory.rs b/crates/biome_css_factory/src/generated/syntax_factory.rs index 5c450656446b..89cd7e03c30b 100644 --- a/crates/biome_css_factory/src/generated/syntax_factory.rs +++ b/crates/biome_css_factory/src/generated/syntax_factory.rs @@ -1492,25 +1492,6 @@ impl SyntaxFactory for CssSyntaxFactory { } slots.into_node(CSS_GENERIC_PROPERTY, children) } - CSS_GRIT_METAVARIABLE => { - let mut elements = (&children).into_iter(); - let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); - let mut current_element = elements.next(); - if let Some(element) = ¤t_element { - if element.kind() == GRIT_METAVARIABLE { - slots.mark_present(); - current_element = elements.next(); - } - } - slots.next_slot(); - if current_element.is_some() { - return RawSyntaxNode::new( - CSS_GRIT_METAVARIABLE.to_bogus(), - children.into_iter().map(Some), - ); - } - slots.into_node(CSS_GRIT_METAVARIABLE, children) - } CSS_ID_SELECTOR => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); @@ -2367,6 +2348,25 @@ impl SyntaxFactory for CssSyntaxFactory { } slots.into_node(CSS_MEDIA_TYPE_QUERY, children) } + CSS_METAVARIABLE => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element { + if element.kind() == GRIT_METAVARIABLE { + slots.mark_present(); + current_element = elements.next(); + } + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + CSS_METAVARIABLE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(CSS_METAVARIABLE, children) + } CSS_NAMED_NAMESPACE_PREFIX => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); diff --git a/crates/biome_css_formatter/src/css/any/declaration_or_rule.rs b/crates/biome_css_formatter/src/css/any/declaration_or_rule.rs index 3a85ef75c0ab..a4619fa981f7 100644 --- a/crates/biome_css_formatter/src/css/any/declaration_or_rule.rs +++ b/crates/biome_css_formatter/src/css/any/declaration_or_rule.rs @@ -11,7 +11,7 @@ impl FormatRule for FormatAnyCssDeclarationOrRule { AnyCssDeclarationOrRule::AnyCssRule(node) => node.format().fmt(f), AnyCssDeclarationOrRule::CssBogus(node) => node.format().fmt(f), AnyCssDeclarationOrRule::CssDeclarationWithSemicolon(node) => node.format().fmt(f), - AnyCssDeclarationOrRule::CssGritMetavariable(node) => node.format().fmt(f), + AnyCssDeclarationOrRule::CssMetavariable(node) => node.format().fmt(f), } } } diff --git a/crates/biome_css_formatter/src/css/any/media_query.rs b/crates/biome_css_formatter/src/css/any/media_query.rs index c564c266fdda..886577d0e138 100644 --- a/crates/biome_css_formatter/src/css/any/media_query.rs +++ b/crates/biome_css_formatter/src/css/any/media_query.rs @@ -10,8 +10,8 @@ impl FormatRule for FormatAnyCssMediaQuery { match node { AnyCssMediaQuery::AnyCssMediaTypeQuery(node) => node.format().fmt(f), AnyCssMediaQuery::CssBogusMediaQuery(node) => node.format().fmt(f), - AnyCssMediaQuery::CssGritMetavariable(node) => node.format().fmt(f), AnyCssMediaQuery::CssMediaConditionQuery(node) => node.format().fmt(f), + AnyCssMediaQuery::CssMetavariable(node) => node.format().fmt(f), } } } diff --git a/crates/biome_css_formatter/src/css/any/selector.rs b/crates/biome_css_formatter/src/css/any/selector.rs index 20dff64f7de2..3a9032db1fb2 100644 --- a/crates/biome_css_formatter/src/css/any/selector.rs +++ b/crates/biome_css_formatter/src/css/any/selector.rs @@ -11,7 +11,7 @@ impl FormatRule for FormatAnyCssSelector { AnyCssSelector::CssBogusSelector(node) => node.format().fmt(f), AnyCssSelector::CssComplexSelector(node) => node.format().fmt(f), AnyCssSelector::CssCompoundSelector(node) => node.format().fmt(f), - AnyCssSelector::CssGritMetavariable(node) => node.format().fmt(f), + AnyCssSelector::CssMetavariable(node) => node.format().fmt(f), } } } diff --git a/crates/biome_css_formatter/src/css/any/value.rs b/crates/biome_css_formatter/src/css/any/value.rs index 140630ba8dd8..6f20174dba10 100644 --- a/crates/biome_css_formatter/src/css/any/value.rs +++ b/crates/biome_css_formatter/src/css/any/value.rs @@ -14,8 +14,8 @@ impl FormatRule for FormatAnyCssValue { AnyCssValue::CssColor(node) => node.format().fmt(f), AnyCssValue::CssCustomIdentifier(node) => node.format().fmt(f), AnyCssValue::CssDashedIdentifier(node) => node.format().fmt(f), - AnyCssValue::CssGritMetavariable(node) => node.format().fmt(f), AnyCssValue::CssIdentifier(node) => node.format().fmt(f), + AnyCssValue::CssMetavariable(node) => node.format().fmt(f), AnyCssValue::CssNumber(node) => node.format().fmt(f), AnyCssValue::CssRatio(node) => node.format().fmt(f), AnyCssValue::CssString(node) => node.format().fmt(f), diff --git a/crates/biome_css_formatter/src/css/auxiliary/grit_metavariable.rs b/crates/biome_css_formatter/src/css/auxiliary/grit_metavariable.rs deleted file mode 100644 index f4162fbd24ed..000000000000 --- a/crates/biome_css_formatter/src/css/auxiliary/grit_metavariable.rs +++ /dev/null @@ -1,12 +0,0 @@ -use crate::prelude::*; -use biome_css_syntax::{CssGritMetavariable, CssGritMetavariableFields}; -use biome_formatter::write; - -#[derive(Debug, Clone, Default)] -pub(crate) struct FormatCssGritMetavariable; -impl FormatNodeRule for FormatCssGritMetavariable { - fn fmt_fields(&self, node: &CssGritMetavariable, f: &mut CssFormatter) -> FormatResult<()> { - let CssGritMetavariableFields { value_token } = node.as_fields(); - write!(f, [value_token.format()]) - } -} diff --git a/crates/biome_css_formatter/src/css/auxiliary/metavariable.rs b/crates/biome_css_formatter/src/css/auxiliary/metavariable.rs new file mode 100644 index 000000000000..cb87ff13e33c --- /dev/null +++ b/crates/biome_css_formatter/src/css/auxiliary/metavariable.rs @@ -0,0 +1,10 @@ +use crate::prelude::*; +use biome_css_syntax::CssMetavariable; +use biome_rowan::AstNode; +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatCssMetavariable; +impl FormatNodeRule for FormatCssMetavariable { + fn fmt_fields(&self, node: &CssMetavariable, f: &mut CssFormatter) -> FormatResult<()> { + format_verbatim_node(node.syntax()).fmt(f) + } +} diff --git a/crates/biome_css_formatter/src/css/auxiliary/mod.rs b/crates/biome_css_formatter/src/css/auxiliary/mod.rs index 3704c7f41593..fd73d3561f17 100644 --- a/crates/biome_css_formatter/src/css/auxiliary/mod.rs +++ b/crates/biome_css_formatter/src/css/auxiliary/mod.rs @@ -29,7 +29,6 @@ pub(crate) mod font_feature_values_block; pub(crate) mod font_feature_values_item; pub(crate) mod function; pub(crate) mod generic_delimiter; -pub(crate) mod grit_metavariable; pub(crate) mod import_anonymous_layer; pub(crate) mod import_named_layer; pub(crate) mod import_supports; @@ -50,6 +49,7 @@ pub(crate) mod media_not_condition; pub(crate) mod media_or_condition; pub(crate) mod media_type; pub(crate) mod media_type_query; +pub(crate) mod metavariable; pub(crate) mod named_namespace_prefix; pub(crate) mod namespace; pub(crate) mod nested_qualified_rule; diff --git a/crates/biome_css_formatter/src/generated.rs b/crates/biome_css_formatter/src/generated.rs index 558e590f1725..f18c7d0861b3 100644 --- a/crates/biome_css_formatter/src/generated.rs +++ b/crates/biome_css_formatter/src/generated.rs @@ -1747,46 +1747,6 @@ impl IntoFormat for biome_css_syntax::CssGenericProperty { ) } } -impl FormatRule - for crate::css::auxiliary::grit_metavariable::FormatCssGritMetavariable -{ - type Context = CssFormatContext; - #[inline(always)] - fn fmt( - &self, - node: &biome_css_syntax::CssGritMetavariable, - f: &mut CssFormatter, - ) -> FormatResult<()> { - FormatNodeRule::::fmt(self, node, f) - } -} -impl AsFormat for biome_css_syntax::CssGritMetavariable { - type Format<'a> = FormatRefWithRule< - 'a, - biome_css_syntax::CssGritMetavariable, - crate::css::auxiliary::grit_metavariable::FormatCssGritMetavariable, - >; - fn format(&self) -> Self::Format<'_> { - #![allow(clippy::default_constructed_unit_structs)] - FormatRefWithRule::new( - self, - crate::css::auxiliary::grit_metavariable::FormatCssGritMetavariable::default(), - ) - } -} -impl IntoFormat for biome_css_syntax::CssGritMetavariable { - type Format = FormatOwnedWithRule< - biome_css_syntax::CssGritMetavariable, - crate::css::auxiliary::grit_metavariable::FormatCssGritMetavariable, - >; - fn into_format(self) -> Self::Format { - #![allow(clippy::default_constructed_unit_structs)] - FormatOwnedWithRule::new( - self, - crate::css::auxiliary::grit_metavariable::FormatCssGritMetavariable::default(), - ) - } -} impl FormatRule for crate::css::selectors::id_selector::FormatCssIdSelector { @@ -2896,6 +2856,46 @@ impl IntoFormat for biome_css_syntax::CssMediaTypeQuery { ) } } +impl FormatRule + for crate::css::auxiliary::metavariable::FormatCssMetavariable +{ + type Context = CssFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_css_syntax::CssMetavariable, + f: &mut CssFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_css_syntax::CssMetavariable { + type Format<'a> = FormatRefWithRule< + 'a, + biome_css_syntax::CssMetavariable, + crate::css::auxiliary::metavariable::FormatCssMetavariable, + >; + fn format(&self) -> Self::Format<'_> { + #![allow(clippy::default_constructed_unit_structs)] + FormatRefWithRule::new( + self, + crate::css::auxiliary::metavariable::FormatCssMetavariable::default(), + ) + } +} +impl IntoFormat for biome_css_syntax::CssMetavariable { + type Format = FormatOwnedWithRule< + biome_css_syntax::CssMetavariable, + crate::css::auxiliary::metavariable::FormatCssMetavariable, + >; + fn into_format(self) -> Self::Format { + #![allow(clippy::default_constructed_unit_structs)] + FormatOwnedWithRule::new( + self, + crate::css::auxiliary::metavariable::FormatCssMetavariable::default(), + ) + } +} impl FormatRule for crate::css::auxiliary::named_namespace_prefix::FormatCssNamedNamespacePrefix { diff --git a/crates/biome_css_parser/src/lexer/mod.rs b/crates/biome_css_parser/src/lexer/mod.rs index a047cb450da9..790be59980ed 100644 --- a/crates/biome_css_parser/src/lexer/mod.rs +++ b/crates/biome_css_parser/src/lexer/mod.rs @@ -323,10 +323,8 @@ impl<'src> CssLexer<'src> { self.advance(1); self.consume_byte(T!["$="]) } - UNI if self.options.is_grit_metavariable_enabled() - && self.is_grit_metavariable_start() => - { - self.consume_grit_metavariable() + UNI if self.options.is_metavariable_enabled() && self.is_metavariable_start() => { + self.consume_metavariable(GRIT_METAVARIABLE) } IDT | UNI | BSL if self.is_ident_start() => self.consume_identifier(), @@ -1320,58 +1318,6 @@ impl<'src> CssLexer<'src> { _ => false, } } - - /// Check if the lexer starts a grit metavariable - fn is_grit_metavariable_start(&mut self) -> bool { - let current_char = self.current_char_unchecked(); - if current_char == 'μ' { - let current_char_length = current_char.len_utf8(); - // μ[a-zA-Z_][a-zA-Z0-9_]* - if matches!( - self.byte_at(current_char_length), - Some(b'a'..=b'z' | b'A'..=b'Z' | b'_') - ) { - return true; - } - - // μ... - if self.byte_at(current_char_length) == Some(b'.') - && self.byte_at(current_char_length + 1) == Some(b'.') - && self.byte_at(current_char_length + 2) == Some(b'.') - { - return true; - } - } - false - } - - /// Consume a grit metavariable(μ[a-zA-Z_][a-zA-Z0-9_]*|μ...) - /// https://github.com/getgrit/gritql/blob/8f3f077d078ccaf0618510bba904a06309c2435e/resources/language-metavariables/tree-sitter-css/grammar.js#L388 - fn consume_grit_metavariable(&mut self) -> CssSyntaxKind { - debug_assert!(self.is_grit_metavariable_start()); - - // SAFETY: We know the current character is μ. - let current_char = self.current_char_unchecked(); - self.advance(current_char.len_utf8()); - - if self.current_byte() == Some(b'.') { - // SAFETY: We know that the current token is μ... - self.advance(3); - } else { - // μ[a-zA-Z_][a-zA-Z0-9_]* - self.advance(1); - while let Some(chr) = self.current_byte() { - match chr { - b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_' => { - self.advance(1); - } - _ => break, - } - } - } - - GRIT_METAVARIABLE - } } impl<'src> ReLexer<'src> for CssLexer<'src> { diff --git a/crates/biome_css_parser/src/parser.rs b/crates/biome_css_parser/src/parser.rs index 7f5bca1393d6..e81585dcdd5c 100644 --- a/crates/biome_css_parser/src/parser.rs +++ b/crates/biome_css_parser/src/parser.rs @@ -32,7 +32,7 @@ pub struct CssParserOptions { /// Enables parsing of Grit metavariables. /// Defaults to `false`. - pub grit_metavariable: bool, + pub grit_metavariables: bool, } impl CssParserOptions { @@ -49,8 +49,8 @@ impl CssParserOptions { } /// Enables parsing of Grit metavariables. - pub fn allow_grit_metavariables(mut self) -> Self { - self.grit_metavariable = true; + pub fn allow_metavariables(mut self) -> Self { + self.grit_metavariables = true; self } @@ -60,8 +60,8 @@ impl CssParserOptions { } /// Checks if parsing of Grit metavariables is enabled. - pub fn is_grit_metavariable_enabled(&self) -> bool { - self.grit_metavariable + pub fn is_metavariable_enabled(&self) -> bool { + self.grit_metavariables } } diff --git a/crates/biome_css_parser/src/syntax/at_rule/media.rs b/crates/biome_css_parser/src/syntax/at_rule/media.rs index 970b22a5ab91..add69df23697 100644 --- a/crates/biome_css_parser/src/syntax/at_rule/media.rs +++ b/crates/biome_css_parser/src/syntax/at_rule/media.rs @@ -3,7 +3,7 @@ use crate::parser::CssParser; use crate::syntax::at_rule::feature::parse_any_query_feature; use crate::syntax::block::parse_conditional_block; use crate::syntax::{ - is_at_grit_metavariable, is_at_identifier, is_nth_at_identifier, parse_grit_metavariable, + is_at_identifier, is_at_metavariable, is_nth_at_identifier, parse_metavariable, parse_regular_identifier, }; use biome_css_syntax::CssSyntaxKind::*; @@ -80,8 +80,8 @@ impl ParseSeparatedList for MediaQueryList { fn parse_any_media_query(p: &mut CssParser) -> ParsedSyntax { if is_at_media_type_query(p) { parse_any_media_type_query(p) - } else if is_at_grit_metavariable(p) { - parse_grit_metavariable(p) + } else if is_at_metavariable(p) { + parse_metavariable(p) } else if is_at_any_media_condition(p) { let m = p.start(); parse_any_media_condition(p).ok(); // TODO handle error diff --git a/crates/biome_css_parser/src/syntax/block/declaration_or_rule_list_block.rs b/crates/biome_css_parser/src/syntax/block/declaration_or_rule_list_block.rs index f17a61066f3a..7daf282d74f6 100644 --- a/crates/biome_css_parser/src/syntax/block/declaration_or_rule_list_block.rs +++ b/crates/biome_css_parser/src/syntax/block/declaration_or_rule_list_block.rs @@ -3,9 +3,8 @@ use crate::syntax::at_rule::{is_at_at_rule, parse_at_rule}; use crate::syntax::block::ParseBlockBody; use crate::syntax::parse_error::expected_any_declaration_or_at_rule; use crate::syntax::{ - is_at_declaration, is_at_grit_metavariable, is_at_nested_qualified_rule, - parse_declaration_with_semicolon, parse_grit_metavariable, parse_nested_qualified_rule, - try_parse, + is_at_declaration, is_at_metavariable, is_at_nested_qualified_rule, + parse_declaration_with_semicolon, parse_metavariable, parse_nested_qualified_rule, try_parse, }; use biome_css_syntax::CssSyntaxKind::*; use biome_css_syntax::{CssSyntaxKind, T}; @@ -39,7 +38,7 @@ fn is_at_declaration_or_rule_item(p: &mut CssParser) -> bool { is_at_at_rule(p) || is_at_nested_qualified_rule(p) || is_at_declaration(p) - || is_at_grit_metavariable(p) + || is_at_metavariable(p) } struct DeclarationOrRuleListParseRecovery; @@ -128,8 +127,8 @@ impl ParseNodeList for DeclarationOrRuleList { parse_declaration_with_semicolon(p) } else if is_at_nested_qualified_rule(p) { parse_nested_qualified_rule(p) - } else if is_at_grit_metavariable(p) { - parse_grit_metavariable(p) + } else if is_at_metavariable(p) { + parse_metavariable(p) } else { Absent } diff --git a/crates/biome_css_parser/src/syntax/mod.rs b/crates/biome_css_parser/src/syntax/mod.rs index 0776b36f1f6b..578b420be045 100644 --- a/crates/biome_css_parser/src/syntax/mod.rs +++ b/crates/biome_css_parser/src/syntax/mod.rs @@ -249,23 +249,23 @@ fn parse_declaration_important(p: &mut CssParser) -> ParsedSyntax { } #[inline] -fn is_at_grit_metavariable(p: &mut CssParser) -> bool { +fn is_at_metavariable(p: &mut CssParser) -> bool { p.at(GRIT_METAVARIABLE) } #[inline] -fn is_nth_at_grit_metavariable(p: &mut CssParser, n: usize) -> bool { +fn is_nth_at_metavariable(p: &mut CssParser, n: usize) -> bool { p.nth_at(n, GRIT_METAVARIABLE) } #[inline] -fn parse_grit_metavariable(p: &mut CssParser) -> ParsedSyntax { - if !is_at_grit_metavariable(p) { +fn parse_metavariable(p: &mut CssParser) -> ParsedSyntax { + if !is_at_metavariable(p) { return Absent; } let m = p.start(); p.bump(GRIT_METAVARIABLE); - Present(m.complete(p, CSS_GRIT_METAVARIABLE)) + Present(m.complete(p, CSS_METAVARIABLE)) } #[inline] @@ -279,7 +279,7 @@ pub(crate) fn is_at_any_value(p: &mut CssParser) -> bool { || is_at_ratio(p) || is_at_color(p) || is_at_bracketed_value(p) - || is_at_grit_metavariable(p) + || is_at_metavariable(p) } #[inline] @@ -304,8 +304,8 @@ pub(crate) fn parse_any_value(p: &mut CssParser) -> ParsedSyntax { parse_color(p) } else if is_at_bracketed_value(p) { parse_bracketed_value(p) - } else if is_at_grit_metavariable(p) { - parse_grit_metavariable(p) + } else if is_at_metavariable(p) { + parse_metavariable(p) } else { Absent } diff --git a/crates/biome_css_parser/src/syntax/selector/mod.rs b/crates/biome_css_parser/src/syntax/selector/mod.rs index 9a161d4a5adb..24af5dcc35db 100644 --- a/crates/biome_css_parser/src/syntax/selector/mod.rs +++ b/crates/biome_css_parser/src/syntax/selector/mod.rs @@ -28,7 +28,7 @@ use biome_parser::prelude::ParsedSyntax; use biome_parser::prelude::ParsedSyntax::{Absent, Present}; use biome_parser::{token_set, CompletedMarker, Parser, ParserProgress, TokenSet}; -use super::{is_nth_at_grit_metavariable, parse_grit_metavariable}; +use super::{is_nth_at_metavariable, parse_metavariable}; /// Determines the lexical context for parsing CSS selectors. /// @@ -199,7 +199,7 @@ impl ParseRecovery for SelectorListParseRecovery { /// the elements to which a set of CSS rules apply. #[inline] pub(crate) fn is_nth_at_selector(p: &mut CssParser, n: usize) -> bool { - is_nth_at_compound_selector(p, n) || is_nth_at_grit_metavariable(p, n) + is_nth_at_compound_selector(p, n) || is_nth_at_metavariable(p, n) } /// Parses a CSS selector. @@ -215,8 +215,8 @@ pub(crate) fn parse_selector(p: &mut CssParser) -> ParsedSyntax { if !is_nth_at_selector(p, 0) { return Absent; } - if is_nth_at_grit_metavariable(p, 0) { - parse_grit_metavariable(p) + if is_nth_at_metavariable(p, 0) { + parse_metavariable(p) } else { // In CSS, we have compound selectors and complex selectors. // Compound selectors are simple, unseparated chains of selectors, diff --git a/crates/biome_css_parser/tests/css_test_suite/ok/grit_metavariable/metavar.css.snap b/crates/biome_css_parser/tests/css_test_suite/ok/grit_metavariable/metavar.css.snap index fb430265fee9..3a5b59789418 100644 --- a/crates/biome_css_parser/tests/css_test_suite/ok/grit_metavariable/metavar.css.snap +++ b/crates/biome_css_parser/tests/css_test_suite/ok/grit_metavariable/metavar.css.snap @@ -55,7 +55,7 @@ CssRoot { }, colon_token: COLON@16..18 ":" [] [Whitespace(" ")], value: CssGenericComponentValueList [ - CssGritMetavariable { + CssMetavariable { value_token: GRIT_METAVARIABLE@18..25 "μcolor" [] [], }, ], @@ -86,7 +86,7 @@ CssRoot { block: CssDeclarationOrRuleBlock { l_curly_token: L_CURLY@35..36 "{" [] [], items: CssDeclarationOrRuleList [ - CssGritMetavariable { + CssMetavariable { value_token: GRIT_METAVARIABLE@36..46 "μbar" [Newline("\n"), Whitespace(" ")] [], }, ], @@ -116,7 +116,7 @@ CssRoot { rule: CssMediaAtRule { media_token: MEDIA_KW@62..68 "media" [] [Whitespace(" ")], queries: CssMediaQueryList [ - CssGritMetavariable { + CssMetavariable { value_token: GRIT_METAVARIABLE@68..74 "μbaz" [] [Whitespace(" ")], }, ], @@ -133,7 +133,7 @@ CssRoot { }, CssQualifiedRule { prelude: CssSelectorList [ - CssGritMetavariable { + CssMetavariable { value_token: GRIT_METAVARIABLE@78..86 "μqux" [Newline("\n"), Newline("\n")] [Whitespace(" ")], }, ], @@ -145,7 +145,7 @@ CssRoot { }, CssQualifiedRule { prelude: CssSelectorList [ - CssGritMetavariable { + CssMetavariable { value_token: GRIT_METAVARIABLE@88..96 "μ..." [Newline("\n"), Newline("\n")] [Whitespace(" ")], }, ], @@ -186,7 +186,7 @@ CssRoot { 0: IDENT@6..16 "color" [Newline("\n"), Whitespace(" ")] [] 1: COLON@16..18 ":" [] [Whitespace(" ")] 2: CSS_GENERIC_COMPONENT_VALUE_LIST@18..25 - 0: CSS_GRIT_METAVARIABLE@18..25 + 0: CSS_METAVARIABLE@18..25 0: GRIT_METAVARIABLE@18..25 "μcolor" [] [] 1: (empty) 1: SEMICOLON@25..26 ";" [] [] @@ -204,7 +204,7 @@ CssRoot { 1: CSS_DECLARATION_OR_RULE_BLOCK@35..48 0: L_CURLY@35..36 "{" [] [] 1: CSS_DECLARATION_OR_RULE_LIST@36..46 - 0: CSS_GRIT_METAVARIABLE@36..46 + 0: CSS_METAVARIABLE@36..46 0: GRIT_METAVARIABLE@36..46 "μbar" [Newline("\n"), Whitespace(" ")] [] 2: R_CURLY@46..48 "}" [Newline("\n")] [] 2: CSS_QUALIFIED_RULE@48..78 @@ -225,7 +225,7 @@ CssRoot { 1: CSS_MEDIA_AT_RULE@62..76 0: MEDIA_KW@62..68 "media" [] [Whitespace(" ")] 1: CSS_MEDIA_QUERY_LIST@68..74 - 0: CSS_GRIT_METAVARIABLE@68..74 + 0: CSS_METAVARIABLE@68..74 0: GRIT_METAVARIABLE@68..74 "μbaz" [] [Whitespace(" ")] 2: CSS_DECLARATION_OR_RULE_BLOCK@74..76 0: L_CURLY@74..75 "{" [] [] @@ -234,7 +234,7 @@ CssRoot { 2: R_CURLY@76..78 "}" [Newline("\n")] [] 3: CSS_QUALIFIED_RULE@78..88 0: CSS_SELECTOR_LIST@78..86 - 0: CSS_GRIT_METAVARIABLE@78..86 + 0: CSS_METAVARIABLE@78..86 0: GRIT_METAVARIABLE@78..86 "μqux" [Newline("\n"), Newline("\n")] [Whitespace(" ")] 1: CSS_DECLARATION_OR_RULE_BLOCK@86..88 0: L_CURLY@86..87 "{" [] [] @@ -242,7 +242,7 @@ CssRoot { 2: R_CURLY@87..88 "}" [] [] 4: CSS_QUALIFIED_RULE@88..98 0: CSS_SELECTOR_LIST@88..96 - 0: CSS_GRIT_METAVARIABLE@88..96 + 0: CSS_METAVARIABLE@88..96 0: GRIT_METAVARIABLE@88..96 "μ..." [Newline("\n"), Newline("\n")] [Whitespace(" ")] 1: CSS_DECLARATION_OR_RULE_BLOCK@96..98 0: L_CURLY@96..97 "{" [] [] diff --git a/crates/biome_css_parser/tests/spec_test.rs b/crates/biome_css_parser/tests/spec_test.rs index 8b88ac43f042..e2029c8a41de 100644 --- a/crates/biome_css_parser/tests/spec_test.rs +++ b/crates/biome_css_parser/tests/spec_test.rs @@ -43,7 +43,7 @@ pub fn run(test_case: &str, _snapshot_name: &str, test_directory: &str, outcome_ let mut options = CssParserOptions::default() // it is an internal option that cannot be configured via options.json // TODO: find a way to make it configurable - .allow_grit_metavariables(); + .allow_metavariables(); let options_path = Path::new(test_directory).join("options.json"); @@ -182,7 +182,7 @@ pub fn quick_test() { CssParserOptions::default() .allow_wrong_line_comments() .allow_css_modules() - .allow_grit_metavariables(), + .allow_metavariables(), ); let syntax = root.syntax(); dbg!(&syntax, root.diagnostics(), root.has_errors()); diff --git a/crates/biome_css_syntax/src/generated/kind.rs b/crates/biome_css_syntax/src/generated/kind.rs index 5a0443256199..b78502c7052d 100644 --- a/crates/biome_css_syntax/src/generated/kind.rs +++ b/crates/biome_css_syntax/src/generated/kind.rs @@ -477,7 +477,7 @@ pub enum CssSyntaxKind { CSS_BOGUS_CUSTOM_IDENTIFIER, CSS_BOGUS_KEYFRAMES_NAME, CSS_BOGUS_UNICODE_RANGE_VALUE, - CSS_GRIT_METAVARIABLE, + CSS_METAVARIABLE, #[doc(hidden)] __LAST, } diff --git a/crates/biome_css_syntax/src/generated/macros.rs b/crates/biome_css_syntax/src/generated/macros.rs index f4691472cd51..da71bfaa054c 100644 --- a/crates/biome_css_syntax/src/generated/macros.rs +++ b/crates/biome_css_syntax/src/generated/macros.rs @@ -217,10 +217,6 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::CssGenericProperty::new_unchecked(node) }; $body } - $crate::CssSyntaxKind::CSS_GRIT_METAVARIABLE => { - let $pattern = unsafe { $crate::CssGritMetavariable::new_unchecked(node) }; - $body - } $crate::CssSyntaxKind::CSS_ID_SELECTOR => { let $pattern = unsafe { $crate::CssIdSelector::new_unchecked(node) }; $body @@ -342,6 +338,10 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::CssMediaTypeQuery::new_unchecked(node) }; $body } + $crate::CssSyntaxKind::CSS_METAVARIABLE => { + let $pattern = unsafe { $crate::CssMetavariable::new_unchecked(node) }; + $body + } $crate::CssSyntaxKind::CSS_NAMED_NAMESPACE_PREFIX => { let $pattern = unsafe { $crate::CssNamedNamespacePrefix::new_unchecked(node) }; $body diff --git a/crates/biome_css_syntax/src/generated/nodes.rs b/crates/biome_css_syntax/src/generated/nodes.rs index 4593d71c2f8e..2e98e0fbc519 100644 --- a/crates/biome_css_syntax/src/generated/nodes.rs +++ b/crates/biome_css_syntax/src/generated/nodes.rs @@ -2100,42 +2100,6 @@ pub struct CssGenericPropertyFields { pub value: CssGenericComponentValueList, } #[derive(Clone, PartialEq, Eq, Hash)] -pub struct CssGritMetavariable { - pub(crate) syntax: SyntaxNode, -} -impl CssGritMetavariable { - #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] - #[doc = r""] - #[doc = r" # Safety"] - #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] - #[doc = r" or a match on [SyntaxNode::kind]"] - #[inline] - pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { - Self { syntax } - } - pub fn as_fields(&self) -> CssGritMetavariableFields { - CssGritMetavariableFields { - value_token: self.value_token(), - } - } - pub fn value_token(&self) -> SyntaxResult { - support::required_token(&self.syntax, 0usize) - } -} -#[cfg(feature = "serde")] -impl Serialize for CssGritMetavariable { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.as_fields().serialize(serializer) - } -} -#[cfg_attr(feature = "serde", derive(Serialize))] -pub struct CssGritMetavariableFields { - pub value_token: SyntaxResult, -} -#[derive(Clone, PartialEq, Eq, Hash)] pub struct CssIdSelector { pub(crate) syntax: SyntaxNode, } @@ -3385,6 +3349,42 @@ pub struct CssMediaTypeQueryFields { pub ty: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] +pub struct CssMetavariable { + pub(crate) syntax: SyntaxNode, +} +impl CssMetavariable { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> CssMetavariableFields { + CssMetavariableFields { + value_token: self.value_token(), + } + } + pub fn value_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } +} +#[cfg(feature = "serde")] +impl Serialize for CssMetavariable { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[cfg_attr(feature = "serde", derive(Serialize))] +pub struct CssMetavariableFields { + pub value_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] pub struct CssNamedNamespacePrefix { pub(crate) syntax: SyntaxNode, } @@ -7331,7 +7331,7 @@ pub enum AnyCssDeclarationOrRule { AnyCssRule(AnyCssRule), CssBogus(CssBogus), CssDeclarationWithSemicolon(CssDeclarationWithSemicolon), - CssGritMetavariable(CssGritMetavariable), + CssMetavariable(CssMetavariable), } impl AnyCssDeclarationOrRule { pub fn as_any_css_rule(&self) -> Option<&AnyCssRule> { @@ -7352,9 +7352,9 @@ impl AnyCssDeclarationOrRule { _ => None, } } - pub fn as_css_grit_metavariable(&self) -> Option<&CssGritMetavariable> { + pub fn as_css_metavariable(&self) -> Option<&CssMetavariable> { match &self { - AnyCssDeclarationOrRule::CssGritMetavariable(item) => Some(item), + AnyCssDeclarationOrRule::CssMetavariable(item) => Some(item), _ => None, } } @@ -7889,8 +7889,8 @@ impl AnyCssMediaOrCombinableCondition { pub enum AnyCssMediaQuery { AnyCssMediaTypeQuery(AnyCssMediaTypeQuery), CssBogusMediaQuery(CssBogusMediaQuery), - CssGritMetavariable(CssGritMetavariable), CssMediaConditionQuery(CssMediaConditionQuery), + CssMetavariable(CssMetavariable), } impl AnyCssMediaQuery { pub fn as_any_css_media_type_query(&self) -> Option<&AnyCssMediaTypeQuery> { @@ -7905,15 +7905,15 @@ impl AnyCssMediaQuery { _ => None, } } - pub fn as_css_grit_metavariable(&self) -> Option<&CssGritMetavariable> { + pub fn as_css_media_condition_query(&self) -> Option<&CssMediaConditionQuery> { match &self { - AnyCssMediaQuery::CssGritMetavariable(item) => Some(item), + AnyCssMediaQuery::CssMediaConditionQuery(item) => Some(item), _ => None, } } - pub fn as_css_media_condition_query(&self) -> Option<&CssMediaConditionQuery> { + pub fn as_css_metavariable(&self) -> Option<&CssMetavariable> { match &self { - AnyCssMediaQuery::CssMediaConditionQuery(item) => Some(item), + AnyCssMediaQuery::CssMetavariable(item) => Some(item), _ => None, } } @@ -8508,7 +8508,7 @@ pub enum AnyCssSelector { CssBogusSelector(CssBogusSelector), CssComplexSelector(CssComplexSelector), CssCompoundSelector(CssCompoundSelector), - CssGritMetavariable(CssGritMetavariable), + CssMetavariable(CssMetavariable), } impl AnyCssSelector { pub fn as_css_bogus_selector(&self) -> Option<&CssBogusSelector> { @@ -8529,9 +8529,9 @@ impl AnyCssSelector { _ => None, } } - pub fn as_css_grit_metavariable(&self) -> Option<&CssGritMetavariable> { + pub fn as_css_metavariable(&self) -> Option<&CssMetavariable> { match &self { - AnyCssSelector::CssGritMetavariable(item) => Some(item), + AnyCssSelector::CssMetavariable(item) => Some(item), _ => None, } } @@ -8836,8 +8836,8 @@ pub enum AnyCssValue { CssColor(CssColor), CssCustomIdentifier(CssCustomIdentifier), CssDashedIdentifier(CssDashedIdentifier), - CssGritMetavariable(CssGritMetavariable), CssIdentifier(CssIdentifier), + CssMetavariable(CssMetavariable), CssNumber(CssNumber), CssRatio(CssRatio), CssString(CssString), @@ -8880,15 +8880,15 @@ impl AnyCssValue { _ => None, } } - pub fn as_css_grit_metavariable(&self) -> Option<&CssGritMetavariable> { + pub fn as_css_identifier(&self) -> Option<&CssIdentifier> { match &self { - AnyCssValue::CssGritMetavariable(item) => Some(item), + AnyCssValue::CssIdentifier(item) => Some(item), _ => None, } } - pub fn as_css_identifier(&self) -> Option<&CssIdentifier> { + pub fn as_css_metavariable(&self) -> Option<&CssMetavariable> { match &self { - AnyCssValue::CssIdentifier(item) => Some(item), + AnyCssValue::CssMetavariable(item) => Some(item), _ => None, } } @@ -11007,47 +11007,6 @@ impl From for SyntaxElement { n.syntax.into() } } -impl AstNode for CssGritMetavariable { - type Language = Language; - const KIND_SET: SyntaxKindSet = - SyntaxKindSet::from_raw(RawSyntaxKind(CSS_GRIT_METAVARIABLE as u16)); - fn can_cast(kind: SyntaxKind) -> bool { - kind == CSS_GRIT_METAVARIABLE - } - fn cast(syntax: SyntaxNode) -> Option { - if Self::can_cast(syntax.kind()) { - Some(Self { syntax }) - } else { - None - } - } - fn syntax(&self) -> &SyntaxNode { - &self.syntax - } - fn into_syntax(self) -> SyntaxNode { - self.syntax - } -} -impl std::fmt::Debug for CssGritMetavariable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("CssGritMetavariable") - .field( - "value_token", - &support::DebugSyntaxResult(self.value_token()), - ) - .finish() - } -} -impl From for SyntaxNode { - fn from(n: CssGritMetavariable) -> SyntaxNode { - n.syntax - } -} -impl From for SyntaxElement { - fn from(n: CssGritMetavariable) -> SyntaxElement { - n.syntax.into() - } -} impl AstNode for CssIdSelector { type Language = Language; const KIND_SET: SyntaxKindSet = @@ -12261,6 +12220,47 @@ impl From for SyntaxElement { n.syntax.into() } } +impl AstNode for CssMetavariable { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(CSS_METAVARIABLE as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == CSS_METAVARIABLE + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for CssMetavariable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("CssMetavariable") + .field( + "value_token", + &support::DebugSyntaxResult(self.value_token()), + ) + .finish() + } +} +impl From for SyntaxNode { + fn from(n: CssMetavariable) -> SyntaxNode { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: CssMetavariable) -> SyntaxElement { + n.syntax.into() + } +} impl AstNode for CssNamedNamespacePrefix { type Language = Language; const KIND_SET: SyntaxKindSet = @@ -17173,9 +17173,9 @@ impl From for AnyCssDeclarationOrRule { AnyCssDeclarationOrRule::CssDeclarationWithSemicolon(node) } } -impl From for AnyCssDeclarationOrRule { - fn from(node: CssGritMetavariable) -> AnyCssDeclarationOrRule { - AnyCssDeclarationOrRule::CssGritMetavariable(node) +impl From for AnyCssDeclarationOrRule { + fn from(node: CssMetavariable) -> AnyCssDeclarationOrRule { + AnyCssDeclarationOrRule::CssMetavariable(node) } } impl AstNode for AnyCssDeclarationOrRule { @@ -17183,10 +17183,10 @@ impl AstNode for AnyCssDeclarationOrRule { const KIND_SET: SyntaxKindSet = AnyCssRule::KIND_SET .union(CssBogus::KIND_SET) .union(CssDeclarationWithSemicolon::KIND_SET) - .union(CssGritMetavariable::KIND_SET); + .union(CssMetavariable::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { match kind { - CSS_BOGUS | CSS_DECLARATION_WITH_SEMICOLON | CSS_GRIT_METAVARIABLE => true, + CSS_BOGUS | CSS_DECLARATION_WITH_SEMICOLON | CSS_METAVARIABLE => true, k if AnyCssRule::can_cast(k) => true, _ => false, } @@ -17199,8 +17199,8 @@ impl AstNode for AnyCssDeclarationOrRule { syntax, }) } - CSS_GRIT_METAVARIABLE => { - AnyCssDeclarationOrRule::CssGritMetavariable(CssGritMetavariable { syntax }) + CSS_METAVARIABLE => { + AnyCssDeclarationOrRule::CssMetavariable(CssMetavariable { syntax }) } _ => { if let Some(any_css_rule) = AnyCssRule::cast(syntax) { @@ -17215,7 +17215,7 @@ impl AstNode for AnyCssDeclarationOrRule { match self { AnyCssDeclarationOrRule::CssBogus(it) => &it.syntax, AnyCssDeclarationOrRule::CssDeclarationWithSemicolon(it) => &it.syntax, - AnyCssDeclarationOrRule::CssGritMetavariable(it) => &it.syntax, + AnyCssDeclarationOrRule::CssMetavariable(it) => &it.syntax, AnyCssDeclarationOrRule::AnyCssRule(it) => it.syntax(), } } @@ -17223,7 +17223,7 @@ impl AstNode for AnyCssDeclarationOrRule { match self { AnyCssDeclarationOrRule::CssBogus(it) => it.syntax, AnyCssDeclarationOrRule::CssDeclarationWithSemicolon(it) => it.syntax, - AnyCssDeclarationOrRule::CssGritMetavariable(it) => it.syntax, + AnyCssDeclarationOrRule::CssMetavariable(it) => it.syntax, AnyCssDeclarationOrRule::AnyCssRule(it) => it.into_syntax(), } } @@ -17234,7 +17234,7 @@ impl std::fmt::Debug for AnyCssDeclarationOrRule { AnyCssDeclarationOrRule::AnyCssRule(it) => std::fmt::Debug::fmt(it, f), AnyCssDeclarationOrRule::CssBogus(it) => std::fmt::Debug::fmt(it, f), AnyCssDeclarationOrRule::CssDeclarationWithSemicolon(it) => std::fmt::Debug::fmt(it, f), - AnyCssDeclarationOrRule::CssGritMetavariable(it) => std::fmt::Debug::fmt(it, f), + AnyCssDeclarationOrRule::CssMetavariable(it) => std::fmt::Debug::fmt(it, f), } } } @@ -17244,7 +17244,7 @@ impl From for SyntaxNode { AnyCssDeclarationOrRule::AnyCssRule(it) => it.into(), AnyCssDeclarationOrRule::CssBogus(it) => it.into(), AnyCssDeclarationOrRule::CssDeclarationWithSemicolon(it) => it.into(), - AnyCssDeclarationOrRule::CssGritMetavariable(it) => it.into(), + AnyCssDeclarationOrRule::CssMetavariable(it) => it.into(), } } } @@ -18910,25 +18910,25 @@ impl From for AnyCssMediaQuery { AnyCssMediaQuery::CssBogusMediaQuery(node) } } -impl From for AnyCssMediaQuery { - fn from(node: CssGritMetavariable) -> AnyCssMediaQuery { - AnyCssMediaQuery::CssGritMetavariable(node) - } -} impl From for AnyCssMediaQuery { fn from(node: CssMediaConditionQuery) -> AnyCssMediaQuery { AnyCssMediaQuery::CssMediaConditionQuery(node) } } +impl From for AnyCssMediaQuery { + fn from(node: CssMetavariable) -> AnyCssMediaQuery { + AnyCssMediaQuery::CssMetavariable(node) + } +} impl AstNode for AnyCssMediaQuery { type Language = Language; const KIND_SET: SyntaxKindSet = AnyCssMediaTypeQuery::KIND_SET .union(CssBogusMediaQuery::KIND_SET) - .union(CssGritMetavariable::KIND_SET) - .union(CssMediaConditionQuery::KIND_SET); + .union(CssMediaConditionQuery::KIND_SET) + .union(CssMetavariable::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { match kind { - CSS_BOGUS_MEDIA_QUERY | CSS_GRIT_METAVARIABLE | CSS_MEDIA_CONDITION_QUERY => true, + CSS_BOGUS_MEDIA_QUERY | CSS_MEDIA_CONDITION_QUERY | CSS_METAVARIABLE => true, k if AnyCssMediaTypeQuery::can_cast(k) => true, _ => false, } @@ -18938,12 +18938,10 @@ impl AstNode for AnyCssMediaQuery { CSS_BOGUS_MEDIA_QUERY => { AnyCssMediaQuery::CssBogusMediaQuery(CssBogusMediaQuery { syntax }) } - CSS_GRIT_METAVARIABLE => { - AnyCssMediaQuery::CssGritMetavariable(CssGritMetavariable { syntax }) - } CSS_MEDIA_CONDITION_QUERY => { AnyCssMediaQuery::CssMediaConditionQuery(CssMediaConditionQuery { syntax }) } + CSS_METAVARIABLE => AnyCssMediaQuery::CssMetavariable(CssMetavariable { syntax }), _ => { if let Some(any_css_media_type_query) = AnyCssMediaTypeQuery::cast(syntax) { return Some(AnyCssMediaQuery::AnyCssMediaTypeQuery( @@ -18958,16 +18956,16 @@ impl AstNode for AnyCssMediaQuery { fn syntax(&self) -> &SyntaxNode { match self { AnyCssMediaQuery::CssBogusMediaQuery(it) => &it.syntax, - AnyCssMediaQuery::CssGritMetavariable(it) => &it.syntax, AnyCssMediaQuery::CssMediaConditionQuery(it) => &it.syntax, + AnyCssMediaQuery::CssMetavariable(it) => &it.syntax, AnyCssMediaQuery::AnyCssMediaTypeQuery(it) => it.syntax(), } } fn into_syntax(self) -> SyntaxNode { match self { AnyCssMediaQuery::CssBogusMediaQuery(it) => it.syntax, - AnyCssMediaQuery::CssGritMetavariable(it) => it.syntax, AnyCssMediaQuery::CssMediaConditionQuery(it) => it.syntax, + AnyCssMediaQuery::CssMetavariable(it) => it.syntax, AnyCssMediaQuery::AnyCssMediaTypeQuery(it) => it.into_syntax(), } } @@ -18977,8 +18975,8 @@ impl std::fmt::Debug for AnyCssMediaQuery { match self { AnyCssMediaQuery::AnyCssMediaTypeQuery(it) => std::fmt::Debug::fmt(it, f), AnyCssMediaQuery::CssBogusMediaQuery(it) => std::fmt::Debug::fmt(it, f), - AnyCssMediaQuery::CssGritMetavariable(it) => std::fmt::Debug::fmt(it, f), AnyCssMediaQuery::CssMediaConditionQuery(it) => std::fmt::Debug::fmt(it, f), + AnyCssMediaQuery::CssMetavariable(it) => std::fmt::Debug::fmt(it, f), } } } @@ -18987,8 +18985,8 @@ impl From for SyntaxNode { match n { AnyCssMediaQuery::AnyCssMediaTypeQuery(it) => it.into(), AnyCssMediaQuery::CssBogusMediaQuery(it) => it.into(), - AnyCssMediaQuery::CssGritMetavariable(it) => it.into(), AnyCssMediaQuery::CssMediaConditionQuery(it) => it.into(), + AnyCssMediaQuery::CssMetavariable(it) => it.into(), } } } @@ -20664,9 +20662,9 @@ impl From for AnyCssSelector { AnyCssSelector::CssCompoundSelector(node) } } -impl From for AnyCssSelector { - fn from(node: CssGritMetavariable) -> AnyCssSelector { - AnyCssSelector::CssGritMetavariable(node) +impl From for AnyCssSelector { + fn from(node: CssMetavariable) -> AnyCssSelector { + AnyCssSelector::CssMetavariable(node) } } impl AstNode for AnyCssSelector { @@ -20674,14 +20672,11 @@ impl AstNode for AnyCssSelector { const KIND_SET: SyntaxKindSet = CssBogusSelector::KIND_SET .union(CssComplexSelector::KIND_SET) .union(CssCompoundSelector::KIND_SET) - .union(CssGritMetavariable::KIND_SET); + .union(CssMetavariable::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, - CSS_BOGUS_SELECTOR - | CSS_COMPLEX_SELECTOR - | CSS_COMPOUND_SELECTOR - | CSS_GRIT_METAVARIABLE + CSS_BOGUS_SELECTOR | CSS_COMPLEX_SELECTOR | CSS_COMPOUND_SELECTOR | CSS_METAVARIABLE ) } fn cast(syntax: SyntaxNode) -> Option { @@ -20693,9 +20688,7 @@ impl AstNode for AnyCssSelector { CSS_COMPOUND_SELECTOR => { AnyCssSelector::CssCompoundSelector(CssCompoundSelector { syntax }) } - CSS_GRIT_METAVARIABLE => { - AnyCssSelector::CssGritMetavariable(CssGritMetavariable { syntax }) - } + CSS_METAVARIABLE => AnyCssSelector::CssMetavariable(CssMetavariable { syntax }), _ => return None, }; Some(res) @@ -20705,7 +20698,7 @@ impl AstNode for AnyCssSelector { AnyCssSelector::CssBogusSelector(it) => &it.syntax, AnyCssSelector::CssComplexSelector(it) => &it.syntax, AnyCssSelector::CssCompoundSelector(it) => &it.syntax, - AnyCssSelector::CssGritMetavariable(it) => &it.syntax, + AnyCssSelector::CssMetavariable(it) => &it.syntax, } } fn into_syntax(self) -> SyntaxNode { @@ -20713,7 +20706,7 @@ impl AstNode for AnyCssSelector { AnyCssSelector::CssBogusSelector(it) => it.syntax, AnyCssSelector::CssComplexSelector(it) => it.syntax, AnyCssSelector::CssCompoundSelector(it) => it.syntax, - AnyCssSelector::CssGritMetavariable(it) => it.syntax, + AnyCssSelector::CssMetavariable(it) => it.syntax, } } } @@ -20723,7 +20716,7 @@ impl std::fmt::Debug for AnyCssSelector { AnyCssSelector::CssBogusSelector(it) => std::fmt::Debug::fmt(it, f), AnyCssSelector::CssComplexSelector(it) => std::fmt::Debug::fmt(it, f), AnyCssSelector::CssCompoundSelector(it) => std::fmt::Debug::fmt(it, f), - AnyCssSelector::CssGritMetavariable(it) => std::fmt::Debug::fmt(it, f), + AnyCssSelector::CssMetavariable(it) => std::fmt::Debug::fmt(it, f), } } } @@ -20733,7 +20726,7 @@ impl From for SyntaxNode { AnyCssSelector::CssBogusSelector(it) => it.into(), AnyCssSelector::CssComplexSelector(it) => it.into(), AnyCssSelector::CssCompoundSelector(it) => it.into(), - AnyCssSelector::CssGritMetavariable(it) => it.into(), + AnyCssSelector::CssMetavariable(it) => it.into(), } } } @@ -21605,16 +21598,16 @@ impl From for AnyCssValue { AnyCssValue::CssDashedIdentifier(node) } } -impl From for AnyCssValue { - fn from(node: CssGritMetavariable) -> AnyCssValue { - AnyCssValue::CssGritMetavariable(node) - } -} impl From for AnyCssValue { fn from(node: CssIdentifier) -> AnyCssValue { AnyCssValue::CssIdentifier(node) } } +impl From for AnyCssValue { + fn from(node: CssMetavariable) -> AnyCssValue { + AnyCssValue::CssMetavariable(node) + } +} impl From for AnyCssValue { fn from(node: CssNumber) -> AnyCssValue { AnyCssValue::CssNumber(node) @@ -21643,8 +21636,8 @@ impl AstNode for AnyCssValue { .union(CssColor::KIND_SET) .union(CssCustomIdentifier::KIND_SET) .union(CssDashedIdentifier::KIND_SET) - .union(CssGritMetavariable::KIND_SET) .union(CssIdentifier::KIND_SET) + .union(CssMetavariable::KIND_SET) .union(CssNumber::KIND_SET) .union(CssRatio::KIND_SET) .union(CssString::KIND_SET) @@ -21655,8 +21648,8 @@ impl AstNode for AnyCssValue { | CSS_COLOR | CSS_CUSTOM_IDENTIFIER | CSS_DASHED_IDENTIFIER - | CSS_GRIT_METAVARIABLE | CSS_IDENTIFIER + | CSS_METAVARIABLE | CSS_NUMBER | CSS_RATIO | CSS_STRING @@ -21676,10 +21669,8 @@ impl AstNode for AnyCssValue { CSS_DASHED_IDENTIFIER => { AnyCssValue::CssDashedIdentifier(CssDashedIdentifier { syntax }) } - CSS_GRIT_METAVARIABLE => { - AnyCssValue::CssGritMetavariable(CssGritMetavariable { syntax }) - } CSS_IDENTIFIER => AnyCssValue::CssIdentifier(CssIdentifier { syntax }), + CSS_METAVARIABLE => AnyCssValue::CssMetavariable(CssMetavariable { syntax }), CSS_NUMBER => AnyCssValue::CssNumber(CssNumber { syntax }), CSS_RATIO => AnyCssValue::CssRatio(CssRatio { syntax }), CSS_STRING => AnyCssValue::CssString(CssString { syntax }), @@ -21705,8 +21696,8 @@ impl AstNode for AnyCssValue { AnyCssValue::CssColor(it) => &it.syntax, AnyCssValue::CssCustomIdentifier(it) => &it.syntax, AnyCssValue::CssDashedIdentifier(it) => &it.syntax, - AnyCssValue::CssGritMetavariable(it) => &it.syntax, AnyCssValue::CssIdentifier(it) => &it.syntax, + AnyCssValue::CssMetavariable(it) => &it.syntax, AnyCssValue::CssNumber(it) => &it.syntax, AnyCssValue::CssRatio(it) => &it.syntax, AnyCssValue::CssString(it) => &it.syntax, @@ -21721,8 +21712,8 @@ impl AstNode for AnyCssValue { AnyCssValue::CssColor(it) => it.syntax, AnyCssValue::CssCustomIdentifier(it) => it.syntax, AnyCssValue::CssDashedIdentifier(it) => it.syntax, - AnyCssValue::CssGritMetavariable(it) => it.syntax, AnyCssValue::CssIdentifier(it) => it.syntax, + AnyCssValue::CssMetavariable(it) => it.syntax, AnyCssValue::CssNumber(it) => it.syntax, AnyCssValue::CssRatio(it) => it.syntax, AnyCssValue::CssString(it) => it.syntax, @@ -21741,8 +21732,8 @@ impl std::fmt::Debug for AnyCssValue { AnyCssValue::CssColor(it) => std::fmt::Debug::fmt(it, f), AnyCssValue::CssCustomIdentifier(it) => std::fmt::Debug::fmt(it, f), AnyCssValue::CssDashedIdentifier(it) => std::fmt::Debug::fmt(it, f), - AnyCssValue::CssGritMetavariable(it) => std::fmt::Debug::fmt(it, f), AnyCssValue::CssIdentifier(it) => std::fmt::Debug::fmt(it, f), + AnyCssValue::CssMetavariable(it) => std::fmt::Debug::fmt(it, f), AnyCssValue::CssNumber(it) => std::fmt::Debug::fmt(it, f), AnyCssValue::CssRatio(it) => std::fmt::Debug::fmt(it, f), AnyCssValue::CssString(it) => std::fmt::Debug::fmt(it, f), @@ -21759,8 +21750,8 @@ impl From for SyntaxNode { AnyCssValue::CssColor(it) => it.into(), AnyCssValue::CssCustomIdentifier(it) => it.into(), AnyCssValue::CssDashedIdentifier(it) => it.into(), - AnyCssValue::CssGritMetavariable(it) => it.into(), AnyCssValue::CssIdentifier(it) => it.into(), + AnyCssValue::CssMetavariable(it) => it.into(), AnyCssValue::CssNumber(it) => it.into(), AnyCssValue::CssRatio(it) => it.into(), AnyCssValue::CssString(it) => it.into(), @@ -22684,11 +22675,6 @@ impl std::fmt::Display for CssGenericProperty { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for CssGritMetavariable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(self.syntax(), f) - } -} impl std::fmt::Display for CssIdSelector { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -22834,6 +22820,11 @@ impl std::fmt::Display for CssMediaTypeQuery { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for CssMetavariable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for CssNamedNamespacePrefix { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/crates/biome_css_syntax/src/generated/nodes_mut.rs b/crates/biome_css_syntax/src/generated/nodes_mut.rs index 557e7e6861d3..795c38da835c 100644 --- a/crates/biome_css_syntax/src/generated/nodes_mut.rs +++ b/crates/biome_css_syntax/src/generated/nodes_mut.rs @@ -841,14 +841,6 @@ impl CssGenericProperty { ) } } -impl CssGritMetavariable { - pub fn with_value_token(self, element: SyntaxToken) -> Self { - Self::unwrap_cast( - self.syntax - .splice_slots(0usize..=0usize, once(Some(element.into()))), - ) - } -} impl CssIdSelector { pub fn with_hash_token(self, element: SyntaxToken) -> Self { Self::unwrap_cast( @@ -1327,6 +1319,14 @@ impl CssMediaTypeQuery { ) } } +impl CssMetavariable { + pub fn with_value_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } +} impl CssNamedNamespacePrefix { pub fn with_name(self, element: CssIdentifier) -> Self { Self::unwrap_cast( diff --git a/crates/biome_formatter/src/diagnostics.rs b/crates/biome_formatter/src/diagnostics.rs index 4bb1ea987421..17ca1f710628 100644 --- a/crates/biome_formatter/src/diagnostics.rs +++ b/crates/biome_formatter/src/diagnostics.rs @@ -55,7 +55,9 @@ impl From for FormatError { impl From<&SyntaxError> for FormatError { fn from(syntax_error: &SyntaxError) -> Self { match syntax_error { - SyntaxError::MissingRequiredChild => FormatError::SyntaxError, + SyntaxError::MissingRequiredChild | SyntaxError::UnexpectedMetavariable => { + FormatError::SyntaxError + } } } } diff --git a/crates/biome_grit_patterns/src/errors.rs b/crates/biome_grit_patterns/src/errors.rs index 8f20db9aa874..325d70650478 100644 --- a/crates/biome_grit_patterns/src/errors.rs +++ b/crates/biome_grit_patterns/src/errors.rs @@ -15,6 +15,9 @@ pub enum CompileError { /// Used for missing syntax nodes. MissingSyntaxNode, + /// A metavariables was discovered in an unexpected context. + UnexpectedMetavariable, + /// If a function or bubble pattern has multiple parameters with the same name. DuplicateParameters, @@ -74,6 +77,9 @@ impl Diagnostic for CompileError { CompileError::MissingSyntaxNode => { fmt.write_markup(markup! { "A syntax node was missing" }) } + CompileError::UnexpectedMetavariable => { + fmt.write_markup(markup! { "Unexpected metavariable" }) + } CompileError::DuplicateParameters => { fmt.write_markup(markup! { "Duplicate parameters" }) } @@ -151,6 +157,7 @@ impl From for CompileError { fn from(error: SyntaxError) -> Self { match error { SyntaxError::MissingRequiredChild => Self::MissingSyntaxNode, + SyntaxError::UnexpectedMetavariable => Self::UnexpectedMetavariable, } } } diff --git a/crates/biome_grit_patterns/src/grit_target_language/js_target_language.rs b/crates/biome_grit_patterns/src/grit_target_language/js_target_language.rs index 4a420f0f0fb1..1635411d1376 100644 --- a/crates/biome_grit_patterns/src/grit_target_language/js_target_language.rs +++ b/crates/biome_grit_patterns/src/grit_target_language/js_target_language.rs @@ -124,7 +124,7 @@ impl GritTargetLanguageImpl for JsTargetLanguage { } fn metavariable_kind() -> Self::Kind { - JsSyntaxKind::JS_GRIT_METAVARIABLE + JsSyntaxKind::JS_METAVARIABLE } fn is_alternative_metavariable_kind(kind: GritTargetSyntaxKind) -> bool { diff --git a/crates/biome_js_analyze/src/lint/complexity/no_static_only_class.rs b/crates/biome_js_analyze/src/lint/complexity/no_static_only_class.rs index 0a892c131ecd..e3d5e45361c9 100644 --- a/crates/biome_js_analyze/src/lint/complexity/no_static_only_class.rs +++ b/crates/biome_js_analyze/src/lint/complexity/no_static_only_class.rs @@ -153,8 +153,9 @@ impl Rule for NoStaticOnlyClass { .members() .iter() .filter_map(|member| match member { - AnyJsClassMember::JsBogusMember(_) => None, - AnyJsClassMember::JsEmptyClassMember(_) => None, + AnyJsClassMember::JsBogusMember(_) + | AnyJsClassMember::JsMetavariable(_) + | AnyJsClassMember::JsEmptyClassMember(_) => None, AnyJsClassMember::JsConstructorClassMember(_) => Some(false), // See GH#4482: Constructors are not regarded as static AnyJsClassMember::TsConstructorSignatureClassMember(_) => Some(false), // See GH#4482: Constructors are not regarded as static AnyJsClassMember::JsGetterClassMember(m) => Some(m.has_static_modifier()), diff --git a/crates/biome_js_analyze/src/lint/correctness/no_invalid_constructor_super.rs b/crates/biome_js_analyze/src/lint/correctness/no_invalid_constructor_super.rs index 5c983c4d6492..8d824099200f 100644 --- a/crates/biome_js_analyze/src/lint/correctness/no_invalid_constructor_super.rs +++ b/crates/biome_js_analyze/src/lint/correctness/no_invalid_constructor_super.rs @@ -222,6 +222,7 @@ fn is_valid_constructor(expression: AnyJsExpression) -> Option { | AnyJsExpression::JsArrowFunctionExpression(_) | AnyJsExpression::JsBinaryExpression(_) | AnyJsExpression::JsBogusExpression(_) + | AnyJsExpression::JsMetavariable(_) | AnyJsExpression::JsInstanceofExpression(_) | AnyJsExpression::JsObjectExpression(_) | AnyJsExpression::JsPostUpdateExpression(_) diff --git a/crates/biome_js_analyze/src/lint/style/use_const.rs b/crates/biome_js_analyze/src/lint/style/use_const.rs index ff1da1f72225..5c93a42c6f3b 100644 --- a/crates/biome_js_analyze/src/lint/style/use_const.rs +++ b/crates/biome_js_analyze/src/lint/style/use_const.rs @@ -315,7 +315,7 @@ fn with_object_binding_pat_identifiers( P::JsObjectBindingPatternShorthandProperty(p) => p .identifier() .map_or(false, |it| with_binding_identifier(it, f)), - P::JsBogusBinding(_) => false, + P::JsBogusBinding(_) | P::JsMetavariable(_) => false, } }) } @@ -344,7 +344,7 @@ fn with_binding_identifier( ) -> bool { match binding { AnyJsBinding::JsIdentifierBinding(id) => f(id), - AnyJsBinding::JsBogusBinding(_) => false, + AnyJsBinding::JsBogusBinding(_) | AnyJsBinding::JsMetavariable(_) => false, } } diff --git a/crates/biome_js_analyze/src/lint/style/use_naming_convention.rs b/crates/biome_js_analyze/src/lint/style/use_naming_convention.rs index 2e3c8330dad7..4cd61880c154 100644 --- a/crates/biome_js_analyze/src/lint/style/use_naming_convention.rs +++ b/crates/biome_js_analyze/src/lint/style/use_naming_convention.rs @@ -1216,6 +1216,7 @@ impl Selector { scope, } = match member { AnyJsClassMember::JsBogusMember(_) + | AnyJsClassMember::JsMetavariable(_) | AnyJsClassMember::JsConstructorClassMember(_) | AnyJsClassMember::TsConstructorSignatureClassMember(_) | AnyJsClassMember::JsEmptyClassMember(_) diff --git a/crates/biome_js_analyze/src/lint/suspicious/no_duplicate_parameters.rs b/crates/biome_js_analyze/src/lint/suspicious/no_duplicate_parameters.rs index 3a9ced687449..f0ce7acebbaa 100644 --- a/crates/biome_js_analyze/src/lint/suspicious/no_duplicate_parameters.rs +++ b/crates/biome_js_analyze/src/lint/suspicious/no_duplicate_parameters.rs @@ -113,7 +113,7 @@ fn traverse_binding( return Some(id_binding); } } - AnyJsBinding::JsBogusBinding(_) => {} + AnyJsBinding::JsBogusBinding(_) | AnyJsBinding::JsMetavariable(_) => {} }, AnyJsBindingPattern::JsArrayBindingPattern(inner_binding) => { return inner_binding.elements().into_iter().find_map(|element| { @@ -150,7 +150,9 @@ fn traverse_binding( AnyJsBinding::JsIdentifierBinding(binding) => { track_binding(&binding, tracked_bindings).then_some(binding) } - AnyJsBinding::JsBogusBinding(_) => None, + AnyJsBinding::JsBogusBinding(_) | AnyJsBinding::JsMetavariable(_) => { + None + } } } AnyJsObjectBindingPatternMember::JsObjectBindingPatternShorthandProperty( @@ -159,9 +161,10 @@ fn traverse_binding( AnyJsBinding::JsIdentifierBinding(id_binding) => { track_binding(&id_binding, tracked_bindings).then_some(id_binding) } - AnyJsBinding::JsBogusBinding(_) => None, + AnyJsBinding::JsBogusBinding(_) | AnyJsBinding::JsMetavariable(_) => None, }, - AnyJsObjectBindingPatternMember::JsBogusBinding(_) => None, + AnyJsObjectBindingPatternMember::JsBogusBinding(_) + | AnyJsObjectBindingPatternMember::JsMetavariable(_) => None, } }) } diff --git a/crates/biome_js_analyze/src/lint/suspicious/no_misleading_instantiator.rs b/crates/biome_js_analyze/src/lint/suspicious/no_misleading_instantiator.rs index 83302975eb16..ab4bc95296b0 100644 --- a/crates/biome_js_analyze/src/lint/suspicious/no_misleading_instantiator.rs +++ b/crates/biome_js_analyze/src/lint/suspicious/no_misleading_instantiator.rs @@ -150,7 +150,12 @@ impl Rule for NoMisleadingInstantiator { /// Checks if the interface has a misleading constructor or new method. fn check_interface_methods(decl: &TsInterfaceDeclaration) -> Option { - let interface_ident = decl.id().ok()?.name_token().ok()?; + let interface_ident = decl + .id() + .ok()? + .as_ts_identifier_binding()? + .name_token() + .ok()?; for member in decl.members() { match member { AnyTsTypeMember::TsConstructSignatureTypeMember(construct) diff --git a/crates/biome_js_analyze/src/lint/suspicious/no_then_property.rs b/crates/biome_js_analyze/src/lint/suspicious/no_then_property.rs index bd782824c848..00119ad80cb0 100644 --- a/crates/biome_js_analyze/src/lint/suspicious/no_then_property.rs +++ b/crates/biome_js_analyze/src/lint/suspicious/no_then_property.rs @@ -217,6 +217,7 @@ fn process_js_method_object_member(node: &JsMethodObjectMember) -> Option return None, } None } diff --git a/crates/biome_js_analyze/src/lint/suspicious/no_unsafe_declaration_merging.rs b/crates/biome_js_analyze/src/lint/suspicious/no_unsafe_declaration_merging.rs index 3d6d8f093d85..e76dba61e201 100644 --- a/crates/biome_js_analyze/src/lint/suspicious/no_unsafe_declaration_merging.rs +++ b/crates/biome_js_analyze/src/lint/suspicious/no_unsafe_declaration_merging.rs @@ -59,7 +59,10 @@ impl Rule for NoUnsafeDeclarationMerging { let ts_interface = ctx.query(); let model = ctx.model(); let interface_binding = ts_interface.id().ok()?; - let interface_name = interface_binding.name_token().ok()?; + let interface_name = interface_binding + .as_ts_identifier_binding()? + .name_token() + .ok()?; let scope = model.scope(ts_interface.syntax()).parent()?; for binding in scope.bindings() { if let Some(AnyJsBindingDeclaration::JsClassDeclaration(class)) = diff --git a/crates/biome_js_factory/src/generated/node_factory.rs b/crates/biome_js_factory/src/generated/node_factory.rs index 30a8fa06ca70..6e9666567949 100644 --- a/crates/biome_js_factory/src/generated/node_factory.rs +++ b/crates/biome_js_factory/src/generated/node_factory.rs @@ -1035,7 +1035,7 @@ impl JsExportDefaultExpressionClauseBuilder { pub fn js_export_from_clause( star_token: SyntaxToken, from_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, ) -> JsExportFromClauseBuilder { JsExportFromClauseBuilder { star_token, @@ -1050,7 +1050,7 @@ pub fn js_export_from_clause( pub struct JsExportFromClauseBuilder { star_token: SyntaxToken, from_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, type_token: Option, export_as: Option, assertion: Option, @@ -1139,7 +1139,7 @@ pub fn js_export_named_from_clause( specifiers: JsExportNamedFromSpecifierList, r_curly_token: SyntaxToken, from_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, ) -> JsExportNamedFromClauseBuilder { JsExportNamedFromClauseBuilder { l_curly_token, @@ -1157,7 +1157,7 @@ pub struct JsExportNamedFromClauseBuilder { specifiers: JsExportNamedFromSpecifierList, r_curly_token: SyntaxToken, from_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, type_token: Option, assertion: Option, semicolon_token: Option, @@ -2017,14 +2017,14 @@ pub fn js_import_assertion_entry( ], )) } -pub fn js_import_bare_clause(source: JsModuleSource) -> JsImportBareClauseBuilder { +pub fn js_import_bare_clause(source: AnyJsModuleSource) -> JsImportBareClauseBuilder { JsImportBareClauseBuilder { source, assertion: None, } } pub struct JsImportBareClauseBuilder { - source: JsModuleSource, + source: AnyJsModuleSource, assertion: Option, } impl JsImportBareClauseBuilder { @@ -2060,7 +2060,7 @@ pub fn js_import_combined_clause( comma_token: SyntaxToken, specifier: AnyJsCombinedSpecifier, from_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, ) -> JsImportCombinedClauseBuilder { JsImportCombinedClauseBuilder { default_specifier, @@ -2076,7 +2076,7 @@ pub struct JsImportCombinedClauseBuilder { comma_token: SyntaxToken, specifier: AnyJsCombinedSpecifier, from_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, assertion: Option, } impl JsImportCombinedClauseBuilder { @@ -2102,7 +2102,7 @@ impl JsImportCombinedClauseBuilder { pub fn js_import_default_clause( default_specifier: JsDefaultImportSpecifier, from_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, ) -> JsImportDefaultClauseBuilder { JsImportDefaultClauseBuilder { default_specifier, @@ -2115,7 +2115,7 @@ pub fn js_import_default_clause( pub struct JsImportDefaultClauseBuilder { default_specifier: JsDefaultImportSpecifier, from_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, type_token: Option, assertion: Option, } @@ -2159,7 +2159,7 @@ pub fn js_import_meta_expression( pub fn js_import_named_clause( named_specifiers: JsNamedImportSpecifiers, from_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, ) -> JsImportNamedClauseBuilder { JsImportNamedClauseBuilder { named_specifiers, @@ -2172,7 +2172,7 @@ pub fn js_import_named_clause( pub struct JsImportNamedClauseBuilder { named_specifiers: JsNamedImportSpecifiers, from_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, type_token: Option, assertion: Option, } @@ -2202,7 +2202,7 @@ impl JsImportNamedClauseBuilder { pub fn js_import_namespace_clause( namespace_specifier: JsNamespaceImportSpecifier, from_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, ) -> JsImportNamespaceClauseBuilder { JsImportNamespaceClauseBuilder { namespace_specifier, @@ -2215,7 +2215,7 @@ pub fn js_import_namespace_clause( pub struct JsImportNamespaceClauseBuilder { namespace_specifier: JsNamespaceImportSpecifier, from_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, type_token: Option, assertion: Option, } @@ -2328,6 +2328,12 @@ pub fn js_logical_expression( ], )) } +pub fn js_metavariable(value_token: SyntaxToken) -> JsMetavariable { + JsMetavariable::unwrap_cast(SyntaxNode::new_detached( + JsSyntaxKind::JS_METAVARIABLE, + [Some(SyntaxElement::Token(value_token))], + )) +} pub fn js_method_class_member( modifiers: JsMethodModifierList, name: AnyJsClassMemberName, @@ -4697,7 +4703,7 @@ pub fn ts_extends_clause(extends_token: SyntaxToken, types: TsTypeList) -> TsExt } pub fn ts_external_module_declaration( module_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, ) -> TsExternalModuleDeclarationBuilder { TsExternalModuleDeclarationBuilder { module_token, @@ -4707,7 +4713,7 @@ pub fn ts_external_module_declaration( } pub struct TsExternalModuleDeclarationBuilder { module_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, body: Option, } impl TsExternalModuleDeclarationBuilder { @@ -4730,7 +4736,7 @@ impl TsExternalModuleDeclarationBuilder { pub fn ts_external_module_reference( require_token: SyntaxToken, l_paren_token: SyntaxToken, - source: JsModuleSource, + source: AnyJsModuleSource, r_paren_token: SyntaxToken, ) -> TsExternalModuleReference { TsExternalModuleReference::unwrap_cast(SyntaxNode::new_detached( @@ -5232,7 +5238,7 @@ pub fn ts_instantiation_expression( } pub fn ts_interface_declaration( interface_token: SyntaxToken, - id: TsIdentifierBinding, + id: AnyTsIdentifierBinding, l_curly_token: SyntaxToken, members: TsTypeMemberList, r_curly_token: SyntaxToken, @@ -5249,7 +5255,7 @@ pub fn ts_interface_declaration( } pub struct TsInterfaceDeclarationBuilder { interface_token: SyntaxToken, - id: TsIdentifierBinding, + id: AnyTsIdentifierBinding, l_curly_token: SyntaxToken, members: TsTypeMemberList, r_curly_token: SyntaxToken, @@ -6247,7 +6253,7 @@ pub fn ts_tuple_type( } pub fn ts_type_alias_declaration( type_token: SyntaxToken, - binding_identifier: TsIdentifierBinding, + binding_identifier: AnyTsIdentifierBinding, eq_token: SyntaxToken, ty: AnyTsType, ) -> TsTypeAliasDeclarationBuilder { @@ -6262,7 +6268,7 @@ pub fn ts_type_alias_declaration( } pub struct TsTypeAliasDeclarationBuilder { type_token: SyntaxToken, - binding_identifier: TsIdentifierBinding, + binding_identifier: AnyTsIdentifierBinding, eq_token: SyntaxToken, ty: AnyTsType, type_parameters: Option, diff --git a/crates/biome_js_factory/src/generated/syntax_factory.rs b/crates/biome_js_factory/src/generated/syntax_factory.rs index c114d1eda91d..4e265b9ebd0a 100644 --- a/crates/biome_js_factory/src/generated/syntax_factory.rs +++ b/crates/biome_js_factory/src/generated/syntax_factory.rs @@ -1659,7 +1659,7 @@ impl SyntaxFactory for JsSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if JsModuleSource::can_cast(element.kind()) { + if AnyJsModuleSource::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -1774,7 +1774,7 @@ impl SyntaxFactory for JsSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if JsModuleSource::can_cast(element.kind()) { + if AnyJsModuleSource::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -2877,7 +2877,7 @@ impl SyntaxFactory for JsSyntaxFactory { let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element { - if JsModuleSource::can_cast(element.kind()) { + if AnyJsModuleSource::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -2957,7 +2957,7 @@ impl SyntaxFactory for JsSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if JsModuleSource::can_cast(element.kind()) { + if AnyJsModuleSource::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -3004,7 +3004,7 @@ impl SyntaxFactory for JsSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if JsModuleSource::can_cast(element.kind()) { + if AnyJsModuleSource::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -3084,7 +3084,7 @@ impl SyntaxFactory for JsSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if JsModuleSource::can_cast(element.kind()) { + if AnyJsModuleSource::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -3131,7 +3131,7 @@ impl SyntaxFactory for JsSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if JsModuleSource::can_cast(element.kind()) { + if AnyJsModuleSource::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -3367,6 +3367,25 @@ impl SyntaxFactory for JsSyntaxFactory { } slots.into_node(JS_LOGICAL_EXPRESSION, children) } + JS_METAVARIABLE => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element { + if element.kind() == GRIT_METAVARIABLE { + slots.mark_present(); + current_element = elements.next(); + } + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + JS_METAVARIABLE.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(JS_METAVARIABLE, children) + } JS_METHOD_CLASS_MEMBER => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<9usize> = RawNodeSlots::default(); @@ -7145,7 +7164,7 @@ impl SyntaxFactory for JsSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if JsModuleSource::can_cast(element.kind()) { + if AnyJsModuleSource::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -7185,7 +7204,7 @@ impl SyntaxFactory for JsSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if JsModuleSource::can_cast(element.kind()) { + if AnyJsModuleSource::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -7884,7 +7903,7 @@ impl SyntaxFactory for JsSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if TsIdentifierBinding::can_cast(element.kind()) { + if AnyTsIdentifierBinding::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } @@ -9426,7 +9445,7 @@ impl SyntaxFactory for JsSyntaxFactory { } slots.next_slot(); if let Some(element) = ¤t_element { - if TsIdentifierBinding::can_cast(element.kind()) { + if AnyTsIdentifierBinding::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); } diff --git a/crates/biome_js_formatter/src/generated.rs b/crates/biome_js_formatter/src/generated.rs index 2db2e99696e3..ec0e5390460c 100644 --- a/crates/biome_js_formatter/src/generated.rs +++ b/crates/biome_js_formatter/src/generated.rs @@ -3231,6 +3231,42 @@ impl IntoFormat for biome_js_syntax::JsLogicalExpression { ) } } +impl FormatRule + for crate::js::auxiliary::metavariable::FormatJsMetavariable +{ + type Context = JsFormatContext; + #[inline(always)] + fn fmt(&self, node: &biome_js_syntax::JsMetavariable, f: &mut JsFormatter) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_js_syntax::JsMetavariable { + type Format<'a> = FormatRefWithRule< + 'a, + biome_js_syntax::JsMetavariable, + crate::js::auxiliary::metavariable::FormatJsMetavariable, + >; + fn format(&self) -> Self::Format<'_> { + #![allow(clippy::default_constructed_unit_structs)] + FormatRefWithRule::new( + self, + crate::js::auxiliary::metavariable::FormatJsMetavariable::default(), + ) + } +} +impl IntoFormat for biome_js_syntax::JsMetavariable { + type Format = FormatOwnedWithRule< + biome_js_syntax::JsMetavariable, + crate::js::auxiliary::metavariable::FormatJsMetavariable, + >; + fn into_format(self) -> Self::Format { + #![allow(clippy::default_constructed_unit_structs)] + FormatOwnedWithRule::new( + self, + crate::js::auxiliary::metavariable::FormatJsMetavariable::default(), + ) + } +} impl FormatRule for crate::js::classes::method_class_member::FormatJsMethodClassMember { @@ -12568,6 +12604,33 @@ impl IntoFormat for biome_js_syntax::AnyJsModuleItem { ) } } +impl AsFormat for biome_js_syntax::AnyJsModuleSource { + type Format<'a> = FormatRefWithRule< + 'a, + biome_js_syntax::AnyJsModuleSource, + crate::js::any::module_source::FormatAnyJsModuleSource, + >; + fn format(&self) -> Self::Format<'_> { + #![allow(clippy::default_constructed_unit_structs)] + FormatRefWithRule::new( + self, + crate::js::any::module_source::FormatAnyJsModuleSource::default(), + ) + } +} +impl IntoFormat for biome_js_syntax::AnyJsModuleSource { + type Format = FormatOwnedWithRule< + biome_js_syntax::AnyJsModuleSource, + crate::js::any::module_source::FormatAnyJsModuleSource, + >; + fn into_format(self) -> Self::Format { + #![allow(clippy::default_constructed_unit_structs)] + FormatOwnedWithRule::new( + self, + crate::js::any::module_source::FormatAnyJsModuleSource::default(), + ) + } +} impl AsFormat for biome_js_syntax::AnyJsName { type Format<'a> = FormatRefWithRule<'a, biome_js_syntax::AnyJsName, crate::js::any::name::FormatAnyJsName>; @@ -13094,6 +13157,33 @@ impl IntoFormat for biome_js_syntax::AnyTsExternalModuleDeclara FormatOwnedWithRule :: new (self , crate :: ts :: any :: external_module_declaration_body :: FormatAnyTsExternalModuleDeclarationBody :: default ()) } } +impl AsFormat for biome_js_syntax::AnyTsIdentifierBinding { + type Format<'a> = FormatRefWithRule< + 'a, + biome_js_syntax::AnyTsIdentifierBinding, + crate::ts::any::identifier_binding::FormatAnyTsIdentifierBinding, + >; + fn format(&self) -> Self::Format<'_> { + #![allow(clippy::default_constructed_unit_structs)] + FormatRefWithRule::new( + self, + crate::ts::any::identifier_binding::FormatAnyTsIdentifierBinding::default(), + ) + } +} +impl IntoFormat for biome_js_syntax::AnyTsIdentifierBinding { + type Format = FormatOwnedWithRule< + biome_js_syntax::AnyTsIdentifierBinding, + crate::ts::any::identifier_binding::FormatAnyTsIdentifierBinding, + >; + fn into_format(self) -> Self::Format { + #![allow(clippy::default_constructed_unit_structs)] + FormatOwnedWithRule::new( + self, + crate::ts::any::identifier_binding::FormatAnyTsIdentifierBinding::default(), + ) + } +} impl AsFormat for biome_js_syntax::AnyTsIndexSignatureModifier { type Format<'a> = FormatRefWithRule< 'a, diff --git a/crates/biome_js_formatter/src/js/any/binding.rs b/crates/biome_js_formatter/src/js/any/binding.rs index 9a68e7ec6805..fbb43e1cdf86 100644 --- a/crates/biome_js_formatter/src/js/any/binding.rs +++ b/crates/biome_js_formatter/src/js/any/binding.rs @@ -10,6 +10,7 @@ impl FormatRule for FormatAnyJsBinding { match node { AnyJsBinding::JsBogusBinding(node) => node.format().fmt(f), AnyJsBinding::JsIdentifierBinding(node) => node.format().fmt(f), + AnyJsBinding::JsMetavariable(node) => node.format().fmt(f), } } } diff --git a/crates/biome_js_formatter/src/js/any/class_member.rs b/crates/biome_js_formatter/src/js/any/class_member.rs index d9e24de40b7a..e3ab803ed1fb 100644 --- a/crates/biome_js_formatter/src/js/any/class_member.rs +++ b/crates/biome_js_formatter/src/js/any/class_member.rs @@ -12,6 +12,7 @@ impl FormatRule for FormatAnyJsClassMember { AnyJsClassMember::JsConstructorClassMember(node) => node.format().fmt(f), AnyJsClassMember::JsEmptyClassMember(node) => node.format().fmt(f), AnyJsClassMember::JsGetterClassMember(node) => node.format().fmt(f), + AnyJsClassMember::JsMetavariable(node) => node.format().fmt(f), AnyJsClassMember::JsMethodClassMember(node) => node.format().fmt(f), AnyJsClassMember::JsPropertyClassMember(node) => node.format().fmt(f), AnyJsClassMember::JsSetterClassMember(node) => node.format().fmt(f), diff --git a/crates/biome_js_formatter/src/js/any/class_member_name.rs b/crates/biome_js_formatter/src/js/any/class_member_name.rs index 0ae133525998..c0f1be7a875c 100644 --- a/crates/biome_js_formatter/src/js/any/class_member_name.rs +++ b/crates/biome_js_formatter/src/js/any/class_member_name.rs @@ -10,6 +10,7 @@ impl FormatRule for FormatAnyJsClassMemberName { match node { AnyJsClassMemberName::JsComputedMemberName(node) => node.format().fmt(f), AnyJsClassMemberName::JsLiteralMemberName(node) => node.format().fmt(f), + AnyJsClassMemberName::JsMetavariable(node) => node.format().fmt(f), AnyJsClassMemberName::JsPrivateClassMemberName(node) => node.format().fmt(f), } } diff --git a/crates/biome_js_formatter/src/js/any/expression.rs b/crates/biome_js_formatter/src/js/any/expression.rs index 9b04df98cd76..c1eceec24086 100644 --- a/crates/biome_js_formatter/src/js/any/expression.rs +++ b/crates/biome_js_formatter/src/js/any/expression.rs @@ -26,6 +26,7 @@ impl FormatRule for FormatAnyJsExpression { AnyJsExpression::JsInExpression(node) => node.format().fmt(f), AnyJsExpression::JsInstanceofExpression(node) => node.format().fmt(f), AnyJsExpression::JsLogicalExpression(node) => node.format().fmt(f), + AnyJsExpression::JsMetavariable(node) => node.format().fmt(f), AnyJsExpression::JsNewExpression(node) => node.format().fmt(f), AnyJsExpression::JsNewTargetExpression(node) => node.format().fmt(f), AnyJsExpression::JsObjectExpression(node) => node.format().fmt(f), diff --git a/crates/biome_js_formatter/src/js/any/mod.rs b/crates/biome_js_formatter/src/js/any/mod.rs index fdb90790b24a..95a61e6efc03 100644 --- a/crates/biome_js_formatter/src/js/any/mod.rs +++ b/crates/biome_js_formatter/src/js/any/mod.rs @@ -32,6 +32,7 @@ pub(crate) mod in_property; pub(crate) mod literal_expression; pub(crate) mod method_modifier; pub(crate) mod module_item; +pub(crate) mod module_source; pub(crate) mod name; pub(crate) mod named_import_specifier; pub(crate) mod object_assignment_pattern_member; diff --git a/crates/biome_js_formatter/src/js/any/module_source.rs b/crates/biome_js_formatter/src/js/any/module_source.rs new file mode 100644 index 000000000000..963f59b9ab38 --- /dev/null +++ b/crates/biome_js_formatter/src/js/any/module_source.rs @@ -0,0 +1,15 @@ +//! This is a generated file. Don't modify it by hand! Run 'cargo codegen formatter' to re-generate the file. + +use crate::prelude::*; +use biome_js_syntax::AnyJsModuleSource; +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatAnyJsModuleSource; +impl FormatRule for FormatAnyJsModuleSource { + type Context = JsFormatContext; + fn fmt(&self, node: &AnyJsModuleSource, f: &mut JsFormatter) -> FormatResult<()> { + match node { + AnyJsModuleSource::JsMetavariable(node) => node.format().fmt(f), + AnyJsModuleSource::JsModuleSource(node) => node.format().fmt(f), + } + } +} diff --git a/crates/biome_js_formatter/src/js/any/object_binding_pattern_member.rs b/crates/biome_js_formatter/src/js/any/object_binding_pattern_member.rs index 0a452faa8fdd..20446b135d08 100644 --- a/crates/biome_js_formatter/src/js/any/object_binding_pattern_member.rs +++ b/crates/biome_js_formatter/src/js/any/object_binding_pattern_member.rs @@ -9,6 +9,7 @@ impl FormatRule for FormatAnyJsObjectBindingPat fn fmt(&self, node: &AnyJsObjectBindingPatternMember, f: &mut JsFormatter) -> FormatResult<()> { match node { AnyJsObjectBindingPatternMember::JsBogusBinding(node) => node.format().fmt(f), + AnyJsObjectBindingPatternMember::JsMetavariable(node) => node.format().fmt(f), AnyJsObjectBindingPatternMember::JsObjectBindingPatternProperty(node) => { node.format().fmt(f) } diff --git a/crates/biome_js_formatter/src/js/any/object_member_name.rs b/crates/biome_js_formatter/src/js/any/object_member_name.rs index 09a8ab35047f..2900658ed1f7 100644 --- a/crates/biome_js_formatter/src/js/any/object_member_name.rs +++ b/crates/biome_js_formatter/src/js/any/object_member_name.rs @@ -10,6 +10,7 @@ impl FormatRule for FormatAnyJsObjectMemberName { match node { AnyJsObjectMemberName::JsComputedMemberName(node) => node.format().fmt(f), AnyJsObjectMemberName::JsLiteralMemberName(node) => node.format().fmt(f), + AnyJsObjectMemberName::JsMetavariable(node) => node.format().fmt(f), } } } diff --git a/crates/biome_js_formatter/src/js/auxiliary/metavariable.rs b/crates/biome_js_formatter/src/js/auxiliary/metavariable.rs new file mode 100644 index 000000000000..b653107c363d --- /dev/null +++ b/crates/biome_js_formatter/src/js/auxiliary/metavariable.rs @@ -0,0 +1,10 @@ +use crate::prelude::*; +use biome_js_syntax::JsMetavariable; +use biome_rowan::AstNode; +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatJsMetavariable; +impl FormatNodeRule for FormatJsMetavariable { + fn fmt_fields(&self, node: &JsMetavariable, f: &mut JsFormatter) -> FormatResult<()> { + format_verbatim_node(node.syntax()).fmt(f) + } +} diff --git a/crates/biome_js_formatter/src/js/auxiliary/mod.rs b/crates/biome_js_formatter/src/js/auxiliary/mod.rs index e351a5eb2227..9d978e673507 100644 --- a/crates/biome_js_formatter/src/js/auxiliary/mod.rs +++ b/crates/biome_js_formatter/src/js/auxiliary/mod.rs @@ -13,6 +13,7 @@ pub(crate) mod finally_clause; pub(crate) mod function_body; pub(crate) mod initializer_clause; pub(crate) mod label; +pub(crate) mod metavariable; pub(crate) mod module; pub(crate) mod name; pub(crate) mod private_name; diff --git a/crates/biome_js_formatter/src/js/bindings/parameters.rs b/crates/biome_js_formatter/src/js/bindings/parameters.rs index 9c7fc4551f27..0bee29f67fcb 100644 --- a/crates/biome_js_formatter/src/js/bindings/parameters.rs +++ b/crates/biome_js_formatter/src/js/bindings/parameters.rs @@ -229,7 +229,10 @@ pub(crate) fn should_hug_function_parameters( match parameter.binding()? { // always true for `[a]` or `{a}` AnyJsBindingPattern::JsArrayBindingPattern(_) - | AnyJsBindingPattern::JsObjectBindingPattern(_) => true, + | AnyJsBindingPattern::JsObjectBindingPattern(_) + | AnyJsBindingPattern::AnyJsBinding(AnyJsBinding::JsMetavariable(_)) => { + true + } // if the type parameter is an object type // `a: { prop: string }` // or parameter is an arrow function parameter diff --git a/crates/biome_js_formatter/src/js/classes/property_class_member.rs b/crates/biome_js_formatter/src/js/classes/property_class_member.rs index a21655ba50ee..fd5f0286aa39 100644 --- a/crates/biome_js_formatter/src/js/classes/property_class_member.rs +++ b/crates/biome_js_formatter/src/js/classes/property_class_member.rs @@ -139,7 +139,8 @@ fn needs_semicolon(property: &AnyJsPropertyClassMember) -> SyntaxResult { | AnyJsClassMember::JsGetterClassMember(_) | AnyJsClassMember::TsGetterSignatureClassMember(_) | AnyJsClassMember::TsSetterSignatureClassMember(_) - | AnyJsClassMember::JsSetterClassMember(_) => false, + | AnyJsClassMember::JsSetterClassMember(_) + | AnyJsClassMember::JsMetavariable(_) => false, // Computed members may be misinterpreted as array accessors/array types member @ @@ -180,7 +181,7 @@ fn has_modifiers(member: &AnyJsClassMember) -> bool { AnyJsClassMember::JsPropertyClassMember(property) => property.modifiers().is_empty(), AnyJsClassMember::JsSetterClassMember(setter) => setter.modifiers().is_empty(), AnyJsClassMember::JsStaticInitializationBlockClassMember(_) => true, - AnyJsClassMember::JsBogusMember(_) => true, + AnyJsClassMember::JsBogusMember(_) | AnyJsClassMember::JsMetavariable(_) => true, AnyJsClassMember::TsConstructorSignatureClassMember(constructor) => { constructor.modifiers().is_empty() } diff --git a/crates/biome_js_formatter/src/ts/any/identifier_binding.rs b/crates/biome_js_formatter/src/ts/any/identifier_binding.rs new file mode 100644 index 000000000000..221d76d151ac --- /dev/null +++ b/crates/biome_js_formatter/src/ts/any/identifier_binding.rs @@ -0,0 +1,15 @@ +//! This is a generated file. Don't modify it by hand! Run 'cargo codegen formatter' to re-generate the file. + +use crate::prelude::*; +use biome_js_syntax::AnyTsIdentifierBinding; +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatAnyTsIdentifierBinding; +impl FormatRule for FormatAnyTsIdentifierBinding { + type Context = JsFormatContext; + fn fmt(&self, node: &AnyTsIdentifierBinding, f: &mut JsFormatter) -> FormatResult<()> { + match node { + AnyTsIdentifierBinding::JsMetavariable(node) => node.format().fmt(f), + AnyTsIdentifierBinding::TsIdentifierBinding(node) => node.format().fmt(f), + } + } +} diff --git a/crates/biome_js_formatter/src/ts/any/mod.rs b/crates/biome_js_formatter/src/ts/any/mod.rs index 1e301b6df2f8..c8b71a37554b 100644 --- a/crates/biome_js_formatter/src/ts/any/mod.rs +++ b/crates/biome_js_formatter/src/ts/any/mod.rs @@ -2,6 +2,7 @@ pub(crate) mod enum_member_name; pub(crate) mod external_module_declaration_body; +pub(crate) mod identifier_binding; pub(crate) mod index_signature_modifier; pub(crate) mod method_signature_modifier; pub(crate) mod module_name; diff --git a/crates/biome_js_formatter/src/ts/any/module_name.rs b/crates/biome_js_formatter/src/ts/any/module_name.rs index 2ba867469740..099f0e3e896c 100644 --- a/crates/biome_js_formatter/src/ts/any/module_name.rs +++ b/crates/biome_js_formatter/src/ts/any/module_name.rs @@ -8,7 +8,7 @@ impl FormatRule for FormatAnyTsModuleName { type Context = JsFormatContext; fn fmt(&self, node: &AnyTsModuleName, f: &mut JsFormatter) -> FormatResult<()> { match node { - AnyTsModuleName::TsIdentifierBinding(node) => node.format().fmt(f), + AnyTsModuleName::AnyTsIdentifierBinding(node) => node.format().fmt(f), AnyTsModuleName::TsQualifiedModuleName(node) => node.format().fmt(f), } } diff --git a/crates/biome_js_formatter/src/ts/any/ts_type.rs b/crates/biome_js_formatter/src/ts/any/ts_type.rs index 78106d4c6c20..e823acb2e512 100644 --- a/crates/biome_js_formatter/src/ts/any/ts_type.rs +++ b/crates/biome_js_formatter/src/ts/any/ts_type.rs @@ -8,6 +8,7 @@ impl FormatRule for FormatAnyTsType { type Context = JsFormatContext; fn fmt(&self, node: &AnyTsType, f: &mut JsFormatter) -> FormatResult<()> { match node { + AnyTsType::JsMetavariable(node) => node.format().fmt(f), AnyTsType::TsAnyType(node) => node.format().fmt(f), AnyTsType::TsArrayType(node) => node.format().fmt(f), AnyTsType::TsBigintLiteralType(node) => node.format().fmt(f), diff --git a/crates/biome_js_formatter/src/ts/lists/union_type_variant_list.rs b/crates/biome_js_formatter/src/ts/lists/union_type_variant_list.rs index dff7004f4ee7..7fbc0ada8009 100644 --- a/crates/biome_js_formatter/src/ts/lists/union_type_variant_list.rs +++ b/crates/biome_js_formatter/src/ts/lists/union_type_variant_list.rs @@ -1,4 +1,3 @@ -use crate::prelude::*; use crate::ts::bogus::bogus_type::FormatTsBogusType; use crate::ts::module::import_type::FormatTsImportType; use crate::ts::types::any_type::FormatTsAnyType; @@ -35,6 +34,7 @@ use crate::ts::types::union_type::FormatTsUnionType; use crate::ts::types::unknown_type::FormatTsUnknownType; use crate::ts::types::void_type::FormatTsVoidType; use crate::JsCommentStyle; +use crate::{js::auxiliary::metavariable::FormatJsMetavariable, prelude::*}; use biome_formatter::{comments::CommentStyle, write, FormatRuleWithOptions}; use biome_js_syntax::{AnyTsType, JsLanguage, TsUnionType, TsUnionTypeVariantList}; use biome_rowan::{AstSeparatedElement, AstSeparatedList}; @@ -134,6 +134,7 @@ impl Format for FormatTypeVariant<'_> { AnyTsType::TsUnknownType(ty) => FormatTsUnknownType.fmt_node(ty, f), AnyTsType::TsVoidType(ty) => FormatTsVoidType.fmt_node(ty, f), AnyTsType::TsBogusType(ty) => FormatTsBogusType.fmt(ty, f), + AnyTsType::JsMetavariable(ty) => FormatJsMetavariable.fmt_node(ty, f), } } }); diff --git a/crates/biome_js_formatter/src/utils/assignment_like.rs b/crates/biome_js_formatter/src/utils/assignment_like.rs index 387d56e72b23..b66abe2b295a 100644 --- a/crates/biome_js_formatter/src/utils/assignment_like.rs +++ b/crates/biome_js_formatter/src/utils/assignment_like.rs @@ -10,13 +10,14 @@ use biome_js_syntax::binary_like_expression::AnyJsBinaryLikeExpression; use biome_js_syntax::{ AnyJsAssignmentPattern, AnyJsBindingPattern, AnyJsCallArgument, AnyJsClassMemberName, AnyJsExpression, AnyJsFunctionBody, AnyJsObjectAssignmentPatternMember, - AnyJsObjectBindingPatternMember, AnyJsObjectMemberName, AnyJsTemplateElement, AnyTsType, - AnyTsVariableAnnotation, JsAssignmentExpression, JsInitializerClause, JsLiteralMemberName, - JsObjectAssignmentPattern, JsObjectAssignmentPatternProperty, JsObjectBindingPattern, - JsPropertyClassMember, JsPropertyClassMemberFields, JsPropertyObjectMember, JsSyntaxKind, - JsVariableDeclarator, TsIdentifierBinding, TsInitializedPropertySignatureClassMember, - TsInitializedPropertySignatureClassMemberFields, TsPropertySignatureClassMember, - TsPropertySignatureClassMemberFields, TsTypeAliasDeclaration, TsTypeArguments, TsUnionType, + AnyJsObjectBindingPatternMember, AnyJsObjectMemberName, AnyJsTemplateElement, + AnyTsIdentifierBinding, AnyTsType, AnyTsVariableAnnotation, JsAssignmentExpression, + JsInitializerClause, JsLiteralMemberName, JsObjectAssignmentPattern, + JsObjectAssignmentPatternProperty, JsObjectBindingPattern, JsPropertyClassMember, + JsPropertyClassMemberFields, JsPropertyObjectMember, JsSyntaxKind, JsVariableDeclarator, + TsInitializedPropertySignatureClassMember, TsInitializedPropertySignatureClassMemberFields, + TsPropertySignatureClassMember, TsPropertySignatureClassMemberFields, TsTypeAliasDeclaration, + TsTypeArguments, TsUnionType, }; use biome_js_syntax::{AnyJsLiteralExpression, JsUnaryExpression}; use biome_rowan::{declare_node_union, AstNode, SyntaxNodeOptionExt, SyntaxResult}; @@ -39,7 +40,7 @@ declare_node_union! { AnyJsAssignmentPattern | AnyJsObjectMemberName | AnyJsBindingPattern | - TsIdentifierBinding | + AnyTsIdentifierBinding | JsLiteralMemberName | AnyJsClassMemberName } diff --git a/crates/biome_js_formatter/src/utils/format_node_without_comments.rs b/crates/biome_js_formatter/src/utils/format_node_without_comments.rs index 7f4be513ae39..adb96cb172b2 100644 --- a/crates/biome_js_formatter/src/utils/format_node_without_comments.rs +++ b/crates/biome_js_formatter/src/utils/format_node_without_comments.rs @@ -1,3 +1,4 @@ +use crate::js::auxiliary::metavariable::FormatJsMetavariable; use crate::js::bogus::bogus_expression::FormatJsBogusExpression; use crate::js::expressions::array_expression::FormatJsArrayExpression; use crate::js::expressions::arrow_function_expression::FormatJsArrowFunctionExpression; @@ -92,6 +93,7 @@ impl FormatRule for FormatAnyJsExpressionWithoutComments { AnyJsExpression::JsFunctionExpression(node) => { FormatJsFunctionExpression::default().fmt_node(node, f) } + AnyJsExpression::JsMetavariable(node) => FormatJsMetavariable.fmt_node(node, f), AnyJsExpression::JsIdentifierExpression(node) => { FormatJsIdentifierExpression.fmt_node(node, f) } diff --git a/crates/biome_js_parser/src/lexer/mod.rs b/crates/biome_js_parser/src/lexer/mod.rs index 884e4b087763..84e2cf2e97e7 100644 --- a/crates/biome_js_parser/src/lexer/mod.rs +++ b/crates/biome_js_parser/src/lexer/mod.rs @@ -32,6 +32,8 @@ use biome_unicode_table::{ }; use bitflags::bitflags; +use crate::JsParserOptions; + use self::errors::invalid_digits_after_unicode_escape_sequence; // The first utf8 byte of every valid unicode whitespace char, used for short circuiting whitespace checks @@ -131,6 +133,8 @@ pub(crate) struct JsLexer<'src> { current_flags: TokenFlags, diagnostics: Vec, + + options: JsParserOptions, } impl<'src> Lexer<'src> for JsLexer<'src> { @@ -309,9 +313,14 @@ impl<'src> JsLexer<'src> { current_flags: TokenFlags::empty(), position: 0, diagnostics: vec![], + options: JsParserOptions::default(), } } + pub(crate) fn with_options(self, options: JsParserOptions) -> Self { + Self { options, ..self } + } + fn re_lex_binary_operator(&mut self) -> JsSyntaxKind { if self.current_byte() == Some(b'>') { match self.next_byte() { @@ -1891,15 +1900,20 @@ impl<'src> JsLexer<'src> { PIP => self.resolve_pipe(), TLD => self.eat_byte(T![~]), - // A BOM can only appear at the start of a file, so if we haven't advanced at all yet, - // perform the check. At any other position, the BOM is just considered plain whitespace. UNI => { + // A BOM can only appear at the start of a file, so if we haven't advanced at all yet, + // perform the check. At any other position, the BOM is just considered plain whitespace. if self.position == 0 { if let Some((bom, bom_size)) = self.consume_potential_bom(UNICODE_BOM) { self.unicode_bom_length = bom_size; return bom; } } + + if self.options.should_parse_metavariables() && self.is_metavariable_start() { + return self.consume_metavariable(GRIT_METAVARIABLE); + } + let chr = self.current_char_unchecked(); if is_linebreak(chr) || (UNICODE_WHITESPACE_STARTS.contains(&byte) && UNICODE_SPACES.contains(&chr)) diff --git a/crates/biome_js_parser/src/options.rs b/crates/biome_js_parser/src/options.rs index b52f45233cb5..14e5d49127bf 100644 --- a/crates/biome_js_parser/src/options.rs +++ b/crates/biome_js_parser/src/options.rs @@ -2,18 +2,34 @@ #[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct JsParserOptions { + /// Enables parsing of Grit metavariables. + /// Defaults to `false`. + #[serde(default)] + pub grit_metavariables: bool, + /// Whether the parsing of the class parameter decorators should happen. /// /// This parameter decorators belong to the old language proposal. + #[serde(default)] pub parse_class_parameter_decorators: bool, } impl JsParserOptions { + /// Enables parsing of Grit metavariables. + pub fn with_metavariables(mut self) -> Self { + self.grit_metavariables = true; + self + } + pub fn with_parse_class_parameter_decorators(mut self) -> Self { self.parse_class_parameter_decorators = true; self } + pub fn should_parse_metavariables(&self) -> bool { + self.grit_metavariables + } + /// Should parse parameter decorators inside classes, e.g.: /// /// ```js diff --git a/crates/biome_js_parser/src/parser.rs b/crates/biome_js_parser/src/parser.rs index faa1c5ae1109..27ab6ded5988 100644 --- a/crates/biome_js_parser/src/parser.rs +++ b/crates/biome_js_parser/src/parser.rs @@ -41,7 +41,7 @@ pub struct JsParser<'source> { impl<'source> JsParser<'source> { /// Creates a new parser that parses the `source`. pub fn new(source: &'source str, source_type: JsFileSource, options: JsParserOptions) -> Self { - let source = JsTokenSource::from_str(source); + let source = JsTokenSource::from_str(source, options.clone()); JsParser { state: JsParserState::new(&source_type), diff --git a/crates/biome_js_parser/src/syntax.rs b/crates/biome_js_parser/src/syntax.rs index 99cebffcbab9..c700547e20e4 100644 --- a/crates/biome_js_parser/src/syntax.rs +++ b/crates/biome_js_parser/src/syntax.rs @@ -15,6 +15,7 @@ pub mod expr; mod function; mod js_parse_error; mod jsx; +mod metavariable; mod module; mod object; mod pattern; diff --git a/crates/biome_js_parser/src/syntax/assignment.rs b/crates/biome_js_parser/src/syntax/assignment.rs index f76e453cc290..6a70e0b1443f 100644 --- a/crates/biome_js_parser/src/syntax/assignment.rs +++ b/crates/biome_js_parser/src/syntax/assignment.rs @@ -18,6 +18,8 @@ use biome_js_syntax::{JsSyntaxKind::*, *}; use biome_parser::diagnostic::expected_any; use biome_rowan::AstNode; +use super::metavariable::is_at_metavariable; + // test js assignment_target // foo += bar = b ??= 3; // a.foo -= bar; @@ -289,7 +291,9 @@ impl ParseObjectPattern for ObjectAssignmentPattern { fn parse_property_pattern(&self, p: &mut JsParser) -> ParsedSyntax { let m = p.start(); - let kind = if (is_at_identifier(p) || p.at(T![=])) && !p.nth_at(1, T![:]) { + let kind = if (is_at_identifier(p) || is_at_metavariable(p) || p.at(T![=])) + && !p.nth_at(1, T![:]) + { parse_assignment( p, AssignmentExprPrecedence::Conditional, diff --git a/crates/biome_js_parser/src/syntax/binding.rs b/crates/biome_js_parser/src/syntax/binding.rs index 9c788c2d13b5..b5fc4ebeca04 100644 --- a/crates/biome_js_parser/src/syntax/binding.rs +++ b/crates/biome_js_parser/src/syntax/binding.rs @@ -1,3 +1,4 @@ +use super::metavariable::{is_at_metavariable, is_nth_at_metavariable, parse_metavariable}; use crate::prelude::*; use crate::span::Span; use crate::syntax::class::parse_initializer_clause; @@ -31,7 +32,7 @@ pub(crate) fn is_at_identifier_binding(p: &mut JsParser) -> bool { #[inline] pub(crate) fn is_nth_at_identifier_binding(p: &mut JsParser, n: usize) -> bool { - is_nth_at_identifier(p, n) + is_nth_at_identifier(p, n) || is_nth_at_metavariable(p, n) } #[inline] @@ -61,6 +62,10 @@ pub(crate) fn parse_binding(p: &mut JsParser) -> ParsedSyntax { /// * it is named "yield" inside of a generator function or in strict mode /// * it is named "await" inside of an async function pub(crate) fn parse_identifier_binding(p: &mut JsParser) -> ParsedSyntax { + if is_at_metavariable(p) { + return parse_metavariable(p); + } + let parsed = parse_identifier(p, JS_IDENTIFIER_BINDING); parsed.map(|mut identifier| { @@ -263,13 +268,18 @@ impl ParseObjectPattern for ObjectBindingPattern { // let { = "test" } = c // let { , d } = c fn parse_property_pattern(&self, p: &mut JsParser) -> ParsedSyntax { - if !is_at_object_member_name(p) && !p.at_ts(token_set![T![:], T![=]]) { + if !is_at_object_member_name(p) + && !is_at_metavariable(p) + && !p.at_ts(token_set![T![:], T![=]]) + { return Absent; } let m = p.start(); - let kind = if p.at(T![=]) || (is_at_identifier_binding(p) && !p.nth_at(1, T![:])) { + let kind = if p.at(T![=]) + || ((is_at_identifier_binding(p) || is_at_metavariable(p)) && !p.nth_at(1, T![:])) + { parse_binding(p).or_add_diagnostic(p, expected_identifier); JS_OBJECT_BINDING_PATTERN_SHORTHAND_PROPERTY } else { diff --git a/crates/biome_js_parser/src/syntax/class.rs b/crates/biome_js_parser/src/syntax/class.rs index 362cce61ee2f..770359a42b51 100644 --- a/crates/biome_js_parser/src/syntax/class.rs +++ b/crates/biome_js_parser/src/syntax/class.rs @@ -52,6 +52,7 @@ use std::slice::Iter; use super::function::LineBreak; use super::js_parse_error::unexpected_body_inside_ambient_context; +use super::metavariable::{is_at_metavariable, parse_metavariable}; use super::typescript::ts_parse_error::{self, unexpected_abstract_member_with_body}; use super::typescript::{ expect_ts_index_signature_member, is_at_ts_index_signature_member, MemberParent, @@ -517,6 +518,10 @@ impl ParseNodeList for ClassMembersList { // static async *foo() {} // } fn parse_class_member(p: &mut JsParser, inside_abstract_class: bool) -> ParsedSyntax { + if is_at_metavariable(p) { + return parse_metavariable(p); + } + let member_marker = p.start(); // test js class_empty_element // class foo { ;;;;;;;;;; get foo() {};;;;} diff --git a/crates/biome_js_parser/src/syntax/expr.rs b/crates/biome_js_parser/src/syntax/expr.rs index 4bc251250d68..a013705ff47c 100644 --- a/crates/biome_js_parser/src/syntax/expr.rs +++ b/crates/biome_js_parser/src/syntax/expr.rs @@ -3,6 +3,7 @@ //! //! See the [ECMAScript spec](https://www.ecma-international.org/ecma-262/5.1/#sec-11). +use super::metavariable::{is_at_metavariable, parse_metavariable}; use super::typescript::*; use crate::lexer::{JsLexContext, JsReLexContext}; use crate::parser::rewrite_parser::{RewriteMarker, RewriteParser}; @@ -1210,6 +1211,10 @@ fn parse_parenthesized_expression(p: &mut JsParser) -> ParsedSyntax { /// A general expression. pub(crate) fn parse_expression(p: &mut JsParser, context: ExpressionContext) -> ParsedSyntax { + if is_at_metavariable(p) { + return parse_metavariable(p); + } + let first = parse_assignment_expression_or_higher(p, context); if p.at(T![,]) { @@ -1486,6 +1491,8 @@ fn parse_primary_expression(p: &mut JsParser, context: ExpressionContext) -> Par // let a = b; T![<] if Jsx.is_supported(p) => return parse_jsx_tag_expression(p), + t if t.is_metavariable() => return parse_metavariable(p), + // test_err js primary_expr_invalid_recovery // let a = \; foo(); t if t.is_contextual_keyword() || t.is_future_reserved_keyword() => { @@ -1544,6 +1551,10 @@ pub(crate) fn is_nth_at_reference_identifier(p: &mut JsParser, n: usize) -> bool /// * It is named `await` inside of an async function /// * It is named `yield` inside of a generator function or in strict mode pub(super) fn parse_identifier(p: &mut JsParser, kind: JsSyntaxKind) -> ParsedSyntax { + if is_at_metavariable(p) { + return parse_metavariable(p); + } + if !is_at_identifier(p) { return Absent; } diff --git a/crates/biome_js_parser/src/syntax/metavariable.rs b/crates/biome_js_parser/src/syntax/metavariable.rs new file mode 100644 index 000000000000..adb36ae12623 --- /dev/null +++ b/crates/biome_js_parser/src/syntax/metavariable.rs @@ -0,0 +1,24 @@ +use crate::JsParser; +use crate::JsSyntaxKind::JS_METAVARIABLE; +use biome_parser::{prelude::ParsedSyntax, Parser}; + +#[inline] +pub(crate) fn is_at_metavariable(p: &mut JsParser) -> bool { + is_nth_at_metavariable(p, 0) +} + +#[inline] +pub(crate) fn is_nth_at_metavariable(p: &mut JsParser, n: usize) -> bool { + p.nth(n).is_metavariable() +} + +#[inline] +pub(crate) fn parse_metavariable(p: &mut JsParser) -> ParsedSyntax { + if is_at_metavariable(p) { + let m = p.start(); + p.bump_any(); + ParsedSyntax::Present(m.complete(p, JS_METAVARIABLE)) + } else { + ParsedSyntax::Absent + } +} diff --git a/crates/biome_js_parser/src/syntax/module.rs b/crates/biome_js_parser/src/syntax/module.rs index 9720a4bfb4d3..8e85b8b1cb4e 100644 --- a/crates/biome_js_parser/src/syntax/module.rs +++ b/crates/biome_js_parser/src/syntax/module.rs @@ -40,6 +40,7 @@ use rustc_hash::FxHashMap; use super::auxiliary::{is_nth_at_declaration_clause, parse_declaration_clause}; use super::js_parse_error::{expected_named_import, expected_namespace_import}; +use super::metavariable::{is_at_metavariable, parse_metavariable}; // test js module // import a from "b"; @@ -1510,7 +1511,7 @@ fn parse_ts_export_declare_clause(p: &mut JsParser, stmt_start: TextSize) -> Par fn is_nth_at_literal_export_name(p: &mut JsParser, n: usize) -> bool { match p.nth(n) { JS_STRING_LITERAL | T![ident] => true, - t if t.is_keyword() => true, + t if t.is_keyword() || t.is_metavariable() => true, _ => false, } } @@ -1527,16 +1528,19 @@ fn parse_literal_export_name(p: &mut JsParser) -> ParsedSyntax { p.bump_remap(T![ident]); Present(m.complete(p, JS_LITERAL_EXPORT_NAME)) } + t if t.is_metavariable() => parse_metavariable(p), _ => Absent, } } pub(crate) fn parse_module_source(p: &mut JsParser) -> ParsedSyntax { - if !p.at(JS_STRING_LITERAL) { - Absent - } else { + if p.at(JS_STRING_LITERAL) { let m = p.start(); p.bump_any(); Present(m.complete(p, JS_MODULE_SOURCE)) + } else if is_at_metavariable(p) { + parse_metavariable(p) + } else { + Absent } } diff --git a/crates/biome_js_parser/src/syntax/object.rs b/crates/biome_js_parser/src/syntax/object.rs index 0d5f4618e6f5..1f8bf6695b96 100644 --- a/crates/biome_js_parser/src/syntax/object.rs +++ b/crates/biome_js_parser/src/syntax/object.rs @@ -27,6 +27,8 @@ use biome_js_syntax::JsSyntaxKind::*; use biome_js_syntax::{JsSyntaxKind, T}; use biome_parser::parse_lists::ParseSeparatedList; +use super::metavariable::parse_metavariable; + // test js object_expr // let a = {}; // let b = {foo,} @@ -355,6 +357,7 @@ fn parse_setter_object_member(p: &mut JsParser) -> ParsedSyntax { pub(crate) fn parse_object_member_name(p: &mut JsParser) -> ParsedSyntax { match p.cur() { T!['['] => parse_computed_member_name(p), + t if t.is_metavariable() => parse_metavariable(p), _ => parse_literal_member_name(p), } } @@ -411,6 +414,10 @@ pub(super) fn parse_literal_member_name(p: &mut JsParser) -> ParsedSyntax { t if t.is_keyword() => { p.bump_remap(T![ident]); } + t if t.is_metavariable() => { + m.abandon(p); + return parse_metavariable(p); + } _ => { m.abandon(p); return Absent; diff --git a/crates/biome_js_parser/src/syntax/stmt.rs b/crates/biome_js_parser/src/syntax/stmt.rs index ff6393dd6aae..b4939697a8f1 100644 --- a/crates/biome_js_parser/src/syntax/stmt.rs +++ b/crates/biome_js_parser/src/syntax/stmt.rs @@ -5,6 +5,7 @@ use super::binding::*; use super::class::is_at_ts_abstract_class_declaration; use super::expr::parse_expression; +use super::metavariable::{is_at_metavariable, is_nth_at_metavariable}; use super::module::parse_export; use super::typescript::*; use crate::parser::RecoveryResult; @@ -332,7 +333,10 @@ pub(crate) fn parse_statement(p: &mut JsParser, context: StatementContext) -> Pa parse_expression_statement(p) } } - T![type] if !p.has_nth_preceding_line_break(1) && is_nth_at_identifier(p, 1) => { + T![type] + if !p.has_nth_preceding_line_break(1) + && (is_nth_at_identifier(p, 1) || is_nth_at_metavariable(p, 1)) => + { // test ts ts_type_variable // let type; // type = getFlowTypeInConstructor(symbol, getDeclaringConstructor(symbol)!); @@ -369,7 +373,7 @@ pub(crate) fn parse_statement(p: &mut JsParser, context: StatementContext) -> Pa }, ) } - _ if is_at_expression(p) => parse_expression_statement(p), + _ if is_at_expression(p) || is_at_metavariable(p) => parse_expression_statement(p), _ => Absent, } } diff --git a/crates/biome_js_parser/src/syntax/typescript.rs b/crates/biome_js_parser/src/syntax/typescript.rs index 99a2b04703b0..ab1d02ad3357 100644 --- a/crates/biome_js_parser/src/syntax/typescript.rs +++ b/crates/biome_js_parser/src/syntax/typescript.rs @@ -44,7 +44,7 @@ fn parse_ts_identifier_binding( ts_identifier_context: TsIdentifierContext, ) -> ParsedSyntax { parse_identifier(p, TS_IDENTIFIER_BINDING).map(|mut ident| { - if ident.kind(p).is_bogus() { + if ident.kind(p).is_bogus() || ident.kind(p).is_metavariable() { return ident; } diff --git a/crates/biome_js_parser/src/syntax/typescript/types.rs b/crates/biome_js_parser/src/syntax/typescript/types.rs index e4d6a03a323e..07ab297d0a35 100644 --- a/crates/biome_js_parser/src/syntax/typescript/types.rs +++ b/crates/biome_js_parser/src/syntax/typescript/types.rs @@ -15,6 +15,7 @@ use crate::syntax::js_parse_error::{ expected_parameters, expected_property_or_signature, modifier_already_seen, modifier_must_precede_modifier, }; +use crate::syntax::metavariable::parse_metavariable; use crate::syntax::object::{ is_at_object_member_name, is_nth_at_type_member_name, parse_object_member_name, }; @@ -883,6 +884,7 @@ fn parse_ts_non_array_type(p: &mut JsParser, context: TypeContext) -> ParsedSynt } } T![import] => parse_ts_import_type(p, context), + t if t.is_metavariable() => parse_metavariable(p), _ => { if !p.nth_at(1, T![.]) { let mapping = match p.cur() { diff --git a/crates/biome_js_parser/src/token_source.rs b/crates/biome_js_parser/src/token_source.rs index 11f3dbd4a30a..a26f8fe708e4 100644 --- a/crates/biome_js_parser/src/token_source.rs +++ b/crates/biome_js_parser/src/token_source.rs @@ -1,5 +1,5 @@ use crate::lexer::{JsLexContext, JsLexer, JsReLexContext, TextRange}; -use crate::prelude::*; +use crate::{prelude::*, JsParserOptions}; use biome_js_syntax::JsSyntaxKind; use biome_js_syntax::JsSyntaxKind::EOF; use biome_parser::lexer::BufferedLexer; @@ -26,8 +26,8 @@ impl<'l> JsTokenSource<'l> { } /// Creates a new token source for the given string - pub fn from_str(source: &'l str) -> JsTokenSource<'l> { - let lexer = JsLexer::from_str(source); + pub fn from_str(source: &'l str, options: JsParserOptions) -> JsTokenSource<'l> { + let lexer = JsLexer::from_str(source).with_options(options); let buffered = BufferedLexer::new(lexer); let mut source = JsTokenSource::new(buffered); diff --git a/crates/biome_js_parser/test_data/inline/ok/metavar.options.json b/crates/biome_js_parser/test_data/inline/ok/metavar.options.json new file mode 100644 index 000000000000..5305a1b4a61b --- /dev/null +++ b/crates/biome_js_parser/test_data/inline/ok/metavar.options.json @@ -0,0 +1 @@ +{ "grit_metavariables": true } diff --git a/crates/biome_js_parser/test_data/inline/ok/metavar.rast b/crates/biome_js_parser/test_data/inline/ok/metavar.rast new file mode 100644 index 000000000000..c93d2ca1cb25 --- /dev/null +++ b/crates/biome_js_parser/test_data/inline/ok/metavar.rast @@ -0,0 +1,364 @@ +JsModule { + bom_token: missing (optional), + interpreter_token: missing (optional), + directives: JsDirectiveList [], + items: JsModuleItemList [ + JsImport { + import_token: IMPORT_KW@0..7 "import" [] [Whitespace(" ")], + import_clause: JsImportDefaultClause { + type_token: missing (optional), + default_specifier: JsDefaultImportSpecifier { + local_name: JsMetavariable { + value_token: GRIT_METAVARIABLE@7..23 "μdefaultImport" [] [Whitespace(" ")], + }, + }, + from_token: FROM_KW@23..28 "from" [] [Whitespace(" ")], + source: JsMetavariable { + value_token: GRIT_METAVARIABLE@28..36 "μsource" [] [], + }, + assertion: missing (optional), + }, + semicolon_token: SEMICOLON@36..37 ";" [] [], + }, + JsImport { + import_token: IMPORT_KW@37..45 "import" [Newline("\n")] [Whitespace(" ")], + import_clause: JsImportNamedClause { + type_token: missing (optional), + named_specifiers: JsNamedImportSpecifiers { + l_curly_token: L_CURLY@45..47 "{" [] [Whitespace(" ")], + specifiers: JsNamedImportSpecifierList [ + JsShorthandNamedImportSpecifier { + type_token: missing (optional), + local_name: JsMetavariable { + value_token: GRIT_METAVARIABLE@47..60 "μnamedImport" [] [], + }, + }, + COMMA@60..62 "," [] [Whitespace(" ")], + JsShorthandNamedImportSpecifier { + type_token: TYPE_KW@62..67 "type" [] [Whitespace(" ")], + local_name: JsMetavariable { + value_token: GRIT_METAVARIABLE@67..79 "μnamedType" [] [Whitespace(" ")], + }, + }, + ], + r_curly_token: R_CURLY@79..81 "}" [] [Whitespace(" ")], + }, + from_token: FROM_KW@81..86 "from" [] [Whitespace(" ")], + source: JsMetavariable { + value_token: GRIT_METAVARIABLE@86..94 "μsource" [] [], + }, + assertion: missing (optional), + }, + semicolon_token: SEMICOLON@94..95 ";" [] [], + }, + JsExpressionStatement { + expression: JsMetavariable { + value_token: GRIT_METAVARIABLE@95..108 "μstatement" [Newline("\n"), Newline("\n")] [], + }, + semicolon_token: SEMICOLON@108..109 ";" [] [], + }, + JsFunctionDeclaration { + async_token: missing (optional), + function_token: FUNCTION_KW@109..120 "function" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + star_token: missing (optional), + id: JsIdentifierBinding { + name_token: IDENT@120..123 "foo" [] [], + }, + type_parameters: missing (optional), + parameters: JsParameters { + l_paren_token: L_PAREN@123..124 "(" [] [], + items: JsParameterList [], + r_paren_token: R_PAREN@124..126 ")" [] [Whitespace(" ")], + }, + return_type_annotation: missing (optional), + body: JsFunctionBody { + l_curly_token: L_CURLY@126..127 "{" [] [], + directives: JsDirectiveList [], + statements: JsStatementList [ + JsExpressionStatement { + expression: JsMetavariable { + value_token: GRIT_METAVARIABLE@127..143 "μstatement" [Newline("\n"), Whitespace(" ")] [], + }, + semicolon_token: SEMICOLON@143..144 ";" [] [], + }, + JsVariableStatement { + declaration: JsVariableDeclaration { + await_token: missing (optional), + kind: CONST_KW@144..155 "const" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")], + declarators: JsVariableDeclaratorList [ + JsVariableDeclarator { + id: JsIdentifierBinding { + name_token: IDENT@155..159 "bar" [] [Whitespace(" ")], + }, + variable_annotation: missing (optional), + initializer: JsInitializerClause { + eq_token: EQ@159..161 "=" [] [Whitespace(" ")], + expression: JsMetavariable { + value_token: GRIT_METAVARIABLE@161..173 "μexpression" [] [], + }, + }, + }, + ], + }, + semicolon_token: SEMICOLON@173..174 ";" [] [], + }, + ], + r_curly_token: R_CURLY@174..176 "}" [Newline("\n")] [], + }, + }, + JsClassDeclaration { + decorators: JsDecoratorList [], + abstract_token: missing (optional), + class_token: CLASS_KW@176..184 "class" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + id: JsIdentifierBinding { + name_token: IDENT@184..188 "Foo" [] [Whitespace(" ")], + }, + type_parameters: missing (optional), + extends_clause: missing (optional), + implements_clause: missing (optional), + l_curly_token: L_CURLY@188..189 "{" [] [], + members: JsClassMemberList [ + JsMetavariable { + value_token: GRIT_METAVARIABLE@189..207 "μclassMember" [Newline("\n"), Whitespace(" ")] [], + }, + JsEmptyClassMember { + semicolon_token: SEMICOLON@207..208 ";" [] [], + }, + ], + r_curly_token: R_CURLY@208..210 "}" [Newline("\n")] [], + }, + JsVariableStatement { + declaration: JsVariableDeclaration { + await_token: missing (optional), + kind: CONST_KW@210..218 "const" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + declarators: JsVariableDeclaratorList [ + JsVariableDeclarator { + id: JsObjectBindingPattern { + l_curly_token: L_CURLY@218..220 "{" [] [Whitespace(" ")], + properties: JsObjectBindingPatternPropertyList [ + JsObjectBindingPatternProperty { + member: JsMetavariable { + value_token: GRIT_METAVARIABLE@220..225 "μkey" [] [], + }, + colon_token: COLON@225..227 ":" [] [Whitespace(" ")], + pattern: JsIdentifierBinding { + name_token: IDENT@227..231 "key" [] [Whitespace(" ")], + }, + init: missing (optional), + }, + ], + r_curly_token: R_CURLY@231..233 "}" [] [Whitespace(" ")], + }, + variable_annotation: missing (optional), + initializer: JsInitializerClause { + eq_token: EQ@233..235 "=" [] [Whitespace(" ")], + expression: JsObjectExpression { + l_curly_token: L_CURLY@235..237 "{" [] [Whitespace(" ")], + members: JsObjectMemberList [ + JsPropertyObjectMember { + name: JsMetavariable { + value_token: GRIT_METAVARIABLE@237..242 "μkey" [] [], + }, + colon_token: COLON@242..244 ":" [] [Whitespace(" ")], + value: JsMetavariable { + value_token: GRIT_METAVARIABLE@244..252 "μvalue" [] [Whitespace(" ")], + }, + }, + ], + r_curly_token: R_CURLY@252..253 "}" [] [], + }, + }, + }, + ], + }, + semicolon_token: SEMICOLON@253..254 ";" [] [], + }, + JsFunctionDeclaration { + async_token: missing (optional), + function_token: FUNCTION_KW@254..265 "function" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + star_token: missing (optional), + id: JsMetavariable { + value_token: GRIT_METAVARIABLE@265..279 "μfunctionName" [] [], + }, + type_parameters: missing (optional), + parameters: JsParameters { + l_paren_token: L_PAREN@279..280 "(" [] [], + items: JsParameterList [], + r_paren_token: R_PAREN@280..282 ")" [] [Whitespace(" ")], + }, + return_type_annotation: missing (optional), + body: JsFunctionBody { + l_curly_token: L_CURLY@282..283 "{" [] [], + directives: JsDirectiveList [], + statements: JsStatementList [], + r_curly_token: R_CURLY@283..284 "}" [] [], + }, + }, + TsTypeAliasDeclaration { + type_token: TYPE_KW@284..291 "type" [Newline("\n"), Newline("\n")] [Whitespace(" ")], + binding_identifier: JsMetavariable { + value_token: GRIT_METAVARIABLE@291..298 "μType" [] [Whitespace(" ")], + }, + type_parameters: missing (optional), + eq_token: EQ@298..300 "=" [] [Whitespace(" ")], + ty: JsMetavariable { + value_token: GRIT_METAVARIABLE@300..311 "μOtherType" [] [], + }, + semicolon_token: SEMICOLON@311..312 ";" [] [], + }, + ], + eof_token: EOF@312..313 "" [Newline("\n")] [], +} + +0: JS_MODULE@0..313 + 0: (empty) + 1: (empty) + 2: JS_DIRECTIVE_LIST@0..0 + 3: JS_MODULE_ITEM_LIST@0..312 + 0: JS_IMPORT@0..37 + 0: IMPORT_KW@0..7 "import" [] [Whitespace(" ")] + 1: JS_IMPORT_DEFAULT_CLAUSE@7..36 + 0: (empty) + 1: JS_DEFAULT_IMPORT_SPECIFIER@7..23 + 0: JS_METAVARIABLE@7..23 + 0: GRIT_METAVARIABLE@7..23 "μdefaultImport" [] [Whitespace(" ")] + 2: FROM_KW@23..28 "from" [] [Whitespace(" ")] + 3: JS_METAVARIABLE@28..36 + 0: GRIT_METAVARIABLE@28..36 "μsource" [] [] + 4: (empty) + 2: SEMICOLON@36..37 ";" [] [] + 1: JS_IMPORT@37..95 + 0: IMPORT_KW@37..45 "import" [Newline("\n")] [Whitespace(" ")] + 1: JS_IMPORT_NAMED_CLAUSE@45..94 + 0: (empty) + 1: JS_NAMED_IMPORT_SPECIFIERS@45..81 + 0: L_CURLY@45..47 "{" [] [Whitespace(" ")] + 1: JS_NAMED_IMPORT_SPECIFIER_LIST@47..79 + 0: JS_SHORTHAND_NAMED_IMPORT_SPECIFIER@47..60 + 0: (empty) + 1: JS_METAVARIABLE@47..60 + 0: GRIT_METAVARIABLE@47..60 "μnamedImport" [] [] + 1: COMMA@60..62 "," [] [Whitespace(" ")] + 2: JS_SHORTHAND_NAMED_IMPORT_SPECIFIER@62..79 + 0: TYPE_KW@62..67 "type" [] [Whitespace(" ")] + 1: JS_METAVARIABLE@67..79 + 0: GRIT_METAVARIABLE@67..79 "μnamedType" [] [Whitespace(" ")] + 2: R_CURLY@79..81 "}" [] [Whitespace(" ")] + 2: FROM_KW@81..86 "from" [] [Whitespace(" ")] + 3: JS_METAVARIABLE@86..94 + 0: GRIT_METAVARIABLE@86..94 "μsource" [] [] + 4: (empty) + 2: SEMICOLON@94..95 ";" [] [] + 2: JS_EXPRESSION_STATEMENT@95..109 + 0: JS_METAVARIABLE@95..108 + 0: GRIT_METAVARIABLE@95..108 "μstatement" [Newline("\n"), Newline("\n")] [] + 1: SEMICOLON@108..109 ";" [] [] + 3: JS_FUNCTION_DECLARATION@109..176 + 0: (empty) + 1: FUNCTION_KW@109..120 "function" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 2: (empty) + 3: JS_IDENTIFIER_BINDING@120..123 + 0: IDENT@120..123 "foo" [] [] + 4: (empty) + 5: JS_PARAMETERS@123..126 + 0: L_PAREN@123..124 "(" [] [] + 1: JS_PARAMETER_LIST@124..124 + 2: R_PAREN@124..126 ")" [] [Whitespace(" ")] + 6: (empty) + 7: JS_FUNCTION_BODY@126..176 + 0: L_CURLY@126..127 "{" [] [] + 1: JS_DIRECTIVE_LIST@127..127 + 2: JS_STATEMENT_LIST@127..174 + 0: JS_EXPRESSION_STATEMENT@127..144 + 0: JS_METAVARIABLE@127..143 + 0: GRIT_METAVARIABLE@127..143 "μstatement" [Newline("\n"), Whitespace(" ")] [] + 1: SEMICOLON@143..144 ";" [] [] + 1: JS_VARIABLE_STATEMENT@144..174 + 0: JS_VARIABLE_DECLARATION@144..173 + 0: (empty) + 1: CONST_KW@144..155 "const" [Newline("\n"), Whitespace(" ")] [Whitespace(" ")] + 2: JS_VARIABLE_DECLARATOR_LIST@155..173 + 0: JS_VARIABLE_DECLARATOR@155..173 + 0: JS_IDENTIFIER_BINDING@155..159 + 0: IDENT@155..159 "bar" [] [Whitespace(" ")] + 1: (empty) + 2: JS_INITIALIZER_CLAUSE@159..173 + 0: EQ@159..161 "=" [] [Whitespace(" ")] + 1: JS_METAVARIABLE@161..173 + 0: GRIT_METAVARIABLE@161..173 "μexpression" [] [] + 1: SEMICOLON@173..174 ";" [] [] + 3: R_CURLY@174..176 "}" [Newline("\n")] [] + 4: JS_CLASS_DECLARATION@176..210 + 0: JS_DECORATOR_LIST@176..176 + 1: (empty) + 2: CLASS_KW@176..184 "class" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 3: JS_IDENTIFIER_BINDING@184..188 + 0: IDENT@184..188 "Foo" [] [Whitespace(" ")] + 4: (empty) + 5: (empty) + 6: (empty) + 7: L_CURLY@188..189 "{" [] [] + 8: JS_CLASS_MEMBER_LIST@189..208 + 0: JS_METAVARIABLE@189..207 + 0: GRIT_METAVARIABLE@189..207 "μclassMember" [Newline("\n"), Whitespace(" ")] [] + 1: JS_EMPTY_CLASS_MEMBER@207..208 + 0: SEMICOLON@207..208 ";" [] [] + 9: R_CURLY@208..210 "}" [Newline("\n")] [] + 5: JS_VARIABLE_STATEMENT@210..254 + 0: JS_VARIABLE_DECLARATION@210..253 + 0: (empty) + 1: CONST_KW@210..218 "const" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 2: JS_VARIABLE_DECLARATOR_LIST@218..253 + 0: JS_VARIABLE_DECLARATOR@218..253 + 0: JS_OBJECT_BINDING_PATTERN@218..233 + 0: L_CURLY@218..220 "{" [] [Whitespace(" ")] + 1: JS_OBJECT_BINDING_PATTERN_PROPERTY_LIST@220..231 + 0: JS_OBJECT_BINDING_PATTERN_PROPERTY@220..231 + 0: JS_METAVARIABLE@220..225 + 0: GRIT_METAVARIABLE@220..225 "μkey" [] [] + 1: COLON@225..227 ":" [] [Whitespace(" ")] + 2: JS_IDENTIFIER_BINDING@227..231 + 0: IDENT@227..231 "key" [] [Whitespace(" ")] + 3: (empty) + 2: R_CURLY@231..233 "}" [] [Whitespace(" ")] + 1: (empty) + 2: JS_INITIALIZER_CLAUSE@233..253 + 0: EQ@233..235 "=" [] [Whitespace(" ")] + 1: JS_OBJECT_EXPRESSION@235..253 + 0: L_CURLY@235..237 "{" [] [Whitespace(" ")] + 1: JS_OBJECT_MEMBER_LIST@237..252 + 0: JS_PROPERTY_OBJECT_MEMBER@237..252 + 0: JS_METAVARIABLE@237..242 + 0: GRIT_METAVARIABLE@237..242 "μkey" [] [] + 1: COLON@242..244 ":" [] [Whitespace(" ")] + 2: JS_METAVARIABLE@244..252 + 0: GRIT_METAVARIABLE@244..252 "μvalue" [] [Whitespace(" ")] + 2: R_CURLY@252..253 "}" [] [] + 1: SEMICOLON@253..254 ";" [] [] + 6: JS_FUNCTION_DECLARATION@254..284 + 0: (empty) + 1: FUNCTION_KW@254..265 "function" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 2: (empty) + 3: JS_METAVARIABLE@265..279 + 0: GRIT_METAVARIABLE@265..279 "μfunctionName" [] [] + 4: (empty) + 5: JS_PARAMETERS@279..282 + 0: L_PAREN@279..280 "(" [] [] + 1: JS_PARAMETER_LIST@280..280 + 2: R_PAREN@280..282 ")" [] [Whitespace(" ")] + 6: (empty) + 7: JS_FUNCTION_BODY@282..284 + 0: L_CURLY@282..283 "{" [] [] + 1: JS_DIRECTIVE_LIST@283..283 + 2: JS_STATEMENT_LIST@283..283 + 3: R_CURLY@283..284 "}" [] [] + 7: TS_TYPE_ALIAS_DECLARATION@284..312 + 0: TYPE_KW@284..291 "type" [Newline("\n"), Newline("\n")] [Whitespace(" ")] + 1: JS_METAVARIABLE@291..298 + 0: GRIT_METAVARIABLE@291..298 "μType" [] [Whitespace(" ")] + 2: (empty) + 3: EQ@298..300 "=" [] [Whitespace(" ")] + 4: JS_METAVARIABLE@300..311 + 0: GRIT_METAVARIABLE@300..311 "μOtherType" [] [] + 5: SEMICOLON@311..312 ";" [] [] + 4: EOF@312..313 "" [Newline("\n")] [] diff --git a/crates/biome_js_parser/test_data/inline/ok/metavar.ts b/crates/biome_js_parser/test_data/inline/ok/metavar.ts new file mode 100644 index 000000000000..15950a21d32e --- /dev/null +++ b/crates/biome_js_parser/test_data/inline/ok/metavar.ts @@ -0,0 +1,19 @@ +import μdefaultImport from μsource; +import { μnamedImport, type μnamedType } from μsource; + +μstatement; + +function foo() { + μstatement; + const bar = μexpression; +} + +class Foo { + μclassMember; +} + +const { μkey: key } = { μkey: μvalue }; + +function μfunctionName() {} + +type μType = μOtherType; diff --git a/crates/biome_js_syntax/src/binding_ext.rs b/crates/biome_js_syntax/src/binding_ext.rs index 9b53b4914f82..eca24bb99e40 100644 --- a/crates/biome_js_syntax/src/binding_ext.rs +++ b/crates/biome_js_syntax/src/binding_ext.rs @@ -68,7 +68,7 @@ impl AnyJsBindingDeclaration { /// /// ``` /// use biome_js_factory::make; - /// use biome_js_syntax::{binding_ext::AnyJsBindingDeclaration, T}; + /// use biome_js_syntax::{AnyTsIdentifierBinding, AnyTsModuleName, binding_ext::AnyJsBindingDeclaration, T}; /// /// let enum_id = make::js_identifier_binding(make::ident("Order")); /// let enum_decl: AnyJsBindingDeclaration = make::ts_enum_declaration( @@ -85,7 +85,7 @@ impl AnyJsBindingDeclaration { /// let namespace_id = make::ts_identifier_binding(make::ident("Order")); /// let namespace_decl: AnyJsBindingDeclaration = make::ts_module_declaration( /// make::token(T![namespace]), - /// namespace_id.into(), + /// AnyTsModuleName::AnyTsIdentifierBinding(AnyTsIdentifierBinding::from(namespace_id)), /// make::ts_module_block( /// make::token(T!['{']), /// make::js_module_item_list([]), diff --git a/crates/biome_js_syntax/src/expr_ext.rs b/crates/biome_js_syntax/src/expr_ext.rs index e7a8f831632e..9622449e42b3 100644 --- a/crates/biome_js_syntax/src/expr_ext.rs +++ b/crates/biome_js_syntax/src/expr_ext.rs @@ -934,7 +934,9 @@ impl AnyJsExpression { } } - AnyJsExpression::JsBogusExpression(_) => OperatorPrecedence::lowest(), + AnyJsExpression::JsBogusExpression(_) | AnyJsExpression::JsMetavariable(_) => { + OperatorPrecedence::lowest() + } AnyJsExpression::JsParenthesizedExpression(_) => OperatorPrecedence::highest(), }; @@ -1527,6 +1529,7 @@ impl AnyJsObjectMemberName { } } AnyJsObjectMemberName::JsLiteralMemberName(expr) => expr.value().ok()?, + AnyJsObjectMemberName::JsMetavariable(_) => return None, }; Some(inner_string_text(&token)) } @@ -1660,6 +1663,7 @@ impl AnyJsClassMemberName { &expr.id_token().ok()?, ))); } + AnyJsClassMemberName::JsMetavariable(_) => return None, }; Some(ClassMemberName::Public(inner_string_text(&token))) } diff --git a/crates/biome_js_syntax/src/generated/kind.rs b/crates/biome_js_syntax/src/generated/kind.rs index 02393005942a..febf32803792 100644 --- a/crates/biome_js_syntax/src/generated/kind.rs +++ b/crates/biome_js_syntax/src/generated/kind.rs @@ -173,6 +173,7 @@ pub enum JsSyntaxKind { COMMENT, MULTILINE_COMMENT, JS_SHEBANG, + GRIT_METAVARIABLE, JS_MODULE, JS_MODULE_ITEM_LIST, JS_SCRIPT, @@ -500,7 +501,7 @@ pub enum JsSyntaxKind { JSX_EXPRESSION_CHILD, JSX_SPREAD_CHILD, JSX_STRING, - JS_GRIT_METAVARIABLE, + JS_METAVARIABLE, JS_BOGUS, JS_BOGUS_EXPRESSION, JS_BOGUS_STATEMENT, diff --git a/crates/biome_js_syntax/src/generated/macros.rs b/crates/biome_js_syntax/src/generated/macros.rs index 0f348aaacc1b..1ddeda95d8a8 100644 --- a/crates/biome_js_syntax/src/generated/macros.rs +++ b/crates/biome_js_syntax/src/generated/macros.rs @@ -383,6 +383,10 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::JsLogicalExpression::new_unchecked(node) }; $body } + $crate::JsSyntaxKind::JS_METAVARIABLE => { + let $pattern = unsafe { $crate::JsMetavariable::new_unchecked(node) }; + $body + } $crate::JsSyntaxKind::JS_METHOD_CLASS_MEMBER => { let $pattern = unsafe { $crate::JsMethodClassMember::new_unchecked(node) }; $body diff --git a/crates/biome_js_syntax/src/generated/nodes.rs b/crates/biome_js_syntax/src/generated/nodes.rs index 6ca50e2cca98..26f6db058120 100644 --- a/crates/biome_js_syntax/src/generated/nodes.rs +++ b/crates/biome_js_syntax/src/generated/nodes.rs @@ -2184,7 +2184,7 @@ impl JsExportFromClause { pub fn from_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 3usize) } - pub fn source(&self) -> SyntaxResult { + pub fn source(&self) -> SyntaxResult { support::required_node(&self.syntax, 4usize) } pub fn assertion(&self) -> Option { @@ -2209,7 +2209,7 @@ pub struct JsExportFromClauseFields { pub star_token: SyntaxResult, pub export_as: Option, pub from_token: SyntaxResult, - pub source: SyntaxResult, + pub source: SyntaxResult, pub assertion: Option, pub semicolon_token: Option, } @@ -2310,7 +2310,7 @@ impl JsExportNamedFromClause { pub fn from_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 4usize) } - pub fn source(&self) -> SyntaxResult { + pub fn source(&self) -> SyntaxResult { support::required_node(&self.syntax, 5usize) } pub fn assertion(&self) -> Option { @@ -2336,7 +2336,7 @@ pub struct JsExportNamedFromClauseFields { pub specifiers: JsExportNamedFromSpecifierList, pub r_curly_token: SyntaxResult, pub from_token: SyntaxResult, - pub source: SyntaxResult, + pub source: SyntaxResult, pub assertion: Option, pub semicolon_token: Option, } @@ -3683,7 +3683,7 @@ impl JsImportBareClause { assertion: self.assertion(), } } - pub fn source(&self) -> SyntaxResult { + pub fn source(&self) -> SyntaxResult { support::required_node(&self.syntax, 0usize) } pub fn assertion(&self) -> Option { @@ -3701,7 +3701,7 @@ impl Serialize for JsImportBareClause { } #[cfg_attr(feature = "serde", derive(Serialize))] pub struct JsImportBareClauseFields { - pub source: SyntaxResult, + pub source: SyntaxResult, pub assertion: Option, } #[derive(Clone, PartialEq, Eq, Hash)] @@ -3781,7 +3781,7 @@ impl JsImportCombinedClause { pub fn from_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 3usize) } - pub fn source(&self) -> SyntaxResult { + pub fn source(&self) -> SyntaxResult { support::required_node(&self.syntax, 4usize) } pub fn assertion(&self) -> Option { @@ -3803,7 +3803,7 @@ pub struct JsImportCombinedClauseFields { pub comma_token: SyntaxResult, pub specifier: SyntaxResult, pub from_token: SyntaxResult, - pub source: SyntaxResult, + pub source: SyntaxResult, pub assertion: Option, } #[derive(Clone, PartialEq, Eq, Hash)] @@ -3838,7 +3838,7 @@ impl JsImportDefaultClause { pub fn from_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 2usize) } - pub fn source(&self) -> SyntaxResult { + pub fn source(&self) -> SyntaxResult { support::required_node(&self.syntax, 3usize) } pub fn assertion(&self) -> Option { @@ -3859,7 +3859,7 @@ pub struct JsImportDefaultClauseFields { pub type_token: Option, pub default_specifier: SyntaxResult, pub from_token: SyntaxResult, - pub source: SyntaxResult, + pub source: SyntaxResult, pub assertion: Option, } #[derive(Clone, PartialEq, Eq, Hash)] @@ -3940,7 +3940,7 @@ impl JsImportNamedClause { pub fn from_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 2usize) } - pub fn source(&self) -> SyntaxResult { + pub fn source(&self) -> SyntaxResult { support::required_node(&self.syntax, 3usize) } pub fn assertion(&self) -> Option { @@ -3961,7 +3961,7 @@ pub struct JsImportNamedClauseFields { pub type_token: Option, pub named_specifiers: SyntaxResult, pub from_token: SyntaxResult, - pub source: SyntaxResult, + pub source: SyntaxResult, pub assertion: Option, } #[derive(Clone, PartialEq, Eq, Hash)] @@ -3996,7 +3996,7 @@ impl JsImportNamespaceClause { pub fn from_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 2usize) } - pub fn source(&self) -> SyntaxResult { + pub fn source(&self) -> SyntaxResult { support::required_node(&self.syntax, 3usize) } pub fn assertion(&self) -> Option { @@ -4017,7 +4017,7 @@ pub struct JsImportNamespaceClauseFields { pub type_token: Option, pub namespace_specifier: SyntaxResult, pub from_token: SyntaxResult, - pub source: SyntaxResult, + pub source: SyntaxResult, pub assertion: Option, } #[derive(Clone, PartialEq, Eq, Hash)] @@ -4354,6 +4354,42 @@ pub struct JsLogicalExpressionFields { pub right: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] +pub struct JsMetavariable { + pub(crate) syntax: SyntaxNode, +} +impl JsMetavariable { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> JsMetavariableFields { + JsMetavariableFields { + value_token: self.value_token(), + } + } + pub fn value_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } +} +#[cfg(feature = "serde")] +impl Serialize for JsMetavariable { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[cfg_attr(feature = "serde", derive(Serialize))] +pub struct JsMetavariableFields { + pub value_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] pub struct JsMethodClassMember { pub(crate) syntax: SyntaxNode, } @@ -9669,7 +9705,7 @@ impl TsExternalModuleDeclaration { pub fn module_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } - pub fn source(&self) -> SyntaxResult { + pub fn source(&self) -> SyntaxResult { support::required_node(&self.syntax, 1usize) } pub fn body(&self) -> Option { @@ -9688,7 +9724,7 @@ impl Serialize for TsExternalModuleDeclaration { #[cfg_attr(feature = "serde", derive(Serialize))] pub struct TsExternalModuleDeclarationFields { pub module_token: SyntaxResult, - pub source: SyntaxResult, + pub source: SyntaxResult, pub body: Option, } #[derive(Clone, PartialEq, Eq, Hash)] @@ -9719,7 +9755,7 @@ impl TsExternalModuleReference { pub fn l_paren_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 1usize) } - pub fn source(&self) -> SyntaxResult { + pub fn source(&self) -> SyntaxResult { support::required_node(&self.syntax, 2usize) } pub fn r_paren_token(&self) -> SyntaxResult { @@ -9739,7 +9775,7 @@ impl Serialize for TsExternalModuleReference { pub struct TsExternalModuleReferenceFields { pub require_token: SyntaxResult, pub l_paren_token: SyntaxResult, - pub source: SyntaxResult, + pub source: SyntaxResult, pub r_paren_token: SyntaxResult, } #[derive(Clone, PartialEq, Eq, Hash)] @@ -10627,7 +10663,7 @@ impl TsInterfaceDeclaration { pub fn interface_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } - pub fn id(&self) -> SyntaxResult { + pub fn id(&self) -> SyntaxResult { support::required_node(&self.syntax, 1usize) } pub fn type_parameters(&self) -> Option { @@ -10658,7 +10694,7 @@ impl Serialize for TsInterfaceDeclaration { #[cfg_attr(feature = "serde", derive(Serialize))] pub struct TsInterfaceDeclarationFields { pub interface_token: SyntaxResult, - pub id: SyntaxResult, + pub id: SyntaxResult, pub type_parameters: Option, pub extends_clause: Option, pub l_curly_token: SyntaxResult, @@ -12804,7 +12840,7 @@ impl TsTypeAliasDeclaration { pub fn type_token(&self) -> SyntaxResult { support::required_token(&self.syntax, 0usize) } - pub fn binding_identifier(&self) -> SyntaxResult { + pub fn binding_identifier(&self) -> SyntaxResult { support::required_node(&self.syntax, 1usize) } pub fn type_parameters(&self) -> Option { @@ -12832,7 +12868,7 @@ impl Serialize for TsTypeAliasDeclaration { #[cfg_attr(feature = "serde", derive(Serialize))] pub struct TsTypeAliasDeclarationFields { pub type_token: SyntaxResult, - pub binding_identifier: SyntaxResult, + pub binding_identifier: SyntaxResult, pub type_parameters: Option, pub eq_token: SyntaxResult, pub ty: SyntaxResult, @@ -13647,6 +13683,7 @@ impl AnyJsAssignmentPattern { pub enum AnyJsBinding { JsBogusBinding(JsBogusBinding), JsIdentifierBinding(JsIdentifierBinding), + JsMetavariable(JsMetavariable), } impl AnyJsBinding { pub fn as_js_bogus_binding(&self) -> Option<&JsBogusBinding> { @@ -13661,6 +13698,12 @@ impl AnyJsBinding { _ => None, } } + pub fn as_js_metavariable(&self) -> Option<&JsMetavariable> { + match &self { + AnyJsBinding::JsMetavariable(item) => Some(item), + _ => None, + } + } } #[derive(Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize))] @@ -13745,6 +13788,7 @@ pub enum AnyJsClassMember { JsConstructorClassMember(JsConstructorClassMember), JsEmptyClassMember(JsEmptyClassMember), JsGetterClassMember(JsGetterClassMember), + JsMetavariable(JsMetavariable), JsMethodClassMember(JsMethodClassMember), JsPropertyClassMember(JsPropertyClassMember), JsSetterClassMember(JsSetterClassMember), @@ -13782,6 +13826,12 @@ impl AnyJsClassMember { _ => None, } } + pub fn as_js_metavariable(&self) -> Option<&JsMetavariable> { + match &self { + AnyJsClassMember::JsMetavariable(item) => Some(item), + _ => None, + } + } pub fn as_js_method_class_member(&self) -> Option<&JsMethodClassMember> { match &self { AnyJsClassMember::JsMethodClassMember(item) => Some(item), @@ -13860,6 +13910,7 @@ impl AnyJsClassMember { pub enum AnyJsClassMemberName { JsComputedMemberName(JsComputedMemberName), JsLiteralMemberName(JsLiteralMemberName), + JsMetavariable(JsMetavariable), JsPrivateClassMemberName(JsPrivateClassMemberName), } impl AnyJsClassMemberName { @@ -13875,6 +13926,12 @@ impl AnyJsClassMemberName { _ => None, } } + pub fn as_js_metavariable(&self) -> Option<&JsMetavariable> { + match &self { + AnyJsClassMemberName::JsMetavariable(item) => Some(item), + _ => None, + } + } pub fn as_js_private_class_member_name(&self) -> Option<&JsPrivateClassMemberName> { match &self { AnyJsClassMemberName::JsPrivateClassMemberName(item) => Some(item), @@ -14294,6 +14351,7 @@ pub enum AnyJsExpression { JsInExpression(JsInExpression), JsInstanceofExpression(JsInstanceofExpression), JsLogicalExpression(JsLogicalExpression), + JsMetavariable(JsMetavariable), JsNewExpression(JsNewExpression), JsNewTargetExpression(JsNewTargetExpression), JsObjectExpression(JsObjectExpression), @@ -14423,6 +14481,12 @@ impl AnyJsExpression { _ => None, } } + pub fn as_js_metavariable(&self) -> Option<&JsMetavariable> { + match &self { + AnyJsExpression::JsMetavariable(item) => Some(item), + _ => None, + } + } pub fn as_js_new_expression(&self) -> Option<&JsNewExpression> { match &self { AnyJsExpression::JsNewExpression(item) => Some(item), @@ -14846,6 +14910,26 @@ impl AnyJsModuleItem { } #[derive(Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize))] +pub enum AnyJsModuleSource { + JsMetavariable(JsMetavariable), + JsModuleSource(JsModuleSource), +} +impl AnyJsModuleSource { + pub fn as_js_metavariable(&self) -> Option<&JsMetavariable> { + match &self { + AnyJsModuleSource::JsMetavariable(item) => Some(item), + _ => None, + } + } + pub fn as_js_module_source(&self) -> Option<&JsModuleSource> { + match &self { + AnyJsModuleSource::JsModuleSource(item) => Some(item), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize))] pub enum AnyJsName { JsName(JsName), JsPrivateName(JsPrivateName), @@ -14939,6 +15023,7 @@ impl AnyJsObjectAssignmentPatternMember { #[cfg_attr(feature = "serde", derive(Serialize))] pub enum AnyJsObjectBindingPatternMember { JsBogusBinding(JsBogusBinding), + JsMetavariable(JsMetavariable), JsObjectBindingPatternProperty(JsObjectBindingPatternProperty), JsObjectBindingPatternRest(JsObjectBindingPatternRest), JsObjectBindingPatternShorthandProperty(JsObjectBindingPatternShorthandProperty), @@ -14950,6 +15035,12 @@ impl AnyJsObjectBindingPatternMember { _ => None, } } + pub fn as_js_metavariable(&self) -> Option<&JsMetavariable> { + match &self { + AnyJsObjectBindingPatternMember::JsMetavariable(item) => Some(item), + _ => None, + } + } pub fn as_js_object_binding_pattern_property(&self) -> Option<&JsObjectBindingPatternProperty> { match &self { AnyJsObjectBindingPatternMember::JsObjectBindingPatternProperty(item) => Some(item), @@ -15035,6 +15126,7 @@ impl AnyJsObjectMember { pub enum AnyJsObjectMemberName { JsComputedMemberName(JsComputedMemberName), JsLiteralMemberName(JsLiteralMemberName), + JsMetavariable(JsMetavariable), } impl AnyJsObjectMemberName { pub fn as_js_computed_member_name(&self) -> Option<&JsComputedMemberName> { @@ -15049,6 +15141,12 @@ impl AnyJsObjectMemberName { _ => None, } } + pub fn as_js_metavariable(&self) -> Option<&JsMetavariable> { + match &self { + AnyJsObjectMemberName::JsMetavariable(item) => Some(item), + _ => None, + } + } } #[derive(Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize))] @@ -15691,6 +15789,26 @@ impl AnyTsExternalModuleDeclarationBody { } #[derive(Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize))] +pub enum AnyTsIdentifierBinding { + JsMetavariable(JsMetavariable), + TsIdentifierBinding(TsIdentifierBinding), +} +impl AnyTsIdentifierBinding { + pub fn as_js_metavariable(&self) -> Option<&JsMetavariable> { + match &self { + AnyTsIdentifierBinding::JsMetavariable(item) => Some(item), + _ => None, + } + } + pub fn as_ts_identifier_binding(&self) -> Option<&TsIdentifierBinding> { + match &self { + AnyTsIdentifierBinding::TsIdentifierBinding(item) => Some(item), + _ => None, + } + } +} +#[derive(Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize))] pub enum AnyTsIndexSignatureModifier { JsStaticModifier(JsStaticModifier), TsReadonlyModifier(TsReadonlyModifier), @@ -15753,13 +15871,13 @@ impl AnyTsMethodSignatureModifier { #[derive(Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize))] pub enum AnyTsModuleName { - TsIdentifierBinding(TsIdentifierBinding), + AnyTsIdentifierBinding(AnyTsIdentifierBinding), TsQualifiedModuleName(TsQualifiedModuleName), } impl AnyTsModuleName { - pub fn as_ts_identifier_binding(&self) -> Option<&TsIdentifierBinding> { + pub fn as_any_ts_identifier_binding(&self) -> Option<&AnyTsIdentifierBinding> { match &self { - AnyTsModuleName::TsIdentifierBinding(item) => Some(item), + AnyTsModuleName::AnyTsIdentifierBinding(item) => Some(item), _ => None, } } @@ -16030,6 +16148,7 @@ impl AnyTsTupleTypeElement { #[derive(Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize))] pub enum AnyTsType { + JsMetavariable(JsMetavariable), TsAnyType(TsAnyType), TsArrayType(TsArrayType), TsBigintLiteralType(TsBigintLiteralType), @@ -16067,6 +16186,12 @@ pub enum AnyTsType { TsVoidType(TsVoidType), } impl AnyTsType { + pub fn as_js_metavariable(&self) -> Option<&JsMetavariable> { + match &self { + AnyTsType::JsMetavariable(item) => Some(item), + _ => None, + } + } pub fn as_ts_any_type(&self) -> Option<&TsAnyType> { match &self { AnyTsType::TsAnyType(item) => Some(item), @@ -20518,6 +20643,47 @@ impl From for SyntaxElement { n.syntax.into() } } +impl AstNode for JsMetavariable { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(JS_METAVARIABLE as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == JS_METAVARIABLE + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for JsMetavariable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("JsMetavariable") + .field( + "value_token", + &support::DebugSyntaxResult(self.value_token()), + ) + .finish() + } +} +impl From for SyntaxNode { + fn from(n: JsMetavariable) -> SyntaxNode { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: JsMetavariable) -> SyntaxElement { + n.syntax.into() + } +} impl AstNode for JsMethodClassMember { type Language = Language; const KIND_SET: SyntaxKindSet = @@ -30026,12 +30192,21 @@ impl From for AnyJsBinding { AnyJsBinding::JsIdentifierBinding(node) } } +impl From for AnyJsBinding { + fn from(node: JsMetavariable) -> AnyJsBinding { + AnyJsBinding::JsMetavariable(node) + } +} impl AstNode for AnyJsBinding { type Language = Language; - const KIND_SET: SyntaxKindSet = - JsBogusBinding::KIND_SET.union(JsIdentifierBinding::KIND_SET); + const KIND_SET: SyntaxKindSet = JsBogusBinding::KIND_SET + .union(JsIdentifierBinding::KIND_SET) + .union(JsMetavariable::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { - matches!(kind, JS_BOGUS_BINDING | JS_IDENTIFIER_BINDING) + matches!( + kind, + JS_BOGUS_BINDING | JS_IDENTIFIER_BINDING | JS_METAVARIABLE + ) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -30039,6 +30214,7 @@ impl AstNode for AnyJsBinding { JS_IDENTIFIER_BINDING => { AnyJsBinding::JsIdentifierBinding(JsIdentifierBinding { syntax }) } + JS_METAVARIABLE => AnyJsBinding::JsMetavariable(JsMetavariable { syntax }), _ => return None, }; Some(res) @@ -30047,12 +30223,14 @@ impl AstNode for AnyJsBinding { match self { AnyJsBinding::JsBogusBinding(it) => &it.syntax, AnyJsBinding::JsIdentifierBinding(it) => &it.syntax, + AnyJsBinding::JsMetavariable(it) => &it.syntax, } } fn into_syntax(self) -> SyntaxNode { match self { AnyJsBinding::JsBogusBinding(it) => it.syntax, AnyJsBinding::JsIdentifierBinding(it) => it.syntax, + AnyJsBinding::JsMetavariable(it) => it.syntax, } } } @@ -30061,6 +30239,7 @@ impl std::fmt::Debug for AnyJsBinding { match self { AnyJsBinding::JsBogusBinding(it) => std::fmt::Debug::fmt(it, f), AnyJsBinding::JsIdentifierBinding(it) => std::fmt::Debug::fmt(it, f), + AnyJsBinding::JsMetavariable(it) => std::fmt::Debug::fmt(it, f), } } } @@ -30069,6 +30248,7 @@ impl From for SyntaxNode { match n { AnyJsBinding::JsBogusBinding(it) => it.into(), AnyJsBinding::JsIdentifierBinding(it) => it.into(), + AnyJsBinding::JsMetavariable(it) => it.into(), } } } @@ -30316,6 +30496,11 @@ impl From for AnyJsClassMember { AnyJsClassMember::JsGetterClassMember(node) } } +impl From for AnyJsClassMember { + fn from(node: JsMetavariable) -> AnyJsClassMember { + AnyJsClassMember::JsMetavariable(node) + } +} impl From for AnyJsClassMember { fn from(node: JsMethodClassMember) -> AnyJsClassMember { AnyJsClassMember::JsMethodClassMember(node) @@ -30377,6 +30562,7 @@ impl AstNode for AnyJsClassMember { .union(JsConstructorClassMember::KIND_SET) .union(JsEmptyClassMember::KIND_SET) .union(JsGetterClassMember::KIND_SET) + .union(JsMetavariable::KIND_SET) .union(JsMethodClassMember::KIND_SET) .union(JsPropertyClassMember::KIND_SET) .union(JsSetterClassMember::KIND_SET) @@ -30395,6 +30581,7 @@ impl AstNode for AnyJsClassMember { | JS_CONSTRUCTOR_CLASS_MEMBER | JS_EMPTY_CLASS_MEMBER | JS_GETTER_CLASS_MEMBER + | JS_METAVARIABLE | JS_METHOD_CLASS_MEMBER | JS_PROPERTY_CLASS_MEMBER | JS_SETTER_CLASS_MEMBER @@ -30420,6 +30607,7 @@ impl AstNode for AnyJsClassMember { JS_GETTER_CLASS_MEMBER => { AnyJsClassMember::JsGetterClassMember(JsGetterClassMember { syntax }) } + JS_METAVARIABLE => AnyJsClassMember::JsMetavariable(JsMetavariable { syntax }), JS_METHOD_CLASS_MEMBER => { AnyJsClassMember::JsMethodClassMember(JsMethodClassMember { syntax }) } @@ -30479,6 +30667,7 @@ impl AstNode for AnyJsClassMember { AnyJsClassMember::JsConstructorClassMember(it) => &it.syntax, AnyJsClassMember::JsEmptyClassMember(it) => &it.syntax, AnyJsClassMember::JsGetterClassMember(it) => &it.syntax, + AnyJsClassMember::JsMetavariable(it) => &it.syntax, AnyJsClassMember::JsMethodClassMember(it) => &it.syntax, AnyJsClassMember::JsPropertyClassMember(it) => &it.syntax, AnyJsClassMember::JsSetterClassMember(it) => &it.syntax, @@ -30498,6 +30687,7 @@ impl AstNode for AnyJsClassMember { AnyJsClassMember::JsConstructorClassMember(it) => it.syntax, AnyJsClassMember::JsEmptyClassMember(it) => it.syntax, AnyJsClassMember::JsGetterClassMember(it) => it.syntax, + AnyJsClassMember::JsMetavariable(it) => it.syntax, AnyJsClassMember::JsMethodClassMember(it) => it.syntax, AnyJsClassMember::JsPropertyClassMember(it) => it.syntax, AnyJsClassMember::JsSetterClassMember(it) => it.syntax, @@ -30519,6 +30709,7 @@ impl std::fmt::Debug for AnyJsClassMember { AnyJsClassMember::JsConstructorClassMember(it) => std::fmt::Debug::fmt(it, f), AnyJsClassMember::JsEmptyClassMember(it) => std::fmt::Debug::fmt(it, f), AnyJsClassMember::JsGetterClassMember(it) => std::fmt::Debug::fmt(it, f), + AnyJsClassMember::JsMetavariable(it) => std::fmt::Debug::fmt(it, f), AnyJsClassMember::JsMethodClassMember(it) => std::fmt::Debug::fmt(it, f), AnyJsClassMember::JsPropertyClassMember(it) => std::fmt::Debug::fmt(it, f), AnyJsClassMember::JsSetterClassMember(it) => std::fmt::Debug::fmt(it, f), @@ -30544,6 +30735,7 @@ impl From for SyntaxNode { AnyJsClassMember::JsConstructorClassMember(it) => it.into(), AnyJsClassMember::JsEmptyClassMember(it) => it.into(), AnyJsClassMember::JsGetterClassMember(it) => it.into(), + AnyJsClassMember::JsMetavariable(it) => it.into(), AnyJsClassMember::JsMethodClassMember(it) => it.into(), AnyJsClassMember::JsPropertyClassMember(it) => it.into(), AnyJsClassMember::JsSetterClassMember(it) => it.into(), @@ -30574,6 +30766,11 @@ impl From for AnyJsClassMemberName { AnyJsClassMemberName::JsLiteralMemberName(node) } } +impl From for AnyJsClassMemberName { + fn from(node: JsMetavariable) -> AnyJsClassMemberName { + AnyJsClassMemberName::JsMetavariable(node) + } +} impl From for AnyJsClassMemberName { fn from(node: JsPrivateClassMemberName) -> AnyJsClassMemberName { AnyJsClassMemberName::JsPrivateClassMemberName(node) @@ -30583,11 +30780,15 @@ impl AstNode for AnyJsClassMemberName { type Language = Language; const KIND_SET: SyntaxKindSet = JsComputedMemberName::KIND_SET .union(JsLiteralMemberName::KIND_SET) + .union(JsMetavariable::KIND_SET) .union(JsPrivateClassMemberName::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, - JS_COMPUTED_MEMBER_NAME | JS_LITERAL_MEMBER_NAME | JS_PRIVATE_CLASS_MEMBER_NAME + JS_COMPUTED_MEMBER_NAME + | JS_LITERAL_MEMBER_NAME + | JS_METAVARIABLE + | JS_PRIVATE_CLASS_MEMBER_NAME ) } fn cast(syntax: SyntaxNode) -> Option { @@ -30598,6 +30799,7 @@ impl AstNode for AnyJsClassMemberName { JS_LITERAL_MEMBER_NAME => { AnyJsClassMemberName::JsLiteralMemberName(JsLiteralMemberName { syntax }) } + JS_METAVARIABLE => AnyJsClassMemberName::JsMetavariable(JsMetavariable { syntax }), JS_PRIVATE_CLASS_MEMBER_NAME => { AnyJsClassMemberName::JsPrivateClassMemberName(JsPrivateClassMemberName { syntax }) } @@ -30609,6 +30811,7 @@ impl AstNode for AnyJsClassMemberName { match self { AnyJsClassMemberName::JsComputedMemberName(it) => &it.syntax, AnyJsClassMemberName::JsLiteralMemberName(it) => &it.syntax, + AnyJsClassMemberName::JsMetavariable(it) => &it.syntax, AnyJsClassMemberName::JsPrivateClassMemberName(it) => &it.syntax, } } @@ -30616,6 +30819,7 @@ impl AstNode for AnyJsClassMemberName { match self { AnyJsClassMemberName::JsComputedMemberName(it) => it.syntax, AnyJsClassMemberName::JsLiteralMemberName(it) => it.syntax, + AnyJsClassMemberName::JsMetavariable(it) => it.syntax, AnyJsClassMemberName::JsPrivateClassMemberName(it) => it.syntax, } } @@ -30625,6 +30829,7 @@ impl std::fmt::Debug for AnyJsClassMemberName { match self { AnyJsClassMemberName::JsComputedMemberName(it) => std::fmt::Debug::fmt(it, f), AnyJsClassMemberName::JsLiteralMemberName(it) => std::fmt::Debug::fmt(it, f), + AnyJsClassMemberName::JsMetavariable(it) => std::fmt::Debug::fmt(it, f), AnyJsClassMemberName::JsPrivateClassMemberName(it) => std::fmt::Debug::fmt(it, f), } } @@ -30634,6 +30839,7 @@ impl From for SyntaxNode { match n { AnyJsClassMemberName::JsComputedMemberName(it) => it.into(), AnyJsClassMemberName::JsLiteralMemberName(it) => it.into(), + AnyJsClassMemberName::JsMetavariable(it) => it.into(), AnyJsClassMemberName::JsPrivateClassMemberName(it) => it.into(), } } @@ -31742,6 +31948,11 @@ impl From for AnyJsExpression { AnyJsExpression::JsLogicalExpression(node) } } +impl From for AnyJsExpression { + fn from(node: JsMetavariable) -> AnyJsExpression { + AnyJsExpression::JsMetavariable(node) + } +} impl From for AnyJsExpression { fn from(node: JsNewExpression) -> AnyJsExpression { AnyJsExpression::JsNewExpression(node) @@ -31857,6 +32068,7 @@ impl AstNode for AnyJsExpression { .union(JsInExpression::KIND_SET) .union(JsInstanceofExpression::KIND_SET) .union(JsLogicalExpression::KIND_SET) + .union(JsMetavariable::KIND_SET) .union(JsNewExpression::KIND_SET) .union(JsNewTargetExpression::KIND_SET) .union(JsObjectExpression::KIND_SET) @@ -31895,6 +32107,7 @@ impl AstNode for AnyJsExpression { | JS_IN_EXPRESSION | JS_INSTANCEOF_EXPRESSION | JS_LOGICAL_EXPRESSION + | JS_METAVARIABLE | JS_NEW_EXPRESSION | JS_NEW_TARGET_EXPRESSION | JS_OBJECT_EXPRESSION @@ -31959,6 +32172,7 @@ impl AstNode for AnyJsExpression { JS_LOGICAL_EXPRESSION => { AnyJsExpression::JsLogicalExpression(JsLogicalExpression { syntax }) } + JS_METAVARIABLE => AnyJsExpression::JsMetavariable(JsMetavariable { syntax }), JS_NEW_EXPRESSION => AnyJsExpression::JsNewExpression(JsNewExpression { syntax }), JS_NEW_TARGET_EXPRESSION => { AnyJsExpression::JsNewTargetExpression(JsNewTargetExpression { syntax }) @@ -32034,6 +32248,7 @@ impl AstNode for AnyJsExpression { AnyJsExpression::JsInExpression(it) => &it.syntax, AnyJsExpression::JsInstanceofExpression(it) => &it.syntax, AnyJsExpression::JsLogicalExpression(it) => &it.syntax, + AnyJsExpression::JsMetavariable(it) => &it.syntax, AnyJsExpression::JsNewExpression(it) => &it.syntax, AnyJsExpression::JsNewTargetExpression(it) => &it.syntax, AnyJsExpression::JsObjectExpression(it) => &it.syntax, @@ -32075,6 +32290,7 @@ impl AstNode for AnyJsExpression { AnyJsExpression::JsInExpression(it) => it.syntax, AnyJsExpression::JsInstanceofExpression(it) => it.syntax, AnyJsExpression::JsLogicalExpression(it) => it.syntax, + AnyJsExpression::JsMetavariable(it) => it.syntax, AnyJsExpression::JsNewExpression(it) => it.syntax, AnyJsExpression::JsNewTargetExpression(it) => it.syntax, AnyJsExpression::JsObjectExpression(it) => it.syntax, @@ -32119,6 +32335,7 @@ impl std::fmt::Debug for AnyJsExpression { AnyJsExpression::JsInExpression(it) => std::fmt::Debug::fmt(it, f), AnyJsExpression::JsInstanceofExpression(it) => std::fmt::Debug::fmt(it, f), AnyJsExpression::JsLogicalExpression(it) => std::fmt::Debug::fmt(it, f), + AnyJsExpression::JsMetavariable(it) => std::fmt::Debug::fmt(it, f), AnyJsExpression::JsNewExpression(it) => std::fmt::Debug::fmt(it, f), AnyJsExpression::JsNewTargetExpression(it) => std::fmt::Debug::fmt(it, f), AnyJsExpression::JsObjectExpression(it) => std::fmt::Debug::fmt(it, f), @@ -32162,6 +32379,7 @@ impl From for SyntaxNode { AnyJsExpression::JsInExpression(it) => it.into(), AnyJsExpression::JsInstanceofExpression(it) => it.into(), AnyJsExpression::JsLogicalExpression(it) => it.into(), + AnyJsExpression::JsMetavariable(it) => it.into(), AnyJsExpression::JsNewExpression(it) => it.into(), AnyJsExpression::JsNewTargetExpression(it) => it.into(), AnyJsExpression::JsObjectExpression(it) => it.into(), @@ -33092,6 +33310,66 @@ impl From for SyntaxElement { node.into() } } +impl From for AnyJsModuleSource { + fn from(node: JsMetavariable) -> AnyJsModuleSource { + AnyJsModuleSource::JsMetavariable(node) + } +} +impl From for AnyJsModuleSource { + fn from(node: JsModuleSource) -> AnyJsModuleSource { + AnyJsModuleSource::JsModuleSource(node) + } +} +impl AstNode for AnyJsModuleSource { + type Language = Language; + const KIND_SET: SyntaxKindSet = + JsMetavariable::KIND_SET.union(JsModuleSource::KIND_SET); + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, JS_METAVARIABLE | JS_MODULE_SOURCE) + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + JS_METAVARIABLE => AnyJsModuleSource::JsMetavariable(JsMetavariable { syntax }), + JS_MODULE_SOURCE => AnyJsModuleSource::JsModuleSource(JsModuleSource { syntax }), + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + AnyJsModuleSource::JsMetavariable(it) => &it.syntax, + AnyJsModuleSource::JsModuleSource(it) => &it.syntax, + } + } + fn into_syntax(self) -> SyntaxNode { + match self { + AnyJsModuleSource::JsMetavariable(it) => it.syntax, + AnyJsModuleSource::JsModuleSource(it) => it.syntax, + } + } +} +impl std::fmt::Debug for AnyJsModuleSource { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + AnyJsModuleSource::JsMetavariable(it) => std::fmt::Debug::fmt(it, f), + AnyJsModuleSource::JsModuleSource(it) => std::fmt::Debug::fmt(it, f), + } + } +} +impl From for SyntaxNode { + fn from(n: AnyJsModuleSource) -> SyntaxNode { + match n { + AnyJsModuleSource::JsMetavariable(it) => it.into(), + AnyJsModuleSource::JsModuleSource(it) => it.into(), + } + } +} +impl From for SyntaxElement { + fn from(n: AnyJsModuleSource) -> SyntaxElement { + let node: SyntaxNode = n.into(); + node.into() + } +} impl From for AnyJsName { fn from(node: JsName) -> AnyJsName { AnyJsName::JsName(node) @@ -33364,6 +33642,11 @@ impl From for AnyJsObjectBindingPatternMember { AnyJsObjectBindingPatternMember::JsBogusBinding(node) } } +impl From for AnyJsObjectBindingPatternMember { + fn from(node: JsMetavariable) -> AnyJsObjectBindingPatternMember { + AnyJsObjectBindingPatternMember::JsMetavariable(node) + } +} impl From for AnyJsObjectBindingPatternMember { fn from(node: JsObjectBindingPatternProperty) -> AnyJsObjectBindingPatternMember { AnyJsObjectBindingPatternMember::JsObjectBindingPatternProperty(node) @@ -33382,6 +33665,7 @@ impl From for AnyJsObjectBindingPattern impl AstNode for AnyJsObjectBindingPatternMember { type Language = Language; const KIND_SET: SyntaxKindSet = JsBogusBinding::KIND_SET + .union(JsMetavariable::KIND_SET) .union(JsObjectBindingPatternProperty::KIND_SET) .union(JsObjectBindingPatternRest::KIND_SET) .union(JsObjectBindingPatternShorthandProperty::KIND_SET); @@ -33389,6 +33673,7 @@ impl AstNode for AnyJsObjectBindingPatternMember { matches!( kind, JS_BOGUS_BINDING + | JS_METAVARIABLE | JS_OBJECT_BINDING_PATTERN_PROPERTY | JS_OBJECT_BINDING_PATTERN_REST | JS_OBJECT_BINDING_PATTERN_SHORTHAND_PROPERTY @@ -33399,6 +33684,9 @@ impl AstNode for AnyJsObjectBindingPatternMember { JS_BOGUS_BINDING => { AnyJsObjectBindingPatternMember::JsBogusBinding(JsBogusBinding { syntax }) } + JS_METAVARIABLE => { + AnyJsObjectBindingPatternMember::JsMetavariable(JsMetavariable { syntax }) + } JS_OBJECT_BINDING_PATTERN_PROPERTY => { AnyJsObjectBindingPatternMember::JsObjectBindingPatternProperty( JsObjectBindingPatternProperty { syntax }, @@ -33421,6 +33709,7 @@ impl AstNode for AnyJsObjectBindingPatternMember { fn syntax(&self) -> &SyntaxNode { match self { AnyJsObjectBindingPatternMember::JsBogusBinding(it) => &it.syntax, + AnyJsObjectBindingPatternMember::JsMetavariable(it) => &it.syntax, AnyJsObjectBindingPatternMember::JsObjectBindingPatternProperty(it) => &it.syntax, AnyJsObjectBindingPatternMember::JsObjectBindingPatternRest(it) => &it.syntax, AnyJsObjectBindingPatternMember::JsObjectBindingPatternShorthandProperty(it) => { @@ -33431,6 +33720,7 @@ impl AstNode for AnyJsObjectBindingPatternMember { fn into_syntax(self) -> SyntaxNode { match self { AnyJsObjectBindingPatternMember::JsBogusBinding(it) => it.syntax, + AnyJsObjectBindingPatternMember::JsMetavariable(it) => it.syntax, AnyJsObjectBindingPatternMember::JsObjectBindingPatternProperty(it) => it.syntax, AnyJsObjectBindingPatternMember::JsObjectBindingPatternRest(it) => it.syntax, AnyJsObjectBindingPatternMember::JsObjectBindingPatternShorthandProperty(it) => { @@ -33443,6 +33733,7 @@ impl std::fmt::Debug for AnyJsObjectBindingPatternMember { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { AnyJsObjectBindingPatternMember::JsBogusBinding(it) => std::fmt::Debug::fmt(it, f), + AnyJsObjectBindingPatternMember::JsMetavariable(it) => std::fmt::Debug::fmt(it, f), AnyJsObjectBindingPatternMember::JsObjectBindingPatternProperty(it) => { std::fmt::Debug::fmt(it, f) } @@ -33459,6 +33750,7 @@ impl From for SyntaxNode { fn from(n: AnyJsObjectBindingPatternMember) -> SyntaxNode { match n { AnyJsObjectBindingPatternMember::JsBogusBinding(it) => it.into(), + AnyJsObjectBindingPatternMember::JsMetavariable(it) => it.into(), AnyJsObjectBindingPatternMember::JsObjectBindingPatternProperty(it) => it.into(), AnyJsObjectBindingPatternMember::JsObjectBindingPatternRest(it) => it.into(), AnyJsObjectBindingPatternMember::JsObjectBindingPatternShorthandProperty(it) => { @@ -33619,12 +33911,21 @@ impl From for AnyJsObjectMemberName { AnyJsObjectMemberName::JsLiteralMemberName(node) } } +impl From for AnyJsObjectMemberName { + fn from(node: JsMetavariable) -> AnyJsObjectMemberName { + AnyJsObjectMemberName::JsMetavariable(node) + } +} impl AstNode for AnyJsObjectMemberName { type Language = Language; - const KIND_SET: SyntaxKindSet = - JsComputedMemberName::KIND_SET.union(JsLiteralMemberName::KIND_SET); + const KIND_SET: SyntaxKindSet = JsComputedMemberName::KIND_SET + .union(JsLiteralMemberName::KIND_SET) + .union(JsMetavariable::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { - matches!(kind, JS_COMPUTED_MEMBER_NAME | JS_LITERAL_MEMBER_NAME) + matches!( + kind, + JS_COMPUTED_MEMBER_NAME | JS_LITERAL_MEMBER_NAME | JS_METAVARIABLE + ) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -33634,6 +33935,7 @@ impl AstNode for AnyJsObjectMemberName { JS_LITERAL_MEMBER_NAME => { AnyJsObjectMemberName::JsLiteralMemberName(JsLiteralMemberName { syntax }) } + JS_METAVARIABLE => AnyJsObjectMemberName::JsMetavariable(JsMetavariable { syntax }), _ => return None, }; Some(res) @@ -33642,12 +33944,14 @@ impl AstNode for AnyJsObjectMemberName { match self { AnyJsObjectMemberName::JsComputedMemberName(it) => &it.syntax, AnyJsObjectMemberName::JsLiteralMemberName(it) => &it.syntax, + AnyJsObjectMemberName::JsMetavariable(it) => &it.syntax, } } fn into_syntax(self) -> SyntaxNode { match self { AnyJsObjectMemberName::JsComputedMemberName(it) => it.syntax, AnyJsObjectMemberName::JsLiteralMemberName(it) => it.syntax, + AnyJsObjectMemberName::JsMetavariable(it) => it.syntax, } } } @@ -33656,6 +33960,7 @@ impl std::fmt::Debug for AnyJsObjectMemberName { match self { AnyJsObjectMemberName::JsComputedMemberName(it) => std::fmt::Debug::fmt(it, f), AnyJsObjectMemberName::JsLiteralMemberName(it) => std::fmt::Debug::fmt(it, f), + AnyJsObjectMemberName::JsMetavariable(it) => std::fmt::Debug::fmt(it, f), } } } @@ -33664,6 +33969,7 @@ impl From for SyntaxNode { match n { AnyJsObjectMemberName::JsComputedMemberName(it) => it.into(), AnyJsObjectMemberName::JsLiteralMemberName(it) => it.into(), + AnyJsObjectMemberName::JsMetavariable(it) => it.into(), } } } @@ -35277,6 +35583,68 @@ impl From for SyntaxElement { node.into() } } +impl From for AnyTsIdentifierBinding { + fn from(node: JsMetavariable) -> AnyTsIdentifierBinding { + AnyTsIdentifierBinding::JsMetavariable(node) + } +} +impl From for AnyTsIdentifierBinding { + fn from(node: TsIdentifierBinding) -> AnyTsIdentifierBinding { + AnyTsIdentifierBinding::TsIdentifierBinding(node) + } +} +impl AstNode for AnyTsIdentifierBinding { + type Language = Language; + const KIND_SET: SyntaxKindSet = + JsMetavariable::KIND_SET.union(TsIdentifierBinding::KIND_SET); + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, JS_METAVARIABLE | TS_IDENTIFIER_BINDING) + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + JS_METAVARIABLE => AnyTsIdentifierBinding::JsMetavariable(JsMetavariable { syntax }), + TS_IDENTIFIER_BINDING => { + AnyTsIdentifierBinding::TsIdentifierBinding(TsIdentifierBinding { syntax }) + } + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + AnyTsIdentifierBinding::JsMetavariable(it) => &it.syntax, + AnyTsIdentifierBinding::TsIdentifierBinding(it) => &it.syntax, + } + } + fn into_syntax(self) -> SyntaxNode { + match self { + AnyTsIdentifierBinding::JsMetavariable(it) => it.syntax, + AnyTsIdentifierBinding::TsIdentifierBinding(it) => it.syntax, + } + } +} +impl std::fmt::Debug for AnyTsIdentifierBinding { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + AnyTsIdentifierBinding::JsMetavariable(it) => std::fmt::Debug::fmt(it, f), + AnyTsIdentifierBinding::TsIdentifierBinding(it) => std::fmt::Debug::fmt(it, f), + } + } +} +impl From for SyntaxNode { + fn from(n: AnyTsIdentifierBinding) -> SyntaxNode { + match n { + AnyTsIdentifierBinding::JsMetavariable(it) => it.into(), + AnyTsIdentifierBinding::TsIdentifierBinding(it) => it.into(), + } + } +} +impl From for SyntaxElement { + fn from(n: AnyTsIdentifierBinding) -> SyntaxElement { + let node: SyntaxNode = n.into(); + node.into() + } +} impl From for AnyTsIndexSignatureModifier { fn from(node: JsStaticModifier) -> AnyTsIndexSignatureModifier { AnyTsIndexSignatureModifier::JsStaticModifier(node) @@ -35453,11 +35821,6 @@ impl From for SyntaxElement { node.into() } } -impl From for AnyTsModuleName { - fn from(node: TsIdentifierBinding) -> AnyTsModuleName { - AnyTsModuleName::TsIdentifierBinding(node) - } -} impl From for AnyTsModuleName { fn from(node: TsQualifiedModuleName) -> AnyTsModuleName { AnyTsModuleName::TsQualifiedModuleName(node) @@ -35466,39 +35829,47 @@ impl From for AnyTsModuleName { impl AstNode for AnyTsModuleName { type Language = Language; const KIND_SET: SyntaxKindSet = - TsIdentifierBinding::KIND_SET.union(TsQualifiedModuleName::KIND_SET); + AnyTsIdentifierBinding::KIND_SET.union(TsQualifiedModuleName::KIND_SET); fn can_cast(kind: SyntaxKind) -> bool { - matches!(kind, TS_IDENTIFIER_BINDING | TS_QUALIFIED_MODULE_NAME) + match kind { + TS_QUALIFIED_MODULE_NAME => true, + k if AnyTsIdentifierBinding::can_cast(k) => true, + _ => false, + } } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { - TS_IDENTIFIER_BINDING => { - AnyTsModuleName::TsIdentifierBinding(TsIdentifierBinding { syntax }) - } TS_QUALIFIED_MODULE_NAME => { AnyTsModuleName::TsQualifiedModuleName(TsQualifiedModuleName { syntax }) } - _ => return None, + _ => { + if let Some(any_ts_identifier_binding) = AnyTsIdentifierBinding::cast(syntax) { + return Some(AnyTsModuleName::AnyTsIdentifierBinding( + any_ts_identifier_binding, + )); + } + return None; + } }; Some(res) } fn syntax(&self) -> &SyntaxNode { match self { - AnyTsModuleName::TsIdentifierBinding(it) => &it.syntax, AnyTsModuleName::TsQualifiedModuleName(it) => &it.syntax, + AnyTsModuleName::AnyTsIdentifierBinding(it) => it.syntax(), } } fn into_syntax(self) -> SyntaxNode { match self { - AnyTsModuleName::TsIdentifierBinding(it) => it.syntax, AnyTsModuleName::TsQualifiedModuleName(it) => it.syntax, + AnyTsModuleName::AnyTsIdentifierBinding(it) => it.into_syntax(), } } } impl std::fmt::Debug for AnyTsModuleName { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - AnyTsModuleName::TsIdentifierBinding(it) => std::fmt::Debug::fmt(it, f), + AnyTsModuleName::AnyTsIdentifierBinding(it) => std::fmt::Debug::fmt(it, f), AnyTsModuleName::TsQualifiedModuleName(it) => std::fmt::Debug::fmt(it, f), } } @@ -35506,7 +35877,7 @@ impl std::fmt::Debug for AnyTsModuleName { impl From for SyntaxNode { fn from(n: AnyTsModuleName) -> SyntaxNode { match n { - AnyTsModuleName::TsIdentifierBinding(it) => it.into(), + AnyTsModuleName::AnyTsIdentifierBinding(it) => it.into(), AnyTsModuleName::TsQualifiedModuleName(it) => it.into(), } } @@ -36277,6 +36648,11 @@ impl From for SyntaxElement { node.into() } } +impl From for AnyTsType { + fn from(node: JsMetavariable) -> AnyTsType { + AnyTsType::JsMetavariable(node) + } +} impl From for AnyTsType { fn from(node: TsAnyType) -> AnyTsType { AnyTsType::TsAnyType(node) @@ -36454,7 +36830,8 @@ impl From for AnyTsType { } impl AstNode for AnyTsType { type Language = Language; - const KIND_SET: SyntaxKindSet = TsAnyType::KIND_SET + const KIND_SET: SyntaxKindSet = JsMetavariable::KIND_SET + .union(TsAnyType::KIND_SET) .union(TsArrayType::KIND_SET) .union(TsBigintLiteralType::KIND_SET) .union(TsBigintType::KIND_SET) @@ -36492,7 +36869,8 @@ impl AstNode for AnyTsType { fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, - TS_ANY_TYPE + JS_METAVARIABLE + | TS_ANY_TYPE | TS_ARRAY_TYPE | TS_BIGINT_LITERAL_TYPE | TS_BIGINT_TYPE @@ -36531,6 +36909,7 @@ impl AstNode for AnyTsType { } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { + JS_METAVARIABLE => AnyTsType::JsMetavariable(JsMetavariable { syntax }), TS_ANY_TYPE => AnyTsType::TsAnyType(TsAnyType { syntax }), TS_ARRAY_TYPE => AnyTsType::TsArrayType(TsArrayType { syntax }), TS_BIGINT_LITERAL_TYPE => { @@ -36584,6 +36963,7 @@ impl AstNode for AnyTsType { } fn syntax(&self) -> &SyntaxNode { match self { + AnyTsType::JsMetavariable(it) => &it.syntax, AnyTsType::TsAnyType(it) => &it.syntax, AnyTsType::TsArrayType(it) => &it.syntax, AnyTsType::TsBigintLiteralType(it) => &it.syntax, @@ -36623,6 +37003,7 @@ impl AstNode for AnyTsType { } fn into_syntax(self) -> SyntaxNode { match self { + AnyTsType::JsMetavariable(it) => it.syntax, AnyTsType::TsAnyType(it) => it.syntax, AnyTsType::TsArrayType(it) => it.syntax, AnyTsType::TsBigintLiteralType(it) => it.syntax, @@ -36664,6 +37045,7 @@ impl AstNode for AnyTsType { impl std::fmt::Debug for AnyTsType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { + AnyTsType::JsMetavariable(it) => std::fmt::Debug::fmt(it, f), AnyTsType::TsAnyType(it) => std::fmt::Debug::fmt(it, f), AnyTsType::TsArrayType(it) => std::fmt::Debug::fmt(it, f), AnyTsType::TsBigintLiteralType(it) => std::fmt::Debug::fmt(it, f), @@ -36705,6 +37087,7 @@ impl std::fmt::Debug for AnyTsType { impl From for SyntaxNode { fn from(n: AnyTsType) -> SyntaxNode { match n { + AnyTsType::JsMetavariable(it) => it.into(), AnyTsType::TsAnyType(it) => it.into(), AnyTsType::TsArrayType(it) => it.into(), AnyTsType::TsBigintLiteralType(it) => it.into(), @@ -37270,6 +37653,11 @@ impl std::fmt::Display for AnyJsModuleItem { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for AnyJsModuleSource { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for AnyJsName { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -37380,6 +37768,11 @@ impl std::fmt::Display for AnyTsExternalModuleDeclarationBody { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for AnyTsIdentifierBinding { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for AnyTsIndexSignatureModifier { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -37905,6 +38298,11 @@ impl std::fmt::Display for JsLogicalExpression { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for JsMetavariable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for JsMethodClassMember { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/crates/biome_js_syntax/src/generated/nodes_mut.rs b/crates/biome_js_syntax/src/generated/nodes_mut.rs index c8b529cb5476..3416d6adc2b5 100644 --- a/crates/biome_js_syntax/src/generated/nodes_mut.rs +++ b/crates/biome_js_syntax/src/generated/nodes_mut.rs @@ -993,7 +993,7 @@ impl JsExportFromClause { .splice_slots(3usize..=3usize, once(Some(element.into()))), ) } - pub fn with_source(self, element: JsModuleSource) -> Self { + pub fn with_source(self, element: AnyJsModuleSource) -> Self { Self::unwrap_cast( self.syntax .splice_slots(4usize..=4usize, once(Some(element.into_syntax().into()))), @@ -1075,7 +1075,7 @@ impl JsExportNamedFromClause { .splice_slots(4usize..=4usize, once(Some(element.into()))), ) } - pub fn with_source(self, element: JsModuleSource) -> Self { + pub fn with_source(self, element: AnyJsModuleSource) -> Self { Self::unwrap_cast( self.syntax .splice_slots(5usize..=5usize, once(Some(element.into_syntax().into()))), @@ -1805,7 +1805,7 @@ impl JsImportAssertionEntry { } } impl JsImportBareClause { - pub fn with_source(self, element: JsModuleSource) -> Self { + pub fn with_source(self, element: AnyJsModuleSource) -> Self { Self::unwrap_cast( self.syntax .splice_slots(0usize..=0usize, once(Some(element.into_syntax().into()))), @@ -1857,7 +1857,7 @@ impl JsImportCombinedClause { .splice_slots(3usize..=3usize, once(Some(element.into()))), ) } - pub fn with_source(self, element: JsModuleSource) -> Self { + pub fn with_source(self, element: AnyJsModuleSource) -> Self { Self::unwrap_cast( self.syntax .splice_slots(4usize..=4usize, once(Some(element.into_syntax().into()))), @@ -1889,7 +1889,7 @@ impl JsImportDefaultClause { .splice_slots(2usize..=2usize, once(Some(element.into()))), ) } - pub fn with_source(self, element: JsModuleSource) -> Self { + pub fn with_source(self, element: AnyJsModuleSource) -> Self { Self::unwrap_cast( self.syntax .splice_slots(3usize..=3usize, once(Some(element.into_syntax().into()))), @@ -1941,7 +1941,7 @@ impl JsImportNamedClause { .splice_slots(2usize..=2usize, once(Some(element.into()))), ) } - pub fn with_source(self, element: JsModuleSource) -> Self { + pub fn with_source(self, element: AnyJsModuleSource) -> Self { Self::unwrap_cast( self.syntax .splice_slots(3usize..=3usize, once(Some(element.into_syntax().into()))), @@ -1973,7 +1973,7 @@ impl JsImportNamespaceClause { .splice_slots(2usize..=2usize, once(Some(element.into()))), ) } - pub fn with_source(self, element: JsModuleSource) -> Self { + pub fn with_source(self, element: AnyJsModuleSource) -> Self { Self::unwrap_cast( self.syntax .splice_slots(3usize..=3usize, once(Some(element.into_syntax().into()))), @@ -2104,6 +2104,14 @@ impl JsLogicalExpression { ) } } +impl JsMetavariable { + pub fn with_value_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } +} impl JsMethodClassMember { pub fn with_modifiers(self, element: JsMethodModifierList) -> Self { Self::unwrap_cast( @@ -4383,7 +4391,7 @@ impl TsExternalModuleDeclaration { .splice_slots(0usize..=0usize, once(Some(element.into()))), ) } - pub fn with_source(self, element: JsModuleSource) -> Self { + pub fn with_source(self, element: AnyJsModuleSource) -> Self { Self::unwrap_cast( self.syntax .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), @@ -4409,7 +4417,7 @@ impl TsExternalModuleReference { .splice_slots(1usize..=1usize, once(Some(element.into()))), ) } - pub fn with_source(self, element: JsModuleSource) -> Self { + pub fn with_source(self, element: AnyJsModuleSource) -> Self { Self::unwrap_cast( self.syntax .splice_slots(2usize..=2usize, once(Some(element.into_syntax().into()))), @@ -4859,7 +4867,7 @@ impl TsInterfaceDeclaration { .splice_slots(0usize..=0usize, once(Some(element.into()))), ) } - pub fn with_id(self, element: TsIdentifierBinding) -> Self { + pub fn with_id(self, element: AnyTsIdentifierBinding) -> Self { Self::unwrap_cast( self.syntax .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), @@ -5792,7 +5800,7 @@ impl TsTypeAliasDeclaration { .splice_slots(0usize..=0usize, once(Some(element.into()))), ) } - pub fn with_binding_identifier(self, element: TsIdentifierBinding) -> Self { + pub fn with_binding_identifier(self, element: AnyTsIdentifierBinding) -> Self { Self::unwrap_cast( self.syntax .splice_slots(1usize..=1usize, once(Some(element.into_syntax().into()))), diff --git a/crates/biome_js_syntax/src/import_ext.rs b/crates/biome_js_syntax/src/import_ext.rs index 485723c978b5..880fbc2befcb 100644 --- a/crates/biome_js_syntax/src/import_ext.rs +++ b/crates/biome_js_syntax/src/import_ext.rs @@ -1,10 +1,13 @@ use crate::{ - inner_string_text, AnyJsBinding, AnyJsImportClause, AnyJsNamedImportSpecifier, - JsCallExpression, JsDefaultImportSpecifier, JsImport, JsImportAssertion, - JsImportCallExpression, JsModuleSource, JsNamedImportSpecifier, JsNamespaceImportSpecifier, - JsShorthandNamedImportSpecifier, JsSyntaxToken, TsExternalModuleDeclaration, + inner_string_text, AnyJsBinding, AnyJsImportClause, AnyJsModuleSource, + AnyJsNamedImportSpecifier, JsCallExpression, JsDefaultImportSpecifier, JsImport, + JsImportAssertion, JsImportCallExpression, JsModuleSource, JsNamedImportSpecifier, + JsNamespaceImportSpecifier, JsShorthandNamedImportSpecifier, JsSyntaxToken, + TsExternalModuleDeclaration, +}; +use biome_rowan::{ + declare_node_union, AstNode, SyntaxError, SyntaxNodeOptionExt, SyntaxResult, TokenText, }; -use biome_rowan::{declare_node_union, AstNode, SyntaxNodeOptionExt, SyntaxResult, TokenText}; impl JsImport { /// It checks if the source of an import against the string `source_to_check` @@ -18,7 +21,7 @@ impl JsImport { /// let source = make::js_module_source(make::js_string_literal("react")); /// let binding = make::js_identifier_binding(make::ident("React")); /// let specifier = make::js_default_import_specifier(binding.into()); - /// let clause = make::js_import_default_clause(specifier, make::token(T![from]), source).build(); + /// let clause = make::js_import_default_clause(specifier, make::token(T![from]), source.into()).build(); /// let import = make::js_import(make::token(T![import]), clause.into()).build(); /// /// assert_eq!(import.source_text().unwrap().text(), "react"); @@ -54,18 +57,23 @@ impl AnyJsImportClause { /// let source = make::js_module_source(make::js_string_literal("react")); /// let binding = make::js_identifier_binding(make::ident("React")); /// let specifier = make::js_default_import_specifier(binding.into()); - /// let clause = make::js_import_default_clause(specifier, make::token(T![from]), source).build(); + /// let clause = make::js_import_default_clause(specifier, make::token(T![from]), source.into()).build(); /// - /// assert_eq!(clause.source().unwrap().inner_string_text().unwrap().text(), "react"); + /// assert_eq!(clause.source().unwrap().as_js_module_source().unwrap().inner_string_text().unwrap().text(), "react"); /// ``` pub fn source(&self) -> SyntaxResult { - match self { + let source = match self { Self::JsImportBareClause(clause) => clause.source(), Self::JsImportDefaultClause(clause) => clause.source(), Self::JsImportNamedClause(clause) => clause.source(), Self::JsImportNamespaceClause(clause) => clause.source(), Self::JsImportCombinedClause(clause) => clause.source(), - } + }; + + source.and_then(|source| match source { + AnyJsModuleSource::JsModuleSource(source) => Ok(source), + AnyJsModuleSource::JsMetavariable(_) => Err(SyntaxError::UnexpectedMetavariable), + }) } /// Assertion of this import clause. @@ -77,9 +85,9 @@ impl AnyJsImportClause { /// let source = make::js_module_source(make::js_string_literal("react")); /// let binding = make::js_identifier_binding(make::ident("React")); /// let specifier = make::js_default_import_specifier(binding.into()); - /// let clause = make::js_import_default_clause(specifier, make::token(T![from]), source).build(); + /// let clause = make::js_import_default_clause(specifier, make::token(T![from]), source.into()).build(); /// - /// assert_eq!(clause.source().unwrap().inner_string_text().unwrap().text(), "react"); + /// assert_eq!(clause.source().unwrap().as_js_module_source().unwrap().inner_string_text().unwrap().text(), "react"); /// ``` pub fn assertion(&self) -> Option { match self { @@ -315,12 +323,12 @@ impl AnyJsImportLike { /// /// let module_token = JsSyntaxToken::new_detached(JsSyntaxKind::MODULE_KW, "module", [], []); /// let module_source = make::js_module_source(make::js_string_literal("foo")); - /// let module_declaration = make::ts_external_module_declaration(module_token, module_source).build(); - /// let any_import_specifier = AnyJsImportLike::JsModuleSource(module_declaration.source().expect("module source")); + /// let module_declaration = make::ts_external_module_declaration(module_token, module_source.into()).build(); + /// let any_import_specifier = AnyJsImportLike::JsModuleSource(module_declaration.source().unwrap().as_js_module_source().unwrap().clone()); /// assert!(any_import_specifier.is_in_ts_module_declaration()); /// /// let module_source = make::js_module_source(make::js_string_literal("bar")); - /// let any_import_specifier = AnyJsImportLike::JsModuleSource(module_source); + /// let any_import_specifier = AnyJsImportLike::JsModuleSource(module_source.into()); /// assert!(!any_import_specifier.is_in_ts_module_declaration()); /// ``` pub fn is_in_ts_module_declaration(&self) -> bool { diff --git a/crates/biome_js_syntax/src/lib.rs b/crates/biome_js_syntax/src/lib.rs index 490b48d3e5d3..fe5db8221d59 100644 --- a/crates/biome_js_syntax/src/lib.rs +++ b/crates/biome_js_syntax/src/lib.rs @@ -66,6 +66,15 @@ impl JsSyntaxKind { && (self as u16) >= (JsSyntaxKind::BREAK_KW as u16) } + /// Returns `true` for any kind representing a Grit metavariable. + #[inline] + pub fn is_metavariable(&self) -> bool { + matches!( + self, + JsSyntaxKind::GRIT_METAVARIABLE | JsSyntaxKind::JS_METAVARIABLE + ) + } + /// Returns `true` for contextual keywords (excluding strict mode contextual keywords) #[inline] pub const fn is_contextual_keyword(self) -> bool { diff --git a/crates/biome_js_syntax/src/parentheses/expression.rs b/crates/biome_js_syntax/src/parentheses/expression.rs index e11a23a32751..633f1f9e172e 100644 --- a/crates/biome_js_syntax/src/parentheses/expression.rs +++ b/crates/biome_js_syntax/src/parentheses/expression.rs @@ -15,7 +15,7 @@ use crate::{ JsCallExpression, JsClassExpression, JsComputedMemberAssignment, JsComputedMemberExpression, JsComputedMemberName, JsConditionalExpression, JsExpressionStatement, JsForStatement, JsFunctionExpression, JsIdentifierExpression, JsImportCallExpression, JsImportMetaExpression, - JsInExpression, JsInstanceofExpression, JsLogicalExpression, JsNewExpression, + JsInExpression, JsInstanceofExpression, JsLogicalExpression, JsMetavariable, JsNewExpression, JsNewTargetExpression, JsNullLiteralExpression, JsNumberLiteralExpression, JsObjectExpression, JsParenthesizedExpression, JsPostUpdateExpression, JsPreUpdateExpression, JsPreUpdateOperator, JsRegexLiteralExpression, JsSequenceExpression, JsStaticMemberExpression, @@ -43,6 +43,7 @@ impl NeedsParentheses for AnyJsExpression { Self::JsComputedMemberExpression(expr) => expr.needs_parentheses(), Self::JsConditionalExpression(expr) => expr.needs_parentheses(), Self::JsFunctionExpression(expr) => expr.needs_parentheses(), + Self::JsMetavariable(expr) => expr.needs_parentheses(), Self::JsIdentifierExpression(expr) => expr.needs_parentheses(), Self::JsImportCallExpression(expr) => expr.needs_parentheses(), Self::JsInExpression(expr) => expr.needs_parentheses(), @@ -325,6 +326,12 @@ impl NeedsParentheses for JsFunctionExpression { } } +impl NeedsParentheses for JsMetavariable { + fn needs_parentheses(&self) -> bool { + false + } +} + impl NeedsParentheses for JsIdentifierExpression { fn needs_parentheses(&self) -> bool { let Some(parent) = self.syntax().parent() else { diff --git a/crates/biome_js_syntax/src/union_ext.rs b/crates/biome_js_syntax/src/union_ext.rs index 61502601c593..e1c14f11d5b5 100644 --- a/crates/biome_js_syntax/src/union_ext.rs +++ b/crates/biome_js_syntax/src/union_ext.rs @@ -106,7 +106,7 @@ impl AnyJsClassMember { AnyJsClassMember::JsPropertyClassMember(property) => property.name().map(Some), AnyJsClassMember::JsSetterClassMember(setter) => setter.name().map(Some), AnyJsClassMember::JsStaticInitializationBlockClassMember(_) => Ok(None), - AnyJsClassMember::JsBogusMember(_) => Ok(None), + AnyJsClassMember::JsBogusMember(_) | AnyJsClassMember::JsMetavariable(_) => Ok(None), AnyJsClassMember::TsConstructorSignatureClassMember(constructor) => constructor .name() .map(|name| Some(AnyJsClassMemberName::from(name))), diff --git a/crates/biome_parser/src/lexer.rs b/crates/biome_parser/src/lexer.rs index 0e7c1c4e1ec8..17b0cff7d783 100644 --- a/crates/biome_parser/src/lexer.rs +++ b/crates/biome_parser/src/lexer.rs @@ -264,6 +264,58 @@ pub trait Lexer<'src> { chr } } + + /// Check if the lexer starts a grit metavariable + fn is_metavariable_start(&mut self) -> bool { + let current_char = self.current_char_unchecked(); + if current_char == 'μ' { + let current_char_length = current_char.len_utf8(); + // μ[a-zA-Z_][a-zA-Z0-9_]* + if matches!( + self.byte_at(current_char_length), + Some(b'a'..=b'z' | b'A'..=b'Z' | b'_') + ) { + return true; + } + + // μ... + if self.byte_at(current_char_length) == Some(b'.') + && self.byte_at(current_char_length + 1) == Some(b'.') + && self.byte_at(current_char_length + 2) == Some(b'.') + { + return true; + } + } + false + } + + /// Consume a grit metavariable(μ[a-zA-Z_][a-zA-Z0-9_]*|μ...) + /// https://github.com/getgrit/gritql/blob/8f3f077d078ccaf0618510bba904a06309c2435e/resources/language-metavariables/tree-sitter-css/grammar.js#L388 + fn consume_metavariable(&mut self, kind: T) -> T { + debug_assert!(self.is_metavariable_start()); + + // SAFETY: We know the current character is μ. + let current_char = self.current_char_unchecked(); + self.advance(current_char.len_utf8()); + + if self.current_byte() == Some(b'.') { + // SAFETY: We know that the current token is μ... + self.advance(3); + } else { + // μ[a-zA-Z_][a-zA-Z0-9_]* + self.advance(1); + while let Some(chr) = self.current_byte() { + match chr { + b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_' => { + self.advance(1); + } + _ => break, + } + } + } + + kind + } } pub trait ReLexer<'src>: Lexer<'src> + LexerWithCheckpoint<'src> { diff --git a/crates/biome_rowan/src/ast/mod.rs b/crates/biome_rowan/src/ast/mod.rs index 133aaf812aef..abff787082ef 100644 --- a/crates/biome_rowan/src/ast/mod.rs +++ b/crates/biome_rowan/src/ast/mod.rs @@ -742,12 +742,16 @@ pub type SyntaxResult = Result; pub enum SyntaxError { /// Error thrown when a mandatory node is not found MissingRequiredChild, + + /// Error thrown when a metavariable node is found in an unexpected context + UnexpectedMetavariable, } impl Display for SyntaxError { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { match self { SyntaxError::MissingRequiredChild => fmt.write_str("missing required child"), + SyntaxError::UnexpectedMetavariable => fmt.write_str("unexpectedd metavariable node"), } } } @@ -820,6 +824,7 @@ pub mod support { match &self.0 { Ok(node) => std::fmt::Debug::fmt(node, f), Err(SyntaxError::MissingRequiredChild) => f.write_str("missing (required)"), + Err(SyntaxError::UnexpectedMetavariable) => f.write_str("metavariable"), } } } diff --git a/crates/biome_service/src/file_handlers/css.rs b/crates/biome_service/src/file_handlers/css.rs index 018e4f401b4c..ff112b9fe339 100644 --- a/crates/biome_service/src/file_handlers/css.rs +++ b/crates/biome_service/src/file_handlers/css.rs @@ -221,7 +221,7 @@ fn parse( css_modules: settings .and_then(|s| s.languages.css.parser.css_modules) .unwrap_or_default(), - grit_metavariable: false, + grit_metavariables: false, }; if let Some(settings) = settings { options = settings diff --git a/crates/biome_service/src/file_handlers/javascript.rs b/crates/biome_service/src/file_handlers/javascript.rs index b7dc321b5cb4..41f254d9f09b 100644 --- a/crates/biome_service/src/file_handlers/javascript.rs +++ b/crates/biome_service/src/file_handlers/javascript.rs @@ -309,6 +309,7 @@ fn parse( cache: &mut NodeCache, ) -> ParseResult { let mut options = JsParserOptions { + grit_metavariables: false, parse_class_parameter_decorators: settings .map(|settings| { settings diff --git a/crates/biome_service/src/workspace_types.rs b/crates/biome_service/src/workspace_types.rs index 3c082c41bc26..6af4bbc7576f 100644 --- a/crates/biome_service/src/workspace_types.rs +++ b/crates/biome_service/src/workspace_types.rs @@ -369,7 +369,7 @@ pub fn generate_type<'a>( let current_module = AnyJsDeclaration::from( make::ts_interface_declaration( make::token(T![interface]), - make::ts_identifier_binding(make::ident(name)), + make::ts_identifier_binding(make::ident(name)).into(), make::token(T!['{']), make::ts_type_member_list(members), make::token(T!['}']), @@ -386,7 +386,7 @@ pub fn generate_type<'a>( let current_module = AnyJsDeclaration::from( make::ts_type_alias_declaration( make::token(T![type]), - make::ts_identifier_binding(make::ident(name)), + make::ts_identifier_binding(make::ident(name)).into(), make::token(T![=]), ts_type, ) diff --git a/xtask/codegen/css.ungram b/xtask/codegen/css.ungram index 800f38570d4e..218380074dde 100644 --- a/xtask/codegen/css.ungram +++ b/xtask/codegen/css.ungram @@ -96,7 +96,7 @@ AnyCssSelector = CssComplexSelector | CssCompoundSelector | CssBogusSelector - | CssGritMetavariable + | CssMetavariable // div a {} // ^^^^^ @@ -442,7 +442,7 @@ AnyCssDeclarationOrRule = AnyCssRule | CssDeclarationWithSemicolon | CssBogus - | CssGritMetavariable + | CssMetavariable // @page :left { background: red; @media (500px <= width <= 500px) { } } // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1011,7 +1011,7 @@ AnyCssMediaQuery = CssMediaConditionQuery | AnyCssMediaTypeQuery | CssBogusMediaQuery - | CssGritMetavariable + | CssMetavariable // @media screen, (width > 500px), print {} // ^^^^^^^^^^^^^^^ @@ -1627,7 +1627,7 @@ AnyCssValue = | CssColor | CssBracketedValue | CssUnicodeRange - | CssGritMetavariable + | CssMetavariable // https://drafts.csswg.org/css-syntax/#typedef-dimension-token @@ -1801,4 +1801,4 @@ CssUnicodeRangeWildcard = value: 'css_unicode_range_wildcard_literal' CssUrlValueRaw = value: 'css_url_value_raw_literal' // https://github.com/getgrit/gritql/blob/main/resources/language-metavariables/tree-sitter-css/grammar.js -CssGritMetavariable = value: 'grit_metavariable' \ No newline at end of file +CssMetavariable = value: 'grit_metavariable' diff --git a/xtask/codegen/js.ungram b/xtask/codegen/js.ungram index 492f66255c87..b8f72a0765e8 100644 --- a/xtask/codegen/js.ungram +++ b/xtask/codegen/js.ungram @@ -114,7 +114,6 @@ AnyJsStatement = | TsGlobalDeclaration | TsImportEqualsDeclaration - JsBlockStatement = '{' statements: JsStatementList @@ -325,6 +324,8 @@ AnyJsExpression = | TsInstantiationExpression // JSX | JsxTagExpression + // Grit + | JsMetavariable JsTemplateExpression = tag: AnyJsExpression? @@ -518,6 +519,7 @@ JsPostUpdateExpression = AnyJsObjectMemberName = JsLiteralMemberName | JsComputedMemberName + | JsMetavariable JsObjectExpression = '{' @@ -630,6 +632,7 @@ AnyJsClassMemberName = JsLiteralMemberName | JsComputedMemberName | JsPrivateClassMemberName + | JsMetavariable AnyJsClassMember = JsConstructorClassMember @@ -647,6 +650,7 @@ AnyJsClassMember = | TsIndexSignatureClassMember | JsEmptyClassMember | JsBogusMember + | JsMetavariable JsStaticModifier = modifier: 'static' JsAccessorModifier = modifier: 'accessor' @@ -1009,6 +1013,7 @@ JsObjectAssignmentPatternRest = AnyJsBinding = JsIdentifierBinding | JsBogusBinding + | JsMetavariable // Binds a value to an identifier. // let x = OR function(test) {} @@ -1058,6 +1063,7 @@ AnyJsObjectBindingPatternMember = JsObjectBindingPatternProperty | JsObjectBindingPatternRest | JsObjectBindingPatternShorthandProperty + | JsMetavariable | JsBogusBinding // let { a: b.m } = {} @@ -1229,7 +1235,7 @@ AnyJsImportClause = // import "abcd" // import "abcd" assert ... JsImportBareClause = - source: JsModuleSource + source: AnyJsModuleSource assertion: JsImportAssertion? // import foo from "mod" @@ -1238,7 +1244,7 @@ JsImportDefaultClause = 'type'? default_specifier: JsDefaultImportSpecifier 'from' - source: JsModuleSource + source: AnyJsModuleSource assertion: JsImportAssertion? // import * as foo from "mod"; @@ -1247,7 +1253,7 @@ JsImportNamespaceClause = 'type'? namespace_specifier: JsNamespaceImportSpecifier 'from' - source: JsModuleSource + source: AnyJsModuleSource assertion: JsImportAssertion? // import { a, b: c } from "d"; @@ -1260,7 +1266,7 @@ JsImportNamedClause = 'type'? named_specifiers: JsNamedImportSpecifiers 'from' - source: JsModuleSource + source: AnyJsModuleSource assertion: JsImportAssertion? // import c, { b } from "c" @@ -1274,7 +1280,7 @@ JsImportCombinedClause = ',' specifier: AnyJsCombinedSpecifier 'from' - source: JsModuleSource + source: AnyJsModuleSource assertion: JsImportAssertion? AnyJsCombinedSpecifier = JsNamedImportSpecifiers | JsNamespaceImportSpecifier @@ -1475,7 +1481,7 @@ JsExportFromClause = '*' export_as: JsExportAsClause? 'from' - source: JsModuleSource + source: AnyJsModuleSource assertion: JsImportAssertion? ';'? @@ -1489,10 +1495,14 @@ JsExportNamedFromClause = specifiers: JsExportNamedFromSpecifierList '}' 'from' - source: JsModuleSource + source: AnyJsModuleSource assertion: JsImportAssertion? ';'? +AnyJsModuleSource = + JsModuleSource + | JsMetavariable + JsExportNamedFromSpecifierList = (JsExportNamedFromSpecifier (',' JsExportNamedFromSpecifier)* ','?) // export { a } from "b"; @@ -1704,6 +1714,7 @@ AnyTsType = | TsConstructorType | TsConditionalType | TsBogusType + | JsMetavariable // Predefined types TsAnyType = 'any' @@ -1730,12 +1741,16 @@ TsReferenceType = TsTypeAliasDeclaration = 'type' - binding_identifier: TsIdentifierBinding + binding_identifier: AnyTsIdentifierBinding type_parameters: TsTypeParameters? '=' ty: AnyTsType ';'? +AnyTsIdentifierBinding = + TsIdentifierBinding + | JsMetavariable + // Binds a type identifier TsIdentifierBinding = name: 'ident' @@ -1775,7 +1790,7 @@ AnyTsModuleReference = TsExternalModuleReference = 'require' '(' - source: JsModuleSource + source: AnyJsModuleSource ')' @@ -1826,7 +1841,7 @@ TsModuleBlock = '}' AnyTsModuleName = - TsIdentifierBinding + AnyTsIdentifierBinding | TsQualifiedModuleName // declare module a.b.c {} @@ -1843,7 +1858,7 @@ TsQualifiedModuleName = // ^^^^^^^^^^^^^^^^^^^^^ TsExternalModuleDeclaration = 'module' - source: JsModuleSource + source: AnyJsModuleSource body: AnyTsExternalModuleDeclarationBody? AnyTsExternalModuleDeclarationBody = @@ -1983,7 +1998,7 @@ TsObjectType = '{' members: TsTypeMemberList '}' TsInterfaceDeclaration = 'interface' - id: TsIdentifierBinding + id: AnyTsIdentifierBinding type_parameters: TsTypeParameters? extends_clause: TsExtendsClause? '{' @@ -2390,3 +2405,6 @@ JsxSpreadChild = JsxText = value: 'jsx_text_literal' JsxString = value: 'jsx_string_literal' + +// https://github.com/getgrit/gritql/blob/main/resources/language-metavariables/tree-sitter-typescript/common/define-grammar.js +JsMetavariable = value: 'grit_metavariable' diff --git a/xtask/codegen/src/css_kinds_src.rs b/xtask/codegen/src/css_kinds_src.rs index 8693d82de21f..4f10f6fd28de 100644 --- a/xtask/codegen/src/css_kinds_src.rs +++ b/xtask/codegen/src/css_kinds_src.rs @@ -507,6 +507,6 @@ pub const CSS_KINDS_SRC: KindsSrc = KindsSrc { "CSS_BOGUS_KEYFRAMES_NAME", "CSS_BOGUS_UNICODE_RANGE_VALUE", // Grit metavariable - "CSS_GRIT_METAVARIABLE", + "CSS_METAVARIABLE", ], }; diff --git a/xtask/codegen/src/generate_bindings.rs b/xtask/codegen/src/generate_bindings.rs index f50d73798acd..950492336884 100644 --- a/xtask/codegen/src/generate_bindings.rs +++ b/xtask/codegen/src/generate_bindings.rs @@ -183,7 +183,7 @@ pub(crate) fn generate_workspace_bindings(mode: Mode) -> Result<()> { make::token(T!['}']), ), make::token(T![from]), - make::js_module_source(make::js_string_literal("./transport")), + make::js_module_source(make::js_string_literal("./transport")).into(), ) .with_type_token(make::token(T![type])) .build(), @@ -316,7 +316,7 @@ pub(crate) fn generate_workspace_bindings(mode: Mode) -> Result<()> { AnyJsExportClause::AnyJsDeclarationClause(AnyJsDeclarationClause::TsTypeAliasDeclaration( make::ts_type_alias_declaration( make::token(T![type]), - make::ts_identifier_binding(make::ident("Configuration")), + make::ts_identifier_binding(make::ident("Configuration")).into(), make::token(T![=]), AnyTsType::TsReferenceType( make::ts_reference_type(AnyTsName::JsReferenceIdentifier( @@ -335,7 +335,7 @@ pub(crate) fn generate_workspace_bindings(mode: Mode) -> Result<()> { AnyJsExportClause::AnyJsDeclarationClause(AnyJsDeclarationClause::TsInterfaceDeclaration( make::ts_interface_declaration( make::token(T![interface]), - make::ts_identifier_binding(make::ident("Workspace")), + make::ts_identifier_binding(make::ident("Workspace")).into(), make::token(T!['{']), make::ts_type_member_list(member_definitions), make::token(T!['}']), diff --git a/xtask/codegen/src/js_kinds_src.rs b/xtask/codegen/src/js_kinds_src.rs index 726a3d0aaed0..90568ccb86ee 100644 --- a/xtask/codegen/src/js_kinds_src.rs +++ b/xtask/codegen/src/js_kinds_src.rs @@ -178,6 +178,7 @@ pub const JS_KINDS_SRC: KindsSrc = KindsSrc { "COMMENT", "MULTILINE_COMMENT", "JS_SHEBANG", + "GRIT_METAVARIABLE", ], nodes: &[ "JS_MODULE", @@ -510,7 +511,7 @@ pub const JS_KINDS_SRC: KindsSrc = KindsSrc { "JSX_SPREAD_CHILD", "JSX_STRING", // Grit metavariable - "JS_GRIT_METAVARIABLE", + "JS_METAVARIABLE", // bogus nodes JS "JS_BOGUS", "JS_BOGUS_EXPRESSION",