diff --git a/src/Bicep.Cli.IntegrationTests/GenerateParamsCommandTests.cs b/src/Bicep.Cli.IntegrationTests/GenerateParamsCommandTests.cs index 2080ee78597..b6a216730c5 100644 --- a/src/Bicep.Cli.IntegrationTests/GenerateParamsCommandTests.cs +++ b/src/Bicep.Cli.IntegrationTests/GenerateParamsCommandTests.cs @@ -93,7 +93,7 @@ public async Task GenerateParams_ImplicitOutputFormatJson_ExplicitIncludeParamsA ""contentVersion"": ""1.0.0.0"", ""parameters"": { ""name"": { - ""value"": """" + ""value"": ""sampleparameter"" } } }".ReplaceLineEndings()); @@ -125,7 +125,7 @@ public async Task GenerateParams_ImplicitOutputFormatJson_ExplicitIncludeParamsA ""contentVersion"": ""1.0.0.0"", ""parameters"": { ""optional"": { - ""value"": """" + ""value"": ""sampleparameter"" }, ""required"": { ""value"": """" @@ -767,5 +767,103 @@ public async Task GenerateParams_ExplicitOutputFormatBicepParam_ExplicitIncludeP ".ReplaceLineEndings()); } } + + [TestMethod] + public async Task GenerateParams_ImplicitOutputFormatJson_ExplicitIncludeParamsAll_OneObjectParameterWithDefaultValue_Should_Succeed() + { + var bicep = $@"param storageAccountConfig object = {{ + name: 'defaultStorageAccount' + sku: 'Standard_LRS' + kind: 'StorageV2' + }}"; + + var tempDirectory = FileHelper.GetUniqueTestOutputPath(TestContext); + Directory.CreateDirectory(tempDirectory); + + var bicepFilePath = Path.Combine(tempDirectory, "built.bicep"); + File.WriteAllText(bicepFilePath, bicep); + + var (output, error, result) = await Bicep("generate-params", "--include-params", "all", bicepFilePath); + + var content = File.ReadAllText(Path.Combine(tempDirectory, "built.parameters.json")).ReplaceLineEndings(); + + content.Should().Be(@"{ + ""$schema"": ""https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#"", + ""contentVersion"": ""1.0.0.0"", + ""parameters"": { + ""storageAccountConfig"": { + ""value"": { + ""name"": ""defaultStorageAccount"", + ""sku"": ""Standard_LRS"", + ""kind"": ""StorageV2"" + } + } + } +}".ReplaceLineEndings()); + } + + [TestMethod] + public async Task GenerateParams_ImplicitOutputFormatJson_ExplicitIncludeParamsAll_OneArrayParameterWithDefaultValue_Should_Succeed() + { + var bicep = $@"param foo array = [1, 2, 3]"; + var tempDirectory = FileHelper.GetUniqueTestOutputPath(TestContext); + Directory.CreateDirectory(tempDirectory); + var bicepFilePath = Path.Combine(tempDirectory, "built.bicep"); + File.WriteAllText(bicepFilePath, bicep); + var (output, error, result) = await Bicep("generate-params", "--include-params", "all", bicepFilePath); + var content = File.ReadAllText(Path.Combine(tempDirectory, "built.parameters.json")).ReplaceLineEndings(); + content.Should().Be(@"{ + ""$schema"": ""https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#"", + ""contentVersion"": ""1.0.0.0"", + ""parameters"": { + ""foo"": { + ""value"": [ + 1, + 2, + 3 + ] + } + } +}".ReplaceLineEndings()); + } + + [TestMethod] + public async Task GenerateParams_ImplicitOutputFormatJson_ExplicitIncludeParamsAll_OneParameterWithDefaultValueAsInvalidBicepSyntax_Should_Succeed() + { + var bicep = $@"param foo string = newGuid()"; + var tempDirectory = FileHelper.GetUniqueTestOutputPath(TestContext); + Directory.CreateDirectory(tempDirectory); + var bicepFilePath = Path.Combine(tempDirectory, "built.bicep"); + File.WriteAllText(bicepFilePath, bicep); + var (output, error, result) = await Bicep("generate-params", "--include-params", "all", bicepFilePath); + var content = File.ReadAllText(Path.Combine(tempDirectory, "built.parameters.json")).ReplaceLineEndings(); + + content.Should().Be(@"{ + ""$schema"": ""https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#"", + ""contentVersion"": ""1.0.0.0"", + ""parameters"": { + ""foo"": { + ""value"": """" + } + } +}".ReplaceLineEndings()); + } + + [TestMethod] + public async Task GenerateParams_ExplicitOutputFormatBicepParam_ExplicitIncludeParamsAll_OneParameterWithDefaultValueAsInvalidBicepSyntax_Should_Succeed() + { + var bicep = $@"param foo string = newGuid()"; + var tempDirectory = FileHelper.GetUniqueTestOutputPath(TestContext); + Directory.CreateDirectory(tempDirectory); + var bicepFilePath = Path.Combine(tempDirectory, "built.bicep"); + File.WriteAllText(bicepFilePath, bicep); + var (output, error, result) = await Bicep("generate-params", "--output-format", "bicepparam", "--include-params", "all", bicepFilePath); + var content = File.ReadAllText(Path.Combine(tempDirectory, "built.bicepparam")).ReplaceLineEndings(); + content.Should().Be(@"using './built.bicep' + +param foo = ? /* TODO : please fix the value assigned to this parameter `newGuid()` */ + +".ReplaceLineEndings()); + } } } diff --git a/src/Bicep.Core/Emit/PlaceholderParametersBicepParamWriter.cs b/src/Bicep.Core/Emit/PlaceholderParametersBicepParamWriter.cs index c6d7e47c451..03f40afb6d0 100644 --- a/src/Bicep.Core/Emit/PlaceholderParametersBicepParamWriter.cs +++ b/src/Bicep.Core/Emit/PlaceholderParametersBicepParamWriter.cs @@ -30,7 +30,7 @@ public void Write(TextWriter writer, string existingContent) var result = filteredParameterDeclarations .OfType() - .Select(e => new ParameterAssignmentSyntax(e.Keyword, e.Name, SyntaxFactory.AssignmentToken, this.GetValueForParameter(e))) + .Select(e => new ParameterAssignmentSyntax(e.Keyword, e.Name, SyntaxFactory.AssignmentToken, GetValueForParameter(e))) .SelectMany(e => new List() { e, SyntaxFactory.NewlineToken }); var processedSyntaxList = new List() @@ -47,14 +47,61 @@ public void Write(TextWriter writer, string existingContent) writer.WriteLine(output); } - private SyntaxBase GetValueForParameter(ParameterDeclarationSyntax syntax) + private static SyntaxBase CheckFunctionCallsInObjectSyntax(ObjectSyntax objectSyntax) + { + var value = objectSyntax.Properties.Select(e => + { + if (e.Value is FunctionCallSyntax valueAsFunctionCallSyntax) + { + return SyntaxFactory.CreateObjectProperty((e.Key as IdentifierSyntax)?.IdentifierName ?? "", CreateCommentSyntaxForFunctionCallSyntax(valueAsFunctionCallSyntax.Name.IdentifierName)); + } + else if (e.Value is ArraySyntax valueAsFunctionArraySyntax) + { + var value = valueAsFunctionArraySyntax.Items.Select(f => + { + if (f.Value is FunctionCallSyntax valueAsFunctionCallSyntax) + { + return SyntaxFactory.CreateArrayItem(CreateCommentSyntaxForFunctionCallSyntax(valueAsFunctionCallSyntax.Name.IdentifierName)); + } + + return f; + }).ToList(); + + return SyntaxFactory.CreateObjectProperty((e.Key as IdentifierSyntax)?.IdentifierName ?? "", SyntaxFactory.CreateArray(value)); + } + else if (e.Value is ObjectSyntax valueAsObjectSyntax) + { + var syntax = CheckFunctionCallsInObjectSyntax(valueAsObjectSyntax); + var item = SyntaxFactory.CreateObjectProperty((e.Key as IdentifierSyntax)?.IdentifierName ?? "", syntax); + return item; + } + + return e; + }).ToList(); + + return SyntaxFactory.CreateObject(value); + } + + private static SyntaxBase CreateCommentSyntaxForFunctionCallSyntax(string functionName, bool isJsonParamWriter = false) + { + if (isJsonParamWriter) + { + return SyntaxFactory.CreateStringLiteral(""); + } + else + { + return SyntaxFactory.CreateInvalidSyntaxWithComment($" TODO : please fix the value assigned to this parameter `{functionName}()` "); + } + } + + public static SyntaxBase GetValueForParameter(ParameterDeclarationSyntax syntax, bool isJsonParamWriter = false) { var defaultValue = SyntaxHelper.TryGetDefaultValue(syntax); if (defaultValue != null) { if (defaultValue is FunctionCallSyntax defaultValueAsFunctionCall) { - return CreateCommentSyntaxForFunctionCallSyntax(defaultValueAsFunctionCall.Name.IdentifierName); + return CreateCommentSyntaxForFunctionCallSyntax(defaultValueAsFunctionCall.Name.IdentifierName, isJsonParamWriter); } else if (defaultValue is ArraySyntax defaultValueAsArray) { @@ -62,10 +109,10 @@ private SyntaxBase GetValueForParameter(ParameterDeclarationSyntax syntax) { if (e.Value is FunctionCallSyntax valueAsFunctionCall) { - return SyntaxFactory.CreateArrayItem(CreateCommentSyntaxForFunctionCallSyntax(valueAsFunctionCall.Name.IdentifierName)); + return SyntaxFactory.CreateArrayItem(CreateCommentSyntaxForFunctionCallSyntax(valueAsFunctionCall.Name.IdentifierName, isJsonParamWriter)).Value; } - return e; + return e.Value; }).ToList(); return SyntaxFactory.CreateArray(value); @@ -102,45 +149,5 @@ private SyntaxBase GetValueForParameter(ParameterDeclarationSyntax syntax) return SyntaxFactory.NewlineToken; } - - private SyntaxBase CheckFunctionCallsInObjectSyntax(ObjectSyntax objectSyntax) - { - var value = objectSyntax.Properties.Select(e => - { - if (e.Value is FunctionCallSyntax valueAsFunctionCallSyntax) - { - return SyntaxFactory.CreateObjectProperty((e.Key as IdentifierSyntax)?.IdentifierName ?? "", CreateCommentSyntaxForFunctionCallSyntax(valueAsFunctionCallSyntax.Name.IdentifierName)); - } - else if (e.Value is ArraySyntax valueAsFunctionArraySyntax) - { - var value = valueAsFunctionArraySyntax.Items.Select(f => - { - if (f.Value is FunctionCallSyntax valueAsFunctionCallSyntax) - { - return SyntaxFactory.CreateArrayItem(CreateCommentSyntaxForFunctionCallSyntax(valueAsFunctionCallSyntax.Name.IdentifierName)); - } - - return f; - }).ToList(); - - return SyntaxFactory.CreateObjectProperty((e.Key as IdentifierSyntax)?.IdentifierName ?? "", SyntaxFactory.CreateArray(value)); - } - else if (e.Value is ObjectSyntax valueAsObjectSyntax) - { - var syntax = CheckFunctionCallsInObjectSyntax(valueAsObjectSyntax); - var item = SyntaxFactory.CreateObjectProperty((e.Key as IdentifierSyntax)?.IdentifierName ?? "", syntax); - return item; - } - - return e; - }).ToList(); - - return SyntaxFactory.CreateObject(value); - } - - private SyntaxBase CreateCommentSyntaxForFunctionCallSyntax(string functionName) - { - return SyntaxFactory.CreateInvalidSyntaxWithComment($" TODO : please fix the value assigned to this parameter `{functionName}()` "); - } } } diff --git a/src/Bicep.Core/Emit/PlaceholderParametersJsonWriter.cs b/src/Bicep.Core/Emit/PlaceholderParametersJsonWriter.cs index 485ac9a7514..c862eb3f377 100644 --- a/src/Bicep.Core/Emit/PlaceholderParametersJsonWriter.cs +++ b/src/Bicep.Core/Emit/PlaceholderParametersJsonWriter.cs @@ -3,6 +3,7 @@ using System.Collections.Immutable; using Bicep.Core.Emit.Options; +using Bicep.Core.Parsing; using Bicep.Core.Semantics; using Bicep.Core.Syntax; using Microsoft.WindowsAzure.ResourceStack.Common.Json; @@ -97,25 +98,17 @@ private JToken GenerateTemplate(string contentVersion) { jsonWriter.WritePropertyName(parameterSymbol.Name); + var value = PlaceholderParametersBicepParamWriter.GetValueForParameter(parameterSymbol.DeclaringParameter, true); + jsonWriter.WriteStartObject(); - switch (parameterSymbol.Type.Name) + + // Emit value property only if the value is not a newline token. + // GetValueForParameter return TokenType.NewLine when syntax of assigning the value is not correct + if (value is not Token { Type: TokenType.NewLine}) { - case "string": - emitter.EmitProperty("value", ""); - break; - case "int": - emitter.EmitProperty("value", () => jsonWriter.WriteValue(0)); - break; - case "bool": - emitter.EmitProperty("value", () => jsonWriter.WriteValue(false)); - break; - case "object": - emitter.EmitProperty("value", () => { jsonWriter.WriteStartObject(); jsonWriter.WriteEndObject(); }); - break; - case "array": - emitter.EmitProperty("value", () => { jsonWriter.WriteStartArray(); jsonWriter.WriteEndArray(); }); - break; + emitter.EmitProperty("value", value); } + jsonWriter.WriteEndObject(); }