mime-todo-spec/scripts/ts-mime-todo/lib/issue.ts
Tiara Rodney 76266cedc6
init
2026-02-10 18:59:59 +01:00

97 lines
2.9 KiB
TypeScript

// mime-todo/lib/issue.ts
export type RelationshipKind = "dependsOn" | "relatesTo" | "blocks"
export interface IssueRelationships {
[kind: string]: number[]
}
export type IssueType = "feature" | "bugfix" | "hotfix"
export type IssueStatus = "open" | "in-progress" | "done" | "hold" | "cancelled"
export type IssuePriority = "low" | "medium" | "high"
export interface Issue {
id: number
type: IssueType
title: string
status: IssueStatus
priority: IssuePriority
created: string // YYYY-MM-DD
relationships: IssueRelationships
dueStart?: string // YYYY-MM-DD
dueEnd?: string // YYYY-MM-DD
description: string
body: string
}
export function parseRelationships(text: string): IssueRelationships {
const relationships: IssueRelationships = {}
// Handle empty relationships
if (!text || text.trim() === "") {
return relationships
}
// Simple parsing for format like "dependsOn:3"
const parts = text.split(/,\s*/).filter(p => p.trim() !== "")
for (const part of parts) {
const [key, value] = part.split(":").map(s => s.trim())
if (key && value) {
relationships[key] = value.split(/[\s]+/).map(Number).filter(n => !isNaN(n))
}
}
return relationships
}
export function parseIssue(text: string): Issue {
const lines = text.split(/\r?\n/)
const issue: Partial<Issue> = {}
let inDescription = false
const descLines: string[] = []
const bodyLines: string[] = []
for (const line of lines) {
if (!inDescription) {
if (line.startsWith("ID:")) issue.id = Number(line.slice(3).trim())
else if (line.startsWith("Type:")) issue.type = line.slice(5).trim()
else if (line.startsWith("Title:")) issue.title = line.slice(6).trim()
else if (line.startsWith("Status:")) issue.status = line.slice(7).trim()
else if (line.startsWith("Priority:")) issue.priority = line.slice(9).trim()
else if (line.startsWith("Created:")) issue.created = line.slice(8).trim()
else if (line.startsWith("DueStart:")) issue.dueStart = line.slice(9).trim()
else if (line.startsWith("DueEnd:")) issue.dueEnd = line.slice(7).trim()
else if (line.startsWith("Relationships:")) {
const rel = line.slice("Relationships:".length).trim()
issue.relationships = parseRelationships(rel)
}
else if (line.startsWith("Description:")) {
inDescription = true
descLines.push(line.slice("Description:".length).trim())
}
} else {
// Description continuation
if (line.trim() === "") {
// blank line ends description
inDescription = false
continue
}
if (/^\s+/.test(line)) {
descLines.push(line.trim())
continue
}
// first non-indented line ends description
inDescription = false
bodyLines.push(line)
}
}
issue.description = descLines.join("\n")
issue.body = bodyLines.join("\n")
return issue as Issue
}