# MD072 - Frontmatter key sort

Aliases: `frontmatter-key-sort`

## Rule Details

This rule ensures that top-level keys in frontmatter are sorted alphabetically. It supports YAML, TOML, and JSON frontmatter formats.

Consistent key ordering makes frontmatter easier to scan and reduces merge conflicts when multiple people edit the same files.

## Supported Formats

| Format | Delimiters | Comments | Auto-fix                      |
| ------ | ---------- | -------- | ----------------------------- |
| YAML   | `---`      | `#`      | Yes (unless comments present) |
| TOML   | `+++`      | `#`      | Yes (unless comments present) |
| JSON   | `{` `}`    | None     | Always                        |

## Examples

### YAML - Incorrect

```markdown
---
title: My Document
author: John Doe
date: 2024-01-15
---

# Heading
```

### YAML - Correct

```markdown
---
author: John Doe
date: 2024-01-15
title: My Document
---

# Heading
```

### TOML - Incorrect

```markdown
+++
title = "My Document"
author = "John Doe"
+++

# Heading
```

### TOML - Correct

```markdown
+++
author = "John Doe"
title = "My Document"
+++

# Heading
```

### JSON - Incorrect

```markdown
{
"title": "My Document",
"author": "John Doe"
}

# Heading
```

### JSON - Correct

```markdown
{
"author": "John Doe",
"title": "My Document"
}

# Heading
```

## Rationale

- Consistent ordering makes it easier to find specific fields
- Reduces merge conflicts when multiple contributors edit frontmatter
- Enforces a predictable structure across all documents
- Aligns with common practices in configuration file management

## Auto-fix Behavior

### YAML and TOML

Auto-fix is available unless the frontmatter contains comments (`#`). Comments would be lost during re-serialization, so the fix is skipped to preserve them.

When comments are present, the warning will indicate:
> "Auto-fix unavailable: frontmatter contains comments."

### JSON

JSON has no comment syntax, so auto-fix is always available.

## Sorting Behavior

- Only top-level keys are sorted (nested keys within objects are not reordered)
- Sorting is case-insensitive (`Author` and `author` are treated equivalently)
- Complex values (lists, nested objects) are preserved during auto-fix

## Configuration

This rule is **disabled by default** (opt-in) because alphabetical key sorting is an opinionated style choice. Many projects prefer semantic ordering (title first, date second) rather than
alphabetical.

| Option          | Type     | Default | Description                                                 |
| --------------- | -------- | ------- | ----------------------------------------------------------- |
| `enabled`       | boolean  | `false` | Enable the rule                                             |
| `key-order`     | string[] | (none)  | Custom key order (unlisted keys sort alphabetically after)  |
| `required-keys` | string[] | `[]`    | Keys that must be present in the frontmatter (no auto-fix)  |

### Enabling the Rule

**.rumdl.toml:**

```toml
[MD072]
enabled = true
```

**pyproject.toml:**

```toml
[tool.rumdl.MD072]
enabled = true
```

### Custom Key Order

You can specify a preferred key order instead of alphabetical sorting. Keys not in the list will be sorted alphabetically after the specified keys.

**.rumdl.toml:**

```toml
[MD072]
enabled = true
key-order = ["title", "date", "author", "tags", "categories"]
```

**pyproject.toml:**

```toml
[tool.rumdl.MD072]
enabled = true
key-order = ["title", "date", "author", "tags", "categories"]
```

With this configuration:

- `title` always comes first
- `date` comes second
- `author` comes third
- `tags` and `categories` follow
- Any other keys (e.g., `description`, `draft`) are sorted alphabetically after the specified keys

This is useful for projects that want semantic ordering (title first for readability) while still ensuring consistency for unlisted keys.

### Required Keys

You can require certain keys to be present in the frontmatter. Each missing key is reported as a separate warning.

**.rumdl.toml:**

```toml
[MD072]
enabled = true
key-order = ["title", "date", "author", "tags", "categories"]
required-keys = ["title", "date"]
```

**pyproject.toml:**

```toml
[tool.rumdl.MD072]
enabled = true
required-keys = ["title", "date"]
```

With this configuration:

- A document whose frontmatter lacks `title` or `date` gets a warning per missing key
- Matching is case-insensitive against top-level keys (`Title:` satisfies `"title"`), consistent with `key-order`
- Nested keys do not count: `meta.title` does not satisfy a required `title`
- TOML table headers and dotted assignments count by their root key: `[taxonomies]`, `[[authors]]`, and `params.seo = true` satisfy required `taxonomies`, `authors`, and `params`
- A quoted TOML key is literal: `"a.b" = 1` satisfies required `a.b`, not `a`
- `required-keys` is independent of `key-order`: you can order many keys while requiring only a few

Notes:

- Missing keys are **not auto-fixed**: rumdl cannot invent a meaningful value, so these warnings have no fix and `rumdl fmt` leaves them in place
- The check only applies to documents that **have** frontmatter; requiring frontmatter to exist at all is out of scope for this rule
- An empty frontmatter block (`---` immediately followed by `---`) is missing every required key and is reported

## Related Rules

- [MD071](md071.md) - Blank line after frontmatter
