createFrontmatterError creates a detailed error for frontmatter parsing issues frontmatterLineOffset is the line number where the frontmatter content begins (1-based) Returns error in VSCode-compatible format: filename:line:column: error message
(filePath, content string, err error, frontmatterLineOffset int)
| 74 | // frontmatterLineOffset is the line number where the frontmatter content begins (1-based) |
| 75 | // Returns error in VSCode-compatible format: filename:line:column: error message |
| 76 | func (c *Compiler) createFrontmatterError(filePath, content string, err error, frontmatterLineOffset int) error { |
| 77 | frontmatterErrorLog.Printf("Creating frontmatter error for file: %s, offset: %d", filePath, frontmatterLineOffset) |
| 78 | |
| 79 | errorStr := err.Error() |
| 80 | |
| 81 | // Check if error already contains formatted yaml.FormatError() output with source context |
| 82 | // yaml.FormatError() produces output like "failed to parse frontmatter:\n[line:col] message\n> line | content..." |
| 83 | if strings.Contains(errorStr, frontmatterParseErrPrefix+"[") && (strings.Contains(errorStr, "\n>") || strings.Contains(errorStr, "|")) { |
| 84 | // Extract line and column from the formatted error for VSCode compatibility |
| 85 | // Pattern: [line:col] message |
| 86 | if matches := lineColPattern.FindStringSubmatch(errorStr); len(matches) >= 4 { |
| 87 | line := matches[1] |
| 88 | col := matches[2] |
| 89 | message := matches[3] |
| 90 | // Extract just the first line of the message (before newline) |
| 91 | if idx := strings.Index(message, "\n"); idx != -1 { |
| 92 | message = message[:idx] |
| 93 | } |
| 94 | // Translate raw YAML parser messages to user-friendly plain English. |
| 95 | // Uses the shared translation table from pkg/parser to keep both code paths in sync. |
| 96 | message = parser.TranslateYAMLMessage(message) |
| 97 | |
| 98 | // Format as: filename:line:column: error: message |
| 99 | // This is compatible with VSCode's problem matcher |
| 100 | vscodeFormat := fmt.Sprintf("%s:%s:%s: error: %s", filePath, line, col, message) |
| 101 | |
| 102 | // Extract just the source context lines (skip the [line:col] message line to avoid duplication) |
| 103 | // Find the first line that starts with whitespace + digit + | (source context line) |
| 104 | if loc := sourceContextPattern.FindStringIndex(errorStr); loc != nil { |
| 105 | // Extract from the first source context line to the end |
| 106 | context := errorStr[loc[0]+1:] // +1 to skip the leading newline |
| 107 | // Return VSCode-compatible format on first line, followed by source context only |
| 108 | frontmatterErrorLog.Print("Formatting error for VSCode compatibility") |
| 109 | return parser.NewFormattedParserError(fmt.Sprintf("%s\n%s", vscodeFormat, context)) |
| 110 | } |
| 111 | |
| 112 | // If we can't extract source context, return just the VSCode format |
| 113 | return parser.NewFormattedParserError(vscodeFormat) |
| 114 | } |
| 115 | |
| 116 | // Fallback if we can't parse the line/col: emit an IDE-compatible error |
| 117 | // pointing to the frontmatter start so the developer is at least brought to |
| 118 | // the right section rather than the useless line 1, col 1. |
| 119 | frontmatterErrorLog.Print("Could not extract line/col from formatted error, falling back to frontmatter start") |
| 120 | fallbackMsg := "failed to parse YAML frontmatter" |
| 121 | // Try to surface a single-line description from the raw error text. |
| 122 | if _, rest, found := strings.Cut(errorStr, frontmatterParseErrPrefix); found { |
| 123 | firstLine, _, _ := strings.Cut(rest, "\n") |
| 124 | if translated := parser.TranslateYAMLMessage(strings.TrimSpace(firstLine)); translated != "" { |
| 125 | fallbackMsg = "failed to parse YAML frontmatter: " + translated |
| 126 | } |
| 127 | } |
| 128 | fallbackFmt := fmt.Sprintf("%s:%d:1: error: %s", filePath, frontmatterLineOffset, fallbackMsg) |
| 129 | return parser.NewFormattedParserError(fallbackFmt) |
| 130 | } |
| 131 | |
| 132 | // Fallback: if not already formatted, create a FormattedParserError pointing to the |
| 133 | // frontmatter start so the IDE navigates to the right file and section rather than |
no test coverage detected