89 lines
3.3 KiB
JavaScript
89 lines
3.3 KiB
JavaScript
// mime-todo/lib/issue.ts
|
|
// Valid status transitions
|
|
const VALID_TRANSITIONS = {
|
|
"open": ["in-progress", "hold", "cancelled"],
|
|
"in-progress": ["done", "hold", "open", "cancelled"],
|
|
"hold": ["open", "in-progress", "cancelled"],
|
|
"done": ["open"],
|
|
"cancelled": ["open"],
|
|
};
|
|
export function validateStatusTransition(from, to) {
|
|
if (from === to)
|
|
return null; // no-op is fine
|
|
const allowed = VALID_TRANSITIONS[from];
|
|
if (!allowed?.includes(to)) {
|
|
return `Invalid status transition: ${from} → ${to}. Allowed from ${from}: ${allowed?.join(", ") ?? "none"}`;
|
|
}
|
|
return null;
|
|
}
|
|
export function parseRelationships(text) {
|
|
const relationships = {};
|
|
// 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) {
|
|
const lines = text.split(/\r?\n/);
|
|
const issue = {};
|
|
let inDescription = false;
|
|
const descLines = [];
|
|
const bodyLines = [];
|
|
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("Module:"))
|
|
issue.module = line.slice("Module:".length).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;
|
|
}
|