Skip to main content
Glama
BaseParseStrategy.ts4.01 kB
import type { Node, Query, Tree } from 'web-tree-sitter'; import type { RepomixConfigMerged } from '../../../config/configSchema.js'; export interface ParseContext { fileContent: string; lines: string[]; tree: Tree; query: Query; config: RepomixConfigMerged; } export interface ParseStrategy { parseCapture( capture: { node: Node; name: string }, lines: string[], processedChunks: Set<string>, context: ParseContext, ): string | null; } /** * Result type for parse operations */ export type ParseResult = { content: string | null; processedSignatures?: Set<string>; }; /** * Base abstract class providing common functionality for all parse strategies * * IMPORTANT: Strategy instances are shared across all files of the same language. * Strategies MUST be stateless - do not add instance variables or mutable state. * All data should come from method parameters only. */ export abstract class BaseParseStrategy implements ParseStrategy { /** * Main entry point for parsing a capture. Must be implemented by subclasses. */ abstract parseCapture( capture: { node: Node; name: string }, lines: string[], processedChunks: Set<string>, context: ParseContext, ): string | null; /** * Helper method to get capture types from a capture name * * NOTE: Uses includes() intentionally to match hierarchical capture names. * Tree-sitter queries use captures like @name.definition.function for function names, * which should match 'definition.function'. This is not a bug but a design choice. * * @param name - The capture name to analyze (e.g., 'name.definition.function') * @param captureTypes - Object containing capture type constants * @returns Set of matching capture types */ protected getCaptureTypes<T extends Record<string, string>>(name: string, captureTypes: T): Set<T[keyof T]> { const types = new Set<T[keyof T]>(); for (const type of Object.values(captureTypes)) { // Uses includes() to match hierarchical names (e.g., 'name.definition.function' matches 'definition.function') if (name.includes(type)) { types.add(type as T[keyof T]); } } return types; } /** * Check if content has been processed and add it if not * @param content - The content to check * @param processedChunks - Set of already processed chunks * @returns true if content is new and was added, false if already processed */ protected checkAndAddToProcessed(content: string, processedChunks: Set<string>): boolean { const normalized = content.trim(); if (processedChunks.has(normalized)) { return false; } processedChunks.add(normalized); return true; } /** * Validate that the line at startRow exists * @param lines - Array of file lines * @param startRow - Row to validate * @returns true if line exists, false otherwise */ protected validateLineExists(lines: string[], startRow: number): boolean { return lines[startRow] !== undefined; } /** * Extract lines from a range and validate * @param lines - Array of file lines * @param startRow - Starting row * @param endRow - Ending row * @returns Array of selected lines, or null if invalid */ protected extractLines(lines: string[], startRow: number, endRow: number): string[] | null { if (!this.validateLineExists(lines, startRow)) { return null; } const selectedLines = lines.slice(startRow, endRow + 1); return selectedLines.length > 0 ? selectedLines : null; } /** * Create a ParseResult with null content */ protected createNullResult(): ParseResult { return { content: null }; } /** * Create a ParseResult with content * @param content - The content to include * @param processedSignatures - Optional set of processed signatures */ protected createResult(content: string, processedSignatures?: Set<string>): ParseResult { return { content, processedSignatures }; } }

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/yamadashy/repomix'

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