From fc27fbe3451aba216082ffc3a303120a904a1d88 Mon Sep 17 00:00:00 2001 From: DorZuberi Date: Thu, 2 Apr 2026 21:26:48 +0300 Subject: [PATCH 1/6] Add Terraform language support with patterns and tests --- src/Highlighter.php | 2 + .../Patterns/TerraformBlockTypePattern.php | 32 +++++++ .../Patterns/TerraformBooleanPattern.php | 27 ++++++ .../TerraformInterpolationPattern.php | 26 ++++++ .../Patterns/TerraformKeywordPattern.php | 32 +++++++ .../Patterns/TerraformOperatorPattern.php | 28 ++++++ .../Patterns/TerraformPropertyPattern.php | 27 ++++++ .../Patterns/TerraformTypePattern.php | 32 +++++++ .../Patterns/TerraformVariablePattern.php | 30 +++++++ src/Languages/Terraform/TerraformLanguage.php | 86 +++++++++++++++++++ 10 files changed, 322 insertions(+) create mode 100644 src/Languages/Terraform/Patterns/TerraformBlockTypePattern.php create mode 100644 src/Languages/Terraform/Patterns/TerraformBooleanPattern.php create mode 100644 src/Languages/Terraform/Patterns/TerraformInterpolationPattern.php create mode 100644 src/Languages/Terraform/Patterns/TerraformKeywordPattern.php create mode 100644 src/Languages/Terraform/Patterns/TerraformOperatorPattern.php create mode 100644 src/Languages/Terraform/Patterns/TerraformPropertyPattern.php create mode 100644 src/Languages/Terraform/Patterns/TerraformTypePattern.php create mode 100644 src/Languages/Terraform/Patterns/TerraformVariablePattern.php create mode 100644 src/Languages/Terraform/TerraformLanguage.php diff --git a/src/Highlighter.php b/src/Highlighter.php index 866fe91..7f97a2c 100644 --- a/src/Highlighter.php +++ b/src/Highlighter.php @@ -26,6 +26,7 @@ use Tempest\Highlight\Languages\Scss\ScssLanguage; use Tempest\Highlight\Languages\Sql\SqlLanguage; use Tempest\Highlight\Languages\Terminal\TerminalLanguage; +use Tempest\Highlight\Languages\Terraform\TerraformLanguage; use Tempest\Highlight\Languages\Text\TextLanguage; use Tempest\Highlight\Languages\Twig\TwigLanguage; use Tempest\Highlight\Languages\Xml\XmlLanguage; @@ -73,6 +74,7 @@ public function __construct(private readonly Theme $theme = new CssTheme()) ->addLanguage(new ScssLanguage()) ->addLanguage(new SqlLanguage()) ->addLanguage(new TerminalLanguage()) + ->addLanguage(new TerraformLanguage()) ->addLanguage(new XmlLanguage()) ->addLanguage(new YamlLanguage()) ->addLanguage(new DotEnvLanguage()) diff --git a/src/Languages/Terraform/Patterns/TerraformBlockTypePattern.php b/src/Languages/Terraform/Patterns/TerraformBlockTypePattern.php new file mode 100644 index 0000000..2467605 --- /dev/null +++ b/src/Languages/Terraform/Patterns/TerraformBlockTypePattern.php @@ -0,0 +1,32 @@ +{$blockTypes})\b/m"; + } + + public function getTokenType(): TokenTypeEnum + { + return TokenTypeEnum::KEYWORD; + } +} diff --git a/src/Languages/Terraform/Patterns/TerraformBooleanPattern.php b/src/Languages/Terraform/Patterns/TerraformBooleanPattern.php new file mode 100644 index 0000000..f40fdce --- /dev/null +++ b/src/Languages/Terraform/Patterns/TerraformBooleanPattern.php @@ -0,0 +1,27 @@ +true|false|null)\b'; + } + + public function getTokenType(): TokenTypeEnum + { + return TokenTypeEnum::VALUE; + } +} diff --git a/src/Languages/Terraform/Patterns/TerraformInterpolationPattern.php b/src/Languages/Terraform/Patterns/TerraformInterpolationPattern.php new file mode 100644 index 0000000..b8a99c4 --- /dev/null +++ b/src/Languages/Terraform/Patterns/TerraformInterpolationPattern.php @@ -0,0 +1,26 @@ +\$\{[^}]+\})'; + } + + public function getTokenType(): TokenTypeEnum + { + return TokenTypeEnum::GENERIC; + } +} diff --git a/src/Languages/Terraform/Patterns/TerraformKeywordPattern.php b/src/Languages/Terraform/Patterns/TerraformKeywordPattern.php new file mode 100644 index 0000000..61933d5 --- /dev/null +++ b/src/Languages/Terraform/Patterns/TerraformKeywordPattern.php @@ -0,0 +1,32 @@ +(?:{$keywords}))\b"; + } + + public function getTokenType(): TokenTypeEnum + { + return TokenTypeEnum::KEYWORD; + } +} diff --git a/src/Languages/Terraform/Patterns/TerraformOperatorPattern.php b/src/Languages/Terraform/Patterns/TerraformOperatorPattern.php new file mode 100644 index 0000000..12ffc51 --- /dev/null +++ b/src/Languages/Terraform/Patterns/TerraformOperatorPattern.php @@ -0,0 +1,28 @@ + value', output: '=>')] +final readonly class TerraformOperatorPattern implements Pattern +{ + use IsPattern; + + public function getPattern(): string + { + return '(?=>|==|!=|>=|<=|&&|\|\||[=>[a-zA-Z_][a-zA-Z0-9_]*)\s*=/m'; + } + + public function getTokenType(): TokenTypeEnum + { + return TokenTypeEnum::PROPERTY; + } +} diff --git a/src/Languages/Terraform/Patterns/TerraformTypePattern.php b/src/Languages/Terraform/Patterns/TerraformTypePattern.php new file mode 100644 index 0000000..0e87bdc --- /dev/null +++ b/src/Languages/Terraform/Patterns/TerraformTypePattern.php @@ -0,0 +1,32 @@ +(?:{$types}))\b"; + } + + public function getTokenType(): TokenTypeEnum + { + return TokenTypeEnum::TYPE; + } +} diff --git a/src/Languages/Terraform/Patterns/TerraformVariablePattern.php b/src/Languages/Terraform/Patterns/TerraformVariablePattern.php new file mode 100644 index 0000000..7318cdd --- /dev/null +++ b/src/Languages/Terraform/Patterns/TerraformVariablePattern.php @@ -0,0 +1,30 @@ +(?:{$prefixes})(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)+)"; + } + + public function getTokenType(): TokenTypeEnum + { + return TokenTypeEnum::VARIABLE; + } +} diff --git a/src/Languages/Terraform/TerraformLanguage.php b/src/Languages/Terraform/TerraformLanguage.php new file mode 100644 index 0000000..64998a1 --- /dev/null +++ b/src/Languages/Terraform/TerraformLanguage.php @@ -0,0 +1,86 @@ + Date: Thu, 2 Apr 2026 21:27:00 +0300 Subject: [PATCH 2/6] Add Terraform language tests, fixtures, and benchmarks --- tests/Bench/Fixtures/terraform.txt | 54 ++++++++++ tests/Bench/HighlighterBench.php | 1 + .../Terraform/TerraformLanguageTest.php | 99 +++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 tests/Bench/Fixtures/terraform.txt create mode 100644 tests/Languages/Terraform/TerraformLanguageTest.php diff --git a/tests/Bench/Fixtures/terraform.txt b/tests/Bench/Fixtures/terraform.txt new file mode 100644 index 0000000..854fc01 --- /dev/null +++ b/tests/Bench/Fixtures/terraform.txt @@ -0,0 +1,54 @@ +# Configure the AWS provider +provider "aws" { + region = "us-east-1" +} + +resource "aws_instance" "web" { + ami = var.ami_id + instance_type = "t2.micro" + count = 3 + + tags = { + Name = "web-${var.environment}" + } + + lifecycle { + create_before_destroy = true + } +} + +variable "instance_type" { + type = string + default = "t2.micro" +} + +output "instance_id" { + value = module.server.id +} + +// Single-line comment +/* Multi-line + comment */ + +data "aws_ami" "ubuntu" { + most_recent = true + + filter { + name = "name" + values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"] + } +} + +locals { + common_tags = { + Environment = var.environment + Project = "example" + } +} + +module "vpc" { + source = "terraform-aws-modules/vpc/aws" + version = "3.0.0" + + cidr = "10.0.0.0/16" +} \ No newline at end of file diff --git a/tests/Bench/HighlighterBench.php b/tests/Bench/HighlighterBench.php index 9c8d83a..23685c5 100644 --- a/tests/Bench/HighlighterBench.php +++ b/tests/Bench/HighlighterBench.php @@ -36,6 +36,7 @@ final class HighlighterBench 'scss' => 'scss.txt', 'sql' => 'sql.txt', 'terminal' => 'terminal.txt', + 'terraform' => 'terraform.txt', 'twig' => 'twig.txt', 'xml' => 'xml.txt', 'yaml' => 'yaml.txt', diff --git a/tests/Languages/Terraform/TerraformLanguageTest.php b/tests/Languages/Terraform/TerraformLanguageTest.php new file mode 100644 index 0000000..c745ee4 --- /dev/null +++ b/tests/Languages/Terraform/TerraformLanguageTest.php @@ -0,0 +1,99 @@ +assertSame( + $expected, + $highlighter->parse($content, 'terraform'), + ); + + $this->assertSame( + $expected, + $highlighter->parse($content, 'tf'), + ); + + $this->assertSame( + $expected, + $highlighter->parse($content, 'hcl'), + ); + } + + public static function provide_highlight_cases(): iterable + { + return [ + [<<<'TXT' +# Configure the AWS provider +provider "aws" { + region = "us-east-1" +} + +resource "aws_instance" "web" { + ami = var.ami_id + instance_type = "t2.micro" + count = 3 + + tags = { + Name = "web-${var.environment}" + } +} +TXT, + <<<'TXT' +# Configure the AWS provider +provider "aws" { + region = "us-east-1" +} + +resource "aws_instance" "web" { + ami = var.ami_id + instance_type = "t2.micro" + count = 3 + + tags = { + Name = "web-${var.environment}" + } +} +TXT], + [<<<'TXT' +variable "instance_type" { + type = string + default = "t2.micro" +} + +output "instance_id" { + value = module.server.id +} + +// This is a single-line comment +/* This is a + multi-line comment */ +TXT, + <<<'TXT' +variable "instance_type" { + type = string + default = "t2.micro" +} + +output "instance_id" { + value = module.server.id +} + +// This is a single-line comment +/* This is a + multi-line comment */ +TXT], + ]; + } +} From e8ce81bd28b4a0df713351d392dac96be91c1846 Mon Sep 17 00:00:00 2001 From: DorZuberi Date: Thu, 2 Apr 2026 21:29:35 +0300 Subject: [PATCH 3/6] Add Terraform heredoc pattern with tests and integration into language --- .../Patterns/TerraformHeredocPattern.php | 41 +++++++++++++++++++ src/Languages/Terraform/TerraformLanguage.php | 2 + 2 files changed, 43 insertions(+) create mode 100644 src/Languages/Terraform/Patterns/TerraformHeredocPattern.php diff --git a/src/Languages/Terraform/Patterns/TerraformHeredocPattern.php b/src/Languages/Terraform/Patterns/TerraformHeredocPattern.php new file mode 100644 index 0000000..c35e6dc --- /dev/null +++ b/src/Languages/Terraform/Patterns/TerraformHeredocPattern.php @@ -0,0 +1,41 @@ +<<-?\s*([A-Z_][A-Z0-9_]*)\n.*?\n\s*\2)/s'; + } + + public function getTokenType(): TokenTypeEnum + { + return TokenTypeEnum::VALUE; + } +} \ No newline at end of file diff --git a/src/Languages/Terraform/TerraformLanguage.php b/src/Languages/Terraform/TerraformLanguage.php index 64998a1..4c3b3b2 100644 --- a/src/Languages/Terraform/TerraformLanguage.php +++ b/src/Languages/Terraform/TerraformLanguage.php @@ -13,6 +13,7 @@ use Tempest\Highlight\Languages\Php\Patterns\DoubleQuoteValuePattern; use Tempest\Highlight\Languages\Terraform\Patterns\TerraformBlockTypePattern; use Tempest\Highlight\Languages\Terraform\Patterns\TerraformBooleanPattern; +use Tempest\Highlight\Languages\Terraform\Patterns\TerraformHeredocPattern; use Tempest\Highlight\Languages\Terraform\Patterns\TerraformInterpolationPattern; use Tempest\Highlight\Languages\Terraform\Patterns\TerraformKeywordPattern; use Tempest\Highlight\Languages\Terraform\Patterns\TerraformOperatorPattern; @@ -53,6 +54,7 @@ public function getPatterns(): array new JsSinglelineCommentPattern(), // VALUES + new TerraformHeredocPattern(), new DoubleQuoteValuePattern(), // BLOCK TYPES From 03b9c0c12f00d31205c9f7b16c95b4cfef712e6e Mon Sep 17 00:00:00 2001 From: DorZuberi Date: Thu, 2 Apr 2026 21:30:45 +0300 Subject: [PATCH 4/6] Add test for Terraform heredoc syntax and highlighting --- .../Terraform/TerraformLanguageTest.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/Languages/Terraform/TerraformLanguageTest.php b/tests/Languages/Terraform/TerraformLanguageTest.php index c745ee4..36fb071 100644 --- a/tests/Languages/Terraform/TerraformLanguageTest.php +++ b/tests/Languages/Terraform/TerraformLanguageTest.php @@ -93,6 +93,26 @@ public static function provide_highlight_cases(): iterable // This is a single-line comment /* This is a multi-line comment */ +TXT], + [<<<'TXT' +resource "aws_iam_policy" "example" { + policy = <<-POLICY + { + "Version": "2012-10-17", + "Statement": [] + } + POLICY +} +TXT, + <<<'TXT' +resource "aws_iam_policy" "example" { + policy = <<-POLICY + { + "Version": "2012-10-17", + "Statement": [] + } + POLICY +} TXT], ]; } From 52ab79d1de80c1fa274b29c28a2f16eec2941ed1 Mon Sep 17 00:00:00 2001 From: DorZuberi Date: Thu, 2 Apr 2026 21:32:09 +0300 Subject: [PATCH 5/6] Add Terragrunt alias and corresponding tests to Terraform language support --- src/Languages/Terraform/TerraformLanguage.php | 2 +- tests/Languages/Terraform/TerraformLanguageTest.php | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Languages/Terraform/TerraformLanguage.php b/src/Languages/Terraform/TerraformLanguage.php index 4c3b3b2..f12ceba 100644 --- a/src/Languages/Terraform/TerraformLanguage.php +++ b/src/Languages/Terraform/TerraformLanguage.php @@ -31,7 +31,7 @@ public function getName(): string #[Override] public function getAliases(): array { - return ['tf', 'hcl']; + return ['tf', 'hcl', 'terragrunt']; } #[Override] diff --git a/tests/Languages/Terraform/TerraformLanguageTest.php b/tests/Languages/Terraform/TerraformLanguageTest.php index 36fb071..c7ee521 100644 --- a/tests/Languages/Terraform/TerraformLanguageTest.php +++ b/tests/Languages/Terraform/TerraformLanguageTest.php @@ -29,6 +29,11 @@ public function test_highlight(string $content, string $expected): void $expected, $highlighter->parse($content, 'hcl'), ); + + $this->assertSame( + $expected, + $highlighter->parse($content, 'terragrunt'), + ); } public static function provide_highlight_cases(): iterable From fadac376bdf3366bf52ee3147a9b0d9d45ecd1e7 Mon Sep 17 00:00:00 2001 From: DorZuberi Date: Thu, 2 Apr 2026 21:33:41 +0300 Subject: [PATCH 6/6] Fix missing newline and extend Terraform test fixtures with IAM policy example --- .../Terraform/Patterns/TerraformHeredocPattern.php | 2 +- tests/Bench/Fixtures/terraform.txt | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Languages/Terraform/Patterns/TerraformHeredocPattern.php b/src/Languages/Terraform/Patterns/TerraformHeredocPattern.php index c35e6dc..0e4c8b4 100644 --- a/src/Languages/Terraform/Patterns/TerraformHeredocPattern.php +++ b/src/Languages/Terraform/Patterns/TerraformHeredocPattern.php @@ -38,4 +38,4 @@ public function getTokenType(): TokenTypeEnum { return TokenTypeEnum::VALUE; } -} \ No newline at end of file +} diff --git a/tests/Bench/Fixtures/terraform.txt b/tests/Bench/Fixtures/terraform.txt index 854fc01..64e9c12 100644 --- a/tests/Bench/Fixtures/terraform.txt +++ b/tests/Bench/Fixtures/terraform.txt @@ -46,6 +46,15 @@ locals { } } +resource "aws_iam_policy" "example" { + policy = <<-POLICY + { + "Version": "2012-10-17", + "Statement": [] + } + POLICY +} + module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "3.0.0"