refactor(adapter): unify repetitive code patterns

This commit is contained in:
kbwo 2024-07-22 23:21:13 +09:00
parent bb1a163f98
commit d8bd53d4ca
6 changed files with 36 additions and 304 deletions

View file

@ -15,8 +15,6 @@ use super::util::detect_workspaces_from_file_paths;
use super::util::discover_rust_tests;
use super::util::parse_cargo_diagnostics;
// If the character value is greater than the line length it defaults back to the line length.
fn parse_diagnostics(
contents: &str,
workspace_root: PathBuf,

View file

@ -17,14 +17,12 @@ use testing_language_server::spec::DiscoverResultItem;
use testing_language_server::spec::RunFileTestResult;
use testing_language_server::spec::RunFileTestResultItem;
use testing_language_server::spec::TestItem;
use tree_sitter::Point;
use tree_sitter::Query;
use tree_sitter::QueryCursor;
use crate::model::Runner;
use super::util::clean_ansi;
use super::util::detect_workspaces_from_file_paths;
use super::util::discover_with_treesitter;
use super::util::MAX_CHAR_LENGTH;
fn get_position_from_output(line: &str) -> Option<(String, u32, u32)> {
@ -101,16 +99,9 @@ fn detect_workspaces(file_paths: Vec<String>) -> DetectWorkspaceResult {
}
fn discover(file_path: &str) -> Result<Vec<TestItem>, LSError> {
let mut parser = tree_sitter::Parser::new();
let mut test_items: Vec<TestItem> = vec![];
parser
.set_language(&tree_sitter_javascript::language())
.expect("Error loading JavaScript grammar");
let source_code = std::fs::read_to_string(file_path)?;
let tree = parser.parse(&source_code, None).unwrap();
// from https://github.com/MarkEmmons/neotest-deno/blob/7136b9342aeecb675c7c16a0bde327d7fcb00a1c/lua/neotest-deno/init.lua#L93
// license: https://github.com/MarkEmmons/neotest-deno/blob/main/LICENSE
let query_string = r#"
let query = r#"
;; Deno.test
(call_expression
function: (member_expression) @func_name (#match? @func_name "^Deno.test$")
@ -159,66 +150,7 @@ fn discover(file_path: &str) -> Result<Vec<TestItem>, LSError> {
]
) @test.definition
"#;
let query = Query::new(&tree_sitter_javascript::language(), query_string)
.expect("Error creating query");
let mut cursor = QueryCursor::new();
cursor.set_byte_range(tree.root_node().byte_range());
let source = source_code.as_bytes();
let matches = cursor.matches(&query, tree.root_node(), source);
for m in matches {
eprintln!("DEBUGPRINT[3]: deno.rs:170: m={:#?}", m);
let mut namespace_name = "";
let mut test_start_position = Point::default();
let mut test_end_position = Point::default();
for capture in m.captures {
let capture_name = query.capture_names()[capture.index as usize];
let value = capture.node.utf8_text(source)?;
let start_position = capture.node.start_position();
let end_position = capture.node.end_position();
match capture_name {
"namespace.name" => {
namespace_name = value;
}
"test.definition" => {
test_start_position = start_position;
test_end_position = end_position;
}
"test.name" => {
let test_name = value;
let test_item = TestItem {
id: format!("{}:{}", namespace_name, test_name),
name: test_name.to_string(),
start_position: Range {
start: Position {
line: test_start_position.row as u32,
character: test_start_position.column as u32,
},
end: Position {
line: test_start_position.row as u32,
character: MAX_CHAR_LENGTH,
},
},
end_position: Range {
start: Position {
line: test_end_position.row as u32,
character: 0,
},
end: Position {
line: test_end_position.row as u32,
character: test_end_position.column as u32,
},
},
};
test_items.push(test_item);
test_start_position = Point::default();
test_end_position = Point::default();
}
_ => {}
}
}
}
Ok(test_items)
discover_with_treesitter(file_path, &tree_sitter_javascript::language(), query)
}
#[derive(Eq, PartialEq, Debug)]

View file

@ -17,14 +17,10 @@ use testing_language_server::spec::DiscoverResultItem;
use testing_language_server::spec::RunFileTestResult;
use testing_language_server::spec::RunFileTestResultItem;
use testing_language_server::spec::TestItem;
use tree_sitter::Point;
use tree_sitter::Query;
use tree_sitter::QueryCursor;
use super::util::detect_workspaces_from_file_paths;
// If the character value is greater than the line length it defaults back to the line length.
const MAX_CHAR_LENGTH: u32 = 10000;
use super::util::discover_with_treesitter;
use super::util::MAX_CHAR_LENGTH;
#[derive(Deserialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
@ -140,16 +136,9 @@ fn parse_diagnostics(
}
fn discover(file_path: &str) -> Result<Vec<TestItem>, LSError> {
let mut parser = tree_sitter::Parser::new();
let mut test_items: Vec<TestItem> = vec![];
parser
.set_language(&tree_sitter_go::language())
.expect("Error loading Rust grammar");
let source_code = std::fs::read_to_string(file_path)?;
let tree = parser.parse(&source_code, None).unwrap();
// from https://github.com/nvim-neotest/neotest-go/blob/92950ad7be2ca02a41abca5c6600ff6ffaf5b5d6/lua/neotest-go/init.lua#L54
// license: https://github.com/nvim-neotest/neotest-go/blob/92950ad7be2ca02a41abca5c6600ff6ffaf5b5d6/README.md
let query_string = r#"
let query = r#"
;;query
((function_declaration
name: (identifier) @test.name)
@ -230,66 +219,7 @@ fn discover(file_path: &str) -> Result<Vec<TestItem>, LSError> {
((identifier) @test.key.name1
(#eq? @test.key.name @test.key.name1))))))))
"#;
let query =
Query::new(&tree_sitter_go::language(), query_string).expect("Error creating query");
let mut cursor = QueryCursor::new();
cursor.set_byte_range(tree.root_node().byte_range());
let source = source_code.as_bytes();
let matches = cursor.matches(&query, tree.root_node(), source);
for m in matches {
let mut namespace_name = "";
let mut test_start_position = Point::default();
let mut test_end_position = Point::default();
for capture in m.captures {
let capture_name = query.capture_names()[capture.index as usize];
let value = capture.node.utf8_text(source)?;
let start_position = capture.node.start_position();
let end_position = capture.node.end_position();
match capture_name {
"namespace.name" => {
namespace_name = value;
}
"test.definition" => {
test_start_position = start_position;
test_end_position = end_position;
}
"test.name" => {
let test_name = value;
let test_item = TestItem {
id: format!("{}:{}", namespace_name, test_name),
name: test_name.to_string(),
start_position: Range {
start: Position {
line: test_start_position.row as u32,
character: test_start_position.column as u32,
},
end: Position {
line: test_start_position.row as u32,
character: MAX_CHAR_LENGTH,
},
},
end_position: Range {
start: Position {
line: test_end_position.row as u32,
character: 0,
},
end: Position {
line: test_end_position.row as u32,
character: test_end_position.column as u32,
},
},
};
test_items.push(test_item);
test_start_position = Point::default();
test_end_position = Point::default();
}
_ => {}
}
}
}
Ok(test_items)
discover_with_treesitter(file_path, &tree_sitter_go::language(), query)
}
#[derive(Eq, PartialEq, Hash, Debug)]

View file

@ -1,8 +1,6 @@
use crate::runner::util::send_stdout;
use lsp_types::Diagnostic;
use lsp_types::DiagnosticSeverity;
use lsp_types::Position;
use lsp_types::Range;
use serde_json::Value;
use std::collections::HashMap;
use std::fs;
@ -15,17 +13,13 @@ use testing_language_server::spec::DiscoverResultItem;
use testing_language_server::spec::RunFileTestResult;
use testing_language_server::spec::RunFileTestResultItem;
use testing_language_server::spec::TestItem;
use tree_sitter::Point;
use tree_sitter::Query;
use tree_sitter::QueryCursor;
use crate::model::Runner;
use super::util::clean_ansi;
use super::util::detect_workspaces_from_file_paths;
// If the character value is greater than the line length it defaults back to the line length.
const MAX_CHAR_LENGTH: u32 = 10000;
use super::util::discover_with_treesitter;
use super::util::MAX_CHAR_LENGTH;
fn parse_diagnostics(
test_result: &str,
@ -84,16 +78,9 @@ fn detect_workspaces(file_paths: Vec<String>) -> DetectWorkspaceResult {
}
fn discover(file_path: &str) -> Result<Vec<TestItem>, LSError> {
let mut parser = tree_sitter::Parser::new();
let mut test_items: Vec<TestItem> = vec![];
parser
.set_language(&tree_sitter_javascript::language())
.expect("Error loading JavaScript grammar");
let source_code = std::fs::read_to_string(file_path)?;
let tree = parser.parse(&source_code, None).unwrap();
// from https://github.com/nvim-neotest/neotest-jest/blob/514fd4eae7da15fd409133086bb8e029b65ac43f/lua/neotest-jest/init.lua#L162
// license: https://github.com/nvim-neotest/neotest-jest/blob/514fd4eae7da15fd409133086bb8e029b65ac43f/LICENSE.md
let query_string = r#"
let query = r#"
; -- Namespaces --
; Matches: `describe('context', () => {})`
((call_expression
@ -162,65 +149,7 @@ fn discover(file_path: &str) -> Result<Vec<TestItem>, LSError> {
arguments: (arguments (string (string_fragment) @test.name) [(arrow_function) (function_expression)])
)) @test.definition
"#;
let query = Query::new(&tree_sitter_javascript::language(), query_string)
.expect("Error creating query");
let mut cursor = QueryCursor::new();
cursor.set_byte_range(tree.root_node().byte_range());
let source = source_code.as_bytes();
let matches = cursor.matches(&query, tree.root_node(), source);
for m in matches {
let mut namespace_name = "";
let mut test_start_position = Point::default();
let mut test_end_position = Point::default();
for capture in m.captures {
let capture_name = query.capture_names()[capture.index as usize];
let value = capture.node.utf8_text(source)?;
let start_position = capture.node.start_position();
let end_position = capture.node.end_position();
match capture_name {
"namespace.name" => {
namespace_name = value;
}
"test.definition" => {
test_start_position = start_position;
test_end_position = end_position;
}
"test.name" => {
let test_name = value;
let test_item = TestItem {
id: format!("{}:{}", namespace_name, test_name),
name: test_name.to_string(),
start_position: Range {
start: Position {
line: test_start_position.row as u32,
character: test_start_position.column as u32,
},
end: Position {
line: test_start_position.row as u32,
character: MAX_CHAR_LENGTH,
},
},
end_position: Range {
start: Position {
line: test_end_position.row as u32,
character: 0,
},
end: Position {
line: test_end_position.row as u32,
character: test_end_position.column as u32,
},
},
};
test_items.push(test_item);
test_start_position = Point::default();
test_end_position = Point::default();
}
_ => {}
}
}
}
Ok(test_items)
discover_with_treesitter(file_path, &tree_sitter_javascript::language(), query)
}
#[derive(Eq, PartialEq, Debug)]

View file

@ -7,7 +7,7 @@ use regex::Regex;
use serde::Serialize;
use testing_language_server::spec::{RunFileTestResultItem, TestItem};
use testing_language_server::{error::LSError, spec::RunFileTestResult};
use tree_sitter::{Point, Query, QueryCursor};
use tree_sitter::{Language, Point, Query, QueryCursor};
// If the character value is greater than the line length it defaults back to the line length.
pub const MAX_CHAR_LENGTH: u32 = 10000;
@ -76,16 +76,9 @@ pub fn clean_ansi(input: &str) -> String {
}
pub fn discover_rust_tests(file_path: &str) -> Result<Vec<TestItem>, LSError> {
let mut parser = tree_sitter::Parser::new();
let mut test_items: Vec<TestItem> = vec![];
parser
.set_language(&tree_sitter_rust::language())
.expect("Error loading Rust grammar");
let source_code = std::fs::read_to_string(file_path)?;
let tree = parser.parse(&source_code, None).unwrap();
// from https://github.com/rouge8/neotest-rust/blob/0418811e1e3499b2501593f2e131d02f5e6823d4/lua/neotest-rust/init.lua#L167
// license: https://github.com/rouge8/neotest-rust/blob/0418811e1e3499b2501593f2e131d02f5e6823d4/LICENSE
let query_string = r#"
let query = r#"
(
(attribute_item
[
@ -119,8 +112,22 @@ pub fn discover_rust_tests(file_path: &str) -> Result<Vec<TestItem>, LSError> {
)
(mod_item name: (identifier) @namespace.name)? @namespace.definition
"#;
let query =
Query::new(&tree_sitter_rust::language(), query_string).expect("Error creating query");
discover_with_treesitter(file_path, &tree_sitter_rust::language(), query)
}
pub fn discover_with_treesitter(
file_path: &str,
language: &Language,
query: &str,
) -> Result<Vec<TestItem>, LSError> {
let mut parser = tree_sitter::Parser::new();
let mut test_items: Vec<TestItem> = vec![];
parser
.set_language(language)
.expect("Error loading Rust grammar");
let source_code = std::fs::read_to_string(file_path)?;
let tree = parser.parse(&source_code, None).unwrap();
let query = Query::new(language, query).expect("Error creating query");
let mut cursor = QueryCursor::new();
cursor.set_byte_range(tree.root_node().byte_range());

View file

@ -3,7 +3,7 @@ use std::{
fs::{self, File},
};
use lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range};
use lsp_types::{Diagnostic, DiagnosticSeverity};
use serde_json::Value;
use tempfile::tempdir;
use testing_language_server::{
@ -12,25 +12,20 @@ use testing_language_server::{
DiscoverResult, DiscoverResultItem, RunFileTestResult, RunFileTestResultItem, TestItem,
},
};
use tree_sitter::{Point, Query, QueryCursor};
use crate::model::Runner;
use super::util::{clean_ansi, detect_workspaces_from_file_paths, send_stdout, MAX_CHAR_LENGTH};
use super::util::{
clean_ansi, detect_workspaces_from_file_paths, discover_with_treesitter, send_stdout,
MAX_CHAR_LENGTH,
};
#[derive(Eq, PartialEq, Hash, Debug)]
pub struct VitestRunner;
fn discover(file_path: &str) -> Result<Vec<TestItem>, LSError> {
let mut parser = tree_sitter::Parser::new();
let mut test_items: Vec<TestItem> = vec![];
parser
.set_language(&tree_sitter_javascript::language())
.expect("Error loading Rust grammar");
let source_code = std::fs::read_to_string(file_path)?;
let tree = parser.parse(&source_code, None).unwrap();
// from https://github.com/marilari88/neotest-vitest/blob/353364aa05b94b09409cbef21b79c97c5564e2ce/lua/neotest-vitest/init.lua#L101
let query_string = r#"
let query = r#"
; -- Namespaces --
; Matches: `describe('context')`
((call_expression
@ -77,66 +72,7 @@ fn discover(file_path: &str) -> Result<Vec<TestItem>, LSError> {
arguments: (arguments (string (string_fragment) @test.name) (arrow_function))
)) @test.definition
"#;
let query = Query::new(&tree_sitter_javascript::language(), query_string)
.expect("Error creating query");
let mut cursor = QueryCursor::new();
cursor.set_byte_range(tree.root_node().byte_range());
let source = source_code.as_bytes();
let matches = cursor.matches(&query, tree.root_node(), source);
for m in matches {
let mut namespace_name = "";
let mut test_start_position = Point::default();
let mut test_end_position = Point::default();
for capture in m.captures {
let capture_name = query.capture_names()[capture.index as usize];
let value = capture.node.utf8_text(source)?;
let start_position = capture.node.start_position();
let end_position = capture.node.end_position();
match capture_name {
"namespace.name" => {
namespace_name = value;
}
"test.definition" => {
test_start_position = start_position;
test_end_position = end_position;
}
"test.name" => {
let test_name = value;
let test_item = TestItem {
id: format!("{}:{}", namespace_name, test_name),
name: test_name.to_string(),
start_position: Range {
start: Position {
line: test_start_position.row as u32,
character: test_start_position.column as u32,
},
end: Position {
line: test_start_position.row as u32,
character: MAX_CHAR_LENGTH,
},
},
end_position: Range {
start: Position {
line: test_end_position.row as u32,
character: 0,
},
end: Position {
line: test_end_position.row as u32,
character: test_end_position.column as u32,
},
},
};
test_items.push(test_item);
test_start_position = Point::default();
test_end_position = Point::default();
}
_ => {}
}
}
}
Ok(test_items)
discover_with_treesitter(file_path, &tree_sitter_javascript::language(), query)
}
fn parse_diagnostics(