Improving terraform hcl

This commit is contained in:
Hugo Fonseca 2020-09-02 23:38:01 +01:00
parent 3efc637414
commit 9d8859a82d
3 changed files with 1400 additions and 239 deletions

1201
src/hcl/hcl.test.ts Normal file

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,7 @@ import ILanguage = monaco.languages.IMonarchLanguage;
export const conf: IRichLanguageConfiguration = { export const conf: IRichLanguageConfiguration = {
comments: { comments: {
lineComment: '//', lineComment: '//',
blockComment: ['/*', '*/'] blockComment: ['/*', '*/'],
}, },
brackets: [ brackets: [
['{', '}'], ['{', '}'],
@ -23,231 +23,191 @@ export const conf: IRichLanguageConfiguration = {
{ open: '[', close: ']' }, { open: '[', close: ']' },
{ open: '(', close: ')' }, { open: '(', close: ')' },
{ open: '"', close: '"', notIn: ['string'] }, { open: '"', close: '"', notIn: ['string'] },
{ open: "'", close: "'", notIn: ['string', 'comment'] }
], ],
surroundingPairs: [ surroundingPairs: [
{ open: '{', close: '}' }, { open: '{', close: '}' },
{ open: '[', close: ']' }, { open: '[', close: ']' },
{ open: '(', close: ')' }, { open: '(', close: ')' },
{ open: '"', close: '"' }, { open: '"', close: '"' },
{ open: "'", close: "'" }
] ]
}; };
export const language = <ILanguage>{ export const language = <ILanguage>{
defaultToken: '', defaultToken: "",
tokenPostfix: '.tf', tokenPostfix: ".hcl",
keywords: [ keywords: [
'var', "var",
'local', "local",
'module', "path",
'data', "for_each",
'path', "any",
'terraform', "string",
'resource', "number",
'provider', "bool",
'variable', "true",
'output', "false",
'locals', "null",
'any', "if ",
'string', "else ",
'number', "endif ",
'bool', "for ",
'abs', "in",
'ceil', "endfor",
'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'
], ],
operators: [ operators: [
'>=', "=",
'<=', ">=",
'==', "<=",
'!=', "==",
'+', "!=",
'-', "+",
'*', "-",
'/', "*",
'%', "/",
'&&', "%",
'||', "&&",
'!', "||",
'<', "!",
'>', "<",
'?', ">",
'...', "?",
':' "...",
":",
], ],
// we include these common regular expressions
symbols: /[=><!~?:&|+\-*\/\^%]+/, symbols: /[=><!~?:&|+\-*\/\^%]+/,
escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/, escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
variable: /\${?[\w]+}?/, terraformFunctions: /(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)/,
terraformMainBlocks: /(module|data|terraform|resource|provider|variable|output|locals)/,
// The main tokenizer for our languages
tokenizer: { tokenizer: {
root: [ root: [
// identifiers and keywords // highlight main blocks
[ [
/[a-zA-Z_]\w*/, /^@terraformMainBlocks([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)(\{)/,
[
"type",
"",
"string",
"",
"string",
"",
"@brackets",
],
],
// highlight all the remaining blocks
[
/(\w+[ \t]+)([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)(\{)/,
[
"identifier",
"",
"string",
"",
"string",
"",
"@brackets",
],
],
// highlight block
[
/(\w+[ \t]+)([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)([\w-]+|"[\w-]+"|)(=)(\{)/,
[
"identifier",
"",
"string",
"",
"operator",
"",
"@brackets",
],
],
// terraform general highlight - shared with expressions
{ include: "@terraform" },
],
terraform : [
// highlight terraform functions
[/@terraformFunctions(\()/, ['type', '@brackets']],
// all other words are variables or keywords
[
/[a-zA-Z_]\w*-*/, // must work with variables such as foo-bar and also with negative numbers
{ {
cases: { cases: {
'@keywords': { token: 'keyword.$0' }, "@keywords": { token: "keyword.$0" },
'@default': 'identifier' "@default": "variable",
} },
} },
], ],
{ include: "@whitespace" },
// whitespace { include: '@heredoc' },
{ include: '@whitespace' },
// delimiters and operators // delimiters and operators
[/[{}()\[\]]/, '@brackets'], [/[{}()\[\]]/, "@brackets"],
[/[<>](?!@symbols)/, '@brackets'], [/[<>](?!@symbols)/, "@brackets"],
[ [
/@symbols/, /@symbols/,
{ {
cases: { cases: {
'@operators': 'delimiter', "@operators": "operator",
'@default': '' "@default": "",
} },
} },
], ],
// numbers // numbers
[/\d*\d+[eE]([\-+]?\d+)?/, 'number.float'], [/\d*\d+[eE]([\-+]?\d+)?/, "number.float"],
[/\d*\.\d+([eE][\-+]?\d+)?/, 'number.float'], [/\d*\.\d+([eE][\-+]?\d+)?/, "number.float"],
[/\d[\d']*/, 'number'], [/\d[\d']*/, "number"],
[/\d/, 'number'], [/\d/, "number"],
[/[;,.]/, "delimiter"], // delimiter: after number because of .\d floats
// delimiter: after number because of .\d floats
[/[;,.]/, 'delimiter'],
// strings // strings
[/"([^"\\]|\\.)*$/, 'string.invalid'], // non-teminated string [/"/, "string", "@string"], // this will include expressions
[/"/, 'string', '@string'] [/'/, "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: [ whitespace: [
[/[ \t\r\n]+/, ''], [/[ \t\r\n]+/, ""],
[/\/\*/, 'comment', '@comment'], [/\/\*/, "comment", "@comment"],
[/\/\/.*$/, 'comment'], [/\/\/.*$/, "comment"],
[/#.*$/, 'comment'] [/#.*$/, "comment"],
], ],
comment: [ comment: [
[/[^\/*]+/, 'comment'], [/[^\/*]+/, "comment"],
[/\*\//, 'comment', '@pop'], [/\*\//, "comment", "@pop"],
[/[\/*]/, 'comment'] [/[\/*]/, "comment"],
], ],
string: [ string: [
[/[^\\"]+/, 'string'], [/\$\{/, { token: "delimiter", next: "@stringExpression" }],
[/@escapes/, 'string.escape'], [/[^\\"\$]+/, "string"],
[/\\./, 'string.escape.invalid'], [/@escapes/, "string.escape"],
[/"/, 'string', '@pop'] [/\\./, "string.escape.invalid"],
] [/"/, "string", "@popall"],
} ],
stringInsideExpression: [
[/[^\\"]+/, "string"],
[/@escapes/, "string.escape"],
[/\\./, "string.escape.invalid"],
[/"/, "string", "@pop"],
],
stringExpression: [
[/\}/, { token: "delimiter", next: "@pop" }],
[/"/, "string", "@stringInsideExpression"],
{ include: "@terraform" },
],
},
}; };