Return correct path and line in query errors from the CLI
This commit is contained in:
parent
297e2bcb28
commit
518916f221
5 changed files with 372 additions and 234 deletions
|
|
@ -1,7 +1,7 @@
|
|||
use super::test_highlight;
|
||||
use std::fmt::Write;
|
||||
use std::io;
|
||||
use tree_sitter::QueryError;
|
||||
use tree_sitter::{QueryError, QueryErrorKind};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error(pub Vec<String>);
|
||||
|
|
@ -51,31 +51,19 @@ impl Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> From<QueryError> for Error {
|
||||
fn from(error: QueryError) -> Self {
|
||||
match error {
|
||||
QueryError::Capture(row, c) => Error::new(format!(
|
||||
"Query error on line {}: Invalid capture name {}",
|
||||
row, c
|
||||
)),
|
||||
QueryError::Field(row, f) => Error::new(format!(
|
||||
"Query error on line {}: Invalid field name {}",
|
||||
row, f
|
||||
)),
|
||||
QueryError::NodeType(row, t) => Error::new(format!(
|
||||
"Query error on line {}. Invalid node type {}",
|
||||
row, t
|
||||
)),
|
||||
QueryError::Syntax(row, l) => Error::new(format!(
|
||||
"Query error on line {}. Invalid syntax:\n{}",
|
||||
row, l
|
||||
)),
|
||||
QueryError::Structure(row, l) => Error::new(format!(
|
||||
"Query error on line {}. Impossible pattern:\n{}",
|
||||
row, l
|
||||
)),
|
||||
QueryError::Predicate(p) => Error::new(format!("Query error: {}", p)),
|
||||
impl<'a> From<(&str, QueryError)> for Error {
|
||||
fn from((path, error): (&str, QueryError)) -> Self {
|
||||
let mut msg = format!("Query error at {}:{}. ", path, error.row + 1);
|
||||
match error.kind {
|
||||
QueryErrorKind::Capture => write!(&mut msg, "Invalid capture name {}", error.message),
|
||||
QueryErrorKind::Field => write!(&mut msg, "Invalid field name {}", error.message),
|
||||
QueryErrorKind::NodeType => write!(&mut msg, "Invalid node type {}", error.message),
|
||||
QueryErrorKind::Syntax => write!(&mut msg, "Invalid syntax:\n{}", error.message),
|
||||
QueryErrorKind::Structure => write!(&mut msg, "Impossible pattern:\n{}", error.message),
|
||||
QueryErrorKind::Predicate => write!(&mut msg, "Invalid predicate: {}", error.message),
|
||||
}
|
||||
.unwrap();
|
||||
Self::new(msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@ use regex::{Regex, RegexBuilder};
|
|||
use serde_derive::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
use std::io::BufReader;
|
||||
use std::ops::Range;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::sync::Mutex;
|
||||
use std::time::SystemTime;
|
||||
use std::{fs, mem};
|
||||
use tree_sitter::Language;
|
||||
use tree_sitter::{Language, QueryError};
|
||||
use tree_sitter_highlight::HighlightConfiguration;
|
||||
use tree_sitter_tags::TagsConfiguration;
|
||||
|
||||
|
|
@ -543,13 +544,32 @@ impl Loader {
|
|||
|
||||
impl<'a> LanguageConfiguration<'a> {
|
||||
pub fn highlight_config(&self, language: Language) -> Result<Option<&HighlightConfiguration>> {
|
||||
fn include_path_in_error<'a>(
|
||||
mut error: QueryError,
|
||||
ranges: &'a Vec<(String, Range<usize>)>,
|
||||
source: &str,
|
||||
start_offset: usize,
|
||||
) -> (&'a str, QueryError) {
|
||||
let offset = error.offset - start_offset;
|
||||
let (path, range) = ranges
|
||||
.iter()
|
||||
.find(|(_, range)| range.contains(&offset))
|
||||
.unwrap();
|
||||
error.row = source[range.start..offset]
|
||||
.chars()
|
||||
.filter(|c| *c == '\n')
|
||||
.count();
|
||||
(path.as_ref(), error)
|
||||
}
|
||||
|
||||
self.highlight_config
|
||||
.get_or_try_init(|| {
|
||||
let highlights_query =
|
||||
let (highlights_query, highlight_ranges) =
|
||||
self.read_queries(&self.highlights_filenames, "highlights.scm")?;
|
||||
let injections_query =
|
||||
let (injections_query, injection_ranges) =
|
||||
self.read_queries(&self.injections_filenames, "injections.scm")?;
|
||||
let locals_query = self.read_queries(&self.locals_filenames, "locals.scm")?;
|
||||
let (locals_query, locals_ranges) =
|
||||
self.read_queries(&self.locals_filenames, "locals.scm")?;
|
||||
|
||||
if highlights_query.is_empty() {
|
||||
Ok(None)
|
||||
|
|
@ -560,9 +580,25 @@ impl<'a> LanguageConfiguration<'a> {
|
|||
&injections_query,
|
||||
&locals_query,
|
||||
)
|
||||
.map_err(Error::wrap(|| {
|
||||
format!("Failed to load queries in {:?}", self.root_path)
|
||||
}))?;
|
||||
.map_err(|error| {
|
||||
if error.offset < injections_query.len() {
|
||||
include_path_in_error(error, &injection_ranges, &injections_query, 0)
|
||||
} else if error.offset < injections_query.len() + locals_query.len() {
|
||||
include_path_in_error(
|
||||
error,
|
||||
&locals_ranges,
|
||||
&locals_query,
|
||||
injections_query.len(),
|
||||
)
|
||||
} else {
|
||||
include_path_in_error(
|
||||
error,
|
||||
&highlight_ranges,
|
||||
&highlights_query,
|
||||
injections_query.len() + locals_query.len(),
|
||||
)
|
||||
}
|
||||
})?;
|
||||
let mut all_highlight_names = self.highlight_names.lock().unwrap();
|
||||
if self.use_all_highlight_names {
|
||||
for capture_name in result.query.capture_names() {
|
||||
|
|
@ -581,8 +617,8 @@ impl<'a> LanguageConfiguration<'a> {
|
|||
pub fn tags_config(&self, language: Language) -> Result<Option<&TagsConfiguration>> {
|
||||
self.tags_config
|
||||
.get_or_try_init(|| {
|
||||
let tags_query = self.read_queries(&self.tags_filenames, "tags.scm")?;
|
||||
let locals_query = self.read_queries(&self.locals_filenames, "locals.scm")?;
|
||||
let (tags_query, _) = self.read_queries(&self.tags_filenames, "tags.scm")?;
|
||||
let (locals_query, _) = self.read_queries(&self.locals_filenames, "locals.scm")?;
|
||||
if tags_query.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
|
|
@ -596,27 +632,34 @@ impl<'a> LanguageConfiguration<'a> {
|
|||
.map(Option::as_ref)
|
||||
}
|
||||
|
||||
fn read_queries(&self, paths: &Option<Vec<String>>, default_path: &str) -> Result<String> {
|
||||
fn read_queries(
|
||||
&self,
|
||||
paths: &Option<Vec<String>>,
|
||||
default_path: &str,
|
||||
) -> Result<(String, Vec<(String, Range<usize>)>)> {
|
||||
let mut query = String::new();
|
||||
let mut path_ranges = Vec::new();
|
||||
if let Some(paths) = paths.as_ref() {
|
||||
let mut query = String::new();
|
||||
for path in paths {
|
||||
let path = self.root_path.join(path);
|
||||
query += &fs::read_to_string(&path).map_err(Error::wrap(|| {
|
||||
let abs_path = self.root_path.join(path);
|
||||
let prev_query_len = query.len();
|
||||
query += &fs::read_to_string(&abs_path).map_err(Error::wrap(|| {
|
||||
format!("Failed to read query file {:?}", path)
|
||||
}))?;
|
||||
path_ranges.push((path.clone(), prev_query_len..query.len()));
|
||||
}
|
||||
Ok(query)
|
||||
} else {
|
||||
let queries_path = self.root_path.join("queries");
|
||||
let path = queries_path.join(default_path);
|
||||
if path.exists() {
|
||||
fs::read_to_string(&path).map_err(Error::wrap(|| {
|
||||
query = fs::read_to_string(&path).map_err(Error::wrap(|| {
|
||||
format!("Failed to read query file {:?}", path)
|
||||
}))
|
||||
} else {
|
||||
Ok(String::new())
|
||||
}))?;
|
||||
path_ranges.push((default_path.to_string(), 0..query.len()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok((query, path_ranges))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -102,14 +102,14 @@ pub fn check_queries_at_path(language: Language, path: &Path) -> Result<()> {
|
|||
if path.exists() {
|
||||
for entry in fs::read_dir(path)? {
|
||||
let entry = entry?;
|
||||
let hidden = entry.file_name().to_str().unwrap_or("").starts_with(".");
|
||||
let filepath = entry.file_name();
|
||||
let filepath = filepath.to_str().unwrap_or("");
|
||||
let hidden = filepath.starts_with(".");
|
||||
if !hidden {
|
||||
let content = fs::read_to_string(entry.path()).map_err(Error::wrap(|| {
|
||||
format!("Error reading query file {:?}", entry.file_name())
|
||||
}))?;
|
||||
Query::new(language, &content).map_err(Error::wrap(|| {
|
||||
format!("Error in query file {:?}", entry.file_name())
|
||||
}))?;
|
||||
Query::new(language, &content).map_err(|e| (filepath, e))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ use lazy_static::lazy_static;
|
|||
use std::env;
|
||||
use std::fmt::Write;
|
||||
use tree_sitter::{
|
||||
Language, Node, Parser, Query, QueryCapture, QueryCursor, QueryError, QueryMatch,
|
||||
QueryPredicate, QueryPredicateArg, QueryProperty,
|
||||
Language, Node, Parser, Query, QueryCapture, QueryCursor, QueryError, QueryErrorKind,
|
||||
QueryMatch, QueryPredicate, QueryPredicateArg, QueryProperty,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
|
|
@ -26,109 +26,98 @@ fn test_query_errors_on_invalid_syntax() {
|
|||
|
||||
// Mismatched parens
|
||||
assert_eq!(
|
||||
Query::new(language, "(if_statement"),
|
||||
Err(QueryError::Syntax(
|
||||
1,
|
||||
[
|
||||
"(if_statement", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
Query::new(language, "(if_statement").unwrap_err().message,
|
||||
[
|
||||
"(if_statement", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
assert_eq!(
|
||||
Query::new(language, "; comment 1\n; comment 2\n (if_statement))"),
|
||||
Err(QueryError::Syntax(
|
||||
3,
|
||||
[
|
||||
" (if_statement))", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
Query::new(language, "; comment 1\n; comment 2\n (if_statement))")
|
||||
.unwrap_err()
|
||||
.message,
|
||||
[
|
||||
" (if_statement))", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
|
||||
// Return an error at the *beginning* of a bare identifier not followed a colon.
|
||||
// If there's a colon but no pattern, return an error at the end of the colon.
|
||||
assert_eq!(
|
||||
Query::new(language, "(if_statement identifier)"),
|
||||
Err(QueryError::Syntax(
|
||||
1,
|
||||
[
|
||||
"(if_statement identifier)", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
Query::new(language, "(if_statement identifier)")
|
||||
.unwrap_err()
|
||||
.message,
|
||||
[
|
||||
"(if_statement identifier)", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
assert_eq!(
|
||||
Query::new(language, "(if_statement condition:)"),
|
||||
Err(QueryError::Syntax(
|
||||
1,
|
||||
[
|
||||
"(if_statement condition:)", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
Query::new(language, "(if_statement condition:)")
|
||||
.unwrap_err()
|
||||
.message,
|
||||
[
|
||||
"(if_statement condition:)", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
|
||||
// Return an error at the beginning of an unterminated string.
|
||||
assert_eq!(
|
||||
Query::new(language, r#"(identifier) "h "#),
|
||||
Err(QueryError::Syntax(
|
||||
1,
|
||||
[
|
||||
r#"(identifier) "h "#, //
|
||||
r#" ^"#,
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
Query::new(language, r#"(identifier) "h "#)
|
||||
.unwrap_err()
|
||||
.message,
|
||||
[
|
||||
r#"(identifier) "h "#, //
|
||||
r#" ^"#,
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Query::new(language, r#"((identifier) ()"#),
|
||||
Err(QueryError::Syntax(
|
||||
1,
|
||||
[
|
||||
"((identifier) ()", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
Query::new(language, r#"((identifier) ()"#)
|
||||
.unwrap_err()
|
||||
.message,
|
||||
[
|
||||
"((identifier) ()", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
assert_eq!(
|
||||
Query::new(language, r#"((identifier) [])"#),
|
||||
Err(QueryError::Syntax(
|
||||
1,
|
||||
[
|
||||
"((identifier) [])", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
Query::new(language, r#"((identifier) [])"#)
|
||||
.unwrap_err()
|
||||
.message,
|
||||
[
|
||||
"((identifier) [])", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
assert_eq!(
|
||||
Query::new(language, r#"((identifier) (#a)"#),
|
||||
Err(QueryError::Syntax(
|
||||
1,
|
||||
[
|
||||
"((identifier) (#a)", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
Query::new(language, r#"((identifier) (#a)"#)
|
||||
.unwrap_err()
|
||||
.message,
|
||||
[
|
||||
"((identifier) (#a)", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
assert_eq!(
|
||||
Query::new(language, r#"((identifier) @x (#eq? @x a"#),
|
||||
Err(QueryError::Syntax(
|
||||
1,
|
||||
[
|
||||
r#"((identifier) @x (#eq? @x a"#,
|
||||
r#" ^"#,
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
Query::new(language, r#"((identifier) @x (#eq? @x a"#)
|
||||
.unwrap_err()
|
||||
.message,
|
||||
[
|
||||
r#"((identifier) @x (#eq? @x a"#,
|
||||
r#" ^"#,
|
||||
]
|
||||
.join("\n")
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
@ -139,53 +128,97 @@ fn test_query_errors_on_invalid_symbols() {
|
|||
let language = get_language("javascript");
|
||||
|
||||
assert_eq!(
|
||||
Query::new(language, "(clas)"),
|
||||
Err(QueryError::NodeType(1, "clas".to_string()))
|
||||
Query::new(language, "(clas)").unwrap_err(),
|
||||
QueryError {
|
||||
row: 1,
|
||||
offset: 1,
|
||||
column: 1,
|
||||
kind: QueryErrorKind::NodeType,
|
||||
message: "clas".to_string()
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
Query::new(language, "(if_statement (arrayyyyy))"),
|
||||
Err(QueryError::NodeType(1, "arrayyyyy".to_string()))
|
||||
Query::new(language, "(if_statement (arrayyyyy))").unwrap_err(),
|
||||
QueryError {
|
||||
row: 1,
|
||||
offset: 15,
|
||||
column: 15,
|
||||
kind: QueryErrorKind::NodeType,
|
||||
message: "arrayyyyy".to_string()
|
||||
},
|
||||
);
|
||||
assert_eq!(
|
||||
Query::new(language, "(if_statement condition: (non_existent3))"),
|
||||
Err(QueryError::NodeType(1, "non_existent3".to_string()))
|
||||
Query::new(language, "(if_statement condition: (non_existent3))").unwrap_err(),
|
||||
QueryError {
|
||||
row: 1,
|
||||
offset: 26,
|
||||
column: 26,
|
||||
kind: QueryErrorKind::NodeType,
|
||||
message: "non_existent3".to_string()
|
||||
},
|
||||
);
|
||||
assert_eq!(
|
||||
Query::new(language, "(if_statement condit: (identifier))"),
|
||||
Err(QueryError::Field(1, "condit".to_string()))
|
||||
Query::new(language, "(if_statement condit: (identifier))").unwrap_err(),
|
||||
QueryError {
|
||||
row: 1,
|
||||
offset: 14,
|
||||
column: 14,
|
||||
kind: QueryErrorKind::Field,
|
||||
message: "condit".to_string()
|
||||
},
|
||||
);
|
||||
assert_eq!(
|
||||
Query::new(language, "(if_statement conditioning: (identifier))"),
|
||||
Err(QueryError::Field(1, "conditioning".to_string()))
|
||||
Query::new(language, "(if_statement conditioning: (identifier))").unwrap_err(),
|
||||
QueryError {
|
||||
row: 1,
|
||||
offset: 14,
|
||||
column: 14,
|
||||
kind: QueryErrorKind::Field,
|
||||
message: "conditioning".to_string()
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_errors_on_invalid_conditions() {
|
||||
fn test_query_errors_on_invalid_predicates() {
|
||||
allocations::record(|| {
|
||||
let language = get_language("javascript");
|
||||
|
||||
assert_eq!(
|
||||
Query::new(language, "((identifier) @id (@id))"),
|
||||
Err(QueryError::Syntax(
|
||||
1,
|
||||
[
|
||||
Query::new(language, "((identifier) @id (@id))").unwrap_err(),
|
||||
QueryError {
|
||||
kind: QueryErrorKind::Syntax,
|
||||
row: 1,
|
||||
column: 19,
|
||||
offset: 19,
|
||||
message: [
|
||||
"((identifier) @id (@id))", //
|
||||
" ^"
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
Query::new(language, "((identifier) @id (#eq? @id))"),
|
||||
Err(QueryError::Predicate(
|
||||
"Wrong number of arguments to #eq? predicate. Expected 2, got 1.".to_string()
|
||||
))
|
||||
Query::new(language, "((identifier) @id (#eq? @id))").unwrap_err(),
|
||||
QueryError {
|
||||
kind: QueryErrorKind::Predicate,
|
||||
row: 0,
|
||||
column: 0,
|
||||
offset: 0,
|
||||
message: "Wrong number of arguments to #eq? predicate. Expected 2, got 1."
|
||||
.to_string()
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
Query::new(language, "((identifier) @id (#eq? @id @ok))"),
|
||||
Err(QueryError::Capture(1, "ok".to_string()))
|
||||
Query::new(language, "((identifier) @id (#eq? @id @ok))").unwrap_err(),
|
||||
QueryError {
|
||||
kind: QueryErrorKind::Capture,
|
||||
row: 1,
|
||||
column: 29,
|
||||
offset: 29,
|
||||
message: "ok".to_string(),
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
@ -201,14 +234,17 @@ fn test_query_errors_on_impossible_patterns() {
|
|||
js_lang,
|
||||
"(binary_expression left: (identifier) left: (identifier))"
|
||||
),
|
||||
Err(QueryError::Structure(
|
||||
1,
|
||||
[
|
||||
Err(QueryError {
|
||||
kind: QueryErrorKind::Structure,
|
||||
row: 1,
|
||||
offset: 38,
|
||||
column: 38,
|
||||
message: [
|
||||
"(binary_expression left: (identifier) left: (identifier))",
|
||||
" ^"
|
||||
]
|
||||
.join("\n"),
|
||||
))
|
||||
})
|
||||
);
|
||||
|
||||
Query::new(
|
||||
|
|
@ -218,27 +254,33 @@ fn test_query_errors_on_impossible_patterns() {
|
|||
.unwrap();
|
||||
assert_eq!(
|
||||
Query::new(js_lang, "(function_declaration name: (statement_block))"),
|
||||
Err(QueryError::Structure(
|
||||
1,
|
||||
[
|
||||
Err(QueryError {
|
||||
kind: QueryErrorKind::Structure,
|
||||
row: 1,
|
||||
offset: 22,
|
||||
column: 22,
|
||||
message: [
|
||||
"(function_declaration name: (statement_block))",
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
})
|
||||
);
|
||||
|
||||
Query::new(rb_lang, "(call receiver:(call))").unwrap();
|
||||
assert_eq!(
|
||||
Query::new(rb_lang, "(call receiver:(binary))"),
|
||||
Err(QueryError::Structure(
|
||||
1,
|
||||
[
|
||||
Err(QueryError {
|
||||
kind: QueryErrorKind::Structure,
|
||||
row: 1,
|
||||
offset: 6,
|
||||
column: 6,
|
||||
message: [
|
||||
"(call receiver:(binary))", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
})
|
||||
);
|
||||
|
||||
Query::new(
|
||||
|
|
@ -259,37 +301,46 @@ fn test_query_errors_on_impossible_patterns() {
|
|||
(generator_function_declaration (identifier))
|
||||
]",
|
||||
),
|
||||
Err(QueryError::Structure(
|
||||
3,
|
||||
[
|
||||
Err(QueryError {
|
||||
kind: QueryErrorKind::Structure,
|
||||
row: 3,
|
||||
offset: 88,
|
||||
column: 42,
|
||||
message: [
|
||||
" (function_declaration (object))", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
})
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Query::new(js_lang, "(identifier (identifier))",),
|
||||
Err(QueryError::Structure(
|
||||
1,
|
||||
[
|
||||
Err(QueryError {
|
||||
kind: QueryErrorKind::Structure,
|
||||
row: 1,
|
||||
offset: 12,
|
||||
column: 12,
|
||||
message: [
|
||||
"(identifier (identifier))", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
Query::new(js_lang, "(true (true))",),
|
||||
Err(QueryError::Structure(
|
||||
1,
|
||||
[
|
||||
Err(QueryError {
|
||||
kind: QueryErrorKind::Structure,
|
||||
row: 1,
|
||||
offset: 6,
|
||||
column: 6,
|
||||
message: [
|
||||
"(true (true))", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
})
|
||||
);
|
||||
|
||||
Query::new(
|
||||
|
|
@ -298,16 +349,20 @@ fn test_query_errors_on_impossible_patterns() {
|
|||
condition: (parenthesized_expression (_expression) @cond))",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
Query::new(js_lang, "(if_statement condition: (_expression))",),
|
||||
Err(QueryError::Structure(
|
||||
1,
|
||||
[
|
||||
Err(QueryError {
|
||||
kind: QueryErrorKind::Structure,
|
||||
row: 1,
|
||||
offset: 14,
|
||||
column: 14,
|
||||
message: [
|
||||
"(if_statement condition: (_expression))", //
|
||||
" ^",
|
||||
]
|
||||
.join("\n")
|
||||
))
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue