def normalize()

in samcli/lib/samlib/resource_metadata_normalizer.py [0:0]


    def normalize(template_dict, normalize_parameters=False):
        """
        Normalize all Resources in the template with the Metadata Key on the resource.

        This method will mutate the template

        Parameters
        ----------
        template_dict dict
            Dictionary representing the template

        """
        resources = template_dict.get(RESOURCES_KEY, {})

        for logical_id, resource in resources.items():
            # copy metadata to another variable, change its values and assign it back in the end
            resource_metadata = deepcopy(resource.get(METADATA_KEY)) or {}

            is_normalized = resource_metadata.get(SAM_IS_NORMALIZED, False)
            if not is_normalized:
                asset_property = resource_metadata.get(ASSET_PROPERTY_METADATA_KEY)
                if asset_property == IMAGE_ASSET_PROPERTY:
                    asset_metadata = ResourceMetadataNormalizer._extract_image_asset_metadata(resource_metadata)
                    ResourceMetadataNormalizer._update_resource_metadata(resource_metadata, asset_metadata)
                    # For image-type functions, the asset path is expected to be the name of the Docker image.
                    # When building, we set the name of the image to be the logical id of the function.
                    asset_path = logical_id.lower()
                else:
                    asset_path = resource_metadata.get(ASSET_PATH_METADATA_KEY)

                ResourceMetadataNormalizer._replace_property(asset_property, asset_path, resource, logical_id)
                if asset_path and asset_property:
                    resource_metadata[SAM_IS_NORMALIZED] = True

            # Set SkipBuild metadata iff is-bundled metadata exists, and value is True
            skip_build = resource_metadata.get(ASSET_BUNDLED_METADATA_KEY, False)
            if skip_build:
                ResourceMetadataNormalizer._update_resource_metadata(
                    resource_metadata,
                    {
                        SAM_METADATA_SKIP_BUILD_KEY: True,
                    },
                )

            # Set Resource Id
            ResourceMetadataNormalizer._update_resource_metadata(
                resource_metadata,
                {SAM_RESOURCE_ID_KEY: ResourceMetadataNormalizer.get_resource_id(resource, logical_id)},
            )
            resource[METADATA_KEY] = resource_metadata

        # This is a work around to allow the customer to use sam deploy or package commands without the need to provide
        # values for the CDK auto generated asset parameters. The suggested solution is to let CDK add some metadata to
        # the autogenerated parameters, so sam can skip them safely.

        # Normalizing CDK auto generated parameters. Search for parameters that meet these conditions:
        # 1- parameter name matches pattern
        #    `AssetParameters[0-9a-f]{64}(?:S3Bucket|S3VersionKey|ArtifactHash)[0-9A-F]{8}`
        # 2- parameter type is string
        # 3- there is no reference to this parameter any where in the template resources, except in Nested Stack
        #    Parameters property.
        # 4- there is no default value for this parameter
        # We set an empty string as default value for the matching parameters, so the customer can use sam deploy or
        # package commands without providing values for the auto generated parameters, as these parameters are not used
        # in SAM (sam set the resources paths directly, and does not depend on template parameters)
        if normalize_parameters and is_cdk_project(template_dict):
            resources_copy = {
                logical_id: resource
                for logical_id, resource in resources.items()
                if resource.get("Type", "") != AWS_CLOUDFORMATION_STACK
            }
            resources_as_string = json.dumps(resources_copy)
            parameters = template_dict.get("Parameters", {})

            default_value = " "
            for parameter_name, parameter_value in parameters.items():
                parameter_name_match = CDK_ASSET_PARAMETER_PATTERN.match(parameter_name)
                if (
                    parameter_name_match
                    and "Default" not in parameter_value
                    and parameter_value.get("Type", "") == "String"
                    and f'"Ref": "{parameter_name}"' not in resources_as_string
                ):
                    LOG.debug("set default value for parameter %s to '%s'", parameter_name, default_value)
                    parameter_value["Default"] = default_value