private IEnumerable AnalyzeAllIncludedTemplates()

in src/Analyzer.Core/TemplateAnalyzer.cs [145:244]


        private IEnumerable<IEvaluation> AnalyzeAllIncludedTemplates(string populatedTemplate, string parameters, string templateFilePath, TemplateContext parentContext, string pathPrefix)
        {
            JToken templatejObject;
            var armTemplateProcessor = new ArmTemplateProcessor(populatedTemplate, logger: this.logger);

            try
            {
                templatejObject = armTemplateProcessor.ProcessTemplate(parameters);
            }
            catch (Exception e)
            {
                throw new TemplateAnalyzerException("Error while processing template.", e);
            }

            var templateContext = new TemplateContext
            {
                OriginalTemplate = JObject.Parse(populatedTemplate),
                ExpandedTemplate = templatejObject,
                IsMainTemplate = parentContext.OriginalTemplate == null, // Even the top level context will have a parent defined, but it won't represent a processed template
                ResourceMappings = armTemplateProcessor.ResourceMappings,
                TemplateIdentifier = templateFilePath,
                IsBicep = parentContext.IsBicep,
                BicepMetadata = parentContext.BicepMetadata,
                PathPrefix = pathPrefix,
                ParentContext = parentContext
            };

            try
            {
                IEnumerable<IEvaluation> evaluations = this.jsonRuleEngine.AnalyzeTemplate(templateContext);

                if (this.powerShellRuleEngine is not null)
                {
                    evaluations = evaluations.Concat(this.powerShellRuleEngine.AnalyzeTemplate(templateContext));
                }

                // Recursively handle nested templates 
                var jsonTemplate = JObject.Parse(populatedTemplate);
                var processedTemplateResources = templatejObject.InsensitiveToken("resources");

                for (int i = 0; i < processedTemplateResources.Count(); i++)
                {
                    var currentProcessedResource = processedTemplateResources[i];

                    if (currentProcessedResource.InsensitiveToken("type")?.ToString().Equals("Microsoft.Resources/deployments", StringComparison.OrdinalIgnoreCase) ?? false)
                    {
                        var nestedTemplate = currentProcessedResource.InsensitiveToken("properties.template");
                        if (nestedTemplate == null)
                        {
                            this.logger?.LogWarning($"A linked template was found on: {templateFilePath}, linked templates are currently not supported");

                            continue;
                        }
                        var populatedNestedTemplate = nestedTemplate.DeepClone();

                        // Check whether scope is set to inner or outer
                        var scope = currentProcessedResource.InsensitiveToken("properties.expressionEvaluationOptions.scope")?.ToString();

                        if (scope == null || scope.Equals("outer", StringComparison.OrdinalIgnoreCase))
                        {
                            // Variables, parameters and functions inherited from parent template
                            string functionsKey = populatedNestedTemplate.InsensitiveToken("functions")?.Parent.Path ?? "functions";
                            string variablesKey = populatedNestedTemplate.InsensitiveToken("variables")?.Parent.Path ?? "variables";
                            string parametersKey = populatedNestedTemplate.InsensitiveToken("parameters")?.Parent.Path ?? "parameters";

                            populatedNestedTemplate[functionsKey] = jsonTemplate.InsensitiveToken("functions");
                            populatedNestedTemplate[variablesKey] = jsonTemplate.InsensitiveToken("variables");
                            populatedNestedTemplate[parametersKey] = jsonTemplate.InsensitiveToken("parameters");
                        }
                        else // scope is inner
                        {
                            // Pass variables and functions to child template
                            (populatedNestedTemplate.InsensitiveToken("variables") as JObject)?.Merge(currentProcessedResource.InsensitiveToken("properties.variables"));
                            (populatedNestedTemplate.InsensitiveToken("functions") as JObject)?.Merge(currentProcessedResource.InsensitiveToken("properties.functions)"));

                            // Pass parameters to child template as the 'parameters' argument
                            var parametersToPass = currentProcessedResource.InsensitiveToken("properties.parameters");

                            if (parametersToPass != null)
                            {
                                parametersToPass["parameters"] = parametersToPass;
                                parametersToPass["$schema"] = "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#";
                                parametersToPass["contentVersion"] = "1.0.0.0";
                                parameters = JsonConvert.SerializeObject(parametersToPass);
                            }
                        }

                        string jsonPopulatedNestedTemplate = JsonConvert.SerializeObject(populatedNestedTemplate);

                        IEnumerable<IEvaluation> result = AnalyzeAllIncludedTemplates(jsonPopulatedNestedTemplate, parameters, templateFilePath, templateContext, nestedTemplate.Path);
                        evaluations = evaluations.Concat(result);
                    }
                }
                return evaluations;
            }
            catch (Exception e)
            {
                throw new TemplateAnalyzerException("Error while evaluating rules.", e);
            }
        }