diff --git a/README.md b/README.md index eccf1043da..e8b928f2fb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,19 @@
- + + + + TanStack Form +

diff --git a/media/header_form.png b/media/header_form.png deleted file mode 100644 index 82a4503c97..0000000000 Binary files a/media/header_form.png and /dev/null differ diff --git a/packages/angular-form/README.md b/packages/angular-form/README.md index 946e70fbbf..23eb7f167f 100644 --- a/packages/angular-form/README.md +++ b/packages/angular-form/README.md @@ -1,6 +1,20 @@ -![TanStack Form Header](https://github.com/TanStack/form/raw/main/media/repo-header.png) + + + + TanStack Angular Form + Directives for managing form state in Angular diff --git a/packages/form-devtools/README.md b/packages/form-devtools/README.md index 76befe0607..4ff18fa061 100644 --- a/packages/form-devtools/README.md +++ b/packages/form-devtools/README.md @@ -1,6 +1,20 @@ -![TanStack Form Header](https://github.com/TanStack/form/raw/main/media/repo-header.png) + + + + TanStack Form + Devtools for the TanStack form library. diff --git a/packages/lit-form/README.md b/packages/lit-form/README.md index ca75c21c78..cbe9688a28 100644 --- a/packages/lit-form/README.md +++ b/packages/lit-form/README.md @@ -1,6 +1,20 @@ -![TanStack Form Header](https://github.com/TanStack/form/raw/main/media/repo-header.png) + + + + TanStack Lit Form + Controllers for managing form state in Lit diff --git a/packages/preact-form/README.md b/packages/preact-form/README.md index b20213713b..6fa21737c4 100644 --- a/packages/preact-form/README.md +++ b/packages/preact-form/README.md @@ -1,6 +1,20 @@ -![TanStack Form Header](https://github.com/TanStack/form/raw/main/media/repo-header.png) + + + + TanStack Preact Form + Hooks for managing form state in Preact diff --git a/packages/react-form-devtools/README.md b/packages/react-form-devtools/README.md index 1866876e9e..ee06f30af1 100644 --- a/packages/react-form-devtools/README.md +++ b/packages/react-form-devtools/README.md @@ -1,6 +1,20 @@ -![TanStack Form Header](https://github.com/TanStack/form/raw/main/media/repo-header.png) + + + + TanStack React Form + Hooks for managing form state in React diff --git a/packages/react-form-nextjs/README.md b/packages/react-form-nextjs/README.md index 1866876e9e..ee06f30af1 100644 --- a/packages/react-form-nextjs/README.md +++ b/packages/react-form-nextjs/README.md @@ -1,6 +1,20 @@ -![TanStack Form Header](https://github.com/TanStack/form/raw/main/media/repo-header.png) + + + + TanStack React Form + Hooks for managing form state in React diff --git a/packages/react-form-start/README.md b/packages/react-form-start/README.md index 1866876e9e..ee06f30af1 100644 --- a/packages/react-form-start/README.md +++ b/packages/react-form-start/README.md @@ -1,6 +1,20 @@ -![TanStack Form Header](https://github.com/TanStack/form/raw/main/media/repo-header.png) + + + + TanStack React Form + Hooks for managing form state in React diff --git a/packages/react-form/README.md b/packages/react-form/README.md index 1866876e9e..ee06f30af1 100644 --- a/packages/react-form/README.md +++ b/packages/react-form/README.md @@ -1,6 +1,20 @@ -![TanStack Form Header](https://github.com/TanStack/form/raw/main/media/repo-header.png) + + + + TanStack React Form + Hooks for managing form state in React diff --git a/packages/solid-form/README.md b/packages/solid-form/README.md index 5db77cbe66..f531c9070a 100644 --- a/packages/solid-form/README.md +++ b/packages/solid-form/README.md @@ -1,6 +1,20 @@ -![TanStack Form Header](https://github.com/TanStack/form/raw/main/media/repo-header.png) + + + + TanStack Solid Form + Signals for managing form state in Solid diff --git a/packages/vue-form/README.md b/packages/vue-form/README.md index a09cdedcac..cd945eebf2 100644 --- a/packages/vue-form/README.md +++ b/packages/vue-form/README.md @@ -1,6 +1,20 @@ -![TanStack Form Header](https://github.com/TanStack/form/raw/main/media/repo-header.png) + + + + TanStack Vue Form + Compositions for managing form state in Vue diff --git a/scripts/verify-links.ts b/scripts/verify-links.ts index 8a1c40ddc5..de044e29a8 100644 --- a/scripts/verify-links.ts +++ b/scripts/verify-links.ts @@ -9,6 +9,7 @@ const errors: Array<{ link: string resolvedPath: string reason: string + nav?: string }> = [] function isRelativeLink(link: string) { @@ -27,6 +28,29 @@ function stripExtension(p: string): string { return p.replace(`${extname(p)}`, '') } +/** + * Map a resolved `/docs` path to the file or directory that actually serves it, + * and report whether that target exists. + */ +function resolveDocTarget(absPath: string): { path: string; exists: boolean } { + // Examples live outside /docs: /docs/framework/{framework}/examples/{name} + // is served from /examples/{framework}/{name} + if (absPath.includes('/examples/')) { + const examplePath = absPath.replace( + /\/docs\/framework\/([^/]+)\/examples\//, + '/examples/$1/', + ) + return { + path: examplePath, + exists: existsSync(examplePath) && statSync(examplePath).isDirectory(), + } + } + + // Everything else is a markdown page + const mdPath = absPath.endsWith('.md') ? absPath : `${absPath}.md` + return { path: mdPath, exists: existsSync(mdPath) } +} + function relativeLinkExists(link: string, file: string): boolean { // Remove hash if present const linkWithoutHash = link.split('#')[0] @@ -39,7 +63,7 @@ function relativeLinkExists(link: string, file: string): boolean { // Resolve the path relative to the markdown file's directory // Nav up a level to simulate how links are resolved on the web - let absPath = resolve(filePath, '..', linkPath) + const absPath = resolve(filePath, '..', linkPath) // Ensure the resolved path is within /docs const docsRoot = resolve('docs') @@ -53,32 +77,13 @@ function relativeLinkExists(link: string, file: string): boolean { return false } - // Check if this is an example path - const isExample = absPath.includes('/examples/') - - let exists = false - - if (isExample) { - // Transform /docs/framework/{framework}/examples/ to /examples/{framework}/ - absPath = absPath.replace( - /\/docs\/framework\/([^/]+)\/examples\//, - '/examples/$1/', - ) - // For examples, we want to check if the directory exists - exists = existsSync(absPath) && statSync(absPath).isDirectory() - } else { - // For non-examples, we want to check if the .md file exists - if (!absPath.endsWith('.md')) { - absPath = `${absPath}.md` - } - exists = existsSync(absPath) - } + const { path: resolvedPath, exists } = resolveDocTarget(absPath) if (!exists) { errors.push({ link, file, - resolvedPath: absPath, + resolvedPath, reason: 'Not found', }) } @@ -108,12 +113,69 @@ async function verifyMarkdownLinks() { }) } } +} + +interface ConfigNode { + label?: string + to?: string + children?: Array + frameworks?: Array +} + +/** + * Every `to` in docs/config.json becomes a sidebar link on tanstack.com, so an + * entry pointing at a page that no longer exists renders as a 404. These are + * invisible to the markdown scan above, which only reads links written inside + * .md files. + */ +function verifyConfigLinks() { + const configPath = 'docs/config.json' + const config = JSON.parse(readFileSync(configPath, 'utf-8')) as { + sections?: Array + } + + const docsRoot = resolve('docs') + let checked = 0 + + function walk(node: ConfigNode, breadcrumb: Array) { + const trail = node.label ? [...breadcrumb, node.label] : breadcrumb + + if (node.to) { + checked++ + const { path: resolvedPath, exists } = resolveDocTarget( + resolve(docsRoot, node.to), + ) + + if (!exists) { + errors.push({ + file: configPath, + link: node.to, + resolvedPath, + reason: 'Not found', + nav: trail.join(' > '), + }) + } + } + + node.children?.forEach((child) => walk(child, trail)) + node.frameworks?.forEach((framework) => walk(framework, trail)) + } + + const sections = config.sections ?? [] + sections.forEach((section) => walk(section, [])) + + console.log(`Found ${checked} nav entries in ${configPath}\n`) +} + +async function verifyLinks() { + await verifyMarkdownLinks() + verifyConfigLinks() if (errors.length > 0) { console.log(`\n❌ Found ${errors.length} broken links:`) errors.forEach((err) => { console.log( - `${err.file}\n link: ${err.link}\n resolved: ${err.resolvedPath}\n why: ${err.reason}\n`, + `${err.file}${err.nav ? `\n nav: ${err.nav}` : ''}\n link: ${err.link}\n resolved: ${err.resolvedPath}\n why: ${err.reason}\n`, ) }) process.exit(1) @@ -122,4 +184,7 @@ async function verifyMarkdownLinks() { } } -verifyMarkdownLinks().catch(console.error) +verifyLinks().catch((error) => { + console.error(error) + process.exitCode = 1 +})