A previous run could merge the '---' separator with the next section
header (---## ✅ Befejezett), breaking section detection. Prefix/suffix
are now trimmed and rejoined with fixed separators. Regression test
added; also create Plane issues for local-only completed work
(MITHOME-28 Custom CMS, MITHOME-29 Webmail) to avoid ID collisions.
103 lines
3.6 KiB
JavaScript
103 lines
3.6 KiB
JavaScript
// WHY: sections are identified by emoji header; order defines generated layout
|
|
const SECTIONS = [
|
|
{ key: 'completed', header: /^## ✅/, emoji: '✅', hasNote: false },
|
|
{ key: 'todo', header: /^## 🚀/, emoji: '⏳', hasNote: true },
|
|
{ key: 'inProgress', header: /^## 🔄/, emoji: '🔄', hasNote: true },
|
|
{ key: 'backlog', header: /^## 📋/, emoji: '📋', hasNote: false }
|
|
];
|
|
|
|
const SECTION_LABEL = {
|
|
completed: 'Befejezett',
|
|
todo: 'TODO',
|
|
inProgress: 'In Progress',
|
|
backlog: 'Backlog'
|
|
};
|
|
|
|
function parseTodoFile(content) {
|
|
const sections = {
|
|
completed: { header: null, rows: [] },
|
|
todo: { header: null, rows: [] },
|
|
inProgress: { header: null, rows: [] },
|
|
backlog: { header: null, rows: [] }
|
|
};
|
|
const rows = [];
|
|
let current = null;
|
|
|
|
for (const line of content.split('\n')) {
|
|
const sec = SECTIONS.find(s => s.header.test(line));
|
|
if (sec) {
|
|
current = sec.key;
|
|
if (!sections[current].header) sections[current].header = line;
|
|
continue;
|
|
}
|
|
if (!current || !line.trim().startsWith('|')) continue;
|
|
const cols = line.split('|').map(c => c.trim()).filter(c => c !== '');
|
|
if (cols.length < 3) continue;
|
|
if (cols[0] === 'Plane' || /^[-]+$/.test(cols[0])) continue;
|
|
const row = { id: cols[0], name: cols[1], status: cols[2], note: cols[3] || '' };
|
|
sections[current].rows.push(row);
|
|
rows.push({ section: current, ...row });
|
|
}
|
|
|
|
return { sections, rows };
|
|
}
|
|
|
|
function seqNum(id) {
|
|
const match = id.match(/(\d+)$/);
|
|
return match ? parseInt(match[1], 10) : 0;
|
|
}
|
|
|
|
function buildTable(sec, rows) {
|
|
const header = sec.hasNote
|
|
? '| Plane | Feladat | Státusz | Megjegyzés |'
|
|
: '| Plane | Feladat | Státusz |';
|
|
const separator = sec.hasNote
|
|
? '|-------|---------|---------|-----------|'
|
|
: '|-------|---------|---------|';
|
|
const body = rows
|
|
.slice()
|
|
.sort((a, b) => seqNum(a.id) - seqNum(b.id))
|
|
.map(row => {
|
|
if (sec.hasNote) return `| ${row.id} | ${row.name} | ${sec.emoji} | ${row.note || ''} |`;
|
|
return `| ${row.id} | ${row.name} | ${sec.emoji} |`;
|
|
});
|
|
return [header, separator, ...body].join('\n');
|
|
}
|
|
|
|
// WHY: only the section region is regenerated, prefix/suffix (overview, commands) are preserved.
|
|
// Prefix/suffix are trimmed and rejoined with normalized separators so that a previous run
|
|
// that dropped the blank line after `---` cannot corrupt the section headers (`---## ✅`).
|
|
function regenerate(content, finalSections) {
|
|
const lines = content.split('\n');
|
|
const firstIdx = lines.findIndex(l => SECTIONS[0].header.test(l));
|
|
const backlogIdx = lines.findIndex(l => SECTIONS[3].header.test(l));
|
|
if (firstIdx === -1 || backlogIdx === -1) throw new Error('TODO.md section headers not found');
|
|
|
|
let endIdx = lines.length;
|
|
for (let i = backlogIdx + 1; i < lines.length; i++) {
|
|
if (lines[i].trim() === '---') {
|
|
endIdx = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
const prefix = lines.slice(0, firstIdx).join('\n').trimEnd();
|
|
const suffix = lines.slice(endIdx + 1).join('\n').trimStart();
|
|
|
|
const headerOf = key => {
|
|
const sec = SECTIONS.find(s => s.key === key);
|
|
const idx = lines.findIndex(l => sec.header.test(l));
|
|
return idx >= 0 ? lines[idx].replace(/^## /, '') : key;
|
|
};
|
|
|
|
const blocks = SECTIONS.map(sec => {
|
|
const rows = finalSections[sec.key] || [];
|
|
return `## ${headerOf(sec.key)}\n\n${buildTable(sec, rows)}`;
|
|
});
|
|
const middle = blocks.join('\n\n---\n\n');
|
|
const result = `${prefix}\n\n${middle}\n\n---\n\n${suffix}`;
|
|
return result.endsWith('\n') ? result : `${result}\n`;
|
|
}
|
|
|
|
module.exports = { SECTIONS, SECTION_LABEL, parseTodoFile, buildTable, regenerate, seqNum };
|