Skip to content

Validate codeblock URLs during build and streamline CI lints#3020

Open
manovotny wants to merge 6 commits intomainfrom
manovotny/codeblock-link-checker
Open

Validate codeblock URLs during build and streamline CI lints#3020
manovotny wants to merge 6 commits intomainfrom
manovotny/codeblock-link-checker

Conversation

@manovotny
Copy link
Contributor

@manovotny manovotny commented Jan 29, 2026

Warning

These upstream changes will need to be merged before the build will pass (because they contain broken or out-od-date urls):

Summary

  • Adds build-time validation for clerk.com/docs URLs found in code block comments
  • Streamlines CI lint workflow to only run lints that don't require a build
  • Fixes outdated documentation URLs

What changed?

Build-time codeblock URL validation

Updated scripts/lib/plugins/validateLinks.ts to validate clerk.com/docs URLs found in code block comments during the build process:

  • Scans code blocks for URLs matching https://clerk.com/docs/*
  • Validates URLs exist in the built docs directory
  • Detects URLs that redirect and suggests the new path
  • Preserves hash fragments when checking redirects
  • Reports warnings during build if URLs are invalid or outdated

CI workflow changes

Updated .github/workflows/lint.yml to run all lints that don't require a build:

  • lint:formatting - Prettier check
  • lint:check-frontmatter - Frontmatter validation
  • lint:check-duplicate-redirects - Duplicate redirect check
  • lint:check-svgs - SVG optimization check
  • lint:check-images - Image reference check

Lints requiring a build (lint:check-redirects) are now validated as part of the build process itself.

Fixed URLs

Fixed outdated clerk.com/docs URLs found in code blocks:

  • /docs/quickstarts/nextjs/docs/nextjs/getting-started/quickstart
  • /docs/custom-flows/error-handling/docs/guides/development/custom-flows/error-handling
  • /docs/reference/tanstack-react-start/custom-sign-in-or-up-page/docs/guides/development/custom-sign-in-or-up-page
  • /docs/references/backend/types/auth-object/docs/reference/backend/types/auth-object
  • /docs/authentication/enterprise-connections/authentication-flows/docs/guides/configure/auth-strategies/enterprise-connections/authentication-flows

Test plan

  • Build passes locally with pnpm run build
  • Lint passes locally with pnpm run lint
  • Verified codeblock URL validation catches outdated URLs
  • Verified redirect detection works correctly

🤖 Generated with Claude Code

@manovotny manovotny requested a review from a team as a code owner January 29, 2026 23:13
@vercel
Copy link

vercel bot commented Jan 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-docs Error Error Feb 6, 2026 5:40pm

Request Review

@NWylynko
Copy link
Contributor

In scripts/lib/plugins/validateLinks.ts we already validate standard links and then have a map of all available guides to check against if they exist. Could we just update that to also check in code blocks?

@manovotny manovotny force-pushed the manovotny/codeblock-link-checker branch from a11c901 to e794dc6 Compare February 4, 2026 17:35
@manovotny manovotny force-pushed the manovotny/codeblock-link-checker branch from 7bf9d01 to ae58e94 Compare February 4, 2026 20:15
@manovotny manovotny changed the title Add codeblock link checker and enable all lints on PR Validate codeblock URLs during build and streamline CI lints Feb 4, 2026
@manovotny
Copy link
Contributor Author

In scripts/lib/plugins/validateLinks.ts we already validate standard links and then have a map of all available guides to check against if they exist. Could we just update that to also check in code blocks?

Done!

Comment on lines +26 to +70
/**
* Follow redirect chain to get final destination
*/
function followRedirectChain(
url: string,
staticRedirects: Map<string, string>,
dynamicRedirects: Redirect[],
maxRedirects = 10,
): string | null {
let currentUrl = url
let redirectCount = 0

while (redirectCount < maxRedirects) {
// Check static redirects first
const staticDest = staticRedirects.get(currentUrl)
if (staticDest) {
currentUrl = staticDest
redirectCount++
continue
}

// Check dynamic redirects (simple prefix matching for common patterns)
let foundDynamic = false
for (const redirect of dynamicRedirects) {
// Handle simple wildcard patterns like /docs/old/:path* -> /docs/new/:path*
const sourceBase = redirect.source.replace(/:\w+\*?$/, '')
if (currentUrl.startsWith(sourceBase)) {
const remainder = currentUrl.slice(sourceBase.length)
const destBase = redirect.destination.replace(/:\w+\*?$/, '')
currentUrl = destBase + remainder
foundDynamic = true
redirectCount++
break
}
}

if (!foundDynamic) {
// No more redirects
return currentUrl !== url ? currentUrl : null
}
}

return currentUrl !== url ? currentUrl : null
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If using the staticRedirects objects set in the build() function, it has already done the redirect chain following (see optimizeRedirects() on line 271) so this wouldn't need to do that. Additionally this logic is wrong as clerk/clerk redirect checks start with dynamic redirects, then static second (see https://github.com/clerk/clerk/blob/main/src/app/(website)/docs/clerk-docs-redirects.ts#L51)

Comment on lines +72 to +73
'link-redirects': (url: string, destination: string): string =>
`Link "${url}" redirects to "${destination}". Update the URL to use the new path.`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As much as this is nice to report, we don't really need to (to fulfill the purpose of this pr), we can just use link-doc-not-found and leave it at that, let the author figure out what the link should be.

Some reasons to not bother:

  • This gives a false sense of like its fine, don't worry a redirect is in place, when really your saying like no this needs to be updated.
  • It would cut down on the complexity of this pr a lot by not reporting that a redirect does or does not exist.

If we do want to go down the route of checking links against the redirects, a couple other options come to mind

  • Update the link in place based off the redirect, so the outputted files already include the latest link
  • Add a --fix flag to the cli that updates the link in the docs folder

manovotny and others added 5 commits February 6, 2026 11:30
- Add scripts/check-codeblock-links.ts to validate clerk.com/docs URLs
  in code block comments against built docs
- Fix 4 outdated URLs found by the new checker
- Update .github/workflows/lint.yml to run all lint checks after build
- Add lint:check-codeblock-links script to package.json

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move codeblock URL validation from standalone script into the existing
validateLinks remark plugin. This validates clerk.com/docs URLs in code
block comments during the build process.

Changes:
- Add codeblock URL validation to validateLinks.ts
- Detect URLs that redirect and suggest the correct path
- Preserve hash fragments in redirect suggestions
- Add 'link-redirects' error message
- Pass redirects to validateLinks for redirect chain resolution
- Remove standalone check-codeblock-links.ts script

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove build step from lint workflow and run only lints that don't
require built artifacts: formatting, frontmatter, duplicate redirects,
SVGs, and images. Build-dependent validations (like codeblock URL
checking) run as part of the build process itself.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Derive redirectsForValidation from existing variables instead of
storing a separate copy of the raw redirect arrays.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants