Skip to main content
Glama
scanady
by scanady
parser.ts4.66 kB
/** * Parser service for markdown files with frontmatter */ import matter from 'gray-matter'; import { Standard, StandardMetadata, ResponseFormat } from '../types.js'; import { validateMetadata } from './validator.js'; import { ERROR_MESSAGES } from '../constants.js'; /** * Parses a markdown file with frontmatter into a Standard object */ export function parseStandard(fileContent: string, filePath: string): Standard { try { const parsed = matter(fileContent); // Validate and parse metadata const metadata = validateMetadata(parsed.data); return { metadata, content: parsed.content.trim(), path: filePath, }; } catch (error) { throw new Error(`${ERROR_MESSAGES.INVALID_METADATA} in ${filePath}: ${error}`); } } /** * Serializes a Standard object back to markdown with frontmatter */ export function serializeStandard(standard: Standard): string { return matter.stringify(standard.content, standard.metadata); } /** * Formats a standard for output based on response format */ export function formatStandard(standard: Standard, format: ResponseFormat): string { if (format === 'json') { return JSON.stringify(standard, null, 2); } // Markdown format return formatStandardAsMarkdown(standard); } /** * Formats a standard as human-readable markdown */ function formatStandardAsMarkdown(standard: Standard): string { const { metadata, content, path } = standard; return `# Standard: ${path} ## Metadata - **Type**: ${metadata.type} - **Tier**: ${metadata.tier} - **Process**: ${metadata.process} - **Tags**: ${metadata.tags.join(', ')} - **Version**: ${metadata.version} - **Status**: ${metadata.status} - **Author**: ${metadata.author} - **Created**: ${metadata.created} - **Last Updated**: ${metadata.updated} ## Content ${content} `; } /** * Formats multiple standards for output */ export function formatStandards(standards: Standard[], format: ResponseFormat): string { if (format === 'json') { return JSON.stringify(standards, null, 2); } // Markdown format if (standards.length === 0) { return 'No standards found.'; } return standards.map((s, i) => `${i + 1}. ${formatStandardAsMarkdown(s)}\n---\n`).join('\n'); } /** * Formats metadata only (without content) for output */ export function formatMetadata( metadata: StandardMetadata, path: string, format: ResponseFormat ): string { if (format === 'json') { return JSON.stringify({ path, metadata }, null, 2); } // Markdown format return `**${path}** - Type: ${metadata.type} - Tier: ${metadata.tier} - Process: ${metadata.process} - Tags: ${metadata.tags.join(', ')} - Version: ${metadata.version} - Status: ${metadata.status} - Author: ${metadata.author} - Updated: ${metadata.updated}`; } /** * Formats multiple metadata entries for output */ export function formatMetadataList( entries: Array<{ path: string; metadata: StandardMetadata }>, format: ResponseFormat ): string { if (format === 'json') { return JSON.stringify(entries, null, 2); } // Markdown format if (entries.length === 0) { return 'No standards found.'; } return entries.map((entry) => formatMetadata(entry.metadata, entry.path, format)).join('\n\n'); } /** * Extracts a snippet of text around a search match */ export function extractContext( text: string, matchIndex: number, contextLength: number = 200 ): string { const halfContext = Math.floor(contextLength / 2); const start = Math.max(0, matchIndex - halfContext); const end = Math.min(text.length, matchIndex + halfContext); let snippet = text.slice(start, end); // Add ellipsis if we're not at the start/end if (start > 0) snippet = '...' + snippet; if (end < text.length) snippet = snippet + '...'; return snippet; } /** * Formats search results for output */ export function formatSearchResults( results: Array<{ standard: Standard; matches: Array<{ context: string }>; score: number; }>, format: ResponseFormat ): string { if (format === 'json') { return JSON.stringify(results, null, 2); } // Markdown format if (results.length === 0) { return 'No results found.'; } return results .map((result, i) => { const { standard, matches, score } = result; const matchContexts = matches.map((m) => ` > ${m.context}`).join('\n'); return `${i + 1}. **${standard.path}** (score: ${score.toFixed(2)}) Type: ${standard.metadata.type} | Tier: ${standard.metadata.tier} | Process: ${standard.metadata.process} Tags: ${standard.metadata.tags.join(', ')} Matches: ${matchContexts} `; }) .join('\n'); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/scanady/engineering-standards-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server