Skip to content

Commit 1a27d54

Browse files
authored
Merge pull request #1119 from ethereum-optimism/lint-check
Automate Internal Link Updates Using Redirects File
2 parents 3dc670f + 2da87a6 commit 1a27d54

17 files changed

+365
-19
lines changed

lychee.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@ exclude = [
4141
]
4242

4343
# Accept these status codes
44-
accept = ["100..=103", "200..=299", "403..=403", "502..=502"]
44+
accept = ["100..=103", "200..=299", "403..=403", "502..=502"]

notes/fix-redirects.md

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Redirect links management guide
2+
3+
## Scripts overview
4+
Two scripts help maintain internal links when pages are redirected:
5+
6+
* `check-redirects`: Identifies links that need updating based on the `_redirects` file.
7+
* `fix-redirects`: Automatically updates links to match `_redirects` entries.
8+
9+
## Checking for broken links
10+
11+
Run the check script:
12+
13+
```bash
14+
pnpm lint //OR
15+
pnpm check-redirects
16+
```
17+
## What it does
18+
19+
* Scans all `.mdx` files in the docs
20+
* Compares internal links against `_redirects` file
21+
* Reports any outdated links that need updating
22+
* Provides a summary of total, broken, and valid links
23+
24+
## Example output
25+
26+
```bash
27+
File "builders/overview.mdx" contains outdated link "/chain/overview" - should be updated to "/stack/overview"
28+
29+
Summary:
30+
Total pages 🔍 - 50
31+
Pages broken 🚫 - 2
32+
Pages OK ✅ - 48
33+
34+
```
35+
36+
## Fixing broken links
37+
38+
Fix links automatically:
39+
40+
```bash
41+
pnpm fix //OR
42+
pnpm fix-redirects
43+
```
44+
45+
## What it does
46+
47+
* Updates all internal links to match `_redirects` entries
48+
* Preserves other content and formatting
49+
* Shows which files and links were updated
50+
* Provides a summary of changes made
51+
52+
## Example output
53+
54+
```bash
55+
Fixed in "builders/overview.mdx": /chain/overview → /stack/overview
56+
57+
Summary:
58+
Total files 🔍 - 50
59+
Files fixed ✅ - 2
60+
Files skipped ⏭️ - 48
61+
```
62+
63+
## Best practices
64+
65+
1. Before running
66+
67+
* Commit current changes
68+
* Review `_redirects` file is up-to-date
69+
* Run `check-redirects` first to preview changes
70+
71+
72+
2. After running
73+
74+
* Review git diff of updated files
75+
* Test updated links locally
76+
* Commit changes with descriptive message
77+
78+
79+
80+
## Common issues
81+
82+
* Script fails: Ensure `_redirects` file exists in public folder, it should always be there!
83+
* No broken links found: Verify `_redirects` entries are correct.

