From 748bb9ac6c0bd3710dd4e731ed95e68aa1e892d8 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Thu, 5 Aug 2021 23:07:00 +0200 Subject: [PATCH] Bicep: Resolved TODO + improvements (#3028) --- components/prism-bicep.js | 64 ++++++++++++++-- components/prism-bicep.min.js | 2 +- tests/languages/bicep/comment_feature.test | 18 +++++ tests/languages/bicep/datatype_feature.test | 47 ++++++++++++ tests/languages/bicep/decorator_feature.test | 42 ++++++++++- tests/languages/bicep/function_feature.test | 79 +++++++++++++------- tests/languages/bicep/keyword_feature.test | 12 +-- tests/languages/bicep/string_feature.test | 62 ++++++++++++++- tests/languages/bicep/var_feature.test | 2 +- 9 files changed, 282 insertions(+), 46 deletions(-) create mode 100644 tests/languages/bicep/comment_feature.test create mode 100644 tests/languages/bicep/datatype_feature.test diff --git a/components/prism-bicep.js b/components/prism-bicep.js index 08ffdcdf92..36317a46ea 100644 --- a/components/prism-bicep.js +++ b/components/prism-bicep.js @@ -14,16 +14,64 @@ Prism.languages.bicep = { greedy: true } ], - 'string': { - // this doesn't handle string interpolalation or multiline strings as yet - pattern: /'(?:\\.|[^'\\\r\n])*'/, - greedy: true + + 'property': [ + { + pattern: /([\r\n][ \t]*)[a-z_]\w*(?=[ \t]*:)/i, + lookbehind: true + }, + { + pattern: /([\r\n][ \t]*)'(?:\\.|\$(?!\{)|[^'\\\r\n$])*'(?=[ \t]*:)/, + lookbehind: true, + greedy: true + } + ], + 'string': [ + { + pattern: /'''[^'][\s\S]*?'''/, + greedy: true + }, + { + pattern: /(^|[^\\'])'(?:\\.|\$(?!\{)|[^'\\\r\n$])*'/, + lookbehind: true, + greedy: true, + } + ], + 'interpolated-string': { + pattern: /(^|[^\\'])'(?:\\.|\$(?:(?!\{)|\{[^{}\r\n]*\})|[^'\\\r\n$])*'/, + lookbehind: true, + greedy: true, + inside: { + 'interpolation': { + pattern: /\$\{[^{}\r\n]*\}/, + inside: { + 'expression': { + pattern: /(^\$\{)[\s\S]+(?=\}$)/, + lookbehind: true + }, + 'punctuation': /^\$\{|\}$/, + } + }, + 'string': /[\s\S]+/ + } }, - 'number': /(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:E[+-]?\d+)?/i, + + 'datatype': { + pattern: /(\b(?:output|param)\b[ \t]+\w+[ \t]+)\w+\b/, + lookbehind: true, + alias: 'class-name' + }, + 'boolean': /\b(?:true|false)\b/, - 'keyword': /\b(?:targetScope|resource|module|param|var|output|for|in|if|existing|null)\b/, // https://github.com/Azure/bicep/blob/114a3251b4e6e30082a58729f19a8cc4e374ffa6/src/textmate/bicep.tmlanguage#L184 - 'function': /\b(?:array|concat|contains|createArray|empty|first|intersection|last|length|max|min|range|skip|take|union)(?:\$|\b)/, // https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions-array + // https://github.com/Azure/bicep/blob/114a3251b4e6e30082a58729f19a8cc4e374ffa6/src/textmate/bicep.tmlanguage#L184 + 'keyword': /\b(?:targetScope|resource|module|param|var|output|for|in|if|existing|null)\b/, + + 'decorator': /@\w+\b/, + 'function': /\b[a-z_]\w*(?=[ \t]*\()/i, + + 'number': /(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:E[+-]?\d+)?/i, 'operator': /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/, 'punctuation': /[{}[\];(),.:]/, - 'decorator': /@\w+\b/ }; + +Prism.languages.bicep['interpolated-string'].inside['interpolation'].inside['expression'].inside = Prism.languages.bicep; diff --git a/components/prism-bicep.min.js b/components/prism-bicep.min.js index c04dde1f00..7be82b9a97 100644 --- a/components/prism-bicep.min.js +++ b/components/prism-bicep.min.js @@ -1 +1 @@ -Prism.languages.bicep={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/'(?:\\.|[^'\\\r\n])*'/,greedy:!0},number:/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:E[+-]?\d+)?/i,boolean:/\b(?:true|false)\b/,keyword:/\b(?:targetScope|resource|module|param|var|output|for|in|if|existing|null)\b/,function:/\b(?:array|concat|contains|createArray|empty|first|intersection|last|length|max|min|range|skip|take|union)(?:\$|\b)/,operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/,punctuation:/[{}[\];(),.:]/,decorator:/@\w+\b/}; \ No newline at end of file +Prism.languages.bicep={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],property:[{pattern:/([\r\n][ \t]*)[a-z_]\w*(?=[ \t]*:)/i,lookbehind:!0},{pattern:/([\r\n][ \t]*)'(?:\\.|\$(?!\{)|[^'\\\r\n$])*'(?=[ \t]*:)/,lookbehind:!0,greedy:!0}],string:[{pattern:/'''[^'][\s\S]*?'''/,greedy:!0},{pattern:/(^|[^\\'])'(?:\\.|\$(?!\{)|[^'\\\r\n$])*'/,lookbehind:!0,greedy:!0}],"interpolated-string":{pattern:/(^|[^\\'])'(?:\\.|\$(?:(?!\{)|\{[^{}\r\n]*\})|[^'\\\r\n$])*'/,lookbehind:!0,greedy:!0,inside:{interpolation:{pattern:/\$\{[^{}\r\n]*\}/,inside:{expression:{pattern:/(^\$\{)[\s\S]+(?=\}$)/,lookbehind:!0},punctuation:/^\$\{|\}$/}},string:/[\s\S]+/}},datatype:{pattern:/(\b(?:output|param)\b[ \t]+\w+[ \t]+)\w+\b/,lookbehind:!0,alias:"class-name"},boolean:/\b(?:true|false)\b/,keyword:/\b(?:targetScope|resource|module|param|var|output|for|in|if|existing|null)\b/,decorator:/@\w+\b/,function:/\b[a-z_]\w*(?=[ \t]*\()/i,number:/(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:E[+-]?\d+)?/i,operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/,punctuation:/[{}[\];(),.:]/},Prism.languages.bicep["interpolated-string"].inside.interpolation.inside.expression.inside=Prism.languages.bicep; \ No newline at end of file diff --git a/tests/languages/bicep/comment_feature.test b/tests/languages/bicep/comment_feature.test new file mode 100644 index 0000000000..3d3a84ce63 --- /dev/null +++ b/tests/languages/bicep/comment_feature.test @@ -0,0 +1,18 @@ +// this is a comment + +/* this +is a +multi line comment */ + +/* so is +this */ + +---------------------------------------------------- + +[ + ["comment", "// this is a comment"], + + ["comment", "/* this\r\nis a\r\nmulti line comment */"], + + ["comment", "/* so is\r\nthis */"] +] diff --git a/tests/languages/bicep/datatype_feature.test b/tests/languages/bicep/datatype_feature.test new file mode 100644 index 0000000000..882430f6fd --- /dev/null +++ b/tests/languages/bicep/datatype_feature.test @@ -0,0 +1,47 @@ +param myString string +param myInt int +param myBool bool +param myObject object +param myArray array + +output myHardcodedOutput int = 42 +output myLoopyOutput array = [for myItem in myArray: { + myProperty: myItem.myOtherProperty +}] + +---------------------------------------------------- + +[ + ["keyword", "param"], " myString ", ["datatype", "string"], + ["keyword", "param"], " myInt ", ["datatype", "int"], + ["keyword", "param"], " myBool ", ["datatype", "bool"], + ["keyword", "param"], " myObject ", ["datatype", "object"], + ["keyword", "param"], " myArray ", ["datatype", "array"], + + ["keyword", "output"], + " myHardcodedOutput ", + ["datatype", "int"], + ["operator", "="], + ["number", "42"], + + ["keyword", "output"], + " myLoopyOutput ", + ["datatype", "array"], + ["operator", "="], + ["punctuation", "["], + ["keyword", "for"], + " myItem ", + ["keyword", "in"], + " myArray", + ["operator", ":"], + ["punctuation", "{"], + + ["property", "myProperty"], + ["operator", ":"], + " myItem", + ["punctuation", "."], + "myOtherProperty\r\n", + + ["punctuation", "}"], + ["punctuation", "]"] +] diff --git a/tests/languages/bicep/decorator_feature.test b/tests/languages/bicep/decorator_feature.test index 524b557ba3..36d29bc222 100644 --- a/tests/languages/bicep/decorator_feature.test +++ b/tests/languages/bicep/decorator_feature.test @@ -6,16 +6,54 @@ param demoPassword string ]) param demoEnum string +@minLength(3) +@maxLength(24) +@description('Name of the storage account') +param storageAccountName string = concat(uniqueString(resourceGroup().id), 'sa') + ---------------------------------------------------- [ ["decorator", "@secure"], ["punctuation", "("], ["punctuation", ")"], - ["keyword", "param"], " demoPassword string\r\n", + ["keyword", "param"], " demoPassword ", ["datatype", "string"], ["decorator", "@allowed"], ["punctuation", "("], ["punctuation", "["], ["string", "'one'"], ["string", "'two'"], ["punctuation", "]"], ["punctuation", ")"], - ["keyword", "param"], " demoEnum string" + ["keyword", "param"], " demoEnum ", ["datatype", "string"], + + ["decorator", "@minLength"], + ["punctuation", "("], + ["number", "3"], + ["punctuation", ")"], + + ["decorator", "@maxLength"], + ["punctuation", "("], + ["number", "24"], + ["punctuation", ")"], + + ["decorator", "@description"], + ["punctuation", "("], + ["string", "'Name of the storage account'"], + ["punctuation", ")"], + + ["keyword", "param"], + " storageAccountName ", + ["datatype", "string"], + ["operator", "="], + ["function", "concat"], + ["punctuation", "("], + ["function", "uniqueString"], + ["punctuation", "("], + ["function", "resourceGroup"], + ["punctuation", "("], + ["punctuation", ")"], + ["punctuation", "."], + "id", + ["punctuation", ")"], + ["punctuation", ","], + ["string", "'sa'"], + ["punctuation", ")"] ] ---------------------------------------------------- diff --git a/tests/languages/bicep/function_feature.test b/tests/languages/bicep/function_feature.test index 4fab9203e8..91b75bf547 100644 --- a/tests/languages/bicep/function_feature.test +++ b/tests/languages/bicep/function_feature.test @@ -1,37 +1,60 @@ -array -concat -contains -createArray -empty -first -intersection -last -length -max -min -range -skip -take -union +param location string = resourceGroup().location +var hostingPlanName = 'hostingplan${uniqueString(resourceGroup().id)}' + +array(parameters('stringToConvert')) +createArray(1, 2, 3) ---------------------------------------------------- [ + ["keyword", "param"], + " location ", + ["datatype", "string"], + ["operator", "="], + ["function", "resourceGroup"], + ["punctuation", "("], + ["punctuation", ")"], + ["punctuation", "."], + "location\r\n", + + ["keyword", "var"], + " hostingPlanName ", + ["operator", "="], + ["interpolated-string", [ + ["string", "'hostingplan"], + ["interpolation", [ + ["punctuation", "${"], + ["expression", [ + ["function", "uniqueString"], + ["punctuation", "("], + ["function", "resourceGroup"], + ["punctuation", "("], + ["punctuation", ")"], + ["punctuation", "."], + "id", + ["punctuation", ")"] + ]], + ["punctuation", "}"] + ]], + ["string", "'"] + ]], + ["function", "array"], - ["function", "concat"], - ["function", "contains"], + ["punctuation", "("], + ["function", "parameters"], + ["punctuation", "("], + ["string", "'stringToConvert'"], + ["punctuation", ")"], + ["punctuation", ")"], + ["function", "createArray"], - ["function", "empty"], - ["function", "first"], - ["function", "intersection"], - ["function", "last"], - ["function", "length"], - ["function", "max"], - ["function", "min"], - ["function", "range"], - ["function", "skip"], - ["function", "take"], - ["function", "union"] + ["punctuation", "("], + ["number", "1"], + ["punctuation", ","], + ["number", "2"], + ["punctuation", ","], + ["number", "3"], + ["punctuation", ")"] ] ---------------------------------------------------- diff --git a/tests/languages/bicep/keyword_feature.test b/tests/languages/bicep/keyword_feature.test index 738ee5b875..9a548ae875 100644 --- a/tests/languages/bicep/keyword_feature.test +++ b/tests/languages/bicep/keyword_feature.test @@ -31,7 +31,7 @@ null ["punctuation", ")"], ["punctuation", "{"], - "\r\n name", + ["property", "name"], ["operator", ":"], " logAnalyticsWsName\r\n", @@ -43,14 +43,15 @@ null ["operator", "="], ["punctuation", "{"], - "\r\n name", + ["property", "name"], ["operator", ":"], ["string", "'cosmosDbDeploy'"], ["punctuation", "}"], ["keyword", "param"], - " env string\r\n", + " env ", + ["datatype", "string"], ["keyword", "var"], " oneNumber ", @@ -58,7 +59,8 @@ null ["number", "123"], ["keyword", "output"], - " databaseName string ", + " databaseName ", + ["datatype", "string"], ["operator", "="], " cosmosdbDatabaseName\r\n", @@ -69,7 +71,7 @@ null ["operator", ":"], ["punctuation", "{"], - "\r\n\tipAddressOrRange", + ["property", "ipAddressOrRange"], ["operator", ":"], " item\r\n", diff --git a/tests/languages/bicep/string_feature.test b/tests/languages/bicep/string_feature.test index b9a6f9861d..7d69ba79e1 100644 --- a/tests/languages/bicep/string_feature.test +++ b/tests/languages/bicep/string_feature.test @@ -1,11 +1,71 @@ +'' +'hello!' +'what\'s up?' +'steve' +'hello ${name}!' +'😁\u{1F642}' 'Microsoft.Web/sites/config@2020-12-01' 'https://${frontDoorName}.azurefd.net/.auth/login/aad/callback' +'''hello!''' +var myVar2 = ''' +hello!''' +''' +hello! +''' +''' + this + is + indented +''' + +''' +comments // are included +/* because everything is read as-is */ +''' + +'''interpolation +is ${blocked}''' + ---------------------------------------------------- [ + ["string", "''"], + ["string", "'hello!'"], + ["string", "'what\\'s up?'"], + ["string", "'steve'"], + ["interpolated-string", [ + ["string", "'hello "], + ["interpolation", [ + ["punctuation", "${"], + ["expression", ["name"]], + ["punctuation", "}"] + ]], + ["string", "!'"] + ]], + ["string", "'😁\\u{1F642}'"], ["string", "'Microsoft.Web/sites/config@2020-12-01'"], - ["string", "'https://${frontDoorName}.azurefd.net/.auth/login/aad/callback'"] + ["interpolated-string", [ + ["string", "'https://"], + ["interpolation", [ + ["punctuation", "${"], + ["expression", ["frontDoorName"]], + ["punctuation", "}"] + ]], + ["string", ".azurefd.net/.auth/login/aad/callback'"] + ]], + + ["string", "'''hello!'''"], + ["keyword", "var"], + " myVar2 ", + ["operator", "="], + ["string", "'''\r\nhello!'''"], + ["string", "'''\r\nhello!\r\n'''"], + ["string", "'''\r\n this\r\n is\r\n indented\r\n'''"], + + ["string", "'''\r\ncomments // are included\r\n/* because everything is read as-is */\r\n'''"], + + ["string", "'''interpolation\r\nis ${blocked}'''"] ] ---------------------------------------------------- diff --git a/tests/languages/bicep/var_feature.test b/tests/languages/bicep/var_feature.test index 481a9ac811..87c0a888e2 100644 --- a/tests/languages/bicep/var_feature.test +++ b/tests/languages/bicep/var_feature.test @@ -16,7 +16,7 @@ var oneObject = { ["number", "123"], ["punctuation", "]"], ["keyword", "var"], " oneObject ", ["operator", "="], ["punctuation", "{"], - "\r\n\tabc", ["operator", ":"], ["number", "123"], + ["property", "abc"], ["operator", ":"], ["number", "123"], ["punctuation", "}"] ]