Types/OpenPackage.Part/get_Metadata.ps1

<#
.SYNOPSIS
    Gets Part Metadata
.DESCRIPTION
    Gets Part Metadata from parts with similar names
.EXAMPLE
    $package.GetPart("/foo").Metadata
.NOTES
    Parts can get metadata from many places.

    This will get metadata in a cascade.

    First, it will get any metadata found in a related data file:
    
    For example, `/foo/bar.md` could have metadata in:

    * `/foo/bar.md.json`
    * `/foo/bar.md.psd1`
    * `/foo/bar.md.toml`
    * `/foo/bar.md.xml`
    * `/foo/bar.md.yaml`

    * `/foo.json`
    * `/foo.psd1`
    * `/foo.toml`
    * `/foo.xml`
    * `/foo.yaml`
    
#>

param()

# For the moment, we will limit the types of files we can process as metadata.
$dataFilePattern = '\.(?>json|psd1|toml|xml|ya?ml)$'

# First, match any directly related files.
$directlyRelated = "^$([Regex]::Escape("$($this.Uri)"))$dataFilePattern"

# Check each part in the package
foreach ($part in $this.Package.Parts) {
    # if it is directly related, and readable, read it.
    if ($part.Uri -notmatch $directlyRelated) { continue }
    if ($part.Reader) {
        try {
            $part.Read()
        } catch {
            Write-Warning "Error Reading $($part.Uri): $_"
        }
    }
}

# Now let's go up thru the list of segments
$segments = @($this.Uri -split '/' -ne '')
# Go backwards to forwards (bottom-most path to topmost path)
for ($segmentNumber = $segments.Count - 1; $segmentNumber -ge 0; $segmentNumber--) {
    # If we're at the topmost path and have an identifier
    $relatedToParent = if ($segmentNumber -eq 0 -and $this.Package.Identifier) {
        # Look for files related to the identifier.
        "/$([Regex]::Escape($this.Package.Identifier))$dataFilePattern"
    } elseif ($segmentNumber -gt 0) {
        # If we're at any greater index, join all segments together
        "/$([Regex]::Escape(
            @(
                $segments[0..$segmentNumber];
                # and repeat the last segment.
                $segments[$segmentNumber]
            ) -join '/'
        ))$dataFilePattern$"

    }

    # Now go thru all of the parts in the package
    foreach ($part in $this.Package.Parts) {
        # and find any related to this level of parent.
        if ($part.Uri -match $relatedToParent -and $part.Reader) {
            try {
                # and read the metadata.
                $part.Read()
            } catch {
                Write-Warning "Error Reading $($part.Uri): $_"
            }            
        }
    }
}