Skip to content

FrontmatterOrder.Sorted ignores standard keys that differ only in case (e.g. Title, Date) under AsIs naming, contradicting StandardOrder.Compare #151

Description

@matt-edmondson

What's wrong

SortFrontmatterProperties (Frontmatter/Frontmatter.cs:259-283) places standard properties with an exact, case-sensitive frontmatter.TryGetValue(key, ...) for each name in StandardOrder.PropertyNames. Under FrontmatterNaming.AsIs, names are not lowercased first, so a key such as Title, Date or Tags is never recognised as standard. It falls into the "remaining properties" pass and keeps its input position.

The library's own public comparer, StandardOrder.Compare (Frontmatter/StandardOrder.cs:209-241), explicitly ignores case (a.ToLowerInvariant()) and says Title sorts before MyCustom. The internal sort therefore disagrees with the public ordering contract.

Reproduction

Console.WriteLine(Frontmatter.CombineFrontmatter(
    "---\nMyCustom: 1\nDate: 2020\nTitle: A\n---\nBody\n",
    FrontmatterNaming.AsIs, FrontmatterOrder.Sorted));
Console.WriteLine(StandardOrder.Compare("Title", "MyCustom"));
Console.WriteLine(StandardOrder.Compare("Date", "Title"));

Actual:

---
MyCustom: 1
Date: 2020
Title: A
---
Body

-1
5

Nothing was sorted, even though Compare says Title < Date < MyCustom.

Expected, matching Compare:

---
Title: A
Date: 2020
MyCustom: 1
---
Body

Why it matters

FrontmatterOrder.Sorted is documented as "Sort properties according to standard conventions" and does not depend on the naming mode. Callers who pick AsIs naming to keep their capitalised keys (common in Obsidian and Hugo front matter) and ask for Sorted output get their properties left unsorted, with no error.

Suggested fix / acceptance criteria

  • Sort with the same case-insensitive rule as StandardOrder.Compare. For example, walk PropertyNames and pick every key equal ignoring case (StringComparison.OrdinalIgnoreCase), or do a stable sort of the entries using StandardOrder.Compare. Keep the order of unknown keys as it is now.
  • Test: CombineFrontmatter("---\nMyCustom: 1\nDate: 2020\nTitle: A\n---\n", AsIs, Sorted) yields Title, Date, MyCustom, with the original spelling kept.
  • A consistency test: for any Sorted output, adjacent standard keys satisfy StandardOrder.Compare(prev, next) <= 0.

Related: the canonical-name casing problem for redirectFrom/redirectTo is filed separately; a fix for both could share the case-insensitive lookup.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions