Skip to main content
Glama
lines.ts7.59 kB
/** * Line-based content manipulation utilities. * * All functions treat lines as 1-indexed (first line is line 1). * Content is split on '\n' — handles both Unix and Windows line endings. */ // ───────────────────────────────────────────────────────────── // Parsing // ───────────────────────────────────────────────────────────── /** * Parse a line range string into start/end numbers. * * @param range - Line specification: "10" (single) or "10-15" (range) * @returns Parsed range or null if invalid * * @example * parseLineRange("10") // { start: 10, end: 10 } * parseLineRange("10-15") // { start: 10, end: 15 } * parseLineRange("15-10") // null (invalid: start > end) * parseLineRange("abc") // null (invalid format) */ export function parseLineRange(range: string): { start: number; end: number } | null { const trimmed = range.trim(); // Single line: "10" if (/^\d+$/.test(trimmed)) { const line = parseInt(trimmed, 10); return { start: line, end: line }; } // Range: "10-15" const match = trimmed.match(/^(\d+)-(\d+)$/); if (match?.[1] && match[2]) { const start = parseInt(match[1], 10); const end = parseInt(match[2], 10); if (start <= end) { return { start, end }; } } return null; } // ───────────────────────────────────────────────────────────── // Display // ───────────────────────────────────────────────────────────── /** * Add line numbers to content for display. * * @param content - Text content to number * @param startLine - Starting line number (default: 1) * @returns Content with line numbers: " 1|line one\n 2|line two" * * @example * addLineNumbers("foo\nbar") * // "1|foo\n2|bar" * * addLineNumbers("foo\nbar", 10) * // "10|foo\n11|bar" */ export function addLineNumbers(content: string, startLine = 1): string { const lines = content.split('\n'); const maxLineNum = startLine + lines.length - 1; const width = String(maxLineNum).length; return lines .map((line, i) => { const lineNum = String(startLine + i).padStart(width, ' '); return `${lineNum}|${line}`; }) .join('\n'); } // ───────────────────────────────────────────────────────────── // Extraction // ───────────────────────────────────────────────────────────── /** * Extract a range of lines from content. * * @param content - Full text content * @param start - Start line (1-indexed, clamped to bounds) * @param end - End line (1-indexed, inclusive, clamped to bounds) * @returns Extracted text and actual line range used * * @example * const file = "a\nb\nc\nd\ne"; * extractLines(file, 2, 4) * // { text: "b\nc\nd", actualStart: 2, actualEnd: 4 } * * extractLines(file, 4, 100) * // { text: "d\ne", actualStart: 4, actualEnd: 5 } */ export function extractLines( content: string, start: number, end: number, ): { text: string; actualStart: number; actualEnd: number } { const lines = content.split('\n'); const actualStart = Math.max(1, start); const actualEnd = Math.min(lines.length, end); const extracted = lines.slice(actualStart - 1, actualEnd).join('\n'); return { text: extracted, actualStart, actualEnd, }; } /** * Get context lines around a target line. * * @param content - Full text content * @param line - Target line number (1-indexed) * @param contextBefore - Lines to include before target * @param contextAfter - Lines to include after target * @returns Lines before and after (not including target line) * * @example * const file = "a\nb\nc\nd\ne"; * getContextLines(file, 3, 1, 1) * // { before: ["b"], after: ["d"] } */ export function getContextLines( content: string, line: number, contextBefore: number, contextAfter: number, ): { before: string[]; after: string[] } { const lines = content.split('\n'); const lineIndex = line - 1; const beforeStart = Math.max(0, lineIndex - contextBefore); const afterEnd = Math.min(lines.length, lineIndex + 1 + contextAfter); return { before: lines.slice(beforeStart, lineIndex), after: lines.slice(lineIndex + 1, afterEnd), }; } // ───────────────────────────────────────────────────────────── // Modification // ───────────────────────────────────────────────────────────── /** * Replace a range of lines with new content. * * @param content - Original content * @param start - First line to replace (1-indexed) * @param end - Last line to replace (1-indexed, inclusive) * @param replacement - New content (can be multi-line) * @returns Modified content * * @example * const file = "a\nb\nc\nd"; * replaceLines(file, 2, 3, "X\nY\nZ") * // "a\nX\nY\nZ\nd" */ export function replaceLines( content: string, start: number, end: number, replacement: string, ): string { const lines = content.split('\n'); const before = lines.slice(0, start - 1); const after = lines.slice(end); return [...before, replacement, ...after].join('\n'); } /** * Insert content before a specific line. * * @param content - Original content * @param line - Line to insert before (1-indexed) * @param insertion - Content to insert * @returns Modified content * * @example * const file = "a\nb\nc"; * insertBeforeLine(file, 2, "X") * // "a\nX\nb\nc" */ export function insertBeforeLine(content: string, line: number, insertion: string): string { const lines = content.split('\n'); const insertIndex = Math.max(0, line - 1); lines.splice(insertIndex, 0, insertion); return lines.join('\n'); } /** * Insert content after a specific line. * * @param content - Original content * @param line - Line to insert after (1-indexed) * @param insertion - Content to insert * @returns Modified content * * @example * const file = "a\nb\nc"; * insertAfterLine(file, 2, "X") * // "a\nb\nX\nc" */ export function insertAfterLine(content: string, line: number, insertion: string): string { const lines = content.split('\n'); const insertIndex = Math.min(lines.length, line); lines.splice(insertIndex, 0, insertion); return lines.join('\n'); } /** * Delete a range of lines from content. * * @param content - Original content * @param start - First line to delete (1-indexed) * @param end - Last line to delete (1-indexed, inclusive) * @returns Modified content * * @example * const file = "a\nb\nc\nd"; * deleteLines(file, 2, 3) * // "a\nd" */ export function deleteLines(content: string, start: number, end: number): string { const lines = content.split('\n'); const before = lines.slice(0, start - 1); const after = lines.slice(end); return [...before, ...after].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/iceener/files-stdio-mcp-server'

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