internal void ExpandPolicyRule()

in src/PSRule.Rules.Azure/Data/Policy/PolicyAssignmentVisitor.cs [443:556]


            internal void ExpandPolicyRule(JToken policyRule, IList<string> types)
            {
                if (policyRule.Type == JTokenType.Object)
                {
                    var hasFieldType = false;
                    var hasFieldCount = false;

                    // Go through each property and make sure fields and counts are sorted first
                    foreach (var child in policyRule.Children<JProperty>().OrderBy(prop => prop, new PropertyNameComparer()))
                    {
                        // Expand field aliases
                        if (child.TryGetProperty(PROPERTY_FIELD, out var field))
                        {
                            if (field.Equals(PROPERTY_TYPE, StringComparison.OrdinalIgnoreCase))
                            {
                                hasFieldType = true;
                                child.Parent[PROPERTY_TYPE] = DOT;
                                child.Remove();
                            }

                            if (TryPolicyAliasPath(field, out var aliasPath))
                                policyRule[child.Name] = aliasPath;
                        }

                        // Set policy rule type
                        else if (hasFieldType && child.TryGetProperty(PROPERTY_EQUALS, out field))
                        {
                            if (string.Equals(TYPE_SUBSCRIPTION_RESOURCE_GROUP, field, StringComparison.OrdinalIgnoreCase))
                                field = TYPE_RESOURCE_GROUP;

                            types.Add(field);
                            SetDefaultResourceType(field);
                        }

                        // Replace equals with count if field count expression is currently being visited
                        // Replace notEquals with notCount if field count expression is currently being visited
                        else if (hasFieldCount && (child.TryRenameProperty(PROPERTY_EQUALS, PROPERTY_COUNT) ||
                            child.TryRenameProperty(PROPERTY_NOTEQUALS, PROPERTY_NOTCOUNT)))
                        {
                            // Do nothing.
                        }

                        // Expand field count expressions
                        else if (child.Name.Equals(PROPERTY_COUNT, StringComparison.OrdinalIgnoreCase))
                        {
                            hasFieldCount = true;

                            if (child.Value.Type == JTokenType.Object)
                            {
                                var countObject = child.Value.ToObject<JObject>();
                                if (countObject.TryStringProperty(PROPERTY_FIELD, out var outerFieldAlias) &&
                                    TryPolicyAliasPath(outerFieldAlias, out var outerFieldAliasPath))
                                {
                                    if (countObject.TryObjectProperty(PROPERTY_WHERE, out var whereExpression))
                                    {
                                        // field in where expression
                                        var fieldFilter = GetFieldObjectPathArrayFilter(whereExpression);
                                        if (fieldFilter != null)
                                        {
                                            var splitAliasPath = outerFieldAliasPath.SplitByLastSubstring(COLLECTION_ALIAS);
                                            policyRule[PROPERTY_FIELD] = FormatObjectPathArrayExpression(splitAliasPath[0], fieldFilter);
                                        }

                                        // nested allOf in where expression
                                        else if (whereExpression.TryArrayProperty(PROPERTY_ALLOF, out var allofExpression))
                                        {
                                            var splitAliasPath = outerFieldAliasPath.SplitByLastSubstring(COLLECTION_ALIAS);
                                            var filter = new StringBuilder();
                                            ExpressionToObjectPathArrayFilter(allofExpression, AND_CLAUSE, filter);
                                            policyRule[PROPERTY_FIELD] = FormatObjectPathArrayExpression(splitAliasPath[0], filter.ToString());
                                        }

                                        // nested anyOf in where expression
                                        else if (whereExpression.TryArrayProperty(PROPERTY_ANYOF, out var anyOfExpression))
                                        {
                                            var splitAliasPath = outerFieldAliasPath.SplitByLastSubstring(COLLECTION_ALIAS);
                                            var filter = new StringBuilder();
                                            ExpressionToObjectPathArrayFilter(anyOfExpression, OR_CLAUSE, filter);
                                            policyRule[PROPERTY_FIELD] = FormatObjectPathArrayExpression(splitAliasPath[0], filter.ToString());
                                        }
                                    }

                                    // Single field in count expression
                                    else
                                        policyRule[PROPERTY_FIELD] = outerFieldAliasPath;

                                    // Remove the count property when we're done
                                    policyRule[PROPERTY_COUNT].Parent.Remove();
                                }
                            }
                        }

                        // Convert string booleans for exists expression
                        else if (child.Name.Equals(PROPERTY_EXISTS, StringComparison.OrdinalIgnoreCase) && child.Value.Type == JTokenType.String)
                            policyRule[child.Name] = child.Value.Value<bool>();

                        // Expand string expressions
                        else if (child.Value.Type == JTokenType.String)
                        {
                            var expression = GetExpression(child);
                            policyRule[child.Name] = expression;
                        }

                        // Recurse any objects or arrays
                        else if (child.Value.Type is JTokenType.Object or JTokenType.Array)
                            ExpandPolicyRule(child.Value, types);
                    }
                }

                // Recurse arrays
                else if (policyRule.Type == JTokenType.Array)
                    foreach (var child in policyRule.Children().ToArray())
                        ExpandPolicyRule(child, types);
            }