MCPcopy Create free account
hub / github.com/SethGammon/Citadel / parsePhaseTable

Function parsePhaseTable

core/campaigns/parse-campaign.js:45–83  ·  view source on GitHub ↗

* Parse the Phases markdown table into structured objects. * * Expects a table with columns (in any order): * | # | Status | Type | Phase | Done When | * * Returns an array of phase objects. Rows that don't parse cleanly are skipped. * * @param {string} content - Full campaign file content

(content)

Source from the content-addressed store, hash-verified

43 * @returns {Array<{number: number, status: string, type: string, name: string, doneWhen: string}>}
44 */
45function parsePhaseTable(content) {
46 const section = parseSection(content, 'Phases');
47 if (!section) return [];
48
49 const rows = section.split(/\r?\n/).filter(line => line.trim().startsWith('|'));
50 if (rows.length < 2) return [];
51
52 // First row is the header — extract column positions
53 const headerCells = rows[0].split('|').map(c => c.trim().toLowerCase());
54 const col = {
55 number: headerCells.indexOf('#'),
56 status: headerCells.indexOf('status'),
57 type: headerCells.indexOf('type'),
58 name: headerCells.findIndex(h => h === 'phase' || h === 'name'),
59 doneWhen: headerCells.findIndex(h => h.includes('done') || h.includes('when')),
60 };
61
62 // Second row is the separator — skip it
63 const dataRows = rows.slice(2);
64 const phases = [];
65
66 for (const row of dataRows) {
67 const cells = row.split('|').map(c => c.trim());
68 // cells[0] is empty (before first |), col indices from indexOf already
69 // account for this empty slot so use them directly — no +1 adjustment.
70 const get = (idx) => (idx >= 0 && idx < cells.length ? cells[idx] : '');
71 const num = parseInt(get(col.number), 10);
72 if (Number.isNaN(num)) continue;
73 phases.push({
74 number: num,
75 status: get(col.status) || 'pending',
76 type: get(col.type) || '',
77 name: get(col.name) || '',
78 doneWhen: get(col.doneWhen) || '',
79 });
80 }
81
82 return phases;
83}
84
85function parseCampaignContent(content, options = {}) {
86 const slug = options.slug || null;

Callers 1

parseCampaignContentFunction · 0.85

Calls 2

parseSectionFunction · 0.85
getFunction · 0.70

Tested by

no test coverage detected