-
Notifications
You must be signed in to change notification settings - Fork 194
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1119 from ethereum-optimism/lint-check
Automate Internal Link Updates Using Redirects File
- Loading branch information
Showing
17 changed files
with
365 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# Redirect links management guide | ||
|
||
## Scripts overview | ||
Two scripts help maintain internal links when pages are redirected: | ||
|
||
* `check-redirects`: Identifies links that need updating based on the `_redirects` file. | ||
* `fix-redirects`: Automatically updates links to match `_redirects` entries. | ||
|
||
## Checking for broken links | ||
|
||
Run the check script: | ||
|
||
```bash | ||
pnpm lint //OR | ||
pnpm check-redirects | ||
``` | ||
## What it does | ||
|
||
* Scans all `.mdx` files in the docs | ||
* Compares internal links against `_redirects` file | ||
* Reports any outdated links that need updating | ||
* Provides a summary of total, broken, and valid links | ||
|
||
## Example output | ||
|
||
```bash | ||
File "builders/overview.mdx" contains outdated link "/chain/overview" - should be updated to "/stack/overview" | ||
|
||
Summary: | ||
Total pages 🔍 - 50 | ||
Pages broken 🚫 - 2 | ||
Pages OK ✅ - 48 | ||
|
||
``` | ||
|
||
## Fixing broken links | ||
|
||
Fix links automatically: | ||
|
||
```bash | ||
pnpm fix //OR | ||
pnpm fix-redirects | ||
``` | ||
|
||
## What it does | ||
|
||
* Updates all internal links to match `_redirects` entries | ||
* Preserves other content and formatting | ||
* Shows which files and links were updated | ||
* Provides a summary of changes made | ||
|
||
## Example output | ||
|
||
```bash | ||
Fixed in "builders/overview.mdx": /chain/overview → /stack/overview | ||
|
||
Summary: | ||
Total files 🔍 - 50 | ||
Files fixed ✅ - 2 | ||
Files skipped ⏭️ - 48 | ||
``` | ||
|
||
## Best practices | ||
|
||
1. Before running | ||
|
||
* Commit current changes | ||
* Review `_redirects` file is up-to-date | ||
* Run `check-redirects` first to preview changes | ||
|
||
|
||
2. After running | ||
|
||
* Review git diff of updated files | ||
* Test updated links locally | ||
* Commit changes with descriptive message | ||
|
||
|
||
|
||
## Common issues | ||
|
||
* Script fails: Ensure `_redirects` file exists in public folder, it should always be there! | ||
* No broken links found: Verify `_redirects` entries are correct. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import * as fs from 'fs/promises'; | ||
import * as path from 'path'; | ||
|
||
const rootDir = path.join(process.cwd(), 'pages'); | ||
const redirectsPath = path.join(process.cwd(), 'public', '_redirects'); | ||
const updates: string[] = []; | ||
|
||
// ANSI color codes | ||
const WHITE = '\x1b[37m'; | ||
const GREEN = '\x1b[32m'; | ||
const YELLOW = '\x1b[33m'; | ||
const RESET = '\x1b[0m'; | ||
const BOLD = '\x1b[1m'; | ||
|
||
interface Redirect { | ||
from: string; | ||
to: string; | ||
} | ||
|
||
interface Summary { | ||
total: number; | ||
fixed: number; | ||
skipped: number; | ||
} | ||
|
||
async function getRedirects(): Promise<Redirect[]> { | ||
const content = await fs.readFile(redirectsPath, 'utf-8'); | ||
return content.split('\n') | ||
.filter(line => line.trim() && !line.startsWith('#')) | ||
.map(line => { | ||
const [from, to] = line.split(/\s+/); | ||
return { from, to }; | ||
}); | ||
} | ||
|
||
async function findMdxFiles(dir: string): Promise<string[]> { | ||
const files: string[] = []; | ||
const entries = await fs.readdir(dir, { withFileTypes: true }); | ||
|
||
for (const entry of entries) { | ||
const fullPath = path.join(dir, entry.name); | ||
if (entry.isDirectory() && !entry.name.startsWith('_')) { | ||
files.push(...await findMdxFiles(fullPath)); | ||
} else if (entry.isFile() && /\.(md|mdx)$/.test(entry.name)) { | ||
files.push(fullPath); | ||
} | ||
} | ||
return files; | ||
} | ||
|
||
async function fixFile(filePath: string, redirects: Redirect[]): Promise<boolean> { | ||
let content = await fs.readFile(filePath, 'utf-8'); | ||
let hasChanges = false; | ||
const relativeFilePath = path.relative(rootDir, filePath); | ||
|
||
redirects.forEach(redirect => { | ||
const markdownRegex = new RegExp(`\\[([^\\]]+)\\]\\(${redirect.from}\\)`, 'g'); | ||
const hrefRegex = new RegExp(`href="${redirect.from}"`, 'g'); | ||
|
||
if (content.match(markdownRegex) || content.match(hrefRegex)) { | ||
content = content | ||
.replace(markdownRegex, `[$1](${redirect.to})`) | ||
.replace(hrefRegex, `href="${redirect.to}"`); | ||
|
||
updates.push(`${WHITE}Fixed in "${relativeFilePath}": ${YELLOW}${redirect.from}${WHITE} → ${GREEN}${redirect.to}${RESET}`); | ||
hasChanges = true; | ||
} | ||
}); | ||
|
||
if (hasChanges) { | ||
await fs.writeFile(filePath, content); | ||
} | ||
|
||
return hasChanges; | ||
} | ||
|
||
function printSummary(summary: Summary) { | ||
console.log('\nSummary:'); | ||
console.log(`${WHITE}Total files 🔍 - ${summary.total}`); | ||
console.log(`${GREEN}Files fixed ✅ - ${summary.fixed}`); | ||
console.log(`${WHITE}Files skipped ⏭️ - ${summary.skipped}${RESET}`); | ||
} | ||
|
||
async function main() { | ||
const summary: Summary = { | ||
total: 0, | ||
fixed: 0, | ||
skipped: 0 | ||
}; | ||
|
||
console.log('Starting to fix redirect links...'); | ||
console.log('Root directory:', rootDir); | ||
|
||
try { | ||
const redirects = await getRedirects(); | ||
const files = await findMdxFiles(rootDir); | ||
|
||
summary.total = files.length; | ||
|
||
for (const file of files) { | ||
const wasFixed = await fixFile(file, redirects); | ||
if (wasFixed) { | ||
summary.fixed++; | ||
} else { | ||
summary.skipped++; | ||
} | ||
} | ||
|
||
if (updates.length > 0) { | ||
console.log(`${GREEN}${BOLD}Fixed links:${RESET}`); | ||
updates.forEach(update => console.log(update)); | ||
printSummary(summary); | ||
} else { | ||
console.log(`${GREEN}No broken links found. Everything is up to date.${RESET}`); | ||
printSummary(summary); | ||
} | ||
} catch (error) { | ||
console.error(`${YELLOW}${BOLD}Error fixing redirects:${RESET}`, error); | ||
process.exit(1); | ||
} | ||
} | ||
|
||
main().catch(error => { | ||
console.error(`${YELLOW}${BOLD}Error in main process:${RESET}`, error); | ||
process.exit(1); | ||
}); |
Oops, something went wrong.