Google Docs Markdown Linting Script


$input  = "input.md"
$output = "output.md"

$lines = Get-Content $input

$result = @()
$prevType = "none"   # paragraph | list | other | none
$prevWasBlank = $false

foreach ($line in $lines) {
    $trimmed = $line.Trim()

    $isBlank   = $trimmed -eq ""
    $isHeading = $trimmed -match '^#'
    $isList    = $trimmed -match '^(\*|-|\d+\.)\s+'

    $isParagraph = (
        -not $isBlank -and
        -not $isHeading -and
        -not $isList -and
        $trimmed -notmatch '^(>|```)'  # exclude blockquotes/code fences
    )

    if ($isBlank) {
        if (-not $prevWasBlank -and ($prevType -eq "paragraph" -or $prevType -eq "list")) {
            # allow ONE blank line after paragraph or list
            $result += ""
            $prevWasBlank = $true
        }
        continue
    }

    # Remove blank line before headings or lists
    if (($isHeading -or $isList) -and $result.Count -gt 0 -and $result[-1] -eq "") {
        $result = $result[0..($result.Count - 2)]
    }

    # Add current line
    $result += $line

    # Update state
    if ($isParagraph) {
        $prevType = "paragraph"
    }
    elseif ($isList) {
        $prevType = "list"
    }
    else {
        $prevType = "other"
    }

    $prevWasBlank = $false
}

# Remove leading blank lines
while ($result.Count -gt 0 -and $result[0] -eq "") {
    $result = $result[1..($result.Count - 1)]
}

# Remove trailing blank lines
while ($result.Count -gt 0 -and $result[-1] -eq "") {
    $result = $result[0..($result.Count - 2)]
}

Set-Content $output $result