diff --git a/.github/workflows/breadcrumbs.yml b/.github/workflows/breadcrumbs.yml
new file mode 100644
index 000000000..a077cf137
--- /dev/null
+++ b/.github/workflows/breadcrumbs.yml
@@ -0,0 +1,32 @@
+name: Check Breadcrumbs
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+ paths:
+ - 'pages/**/*.mdx'
+ - 'pages/**/*.md'
+
+jobs:
+ check-breadcrumbs:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Check out code
+ uses: actions/checkout@v2
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v2
+ with:
+ node-version: '20.x'
+
+ - name: Install pnpm
+ run: npm install -g pnpm
+
+ - name: Install dependencies
+ run: pnpm install
+
+ - name: Run breadcrumb check
+ run: pnpm check-breadcrumbs
\ No newline at end of file
diff --git a/notes/breadcrumbs.md b/notes/breadcrumbs.md
index e30512e7f..c05467848 100644
--- a/notes/breadcrumbs.md
+++ b/notes/breadcrumbs.md
@@ -11,10 +11,16 @@ Quick guide on using our breadcrumbs automation script for the OP Stack document
## Using the Script
-Breadcrumbs for the docs can be generated by running:
+* Breadcrumbs for the docs can be generated by running:
```bash
-pnpm create-breadcrumbs
+pnpm breadcrumbs
+```
+
+* To check files with missing breadcrumbs, run:
+
+```bash
+pnpm fix
```
### What to Watch For
@@ -26,7 +32,7 @@ pnpm create-breadcrumbs
2. **After Running**
* Review generated `.mdx` files in each folder
- * Check updated descriptions
+ * Check updated descriptions, please update the description.
* Verify Card components and links
## Common Issues
diff --git a/package.json b/package.json
index 6f0b17b6a..b1690e4f0 100644
--- a/package.json
+++ b/package.json
@@ -3,12 +3,13 @@
"version": "0.0.1",
"description": "Optimism Docs",
"scripts": {
- "lint": "eslint . --ext mdx --max-warnings 0 && pnpm spellcheck:lint",
- "fix": "eslint . --ext mdx --fix && pnpm spellcheck:fix",
+ "lint": "eslint . --ext mdx --max-warnings 0 && pnpm spellcheck:lint && pnpm check-breadcrumbs",
+ "fix": "eslint . --ext mdx --fix && pnpm spellcheck:fix && pnpm check-breadcrumbs",
"spellcheck:lint": "cspell lint \"**/*.mdx\"",
"spellcheck:fix": "cspell --words-only --unique \"**/*.mdx\" | sort --ignore-case | uniq > words.txt",
"linkcheck": "lychee --config ./lychee.toml --quiet \"./pages\"",
- "create-breadcrumbs":"npx ts-node --skip-project utils/create-breadcrumbs.ts",
+ "breadcrumbs":"npx ts-node --skip-project utils/create-breadcrumbs.ts",
+ "check-breadcrumbs":"npx ts-node --skip-project utils/breadcrumbs.ts",
"index:docs": "npx ts-node --skip-project utils/algolia-indexer.ts",
"dev": "next dev",
"build": "next build",
diff --git a/pages/builders/app-developers.mdx b/pages/builders/app-developers.mdx
index 4bf0f90ce..c5dc109d2 100644
--- a/pages/builders/app-developers.mdx
+++ b/pages/builders/app-developers.mdx
@@ -1,28 +1,27 @@
---
title: App Developers
+description: If you're a developer looking to build on OP Stack, you've come to the right place. In this area of the Optimism Docs you'll find everything you ...
lang: en-US
-description: Essential resources for app developers building on the OP Stack, including guides for deploying contracts, handling transactions, and cross-chain messaging.
---
import { Card, Cards } from 'nextra/components'
# App Developers
-Welcome to the App Developers section, where you'll find essential resources for deploying contracts, handling transactions, cross-chain messaging, and more.
-Access quick-start guides, tutorials, and tools to help you build applications on the OP Stack efficiently
+If you're a developer looking to build on OP Mainnet, you've come to the right place. In this area of the Optimism Docs you'll find everything you ...
-
+
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/pages/builders/app-developers/contracts.mdx b/pages/builders/app-developers/contracts.mdx
index 6c01b91e2..f2836e72d 100644
--- a/pages/builders/app-developers/contracts.mdx
+++ b/pages/builders/app-developers/contracts.mdx
@@ -18,4 +18,6 @@ This section provides information on Solidity compatibility, contract optimizati
+
+
diff --git a/pages/builders/cex-wallet-developers.mdx b/pages/builders/cex-wallet-developers.mdx
index 0ac230932..aedc0e7eb 100644
--- a/pages/builders/cex-wallet-developers.mdx
+++ b/pages/builders/cex-wallet-developers.mdx
@@ -1,19 +1,17 @@
---
-title: CEX Wallet Developers
-description: >-
- This section provides information on supporting OP Stack in your exchange and
- supporting OP Stack in your wallet. You'll find guide to help you...
+title: Cex Wallet Developers
+description: Documentation covering Cex Support, Wallet Support in the Cex Wallet Developers section of the OP Stack ecosystem.
lang: en-US
---
import { Card, Cards } from 'nextra/components'
-# CEX Wallet Developers
+# Cex Wallet Developers
-This section provides information on supporting op mainnet in your exchange and supporting op mainnet in your wallet. You'll find guide to help you understand and work with these topics.
+Documentation covering Cex Support, Wallet Support in the Cex Wallet Developers section of the OP Stack ecosystem.
-
+
-
+
diff --git a/pages/builders/chain-operators.mdx b/pages/builders/chain-operators.mdx
index 872c69d26..73c0e4bb9 100644
--- a/pages/builders/chain-operators.mdx
+++ b/pages/builders/chain-operators.mdx
@@ -1,21 +1,21 @@
---
title: Chain Operators
+description: Documentation covering Architecture, Configuration, Deploy, Features, Hacks, Management, Self Hosted, Tools, Tutorials in the Chain Operators section of the OP Stack ecosystem.
lang: en-US
-description: Information on chain architecture, configuration, deployment, and management for OP Stack chain operators.
---
import { Card, Cards } from 'nextra/components'
-# Chain operators
+# Chain Operators
-This section provides information on chain architecture, configuration, deployment, features, hacks, management, and how to start a self-hosted chain. You'll also find tools, APIs, overviews, guides, and introductions to help you understand and work with these topics.
+Documentation covering Architecture, Configuration, Deploy, Features, Hacks, Management, Self Hosted, Tools, Tutorials in the Chain Operators section of the OP Stack ecosystem.
-
+
@@ -23,7 +23,7 @@ This section provides information on chain architecture, configuration, deployme
-
+
diff --git a/pages/builders/chain-operators/tools.mdx b/pages/builders/chain-operators/tools.mdx
index 1b8103c61..c8018d508 100644
--- a/pages/builders/chain-operators/tools.mdx
+++ b/pages/builders/chain-operators/tools.mdx
@@ -21,5 +21,9 @@ This section provides information on chain monitoring options, deploying a block
+
+
+
+
diff --git a/pages/builders/node-operators.mdx b/pages/builders/node-operators.mdx
index bd2ffdeba..9d25972cb 100644
--- a/pages/builders/node-operators.mdx
+++ b/pages/builders/node-operators.mdx
@@ -1,6 +1,6 @@
---
title: Node Operators
-description: This section provides information on node architecture, configuration, json rpc api, management, network upgrades, node software releases, how to run...
+description: Documentation covering Architecture, Configuration, Json Rpc, Management, Network Upgrades, Releases, Rollup Node, Tutorials in the Node Operators section of the OP Stack ecosystem.
lang: en-US
---
@@ -8,22 +8,22 @@ import { Card, Cards } from 'nextra/components'
# Node Operators
-This section provides information on node architecture, configuration, json rpc api, management, network upgrades, node software releases, how to run a node in the superchain and tutorials. You'll find api, guide, overview to help you understand and work with these topics.
+Documentation covering Architecture, Configuration, Json Rpc, Management, Network Upgrades, Releases, Rollup Node, Tutorials in the Node Operators section of the OP Stack ecosystem.
-
+
-
+
-
+
diff --git a/pages/builders/notices.mdx b/pages/builders/notices.mdx
index 53ca1701f..27aaaa0ab 100644
--- a/pages/builders/notices.mdx
+++ b/pages/builders/notices.mdx
@@ -1,6 +1,6 @@
---
title: Notices
-description: This section provides information on preparing for fault proofs breaking changes, preparing for granite breaking changes and deprecation of the...
+description: Documentation covering Sdk Deprecation in the Notices section of the OP Stack ecosystem.
lang: en-US
---
@@ -8,8 +8,8 @@ import { Card, Cards } from 'nextra/components'
# Notices
-This section offers essential information for builders to stay up-to-date with the latest changes in the OP Stack.
+Documentation covering Sdk Deprecation in the Notices section of the OP Stack ecosystem.
-
+
diff --git a/pages/builders/tools.mdx b/pages/builders/tools.mdx
index 4541d4cd8..354ca94dd 100644
--- a/pages/builders/tools.mdx
+++ b/pages/builders/tools.mdx
@@ -1,6 +1,6 @@
---
title: Tools
-description: This section provides information on build, connect, fjord fee parameter calculator, monitor, op tools and developer tools. You'll find guide, tool,...
+description: Welcome to the Optimism developer tools!
lang: en-US
---
@@ -8,7 +8,7 @@ import { Card, Cards } from 'nextra/components'
# Tools
-This section provides information on build, connect, fjord fee parameter calculator, monitor, op tools and developer tools. You'll find guide, tool, overview to help you understand and work with these topics.
+Welcome to the Optimism developer tools!
@@ -19,7 +19,7 @@ This section provides information on build, connect, fjord fee parameter calcula
-
+
diff --git a/pages/chain/identity.mdx b/pages/chain/identity.mdx
index 2f9a23ac9..87c4b79e5 100644
--- a/pages/chain/identity.mdx
+++ b/pages/chain/identity.mdx
@@ -1,6 +1,6 @@
---
title: Identity
-description: This section provides information on about attestations, attestation apps, contracts (eas), individual identity, organizations, identity overview,...
+description: This guide explains the role of decentralized identity in the Optimism Collective and its key components.
lang: en-US
---
@@ -8,14 +8,14 @@ import { Card, Cards } from 'nextra/components'
# Identity
-This section provides information on about attestations, attestation apps, contracts (eas), individual identity, organizations, identity overview, projects and schemas. You'll find guide, reference, overview to help you understand and work with these topics.
+This guide explains the role of decentralized identity in the Optimism Collective and its key components.
-
+
-
+
diff --git a/pages/chain/security.mdx b/pages/chain/security.mdx
index b1a09682c..e4f10a998 100644
--- a/pages/chain/security.mdx
+++ b/pages/chain/security.mdx
@@ -1,8 +1,6 @@
---
title: Security
-description: >-
- This section provides information on OP Stack security model, privileged roles
- in OP Stack and security policy and bug bounty program.
+description: Documentation covering Faq, Privileged Roles, Security Policy in the Security section of the OP Stack ecosystem.
lang: en-US
---
@@ -10,12 +8,12 @@ import { Card, Cards } from 'nextra/components'
# Security
-This section provides information on op mainnet security model, privileged roles in op mainnet and security policy and bug bounty program.
+Documentation covering Faq, Privileged Roles, Security Policy in the Security section of the OP Stack ecosystem.
-
+
-
+
diff --git a/pages/chain/testing.mdx b/pages/chain/testing.mdx
index 923766e11..fc2af6d47 100644
--- a/pages/chain/testing.mdx
+++ b/pages/chain/testing.mdx
@@ -1,8 +1,6 @@
---
title: Testing
-description: >-
- This section provides information on running a local development environment
- and testing apps for OP Stack. You'll find tutorial, guide to help you...
+description: Documentation covering Dev Node, Testing Apps in the Testing section of the OP Stack ecosystem.
lang: en-US
---
@@ -10,10 +8,10 @@ import { Card, Cards } from 'nextra/components'
# Testing
-This section provides information on running a local development environment and testing apps for op mainnet. You'll find tutorial, guide to help you understand and work with these topics.
+Documentation covering Dev Node, Testing Apps in the Testing section of the OP Stack ecosystem.
-
+
diff --git a/pages/connect/contribute.mdx b/pages/connect/contribute.mdx
index 8ef9eb298..a7cf78027 100644
--- a/pages/connect/contribute.mdx
+++ b/pages/connect/contribute.mdx
@@ -1,6 +1,6 @@
---
title: Contribute
-description: This section provides information on ways to contribute to optimism docs, contribute to the op stack and optimism docs style guide. You'll find...
+description: Documentation covering Docs Contribute, Stack Contribute, Style Guide in the Contribute section of the OP Stack ecosystem.
lang: en-US
---
@@ -8,12 +8,10 @@ import { Card, Cards } from 'nextra/components'
# Contribute
-This section provides information on ways to contribute to optimism docs, contribute to the op stack and optimism docs style guide. You'll find tutorial, overview, guide to help you understand and work with these topics.
+Documentation covering Docs Contribute, Stack Contribute, Style Guide in the Contribute section of the OP Stack ecosystem.
-
-
-
-
-
+
+
+
diff --git a/pages/connect/resources.mdx b/pages/connect/resources.mdx
index 80b083fe7..a4ae2c526 100644
--- a/pages/connect/resources.mdx
+++ b/pages/connect/resources.mdx
@@ -1,6 +1,6 @@
---
title: Resources
-description: This section provides information on . You'll find concept to help you understand and work with these topics.
+description: Documentation covering Glossary in the Resources section of the OP Stack ecosystem.
lang: en-US
---
@@ -8,7 +8,7 @@ import { Card, Cards } from 'nextra/components'
# Resources
-This section provides information on . You'll find concept to help you understand and work with these topics.
+Documentation covering Glossary in the Resources section of the OP Stack ecosystem.
diff --git a/pages/stack/beta-features.mdx b/pages/stack/beta-features.mdx
new file mode 100644
index 000000000..24257e8e3
--- /dev/null
+++ b/pages/stack/beta-features.mdx
@@ -0,0 +1,17 @@
+---
+title: Beta Features
+description: Documentation covering Alt Da Mode, Custom Gas Token in the Beta Features section of the OP Stack ecosystem.
+lang: en-US
+---
+
+import { Card, Cards } from 'nextra/components'
+
+# Beta Features
+
+Documentation covering Alt Da Mode, Custom Gas Token in the Beta Features section of the OP Stack ecosystem.
+
+
+
+
+
+
diff --git a/pages/stack/fault-proofs.mdx b/pages/stack/fault-proofs.mdx
new file mode 100644
index 000000000..4da08bb26
--- /dev/null
+++ b/pages/stack/fault-proofs.mdx
@@ -0,0 +1,25 @@
+---
+title: Fault Proofs
+description: Documentation covering Cannon, Challenger, Explainer, Fp Components, Fp Security, Mips in the Fault Proofs section of the OP Stack ecosystem.
+lang: en-US
+---
+
+import { Card, Cards } from 'nextra/components'
+
+# Fault Proofs
+
+Documentation covering Cannon, Challenger, Explainer, Fp Components, Fp Security, Mips in the Fault Proofs section of the OP Stack ecosystem.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/stack/features.mdx b/pages/stack/features.mdx
new file mode 100644
index 000000000..84cad55a4
--- /dev/null
+++ b/pages/stack/features.mdx
@@ -0,0 +1,15 @@
+---
+title: Features
+description: Documentation covering Send Raw Transaction Conditional in the Features section of the OP Stack ecosystem.
+lang: en-US
+---
+
+import { Card, Cards } from 'nextra/components'
+
+# Features
+
+Documentation covering Send Raw Transaction Conditional in the Features section of the OP Stack ecosystem.
+
+
+
+
diff --git a/pages/stack/interop.mdx b/pages/stack/interop.mdx
new file mode 100644
index 000000000..b7823d3b7
--- /dev/null
+++ b/pages/stack/interop.mdx
@@ -0,0 +1,29 @@
+---
+title: Interop
+description: Documentation covering Cross Chain Message, Explainer, Message Passing, Op Supervisor, Superchain Erc20, Superchain Weth, Supersim, Transfer Superchainerc20 in the Interop section of the OP Stack ecosystem.
+lang: en-US
+---
+
+import { Card, Cards } from 'nextra/components'
+
+# Interop
+
+Documentation covering Cross Chain Message, Explainer, Message Passing, Op Supervisor, Superchain Erc20, Superchain Weth, Supersim, Transfer Superchainerc20 in the Interop section of the OP Stack ecosystem.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/stack/research.mdx b/pages/stack/research.mdx
new file mode 100644
index 000000000..1a485ee0f
--- /dev/null
+++ b/pages/stack/research.mdx
@@ -0,0 +1,15 @@
+---
+title: Research
+description: Documentation covering Block Time Research in the Research section of the OP Stack ecosystem.
+lang: en-US
+---
+
+import { Card, Cards } from 'nextra/components'
+
+# Research
+
+Documentation covering Block Time Research in the Research section of the OP Stack ecosystem.
+
+
+
+
diff --git a/pages/stack/rollup.mdx b/pages/stack/rollup.mdx
new file mode 100644
index 000000000..ca95c2564
--- /dev/null
+++ b/pages/stack/rollup.mdx
@@ -0,0 +1,19 @@
+---
+title: Rollup
+description: The big idea that makes Optimism possible is the Optimistic Rollup. We'll go through a brief explainer of *how* Optimistic Rollups work at a high l...
+lang: en-US
+---
+
+import { Card, Cards } from 'nextra/components'
+
+# Rollup
+
+The big idea that makes Optimism possible is the Optimistic Rollup. We'll go through a brief explainer of *how* Optimistic Rollups work at a high l...
+
+
+
+
+
+
+
+
diff --git a/pages/stack/security.mdx b/pages/stack/security.mdx
index 11e8a0d7c..fbf62b199 100644
--- a/pages/stack/security.mdx
+++ b/pages/stack/security.mdx
@@ -1,6 +1,6 @@
---
title: Security
-description: This section provides information on op stack security faqs and pausing the bridge.
+description: Documentation covering Faq, Pause in the Security section of the OP Stack ecosystem.
lang: en-US
---
@@ -8,10 +8,10 @@ import { Card, Cards } from 'nextra/components'
# Security
-This section provides information on op stack security faqs and pausing the bridge.
+Documentation covering Faq, Pause in the Security section of the OP Stack ecosystem.
-
+
diff --git a/pages/stack/transactions.mdx b/pages/stack/transactions.mdx
index 929eea7c7..42bfac5a8 100644
--- a/pages/stack/transactions.mdx
+++ b/pages/stack/transactions.mdx
@@ -1,6 +1,6 @@
---
title: Transactions
-description: This section provides information on . You'll find reference to help you understand and work with these topics.
+description: Documentation covering Cross Domain, Deposit Flow, Fees, Forced Transaction, Transaction Flow, Transactions, Withdrawal Flow in the Transactions section of the OP Stack ecosystem.
lang: en-US
---
@@ -8,8 +8,20 @@ import { Card, Cards } from 'nextra/components'
# Transactions
-This section provides information on . You'll find reference to help you understand and work with these topics.
+Documentation covering Cross Domain, Deposit Flow, Fees, Forced Transaction, Transaction Flow, Transactions, Withdrawal Flow in the Transactions section of the OP Stack ecosystem.
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/stack/transactions/transactions.mdx b/pages/stack/transactions/transactions.mdx
new file mode 100644
index 000000000..02d703c69
--- /dev/null
+++ b/pages/stack/transactions/transactions.mdx
@@ -0,0 +1,25 @@
+---
+title: Transactions
+description: Documentation covering Cross Domain, Deposit Flow, Fees, Forced Transaction, Transaction Flow, Withdrawal Flow in the Transactions section of the OP Stack ecosystem.
+lang: en-US
+---
+
+import { Card, Cards } from 'nextra/components'
+
+# Transactions
+
+Documentation covering Cross Domain, Deposit Flow, Fees, Forced Transaction, Transaction Flow, Withdrawal Flow in the Transactions section of the OP Stack ecosystem.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/utils/breadcrumbs.ts b/utils/breadcrumbs.ts
new file mode 100644
index 000000000..ff00309d7
--- /dev/null
+++ b/utils/breadcrumbs.ts
@@ -0,0 +1,154 @@
+import * as fs from 'fs/promises';
+import * as path from 'path';
+import matter from 'gray-matter';
+
+const rootDir: string = path.join(__dirname, '..', 'pages');
+const warnings: string[] = [];
+
+// ANSI color codes
+const YELLOW = '\x1b[33m';
+const RESET = '\x1b[0m';
+const BOLD = '\x1b[1m';
+
+interface FileInfo {
+ title: string;
+ url: string;
+ description?: string;
+ content: string;
+}
+
+// Pages to exclude from checks
+const excludedPages = [
+ '400.mdx',
+ '500.mdx',
+ 'index.mdx',
+ '404.mdx',
+ 'console',
+ 'block-explorer',
+ 'bridge',
+ 'sdk',
+ 'faucet',
+ 'gas',
+ 'bug-bounty',
+ 'live-support',
+ 'governance',
+ 'changelog',
+ 'experimental'
+];
+
+async function getContentFiles(folderPath: string): Promise {
+ const files = await fs.readdir(folderPath, { withFileTypes: true });
+ const fileInfos: FileInfo[] = [];
+ const folderName = path.basename(folderPath);
+
+ for (const file of files) {
+ if (file.name.startsWith('_') ||
+ file.name.startsWith('.') ||
+ excludedPages.includes(file.name)) {
+ continue;
+ }
+
+ const filePath = path.join(folderPath, file.name);
+
+ if (file.isFile() && (file.name.endsWith('.md') || file.name.endsWith('.mdx'))) {
+ try {
+ const content = await fs.readFile(filePath, 'utf-8');
+ const { data: frontMatter } = matter(content);
+ const fileName = path.basename(file.name, path.extname(file.name));
+ const fileTitle = frontMatter.title || fileName;
+ const relativeUrl = `/${path.relative(rootDir, filePath)}`.replace(/\.(md|mdx)$/, '');
+
+ fileInfos.push({
+ title: fileTitle,
+ url: relativeUrl,
+ description: frontMatter.description,
+ content: content
+ });
+ } catch (error) {
+ console.error(`Error processing file ${file.name}:`, error);
+ }
+ }
+ }
+
+ return fileInfos;
+}
+
+async function getBreadcrumbCards(breadcrumbPath: string): Promise> {
+ try {
+ const content = await fs.readFile(breadcrumbPath, 'utf-8');
+ const cardMatches = content.match(/]*href="([^"]+)"[^>]*>/g) || [];
+ return new Set(
+ cardMatches.map(match => {
+ const hrefMatch = match.match(/href="([^"]+)"/);
+ return hrefMatch ? hrefMatch[1] : '';
+ }).filter(Boolean)
+ );
+ } catch (error) {
+ return new Set();
+ }
+}
+
+async function checkDirectory(dirPath: string): Promise {
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
+
+ for (const entry of entries) {
+ if (entry.isDirectory() && !entry.name.startsWith('_') && !entry.name.startsWith('.')) {
+ const folderPath = path.join(dirPath, entry.name);
+ const breadcrumbPath = path.join(dirPath, `${entry.name}.mdx`);
+
+ // Get all content files in the folder
+ const files = await getContentFiles(folderPath);
+
+ // Get existing cards in breadcrumb
+ const existingCards = await getBreadcrumbCards(breadcrumbPath);
+
+ // Check for missing pages
+ files.forEach(({ title, url }) => {
+ if (!existingCards.has(url)) {
+ warnings.push(
+ `Page "${title}" at ${url} needs to be added to the breadcrumb file ${entry.name}.mdx`
+ );
+ }
+ });
+
+ // Recursively check subdirectories
+ await checkDirectory(folderPath);
+ }
+ }
+}
+
+async function main() {
+ console.log('Starting breadcrumb check process...');
+ console.log('Root directory:', rootDir);
+
+ try {
+ // Process main sections: builders, chain, connect, stack
+ const mainSections = ['builders', 'chain', 'connect', 'stack'];
+ for (const section of mainSections) {
+ const sectionPath = path.join(rootDir, section);
+ try {
+ await fs.access(sectionPath);
+ await checkDirectory(sectionPath);
+ console.log(`Completed checking ${section} section`);
+ } catch (error) {
+ console.log(`Skipping ${section} - directory not found`);
+ }
+ }
+
+ if (warnings.length > 0) {
+ console.log(`${YELLOW}${BOLD}Missing pages in breadcrumb navigation:${RESET}`);
+ warnings.forEach(warning => console.log(`${YELLOW}- ${warning}${RESET}`));
+ process.exit(1);
+ } else {
+ console.log('All pages are properly referenced in breadcrumb files.');
+ }
+ } catch (error) {
+ console.log(`${YELLOW}${BOLD}Error checking breadcrumbs:${RESET}`, error);
+ process.exit(1);
+ }
+}
+
+main().catch(error => {
+ console.error('Error in main process:', error);
+ process.exit(1);
+});
diff --git a/utils/create-breadcrumbs.ts b/utils/create-breadcrumbs.ts
index 7bfab9804..370e44bc4 100644
--- a/utils/create-breadcrumbs.ts
+++ b/utils/create-breadcrumbs.ts
@@ -2,85 +2,255 @@ import * as fs from 'fs/promises';
import * as path from 'path';
import matter from 'gray-matter';
-const targetFolders: string[] = ['builders', 'chain', 'stack', 'connect'];
const rootDir: string = path.join(__dirname, '..', 'pages');
interface FileInfo {
title: string;
url: string;
+ description?: string;
+ content: string;
}
-function updateOPTerminology(description: string): string {
+// Pages to exclude
+const excludedPages = [
+ '400.mdx',
+ '500.mdx',
+ 'index.mdx',
+ '404.mdx',
+ '_app.tsx',
+ '_document.tsx',
+ '_meta.json'
+];
- if (description.includes('OP Stack')) {
- return description;
- }
+function toTitleCase(str: string): string {
+ return str.split('-')
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
+ .join(' ');
+}
+
+function extractFirstParagraph(content: string): string {
+ // Remove frontmatter
+ content = content.replace(/^---[\s\S]*?---/, '');
+
+ // Remove import statements
+ content = content.replace(/^import[\s\S]*?\n/gm, '');
+
+ // Remove HTML/MDX tags
+ content = content.replace(/<[^>]+>/g, ' ');
+
+ // Remove markdown links but keep text
+ content = content.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1');
- // Replace variations of "OP Mainnet" with "OP Stack"
- return description
- .replace(/\bOP Mainnet\b/gi, 'OP Stack')
- .replace(/\bOptimism Mainnet\b/gi, 'OP Stack')
- .replace(/\bOptimism mainnet\b/gi, 'OP Stack');
+ // Remove headers
+ content = content.replace(/^#.+$/gm, '');
+
+ const paragraphs = content.split(/\n\n+/);
+ const firstParagraph = paragraphs.find(p => {
+ const cleaned = p.trim();
+ return cleaned.length > 30 && // Minimum length
+ !cleaned.startsWith('import') &&
+ !cleaned.startsWith('export');
+ });
+
+ if (firstParagraph) {
+ const cleaned = firstParagraph.replace(/\s+/g, ' ').trim();
+ return cleaned.length > 150 ? cleaned.slice(0, 147) + '...' : cleaned;
+ }
+
+ return '';
}
-const updateBreadcrumbFile = async (filePath: string): Promise => {
- try {
- const content = await fs.readFile(filePath, 'utf-8');
- const { data: frontMatter, content: fileContent } = matter(content);
+async function generateFolderDescription(folderName: string, files: FileInfo[]): Promise {
+ if (files.length === 0) {
+ return `Documentation for ${toTitleCase(folderName)} is coming soon.`;
+ }
- if (frontMatter.description &&
- frontMatter.description.match(/\bOP Mainnet\b|\bOptimism Mainnet\b/gi) &&
- !frontMatter.description.includes('OP Stack')) {
+ // Try to find overview or introduction file
+ const overviewFile = files.find(file =>
+ file.url.toLowerCase().includes('overview') ||
+ file.url.toLowerCase().includes('introduction')
+ );
- frontMatter.description = updateOPTerminology(frontMatter.description);
-
+ if (overviewFile && overviewFile.content) {
+ const desc = extractFirstParagraph(overviewFile.content);
+ if (desc) return desc;
+ }
+
+ // Generate description from files if no overview is found
+ const topics = files.map(file => toTitleCase(path.basename(file.url))).join(', ');
+ return `Documentation covering ${topics} in the ${toTitleCase(folderName)} section of the OP Stack ecosystem.`;
+}
+
+async function getContentFiles(folderPath: string): Promise {
+ const files = await fs.readdir(folderPath, { withFileTypes: true });
+ const fileInfos: FileInfo[] = [];
+ const folderName = path.basename(folderPath);
- const updatedContent = matter.stringify(fileContent, frontMatter);
- await fs.writeFile(filePath, updatedContent);
- console.log(`Updated description in breadcrumb file: ${filePath}`);
+ for (const file of files) {
+ if (file.name.startsWith('_') ||
+ file.name.startsWith('.') ||
+ excludedPages.includes(file.name)) {
+ continue;
+ }
+
+ const filePath = path.join(folderPath, file.name);
+
+ if (file.isFile() && (file.name.endsWith('.md') || file.name.endsWith('.mdx'))) {
+ try {
+ const content = await fs.readFile(filePath, 'utf-8');
+ const { data: frontMatter } = matter(content);
+ const fileName = path.basename(file.name, path.extname(file.name));
+ const fileTitle = frontMatter.title || toTitleCase(fileName);
+ const relativeUrl = `/${path.relative(rootDir, filePath)}`.replace(/\.(md|mdx)$/, '');
+
+ fileInfos.push({
+ title: fileTitle,
+ url: relativeUrl,
+ description: frontMatter.description,
+ content: content
+ });
+ } catch (error) {
+ console.error(`Error processing file ${file.name}:`, error);
+ }
}
- } catch (error) {
- console.error(`Error processing file ${filePath}:`, error);
}
-};
-const processFolder = async (folderPath: string): Promise => {
+ return fileInfos;
+}
+
+async function getExistingBreadcrumbContent(breadcrumbPath: string): Promise<{
+ existingContent: string;
+ existingCards: Set;
+} | null> {
try {
- const files = await fs.readdir(folderPath);
+ const content = await fs.readFile(breadcrumbPath, 'utf-8');
+ const cardMatches = content.match(/]*href="([^"]+)"[^>]*>/g) || [];
+ const existingCards = new Set(
+ cardMatches.map(match => {
+ const hrefMatch = match.match(/href="([^"]+)"/);
+ return hrefMatch ? hrefMatch[1] : '';
+ }).filter(Boolean)
+ );
+ return { existingContent: content, existingCards };
+ } catch (error) {
+ return null;
+ }
+}
+
+async function createOrUpdateBreadcrumb(parentPath: string, folderName: string): Promise {
+ const folderPath = path.join(parentPath, folderName);
+ const breadcrumbPath = path.join(parentPath, `${folderName}.mdx`);
+
+ // Get current files in the folder
+ const files = await getContentFiles(folderPath);
+
+ // Check existing breadcrumb
+ const existing = await getExistingBreadcrumbContent(breadcrumbPath);
+
+ if (existing) {
+ // If breadcrumb exists, only add new cards
+ const newCards: string[] = [];
+ let content = existing.existingContent;
- for (const file of files) {
- const filePath = path.join(folderPath, file);
- const stats = await fs.stat(filePath);
-
- if (stats.isDirectory()) {
+ files.forEach(({ title: fileTitle, url }) => {
+ if (!existing.existingCards.has(url)) {
+ newCards.push(` `);
+ }
+ });
+
+ if (newCards.length > 0) {
+ // Find the closing tag and insert new cards before it
+ const cardsSectionEnd = content.lastIndexOf('');
+ if (cardsSectionEnd !== -1) {
+ content = content.slice(0, cardsSectionEnd) +
+ '\n' + newCards.join('\n') + '\n' +
+ content.slice(cardsSectionEnd);
+
+ await fs.writeFile(breadcrumbPath, content);
+ console.log(`Added ${newCards.length} new cards to: ${folderName}.mdx`);
+ }
+ } else {
+ console.log(`No new cards needed for: ${folderName}.mdx`);
+ }
+ } else {
+ // If breadcrumb doesn't exist, create new one
+ const title = toTitleCase(folderName);
+ const description = await generateFolderDescription(folderName, files);
+
+ let content = `---
+title: ${title}
+description: ${description}
+lang: en-US
+---
- const breadcrumbFile = path.join(folderPath, `${file}.mdx`);
- try {
- await fs.access(breadcrumbFile);
- await updateBreadcrumbFile(breadcrumbFile);
- } catch (error) {
+import { Card, Cards } from 'nextra/components'
- }
-
+# ${title}
+
+${description}
+
+`;
+
+ if (files.length > 0) {
+ content += '\n';
+ files.forEach(({ title: fileTitle, url }) => {
+ content += ` \n`;
+ });
+ content += '';
+ } else {
+ content += 'Documentation for this section is coming soon.';
+ }
+
+ await fs.writeFile(breadcrumbPath, content);
+ console.log(`Created new breadcrumb file: ${folderName}.mdx`);
+ }
+}
+
+async function processSubfolders(parentPath: string): Promise {
+ try {
+ const entries = await fs.readdir(parentPath, { withFileTypes: true });
+
+ for (const entry of entries) {
+ if (!entry.isDirectory() || entry.name.startsWith('_')) {
+ continue;
+ }
- await processFolder(filePath);
+ const folderName = entry.name;
+ console.log(`Processing folder: ${folderName}`);
+
+ try {
+ await createOrUpdateBreadcrumb(parentPath, folderName);
+ } catch (error) {
+ console.error(`Error processing breadcrumb for ${folderName}:`, error);
}
}
} catch (error) {
- console.error(`Error processing folder ${folderPath}:`, error);
+ console.error('Error processing folders:', error);
}
-};
+}
const main = async (): Promise => {
- console.log('Starting breadcrumb description update process...');
+ console.log('Starting breadcrumb update process...');
console.log('Root directory:', rootDir);
- for (const folder of targetFolders) {
- const folderPath = path.join(rootDir, folder);
- await processFolder(folderPath);
+ try {
+ // Process main sections: builders, chain, connect, stack
+ const mainSections = ['builders', 'chain', 'connect', 'stack'];
+ for (const section of mainSections) {
+ const sectionPath = path.join(rootDir, section);
+ try {
+ await fs.access(sectionPath);
+ await processSubfolders(sectionPath);
+ console.log(`Completed processing ${section} section`);
+ } catch (error) {
+ console.log(`Skipping ${section} - directory not found`);
+ }
+ }
+ console.log('Finished updating all breadcrumbs.');
+ } catch (error) {
+ console.error('Error in main process:', error);
+ process.exit(1);
}
-
- console.log('Finished updating breadcrumb descriptions.');
};
main().catch(error => {
diff --git a/words.txt b/words.txt
index 2e0d2c443..a7c0cdb64 100644
--- a/words.txt
+++ b/words.txt
@@ -362,6 +362,7 @@ SUPERCHAIN
Superchain
superchain
Superchain's
+Superchainerc
Superchains
Superscan
Supersim
@@ -385,6 +386,7 @@ txns
TXPOOL
txpool
txproxy
+txproxyd
uncountered
Unprotect
unsubmitted