Skip to content

Commit a19d66c

Browse files
Implement decompilation for the 'scope' property (#1190)
1 parent 0b7427f commit a19d66c

File tree

3 files changed

+152
-27
lines changed

3 files changed

+152
-27
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
param hostingPlanName string
2+
param location string = resourceGroup().location
3+
4+
var siteName_var = 'ExampleSite${uniqueString(resourceGroup().id)}'
5+
6+
resource hostingPlanName_resource 'Microsoft.Web/serverfarms@2020-06-01' = {
7+
name: hostingPlanName
8+
location: location
9+
sku: {
10+
tier: 'Free'
11+
name: 'f1'
12+
capacity: 0
13+
}
14+
properties: {
15+
targetWorkerCount: 1
16+
}
17+
}
18+
19+
resource siteName 'Microsoft.Web/sites@2020-06-01' = {
20+
name: siteName_var
21+
location: location
22+
properties: {
23+
serverFarmId: hostingPlanName
24+
}
25+
dependsOn: [
26+
hostingPlanName_resource
27+
]
28+
}
29+
30+
resource siteLock 'Microsoft.Authorization/locks@2016-09-01' = {
31+
name: 'siteLock'
32+
properties: {
33+
level: 'CanNotDelete'
34+
notes: 'Site should not be deleted.'
35+
}
36+
scope: siteName
37+
dependsOn: [
38+
siteName
39+
]
40+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3+
"contentVersion": "1.0.0.0",
4+
"parameters": {
5+
"hostingPlanName": {
6+
"type": "string"
7+
},
8+
"location": {
9+
"type": "string",
10+
"defaultValue": "[resourceGroup().location]"
11+
}
12+
},
13+
"variables": {
14+
"siteName": "[concat('ExampleSite', uniqueString(resourceGroup().id))]"
15+
},
16+
"resources": [
17+
{
18+
"type": "Microsoft.Web/serverfarms",
19+
"apiVersion": "2020-06-01",
20+
"name": "[parameters('hostingPlanName')]",
21+
"location": "[parameters('location')]",
22+
"sku": {
23+
"tier": "Free",
24+
"name": "f1",
25+
"capacity": 0
26+
},
27+
"properties": {
28+
"targetWorkerCount": 1
29+
}
30+
},
31+
{
32+
"type": "Microsoft.Web/sites",
33+
"apiVersion": "2020-06-01",
34+
"name": "[variables('siteName')]",
35+
"location": "[parameters('location')]",
36+
"dependsOn": [
37+
"[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]"
38+
],
39+
"properties": {
40+
"serverFarmId": "[parameters('hostingPlanName')]"
41+
}
42+
},
43+
{
44+
"type": "Microsoft.Authorization/locks",
45+
"apiVersion": "2016-09-01",
46+
"name": "siteLock",
47+
"scope": "[concat('Microsoft.Web/sites/', variables('siteName'))]",
48+
"dependsOn": [
49+
"[resourceId('Microsoft.Web/sites', variables('siteName'))]"
50+
],
51+
"properties": {
52+
"level": "CanNotDelete",
53+
"notes": "Site should not be deleted."
54+
}
55+
}
56+
]
57+
}

src/Bicep.Decompiler/TemplateConverter.cs

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -639,28 +639,28 @@ StringSyntax createFakeModulePath(string templateLinkExpression)
639639
return SyntaxHelpers.CreateStringLiteral(filePath);
640640
}
641641

642-
private SyntaxBase? ProcessCondition(JObject resource)
643-
{
644-
JProperty? conditionProperty = TemplateHelpers.GetProperty(resource, "condition");
645-
646-
if (conditionProperty == null)
647-
{
648-
return null;
649-
}
650-
651-
SyntaxBase conditionExpression = ParseJToken(conditionProperty.Value);
652-
653-
if (conditionExpression is not ParenthesizedExpressionSyntax)
654-
{
655-
conditionExpression = new ParenthesizedExpressionSyntax(
656-
SyntaxHelpers.CreateToken(TokenType.LeftParen, "("),
657-
conditionExpression,
658-
SyntaxHelpers.CreateToken(TokenType.RightParen, ")"));
659-
}
660-
661-
return new IfConditionSyntax(
662-
SyntaxHelpers.CreateToken(TokenType.Identifier, "if"),
663-
conditionExpression);
642+
private SyntaxBase? ProcessCondition(JObject resource)
643+
{
644+
JProperty? conditionProperty = TemplateHelpers.GetProperty(resource, "condition");
645+
646+
if (conditionProperty == null)
647+
{
648+
return null;
649+
}
650+
651+
SyntaxBase conditionExpression = ParseJToken(conditionProperty.Value);
652+
653+
if (conditionExpression is not ParenthesizedExpressionSyntax)
654+
{
655+
conditionExpression = new ParenthesizedExpressionSyntax(
656+
SyntaxHelpers.CreateToken(TokenType.LeftParen, "("),
657+
conditionExpression,
658+
SyntaxHelpers.CreateToken(TokenType.RightParen, ")"));
659+
}
660+
661+
return new IfConditionSyntax(
662+
SyntaxHelpers.CreateToken(TokenType.Identifier, "if"),
663+
conditionExpression);
664664
}
665665

666666
private SyntaxBase? ProcessDependsOn(JObject resource)
@@ -707,7 +707,7 @@ StringSyntax createFakeModulePath(string templateLinkExpression)
707707
return SyntaxHelpers.CreateArray(syntaxItems);
708708
}
709709

