Skip to content

Commit cc524d6

Browse files
docs: correct local relative links
1 parent 9e8709e commit cc524d6

3 files changed

Lines changed: 46 additions & 43 deletions

File tree

docs/framework/react/guides/prefetching.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ Because data fetching in the component tree itself can easily lead to request wa
369369

370370
In this approach, you explicitly declare for each _route_ what data is going to be needed for that component tree, ahead of time. Because Server Rendering has traditionally needed all data to be loaded before rendering starts, this has been the dominating approach for SSR'd apps for a long time. This is still a common approach and you can read more about it in the [Server Rendering & Hydration guide](../ssr.md).
371371

372-
For now, let's focus on the client side case and look at an example of how you can make this work with [Tanstack Router](https://tanstack.com/router). These examples leave out a lot of setup and boilerplate to stay concise, you can check out a [full React Query example](https://tanstack.com/router/.latest/docs/framework/react/examples/basic-react-query-file-based) over in the [Tanstack Router docs](https://tanstack.com/router/latest/docs).
372+
For now, let's focus on the client side case and look at an example of how you can make this work with [Tanstack Router](https://tanstack.com/router). These examples leave out a lot of setup and boilerplate to stay concise, you can check out a [full React Query example](../examples/basic-react-query-file-based) over in the [Tanstack Router docs](https://tanstack.com/router/latest/docs).
373373

374374
When integrating at the router level, you can choose to either _block_ rendering of that route until all data is present, or you can start a prefetch but not await the result. That way, you can start rendering the route as soon as possible. You can also mix these two approaches and await some critical data, but start rendering before all the secondary data has finished loading. In this example, we'll configure an `/article` route to not render until the article data has finished loading, as well as start prefetching comments as soon as possible, but not block rendering the route if comments haven't finished loading yet.
375375

docs/framework/solid/guides/prefetching.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ replace:
1111
'useQuery[(]': 'useQuery(() => ',
1212
'useQueries[(]': 'useQueries(() => ',
1313
'useInfiniteQuery[(]': 'useInfiniteQuery(() => ',
14-
'/docs/framework/react/examples/basic-react-query-file-based': '/docs/framework/solid/examples/basic-solid-query-file-based',
14+
'../examples/basic-react-query-file-based': '../examples/basic-solid-query-file-based',
1515
}
1616
---

scripts/verify-links.ts

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import { existsSync, readFileSync, statSync } from 'node:fs'
2-
import path, { resolve } from 'node:path'
2+
import { extname, resolve } from 'node:path'
33
import { glob } from 'tinyglobby'
44
// @ts-ignore Could not find a declaration file for module 'markdown-link-extractor'.
55
import markdownLinkExtractor from 'markdown-link-extractor'
66

