Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion src/data-layer/fetchers/developer-tools/fetchBuidlGuidl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,35 @@ import { DeveloperToolsResponse } from "@/lib/types"

import { fetchRetry } from "@/data-layer/fetchers/fetchRetry"

/**
* Normalizes a URL field by ensuring it has an https:// protocol prefix.
* Returns undefined for empty/whitespace-only values.
*/
function normalizeUrl(value: string | undefined): string | undefined {
if (!value) return undefined
const trimmed = value.trim()
if (!trimmed) return undefined
if (/^https?:\/\//i.test(trimmed)) return trimmed
return `https://${trimmed}`
}

/**
* Normalizes a Twitter/X social field into a full URL.
* Handles bare handles (@foo, foo), partial URLs (x.com/foo, twitter.com/foo),
* and full URLs.
*/
function normalizeTwitter(value: string | undefined): string | undefined {
if (!value) return undefined
const trimmed = value.trim()
if (!trimmed) return undefined
if (/^https?:\/\//i.test(trimmed)) return trimmed
// Already a partial domain URL (x.com/..., twitter.com/...)
if (/^(x\.com|twitter\.com)\//i.test(trimmed)) return `https://${trimmed}`
// Bare handle with or without @
const handle = trimmed.replace(/^@/, "")
return `https://x.com/${handle}`
}

export async function fetchBuidlGuidl(): Promise<DeveloperToolsResponse[]> {
const url =
"https://raw.githubusercontent.com/BuidlGuidl/Developer-Tooling/refs/heads/main/output/results.json"
Expand All @@ -21,5 +50,9 @@ export async function fetchBuidlGuidl(): Promise<DeveloperToolsResponse[]> {

console.log("Successfully fetched BuidlGuidl developer tooling data")

return json
return json.map((tool) => ({
...tool,
website: normalizeUrl(tool.website),
twitter: normalizeTwitter(tool.twitter),
}))
}
6 changes: 3 additions & 3 deletions src/data-layer/mocks/fetch-developer-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@
"description": "Ethers.js is a simple, compact and complete JavaScript (via TypeScript) library for interacting with Ethereum and related blockchains.\n\nIt is currently used in a very large number of Blockchain projects, including everything from block explorers to wallets (like MetaMask) and is downloaded over 7.1 million times per month (as of this writing). It is also one of the top 500 projects (by dependants) on NPM.\n\nIt was written and is maintained by me, RicMoo (Richard Moore), a random developer from Canada that is passionate about open-source and dedicates most his waking-time (and some sleeping-time) to it.\n\nHack the Planet! :)",
"thumbnail_url": "https://storage.googleapis.com/op-atlas/f8d776ab-ca70-42ee-9e41-d4f709cd6fd4.png",
"banner_url": "https://storage.googleapis.com/op-atlas/459bdd5e-60a5-49ca-88b8-d4537ebfec16.png",
"twitter": "@ricmoo",
"twitter": "https://x.com/ricmoo",
"tags": [
"frontend",
"json-rpc",
Expand Down Expand Up @@ -628,14 +628,14 @@
"description": "Runtime Verification is a leading formal verification company specializing in blockchain security and smart contract correctness. We've developed ERCx, the most comprehensive open-source testing library for ERC token standards, featuring over 500 individual tests across ERC-20, ERC-721, ERC-1155, and ERC-4626 implementations.\nERCx directly empowers Superchain builders by providing production-ready test suites that verify both standard compliance and security properties. Our library offers zero-configuration testing for deployed contracts via Foundry fork testing, plus simple integration for pre-deployment source code validation. With three testing tiers: Standard (EIP compliance), Security (vulnerability detection), and Features (implementation validation), developers can ship token contracts with confidence, knowing they've been thoroughly vetted against real-world attack vectors and edge cases.\nWhat makes ERCx particularly valuable for the Optimism ecosystem is its cross-chain compatibility and handling of complex deployment scenarios. The library seamlessly works across OP Stack chains and handles storage complexities that often challenge developers working with established tokens like USDC or stETH. By providing this critical testing infrastructure as open-source tooling, we're enabling safer, more reliable token implementations across the entire Superchain, directly supporting the ecosystem's growth while reducing the security risks that have historically plagued token contracts in DeFi.",
"thumbnail_url": "https://storage.googleapis.com/op-atlas/e6a6dd9b-4ace-4187-8408-0e5729bb0265.png",
"banner_url": "https://storage.googleapis.com/op-atlas/eee0738d-3735-42c8-8802-93b22a041803.png",
"twitter": "x.com/rv_inc",
"twitter": "https://x.com/rv_inc",
"tags": [
"foundry",
"security",
"erc721",
"runtime-verification"
],
"website": "ercx.runtimeverification.com",
"website": "https://ercx.runtimeverification.com",
"category": "Security, Testing & Formal Verification",
"repos": [
{
Expand Down
6 changes: 2 additions & 4 deletions src/scripts/i18n/post_import_sanitize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2891,12 +2891,10 @@ function fixSpanWrappedBackticks(content: string): {
const parts = content.split(fencePattern)

// Pattern 1: <span dir="ltr"> wrapping backtick content
const spanAroundBacktickRe =
/<span dir="ltr">\s*(`[^`]+`)\s*<\/span>/g
const spanAroundBacktickRe = /<span dir="ltr">\s*(`[^`]+`)\s*<\/span>/g

// Pattern 2: backticks wrapping <span dir="ltr"> content (makes span visible as code)
const backtickAroundSpanRe =
/`<span dir="ltr">\s*([\s\S]+?)\s*<\/span>`/g
const backtickAroundSpanRe = /`<span dir="ltr">\s*([\s\S]+?)\s*<\/span>`/g

for (let i = 0; i < parts.length; i++) {
if (i % 2 === 1) continue // Skip code fences
Expand Down
7 changes: 4 additions & 3 deletions tests/unit/sanitizer/standalone-fixes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2491,7 +2491,8 @@ author: Ori Pomerantz

test.describe("fixCrossScriptPunctuation", () => {
test("replaces \u3002 with \u06D4 for locale ur", () => {
const input = "\u06CC\u06C1 \u0627\u06CC\u06A9 \u062C\u0645\u0644\u06C1 \u06C1\u06D2\u3002"
const input =
"\u06CC\u06C1 \u0627\u06CC\u06A9 \u062C\u0645\u0644\u06C1 \u06C1\u06D2\u3002"
const { content, fixCount } = fixCrossScriptPunctuation(input, "ur")
expect(content).toBe(
"\u06CC\u06C1 \u0627\u06CC\u06A9 \u062C\u0645\u0644\u06C1 \u06C1\u06D2\u06D4"
Expand Down Expand Up @@ -2567,7 +2568,7 @@ author: Ori Pomerantz
})

test.describe("fixSpanWrappedBackticks", () => {
test("unwraps <span dir=\"ltr\"> around backtick content", () => {
test('unwraps <span dir="ltr"> around backtick content', () => {
const input = '<span dir="ltr">`APPLY(S,TX) -> S\'`</span>'
const { content, fixCount } = fixSpanWrappedBackticks(input)
expect(content).toBe("`APPLY(S,TX) -> S'`")
Expand All @@ -2584,7 +2585,7 @@ author: Ori Pomerantz
expect(fixCount).toBe(2)
})

test("does not touch <span dir=\"ltr\"> wrapping non-backtick content", () => {
test('does not touch <span dir="ltr"> wrapping non-backtick content', () => {
const input = '<span dir="ltr">2026-03-15</span>'
const { content, fixCount } = fixSpanWrappedBackticks(input)
expect(content).toBe(input)
Expand Down
Loading