From 638c2508524afa8f30416c82cd59c6b6dd953e27 Mon Sep 17 00:00:00 2001 From: "Arend van Beelen jr." Date: Thu, 19 Sep 2024 10:33:24 +0200 Subject: [PATCH] feat(grit): support for Grit pattern, predicate and function definitions (#3983) --- crates/biome_grit_patterns/src/errors.rs | 18 ++ .../biome_grit_patterns/src/grit_context.rs | 21 ++- .../src/grit_definitions.rs | 167 ++++++++++++++++++ crates/biome_grit_patterns/src/grit_query.rs | 35 +++- crates/biome_grit_patterns/src/lib.rs | 1 + .../src/pattern_compiler.rs | 7 + .../src/pattern_compiler/and_compiler.rs | 22 ++- .../src/pattern_compiler/call_compiler.rs | 6 +- .../pattern_compiler/compilation_context.rs | 5 +- .../function_definition_compiler.rs | 43 +++++ .../pattern_definition_compiler.rs | 44 +++++ .../predicate_definition_compiler.rs | 44 +++++ .../tests/specs/ts/patternDefinition.grit | 4 + .../tests/specs/ts/patternDefinition.snap | 12 ++ .../tests/specs/ts/patternDefinition.ts | 2 + 15 files changed, 406 insertions(+), 25 deletions(-) create mode 100644 crates/biome_grit_patterns/src/grit_definitions.rs create mode 100644 crates/biome_grit_patterns/src/pattern_compiler/function_definition_compiler.rs create mode 100644 crates/biome_grit_patterns/src/pattern_compiler/pattern_definition_compiler.rs create mode 100644 crates/biome_grit_patterns/src/pattern_compiler/predicate_definition_compiler.rs create mode 100644 crates/biome_grit_patterns/tests/specs/ts/patternDefinition.grit create mode 100644 crates/biome_grit_patterns/tests/specs/ts/patternDefinition.snap create mode 100644 crates/biome_grit_patterns/tests/specs/ts/patternDefinition.ts diff --git a/crates/biome_grit_patterns/src/errors.rs b/crates/biome_grit_patterns/src/errors.rs index 22cf152ce4b0..501152a7d52e 100644 --- a/crates/biome_grit_patterns/src/errors.rs +++ b/crates/biome_grit_patterns/src/errors.rs @@ -18,9 +18,18 @@ pub enum CompileError { /// A metavariables was discovered in an unexpected context. UnexpectedMetavariable, + /// If a function with the same name is defined multiple times. + DuplicateFunctionDefinition(String), + /// If a function or bubble pattern has multiple parameters with the same name. DuplicateParameters, + /// If a function with the same name is defined multiple times. + DuplicatePatternDefinition(String), + + /// If a function with the same name is defined multiple times. + DuplicatePredicateDefinition(String), + /// A metavariable was expected at the given range. InvalidMetavariableRange(ByteRange), @@ -89,9 +98,18 @@ impl Diagnostic for CompileError { CompileError::UnexpectedMetavariable => { fmt.write_markup(markup! { "Unexpected metavariable" }) } + CompileError::DuplicateFunctionDefinition(name) => { + fmt.write_markup(markup! { "Duplicate function definition: "{{name}} }) + } CompileError::DuplicateParameters => { fmt.write_markup(markup! { "Duplicate parameters" }) } + CompileError::DuplicatePatternDefinition(name) => { + fmt.write_markup(markup! { "Duplicate pattern definition: "{{name}} }) + } + CompileError::DuplicatePredicateDefinition(name) => { + fmt.write_markup(markup! { "Duplicate predicate definition: "{{name}} }) + } CompileError::InvalidMetavariableRange(_) => { fmt.write_markup(markup! { "Invalid range for metavariable" }) } diff --git a/crates/biome_grit_patterns/src/grit_context.rs b/crates/biome_grit_patterns/src/grit_context.rs index 846593fefcc1..33883b7fed4c 100644 --- a/crates/biome_grit_patterns/src/grit_context.rs +++ b/crates/biome_grit_patterns/src/grit_context.rs @@ -45,9 +45,9 @@ pub struct GritExecContext<'a> { loadable_files: &'a [GritTargetFile], files: &'a FileOwners, - functions: Vec>, - patterns: Vec>, - predicates: Vec>, + functions: &'a [GritFunctionDefinition], + patterns: &'a [PatternDefinition], + predicates: &'a [PredicateDefinition], } impl<'a> GritExecContext<'a> { @@ -56,30 +56,33 @@ impl<'a> GritExecContext<'a> { name: Option<&'a str>, loadable_files: &'a [GritTargetFile], files: &'a FileOwners, + functions: &'a [GritFunctionDefinition], + patterns: &'a [PatternDefinition], + predicates: &'a [PredicateDefinition], ) -> Self { Self { lang, name, loadable_files, files, - functions: Vec::new(), - patterns: Vec::new(), - predicates: Vec::new(), + functions, + patterns, + predicates, } } } impl<'a> ExecContext<'a, GritQueryContext> for GritExecContext<'a> { fn pattern_definitions(&self) -> &[PatternDefinition] { - &self.patterns + self.patterns } fn predicate_definitions(&self) -> &[PredicateDefinition] { - &self.predicates + self.predicates } fn function_definitions(&self) -> &[GritFunctionDefinition] { - &self.functions + self.functions } fn ignore_limit_pattern(&self) -> bool { diff --git a/crates/biome_grit_patterns/src/grit_definitions.rs b/crates/biome_grit_patterns/src/grit_definitions.rs new file mode 100644 index 000000000000..4a2f0df3d5ea --- /dev/null +++ b/crates/biome_grit_patterns/src/grit_definitions.rs @@ -0,0 +1,167 @@ +use std::collections::BTreeMap; + +use crate::{ + grit_context::GritQueryContext, + pattern_compiler::{ + compilation_context::{DefinitionInfo, NodeCompilationContext}, + FunctionDefinitionCompiler, PatternDefinitionCompiler, PredicateDefinitionCompiler, + }, + util::TextRangeGritExt, + CompileError, +}; +use biome_grit_syntax::{AnyGritDefinition, GritDefinitionList, GritVariableList}; +use biome_rowan::AstNode; +use grit_pattern_matcher::pattern::{ + GritFunctionDefinition, PatternDefinition, PredicateDefinition, +}; +use grit_util::ByteRange; + +#[derive(Clone, Debug)] +pub struct Definitions { + pub patterns: Vec>, + pub predicates: Vec>, + pub functions: Vec>, +} + +/// Compiles all definitions. +/// +/// Must be called after [scan_definitions()]. +pub fn compile_definitions( + definitions: GritDefinitionList, + context: &mut NodeCompilationContext, +) -> Result { + let mut patterns = Vec::new(); + let mut predicates = Vec::new(); + let mut functions = Vec::new(); + for definition in definitions { + match definition? { + AnyGritDefinition::AnyGritPattern(_) => continue, // Handled separately. + AnyGritDefinition::GritPatternDefinition(node) => { + patterns.push(PatternDefinitionCompiler::from_node(node, context)?); + } + AnyGritDefinition::GritPredicateDefinition(node) => { + predicates.push(PredicateDefinitionCompiler::from_node(node, context)?); + } + AnyGritDefinition::GritFunctionDefinition(node) => { + functions.push(FunctionDefinitionCompiler::from_node(node, context)?); + } + AnyGritDefinition::GritBogusDefinition(_) => { + unreachable!(); // Should be handled in `scan_definitions()`. + } + } + } + + Ok(Definitions { + patterns, + predicates, + functions, + }) +} + +pub struct ScannedDefinitionInfo { + pub pattern_definition_info: BTreeMap, + pub predicate_definition_info: BTreeMap, + pub function_definition_info: BTreeMap, +} + +/// Finds all definitions so that we can allocate their scopes in preparation +/// for the compilation phase. +pub fn scan_definitions( + definitions: GritDefinitionList, +) -> Result { + let mut pattern_definition_info = BTreeMap::new(); + let mut pattern_index = 0; + + let mut predicate_definition_info = BTreeMap::new(); + let mut predicate_index = 0; + + let mut function_definition_info = BTreeMap::new(); + let mut function_index = 0; + + for definition in definitions { + match definition? { + AnyGritDefinition::AnyGritPattern(_) => continue, // Handled separately. + AnyGritDefinition::GritPatternDefinition(node) => { + let name = node.name()?.text(); + let name = name.trim(); + if pattern_definition_info.contains_key(name) { + return Err(CompileError::DuplicatePatternDefinition(name.to_owned())); + } + + pattern_definition_info.insert( + name.to_owned(), + DefinitionInfo { + index: pattern_index, + parameters: collect_variables(node.args()?.grit_variable_list())?, + }, + ); + + pattern_index += 1; + } + AnyGritDefinition::GritPredicateDefinition(node) => { + let name = node.name()?.text(); + let name = name.trim(); + if predicate_definition_info.contains_key(name) { + return Err(CompileError::DuplicatePredicateDefinition(name.to_owned())); + } + + predicate_definition_info.insert( + name.to_owned(), + DefinitionInfo { + index: predicate_index, + parameters: collect_variables(node.args()?.grit_variable_list())?, + }, + ); + + predicate_index += 1; + } + AnyGritDefinition::GritFunctionDefinition(node) => { + let name = node.name()?.text(); + let name = name.trim(); + if function_definition_info.contains_key(name) { + return Err(CompileError::DuplicateFunctionDefinition(name.to_owned())); + } + + function_definition_info.insert( + name.to_owned(), + DefinitionInfo { + index: function_index, + parameters: collect_variables(node.args())?, + }, + ); + + function_index += 1; + } + AnyGritDefinition::GritBogusDefinition(bogus) => { + return Err(CompileError::UnexpectedKind( + bogus + .items() + .next() + .map(|item| item.kind().into()) + .unwrap_or_default(), + )); + } + } + } + + Ok(ScannedDefinitionInfo { + pattern_definition_info, + predicate_definition_info, + function_definition_info, + }) +} + +fn collect_variables( + variables: GritVariableList, +) -> Result, CompileError> { + variables + .into_iter() + .map(|var| { + let token = var?.value_token()?; + Ok(( + token.text_trimmed().to_string(), + token.text_trimmed_range().to_byte_range(), + )) + }) + .collect() +} diff --git a/crates/biome_grit_patterns/src/grit_query.rs b/crates/biome_grit_patterns/src/grit_query.rs index aba58ae58e87..11edc833bfdf 100644 --- a/crates/biome_grit_patterns/src/grit_query.rs +++ b/crates/biome_grit_patterns/src/grit_query.rs @@ -1,5 +1,8 @@ use crate::diagnostics::CompilerDiagnostic; use crate::grit_context::{GritExecContext, GritQueryContext, GritTargetFile}; +use crate::grit_definitions::{ + compile_definitions, scan_definitions, Definitions, ScannedDefinitionInfo, +}; use crate::grit_resolved_pattern::GritResolvedPattern; use crate::grit_target_language::GritTargetLanguage; use crate::grit_tree::GritTargetTree; @@ -40,6 +43,9 @@ const GLOBAL_VARS: [(&str, usize); 4] = [ pub struct GritQuery { pub pattern: Pattern, + /// Definitions for named patterns, predicates and functions. + pub definitions: Definitions, + /// Diagnostics discovered during compilation of the query. pub diagnostics: Vec, @@ -63,6 +69,9 @@ impl GritQuery { self.name.as_deref(), &files, &file_owners, + &self.definitions.functions, + &self.definitions.patterns, + &self.definitions.predicates, ); let var_registry = VarRegistry::from_locations(&self.variable_locations); @@ -91,16 +100,28 @@ impl GritQuery { pub fn from_node( root: GritRoot, - path: Option<&Path>, + source_path: Option<&Path>, lang: GritTargetLanguage, ) -> Result { - let context = CompilationContext::new(path, lang); + let ScannedDefinitionInfo { + pattern_definition_info, + predicate_definition_info, + function_definition_info, + } = scan_definitions(root.definitions())?; + + let context = CompilationContext { + source_path, + lang, + pattern_definition_info, + predicate_definition_info, + function_definition_info, + }; let mut vars_array = vec![GLOBAL_VARS .iter() .map(|global_var| VariableSourceLocations { name: global_var.0.to_string(), - file: path + file: source_path .map(Path::to_string_lossy) .map_or_else(|| "unnamed".to_owned(), |p| p.to_string()), locations: BTreeSet::new(), @@ -124,22 +145,23 @@ impl GritQuery { &mut diagnostics, ); + let mut definitions = compile_definitions(root.definitions(), &mut node_context)?; + let pattern = PatternCompiler::from_node( &root.pattern().ok_or(CompileError::MissingPattern)?, &mut node_context, )?; - let mut pattern_definitions = Vec::new(); let pattern = auto_wrap_pattern( pattern, - &mut pattern_definitions, + &mut definitions.patterns, true, None, &mut node_context, None, )?; - let name = path + let name = source_path .and_then(Path::file_stem) .map(OsStr::to_string_lossy) .map(|stem| stem.into_owned()); @@ -148,6 +170,7 @@ impl GritQuery { Ok(Self { pattern, + definitions, name, language, diagnostics, diff --git a/crates/biome_grit_patterns/src/lib.rs b/crates/biome_grit_patterns/src/lib.rs index b4b5be804ddc..f2ad2ea075b2 100644 --- a/crates/biome_grit_patterns/src/lib.rs +++ b/crates/biome_grit_patterns/src/lib.rs @@ -4,6 +4,7 @@ mod grit_analysis_ext; mod grit_binding; mod grit_code_snippet; mod grit_context; +mod grit_definitions; mod grit_file; mod grit_js_parser; mod grit_node; diff --git a/crates/biome_grit_patterns/src/pattern_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler.rs index a3453bce61d6..0c36aae3a2b0 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler.rs @@ -37,6 +37,7 @@ mod contains_compiler; mod divide_compiler; mod equal_compiler; mod every_compiler; +mod function_definition_compiler; mod if_compiler; mod includes_compiler; mod like_compiler; @@ -53,8 +54,10 @@ mod multiply_compiler; mod node_like_compiler; mod not_compiler; mod or_compiler; +mod pattern_definition_compiler; mod predicate_call_compiler; mod predicate_compiler; +mod predicate_definition_compiler; mod predicate_return_compiler; mod regex_compiler; mod rewrite_compiler; @@ -67,6 +70,10 @@ mod variable_compiler; mod where_compiler; mod within_compiler; +pub use function_definition_compiler::FunctionDefinitionCompiler; +pub use pattern_definition_compiler::PatternDefinitionCompiler; +pub use predicate_definition_compiler::PredicateDefinitionCompiler; + use self::{ accumulate_compiler::AccumulateCompiler, add_compiler::AddCompiler, after_compiler::AfterCompiler, and_compiler::AndCompiler, any_compiler::AnyCompiler, diff --git a/crates/biome_grit_patterns/src/pattern_compiler/and_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/and_compiler.rs index a13137b05299..f322c77fea8c 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/and_compiler.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/and_compiler.rs @@ -3,7 +3,7 @@ use super::{ PatternCompiler, }; use crate::{grit_context::GritQueryContext, CompileError}; -use biome_grit_syntax::{GritPatternAnd, GritPredicateAnd}; +use biome_grit_syntax::{GritPatternAnd, GritPatternList, GritPredicateAnd, GritPredicateList}; use grit_pattern_matcher::pattern::{And, PrAnd}; pub(crate) struct AndCompiler; @@ -13,8 +13,14 @@ impl AndCompiler { node: &GritPatternAnd, context: &mut NodeCompilationContext, ) -> Result, CompileError> { - let patterns = node - .patterns() + Self::from_patterns(node.patterns(), context) + } + + pub(crate) fn from_patterns( + patterns: GritPatternList, + context: &mut NodeCompilationContext, + ) -> Result, CompileError> { + let patterns = patterns .into_iter() .map(|pattern| match pattern { Ok(pattern) => Ok(PatternCompiler::from_node(&pattern, context)?), @@ -33,8 +39,14 @@ impl PrAndCompiler { node: &GritPredicateAnd, context: &mut NodeCompilationContext, ) -> Result, CompileError> { - let predicates = node - .predicates() + Self::from_predicates(node.predicates(), context) + } + + pub(crate) fn from_predicates( + predicates: GritPredicateList, + context: &mut NodeCompilationContext, + ) -> Result, CompileError> { + let predicates = predicates .into_iter() .map(|predicate| match predicate { Ok(predicate) => Ok(PredicateCompiler::from_node(&predicate, context)?), diff --git a/crates/biome_grit_patterns/src/pattern_compiler/call_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/call_compiler.rs index 26251140aa40..6dc7bdd6caa2 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/call_compiler.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/call_compiler.rs @@ -3,9 +3,9 @@ use crate::{grit_context::GritQueryContext, CompileError, NodeLikeArgumentError} use biome_grit_syntax::{ AnyGritMaybeNamedArg, AnyGritPattern, GritNamedArgList, GritNodeLike, GritSyntaxKind, }; -use biome_rowan::{AstNode, TextRange}; +use biome_rowan::AstNode; use grit_pattern_matcher::pattern::{Call, CallFunction, FilePattern, Pattern}; -use grit_util::Language; +use grit_util::{ByteRange, Language}; use std::collections::BTreeMap; const VALID_FILE_ARGS: &[&str] = &["$name", "$body"]; @@ -58,7 +58,7 @@ pub(super) fn call_pattern_from_node_with_name( } } -pub(super) fn collect_params(parameters: &[(String, TextRange)]) -> Vec { +pub(super) fn collect_params(parameters: &[(String, ByteRange)]) -> Vec { parameters.iter().map(|p| p.0.clone()).collect() } diff --git a/crates/biome_grit_patterns/src/pattern_compiler/compilation_context.rs b/crates/biome_grit_patterns/src/pattern_compiler/compilation_context.rs index f9fe1e8fa16b..f0c9d112bc23 100644 --- a/crates/biome_grit_patterns/src/pattern_compiler/compilation_context.rs +++ b/crates/biome_grit_patterns/src/pattern_compiler/compilation_context.rs @@ -1,5 +1,5 @@ -use biome_rowan::TextRange; use grit_pattern_matcher::pattern::VariableSourceLocations; +use grit_util::ByteRange; use crate::{diagnostics::CompilerDiagnostic, grit_target_language::GritTargetLanguage}; use std::{collections::BTreeMap, path::Path}; @@ -17,6 +17,7 @@ pub(crate) struct CompilationContext<'a> { } impl<'a> CompilationContext<'a> { + #[cfg(test)] pub(crate) fn new(source_path: Option<&'a Path>, lang: GritTargetLanguage) -> Self { Self { source_path, @@ -80,5 +81,5 @@ impl<'a> NodeCompilationContext<'a> { pub(crate) struct DefinitionInfo { pub(crate) index: usize, - pub(crate) parameters: Vec<(String, TextRange)>, + pub(crate) parameters: Vec<(String, ByteRange)>, } diff --git a/crates/biome_grit_patterns/src/pattern_compiler/function_definition_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/function_definition_compiler.rs new file mode 100644 index 000000000000..9f41bfe926b0 --- /dev/null +++ b/crates/biome_grit_patterns/src/pattern_compiler/function_definition_compiler.rs @@ -0,0 +1,43 @@ +use super::{and_compiler::PrAndCompiler, compilation_context::NodeCompilationContext}; +use crate::{grit_context::GritQueryContext, CompileError}; +use biome_rowan::AstNode; +use grit_pattern_matcher::pattern::{GritFunctionDefinition, Predicate}; +use std::collections::BTreeMap; + +pub struct FunctionDefinitionCompiler; + +impl FunctionDefinitionCompiler { + pub fn from_node( + node: biome_grit_syntax::GritFunctionDefinition, + context: &mut NodeCompilationContext, + ) -> Result, CompileError> { + let name = node.name()?.text(); + let name = name.trim(); + let mut local_vars = BTreeMap::new(); + let (scope_index, mut context) = create_scope!(context, local_vars); + // important that this occurs first, as calls assume + // that parameters are registered first + let params = context.get_variables( + &context + .compilation + .function_definition_info + .get(name) + .ok_or_else(|| CompileError::UnknownFunctionOrPredicate(name.to_owned()))? + .parameters, + ); + + let body = Predicate::And(Box::new(PrAndCompiler::from_predicates( + node.body()?.predicates(), + &mut context, + )?)); + + let pattern_def = GritFunctionDefinition::new( + name.to_owned(), + scope_index, + params, + local_vars.values().copied().collect(), + body, + ); + Ok(pattern_def) + } +} diff --git a/crates/biome_grit_patterns/src/pattern_compiler/pattern_definition_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/pattern_definition_compiler.rs new file mode 100644 index 000000000000..dba96d0d8384 --- /dev/null +++ b/crates/biome_grit_patterns/src/pattern_compiler/pattern_definition_compiler.rs @@ -0,0 +1,44 @@ +use super::{and_compiler::AndCompiler, compilation_context::NodeCompilationContext}; +use crate::{grit_context::GritQueryContext, CompileError}; +use biome_grit_syntax::GritPatternDefinition; +use biome_rowan::AstNode; +use grit_pattern_matcher::pattern::{Pattern, PatternDefinition}; +use std::collections::BTreeMap; + +pub struct PatternDefinitionCompiler; + +impl PatternDefinitionCompiler { + pub fn from_node( + node: GritPatternDefinition, + context: &mut NodeCompilationContext, + ) -> Result, CompileError> { + let name = node.name()?.text(); + let name = name.trim(); + let mut local_vars = BTreeMap::new(); + let (scope_index, mut context) = create_scope!(context, local_vars); + // important that this occurs first, as calls assume + // that parameters are registered first + let params = context.get_variables( + &context + .compilation + .pattern_definition_info + .get(name) + .ok_or_else(|| CompileError::UnknownFunctionOrPattern(name.to_owned()))? + .parameters, + ); + + let body = Pattern::And(Box::new(AndCompiler::from_patterns( + node.body()?.patterns(), + &mut context, + )?)); + + let pattern_def = PatternDefinition::new( + name.to_owned(), + scope_index, + params, + local_vars.values().copied().collect(), + body, + ); + Ok(pattern_def) + } +} diff --git a/crates/biome_grit_patterns/src/pattern_compiler/predicate_definition_compiler.rs b/crates/biome_grit_patterns/src/pattern_compiler/predicate_definition_compiler.rs new file mode 100644 index 000000000000..38d493239e52 --- /dev/null +++ b/crates/biome_grit_patterns/src/pattern_compiler/predicate_definition_compiler.rs @@ -0,0 +1,44 @@ +use super::{and_compiler::PrAndCompiler, compilation_context::NodeCompilationContext}; +use crate::{grit_context::GritQueryContext, CompileError}; +use biome_grit_syntax::GritPredicateDefinition; +use biome_rowan::AstNode; +use grit_pattern_matcher::pattern::{Predicate, PredicateDefinition}; +use std::collections::BTreeMap; + +pub struct PredicateDefinitionCompiler; + +impl PredicateDefinitionCompiler { + pub fn from_node( + node: GritPredicateDefinition, + context: &mut NodeCompilationContext, + ) -> Result, CompileError> { + let name = node.name()?.text(); + let name = name.trim(); + let mut local_vars = BTreeMap::new(); + let (scope_index, mut context) = create_scope!(context, local_vars); + // important that this occurs first, as calls assume + // that parameters are registered first + let params = context.get_variables( + &context + .compilation + .predicate_definition_info + .get(name) + .ok_or_else(|| CompileError::UnknownFunctionOrPredicate(name.to_owned()))? + .parameters, + ); + + let body = Predicate::And(Box::new(PrAndCompiler::from_predicates( + node.body()?.predicates(), + &mut context, + )?)); + + let pattern_def = PredicateDefinition::new( + name.to_owned(), + scope_index, + params, + local_vars.values().copied().collect(), + body, + ); + Ok(pattern_def) + } +} diff --git a/crates/biome_grit_patterns/tests/specs/ts/patternDefinition.grit b/crates/biome_grit_patterns/tests/specs/ts/patternDefinition.grit new file mode 100644 index 000000000000..e03ea4371151 --- /dev/null +++ b/crates/biome_grit_patterns/tests/specs/ts/patternDefinition.grit @@ -0,0 +1,4 @@ +pattern console_method_to_info($method) { + `console.$method($message)` => `console.info($message)` +} +console_method_to_info(method = `log`) diff --git a/crates/biome_grit_patterns/tests/specs/ts/patternDefinition.snap b/crates/biome_grit_patterns/tests/specs/ts/patternDefinition.snap new file mode 100644 index 000000000000..36ecd4420476 --- /dev/null +++ b/crates/biome_grit_patterns/tests/specs/ts/patternDefinition.snap @@ -0,0 +1,12 @@ +--- +source: crates/biome_grit_patterns/tests/spec_tests.rs +expression: patternDefinition +--- +SnapshotResult { + messages: [], + matched_ranges: [ + "1:1-1:29", + ], + rewritten_files: [], + created_files: [], +} diff --git a/crates/biome_grit_patterns/tests/specs/ts/patternDefinition.ts b/crates/biome_grit_patterns/tests/specs/ts/patternDefinition.ts new file mode 100644 index 000000000000..69a609227acc --- /dev/null +++ b/crates/biome_grit_patterns/tests/specs/ts/patternDefinition.ts @@ -0,0 +1,2 @@ +console.log('Hello, world!'); +console.warn('Can you hear me?');