From 9b384e57e6a4fe39c9fd0a3aca911db64777a285 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 01:14:01 +0000 Subject: [PATCH 1/2] Initial plan From 891126acb3863053b118c538311a6957e02cd84f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 01:23:28 +0000 Subject: [PATCH 2/2] perf: streamline frontmatter metadata extraction Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com> --- pkg/parser/frontmatter_content.go | 75 +++++++++++++--------- pkg/parser/frontmatter_field_lines_test.go | 9 +++ 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/pkg/parser/frontmatter_content.go b/pkg/parser/frontmatter_content.go index 1c5878d282b..59730147418 100644 --- a/pkg/parser/frontmatter_content.go +++ b/pkg/parser/frontmatter_content.go @@ -31,35 +31,7 @@ type FrontmatterResult struct { // opening "---" delimiter). The returned line numbers are absolute: they can be used // directly as file:line positions for IDE-navigable error messages. func extractTopLevelFieldLines(yamlContent string, frontmatterStart int) map[string]int { - fieldLines := make(map[string]int) - relLine := 0 - for line := range strings.SplitSeq(yamlContent, "\n") { - relLine++ - // Skip empty lines and YAML comments - trimmed := strings.TrimSpace(line) - if trimmed == "" || strings.HasPrefix(trimmed, "#") { - continue - } - // Top-level keys have no leading indentation - if len(line) > 0 && line[0] != ' ' && line[0] != '\t' { - colonIdx := strings.Index(trimmed, ":") - if colonIdx > 0 { - key := strings.TrimSpace(trimmed[:colonIdx]) - // Accept simple unquoted keys only. Bracket characters in the key position - // ({, }, [, ]) indicate inline YAML maps/sequences rather than plain string keys - // (e.g. `[anchor]: value` or `{implicit_key}: value`). These forms are not used - // in workflow frontmatter, so we skip them to avoid false positives. - // Quoted YAML keys such as `"key[0]"` are also not used in workflow frontmatter - // and are excluded by this check (the extracted substring will contain the quote). - if key != "" && !strings.ContainsAny(key, " \t{}[]\"'") { - if _, alreadySeen := fieldLines[key]; !alreadySeen { - // absoluteLine = relLine + frontmatterStart - 1 - fieldLines[key] = relLine + frontmatterStart - 1 - } - } - } - } - } + _, fieldLines := extractFrontmatterMetadata(yamlContent, frontmatterStart) return fieldLines } @@ -79,7 +51,7 @@ func ExtractFrontmatterFromContent(content string) (*FrontmatterResult, error) { } frontmatterYAML := content[searchStart:frontmatterEndStart] - frontmatterLines := splitFrontmatterLines(frontmatterYAML) + frontmatterLines, fieldLines := extractFrontmatterMetadata(frontmatterYAML, frontmatterStartLine) frontmatter, err := parseFrontmatterYAML(frontmatterYAML) if err != nil { return nil, err @@ -87,16 +59,17 @@ func ExtractFrontmatterFromContent(content string) (*FrontmatterResult, error) { markdown := extractMarkdownAfterFrontmatter(content, markdownStart) parserLog.Printf("Successfully extracted frontmatter: fields=%d, markdown_size=%d bytes", len(frontmatter), len(markdown)) - const frontmatterStartLine = 2 // Line 2 is where frontmatter content starts (after opening ---) return &FrontmatterResult{ Frontmatter: frontmatter, Markdown: strings.TrimSpace(markdown), FrontmatterLines: frontmatterLines, FrontmatterStart: frontmatterStartLine, - FieldLines: extractTopLevelFieldLines(frontmatterYAML, frontmatterStartLine), + FieldLines: fieldLines, }, nil } +const frontmatterStartLine = 2 // Line 2 is where frontmatter content starts (after opening ---) + func splitFirstLine(content string) (int, string) { firstNewline := strings.IndexByte(content, '\n') if firstNewline < 0 { @@ -168,6 +141,44 @@ func splitFrontmatterLines(frontmatterYAML string) []string { return lines } +func extractFrontmatterMetadata(frontmatterYAML string, frontmatterStart int) ([]string, map[string]int) { + if frontmatterYAML == "" { + return []string{}, map[string]int{} + } + + lines := make([]string, 0, strings.Count(frontmatterYAML, "\n")+1) + fieldLines := make(map[string]int) + relLine := 0 + + for line := range strings.SplitSeq(frontmatterYAML, "\n") { + relLine++ + lines = append(lines, line) + + trimmed := strings.TrimSpace(line) + if trimmed == "" || strings.HasPrefix(trimmed, "#") { + continue + } + + if len(line) > 0 && line[0] != ' ' && line[0] != '\t' { + colonIdx := strings.IndexByte(trimmed, ':') + if colonIdx > 0 { + key := strings.TrimSpace(trimmed[:colonIdx]) + if key != "" && !strings.ContainsAny(key, " \t{}[]\"'") { + if _, alreadySeen := fieldLines[key]; !alreadySeen { + fieldLines[key] = relLine + frontmatterStart - 1 + } + } + } + } + } + + if strings.HasSuffix(frontmatterYAML, "\n") { + lines = lines[:len(lines)-1] + } + + return lines, fieldLines +} + func parseFrontmatterYAML(frontmatterYAML string) (map[string]any, error) { frontmatterYAML = strings.ReplaceAll(frontmatterYAML, "\u00A0", " ") var frontmatter map[string]any diff --git a/pkg/parser/frontmatter_field_lines_test.go b/pkg/parser/frontmatter_field_lines_test.go index d6843b7d4d2..989c53a72c5 100644 --- a/pkg/parser/frontmatter_field_lines_test.go +++ b/pkg/parser/frontmatter_field_lines_test.go @@ -103,4 +103,13 @@ func TestFrontmatterResultFieldLines(t *testing.T) { // FieldLines is nil when there is no frontmatter assert.Nil(t, result.FieldLines, "FieldLines should be nil when there is no frontmatter") }) + + t.Run("preserves blank frontmatter lines while tracking top level fields", func(t *testing.T) { + content := "---\nengine: copilot\n\n# comment\non: push\n---\n# Workflow\n" + result, err := ExtractFrontmatterFromContent(content) + require.NoError(t, err, "Should parse frontmatter without error") + + assert.Equal(t, []string{"engine: copilot", "", "# comment", "on: push"}, result.FrontmatterLines) + assert.Equal(t, map[string]int{"engine": 2, "on": 5}, result.FieldLines) + }) }