Skip to content

Commit

Permalink
Cache snippet calculations (Azure#8967)
Browse files Browse the repository at this point in the history
* Cache snippet calculations

* Address PR feedback
  • Loading branch information
anthony-c-martin authored Nov 10, 2022
1 parent 741f204 commit 83bbe03
Show file tree
Hide file tree
Showing 264 changed files with 1,461 additions and 1,347 deletions.
4 changes: 2 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ We are integrating the Bicep examples into the [Azure QuickStart Templates](http
* [ ] I have a snippet that is either a single, generic resource or multi resource that uses [parent-child syntax](https://docs.microsoft.com/azure/azure-resource-manager/bicep/child-resource-name-type)
* [ ] I have checked that there is not an equivalent snippet already submitted
* [ ] I have used camelCasing unless I have a justification to use another casing style
* [ ] I have placeholders values that correspond to their property names (e.g. `dnsPrefix: 'dnsPrefix'`), unless it's a property that MUST be changed or parameterized in order to deploy. In that case, I use 'REQUIRED' e.g. [keyData](./src/Bicep.LangServer/Snippets/Templates/res-aks-cluster.bicep#L26)
* [ ] I have my symbolic name as the first tab stop ($1) in the snippet. e.g. [res-aks-cluster.bicep](./src/Bicep.LangServer/Snippets/Templates/res-aks-cluster.bicep)
* [ ] I have placeholders values that correspond to their property names (e.g. `dnsPrefix: 'dnsPrefix'`), unless it's a property that MUST be changed or parameterized in order to deploy. In that case, I use 'REQUIRED' e.g. [keyData](./src/Bicep.LangServer/Files/SnippetTemplates/res-aks-cluster.bicep#L26)
* [ ] I have my symbolic name as the first tab stop ($1) in the snippet. e.g. [res-aks-cluster.bicep](./src/Bicep.LangServer/Files/SnippetTemplates/res-aks-cluster.bicep)
* [ ] I have a resource name property equal to "name"
* [ ] If applicable, I have set the `location` property to `location: /*${<id>:location}*/'location'` (not `resourceGroup().location`) where `<id>` is a placeholder id, and added `param location string` to the test's main.bicep file so that the resulting main.combined.bicep file used in the tests compiles without errors
* [ ] I have verified that the snippet deploys correctly when used in the context of an actual bicep file
Expand Down
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,15 @@ We are integrating the Bicep examples into the [Azure QuickStart Templates](http
If you'd like to contribute to the collection of snippets:

* A snippet should either be a single, generic resource or follow [parent-child syntax](https://docs.microsoft.com/azure/azure-resource-manager/bicep/child-resource-name-type). Ensure your snippet meets this criteria.
* Add a Bicep file to [`./src/Bicep.LangServer/Snippets/Templates`](./src/Bicep.LangServer/Snippets/Templates) using the naming convention res-RESOURCENAME.bicep
* Add a Bicep file to [`./src/Bicep.LangServer/Files/SnippetTemplates`](./src/Bicep.LangServer/Files/SnippetTemplates) using the naming convention res-RESOURCENAME.bicep
* The file name without extension will be used as the label.
* A single line comment at the top of the file will be used as the description.
* E.g. [`res-aks-cluster.bicep`](./src/Bicep.LangServer/Snippets/Templates/res-aks-cluster.bicep) results in the following label and description:
* E.g. [`res-aks-cluster.bicep`](./src/Bicep.LangServer/Files/SnippetTemplates/res-aks-cluster.bicep) results in the following label and description:
![](./docs/images/snippet-template.png)
* Add the Bicep resource declaration.
* Add placeholders for tab stops. Placeholders must be enclosed within comment and followed by default text e.g. `/*${1:foo}*/foo`. The placeholder text will be inserted and selected such that it can be easily changed. The symbolic name should be the first tab stop.
* To add a multi-choice placeholder, the syntax is a comma separated enumeration of values, enclosed with the pipe-character, for example `${1|one,two,three|}`. When the snippet is inserted and the placeholder selected, choices will prompt the user to pick one of the values. [More info on snippet syntax](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#snippet_syntax)
* Property placeholder values should correspond to their property names (e.g. dnsPrefix: 'dnsPrefix'), unless it's a property that MUST be changed or parameterized in order to deploy. In that case, use 'REQUIRED' e.g. [keyData](./src/Bicep.LangServer/Snippets/Templates/res-aks-cluster.bicep#L26)
* Property placeholder values should correspond to their property names (e.g. dnsPrefix: 'dnsPrefix'), unless it's a property that MUST be changed or parameterized in order to deploy. In that case, use 'REQUIRED' e.g. [keyData](./src/Bicep.LangServer/Files/SnippetTemplates/res-aks-cluster.bicep#L26)
* Snippet with parent-child syntax, should have parent resource declared first. Do not add placeholder for parent resource symbolic name.
* Add a new folder in the following directory, for an integration test that validates snippet completion: [`./src/Bicep.LangServer.IntegrationTests/Files/SnippetTemplates`](./src/Bicep.LangServer.IntegrationTests/Files/SnippetTemplates)
* The folder name should match the snippet label/prefix.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ private class AadTypeProvider : IResourceTypeProvider
new TypeProperty("uniqueName", LanguageConstants.String, TypePropertyFlags.Required | TypePropertyFlags.SystemProperty),
new TypeProperty("appId", LanguageConstants.String, TypePropertyFlags.ReadOnly),
}, null)),
}.ToImmutableDictionary(x => x.TypeReference, ResourceTypeReferenceComparer.Instance);
}.ToImmutableDictionary(x => x.TypeReference);

public ResourceType? TryGenerateFallbackType(NamespaceType declaringNamespace, ResourceTypeReference reference, ResourceTypeGenerationFlags flags)
=> null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private class StorageTypeProvider : IResourceTypeProvider
new TypeProperty("name", LanguageConstants.String, TypePropertyFlags.Required),
new TypeProperty("base64Content", LanguageConstants.String, TypePropertyFlags.Required),
}, null)),
}.ToImmutableDictionary(x => x.TypeReference, ResourceTypeReferenceComparer.Instance);
}.ToImmutableDictionary(x => x.TypeReference);

