Private/MappingStore.ps1

# Shared mapping-file helpers used by all public functions.

function Get-DefaultMappingFile {
    <#
    .SYNOPSIS
        Returns the default mapping-file path in the current user's profile.
    #>

    Join-Path $env:USERPROFILE 'MaskSensitiveData_Map.json'
}

function Import-Mapping {
    <#
    .SYNOPSIS
        Reads a mapping JSON file into a hashtable.
    .DESCRIPTION
        Returns an empty hashtable when the file does not exist (so callers like Add-MaskMapping can
        create it). Use -Require to throw instead when the file is missing.
    #>

    param(
        [string]$MappingFile,
        [switch]$Require
    )

    if (Test-Path $MappingFile) {
        $content = Get-Content $MappingFile -Raw
        if ([string]::IsNullOrWhiteSpace($content)) {
            return @{}
        }
        return $content | ConvertFrom-Json -AsHashtable
    }

    if ($Require) {
        throw "Mapping file '$MappingFile' not found."
    }

    return @{}
}

function Export-Mapping {
    <#
    .SYNOPSIS
        Writes a hashtable mapping to a JSON file (UTF-8, sorted by key for stable diffs).
    #>

    param(
        [hashtable]$Map,
        [string]$MappingFile
    )

    $ordered = [ordered]@{}
    foreach ($key in ($Map.Keys | Sort-Object)) {
        $ordered[$key] = $Map[$key]
    }

    $dir = Split-Path $MappingFile -Parent
    if ($dir -and -not (Test-Path $dir)) {
        New-Item -ItemType Directory -Path $dir -Force | Out-Null
    }

    $ordered | ConvertTo-Json -Depth 5 | Set-Content -Path $MappingFile -Encoding utf8
}

function Resolve-ReplacementMap {
    <#
    .SYNOPSIS
        Resolves the active replacement map from -Replacements (preferred) or a -MappingFile.
    .DESCRIPTION
        Shared by Protect-SensitiveData and Unprotect-SensitiveData. Throws a clear error when neither
        an explicit hashtable nor an existing mapping file is available.
    #>

    param(
        [hashtable]$Replacements,
        [string]$MappingFile
    )

    if ($Replacements) {
        return $Replacements
    }
    if ($MappingFile -and (Test-Path $MappingFile)) {
        return Import-Mapping -MappingFile $MappingFile
    }
    if ($MappingFile) {
        throw "Mapping file '$MappingFile' not found. Specify -MappingFile or -Replacements."
    }
    throw "Specify either -MappingFile or -Replacements."
}