Skip to content

Commit

Permalink
feat(grit): implement variable matching (#3575)
Browse files Browse the repository at this point in the history
  • Loading branch information
arendjr committed Aug 2, 2024
1 parent 221a74f commit bd1d0c6
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 43 deletions.
12 changes: 10 additions & 2 deletions crates/biome_grit_patterns/src/grit_js_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ impl Parser for GritJsParser {
logs: &mut AnalysisLogs,
_old_tree: FileOrigin<'_, GritTargetTree>,
) -> Option<GritTargetTree> {
let parse_result = parse(body, JsFileSource::tsx(), JsParserOptions::default());
let parse_result = parse(
body,
JsFileSource::tsx(),
JsParserOptions::default().with_metavariables(),
);

for diagnostic in parse_result.diagnostics() {
logs.push(diagnostic.to_log(path));
Expand All @@ -58,7 +62,11 @@ impl Parser for GritJsParser {
|src: &str| src.len() as u32
};

let parse_result = parse(&context, JsFileSource::tsx(), JsParserOptions::default());
let parse_result = parse(
&context,
JsFileSource::tsx(),
JsParserOptions::default().with_metavariables(),
);

SnippetTree {
tree: GritTargetTree::new(parse_result.syntax().into()),
Expand Down
110 changes: 69 additions & 41 deletions crates/biome_grit_patterns/src/pattern_compiler/snippet_compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,19 +207,18 @@ fn pattern_from_node(
range_map: &BTreeMap<ByteRange, ByteRange>,
context: &mut NodeCompilationContext,
is_rhs: bool,
) -> anyhow::Result<Pattern<GritQueryContext>, CompileError> {
) -> Result<Pattern<GritQueryContext>, CompileError> {
let metavariable = metavariable_descendent(node, context_range, range_map, context, is_rhs)?;
if let Some(metavariable) = metavariable {
return Ok(metavariable);
}

if !node.has_children() {
if node.slots().is_none() {
let content = node.text();
let lang = &context.compilation.lang;
let pattern = if let Some(regex_pattern) = lang
.matches_replaced_metavariable(content)
.then(|| implicit_metavariable_regex(node, context_range, range_map, context))
.transpose()?
.flatten()
{
Pattern::Regex(Box::new(regex_pattern))
Expand Down Expand Up @@ -292,7 +291,7 @@ fn implicit_metavariable_regex(
context_range: ByteRange,
range_map: &BTreeMap<ByteRange, ByteRange>,
context: &mut NodeCompilationContext,
) -> Result<Option<RegexPattern<GritQueryContext>>, CompileError> {
) -> Option<RegexPattern<GritQueryContext>> {
let source = node.text();
let capture_string = "(.*)";
let uncapture_string = ".*";
Expand All @@ -305,9 +304,9 @@ fn implicit_metavariable_regex(
let range = ByteRange::new(m.start(), m.end());
last = range.end;
let name = m.as_str();
let variable = text_to_var(name, range, context_range, range_map, context)?;
let variable = text_to_var(name, range, context_range, range_map, context).ok()?;
match variable {
SnippetValues::Dots => return Ok(None),
SnippetValues::Dots => return None,
SnippetValues::Underscore => regex_string.push_str(uncapture_string),
SnippetValues::Variable(var) => {
regex_string.push_str(capture_string);
Expand All @@ -321,7 +320,7 @@ fn implicit_metavariable_regex(
}
let regex = regex_string.to_string();
let regex = RegexLike::Regex(regex);
Ok(Some(RegexPattern::new(regex, variables)))
Some(RegexPattern::new(regex, variables))
}

fn metavariable_descendent(
Expand All @@ -347,27 +346,20 @@ fn metavariable_descendent(
text_to_var(name, range, context_range, range_map, context).map(|s| Some(s.into()))
}

// assumes that metavariable substitute is 1 byte larger than the original. eg.
// len(µ) = 2 bytes, len($) = 1 byte
fn metavariable_range_mapping(
node: &GritTargetNode,
lang: &GritTargetLanguage,
) -> BTreeMap<ByteRange, ByteRange> {
let mut ranges = metavariable_ranges(node, lang);
let snippet_start = node.text().chars().next().unwrap_or_default() as usize;
let snippet_start = node.start_byte() as usize;

// assumes metavariable ranges do not enclose one another
ranges.sort_by_key(|r| r.start);

let mut byte_offset = snippet_start;
let mut map = BTreeMap::new();
for range in ranges {
let start_byte = range.start - byte_offset;
if !cfg!(target_arch = "wasm32") {
byte_offset += 1;
}

let end_byte = range.end - byte_offset;
let start_byte = range.start - snippet_start;
let end_byte = range.end - snippet_start;
let new_range = ByteRange::new(start_byte, end_byte);
map.insert(range, new_range);
}
Expand Down Expand Up @@ -620,13 +612,25 @@ mod tests {
args: [
GritNodePatternArg {
slot_index: 0,
pattern: AstLeafNode(
GritLeafNodePattern {
pattern: AstNode(
GritNodePattern {
kind: JsSyntaxKind(
JS_REFERENCE_IDENTIFIER,
),
equivalence_class: None,
text: "console",
args: [
GritNodePatternArg {
slot_index: 0,
pattern: AstLeafNode(
GritLeafNodePattern {
kind: JsSyntaxKind(
IDENT,
),
equivalence_class: None,
text: "console",
},
),
},
],
},
),
},
Expand All @@ -648,13 +652,25 @@ mod tests {
},
GritNodePatternArg {
slot_index: 2,
pattern: AstLeafNode(
GritLeafNodePattern {
pattern: AstNode(
GritNodePattern {
kind: JsSyntaxKind(
JS_NAME,
),
equivalence_class: None,
text: "log",
args: [
GritNodePatternArg {
slot_index: 0,
pattern: AstLeafNode(
GritLeafNodePattern {
kind: JsSyntaxKind(
IDENT,
),
equivalence_class: None,
text: "log",
},
),
},
],
},
),
},
Expand Down Expand Up @@ -715,31 +731,43 @@ mod tests {
pattern: List(
List {
patterns: [
AstLeafNode(
GritLeafNodePattern {
AstNode(
GritNodePattern {
kind: JsSyntaxKind(
JS_STRING_LITERAL_EXPRESSION,
),
equivalence_class: Some(
LeafEquivalenceClass {
representative: "hello",
class: [
LeafNormalizer {
args: [
GritNodePatternArg {
slot_index: 0,
pattern: AstLeafNode(
GritLeafNodePattern {
kind: JsSyntaxKind(
JS_STRING_LITERAL,
),
normalizer: [address redacted],
},
LeafNormalizer {
kind: JsSyntaxKind(
JS_STRING_LITERAL_EXPRESSION,
equivalence_class: Some(
LeafEquivalenceClass {
representative: "hello",
class: [
LeafNormalizer {
kind: JsSyntaxKind(
JS_STRING_LITERAL,
),
normalizer: [address redacted],
},
LeafNormalizer {
kind: JsSyntaxKind(
JS_STRING_LITERAL_EXPRESSION,
),
normalizer: [address redacted],
},
],
},
),
normalizer: [address redacted],
text: "'hello'",
},
],
),
},
),
text: "'hello'",
],
},
),
],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`$fn && $fn()` => `$fn?.()`
12 changes: 12 additions & 0 deletions crates/biome_grit_patterns/tests/specs/ts/duplicateVariable.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
source: crates/biome_grit_patterns/tests/spec_tests.rs
expression: duplicateVariable
---
SnapshotResult {
messages: [],
matched_ranges: [
"2:1-2:13",
],
rewritten_files: [],
created_files: [],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

foo && foo();
foo && bar();
foo && foo.bar();
bar || bar();

0 comments on commit bd1d0c6

Please sign in to comment.