Skip to main content
Glama
linting-utils.ts5.35 kB
// @ts-ignore - ESLint types may not be available import { ESLint } from 'eslint'; import prettier from 'prettier'; import { readFileSync } from 'fs'; import type { LintResult, FormatResult } from '../types/index.js'; export class LintingUtils { private eslint: ESLint | null = null; /** * Initialize ESLint */ private async getESLint(): Promise<ESLint> { if (!this.eslint) { this.eslint = new ESLint({ useEslintrc: true, fix: false, }); } return this.eslint; } /** * Lint code files */ async lintFiles(filePaths: string[]): Promise<LintResult[]> { try { const eslint = await this.getESLint(); const results = await eslint.lintFiles(filePaths); return results.map((result: any) => ({ file: result.filePath, messages: result.messages.map((msg: any) => ({ ruleId: msg.ruleId, severity: msg.severity as 0 | 1 | 2, message: msg.message, line: msg.line, column: msg.column, endLine: msg.endLine, endColumn: msg.endColumn, fix: msg.fix ? { range: [msg.fix.range[0], msg.fix.range[1]], text: msg.fix.text, } : undefined, })), errorCount: result.errorCount, warningCount: result.warningCount, fixableErrorCount: result.fixableErrorCount, fixableWarningCount: result.fixableWarningCount, })); } catch (error) { // If ESLint is not configured, return empty results if (error instanceof Error && error.message.includes('No ESLint configuration')) { return filePaths.map((file) => ({ file, messages: [], errorCount: 0, warningCount: 0, fixableErrorCount: 0, fixableWarningCount: 0, })); } throw error; } } /** * Fix linting issues automatically */ async fixLintIssues(filePaths: string[]): Promise<LintResult[]> { try { const eslint = new ESLint({ useEslintrc: true, fix: true, }); const results = await eslint.lintFiles(filePaths); await ESLint.outputFixes(results); return this.lintFiles(filePaths); } catch (error) { if (error instanceof Error && error.message.includes('No ESLint configuration')) { return filePaths.map((file) => ({ file, messages: [], errorCount: 0, warningCount: 0, fixableErrorCount: 0, fixableWarningCount: 0, })); } throw error; } } /** * Format code with Prettier */ async formatCode(filePath: string, options?: prettier.Options): Promise<FormatResult> { try { const content = readFileSync(filePath, 'utf-8'); const formatted = await prettier.format(content, { filepath: filePath, ...options, }); return { file: filePath, formatted: content !== formatted, original: content, formattedContent: formatted, }; } catch (error) { // If Prettier fails, return unformatted const content = readFileSync(filePath, 'utf-8'); return { file: filePath, formatted: false, original: content, formattedContent: content, }; } } /** * Check TypeScript syntax */ async checkTypeScript(_filePath: string): Promise<{ errors: Array<{ line: number; column: number; message: string; code: string }>; valid: boolean; }> { // This is a simplified version. In production, we'd use TypeScript compiler API // For now, return basic validation try { // Basic TypeScript syntax checks const errors: Array<{ line: number; column: number; message: string; code: string }> = []; // This is a simplified version. In production, we'd use TypeScript compiler API // For now, return empty errors array return { errors, valid: errors.length === 0, }; } catch (error) { return { errors: [ { line: 1, column: 1, message: error instanceof Error ? error.message : 'Unknown error', code: 'UNKNOWN', }, ], valid: false, }; } } /** * Validate syntax (basic) */ validateSyntax(code: string, language: string): { valid: boolean; errors: string[] } { const errors: string[] = []; if (language === 'javascript' || language === 'typescript') { // Basic bracket matching const openBracesCount = (code.match(/{/g) || []).length; const closeBracesCount = (code.match(/}/g) || []).length; if (openBracesCount !== closeBracesCount) { errors.push('Unmatched braces'); } const openParens = (code.match(/\(/g) || []).length; const closeParens = (code.match(/\)/g) || []).length; if (openParens !== closeParens) { errors.push('Unmatched parentheses'); } const openBrackets = (code.match(/\[/g) || []).length; const closeBrackets = (code.match(/\]/g) || []).length; if (openBrackets !== closeBrackets) { errors.push('Unmatched brackets'); } } return { valid: errors.length === 0, errors, }; } }

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/code-alchemist01/development-tools-mcp-Server'

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