use facet::Facet;
#[cfg(feature = "json-import")]
use crate::{
diagnostic::{ImportError, JsonDocumentKind},
source::{PackageRoot, SourceFile},
};
#[derive(Debug, Clone, Facet, PartialEq, Eq)]
pub struct TreeSitterConfigJson {
pub raw: String,
pub config: TreeSitterConfig,
}
impl TreeSitterConfigJson {
#[cfg(feature = "json-import")]
pub fn from_source_file(
root: &PackageRoot,
source_file: SourceFile<String>,
) -> Result<SourceFile<Self>, ImportError> {
let path = root.join(&source_file.path);
let source_id = source_file.id;
let package_path = source_file.path.clone();
let config =
facet_json::from_str(&source_file.body).map_err(|source| ImportError::Json {
package_root: Some(root.as_path().to_owned()),
path: Some(path),
source_id: Some(source_id),
package_path: Some(package_path),
document: JsonDocumentKind::TreeSitterConfig,
phase: "decode raw tree-sitter.json",
source,
})?;
Ok(source_file.map(|raw| Self { raw, config }))
}
}
#[derive(Debug, Clone, Facet, PartialEq, Eq)]
pub struct TreeSitterConfig {
#[facet(rename = "$schema")]
pub schema: Option<String>,
pub grammars: Vec<TreeSitterGrammarConfig>,
pub metadata: TreeSitterPackageMetadata,
pub bindings: Option<TreeSitterBindings>,
}
#[derive(Debug, Clone, Facet, PartialEq, Eq)]
pub struct TreeSitterGrammarConfig {
pub name: String,
pub camelcase: Option<String>,
pub title: Option<String>,
pub scope: String,
pub path: Option<String>,
#[facet(rename = "external-files")]
pub external_files: Option<Vec<String>>,
#[facet(rename = "file-types")]
pub file_types: Option<Vec<String>>,
pub highlights: Option<QueryPaths>,
pub injections: Option<QueryPaths>,
pub locals: Option<QueryPaths>,
pub tags: Option<QueryPaths>,
#[facet(rename = "injection-regex")]
pub injection_regex: Option<String>,
#[facet(rename = "first-line-regex")]
pub first_line_regex: Option<String>,
#[facet(rename = "content-regex")]
pub content_regex: Option<String>,
#[facet(rename = "class-name")]
pub class_name: Option<String>,
}
#[derive(Debug, Clone, Facet, PartialEq, Eq)]
#[facet(untagged)]
#[repr(u8)]
pub enum QueryPaths {
One(String),
Many(Vec<String>),
}
impl QueryPaths {
pub fn as_slice(&self) -> &[String] {
match self {
Self::One(path) => std::slice::from_ref(path),
Self::Many(paths) => paths.as_slice(),
}
}
pub fn iter(&self) -> impl Iterator<Item = &str> {
self.as_slice().iter().map(String::as_str)
}
}
#[derive(Debug, Clone, Facet, PartialEq, Eq)]
pub struct TreeSitterPackageMetadata {
pub version: String,
pub license: Option<String>,
pub description: Option<String>,
#[facet(default)]
pub authors: Vec<TreeSitterAuthor>,
pub links: TreeSitterLinks,
pub namespace: Option<String>,
}
#[derive(Debug, Clone, Facet, PartialEq, Eq)]
pub struct TreeSitterAuthor {
pub name: String,
pub email: Option<String>,
pub url: Option<String>,
}
#[derive(Debug, Clone, Facet, PartialEq, Eq)]
pub struct TreeSitterLinks {
pub repository: String,
pub funding: Option<String>,
}
#[derive(Debug, Clone, Facet, PartialEq, Eq)]
pub struct TreeSitterBindings {
pub c: Option<bool>,
pub go: Option<bool>,
pub java: Option<bool>,
pub kotlin: Option<bool>,
pub node: Option<bool>,
pub python: Option<bool>,
pub rust: Option<bool>,
pub swift: Option<bool>,
pub zig: Option<bool>,
}