ccshare
Version:
Share Claude Code prompts and results easily
343 lines • 13 kB
JavaScript
import fs from 'fs/promises';
import path from 'path';
export async function detectTechStack(projectPath) {
const techStack = {
languages: [],
frameworks: [],
tools: [],
databases: [],
versions: {},
dependencies: {}
};
// Check for various config files and detect tech stack
const filesToCheck = [
'package.json',
'Gemfile',
'requirements.txt',
'Cargo.toml',
'go.mod',
'pom.xml',
'build.gradle',
'composer.json',
'.gitignore',
'Dockerfile',
'docker-compose.yml'
];
for (const file of filesToCheck) {
try {
const filePath = path.join(projectPath, file);
const content = await fs.readFile(filePath, 'utf-8');
detectFromFile(file, content, techStack);
}
catch {
// File doesn't exist
}
}
// Check file extensions in src or root directory
try {
const files = await fs.readdir(projectPath);
await detectFromFileExtensions(files, techStack);
// Also check src directory if exists
try {
const srcFiles = await fs.readdir(path.join(projectPath, 'src'));
await detectFromFileExtensions(srcFiles, techStack);
}
catch { }
}
catch { }
// Helper function to capitalize tech stack items
const capitalizeItems = (items) => {
return items.map(item => {
// Special cases for known acronyms and proper names
const specialCases = {
'javascript': 'JavaScript',
'typescript': 'TypeScript',
'nodejs': 'Node.js',
'node': 'Node.js',
'nextjs': 'Next.js',
'vue': 'Vue',
'react': 'React',
'angular': 'Angular',
'express': 'Express',
'nestjs': 'NestJS',
'postgresql': 'PostgreSQL',
'mongodb': 'MongoDB',
'mysql': 'MySQL',
'redis': 'Redis',
'sqlite': 'SQLite',
'docker': 'Docker',
'docker-compose': 'Docker Compose',
'webpack': 'Webpack',
'vite': 'Vite',
'jest': 'Jest',
'mocha': 'Mocha',
'eslint': 'ESLint',
'pytest': 'pytest',
'numpy': 'NumPy',
'pandas': 'pandas',
'tensorflow': 'TensorFlow',
'pytorch': 'PyTorch',
'django': 'Django',
'flask': 'Flask',
'fastapi': 'FastAPI',
'rails': 'Rails',
'sinatra': 'Sinatra',
'spring': 'Spring',
'laravel': 'Laravel',
'symfony': 'Symfony',
'go': 'Go',
'rust': 'Rust',
'java': 'Java',
'python': 'Python',
'ruby': 'Ruby',
'php': 'PHP',
'csharp': 'C#',
'c++': 'C++',
'swift': 'Swift',
'kotlin': 'Kotlin',
'actix': 'Actix',
'rocket': 'Rocket',
'gin': 'Gin',
'fiber': 'Fiber',
'echo': 'Echo',
'tokio': 'Tokio',
'junit': 'JUnit',
'rspec': 'RSpec',
'gatsby': 'Gatsby',
'svelte': 'Svelte',
'nuxt': 'Nuxt'
};
// Check if we have a special case
if (specialCases[item.toLowerCase()]) {
return specialCases[item.toLowerCase()];
}
// Otherwise, capitalize first letter
return item.charAt(0).toUpperCase() + item.slice(1);
});
};
// Remove duplicates and capitalize before returning
return {
languages: capitalizeItems([...new Set(techStack.languages)]),
frameworks: capitalizeItems([...new Set(techStack.frameworks)]),
tools: capitalizeItems([...new Set(techStack.tools)]),
databases: capitalizeItems([...new Set(techStack.databases)]),
versions: techStack.versions,
dependencies: techStack.dependencies
};
}
function detectFromFile(filename, content, techStack) {
switch (filename) {
case 'package.json':
techStack.languages.push('javascript', 'node');
const pkg = JSON.parse(content);
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
// Store project version
if (pkg.version) {
techStack.versions['project'] = pkg.version;
}
// Store Node engine version
if (pkg.engines?.node) {
techStack.versions['node'] = pkg.engines.node;
}
// Frameworks with versions
if (deps.react) {
techStack.frameworks.push('react');
techStack.versions['react'] = deps.react;
}
if (deps.vue) {
techStack.frameworks.push('vue');
techStack.versions['vue'] = deps.vue;
}
if (deps.angular) {
techStack.frameworks.push('angular');
techStack.versions['angular'] = deps.angular;
}
if (deps.express) {
techStack.frameworks.push('express');
techStack.versions['express'] = deps.express;
}
if (deps.next) {
techStack.frameworks.push('nextjs');
techStack.versions['nextjs'] = deps.next;
}
if (deps.gatsby) {
techStack.frameworks.push('gatsby');
techStack.versions['gatsby'] = deps.gatsby;
}
if (deps.svelte) {
techStack.frameworks.push('svelte');
techStack.versions['svelte'] = deps.svelte;
}
if (deps.nuxt) {
techStack.frameworks.push('nuxt');
techStack.versions['nuxt'] = deps.nuxt;
}
if (deps.nestjs || deps['@nestjs/core']) {
techStack.frameworks.push('nestjs');
techStack.versions['nestjs'] = deps['@nestjs/core'] || deps.nestjs;
}
// Tools
if (deps.typescript) {
techStack.languages.push('typescript');
techStack.versions['typescript'] = deps.typescript;
}
if (deps.webpack)
techStack.tools.push('webpack');
if (deps.vite)
techStack.tools.push('vite');
if (deps.jest)
techStack.tools.push('jest');
if (deps.mocha)
techStack.tools.push('mocha');
if (deps.eslint)
techStack.tools.push('eslint');
// Databases
if (deps.mongodb || deps.mongoose)
techStack.databases.push('mongodb');
if (deps.mysql || deps.mysql2)
techStack.databases.push('mysql');
if (deps.pg || deps.postgres)
techStack.databases.push('postgresql');
if (deps.redis)
techStack.databases.push('redis');
if (deps.sqlite3)
techStack.databases.push('sqlite');
// Store key dependencies (limit to 20 most important)
const importantDeps = Object.entries(deps)
.filter(([name]) => !name.startsWith('@types/'))
.slice(0, 20);
for (const [name, version] of importantDeps) {
techStack.dependencies[name] = version;
}
break;
case 'Gemfile':
techStack.languages.push('ruby');
if (content.includes('rails'))
techStack.frameworks.push('rails');
if (content.includes('sinatra'))
techStack.frameworks.push('sinatra');
if (content.includes('rspec'))
techStack.tools.push('rspec');
if (content.includes('pg'))
techStack.databases.push('postgresql');
if (content.includes('mysql2'))
techStack.databases.push('mysql');
if (content.includes('redis'))
techStack.databases.push('redis');
break;
case 'requirements.txt':
techStack.languages.push('python');
if (content.includes('django'))
techStack.frameworks.push('django');
if (content.includes('flask'))
techStack.frameworks.push('flask');
if (content.includes('fastapi'))
techStack.frameworks.push('fastapi');
if (content.includes('pytest'))
techStack.tools.push('pytest');
if (content.includes('numpy'))
techStack.tools.push('numpy');
if (content.includes('pandas'))
techStack.tools.push('pandas');
if (content.includes('tensorflow'))
techStack.tools.push('tensorflow');
if (content.includes('torch'))
techStack.tools.push('pytorch');
break;
case 'Cargo.toml':
techStack.languages.push('rust');
if (content.includes('actix-web'))
techStack.frameworks.push('actix');
if (content.includes('rocket'))
techStack.frameworks.push('rocket');
if (content.includes('tokio'))
techStack.tools.push('tokio');
break;
case 'go.mod':
techStack.languages.push('go');
if (content.includes('gin-gonic/gin'))
techStack.frameworks.push('gin');
if (content.includes('fiber'))
techStack.frameworks.push('fiber');
if (content.includes('echo'))
techStack.frameworks.push('echo');
break;
case 'pom.xml':
techStack.languages.push('java');
if (content.includes('spring'))
techStack.frameworks.push('spring');
if (content.includes('junit'))
techStack.tools.push('junit');
break;
case 'build.gradle':
techStack.languages.push('java');
if (content.includes('kotlin'))
techStack.languages.push('kotlin');
if (content.includes('spring'))
techStack.frameworks.push('spring');
break;
case 'composer.json':
techStack.languages.push('php');
const composer = JSON.parse(content);
const phpDeps = { ...composer.require, ...composer['require-dev'] || {} };
if (phpDeps['laravel/framework'])
techStack.frameworks.push('laravel');
if (phpDeps['symfony/framework-bundle'])
techStack.frameworks.push('symfony');
break;
case 'Dockerfile':
techStack.tools.push('docker');
break;
case 'docker-compose.yml':
techStack.tools.push('docker', 'docker-compose');
if (content.includes('postgres'))
techStack.databases.push('postgresql');
if (content.includes('mysql'))
techStack.databases.push('mysql');
if (content.includes('mongo'))
techStack.databases.push('mongodb');
if (content.includes('redis'))
techStack.databases.push('redis');
break;
}
}
async function detectFromFileExtensions(files, techStack) {
const extensions = files.map(f => path.extname(f).toLowerCase());
if (extensions.includes('.js') || extensions.includes('.jsx')) {
techStack.languages.push('javascript');
}
if (extensions.includes('.ts') || extensions.includes('.tsx')) {
techStack.languages.push('typescript');
}
if (extensions.includes('.py')) {
techStack.languages.push('python');
}
if (extensions.includes('.rb')) {
techStack.languages.push('ruby');
}
if (extensions.includes('.java')) {
techStack.languages.push('java');
}
if (extensions.includes('.kt')) {
techStack.languages.push('kotlin');
}
if (extensions.includes('.go')) {
techStack.languages.push('go');
}
if (extensions.includes('.rs')) {
techStack.languages.push('rust');
}
if (extensions.includes('.php')) {
techStack.languages.push('php');
}
if (extensions.includes('.cs')) {
techStack.languages.push('csharp');
}
if (extensions.includes('.swift')) {
techStack.languages.push('swift');
}
if (extensions.includes('.cpp') || extensions.includes('.cc') || extensions.includes('.c')) {
techStack.languages.push('c++');
}
}
//# sourceMappingURL=tech-detector.js.map