public ResourceType? TryGenerateFallbackType(NamespaceType declaringNamespace, ResourceTypeReference reference, ResourceTypeGenerationFlags flags)
=> null;
Expand Down
2 changes: 1 addition & 1 deletion src/Bicep.Core.IntegrationTests/ParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public void Parser_should_produce_expected_syntax(DataSet dataSet)
public void Params_Parser_should_produce_expected_syntax(BaselineData_Bicepparam baselineData)
{
var data = baselineData.GetData(TestContext);
var program = ParamsParserHelper.ParamsParse(data.Parameters.EmbeddedFile.Contents);
var program = ParserHelper.ParamsParse(data.Parameters.EmbeddedFile.Contents);
var syntaxList = SyntaxCollectorVisitor.Build(program);
var syntaxByParent = syntaxList.ToLookup(x => x.Parent);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public void PrintProgram_AnyProgram_ShouldProduceExpectedOutput(DataSet dataSet)
public void PrintProgram_ParamsFile_ShouldProduceExpectedOutput(BaselineData_Bicepparam baselineData)
{
var data = baselineData.GetData(TestContext);
var program = ParamsParserHelper.ParamsParse(data.Parameters.EmbeddedFile.Contents);
var program = ParserHelper.ParamsParse(data.Parameters.EmbeddedFile.Contents);
var options = new PrettyPrintOptions(NewlineOption.Auto, IndentKindOption.Space, 2, true);

var formattedOutput = PrettyPrinter.PrintProgram(program, options);
Expand Down
8 changes: 4 additions & 4 deletions src/Bicep.Core.UnitTests/Parsing/ParamsParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public void LiteralExpressionsShouldParseCorrectly(string text, string expected,
[DataRow("param mystr = 'hello world' \n")]
public void TestParsingParameterAssignment(String text)
{
var programSyntax = ParamsParserHelper.ParamsParse(text);
var programSyntax = ParserHelper.ParamsParse(text);

programSyntax.Children.OfType<ParameterAssignmentSyntax>().Should().HaveCount(1);
}
Expand All @@ -38,7 +38,7 @@ public void TestParsingParameterAssignment(String text)
[DataRow("param myobj = {\nname : 'vm1'\nlocation : 'westus'\n} \n")]
public void TestParameterObjectAssignment(String text)
{
var programSyntax = ParamsParserHelper.ParamsParse(text);
var programSyntax = ParserHelper.ParamsParse(text);

programSyntax.Children.OfType<ParameterAssignmentSyntax>().Should().HaveCount(1);
}
Expand All @@ -47,7 +47,7 @@ public void TestParameterObjectAssignment(String text)
[DataRow("param myarr = [ 1\n2\n3\n4\n5 ] \n")]
public void TestParameterArrayAssignment(String text)
{
var programSyntax = ParamsParserHelper.ParamsParse(text);
var programSyntax = ParserHelper.ParamsParse(text);

programSyntax.Children.OfType<ParameterAssignmentSyntax>().Should().HaveCount(1);
}
Expand All @@ -56,7 +56,7 @@ public void TestParameterArrayAssignment(String text)
[DataRow("using './main.bicep' \n")]
public void TestParsingUsingKeyword(String text)
{
var programSyntax = ParamsParserHelper.ParamsParse(text);
var programSyntax = ParserHelper.ParamsParse(text);

programSyntax.Children.OfType<UsingDeclarationSyntax>().Should().HaveCount(1);
}
Expand Down

This file was deleted.

28 changes: 28 additions & 0 deletions src/Bicep.Core.UnitTests/Resource/ResourceTypeReferenceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,34 @@ public void Combine_CombinesValidTypeSegments(string baseTypeText, string childT
actual.Should().NotBeNull();
actual!.FormatName().Should().BeEquivalentTo(expected);
}
[DataTestMethod]
[DataRow("Microsoft.Compute/virtualMachines@2019-06-01", "Microsoft.Compute/virtualMachines@2019-06-01")] // same string
[DataRow("Microsoft.Compute/virtualMachines@2019-06-01", "Microsoft.Compute/vIrTuAlMaChiNeS@2019-06-01")] // different type casing
[DataRow("Microsoft.Compute/virtualMachines@2019-06-01-preview", "Microsoft.Compute/vIrTuAlMaChiNeS@2019-06-01-PREVIEW")] // different api version casing
[DataRow("Microsoft.Compute/virtualMachines@2019-06-01", "Microsoft.COMPUTE/vIrTuAlMaChiNeS@2019-06-01")] // different provider name casing
[DataRow("Microsoft.Compute/virtualMachines/extensions@2019-06-01", "Microsoft.COMPUTE/vIrTuAlMaChiNeS/eXtEnSIONs@2019-06-01")] // different child name casing
public void Equals_and_GetHashCode_should_determine_equality_correctly_for_equal_types(string first, string second)
{
var firstReference = ResourceTypeReference.Parse(first);
var secondReference = ResourceTypeReference.Parse(second);

firstReference.Equals(secondReference).Should().BeTrue($"'{firstReference}' and '{secondReference}' should be considered equal");
firstReference.GetHashCode().Should().Be(secondReference.GetHashCode(), $"calculated hash codes of '{firstReference}' and '{secondReference}' should be equal");
}

[DataTestMethod]
[DataRow("Microsoft.Compute/virtualMachines@2019-06-01", "Microsoft.Compute/virtualMachines@2019-07-01")] // different api version
[DataRow("Microsoft.Compute/virtualMachines@2019-06-01", "Microsoft.Compute/virtualMachineScaleSets@2019-06-01")] // different type
[DataRow("Microsoft.Compute/virtualMachines@2019-06-01", "Microsoft.Copmute/virtualMachines@2019-06-01")] // different provider name
[DataRow("Microsoft.Compute/virtualMachines@2019-06-01", "Microsoft.COMPUTE/vIrTuAlMaChiNeS/extensions@2019-06-01")] // different number of child types
[DataRow("Microsoft.Compute/virtualMachines/extensions@2019-06-01", "Microsoft.COMPUTE/virtualMachines/etxensions@2019-06-01")] // different child type
public void Equals_should_determine_equality_correctly_for_inequal_types(string first, string second)
{
var firstReference = ResourceTypeReference.Parse(first);
var secondReference = ResourceTypeReference.Parse(second);

firstReference.Equals(secondReference).Should().BeFalse($"'{firstReference}' and '{secondReference}' should not be considered equal");
}
}
}

39 changes: 0 additions & 39 deletions src/Bicep.Core.UnitTests/Utils/ParamsParserHelper.cs

This file was deleted.

29 changes: 21 additions & 8 deletions src/Bicep.Core.UnitTests/Utils/ParserHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Collections.Generic;
using System.Linq;
using System.Text;
using Bicep.Core.Parsing;
using Bicep.Core.Syntax;
using FluentAssertions;
Expand All @@ -18,25 +19,37 @@ public static ProgramSyntax Parse(string text)
return parser.Program();
}