package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
"version": "0.0.1",
44
"description": "Optimism Docs",
55
"scripts": {
6-
"lint": "eslint . --ext mdx --max-warnings 0 && pnpm spellcheck:lint && pnpm check-breadcrumbs",
7-
"fix": "eslint . --ext mdx --fix && pnpm spellcheck:fix && pnpm check-breadcrumbs",
6+
"lint": "eslint . --ext mdx --max-warnings 0 && pnpm spellcheck:lint && pnpm check-breadcrumbs && pnpm check-redirects",
7+
"fix": "eslint . --ext mdx --fix && pnpm spellcheck:fix && pnpm check-breadcrumbs && pnpm fix-redirects",
88
"spellcheck:lint": "cspell lint \"**/*.mdx\"",
99
"spellcheck:fix": "cspell --words-only --unique \"**/*.mdx\" | sort --ignore-case | uniq > words.txt",
1010
"linkcheck": "lychee --config ./lychee.toml --quiet \"./pages\"",
1111
"breadcrumbs":"npx ts-node --skip-project utils/create-breadcrumbs.ts",
12+
"check-redirects": "npx ts-node --skip-project utils/redirects.ts",
13+
"fix-redirects": "npx ts-node --skip-project utils/fix-redirects.ts",
1214
"check-breadcrumbs":"npx ts-node --skip-project utils/breadcrumbs.ts",
1315
"index:docs": "npx ts-node --skip-project utils/algolia-indexer.ts",
1416
"dev": "next dev",

pages/builders.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ Welcome to the Builders section. Here you'll find resources and guides for devel
1515
<Card title="App Developers" href="/builders/app-developers" />
1616
<Card title="Chain Operators" href="/builders/chain-operators" />
1717
<Card title="Node Operators" href="/builders/node-operators" />
18-
<Card title="Wallets & CEXs" href="/builders/cex-wallet-developers" />
18+
<Card title="Wallets & CEXs" href="/builders/app-developers/overview" />
1919
<Card title="Developer Tools" href="/builders/tools" />
2020
</Cards>

pages/builders/app-developers/overview.mdx

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ In this area of the Optimism Docs you'll find everything you need to know about
1616
If you're brand new to OP Mainnet, try starting with the guide on [deploying a basic contract](/chain/getting-started).
1717
It'll get you familiar with the basic steps required to get a contract deployed to the network.
1818
OP Mainnet is [EVM equivalent](https://web.archive.org/web/20231127160757/https://medium.com/ethereum-optimism/introducing-evm-equivalence-5c2021deb306) so you can feel confident that your existing Ethereum smart contract skills will carry over to OP Mainnet.
19-
Just make sure to be aware of the few small [differences between Ethereum and OP Mainnet](/chain/differences).
19+
Just make sure to be aware of the few small [differences between Ethereum and OP Mainnet](/stack/differences).
2020

2121
You might also want to check out the [testing on OP Networks guide](/chain/testing/testing-apps) and the tutorial on [running a local development environment](/chain/testing/dev-node) to help you feel totally confident in your OP Mainnet deployment.
2222

2323
<Cards>
24-
<Card title="Deploying Your First Contract to OP Mainnet" href="/builders/app-developers/tutorials/first-contract" icon={<img src="/img/icons/shapes.svg" />} />
24+
<Card title="Deploying Your First Contract to OP Mainnet" href="/builders/app-developers/overview" icon={<img src="/img/icons/shapes.svg" />} />
2525

26-
<Card title="Solidity Compatibility on OP Mainnet" href="/builders/app-developers/contracts/compatibility" icon={<img src="/img/icons/shapes.svg" />} />
26+
<Card title="Solidity Compatibility on OP Mainnet" href="/stack/differences" icon={<img src="/img/icons/shapes.svg" />} />
2727

2828
<Card title="Testing Apps on OP Mainnet" href="/chain/testing/testing-apps" icon={<img src="/img/icons/shapes.svg" />} />
2929
</Cards>

pages/builders/app-developers/tutorials/cross-dom-bridge-erc20.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Make sure to check out the [Standard Bridge guide](/builders/app-developers/brid
3131

3232
The Optimism SDK supports any of the [Superchain networks](/chain/networks).
3333
[Some Superchain networks](https://sdk.optimism.io/enums/l2chainid) are already included in the SDK by default.
34-
If you want to use a network that isn't included by default, you can simply [instantiate the SDK with the appropriate contract addresses](/builders/chain-operators/tutorials/sdk).
34+
If you want to use a network that isn't included by default, you can simply [instantiate the SDK with the appropriate contract addresses](/builders/app-developers/overview).
3535

3636
## Dependencies
3737

pages/builders/chain-operators/tutorials.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ This section provides information on adding attributes to the derivation functio
2323

2424
<Card title="Modifying predeployed contracts" href="/builders/chain-operators/tutorials/modifying-predeploys" />
2525

26-
<Card title="Using viem" href="/builders/chain-operators/tutorials/sdk" />
26+
<Card title="Using viem" href="/builders/app-developers/overview" />
2727
</Cards>

pages/chain/getting-started.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { Steps } from 'nextra/components'
1111
This guide explains the basics of OP Mainnet development.
1212
OP Mainnet is [EVM equivalent](https://web.archive.org/web/20231127160757/https://medium.com/ethereum-optimism/introducing-evm-equivalence-5c2021deb306), meaning we run a slightly modified version of the same `geth` you run on mainnet.
1313
Therefore, the differences between OP Mainnet development and Ethereum development are minor.
14-
But a few differences [do exist](/chain/differences).
14+
But a few differences [do exist](/stack/differences).
1515

1616
## OP Mainnet and OP Sepolia endpoint URLs
1717

pages/chain/testing/dev-node.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ We generally recommend using the local development environment if your applicati
2424

2525
1. **You're building contracts on both OP Mainnet and Ethereum that need to interact with one another.** The local development environment is a great way to quickly test interactions between L1 and L2. The OP Mainnet and test networks have a communication delay between L1 and L2 that can make testing slow during the early stages of development.
2626

27-
2. **You're building an application that might be subject to one of the few [differences between Ethereum and OP Mainnet](/chain/differences).** Although OP Mainnet is [EVM equivalent](https://web.archive.org/web/20231127160757/https://medium.com/ethereum-optimism/introducing-evm-equivalence-5c2021deb306), it's not exactly the same as Ethereum. If you're building an application that might be subject to one of these differences, you should use the local development environment to double check that everything is running as expected. You might otherwise have unexpected issues when you move to testnet. We strongly recommend reviewing these differences carefully to see if you might fall into this category.
27+
2. **You're building an application that might be subject to one of the few [differences between Ethereum and OP Mainnet](/stack/differences).** Although OP Mainnet is [EVM equivalent](https://web.archive.org/web/20231127160757/https://medium.com/ethereum-optimism/introducing-evm-equivalence-5c2021deb306), it's not exactly the same as Ethereum. If you're building an application that might be subject to one of these differences, you should use the local development environment to double check that everything is running as expected. You might otherwise have unexpected issues when you move to testnet. We strongly recommend reviewing these differences carefully to see if you might fall into this category.
2828

2929
However, not everyone will need to use the local development environment.
3030
OP Mainnet is [EVM equivalent](https://web.archive.org/web/20231127160757/https://medium.com/ethereum-optimism/introducing-evm-equivalence-5c2021deb306), which means that OP Mainnet looks almost exactly like Ethereum under the hood.

pages/index.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Whether you're a developer building a app on OP Mainnet, a node operator running
2222

2323
<Card title="Node operators" href="/builders/node-operators/rollup-node" icon={<img src="img/icons/computer-line.svg" />} />
2424

25-
<Card title="Wallets & CEXs" href="/builders/cex-wallet-developers/wallet-support" icon={<img src="img/icons/wallet.svg" />} />
25+
<Card title="Wallets & CEXs" href="/builders/app-developers/overview" icon={<img src="img/icons/wallet.svg" />} />
2626

2727
<Card title="Developer tools" href="/builders/tools/overview" icon={<img src="img/icons/tools.svg" />} />
2828

pages/stack/differences.mdx

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ However, there are some minor differences between the behavior of Ethereum and O
1616

1717
### Bridging - Deposit Transactions
1818

19-
Deposit transactions don't exist on L1's, and are how transactions on an L2 can be initiated from the L1. Importantly, this is how bridge applications can get L1 ETH or tokens into an L2 OP Stack chain. You can read more on deposit transactions [here](/stack/protocol/rollup/deposit-flow).
19+
Deposit transactions don't exist on L1's, and are how transactions on an L2 can be initiated from the L1. Importantly, this is how bridge applications can get L1 ETH or tokens into an L2 OP Stack chain. You can read more on deposit transactions [here](/stack/transactions/deposit-flow).
2020

2121
### Bridging - Withdrawal Transactions and Fault Proofs
2222

23-
Withdrawal transactions are how the state of the L2 rollup can be proven to the L1. Often this involves users withdrawing tokens or ETH to the L1. Fault proofs are the mechanism by which withdrawal transactions are currently proven to the L1. You can read more about fault proofs [here](/stack/protocol/fault-proofs/explainer).
23+
Withdrawal transactions are how the state of the L2 rollup can be proven to the L1. Often this involves users withdrawing tokens or ETH to the L1. Fault proofs are the mechanism by which withdrawal transactions are currently proven to the L1. You can read more about fault proofs [here](/stack/fault-proofs/explainer).
2424

2525
## Opcodes
2626

pages/stack/features/send-raw-transaction-conditional.mdx

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ Successful submission does **NOT** guarantee inclusion! The caller must observe
5656
This feature can be enabled with the addition of a flag to op-geth.
5757

5858
* `--rollup.sequencertxconditionalenabled` (default: false) a boolean flag which enables the rpc.
59-
* `--rollup.sequencertxconditionalcostratelimit` (default: 5000) an integer flag that sets the rate limit for cost observable per second.
59+
* `--rollup.sequencertxconditionalcostratelimit` (default: 5000) an integer flag that sets the rate limit for cost observable per second.
6060

6161
<Callout type="warning">
62-
It is not advised to publicly expose this sequencer endpoint due to DoS concerns. This supplemental proxy, [op-txproxy](/stack/operators/features/op-txproxy), should be used to apply additional constraints on this endpoint prior to passing through to the sequencer.
62+
It is not advised to publicly expose this sequencer endpoint due to DoS concerns. This supplemental proxy, [op-txproxy](/builders/chain-operators/tools/op-txproxy), should be used to apply additional constraints on this endpoint prior to passing through to the sequencer.
6363
</Callout>

pages/stack/getting-started.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { Callout } from 'nextra/components'
1616

1717
The OP Stack consists of the many different software components managed and maintained by the Optimism Collective that, together, form the backbone of Optimism.
1818
The OP Stack is built as a public good for the Ethereum and Optimism ecosystems.
19-
To understand how to operate an OP Stack chain, including roll-up and chain deployment basics, visit [Chain Operator guide](/builders/chain-operators/self-hosted). Check out these guides to get an overview of everything you need to know to properly support OP mainnet within your [exchange](/builders/cex-wallet-developers/cex-support) and [wallet](/builders/cex-wallet-developers/wallet-support).
19+
To understand how to operate an OP Stack chain, including roll-up and chain deployment basics, visit [Chain Operator guide](/builders/chain-operators/self-hosted). Check out these guides to get an overview of everything you need to know to properly support OP mainnet within your [exchange](/builders/app-developers/overview) and [wallet](/builders/app-developers/overview).
2020

2121
## The OP Stack powers Optimism
2222

pages/stack/interop/assets/deploy-superchain-erc20.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { Steps } from 'nextra/components'
1313
Interop is currently in active development and not yet ready for production use. The information provided here may change. Check back regularly for the most up-to-date information.
1414
</Callout>
1515

16-
This guide explains how to issue new assets with the `SuperchainERC20` and bridge them effectively using the `SuperchainERC20Bridge`. If you want more information about the `SuperchainERC20 standard`, see our [`SuperchainERC20` standard explainer](/stack/interop/superchain-erc20)
16+
This guide explains how to issue new assets with the `SuperchainERC20` and bridge them effectively using the `SuperchainERC20Bridge`. If you want more information about the `SuperchainERC20 standard`, see our [`SuperchainERC20` standard explainer](/stack/interop/assets/superchain-erc20)
1717

1818
Note that bridging assets through the Superchain using `SuperchainERC20` never affects the total supply of your asset. The supply remains fixed, and bridging only changes the chain on which your asset is located. This keeps the token's total amount the same across all networks, ensuring its value stays stable during the move and that the `SuperchainERC20` retains a unified, global supply count.
1919

pages/stack/interop/explainer.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Native OP Stack interoperability provides the ability to read messages and trans
2424
Superchain interop includes both the protocol layer message passing and the Superchain ERC20 token specification.
2525

2626
* **Message passing protocol:** the initial + finalizing/executing [message](cross-chain-message) that fire events to be consumed by the chains in the [dependency set](https://specs.optimism.io/interop/dependency-set.html)
27-
* **SuperchainERC20 token specification**: the [SuperchainERC20](superchain-erc20) turns message passing into asset transfer between chains in the interop set. Learn more about how the SuperchainERC20 token standard enables asset interoperability in the Superchain [here](/stack/interop/superchain-erc20)
27+
* **SuperchainERC20 token specification**: the [SuperchainERC20](superchain-erc20) turns message passing into asset transfer between chains in the interop set. Learn more about how the SuperchainERC20 token standard enables asset interoperability in the Superchain [here](/stack/interop/assets/superchain-erc20)
2828

2929
This means ETH and ERC-20s can seamlessly and securely move across L2s, and intent-based protocols (i.e., bridges) can build better experiences on top of the message passing protocol.
3030

utils/fix-redirects.ts

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import * as fs from 'fs/promises';
2+
import * as path from 'path';
3+
4+
const rootDir = path.join(process.cwd(), 'pages');
5+
const redirectsPath = path.join(process.cwd(), 'public', '_redirects');
6+
const updates: string[] = [];
7+
8+
// ANSI color codes
9+
const WHITE = '\x1b[37m';
10+
const GREEN = '\x1b[32m';
11+
const YELLOW = '\x1b[33m';
12+
const RESET = '\x1b[0m';
13+
const BOLD = '\x1b[1m';
14+
15+
interface Redirect {
16+
from: string;
17+
to: string;
18+
}
19+
20+
interface Summary {
21+
total: number;
22+
fixed: number;
23+
skipped: number;
24+
}
25+
26+
async function getRedirects(): Promise<Redirect[]> {
27+
const content = await fs.readFile(redirectsPath, 'utf-8');
28+
return content.split('\n')
29+
.filter(line => line.trim() && !line.startsWith('#'))
30+
.map(line => {
31+
const [from, to] = line.split(/\s+/);
32+
return { from, to };
33+
});
34+
}
35+
36+
async function findMdxFiles(dir: string): Promise<string[]> {
37+
const files: string[] = [];
38+
const entries = await fs.readdir(dir, { withFileTypes: true });
39+
40+
for (const entry of entries) {
41+
const fullPath = path.join(dir, entry.name);
42+
if (entry.isDirectory() && !entry.name.startsWith('_')) {
43+
files.push(...await findMdxFiles(fullPath));
44+
} else if (entry.isFile() && /\.(md|mdx)$/.test(entry.name)) {
45+
files.push(fullPath);
46+
}
47+
}
48+
return files;
49+
}
50+
51+
async function fixFile(filePath: string, redirects: Redirect[]): Promise<boolean> {
52+
let content = await fs.readFile(filePath, 'utf-8');
53+
let hasChanges = false;
54+
const relativeFilePath = path.relative(rootDir, filePath);
55+
56+
redirects.forEach(redirect => {
57+
const markdownRegex = new RegExp(`\\[([^\\]]+)\\]\\(${redirect.from}\\)`, 'g');
58+
const hrefRegex = new RegExp(`href="${redirect.from}"`, 'g');
59+
60+
if (content.match(markdownRegex) || content.match(hrefRegex)) {
61+
content = content
62+
.replace(markdownRegex, `[$1](${redirect.to})`)
63+
.replace(hrefRegex, `href="${redirect.to}"`);
64+
65+
updates.push(`${WHITE}Fixed in "${relativeFilePath}": ${YELLOW}${redirect.from}${WHITE}${GREEN}${redirect.to}${RESET}`);
66+
hasChanges = true;
67+
}
68+
});
69+
70+
if (hasChanges) {
71+
await fs.writeFile(filePath, content);
72+
}
73+
74+
return hasChanges;
75+
}
76+
77+
function printSummary(summary: Summary) {
78+
console.log('\nSummary:');
79+
console.log(`${WHITE}Total files 🔍 - ${summary.total}`);
80+
console.log(`${GREEN}Files fixed ✅ - ${summary.fixed}`);
81+
console.log(`${WHITE}Files skipped ⏭️ - ${summary.skipped}${RESET}`);
82+
}
83+
84+
async function main() {
85+
const summary: Summary = {
86+
total: 0,
87+
fixed: 0,
88+
skipped: 0
89+
};
90+
91+
console.log('Starting to fix redirect links...');
92+
console.log('Root directory:', rootDir);
93+
94+
try {
95+
const redirects = await getRedirects();
96+
const files = await findMdxFiles(rootDir);
97+
98+
summary.total = files.length;
99+
100+
for (const file of files) {
101+
const wasFixed = await fixFile(file, redirects);
102+
if (wasFixed) {
103+
summary.fixed++;
104+
} else {
105+
summary.skipped++;
106+
}
107+
}
108+
109+
if (updates.length > 0) {
110+
console.log(`${GREEN}${BOLD}Fixed links:${RESET}`);
111+
updates.forEach(update => console.log(update));
112+
printSummary(summary);
113+
} else {
114+
console.log(`${GREEN}No broken links found. Everything is up to date.${RESET}`);
115+
printSummary(summary);
116+
}
117+
} catch (error) {
118+
console.error(`${YELLOW}${BOLD}Error fixing redirects:${RESET}`, error);
119+
process.exit(1);
120+
}
121+
}
122+
123+
main().catch(error => {
124+
console.error(`${YELLOW}${BOLD}Error in main process:${RESET}`, error);
125+
process.exit(1);
126+
});

0 commit comments

Comments
 (0)