next-validate-link

Introduction

A tool for validating links in Markdown files

Setup

Install it.

npm i next-validate-link fast-glob

Scan available URLs, it predicts them from your file-system based routing.

import { scanURLs } from 'next-validate-link';
 
const scanned = await scanURLs();

Validate Markdown files and print errors.

import fg from 'fast-glob';
import { printErrors, validateFiles } from 'next-validate-link';
 
printErrors(
  await validateFiles(await fg('content/**/*.{md,mdx}'), {
    scanned,
  }),
  // exit with code 1 if errors detected
  true,
);

The validateFiles function accepts a list of file paths or file objects containing its path and content.

You can run this script during lint process, or before builds.

bun ./lint.ts
You can use other TypeScript executors like tsx.

Configurations

Meta

Specify allowed queries and fragments of a page.

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

Static Params

Use populate to populate dynamic routes into static.

import { scanURLs } from 'next-validate-link';
 
const scanned = await scanURLs({
  populate: {
    // you can generate them too! (e.g. from file system or CMS)
    '(home)/blog/[slug]': [{ value: 'blog-1' }, { value: 'blog-2' }],
    'docs/[...slug]': [
      {
        value: ['hello', 'world'],
        // allowed fragment strings
        hashes: ['fragment'],
        // allowed queries
        queries: [
          {
            search: 'fumadocs',
          },
        ],
      },
    ],
  },
});

Each param object indicates a page, allowed hashes and queries can be specified individually.

Multiple Params

When you have multiple dynamic routes, you need to use an object instead.

import { scanURLs } from 'next-validate-link';
 
const scanned = await scanURLs({
  populate: {
    '[lang]/blog/[slug]': [
      {
        value: {
          lang: 'en',
          slug: 'blog-1',
        },
      },
      {
        value: {
          lang: 'cn',
          slug: 'blog-1',
        },
      },
    ],
  },
});

External Urls

To validate external urls, enable it.

import fg from 'fast-glob';
import { validateFiles } from 'next-validate-link';
 
await validateFiles(await fg('content/**/*.{md,mdx}'), {
  scanned,
  checkExternal: true,
});

Relative Urls

To support relative urls, you need to specify a function that generates url based on file path.

import path from 'node:path';
 
await validateFiles(await fg('content/**/*.{md,mdx}'), {
  pathToUrl: (file) => {
    // just an example
    return path.dirname(file);
  },
});

Utilities

readFiles

Read files for given glob patterns, and output a list of file objects.

import { readFiles } from 'next-validate-link';
 
const files = await readFiles('content/docs/**/*.{md,mdx}');

You can use it in conjunction with validateFiles.

On this page