diff --git a/src/hcl/hcl.contribution.ts b/src/hcl/hcl.contribution.ts index 15b0b513..b802cef8 100644 --- a/src/hcl/hcl.contribution.ts +++ b/src/hcl/hcl.contribution.ts @@ -7,8 +7,8 @@ import { registerLanguage } from '../_.contribution'; registerLanguage({ - id: 'hcl', - extensions: ['.tf', '.tfvars', '.hcl'], - aliases: ['Terraform', 'tf', 'HCL', 'hcl'], - loader: () => import('./hcl') + id: 'hcl', + extensions: ['.tf', '.tfvars', '.hcl'], + aliases: ['Terraform', 'tf', 'HCL', 'hcl'], + loader: () => import('./hcl') }); diff --git a/src/hcl/hcl.test.ts b/src/hcl/hcl.test.ts new file mode 100644 index 00000000..e8ccd03d --- /dev/null +++ b/src/hcl/hcl.test.ts @@ -0,0 +1,1201 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +"use strict"; + +import { testTokenization } from "../test/testRunner"; + +testTokenization("hcl", [ + /* + // Foo + /* Bar */ + /* + /* + Baz + *\/ + # Another + + # Multiple + # Lines + foo = "bar" + */ + [ + { + line: "// Foo", + tokens: [{ startIndex: 0, type: "comment.hcl" }], + }, + { + line: "/* Bar */", + tokens: [{ startIndex: 0, type: "comment.hcl" }], + }, + { + line: "/*", + tokens: [{ startIndex: 0, type: "comment.hcl" }], + }, + { + line: "/*", + tokens: [{ startIndex: 0, type: "comment.hcl" }], + }, + { + line: "Baz", + tokens: [{ startIndex: 0, type: "comment.hcl" }], + }, + { + line: "*/", + tokens: [{ startIndex: 0, type: "comment.hcl" }], + }, + { + line: "# Another", + tokens: [{ startIndex: 0, type: "comment.hcl" }], + }, + { + line: "", + tokens: [], + }, + { + line: "# Multiple", + tokens: [{ startIndex: 0, type: "comment.hcl" }], + }, + { + line: "# Lines", + tokens: [{ startIndex: 0, type: "comment.hcl" }], + }, + { + line: 'foo = "bar"', + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "string.hcl" }, + ], + }, + ], + + [ + { + line: "", + tokens: [], + }, + ], + + /* + foo = [ + "1", + "2", # comment + ] + */ + [ + { + line: "foo = [", + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "delimiter.square.hcl" }, + ], + }, + { + line: '"1",', + tokens: [ + { startIndex: 0, type: "string.hcl" }, + { startIndex: 3, type: "delimiter.hcl" }, + ], + }, + { + line: '"2", # comment', + tokens: [ + { startIndex: 0, type: "string.hcl" }, + { startIndex: 3, type: "delimiter.hcl" }, + { startIndex: 4, type: "" }, + { startIndex: 5, type: "comment.hcl" }, + ], + }, + { + line: "]", + tokens: [{ startIndex: 0, type: "delimiter.square.hcl" }], + }, + ], + + /* + resource = [{ + "foo": { + "bar": {}, + "baz": [1, 2, "foo"], + } + }] + */ + [ + { + line: "resource = [{", + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 8, type: "" }, + { startIndex: 9, type: "operator.hcl" }, + { startIndex: 10, type: "" }, + { startIndex: 11, type: "delimiter.square.hcl" }, + { startIndex: 12, type: "delimiter.curly.hcl" }, + ], + }, + { + line: '"foo": {', + tokens: [ + { startIndex: 0, type: "string.hcl" }, + { startIndex: 5, type: "operator.hcl" }, + { startIndex: 6, type: "" }, + { startIndex: 7, type: "delimiter.curly.hcl" }, + ], + }, + { + line: '"bar": {},', + tokens: [ + { startIndex: 0, type: "string.hcl" }, + { startIndex: 5, type: "operator.hcl" }, + { startIndex: 6, type: "" }, + { startIndex: 7, type: "delimiter.curly.hcl" }, + { startIndex: 9, type: "delimiter.hcl" }, + ], + }, + { + line: '"baz": [1, 2, "foo"],', + tokens: [ + { startIndex: 0, type: "string.hcl" }, + { startIndex: 5, type: "operator.hcl" }, + { startIndex: 6, type: "" }, + { startIndex: 7, type: "delimiter.square.hcl" }, + { startIndex: 8, type: "number.hcl" }, + { startIndex: 9, type: "delimiter.hcl" }, + { startIndex: 10, type: "" }, + { startIndex: 11, type: "number.hcl" }, + { startIndex: 12, type: "delimiter.hcl" }, + { startIndex: 13, type: "" }, + { startIndex: 14, type: "string.hcl" }, + { startIndex: 19, type: "delimiter.square.hcl" }, + { startIndex: 20, type: "delimiter.hcl" }, + ], + }, + { + line: "}", + tokens: [{ startIndex: 0, type: "delimiter.curly.hcl" }], + }, + { + line: "}]", + tokens: [ + { startIndex: 0, type: "delimiter.curly.hcl" }, + { startIndex: 1, type: "delimiter.square.hcl" }, + ], + }, + ], + + /* + variable "foo" { + default = "bar" + description = "bar" + } + */ + [ + { + line: 'variable "foo" {', + tokens: [ + { startIndex: 0, type: "type.hcl" }, + { startIndex: 8, type: "" }, + { startIndex: 9, type: "string.hcl" }, + { startIndex: 14, type: "" }, + { startIndex: 15, type: "delimiter.curly.hcl" }, + ], + }, + { + line: ' default = "bar"', + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "variable.hcl" }, + { startIndex: 9, type: "" }, + { startIndex: 10, type: "operator.hcl" }, + { startIndex: 11, type: "" }, + { startIndex: 12, type: "string.hcl" }, + ], + }, + { + line: ' description = "bar"', + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "variable.hcl" }, + { startIndex: 13, type: "" }, + { startIndex: 14, type: "operator.hcl" }, + { startIndex: 15, type: "" }, + { startIndex: 16, type: "string.hcl" }, + ], + }, + { + line: "}", + tokens: [{ startIndex: 0, type: "delimiter.curly.hcl" }], + }, + ], + [ + { + line: 'provider "aws" {', + tokens: [ + { startIndex: 0, type: "type.hcl" }, + { startIndex: 8, type: "" }, + { startIndex: 9, type: "string.hcl" }, + { startIndex: 14, type: "" }, + { startIndex: 15, type: "delimiter.curly.hcl" }, + ], + }, + ], + /* + provider "do" { + api_key = "${var.foo}" + } + */ + [ + { + line: 'provider "do" {', + tokens: [ + { startIndex: 0, type: "type.hcl" }, + { startIndex: 8, type: "" }, + { startIndex: 9, type: "string.hcl" }, + { startIndex: 13, type: "" }, + { startIndex: 14, type: "delimiter.curly.hcl" }, + ], + }, + { + line: ' api_key = "${var.foo}"', + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "variable.hcl" }, + { startIndex: 9, type: "" }, + { startIndex: 10, type: "operator.hcl" }, + { startIndex: 11, type: "" }, + { startIndex: 12, type: "string.hcl" }, + { startIndex: 13, type: "delimiter.hcl" }, + { startIndex: 15, type: "keyword.var.hcl" }, + { startIndex: 18, type: "delimiter.hcl" }, + { startIndex: 19, type: "variable.hcl" }, + { startIndex: 22, type: "delimiter.hcl" }, + { startIndex: 23, type: "string.hcl" }, + ], + }, + { + line: "}", + tokens: [{ startIndex: 0, type: "delimiter.curly.hcl" }], + }, + ], + /* + resource "aws_security_group" "firewall" { + count = 5 + } + */ + [ + { + line: 'resource "aws_security_group" "firewall" {', + tokens: [ + { startIndex: 0, type: "type.hcl" }, + { startIndex: 8, type: "" }, + { startIndex: 9, type: "string.hcl" }, + { startIndex: 29, type: "" }, + { startIndex: 30, type: "string.hcl" }, + { startIndex: 40, type: "" }, + { startIndex: 41, type: "delimiter.curly.hcl" }, + ], + }, + { + line: " count = 5", + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "variable.hcl" }, + { startIndex: 7, type: "" }, + { startIndex: 8, type: "operator.hcl" }, + { startIndex: 9, type: "" }, + { startIndex: 10, type: "number.hcl" }, + ], + }, + { + line: "}", + tokens: [{ startIndex: 0, type: "delimiter.curly.hcl" }], + }, + ], + [ + { + line: "resource aws_security_group firewall {", + tokens: [ + { startIndex: 0, type: "type.hcl" }, + { startIndex: 8, type: "" }, + { startIndex: 9, type: "string.hcl" }, + { startIndex: 27, type: "" }, + { startIndex: 28, type: "string.hcl" }, + { startIndex: 36, type: "" }, + { startIndex: 37, type: "delimiter.curly.hcl" }, + ], + }, + ], + [ + { + line: 'resource "aws_security_group" firewall {', + tokens: [ + { startIndex: 0, type: "type.hcl" }, + { startIndex: 8, type: "" }, + { startIndex: 9, type: "string.hcl" }, + { startIndex: 29, type: "" }, + { startIndex: 30, type: "string.hcl" }, + { startIndex: 38, type: "" }, + { startIndex: 39, type: "delimiter.curly.hcl" }, + ], + }, + ], + [ + { + line: 'resource aws_security_group "firewall" {', + tokens: [ + { startIndex: 0, type: "type.hcl" }, + { startIndex: 8, type: "" }, + { startIndex: 9, type: "string.hcl" }, + { startIndex: 27, type: "" }, + { startIndex: 28, type: "string.hcl" }, + { startIndex: 38, type: "" }, + { startIndex: 39, type: "delimiter.curly.hcl" }, + ], + }, + ], + /* + resource aws_instance "web" { + ami = "${var.foo}" + security_groups = [ + "foo", + "${aws_security_group.firewall.foo}" + ] + network_interface { + device_index = 0 + description = "Main network interface" + } + } + */ + [ + { + line: 'resource aws_instance "web" {', + tokens: [ + { startIndex: 0, type: "type.hcl" }, + { startIndex: 8, type: "" }, + { startIndex: 9, type: "string.hcl" }, + { startIndex: 21, type: "" }, + { startIndex: 22, type: "string.hcl" }, + { startIndex: 27, type: "" }, + { startIndex: 28, type: "delimiter.curly.hcl" }, + ], + }, + { + line: ' ami = "${var.foo}"', + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "variable.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "operator.hcl" }, + { startIndex: 7, type: "" }, + { startIndex: 8, type: "string.hcl" }, + { startIndex: 9, type: "delimiter.hcl" }, + { startIndex: 11, type: "keyword.var.hcl" }, + { startIndex: 14, type: "delimiter.hcl" }, + { startIndex: 15, type: "variable.hcl" }, + { startIndex: 18, type: "delimiter.hcl" }, + { startIndex: 19, type: "string.hcl" }, + ], + }, + { + line: " security_groups = [", + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "variable.hcl" }, + { startIndex: 17, type: "" }, + { startIndex: 18, type: "operator.hcl" }, + { startIndex: 19, type: "" }, + { startIndex: 20, type: "delimiter.square.hcl" }, + ], + }, + { + line: ' "foo",', + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 4, type: "string.hcl" }, + { startIndex: 9, type: "delimiter.hcl" }, + ], + }, + { + line: ' "${aws_security_group.firewall.foo}"', + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 4, type: "string.hcl" }, + { startIndex: 5, type: "delimiter.hcl" }, + { startIndex: 7, type: "variable.hcl" }, + { startIndex: 25, type: "delimiter.hcl" }, + { startIndex: 26, type: "variable.hcl" }, + { startIndex: 34, type: "delimiter.hcl" }, + { startIndex: 35, type: "variable.hcl" }, + { startIndex: 38, type: "delimiter.hcl" }, + { startIndex: 39, type: "string.hcl" }, + ], + }, + { + line: " ]", + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "delimiter.square.hcl" }, + ], + }, + { + line: " network_interface {", + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "identifier.hcl" }, + { startIndex: 20, type: "delimiter.curly.hcl" }, + ], + }, + { + line: " device_index = 0", + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 4, type: "variable.hcl" }, + { startIndex: 16, type: "" }, + { startIndex: 17, type: "operator.hcl" }, + { startIndex: 18, type: "" }, + { startIndex: 19, type: "number.hcl" }, + ], + }, + { + line: ' description = "Main network interface"', + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 4, type: "variable.hcl" }, + { startIndex: 15, type: "" }, + { startIndex: 16, type: "operator.hcl" }, + { startIndex: 17, type: "" }, + { startIndex: 18, type: "string.hcl" }, + ], + }, + { + line: " }", + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "delimiter.curly.hcl" }, + ], + }, + { + line: "}", + tokens: [{ startIndex: 0, type: "delimiter.curly.hcl" }], + }, + ], + /* + resource "aws_instance" "db" { + security_groups = "${aws_security_group.firewall.*.id}" + VPC = "foo" + depends_on = ["aws_instance.web"] + } + */ + [ + { + line: 'resource "aws_instance" "db" {', + tokens: [ + { startIndex: 0, type: "type.hcl" }, + { startIndex: 8, type: "" }, + { startIndex: 9, type: "string.hcl" }, + { startIndex: 23, type: "" }, + { startIndex: 24, type: "string.hcl" }, + { startIndex: 28, type: "" }, + { startIndex: 29, type: "delimiter.curly.hcl" }, + ], + }, + { + line: ' security_groups = "${aws_security_group.firewall.*.id}"', + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "variable.hcl" }, + { startIndex: 17, type: "" }, + { startIndex: 18, type: "operator.hcl" }, + { startIndex: 19, type: "" }, + { startIndex: 20, type: "string.hcl" }, + { startIndex: 21, type: "delimiter.hcl" }, + { startIndex: 23, type: "variable.hcl" }, + { startIndex: 41, type: "delimiter.hcl" }, + { startIndex: 42, type: "variable.hcl" }, + { startIndex: 50, type: "delimiter.hcl" }, + { startIndex: 51, type: "operator.hcl" }, + { startIndex: 52, type: "delimiter.hcl" }, + { startIndex: 53, type: "variable.hcl" }, + { startIndex: 55, type: "delimiter.hcl" }, + { startIndex: 56, type: "string.hcl" }, + ], + }, + { + line: ' VPC = "foo"', + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "variable.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "operator.hcl" }, + { startIndex: 7, type: "" }, + { startIndex: 8, type: "string.hcl" }, + ], + }, + { + line: ' depends_on = ["aws_instance.web"]', + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "variable.hcl" }, + { startIndex: 12, type: "" }, + { startIndex: 13, type: "operator.hcl" }, + { startIndex: 14, type: "" }, + { startIndex: 15, type: "delimiter.square.hcl" }, + { startIndex: 16, type: "string.hcl" }, + { startIndex: 34, type: "delimiter.square.hcl" }, + ], + }, + { + line: "}", + tokens: [{ startIndex: 0, type: "delimiter.curly.hcl" }], + }, + ], + /* + output "web_ip" { + value = "${aws_instance.web.private_ip}" + } + */ + [ + { + line: 'output "web_ip" {', + tokens: [ + { startIndex: 0, type: "type.hcl" }, + { startIndex: 6, type: "" }, + { startIndex: 7, type: "string.hcl" }, + { startIndex: 15, type: "" }, + { startIndex: 16, type: "delimiter.curly.hcl" }, + ], + }, + { + line: 'value = "${aws_instance.web.private_ip}"', + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "operator.hcl" }, + { startIndex: 7, type: "" }, + { startIndex: 8, type: "string.hcl" }, + { startIndex: 9, type: "delimiter.hcl" }, + { startIndex: 11, type: "variable.hcl" }, + { startIndex: 23, type: "delimiter.hcl" }, + { startIndex: 24, type: "variable.hcl" }, + { startIndex: 27, type: "delimiter.hcl" }, + { startIndex: 28, type: "variable.hcl" }, + { startIndex: 38, type: "delimiter.hcl" }, + { startIndex: 39, type: "string.hcl" }, + ], + }, + { + line: "}", + tokens: [{ startIndex: 0, type: "delimiter.curly.hcl" }], + }, + ], + + [ + { + line: 'foo = [1, 2, "foo"]', + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "delimiter.square.hcl" }, + { startIndex: 7, type: "number.hcl" }, + { startIndex: 8, type: "delimiter.hcl" }, + { startIndex: 9, type: "" }, + { startIndex: 10, type: "number.hcl" }, + { startIndex: 11, type: "delimiter.hcl" }, + { startIndex: 12, type: "" }, + { startIndex: 13, type: "string.hcl" }, + { startIndex: 18, type: "delimiter.square.hcl" }, + ], + }, + ], + [ + { + line: 'foo = [1, 2, "foo",]', + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "delimiter.square.hcl" }, + { startIndex: 7, type: "number.hcl" }, + { startIndex: 8, type: "delimiter.hcl" }, + { startIndex: 9, type: "" }, + { startIndex: 10, type: "number.hcl" }, + { startIndex: 11, type: "delimiter.hcl" }, + { startIndex: 12, type: "" }, + { startIndex: 13, type: "string.hcl" }, + { startIndex: 18, type: "delimiter.hcl" }, + { startIndex: 19, type: "delimiter.square.hcl" }, + ], + }, + ], + /* + default = { + "eu-west-1": "ami-b1cf19c6", + } + */ + [ + { + line: "default = {", + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 7, type: "" }, + { startIndex: 8, type: "operator.hcl" }, + { startIndex: 9, type: "" }, + { startIndex: 10, type: "delimiter.curly.hcl" }, + ], + }, + { + line: ' "eu-west-1": "ami-b1cf19c6",', + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "string.hcl" }, + { startIndex: 13, type: "operator.hcl" }, + { startIndex: 14, type: "" }, + { startIndex: 15, type: "string.hcl" }, + { startIndex: 29, type: "delimiter.hcl" }, + ], + }, + { + line: "}", + tokens: [{ startIndex: 0, type: "delimiter.curly.hcl" }], + }, + ], + [ + { + line: 'resource "foo" "bar" {}', + tokens: [ + { startIndex: 0, type: "type.hcl" }, + { startIndex: 8, type: "" }, + { startIndex: 9, type: "string.hcl" }, + { startIndex: 14, type: "" }, + { startIndex: 15, type: "string.hcl" }, + { startIndex: 20, type: "" }, + { startIndex: 21, type: "delimiter.curly.hcl" }, + ], + }, + ], + [ + { + line: 'foo = "bar"', + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "string.hcl" }, + ], + }, + ], + [ + { + line: "bar = 7", + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "number.hcl" }, + ], + }, + ], + [ + { + line: "baz = [1,2,3]", + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "delimiter.square.hcl" }, + { startIndex: 7, type: "number.hcl" }, + { startIndex: 8, type: "delimiter.hcl" }, + { startIndex: 9, type: "number.hcl" }, + { startIndex: 10, type: "delimiter.hcl" }, + { startIndex: 11, type: "number.hcl" }, + { startIndex: 12, type: "delimiter.square.hcl" }, + ], + }, + ], + [ + { + line: "foo = -12", + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "operator.hcl" }, + { startIndex: 7, type: "number.hcl" }, + ], + }, + ], + [ + { + line: "bar = 3.14159", + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "number.float.hcl" }, + ], + }, + ], + [ + { + line: "foo = true", + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "keyword.true.hcl" }, + ], + }, + ], + [ + { + line: "bar = false", + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "keyword.false.hcl" }, + ], + }, + ], + /* + resource = [{ + foo = [{ + bar = {} + }] + }] + */ + [ + { + line: "resource = [{", + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 8, type: "" }, + { startIndex: 9, type: "operator.hcl" }, + { startIndex: 10, type: "" }, + { startIndex: 11, type: "delimiter.square.hcl" }, + { startIndex: 12, type: "delimiter.curly.hcl" }, + ], + }, + { + line: " foo = [{", + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "variable.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "operator.hcl" }, + { startIndex: 7, type: "" }, + { startIndex: 8, type: "delimiter.square.hcl" }, + { startIndex: 9, type: "delimiter.curly.hcl" }, + ], + }, + { + line: " bar = {}", + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 4, type: "variable.hcl" }, + { startIndex: 7, type: "" }, + { startIndex: 8, type: "operator.hcl" }, + { startIndex: 9, type: "" }, + { startIndex: 10, type: "delimiter.curly.hcl" }, + ], + }, + { + line: " }]", + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "delimiter.curly.hcl" }, + { startIndex: 3, type: "delimiter.square.hcl" }, + ], + }, + { + line: "}]", + tokens: [ + { startIndex: 0, type: "delimiter.curly.hcl" }, + { startIndex: 1, type: "delimiter.square.hcl" }, + ], + }, + ], + [ + { + line: 'bar = "${file("bing/bong.txt")}"', + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "string.hcl" }, + { startIndex: 7, type: "delimiter.hcl" }, + { startIndex: 9, type: "type.hcl" }, + { startIndex: 13, type: "delimiter.parenthesis.hcl" }, + { startIndex: 14, type: "string.hcl" }, + { startIndex: 29, type: "delimiter.parenthesis.hcl" }, + { startIndex: 30, type: "delimiter.hcl" }, + { startIndex: 31, type: "string.hcl" }, + ], + }, + ], + [ + { + line: 'foo-bar="baz"', + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 7, type: "operator.hcl" }, + { startIndex: 8, type: "string.hcl" }, + ], + }, + ], + /* + key "foo/" { + policy = "write" + } + */ + [ + { + line: 'key "foo/" {', + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "string.hcl" }, + { startIndex: 10, type: "" }, + { startIndex: 11, type: "delimiter.curly.hcl" }, + ], + }, + { + line: ' policy = "write"', + tokens: [ + { startIndex: 0, type: "" }, + { startIndex: 2, type: "variable.hcl" }, + { startIndex: 8, type: "" }, + { startIndex: 9, type: "operator.hcl" }, + { startIndex: 10, type: "" }, + { startIndex: 11, type: "string.hcl" }, + ], + }, + { + line: "}", + tokens: [{ startIndex: 0, type: "delimiter.curly.hcl" }], + }, + ], + [ + { + line: 'foo = "bar\\"baz\\\\n"', + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "string.hcl" }, + { startIndex: 10, type: "string.escape.hcl" }, + { startIndex: 12, type: "string.hcl" }, + { startIndex: 15, type: "string.escape.hcl" }, + { startIndex: 17, type: "string.hcl" }, + ], + }, + ], + [ + { + line: 'bar = "new\\nline"', + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "string.hcl" }, + { startIndex: 10, type: "string.escape.hcl" }, + { startIndex: 12, type: "string.hcl" }, + ], + }, + ], + [ + { + line: 'qux = "back\\\\slash"', + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "string.hcl" }, + { startIndex: 11, type: "string.escape.hcl" }, + { startIndex: 13, type: "string.hcl" }, + ], + }, + ], + [ + { + line: 'qax = "slash\\\\:colon"', + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 3, type: "" }, + { startIndex: 4, type: "operator.hcl" }, + { startIndex: 5, type: "" }, + { startIndex: 6, type: "string.hcl" }, + { startIndex: 12, type: "string.escape.hcl" }, + { startIndex: 14, type: "string.hcl" }, + ], + }, + ], + [ + { + line: 'nested = "${HH\\\\:mm\\\\:ss}"', + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 6, type: "" }, + { startIndex: 7, type: "operator.hcl" }, + { startIndex: 8, type: "" }, + { startIndex: 9, type: "string.hcl" }, + { startIndex: 10, type: "delimiter.hcl" }, + { startIndex: 12, type: "variable.hcl" }, + { startIndex: 14, type: "" }, + { startIndex: 16, type: "operator.hcl" }, + { startIndex: 17, type: "variable.hcl" }, + { startIndex: 19, type: "" }, + { startIndex: 21, type: "operator.hcl" }, + { startIndex: 22, type: "variable.hcl" }, + { startIndex: 24, type: "delimiter.hcl" }, + { startIndex: 25, type: "string.hcl" }, + ], + }, + ], + [ + { + line: 'nestedquotes = "${"\\"stringwrappedinquotes\\""}"', + tokens: [ + { startIndex: 0, type: "variable.hcl" }, + { startIndex: 12, type: "" }, + { startIndex: 13, type: "operator.hcl" }, + { startIndex: 14, type: "" }, + { startIndex: 15, type: "string.hcl" }, + { startIndex: 16, type: "delimiter.hcl" }, + { startIndex: 18, type: "string.hcl" }, + { startIndex: 19, type: "string.escape.hcl" }, + { startIndex: 21, type: "string.hcl" }, + { startIndex: 42, type: "string.escape.hcl" }, + { startIndex: 44, type: "string.hcl" }, + { startIndex: 45, type: "delimiter.hcl" }, + { startIndex: 46, type: "string.hcl" }, + ], + }, + ], + /* + foo = <{ - defaultToken: '', - tokenPostfix: '.tf', + defaultToken: "", + tokenPostfix: ".hcl", - keywords: [ - 'var', - 'local', - 'module', - 'data', - 'path', - 'terraform', - 'resource', - 'provider', - 'variable', - 'output', - 'locals', - 'any', - 'string', - 'number', - 'bool', - 'abs', - 'ceil', - 'floor', - 'log', - 'max', - 'min', - 'pow', - 'signum', - 'chomp', - 'format', - 'formatlist', - 'indent', - 'join', - 'lower', - 'regex', - 'regexall', - 'replace', - 'split', - 'strrev', - 'substr', - 'title', - 'trimspace', - 'upper', - 'chunklist', - 'coalesce', - 'coalescelist', - 'compact', - 'concat', - 'contains', - 'distinct', - 'element', - 'flatten', - 'index', - 'keys', - 'length', - 'list', - 'lookup', - 'map', - 'matchkeys', - 'merge', - 'range', - 'reverse', - 'setintersection', - 'setproduct', - 'setunion', - 'slice', - 'sort', - 'transpose', - 'values', - 'zipmap', - 'base64decode', - 'base64encode', - 'base64gzip', - 'csvdecode', - 'jsondecode', - 'jsonencode', - 'urlencode', - 'yamldecode', - 'yamlencode', - 'abspath', - 'dirname', - 'pathexpand', - 'basename', - 'file', - 'fileexists', - 'fileset', - 'filebase64', - 'templatefile', - 'formatdate', - 'timeadd', - 'timestamp', - 'base64sha256', - 'base64sha512', - 'bcrypt', - 'filebase64sha256', - 'filebase64sha512', - 'filemd5', - 'filemd1', - 'filesha256', - 'filesha512', - 'md5', - 'rsadecrypt', - 'sha1', - 'sha256', - 'sha512', - 'uuid', - 'uuidv5', - 'cidrhost', - 'cidrnetmask', - 'cidrsubnet', - 'tobool', - 'tolist', - 'tomap', - 'tonumber', - 'toset', - 'tostring', - 'true', - 'false', - 'null', - 'if ', - 'else ', - 'endif ', - 'for ', - 'in', - 'endfor' - ], + keywords: [ + "var", + "local", + "path", + "for_each", + "any", + "string", + "number", + "bool", + "true", + "false", + "null", + "if ", + "else ", + "endif ", + "for ", + "in", + "endfor", + ], - operators: [ - '>=', - '<=', - '==', - '!=', - '+', - '-', - '*', - '/', - '%', - '&&', - '||', - '!', - '<', - '>', - '?', - '...', - ':' - ], + operators: [ + "=", + ">=", + "<=", + "==", + "!=", + "+", + "-", + "*", + "/", + "%", + "&&", + "||", + "!", + "<", + ">", + "?", + "...", + ":", + ], - // we include these common regular expressions - symbols: /[=>](?!@symbols)/, '@brackets'], - [ - /@symbols/, - { - cases: { - '@operators': 'delimiter', - '@default': '' - } - } - ], - - // numbers - [/\d*\d+[eE]([\-+]?\d+)?/, 'number.float'], - [/\d*\.\d+([eE][\-+]?\d+)?/, 'number.float'], - [/\d[\d']*/, 'number'], - [/\d/, 'number'], - - // delimiter: after number because of .\d floats - [/[;,.]/, 'delimiter'], - - // strings - [/"([^"\\]|\\.)*$/, 'string.invalid'], // non-teminated string - [/"/, 'string', '@string'] - ], - - whitespace: [ - [/[ \t\r\n]+/, ''], - [/\/\*/, 'comment', '@comment'], - [/\/\/.*$/, 'comment'], - [/#.*$/, 'comment'] - ], - - comment: [ - [/[^\/*]+/, 'comment'], - [/\*\//, 'comment', '@pop'], - [/[\/*]/, 'comment'] - ], - - string: [ - [/[^\\"]+/, 'string'], - [/@escapes/, 'string.escape'], - [/\\./, 'string.escape.invalid'], - [/"/, 'string', '@pop'] - ] - } + symbols: /[=>](?!@symbols)/, "@brackets"], + [ + /@symbols/, + { + cases: { + "@operators": "operator", + "@default": "", + }, + }, + ], + // numbers + [/\d*\d+[eE]([\-+]?\d+)?/, "number.float"], + [/\d*\.\d+([eE][\-+]?\d+)?/, "number.float"], + [/\d[\d']*/, "number"], + [/\d/, "number"], + [/[;,.]/, "delimiter"], // delimiter: after number because of .\d floats + // strings + [/"/, "string", "@string"], // this will include expressions + [/'/, "invalid"], + ], + heredoc: [ + [ + /<<[-]*\s*["]?([\w\-]+)["]?/, + { token: 'string.heredoc.delimiter', next: '@heredocBody.$1' }, + ], + ], + heredocBody: [ + [ + /^([\w\-]+)$/, + { + cases: { + '$1==$S2': [{ token: 'string.heredoc.delimiter', next: '@popall' }], + '@default': 'string.heredoc', + }, + }, + ], + [/./, 'string.heredoc'], + ], + whitespace: [ + [/[ \t\r\n]+/, ""], + [/\/\*/, "comment", "@comment"], + [/\/\/.*$/, "comment"], + [/#.*$/, "comment"], + ], + comment: [ + [/[^\/*]+/, "comment"], + [/\*\//, "comment", "@pop"], + [/[\/*]/, "comment"], + ], + string: [ + [/\$\{/, { token: "delimiter", next: "@stringExpression" }], + [/[^\\"\$]+/, "string"], + [/@escapes/, "string.escape"], + [/\\./, "string.escape.invalid"], + [/"/, "string", "@popall"], + ], + stringInsideExpression: [ + [/[^\\"]+/, "string"], + [/@escapes/, "string.escape"], + [/\\./, "string.escape.invalid"], + [/"/, "string", "@pop"], + ], + stringExpression: [ + [/\}/, { token: "delimiter", next: "@pop" }], + [/"/, "string", "@stringInsideExpression"], + { include: "@terraform" }, + ], + }, };