diff --git a/.github/workflows/validate-documentation.yml b/.github/workflows/validate-documentation.yml index 8fc7d6926b..b2ce951135 100644 --- a/.github/workflows/validate-documentation.yml +++ b/.github/workflows/validate-documentation.yml @@ -58,6 +58,45 @@ jobs: return $null } + function Get-ImagesFromLine($line) { + $images = @() + $lineForParsing = [regex]::Replace($line, '`[^`]*`', '') + + # Process markdown and HTML images + $imagePatterns = @( + @{ Pattern = "!\[([^\]]*)\]\(([^)]+)\)"; Type = "Markdown"; AltGroup = 1; UrlGroup = 2 } + @{ Pattern = ']*>'; Type = "HTML"; AltGroup = -1; UrlGroup = -1 } + ) + + foreach ($pattern in $imagePatterns) { + foreach ($match in [regex]::Matches($lineForParsing, $pattern.Pattern)) { + $altText = "" + $url = "" + + if ($pattern.Type -eq "Markdown") { + $altText = $match.Groups[$pattern.AltGroup].Value + $url = $match.Groups[$pattern.UrlGroup].Value + } else { + # Extract from HTML + $imgTag = $match.Value + if ($imgTag -match 'alt\s*=\s*[`"'']([^`"'']*)[`"'']') { $altText = $matches[1] } + if ($imgTag -match 'src\s*=\s*[`"'']([^`"'']*)[`"'']') { $url = $matches[1] } + } + + $images += @{ + Match = $match.Value + Type = $pattern.Type + AltText = $altText + Url = $url + StartIndex = $match.Index + Length = $match.Length + } + } + } + + return $images + } + # Initialize $tabFile = Join-Path $PWD "src/slic3r/GUI/Tab.cpp" $docDir = Join-Path $PWD 'doc' @@ -99,8 +138,35 @@ jobs: if ($inCodeFence) { continue } $lineForParsing = [regex]::Replace($line, '`[^`]*`', '') - foreach ($linkMatch in [regex]::Matches($lineForParsing, '(?]*>'; Type = "HTML"; AltGroup = -1; UrlGroup = -1 } - ) - - foreach ($pattern in $imagePatterns) { - foreach ($match in [regex]::Matches($lineForParsing, $pattern.Pattern)) { - $altText = "" - $url = "" - - if ($pattern.Type -eq "Markdown") { - $altText = $match.Groups[$pattern.AltGroup].Value - $url = $match.Groups[$pattern.UrlGroup].Value - } else { - # Extract from HTML - $imgTag = $match.Value - if ($imgTag -match 'alt\s*=\s*[`"'']([^`"'']*)[`"'']') { $altText = $matches[1] } - if ($imgTag -match 'src\s*=\s*[`"'']([^`"'']*)[`"'']') { $url = $matches[1] } - } - - if (-not $altText.Trim() -and $url) { - $brokenReferences += Add-BrokenReference $relPath ($lineNumber + 1) $match.Value "[$($pattern.Type)] Missing alt text for image" "Image" - } elseif ($url -and $altText) { - # Validate URL format and file existence - if ($url -match $expectedUrlPattern) { - $relativePathInUrl = $matches[1] - $fileNameFromUrl = [System.IO.Path]::GetFileNameWithoutExtension($relativePathInUrl) - - if ($altText -ne $fileNameFromUrl) { - $brokenReferences += Add-BrokenReference $relPath ($lineNumber + 1) $match.Value "[$($pattern.Type)] Alt text `"$altText`" ≠ filename `"$fileNameFromUrl`"" "Image" - } - - $expectedImagePath = Join-Path $PWD ($relativePathInUrl -replace "/", "\") - if (-not (Test-Path $expectedImagePath)) { - $brokenReferences += Add-BrokenReference $relPath ($lineNumber + 1) $match.Value "[$($pattern.Type)] Image not found at path: $relativePathInUrl" "Image" - } - } else { - $urlIssues = @() - if (-not $url.StartsWith('https://github.com/SoftFever/OrcaSlicer/blob/main/')) { $urlIssues += "URL must start with expected prefix" } - if (-not $url.EndsWith('?raw=true')) { $urlIssues += "URL must end with '?raw=true'" } - if ($url -match '^https?://(?!github\.com/SoftFever/OrcaSlicer)') { $urlIssues += "External URLs not allowed" } - - $issueText = "[$($pattern.Type)] URL format issues: " + ($urlIssues -join '; ') - $brokenReferences += Add-BrokenReference $relPath ($lineNumber + 1) $match.Value $issueText "Image" + foreach ($image in $imagesInLine) { + $altText = $image.AltText + $url = $image.Url + $imageMatch = $image.Match + $imageType = $image.Type + + if (-not $altText.Trim() -and $url) { + $brokenReferences += Add-BrokenReference $relPath ($lineNumber + 1) $imageMatch "[$imageType] Missing alt text for image" "Image" + } elseif ($url -and $altText) { + # Validate URL format and file existence + if ($url -match $expectedUrlPattern) { + $relativePathInUrl = $matches[1] + $fileNameFromUrl = [System.IO.Path]::GetFileNameWithoutExtension($relativePathInUrl) + + if ($altText -ne $fileNameFromUrl) { + $brokenReferences += Add-BrokenReference $relPath ($lineNumber + 1) $imageMatch "[$imageType] Alt text `"$altText`" ≠ filename `"$fileNameFromUrl`"" "Image" } + + $expectedImagePath = Join-Path $PWD ($relativePathInUrl -replace "/", "\") + if (-not (Test-Path $expectedImagePath)) { + $brokenReferences += Add-BrokenReference $relPath ($lineNumber + 1) $imageMatch "[$imageType] Image not found at path: $relativePathInUrl" "Image" + } + } else { + $urlIssues = @() + if (-not $url.StartsWith('https://github.com/SoftFever/OrcaSlicer/blob/main/')) { $urlIssues += "URL must start with expected prefix" } + if (-not $url.EndsWith('?raw=true')) { $urlIssues += "URL must end with '?raw=true'" } + if ($url -match '^https?://(?!github\.com/SoftFever/OrcaSlicer)') { $urlIssues += "External URLs not allowed" } + + $issueText = "[$imageType] URL format issues: " + ($urlIssues -join '; ') + $brokenReferences += Add-BrokenReference $relPath ($lineNumber + 1) $imageMatch $issueText "Image" } } } @@ -314,22 +365,4 @@ jobs: } else { Write-Host "::notice::All documentation is valid!" exit 0 - } - - - name: Comment on PR - if: failure() && github.event_name == 'pull_request' - uses: actions/github-script@v8 - with: - script: | - const validationErrors = process.env.VALIDATION_ERRORS || ''; - - const body = `❌ **Documentation validation failed** - - ${validationErrors || 'Please check the workflow logs for details about the validation errors.'}`; - - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: body - }) + } \ No newline at end of file