Tasks/Content/JSONSchema.ps1

<#
    .SYNOPSIS
    Validates JSON files against configured JSON schemas.

    .DESCRIPTION
    Uses configured JSON schema mappings to validate matching `.json` files
    under the build root with `Test-Json`.

    .GROUP
    Content

    .CONFIGURATION
    `JsonSchemas` defines the JSON files and schema files to validate. Each
    mapping has a repository-relative `Path` pattern for matching JSON files
    and a `Schema` value for the schema file.

    Use `**/*.json` to match JSON files recursively.

    `ExcludePaths.JSONSchema` excludes matching files from this task.

    ### Example

    ```powershell
    . (Get-PlumberTaskLoader) -Config @{
        ModuleManifest = 'MyModule.psd1'
        JsonSchemas = @(
            @{
                Path = 'Resource/*.json'
                Schema = 'Resource/Schema/config.schema.json'
            }
        )
        ExcludePaths = @{
            JSONSchema = @('Resource/Schema/*.json')
        }
    }
    ```

    .RUN
    ```powershell
    Invoke-Plumber -Task JSONSchema
    ```

    .PASS
    ```json
    {
      "name": "Plumber",
      "enabled": true
    }
    ```

    .FAIL
    ```json
    {
      "enabled": true
    }
    ```
#>

Add-BuildTask -Name JSONSchema -Jobs {
    # Scope can be lost when running Plumber on Plumber multiple times
    if (-not (Get-Command Get-PlumberTaskFile -ErrorAction SilentlyContinue)) {
        . (Join-Path $script:PlumberConfig.ModuleRoot 'Private/Test-PlumberTaskPathExcluded.ps1')
        . (Join-Path $script:PlumberConfig.ModuleRoot 'Private/Get-PlumberTaskFile.ps1')
    }

    if (-not (Get-Command Test-Json -ErrorAction SilentlyContinue)) {
        Write-Error 'Test-Json is required for JSON schema validation'
        return
    }

    if (-not $script:PlumberConfig.JsonSchemas) {
        Write-Build Yellow 'No JSON schema mappings configured'
        return
    }

    foreach ($mapping in $script:PlumberConfig.JsonSchemas) {
        $schema = Join-Path $BuildRoot $mapping.Schema

        if (-not (Test-Path $schema)) {
            Write-Error "JSON schema not found: $schema"
            continue
        }

        $normalizedPattern = $mapping.Path.Replace('\', '/')
        $pathRegex = [regex]::Escape($normalizedPattern).
            Replace('\*\*/', '(?:.*/)?').
            Replace('\*\*', '.*').
            Replace('\*', '[^/]*').
            Replace('\?', '[^/]')
        $pathRegex = "^$pathRegex$"

        $jsonFiles = @(
            Get-PlumberTaskFile -Task JSONSchema -Extension '.json' |
                Where-Object {
                    $relativePath = [System.IO.Path]::GetRelativePath($BuildRoot, $_.FullName)
                    $relativePath.Replace('\', '/') -match $pathRegex
                }
        )
        if (-not $jsonFiles) {
            Write-Build Yellow "No JSON files matched schema path: $($mapping.Path)"
            continue
        }

        foreach ($jsonFile in $jsonFiles) {
            $valid = Test-Json -Path $jsonFile.FullName -SchemaFile $schema -ErrorAction Stop
            if (-not $valid) {
                Write-Error "JSON schema validation failed: $($jsonFile.FullName)"
            }
        }
    }
}