Extract YAML frontmatter and message body from markdown. Returns (frontmatter_dict, message_body). Supports multi-line dictionary items in lists by preserving indentation.
(content: str)
| 85 | |
| 86 | |
| 87 | def extract_frontmatter(content: str) -> tuple[Dict[str, Any], str]: |
| 88 | """Extract YAML frontmatter and message body from markdown. |
| 89 | |
| 90 | Returns (frontmatter_dict, message_body). |
| 91 | |
| 92 | Supports multi-line dictionary items in lists by preserving indentation. |
| 93 | """ |
| 94 | if not content.startswith('---'): |
| 95 | return {}, content |
| 96 | |
| 97 | # Split on --- markers |
| 98 | parts = content.split('---', 2) |
| 99 | if len(parts) < 3: |
| 100 | return {}, content |
| 101 | |
| 102 | frontmatter_text = parts[1] |
| 103 | message = parts[2].strip() |
| 104 | |
| 105 | # Simple YAML parser that handles indented list items |
| 106 | frontmatter = {} |
| 107 | lines = frontmatter_text.split('\n') |
| 108 | |
| 109 | current_key = None |
| 110 | current_list = [] |
| 111 | current_dict = {} |
| 112 | in_list = False |
| 113 | in_dict_item = False |
| 114 | |
| 115 | for line in lines: |
| 116 | # Skip empty lines and comments |
| 117 | stripped = line.strip() |
| 118 | if not stripped or stripped.startswith('#'): |
| 119 | continue |
| 120 | |
| 121 | # Check indentation level |
| 122 | indent = len(line) - len(line.lstrip()) |
| 123 | |
| 124 | # Top-level key (no indentation or minimal) |
| 125 | if indent == 0 and ':' in line and not line.strip().startswith('-'): |
| 126 | # Save previous list/dict if any |
| 127 | if in_list and current_key: |
| 128 | if in_dict_item and current_dict: |
| 129 | current_list.append(current_dict) |
| 130 | current_dict = {} |
| 131 | frontmatter[current_key] = current_list |
| 132 | in_list = False |
| 133 | in_dict_item = False |
| 134 | current_list = [] |
| 135 | |
| 136 | key, value = line.split(':', 1) |
| 137 | key = key.strip() |
| 138 | value = value.strip() |
| 139 | |
| 140 | if not value: |
| 141 | # Empty value - list or nested structure follows |
| 142 | current_key = key |
| 143 | in_list = True |
| 144 | current_list = [] |
no outgoing calls
no test coverage detected