7+
const errors: Array<{
8+
file: string
9+
link: string
10+
resolvedPath: string
11+
reason: string
12+
}> = []
13+
714
function isRelativeLink(link: string) {
815
return (
9-
link &&
16+
!link.startsWith(`/`) &&
1017
!link.startsWith('http://') &&
1118
!link.startsWith('https://') &&
1219
!link.startsWith('//') &&
@@ -15,39 +22,33 @@ function isRelativeLink(link: string) {
1522
)
1623
}
1724

18-
function normalizePath(p: string): string {
19-
// Remove any trailing .md
20-
p = p.replace(`${path.extname(p)}`, '')
21-
return p
25+
/** Remove any trailing .md */
26+
function stripExtension(p: string): string {
27+
return p.replace(`${extname(p)}`, '')
2228
}
2329

24-
function fileExistsForLink(
25-
link: string,
26-
markdownFile: string,
27-
errors: Array<any>,
28-
): boolean {
30+
function relativeLinkExists(link: string, file: string): boolean {
2931
// Remove hash if present
30-
const filePart = link.split('#')[0]
32+
const linkWithoutHash = link.split('#')[0]
3133
// If the link is empty after removing hash, it's not a file
32-
if (!filePart) return false
33-
34-
// Normalize the markdown file path
35-
markdownFile = normalizePath(markdownFile)
34+
if (!linkWithoutHash) return false
3635

37-
// Normalize the path
38-
const normalizedPath = normalizePath(filePart)
36+
// Strip the file/link extensions
37+
const filePath = stripExtension(file)
38+
const linkPath = stripExtension(linkWithoutHash)
3939

4040
// Resolve the path relative to the markdown file's directory
41-
let absPath = resolve(markdownFile, normalizedPath)
41+
// Nav up a level to simulate how links are resolved on the web
42+
let absPath = resolve(filePath, '..', linkPath)
4243

4344
// Ensure the resolved path is within /docs
4445
const docsRoot = resolve('docs')
4546
if (!absPath.startsWith(docsRoot)) {
4647
errors.push({
4748
link,
48-
markdownFile,
49+
file,
4950
resolvedPath: absPath,
50-
reason: 'navigates above /docs, invalid',
51+
reason: 'Path outside /docs',
5152
})
5253
return false
5354
}
@@ -76,42 +77,44 @@ function fileExistsForLink(
7677
if (!exists) {
7778
errors.push({
7879
link,
79-
markdownFile,
80+
file,
8081
resolvedPath: absPath,
81-
reason: 'not found',
82+
reason: 'Not found',
8283
})
8384
}
8485
return exists
8586
}
8687

87-
async function findMarkdownLinks() {
88+
async function verifyMarkdownLinks() {
8889
// Find all markdown files in docs directory
8990
const markdownFiles = await glob('docs/**/*.md', {
9091
ignore: ['**/node_modules/**'],
9192
})
9293

9394
console.log(`Found ${markdownFiles.length} markdown files\n`)
9495

95-
const errors: Array<any> = []
96-
9796
// Process each file
9897
for (const file of markdownFiles) {
9998
const content = readFileSync(file, 'utf-8')
100-
const links: Array<any> = markdownLinkExtractor(content)
101-
102-
const filteredLinks = links.filter((link: any) => {
103-
if (typeof link === 'string') {
104-
return isRelativeLink(link)
105-
} else if (link && typeof link.href === 'string') {
106-
return isRelativeLink(link.href)
107-
}
108-
return false
99+
const links: Array<string> = markdownLinkExtractor(content)
100+
101+
const relativeLinks = links.filter((link: string) => {
102+
return isRelativeLink(link)
109103
})
110104

111-
if (filteredLinks.length > 0) {
112-
filteredLinks.forEach((link) => {
113-
const href = typeof link === 'string' ? link : link.href
114-
fileExistsForLink(href, file, errors)
105+
if (relativeLinks.length > 0) {
106+
relativeLinks.forEach((link) => {
107+
if (!link.startsWith('.')) {
108+
errors.push({
109+
link,
110+
file,
111+
resolvedPath: '',
112+
reason: 'Does not start with ./ or ../',
113+
})
114+
return
115+
}
116+
117+
relativeLinkExists(link, file)
115118
})
116119
}
117120
}
@@ -120,7 +123,7 @@ async function findMarkdownLinks() {
120123
console.log(`\n❌ Found ${errors.length} broken links:`)
121124
errors.forEach((err) => {
122125
console.log(
123-
`${err.link}\n in: ${err.markdownFile}\n path: ${err.resolvedPath}\n why: ${err.reason}\n`,
126+
`${err.file}\n link: ${err.link}\n resolved: ${err.resolvedPath}\n why: ${err.reason}\n`,
124127
)
125128
})
126129
process.exit(1)
@@ -129,4 +132,4 @@ async function findMarkdownLinks() {
129132
}
130133
}
131134

132-
findMarkdownLinks().catch(console.error)
135+
verifyMarkdownLinks().catch(console.error)

0 commit comments

Comments
 (0)