Types/OpenPackage.Part/get_Writer.ps1

<#
.SYNOPSIS
    Gets a Part's available writers
.DESCRIPTION
    Gets the different methods we can use to Write to a part.
#>

param()

# If we already have a cached list of writers
if ($this.'#Writers') {
    # return it.
    return $this.'#Writers'
}

# To get all of our methods, go over each method on this object
$WriteMethods = @(:nextMethod foreach ($method in $this.PSObject.Methods) {
    # and ignore any methods that do not start with `Write`.
    if ($method.Name -notmatch 'Write.+?') {
        continue
    }
    # If there is no script, ignore the method.
    if (-not $method.Script) { continue }
    $script = $method.Script
    # If there are no attributes, ignore the method
    if (-not $script.Attributes) { continue }
    # Gather all of our attribute data
    $attributeData = [Ordered]@{}
    :nextAttribute foreach ($attribute in $script.Attributes) {
        # If the attribute does not have a key and value,
        if (-not ($attribute.Key -and $attribute.value)) {            
            continue nextAttribute # continue to the next attribute
        }

        # If we do not already know about this key
        if (-not $attributeData[$attribute.key]) {
            # set it
            $attributeData[$attribute.key] = $attribute.value
        } else {
            # otherwise, make our data a list and add the new value
            $attributeData[$attribute.key] = @(
                $attributeData[$attribute.key]
            ) + $attribute.Value
        }        
    }

    # Now we want to try to match.
    try {
        # If either the `FilePattern` or `ContentTypePattern` matches
        # we consider this to be a potential writer.
        
        # Loop thru the file patterns
        foreach ($pattern in $attributeData.FilePattern) {
            # skip parts that do not match.
            if ($this.Uri -notmatch $pattern) { continue }
            # Output the matching method
            $method
            continue nextMethod # and continue to the next method
        }
        # Loop thru the content type patterns
        foreach ($pattern in $attributeData.ContentTypePattern) {
            # skip parts that do not match.
            if ($this.ContentType -notmatch $pattern) { continue }
            # Output the matching method
            $method
            continue nextMethod # and continue to the next method.
        }
    } catch {
        Write-Debug "$_"
    }
})

# Now that we know all of the methods, we need to put them in order.
$WriteMethods = @(
    $WriteMethods | # We can do this with a dynamic sort.
        Sort-Object {
            $in = $_
            # Simply walk over each attribute
            foreach ($attr in $in.Script.Attributes) {
                # any named `Order` with an integer value
                if ($attr.Key -eq 'Order' -and $attr.Value -as [int]) {
                    # will use that value
                    return ($attr.Value -as [int])
                }
            }
            # Without an order attribute, use zero
            return 0
    }, Name # and perform a secondary sort by name.
)

# Now that we've gotten our writers and sorted them
# cache them on the object.
$this | Add-Member NoteProperty '#Writers' $WriteMethods -Force
# and return the cached value.
return $this.'#Writers'