Header (frontmatter) is silently discarded for CRLF files when a blank line precedes the closing `---` · Issue #6 · mark-when/parser · GitHub
Skip to content

Header (frontmatter) is silently discarded for CRLF files when a blank line precedes the closing --- #6

Open

Description

@polychromous

Summary

When a markwhen document uses Windows line endings (CRLF), a blank line right before the closing --- (i.e. at the end of the header) causes YAML parsing to fail, and the entire header is discarded. As a result, title, ranges, tag color definitions (e.g. #holiday: #f00), etc. are all ignored, and tags fall back to the default palette.

The same document with LF line endings parses correctly.

Environment

  • @markwhen/parser 1.2.0 (latest) — reproduced
  • @markwhen/parser 0.11.2 (bundled with VS Code extension markwhen.markwhen 1.4.4) — reproduced
  • Node.js on macOS; the file itself was created/edited on Windows (OneDrive shared folder), hence CRLF

Reproduction

import { parse } from "@markwhen/parser";

const body = "2026-01-01: a #holiday\r\n";
const cases = {
  "CRLF, blank line before closing ---": "---\r\ntitle: x\r\n#holiday: #f00\r\n\r\n---\r\n" + body,
  "CRLF, no blank line":                 "---\r\ntitle: x\r\n#holiday: #f00\r\n---\r\n" + body,
  "LF, blank line before closing ---":   "---\ntitle: x\n#holiday: #f00\n\n---\n" + body.replace("\r", ""),
};

for (const [name, src] of Object.entries(cases)) {
  const t = parse(src).timelines[0];
  console.log(name, JSON.stringify({ title: t.header.title, holiday: t.header[")holiday"] }));
}

Actual (1.2.0)

CRLF, blank line before closing ---   {}
    parseMessages: "Implicit map keys need to be followed by map values at line 4, column 1"
CRLF, no blank line                   {"title":"x","holiday":")f00\r"}
LF, blank line before closing ---     {"title":"x","holiday":")f00"}

Expected

All three cases should yield {"title":"x","holiday":")f00"}.

Cause (as far as I can tell)

linesAndLengths() splits the source with split("\n"), so every line keeps its trailing \r. In parseHeader, the header lines are joined back with "\n" and passed to YAML.parse. The closing --- line is not included, so the last header line is passed without a following \n:

  • A blank line before the closing --- becomes a lone "\r" at the very end of the YAML source. The YAML parser does not treat it as a line break, which leads to Implicit map keys need to be followed by map values. The catch then replaces the whole header with { dateFormat }.
  • If there is no blank line, parsing succeeds, but the last value keeps a trailing \r (")f00\r"). This may break consumers such as hex color parsing.

Suggested fix

Normalize line endings before parsing, e.g. strip a trailing \r from each line in linesAndLengths() (while keeping lengthAtIndex based on the original lengths so ranges stay correct), or at least strip \r from header lines before YAML.parse.

Note

It would also help if editors surfaced header parse failures more visibly. In the VS Code extension (1.4.4), the header is dropped silently, so the only symptom is that "tag colors don't work", which is hard to diagnose.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions