UNPKG

aios-core

Version:

Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework

199 lines (177 loc) 5.57 kB
/** * @fileoverview Parser for Markdown files with AIOS-MANAGED sections * @module merger/parsers/markdown-section-parser */ // Regex patterns for AIOS markers const AIOS_START_MARKER = /^<!--\s*AIOS-MANAGED-START:\s*([a-zA-Z0-9_-]+)\s*-->$/; const AIOS_END_MARKER = /^<!--\s*AIOS-MANAGED-END:\s*([a-zA-Z0-9_-]+)\s*-->$/; const HEADER_PATTERN = /^(#{1,6})\s+(.+)$/; /** * Parsed section from markdown * @typedef {Object} ParsedSection * @property {string} id - Section identifier (slug or marker id) * @property {string} [title] - Section title (from header) * @property {number} [level] - Header level (1-6) * @property {number} startLine - Start line number (0-indexed) * @property {number} [endLine] - End line number (0-indexed) * @property {boolean} managed - True if AIOS-MANAGED section * @property {string[]} lines - Lines in this section (excluding markers) */ /** * Result of parsing a markdown file * @typedef {Object} ParsedMarkdownFile * @property {ParsedSection[]} sections - All sections found * @property {boolean} hasAiosMarkers - True if file has AIOS-MANAGED markers * @property {string[]} preamble - Lines before first section * @property {string[]} rawLines - Original lines */ /** * Convert a string to a URL-friendly slug * @param {string} text - Text to slugify * @returns {string} Slugified text */ function slugify(text) { return text .toLowerCase() .trim() .replace(/[^\w\s-]/g, '') // Remove special chars .replace(/[\s_-]+/g, '-') // Replace spaces/underscores with hyphens .replace(/^-+|-+$/g, ''); // Remove leading/trailing hyphens } /** * Parse a markdown file, identifying sections and AIOS-MANAGED areas * @param {string} content - Markdown content * @returns {ParsedMarkdownFile} Parsed result */ function parseMarkdownSections(content) { if (!content || content.trim() === '') { return { sections: [], hasAiosMarkers: false, preamble: [], rawLines: [], }; } const lines = content.split('\n'); const result = { sections: [], hasAiosMarkers: false, preamble: [], rawLines: lines, }; let currentSection = null; let aiosSection = null; let inPreamble = true; for (let i = 0; i < lines.length; i++) { const line = lines[i]; const trimmed = line.trim(); // Check for AIOS start marker const startMatch = trimmed.match(AIOS_START_MARKER); if (startMatch) { // Close any current non-managed section if (currentSection && !currentSection.managed) { currentSection.endLine = i - 1; result.sections.push(currentSection); currentSection = null; } // Start new AIOS-managed section aiosSection = { id: startMatch[1], startLine: i, managed: true, lines: [], }; result.hasAiosMarkers = true; inPreamble = false; continue; } // Check for AIOS end marker const endMatch = trimmed.match(AIOS_END_MARKER); if (endMatch && aiosSection) { if (endMatch[1] === aiosSection.id) { aiosSection.endLine = i; result.sections.push(aiosSection); aiosSection = null; } continue; } // If we're in an AIOS section, collect lines if (aiosSection) { aiosSection.lines.push(line); continue; } // Check for regular header const headerMatch = line.match(HEADER_PATTERN); if (headerMatch) { // Close any current section if (currentSection) { currentSection.endLine = i - 1; result.sections.push(currentSection); } // Start new section currentSection = { id: slugify(headerMatch[2]), title: headerMatch[2], level: headerMatch[1].length, startLine: i, managed: false, lines: [line], }; inPreamble = false; continue; } // Regular content line if (inPreamble) { result.preamble.push(line); } else if (currentSection) { currentSection.lines.push(line); } else if (!aiosSection) { // Content after an AIOS section but before next section // This shouldn't happen in well-formed files, but handle it result.preamble.push(line); } } // Close final section if open if (currentSection) { currentSection.endLine = lines.length - 1; result.sections.push(currentSection); } // Handle unclosed AIOS section (malformed) if (aiosSection) { aiosSection.endLine = lines.length - 1; aiosSection.lines.push('<!-- WARNING: Unclosed AIOS-MANAGED section -->'); result.sections.push(aiosSection); } return result; } /** * Check if content has AIOS-MANAGED markers * @param {string} content - Markdown content * @returns {boolean} True if markers found */ function hasAiosMarkers(content) { if (!content) return false; // Check for both START and END markers const hasStart = /<!--\s*AIOS-MANAGED-START:\s*[a-zA-Z0-9_-]+\s*-->/.test(content); const hasEnd = /<!--\s*AIOS-MANAGED-END:\s*[a-zA-Z0-9_-]+\s*-->/.test(content); return hasStart && hasEnd; } /** * Get all AIOS section IDs from content * @param {string} content - Markdown content * @returns {string[]} Array of section IDs */ function getAiosSectionIds(content) { const ids = []; const matches = content.matchAll(/<!--\s*AIOS-MANAGED-START:\s*([a-zA-Z0-9_-]+)\s*-->/g); for (const match of matches) { ids.push(match[1]); } return ids; } module.exports = { slugify, parseMarkdownSections, hasAiosMarkers, getAiosSectionIds, };