710-
private SyntaxBase? TryGetScopeProperty(JObject resource)
710+
private SyntaxBase? TryModuleGetScopeProperty(JObject resource)
711711
{
712712
var subscriptionId = TemplateHelpers.GetProperty(resource, "subscriptionId");
713713
var resourceGroup = TemplateHelpers.GetProperty(resource, "resourceGroup");
@@ -789,7 +789,7 @@ private SyntaxBase ParseModule(JObject resource, string typeString, string nameS
789789
var properties = new List<ObjectPropertySyntax>();
790790
properties.Add(SyntaxHelpers.CreateObjectProperty("name", ParseJToken(nameString)));
791791

792-
var scope = TryGetScopeProperty(resource);
792+
var scope = TryModuleGetScopeProperty(resource);
793793
if (scope is not null)
794794
{
795795
properties.Add(SyntaxHelpers.CreateObjectProperty("scope", scope));
@@ -854,7 +854,28 @@ private SyntaxBase ParseModule(JObject resource, string typeString, string nameS
854854
SyntaxHelpers.CreateObject(properties));
855855
}
856856

857-
public SyntaxBase ParseResource(JObject template, JToken value)
857+
private SyntaxBase? TryGetResourceScopeProperty(JObject resource)
858+
{
859+
if (TemplateHelpers.GetProperty(resource, "scope") is not JProperty scopeProperty)
860+
{
861+
return null;
862+
}
863+
864+
var scopeExpression = ExpressionHelpers.ParseExpression(scopeProperty.Value.Value<string>());
865+
if (TryLookupResource(scopeExpression) is string resourceName)
866+
{
867+
return SyntaxHelpers.CreateIdentifier(resourceName);
868+
}
869+
870+
if (TryParseStringExpression(scopeExpression) is SyntaxBase parsedSyntax)
871+
{
872+
return parsedSyntax;
873+
}
874+
875+
throw new ConversionFailedException($"Parsing failed for property value {scopeProperty}", scopeProperty);
876+
}
877+
878+
public SyntaxBase ParseResource(JToken value)
858879
{
859880
var resource = (value as JObject) ?? throw new ConversionFailedException($"Incorrect resource format", value);
860881

@@ -886,6 +907,7 @@ public SyntaxBase ParseResource(JObject template, JToken value)
886907
"properties",
887908
"dependsOn",
888909
"comments",
910+
"scope",
889911
}, StringComparer.OrdinalIgnoreCase);
890912

891913
var resourcePropsToOmit = new HashSet<string>(new [] {
@@ -894,10 +916,10 @@ public SyntaxBase ParseResource(JObject template, JToken value)
894916
"apiVersion",
895917
"dependsOn",
896918
"comments",
919+
"scope",
897920
}, StringComparer.OrdinalIgnoreCase);
898921

899922
TemplateHelpers.AssertUnsupportedProperty(resource, "copy", "The 'copy' property is not supported");
900-
TemplateHelpers.AssertUnsupportedProperty(resource, "scope", "The 'scope' property is not supported");
901923

902924
var topLevelProperties = new List<ObjectPropertySyntax>();
903925
foreach (var prop in resource.Properties())
@@ -921,6 +943,12 @@ public SyntaxBase ParseResource(JObject template, JToken value)
921943
topLevelProperties.Add(SyntaxHelpers.CreateObjectProperty(prop.Name, valueSyntax));
922944
}
923945

946+
var scope = TryGetResourceScopeProperty(resource);
947+
if (scope is not null)
948+
{
949+
topLevelProperties.Add(SyntaxHelpers.CreateObjectProperty("scope", scope));
950+
}
951+
924952
var dependsOn = ProcessDependsOn(resource);
925953
if (dependsOn != null)
926954
{
@@ -1025,7 +1053,7 @@ private ProgramSyntax Parse()
10251053

10261054
AddSyntaxBlock(statements, parameters.Select(ParseParam), false);
10271055
AddSyntaxBlock(statements, variables.Select(ParseVariable), false);
1028-
AddSyntaxBlock(statements, flattenedResources.Select(r => ParseResource(template, r)), true);
1056+
AddSyntaxBlock(statements, flattenedResources.Select(ParseResource), true);
10291057
AddSyntaxBlock(statements, outputs.Select(ParseOutput), false);
10301058

10311059
return new ProgramSyntax(

0 commit comments

Comments
 (0)