next-validate-link

repository·dev·Indexed 41 days ago

https://github.com/fuma-nama/next-validate-link

A utility for validating Markdown links to ensure they are correct and not broken. It supports multiple framework presets including Next.js, Astro, Nuxt, Waku, TanStack Start, and React Router. The tool provides functions like scanURLs to discover available routes, validateFiles to check content, and printErrors for CI/CD integration. It supports external URL validation, relative path checking, and dynamic route population.

Tokens
7.4K
Snippets
26
Records
32
Agent score
100%

What's inside next-validate-link

  1. Use next-validate-link with Nuxt

    dev

    By default, next-validate-link assumes a Next.js routing structure. To use it with Nuxt, you must provide the nuxt framework preset to the scanURLs function. This tells the scanner how to identify and scan your application's pages.

    import { scanURLs } from 'next-validate-link';
    
    const scanned = await scanURLs({
      preset: 'nuxt',
    });
    // validate with the scanned urls
  2. Validate Markdown files and print errors

    dev

    To validate links, use readFiles to get your content and validateFiles to check them against the scanned URLs. Use printErrors to output the results. Setting the second argument of printErrors to true will cause the process to exit with code 1 if errors are detected, which is useful for CI/CD linting or build steps.

    import { printErrors, validateFiles, readFiles } from 'next-validate-link';
    
    // Assuming 'scanned' was generated via scanURLs
    printErrors(
      await validateFiles(await readFiles('content/**/*.{md,mdx}'), {
        scanned,
      }),
      // exit with code 1 if errors detected
      true,
    );
  3. Use next-validate-link with Astro

    dev

    By default, next-validate-link assumes a Next.js routing structure. To use it with Astro, you must provide the astro framework preset to the scanURLs function. This tells the scanner how to correctly identify and scan your Astro pages.

    import { scanURLs } from 'next-validate-link';
    
    const scanned = await scanURLs({
      preset: 'astro',
    });
    // validate with the scanned urls
  4. Configure relative URL checking

    dev

    The tool checks relative URLs (e.g., [Test](./my-page)) by default. To make these work, you must provide context so the tool can resolve them. You can either:

    • Define file.url in the input file objects.
    • Provide a pathToUrl option.
    • Provide a baseUrl option.

    To disable this check entirely, set checkRelativeUrls: false.

    import { readFiles, validateFiles } from "next-validate-link";
    
    // Disable relative URL checking
    await validateFiles(await readFiles('content/**/*.{md,mdx}'), {
      checkRelativeUrls: false,
    });
  5. Customize URL extraction with onNode

    dev

    The onNode property in MarkdownConfig allows you to define custom logic for finding URLs within the Markdown/MDX Abstract Syntax Tree (AST).

    If you do not provide onNode, the validator uses a default implementation that:

    1. Extracts url from standard Markdown link nodes.
    2. Scans MDX JSX elements (mdxJsxFlowElement or mdxJsxTextElement) if their name exists in the components configuration and the attribute name matches one of the specified attributes.

    If you provide onNode, you take full responsibility for returning an object containing an array of strings: { hrefs: string[] } for every node you want to scan.

  6. Populate dynamic routes with static params

    dev

    For dynamic routes, use the populate option in scanURLs to map route patterns to specific values. This allows the validator to know which dynamic paths actually exist.

    • For single parameter routes, provide an array of objects with a value property.
    • For routes with multiple parameters, provide an array of objects where value is an object containing all parameter keys.
    • You can also specify allowed hashes and queries for specific parameter values.
    import { scanURLs } from 'next-validate-link';
    
    const scanned = await scanURLs({
      populate: {
        // Single parameter route
        'docs/[...slug]': [
          {
            value: ['hello', 'world'],
            hashes: ['fragment'],
            queries: [{ search: 'fumadocs' }],
          },
        ],
        // Multiple parameter route
        '[lang]/blog/[slug]': [
          {
            value: { lang: 'en', slug: 'blog-1' },
          },
          {
            value: { lang: 'cn', slug: 'blog-1' },
          },
        ],
      },
    });
  7. Validate external URLs

    dev

    By default, the tool focuses on internal links. To validate external URLs, enable checkExternal in the validateFiles options. You can provide a custom validate function to define what constitutes a successful external link check.

    import { validateFiles, readFiles } from 'next-validate-link';
    
    // Simple external check
    await validateFiles(await readFiles('content/**/*.{md,mdx}'), {
      scanned,
      checkExternal: true,
    });
    
    // Custom external validation logic
    await validateFiles(await readFiles('content/**/*.{md,mdx}'), {
      scanned,
      checkExternal: {
        async validate(url) {
          return { success: true };
        }
      },
    });
  8. Configure allowed meta (queries and fragments)

    dev

    You can restrict which queries and URL fragments are considered valid for specific paths using the meta option in scanURLs.

    import { scanURLs } from 'next-validate-link';
    
    const scanned = await scanURLs({
      meta: {
        '/': {
          // allowed fragment strings
          hashes: ['fragment'],
          // allowed queries
          queries: [
            {
              search: 'fumadocs',
            },
          ],
        },
      },
    });
  9. Configure relative path checking

    dev

    To validate relative file paths (e.g., [Test](./another-file.md)), use the checkRelativePaths option in validateFiles. Supported values:

    • exists: Checks if the referenced file exists on the file system.
    • as-url: Resolves the file path as a URL. Requires providing a pathToUrl function that converts a file path to a valid URL/pathname.
    • false (default): Ignores relative paths.
    import path from "node:path";
    import { readFiles, validateFiles } from "next-validate-link";
    
    // Check if files exist
    await validateFiles(await readFiles('content/**/*.{md,mdx}'), {
      checkRelativePaths: 'exists',
    });
    
    // Resolve paths as URLs
    await validateFiles(await readFiles('content/**/*.{md,mdx}'), {
      checkRelativePaths: 'as-url',
      pathToUrl: (file) => {
        return path.dirname(file);
      },
    });