def eval()

in cfn_policy_validator/parsers/utils/node_evaluator.py [0:0]


    def eval(self, value: Any, resource_properties_to_eval=None, visited_values=None):
        """ Evaluates the value of a CloudFormation key/value pair by evaluating intrinsic functions and pseudo
            parameters in the template and returns the evaluated value.

            value: the value of a key/value pair in a CloudFormation template
            resource_properties_to_eval: only evaluate these properties for a resource.  This limits the scope of intrinsic
                function support to be only those functions that we'd expect to exist in an IAM policy
                (e.g. Fn::GetAZs is not likely to appear)
            visited_values: tracks visited values to detect circular references in a CloudFormation template
        """
        visited_values = [] if visited_values is None else visited_values

        if isinstance(value, list):
            # when passing the list of visited values to child list items, we create a separate copy for each so
            # that they don't share the same visited references
            return [self.eval(item, copy.deepcopy(visited_values)) for item in value]

        elif isinstance(value, CfnObject):
            # intrinsic functions must be the only key, so we only need to look at the first key
            first_key = next(iter(value), None)
            evaluator = self.evaluators.get(first_key)
            if evaluator is not None:
                intrinsic_function_value = value.get(first_key)
                return evaluator.evaluate(intrinsic_function_value, visited_values=visited_values)

            # if it's not an intrinsic function, recursively traverse through child nodes
            for key in value.keys():
                # we only want to evaluate resource properties that we care about for IAM policies
                # if we were to evaluate all resource properties, the scope of supported intrinsic functions and
                # CFN parameters that would need to be passed would be larger.  This will ignore properties that we
                # don't care about.
                if value.parent == 'Properties':
                    if resource_properties_to_eval is not None and \
                            key not in resource_properties_to_eval:
                        continue

                # when passing the list of visited values to child evals, create a separate copy for each so
                # that they don't share the same visited references
                copy_of_visited_values = copy.deepcopy(visited_values)
                value[key] = self.eval(value[key], resource_properties_to_eval, copy_of_visited_values)

            return dict(value)

        else:
            return value