diff --git a/src/hcl/hcl.test.ts b/src/hcl/hcl.test.ts new file mode 100644 index 00000000..bd1d9ea2 --- /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', + tokenPostfix: '.hcl', keywords: [ 'var', 'local', - 'module', - 'data', 'path', - 'terraform', - 'resource', - 'provider', - 'variable', - 'output', - 'locals', + 'for_each', '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', @@ -162,6 +57,7 @@ export const language = { ], operators: [ + '=', '>=', '<=', '==', @@ -181,28 +77,45 @@ export const language = { ':' ], - // we include these common regular expressions symbols: /[=>](?!@symbols)/, '@brackets'], @@ -210,44 +123,72 @@ export const language = { /@symbols/, { cases: { - '@operators': 'delimiter', + '@operators': 'operator', '@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'], - + [/[;,.]/, 'delimiter'], // delimiter: after number because of .\d floats // strings - [/"([^"\\]|\\.)*$/, 'string.invalid'], // non-teminated string - [/"/, 'string', '@string'] + [/"/, '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' } ] } };