diff --git a/Cargo.lock b/Cargo.lock index 198aea2..57cc6da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -386,6 +386,7 @@ dependencies = [ "tree-sitter-erlang", "tree-sitter-go", "tree-sitter-haskell", + "tree-sitter-hcl", "tree-sitter-html", "tree-sitter-java", "tree-sitter-javascript", @@ -2687,6 +2688,16 @@ dependencies = [ "tree-sitter-language", ] +[[package]] +name = "tree-sitter-hcl" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a7b2cc3d7121553b84309fab9d11b3ff3d420403eef9ae50f9fd1cd9d9cf012" +dependencies = [ + "cc", + "tree-sitter-language", +] + [[package]] name = "tree-sitter-html" version = "0.23.2" diff --git a/Cargo.toml b/Cargo.toml index 758a877..e785160 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,6 +80,7 @@ tree-sitter-typescript = "0.23.2" tree-sitter-vhdl = "<2" tree-sitter-yaml = "0.7.2" tree-sitter-zig = "<2" +tree-sitter-hcl = "1.1" codebook-tree-sitter-just = "<0.2.0" codebook-tree-sitter-latex = "<0.7.0" codebook-tree-sitter-typst = "<0.13.0" diff --git a/crates/codebook/Cargo.toml b/crates/codebook/Cargo.toml index 0d70d04..b54a162 100644 --- a/crates/codebook/Cargo.toml +++ b/crates/codebook/Cargo.toml @@ -58,6 +58,7 @@ codebook-tree-sitter-typst.workspace = true tree-sitter-yaml.workspace = true tree-sitter-zig.workspace = true tree-sitter-c-sharp.workspace = true +tree-sitter-hcl.workspace = true tree-sitter.workspace = true unicase.workspace = true unicode-script.workspace = true diff --git a/crates/codebook/src/queries.rs b/crates/codebook/src/queries.rs index 12e9e32..cd9197d 100644 --- a/crates/codebook/src/queries.rs +++ b/crates/codebook/src/queries.rs @@ -37,6 +37,7 @@ pub enum LanguageType { VHDL, YAML, Zig, + Hcl, } impl FromStr for LanguageType { @@ -312,6 +313,13 @@ pub static LANGUAGE_SETTINGS: &[LanguageSetting] = &[ query: include_str!("queries/vhdl.scm"), extensions: &["vhd", "vhdl"], }, + LanguageSetting { + type_: LanguageType::Hcl, + ids: &["hcl", "terraform"], + dictionary_ids: &["hcl"], + query: include_str!("queries/hcl.scm"), + extensions: &["tf", "tfvars"], + }, ]; #[derive(Debug)] @@ -360,6 +368,7 @@ impl LanguageSetting { LanguageType::VHDL => Some(tree_sitter_vhdl::LANGUAGE.into()), LanguageType::YAML => Some(tree_sitter_yaml::LANGUAGE.into()), LanguageType::Zig => Some(tree_sitter_zig::LANGUAGE.into()), + LanguageType::Hcl => Some(tree_sitter_hcl::LANGUAGE.into()), } } } diff --git a/crates/codebook/src/queries/hcl.scm b/crates/codebook/src/queries/hcl.scm new file mode 100644 index 0000000..7a7411e --- /dev/null +++ b/crates/codebook/src/queries/hcl.scm @@ -0,0 +1,5 @@ +(comment) @comment + +(attribute (identifier) @identifier.field) + +(template_literal) @string diff --git a/crates/codebook/tests/languages/main.rs b/crates/codebook/tests/languages/main.rs index 5900037..8b62703 100644 --- a/crates/codebook/tests/languages/main.rs +++ b/crates/codebook/tests/languages/main.rs @@ -11,6 +11,7 @@ mod test_erlang; mod test_files; mod test_go; mod test_haskell; +mod test_hcl; mod test_java; mod test_javascript; mod test_just; diff --git a/crates/codebook/tests/languages/test_hcl.rs b/crates/codebook/tests/languages/test_hcl.rs new file mode 100644 index 0000000..2db6b6b --- /dev/null +++ b/crates/codebook/tests/languages/test_hcl.rs @@ -0,0 +1,94 @@ +use codebook::queries::LanguageType; + +use super::utils::{assert_spelling, assert_spelling_at}; + +#[test] +fn test_hcl_attribute_identifiers() { + let sample_text = r#" +resource "aws_instance" "web_server" { + instnace_type = "t3.micro" + descriptin = "Valid text" +} +"#; + + assert_spelling( + LanguageType::Hcl, + sample_text, + &["instnace", "descriptin"], + &["resource", "aws_instance", "web_server"], + ); +} + +#[test] +fn test_hcl_strings_and_comments() { + let sample_text = r#" +# Comment with a speling error. + +/* Multi-line comment +with an error on the seconnd line. */ + +variable "region" { + description = "Cloud regon for the deploymant." + default = "eu-west-1" +} + +resource "aws_instance" "web_server" { + user_data = <<-EOT + Configure the servver for this environment. + Enable applicaton logging for ${var.region}. + EOT +} +"#; + + assert_spelling_at( + LanguageType::Hcl, + sample_text, + &[ + ("speling", &[0]), + ("seconnd", &[0]), + ("regon", &[0]), + ("deploymant", &[0]), + ("servver", &[0]), + ("applicaton", &[0]), + ], + ); +} + +#[test] +fn test_hcl_only_checks_identifier_definitions() { + let sample_text = r#" +variable "source_value" { + default = "valid" +} + +locals { + misspeled_value = var.source_value +} + +output "result" { + value = local.misspeled_value +} +"#; + + assert_spelling_at(LanguageType::Hcl, sample_text, &[("misspeled", &[0])]); +} + +#[test] +fn test_hcl_string_interpolation() { + let sample_text = r#" +variable "region" { + default = "eu-west-1" +} + +locals { + message = "Deploy to the regon ${var.misspeled_reference}" +} +"#; + + assert_spelling( + LanguageType::Hcl, + sample_text, + &["regon"], + &["misspeled_reference"], + ); +} diff --git a/examples/example.tf b/examples/example.tf new file mode 100644 index 0000000..64c4841 --- /dev/null +++ b/examples/example.tf @@ -0,0 +1,31 @@ +# Provision the applicaton infrastructure for the staging enviroment. + +terraform { + required_version = ">= 1.5.0" +} + +variable "region" { + description = "Cloud regon used for the deployment." + type = string + default = "eu-west-1" +} + +resource "aws_instance" "web_server" { + ami = "ami-12345678" + instance_type = "t3.micro" + + tags = { + Name = "Applicaton server" + Description = "Handles incoming requsts" + } + + user_data = <<-EOT + Configure the servver for the staging environment. + Enable applicaton logging. + EOT +} + +output "instance_id" { + description = "Identifer of the created instance." + value = aws_instance.web_server.id +}