public static ProgramSyntax ParamsParse(string text)
{
var parser = new ParamsParser(text);

return parser.Program();
}

public static SyntaxBase ParseExpression(string text, ExpressionFlags expressionFlags = ExpressionFlags.AllowComplexLiterals) => new Parser(text).Expression(expressionFlags);

public static (string file, IReadOnlyList<int> cursors) GetFileWithCursors(string fileWithCursors, char cursor)
{
var bicepFile = fileWithCursors.Replace(cursor.ToString(), "");
=> GetFileWithCursors(fileWithCursors, cursor.ToString());

public static (string file, IReadOnlyList<int> cursors) GetFileWithCursors(string fileWithCursors, string cursor)
{
var fileWithoutCursors = fileWithCursors.Replace(cursor, "");
var cursors = new List<int>();
for (var i = 0; i < fileWithCursors.Length; i++)
var position = 0;

while ((position = fileWithCursors.IndexOf(cursor, position)) != -1)
{
if (fileWithCursors[i] == cursor)
{
cursors.Add(i - cursors.Count);
}
cursors.Add(position - (cursors.Count * cursor.Length));
position += cursor.Length;
}

return (bicepFile, cursors);
return (fileWithoutCursors, cursors);
}

public static (string file, int cursor) GetFileWithSingleCursor(string fileWithCursors, char cursor)
=> GetFileWithSingleCursor(fileWithCursors, cursor.ToString());

public static (string file, int cursor) GetFileWithSingleCursor(string fileWithCursors, string cursor)
{
var (file, cursors) = GetFileWithCursors(fileWithCursors, cursor);
cursors.Should().HaveCount(1);
Expand Down
5 changes: 1 addition & 4 deletions src/Bicep.Core.UnitTests/Utils/TestTypeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ private class TestResourceTypeLoader : IAzResourceTypeLoader

public TestResourceTypeLoader(IEnumerable<ResourceTypeComponents> resourceTypes)
{
this.resourceTypes = resourceTypes.ToImmutableDictionary(
x => x.TypeReference,
x => x,
ResourceTypeReferenceComparer.Instance);
this.resourceTypes = resourceTypes.ToImmutableDictionary(x => x.TypeReference);
}

public ResourceTypeComponents LoadType(ResourceTypeReference reference)
Expand Down
Loading

0 comments on commit 83bbe03

Please sign in to comment.