# MD051 - Link anchors should exist

Aliases: `link-fragments`

## What this rule does

Ensures that links to sections within the same document (like `#introduction`) point to actual headings that exist. Cross-file fragment links (like `file.md#heading`) are not validated by this rule.

## Why this matters

- **Navigation**: Broken internal links frustrate readers trying to jump to sections
- **Maintenance**: Helps you catch links that break when headings are renamed
- **User experience**: Ensures smooth document navigation

## Examples

### ✅ Correct

```markdown
# Introduction

## Getting Started

See the [Introduction](#introduction) for background.

Jump to [Getting Started](#getting-started) to begin.

# Working with **bold** and *italic*

Link to [formatted heading](#working-with-bold-and-italic)

<!-- Cross-file links are ignored by MD051 -->
See [external documentation](README.md#setup) for setup instructions.
```

### ❌ Incorrect

<!-- rumdl-disable MD051 -->

```markdown
# Introduction

## Getting Started

[Jump to Installation](#installation)  <!-- No "Installation" heading exists -->

[See Overview](#overview)  <!-- No "Overview" heading exists -->
```

<!-- rumdl-enable MD051 -->

### 🔧 Fixed

This rule cannot automatically fix missing anchors - you need to either:

- Add the missing heading
- Update the link to point to an existing heading
- Remove the broken link

## Configuration

This rule supports configuring the anchor generation style to match different Markdown processors:

```toml
[MD051]
# Anchor generation style (default: "github")
# - "github": Preserves Unicode, underscores, and consecutive hyphens
# - "kramdown": ASCII-only with normalization, removes underscores
# - "bitbucket": Adds 'markdown-header-' prefix
anchor-style = "github"
```

### Anchor style differences

| Heading              | GitHub                | kramdown            | Pandoc                | Bitbucket                             |
| -------------------- | --------------------- | ------------------- | --------------------- | ------------------------------------- |
| `Hello World`        | `#hello-world`        | `#hello-world`      | `#hello-world`        | `#markdown-header-hello-world`        |
| `respect_gitignore`  | `#respect_gitignore`  | `#respectgitignore` | `#respect_gitignore`  | `#markdown-header-respect_gitignore`  |
| `snake_case_example` | `#snake_case_example` | `#snakecaseexample` | `#snake_case_example` | `#markdown-header-snake_case_example` |
| `123 Numbers`        | `#123-numbers`        | `#numbers`          | `#numbers`            | `#markdown-header-123-numbers`        |
| `_underscore`        | `#_underscore`        | `#underscore`       | `#underscore`         | `#markdown-header-_underscore`        |
| `The End - yay`      | `#the-end---yay`      | `#the-end---yay`    | `#the-end---yay`      | `#markdown-header-the-end-yay`        |
| `CI/CD Migration`    | `#cicd-migration`     | `#cicd-migration`   | `#cicd-migration`     | `#markdown-header-cicd-migration`     |
| `Café au Lait`       | `#café-au-lait`       | `#cafe-au-lait`     | `#café-au-lait`       | `#markdown-header-cafe-au-lait`       |
| `Über uns`           | `#über-uns`           | `#uber-uns`         | `#über-uns`           | `#markdown-header-uber-uns`           |
| `你好世界`           | `#你好世界`           | `#section`          | `#你好世界`           | `#markdown-header-`                   |
| `こんにちは`         | `#こんにちは`         | `#section`          | `#こんにちは`         | `#markdown-header-`                   |

**Key differences**:

- **GitHub**: Preserves Unicode characters (Chinese, Japanese, Arabic, accented Latin), underscores, and consecutive hyphens
- **kramdown**: Normalizes accented Latin to ASCII, converts non-Latin scripts to `#section`, removes underscores, preserves consecutive hyphens
- **Bitbucket**: Adds `markdown-header-` prefix, normalizes accented characters, preserves underscores, collapses consecutive hyphens

## Automatic fixes

This rule does not provide automatic fixes since it cannot guess which heading you meant to link to.

## How heading anchors work

When you create a heading like `## Getting Started`, Markdown automatically creates an anchor `#getting-started` that you can link to. The conversion follows these rules:

1. Convert to lowercase: `Getting Started` → `getting started`
2. Replace spaces with hyphens: `getting started` → `getting-started`
3. Remove special characters: `FAQ's & Tips!` → `faqs-tips`
4. Strip formatting: `**Bold** Text` → `bold-text`

## Learn more

- [CommonMark anchors](https://spec.commonmark.org/) - How link anchors work
- [GitHub heading IDs][github-ids] - GitHub's approach to heading anchors

[github-ids]: https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#section-links

## Related rules

- [MD042](md042.md) - No empty links
- [MD034](md034.md) - URLs should be formatted as links
- [MD039](md039.md) - No spaces inside link text
