/// <summary>
        /// Generate the HCL tfvars file
        /// </summary>
        static string GenerateHclVariables(JObject parsedProperties, IImmutableVariableDictionary variableDictionary, Metadata metadata)
        {
            var properties = GetPropertiesAsList(parsedProperties, metadata, GetHclVariableValue);
            var asStr      = string.Join("\n", properties);

            return(variableDictionary.EvaluateIgnoringErrors(asStr) !);
        }
        /// <summary>
        /// Generate the JSON tfvars.json file
        /// </summary>
        static string GenerateJsonVariables(JObject parsedProperties, IImmutableVariableDictionary variableDictionary, Metadata metadata)
        {
            var properties = GetPropertiesAsList(parsedProperties, metadata, GetJsonVariableValue);
            var asJson     = "{" + string.Join(",", properties) + "}";

            return(variableDictionary.EvaluateIgnoringErrors(asJson) !);
        }
        /// <summary>
        /// When variables are supplied from the UI (i.e. not from a package), all values are strings.
        /// So maps and lists are just strings, even though they should be objects.
        ///
        /// This method find variables that should be objects, and parses the strings sent in
        /// into real objects.
        /// </summary>
        public static string ConvertStringPropsToObjects(
            TerraformTemplateFormat terraformTemplateFormat,
            IImmutableVariableDictionary variableDictionary,
            string variables,
            Metadata metadata)
        {
            var parsedProperties = JObject.Parse(variables);

            RemoveEmptyVariables(parsedProperties);

            switch (terraformTemplateFormat)
            {
            case TerraformTemplateFormat.Json:
                return(GenerateJsonVariables(parsedProperties, variableDictionary, metadata));

            case TerraformTemplateFormat.Hcl:
                return(GenerateHclVariables(parsedProperties, variableDictionary, metadata));

            default:
                throw new ArgumentOutOfRangeException(nameof(terraformTemplateFormat), terraformTemplateFormat, null);
            }
        }
        public static string TemplateParameters(string parametersJson, IReadOnlyDictionary <string, string?> parameterMetadata, IImmutableVariableDictionary contextVariables)
        {
            using (var stringWriter = new StringWriter())
                using (JsonWriter writer = new JsonTextWriter(stringWriter))
                {
                    writer.Formatting = Formatting.Indented;

                    var jObject = JObject.Parse(parametersJson, new JsonLoadSettings {
                        CommentHandling = CommentHandling.Ignore, LineInfoHandling = LineInfoHandling.Ignore
                    });

                    writer.WriteStartObject();

                    foreach (var pair in jObject)
                    {
                        var    propertyName = pair.Key;
                        var    selectToken  = pair.Value?.SelectToken("value");
                        string?propertyValue;
                        if (selectToken is JValue jValue)
                        {
                            propertyValue = jValue.Value?.ToString();
                        }
                        else
                        {
                            propertyValue = selectToken?.ToString(Formatting.None);
                        }

                        var evaluatedValue = contextVariables.EvaluateIgnoringErrors(propertyValue);

                        writer.WritePropertyName(propertyName);
                        writer.WriteStartObject();
                        writer.WritePropertyName("value");
                        switch (parameterMetadata[propertyName]?.ToLower())
                        {
                        case "string":
                        case "securestring":
                            writer.WriteValue(evaluatedValue);
                            break;

                        case "int":
                            Int32.TryParse(evaluatedValue, out var intResult);
                            writer.WriteValue(intResult);
                            break;

                        case "bool":
                            Boolean.TryParse(evaluatedValue, out var boolResult);
                            writer.WriteValue(boolResult);
                            break;

                        default:
                            writer.WriteRawValue(evaluatedValue);
                            break;
                        }

                        writer.WriteEndObject();
                    }

                    writer.WriteEndObject();
                    writer.Flush();

                    return(stringWriter.ToString());
                }
        }