Skip to main content
Glama
dependencies.js6.27 kB
import fs from 'fs/promises'; import path from 'path'; /** * Parse dependencies from various package manager files * @param {string} projectPath - Path to the project directory * @param {string[]} files - List of files in the project * @returns {Promise<{primary: string[], dev: string[], all: string[]}>} */ export async function parseDependencies(projectPath, files) { const result = { primary: [], dev: [], all: [] }; const fileSet = new Set(files.map(f => path.basename(f))); // Parse package.json (Node.js/TypeScript) if (fileSet.has('package.json')) { try { const pkgPath = path.join(projectPath, 'package.json'); const data = await fs.readFile(pkgPath, 'utf-8'); const pkg = JSON.parse(data); if (pkg.dependencies) { result.primary.push(...Object.keys(pkg.dependencies)); } if (pkg.devDependencies) { result.dev.push(...Object.keys(pkg.devDependencies)); } } catch { // Ignore parse errors } } // Parse requirements.txt (Python) if (fileSet.has('requirements.txt')) { try { const reqPath = path.join(projectPath, 'requirements.txt'); const data = await fs.readFile(reqPath, 'utf-8'); const deps = parseRequirementsTxt(data); result.primary.push(...deps); } catch { // Ignore parse errors } } // Parse pyproject.toml (Python - basic parsing) if (fileSet.has('pyproject.toml')) { try { const tomlPath = path.join(projectPath, 'pyproject.toml'); const data = await fs.readFile(tomlPath, 'utf-8'); const deps = parsePyprojectToml(data); result.primary.push(...deps); } catch { // Ignore parse errors } } // Parse composer.json (PHP) if (fileSet.has('composer.json')) { try { const composerPath = path.join(projectPath, 'composer.json'); const data = await fs.readFile(composerPath, 'utf-8'); const pkg = JSON.parse(data); if (pkg.require) { result.primary.push(...Object.keys(pkg.require).filter(k => k !== 'php')); } if (pkg['require-dev']) { result.dev.push(...Object.keys(pkg['require-dev'])); } } catch { // Ignore parse errors } } // Parse go.mod (Go) if (fileSet.has('go.mod')) { try { const goModPath = path.join(projectPath, 'go.mod'); const data = await fs.readFile(goModPath, 'utf-8'); const deps = parseGoMod(data); result.primary.push(...deps); } catch { // Ignore parse errors } } // Parse Cargo.toml (Rust - basic parsing) if (fileSet.has('Cargo.toml')) { try { const cargoPath = path.join(projectPath, 'Cargo.toml'); const data = await fs.readFile(cargoPath, 'utf-8'); const deps = parseCargoToml(data); result.primary.push(...deps); } catch { // Ignore parse errors } } // Deduplicate result.primary = [...new Set(result.primary)]; result.dev = [...new Set(result.dev)]; result.all = [...new Set([...result.primary, ...result.dev])]; return result; } /** * Parse requirements.txt format */ function parseRequirementsTxt(content) { const deps = []; const lines = content.split('\n'); for (const line of lines) { const trimmed = line.trim(); // Skip comments and empty lines if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('-')) { continue; } // Extract package name (before ==, >=, <=, ~=, etc.) const match = trimmed.match(/^([a-zA-Z0-9_-]+)/); if (match) { deps.push(match[1].toLowerCase()); } } return deps; } /** * Parse pyproject.toml dependencies (basic regex-based) */ function parsePyprojectToml(content) { const deps = []; // Match dependencies array in [project] or [tool.poetry.dependencies] const depsMatch = content.match(/dependencies\s*=\s*\[([\s\S]*?)\]/); if (depsMatch) { const depsBlock = depsMatch[1]; const packageMatches = depsBlock.matchAll(/"([a-zA-Z0-9_-]+)[\s\S]*?"/g); for (const match of packageMatches) { deps.push(match[1].toLowerCase()); } } // Also check poetry format const poetryMatch = content.match(/\[tool\.poetry\.dependencies\]([\s\S]*?)(\[|$)/); if (poetryMatch) { const block = poetryMatch[1]; const lines = block.split('\n'); for (const line of lines) { const match = line.match(/^([a-zA-Z0-9_-]+)\s*=/); if (match && match[1] !== 'python') { deps.push(match[1].toLowerCase()); } } } return deps; } /** * Parse go.mod require block */ function parseGoMod(content) { const deps = []; // Match single require statements const singleMatches = content.matchAll(/^require\s+(\S+)/gm); for (const match of singleMatches) { deps.push(match[1]); } // Match require block const blockMatch = content.match(/require\s*\(([\s\S]*?)\)/); if (blockMatch) { const lines = blockMatch[1].split('\n'); for (const line of lines) { const match = line.trim().match(/^(\S+)/); if (match && match[1] && !match[1].startsWith('//')) { deps.push(match[1]); } } } return deps; } /** * Parse Cargo.toml dependencies (basic regex-based) */ function parseCargoToml(content) { const deps = []; // Match [dependencies] section const depsMatch = content.match(/\[dependencies\]([\s\S]*?)(\[|$)/); if (depsMatch) { const block = depsMatch[1]; const lines = block.split('\n'); for (const line of lines) { const match = line.match(/^([a-zA-Z0-9_-]+)\s*=/); if (match) { deps.push(match[1]); } } } return deps; }

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/QoutaID/qoutaMcp'

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