(content: string, id: string)
| 136 | |
| 137 | /** Parse bump file content (for testing) */ |
| 138 | export function parseBumpFile(content: string, id: string): BumpFileParseResult { |
| 139 | const errors: string[] = []; |
| 140 | const match = content.match(/^---\n([\s\S]*?)\n?---\n?([\s\S]*)$/); |
| 141 | if (!match) { |
| 142 | errors.push(`Bump file "${id}" has no valid frontmatter (expected --- delimiters)`); |
| 143 | return { bumpFile: null, errors }; |
| 144 | } |
| 145 | |
| 146 | const frontmatter = match[1]!; |
| 147 | const summary = match[2]!.trim(); |
| 148 | |
| 149 | // Empty frontmatter is intentional — signals no releases needed |
| 150 | if (!frontmatter.trim()) { |
| 151 | return { bumpFile: null, errors }; |
| 152 | } |
| 153 | |
| 154 | let parsed: Record<string, unknown>; |
| 155 | try { |
| 156 | parsed = yaml.load(frontmatter) as Record<string, unknown>; |
| 157 | } catch (e) { |
| 158 | errors.push(`Bump file "${id}" has invalid YAML: ${e instanceof Error ? e.message : e}`); |
| 159 | return { bumpFile: null, errors }; |
| 160 | } |
| 161 | if (!parsed || typeof parsed !== 'object') { |
| 162 | errors.push(`Bump file "${id}" has empty or invalid frontmatter`); |
| 163 | return { bumpFile: null, errors }; |
| 164 | } |
| 165 | |
| 166 | const releases: BumpFileRelease[] = []; |
| 167 | let noChangelog = false; |
| 168 | for (const [name, value] of Object.entries(parsed)) { |
| 169 | // Reserved meta keys are sigil-prefixed (`$`) so they can never collide with |
| 170 | // a package name (`$` is rejected by validatePackageName). |
| 171 | if (name.startsWith('$')) { |
| 172 | if (name === '$changelog') { |
| 173 | if (typeof value !== 'boolean') { |
| 174 | errors.push(`Reserved key "$changelog" in bump file "${id}" must be true or false`); |
| 175 | } else if (value === false) { |
| 176 | noChangelog = true; |
| 177 | } |
| 178 | } else { |
| 179 | errors.push(`Unknown reserved key "${name}" in bump file "${id}" (expected: $changelog)`); |
| 180 | } |
| 181 | continue; |
| 182 | } |
| 183 | |
| 184 | if (!validatePackageName(name)) { |
| 185 | errors.push(`Invalid package name "${name}" in bump file "${id}"`); |
| 186 | continue; |
| 187 | } |
| 188 | |
| 189 | if (typeof value === 'string') { |
| 190 | if (!VALID_BUMP_TYPES.has(value)) { |
| 191 | errors.push( |
| 192 | `Unknown bump type "${value}" for "${name}" in bump file "${id}" (expected: major, minor, patch, or none)`, |
| 193 | ); |
| 194 | continue; |
| 195 | } |
no test coverage detected
searching dependent graphs…