Skip to content

Commit

Permalink
feat(js_parser): support metavariables
Browse files Browse the repository at this point in the history
  • Loading branch information
arendjr committed Jul 30, 2024
1 parent 6be2bdd commit d85b4c1
Show file tree
Hide file tree
Showing 67 changed files with 1,382 additions and 213 deletions.
54 changes: 1 addition & 53 deletions crates/biome_css_parser/src/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ impl<'src> CssLexer<'src> {
UNI if self.options.is_grit_metavariable_enabled()
&& self.is_grit_metavariable_start() =>
{
self.consume_grit_metavariable()
self.consume_grit_metavariable(GRIT_METAVARIABLE)
}
IDT | UNI | BSL if self.is_ident_start() => self.consume_identifier(),

Expand Down Expand Up @@ -1320,58 +1320,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> {
Expand Down
6 changes: 3 additions & 3 deletions crates/biome_css_parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -50,7 +50,7 @@ impl CssParserOptions {

/// Enables parsing of Grit metavariables.
pub fn allow_grit_metavariables(mut self) -> Self {
self.grit_metavariable = true;
self.grit_metavariables = true;
self
}

Expand All @@ -61,7 +61,7 @@ impl CssParserOptions {

/// Checks if parsing of Grit metavariables is enabled.
pub fn is_grit_metavariable_enabled(&self) -> bool {
self.grit_metavariable
self.grit_metavariables
}
}

Expand Down
4 changes: 3 additions & 1 deletion crates/biome_formatter/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ impl From<SyntaxError> 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
}
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions crates/biome_grit_patterns/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand Down Expand Up @@ -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" })
}
Expand Down Expand Up @@ -151,6 +157,7 @@ impl From<SyntaxError> for CompileError {
fn from(error: SyntaxError) -> Self {
match error {
SyntaxError::MissingRequiredChild => Self::MissingSyntaxNode,
SyntaxError::UnexpectedMetavariable => Self::UnexpectedMetavariable,
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,9 @@ impl Rule for NoStaticOnlyClass {
.members()
.iter()
.filter_map(|member| match member {
AnyJsClassMember::JsBogusMember(_) => None,
AnyJsClassMember::JsEmptyClassMember(_) => None,
AnyJsClassMember::JsBogusMember(_)
| AnyJsClassMember::JsGritMetavariable(_)
| 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()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ fn is_valid_constructor(expression: AnyJsExpression) -> Option<bool> {
| AnyJsExpression::JsArrowFunctionExpression(_)
| AnyJsExpression::JsBinaryExpression(_)
| AnyJsExpression::JsBogusExpression(_)
| AnyJsExpression::JsGritMetavariable(_)
| AnyJsExpression::JsInstanceofExpression(_)
| AnyJsExpression::JsObjectExpression(_)
| AnyJsExpression::JsPostUpdateExpression(_)
Expand Down
4 changes: 2 additions & 2 deletions crates/biome_js_analyze/src/lint/style/use_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::JsGritMetavariable(_) => false,
}
})
}
Expand Down Expand Up @@ -344,7 +344,7 @@ fn with_binding_identifier(
) -> bool {
match binding {
AnyJsBinding::JsIdentifierBinding(id) => f(id),
AnyJsBinding::JsBogusBinding(_) => false,
AnyJsBinding::JsBogusBinding(_) | AnyJsBinding::JsGritMetavariable(_) => false,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,7 @@ impl Selector {
scope,
} = match member {
AnyJsClassMember::JsBogusMember(_)
| AnyJsClassMember::JsGritMetavariable(_)
| AnyJsClassMember::JsConstructorClassMember(_)
| AnyJsClassMember::TsConstructorSignatureClassMember(_)
| AnyJsClassMember::JsEmptyClassMember(_)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ fn traverse_binding(
return Some(id_binding);
}
}
AnyJsBinding::JsBogusBinding(_) => {}
AnyJsBinding::JsBogusBinding(_) | AnyJsBinding::JsGritMetavariable(_) => {}
},
AnyJsBindingPattern::JsArrayBindingPattern(inner_binding) => {
return inner_binding.elements().into_iter().find_map(|element| {
Expand Down Expand Up @@ -150,7 +150,8 @@ fn traverse_binding(
AnyJsBinding::JsIdentifierBinding(binding) => {
track_binding(&binding, tracked_bindings).then_some(binding)
}
AnyJsBinding::JsBogusBinding(_) => None,
AnyJsBinding::JsBogusBinding(_)
| AnyJsBinding::JsGritMetavariable(_) => None,
}
}
AnyJsObjectBindingPatternMember::JsObjectBindingPatternShorthandProperty(
Expand All @@ -159,9 +160,12 @@ fn traverse_binding(
AnyJsBinding::JsIdentifierBinding(id_binding) => {
track_binding(&id_binding, tracked_bindings).then_some(id_binding)
}
AnyJsBinding::JsBogusBinding(_) => None,
AnyJsBinding::JsBogusBinding(_) | AnyJsBinding::JsGritMetavariable(_) => {
None
}
},
AnyJsObjectBindingPatternMember::JsBogusBinding(_) => None,
AnyJsObjectBindingPatternMember::JsBogusBinding(_)
| AnyJsObjectBindingPatternMember::JsGritMetavariable(_) => None,
}
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<RuleState> {
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ fn process_js_method_object_member(node: &JsMethodObjectMember) -> Option<RuleSt
});
}
}
_ => return None,
}
None
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)) =
Expand Down
Loading

0 comments on commit d85b4c1

Please sign in to comment.