Skip to main content
Glama
skillTechStack.test.ts11.1 kB
import { describe, expect, test } from 'vitest'; import type { ProcessedFile } from '../../../src/core/file/fileTypes.js'; import { detectTechStack, generateTechStackMd } from '../../../src/core/skill/skillTechStack.js'; describe('skillTechStack', () => { describe('detectTechStack', () => { test('should detect Node.js from package.json', () => { const files: ProcessedFile[] = [ { path: 'package.json', content: JSON.stringify({ dependencies: { react: '^18.2.0', express: '^4.18.0', }, devDependencies: { typescript: '^5.0.0', }, }), }, ]; const result = detectTechStack(files); expect(result).not.toBeNull(); expect(result?.languages).toContain('Node.js'); expect(result?.frameworks).toContain('React'); expect(result?.frameworks).toContain('Express'); expect(result?.frameworks).toContain('TypeScript'); expect(result?.dependencies.length).toBeGreaterThan(0); expect(result?.devDependencies.length).toBeGreaterThan(0); }); test('should detect Python from requirements.txt', () => { const files: ProcessedFile[] = [ { path: 'requirements.txt', content: `django==4.2.0 flask>=2.0.0 fastapi # comment -r base.txt`, }, ]; const result = detectTechStack(files); expect(result).not.toBeNull(); expect(result?.languages).toContain('Python'); expect(result?.frameworks).toContain('Django'); expect(result?.frameworks).toContain('Flask'); expect(result?.frameworks).toContain('FastAPI'); }); test('should detect Go from go.mod', () => { const files: ProcessedFile[] = [ { path: 'go.mod', content: `module example.com/myproject go 1.21 require ( github.com/gin-gonic/gin v1.9.0 github.com/stretchr/testify v1.8.0 )`, }, ]; const result = detectTechStack(files); expect(result).not.toBeNull(); expect(result?.languages).toContain('Go'); expect(result?.frameworks).toContain('Gin'); }); test('should detect Rust from Cargo.toml', () => { const files: ProcessedFile[] = [ { path: 'Cargo.toml', content: `[package] name = "myproject" version = "0.1.0" [dependencies] actix-web = "4.0" tokio = { version = "1.0", features = ["full"] }`, }, ]; const result = detectTechStack(files); expect(result).not.toBeNull(); expect(result?.languages).toContain('Rust'); expect(result?.frameworks).toContain('Actix'); expect(result?.frameworks).toContain('Tokio'); }); test('should return null when no dependency files found', () => { const files: ProcessedFile[] = [ { path: 'src/index.ts', content: 'console.log("hello")' }, { path: 'README.md', content: '# My Project' }, ]; const result = detectTechStack(files); expect(result).toBeNull(); }); test('should ignore dependency files in subdirectories', () => { const files: ProcessedFile[] = [ { path: 'packages/sub/package.json', content: JSON.stringify({ dependencies: { lodash: '4.0.0' } }), }, ]; const result = detectTechStack(files); expect(result).toBeNull(); }); test('should detect package manager from packageManager field', () => { const files: ProcessedFile[] = [ { path: 'package.json', content: JSON.stringify({ packageManager: 'pnpm@8.0.0', dependencies: {}, }), }, ]; const result = detectTechStack(files); expect(result?.packageManager).toBe('pnpm'); }); }); describe('generateTechStackMd', () => { test('should generate markdown with all sections', () => { const techStack = { languages: ['Node.js'], frameworks: ['React', 'TypeScript'], dependencies: [ { name: 'react', version: '^18.2.0' }, { name: 'react-dom', version: '^18.2.0' }, ], devDependencies: [{ name: 'typescript', version: '^5.0.0' }], packageManager: 'npm', runtimeVersions: [{ runtime: 'Node.js', version: '22.0.0' }], configFiles: ['package.json', 'tsconfig.json'], }; const result = generateTechStackMd(techStack); expect(result).toContain('# Tech Stack'); expect(result).toContain('## Languages'); expect(result).toContain('- Node.js'); expect(result).toContain('## Frameworks'); expect(result).toContain('- React'); expect(result).toContain('- TypeScript'); expect(result).toContain('## Runtime Versions'); expect(result).toContain('- Node.js: 22.0.0'); expect(result).toContain('## Package Manager'); expect(result).toContain('- npm'); expect(result).toContain('## Dependencies'); expect(result).toContain('- react (^18.2.0)'); expect(result).toContain('## Dev Dependencies'); expect(result).toContain('- typescript (^5.0.0)'); expect(result).toContain('## Configuration Files'); expect(result).toContain('- package.json'); expect(result).toContain('- tsconfig.json'); }); test('should show all dependencies without truncation', () => { const techStack = { languages: ['Node.js'], frameworks: [], dependencies: Array.from({ length: 25 }, (_, i) => ({ name: `dep-${i}`, version: '1.0.0' })), devDependencies: [], runtimeVersions: [], configFiles: [], }; const result = generateTechStackMd(techStack); expect(result).toContain('- dep-0 (1.0.0)'); expect(result).toContain('- dep-24 (1.0.0)'); expect(result).not.toContain('... and'); }); test('should handle empty sections', () => { const techStack = { languages: ['Node.js'], frameworks: [], dependencies: [], devDependencies: [], runtimeVersions: [], configFiles: [], }; const result = generateTechStackMd(techStack); expect(result).toContain('# Tech Stack'); expect(result).toContain('## Languages'); expect(result).not.toContain('## Frameworks'); expect(result).not.toContain('## Dependencies'); expect(result).not.toContain('## Configuration Files'); }); }); describe('detectTechStack with version files', () => { test('should detect Node.js version from .node-version', () => { const files: ProcessedFile[] = [{ path: '.node-version', content: '22.0.0\n' }]; const result = detectTechStack(files); expect(result).not.toBeNull(); expect(result?.runtimeVersions).toHaveLength(1); expect(result?.runtimeVersions[0]).toEqual({ runtime: 'Node.js', version: '22.0.0' }); }); test('should detect Node.js version from .nvmrc', () => { const files: ProcessedFile[] = [{ path: '.nvmrc', content: 'v20.10.0' }]; const result = detectTechStack(files); expect(result).not.toBeNull(); expect(result?.runtimeVersions).toHaveLength(1); expect(result?.runtimeVersions[0]).toEqual({ runtime: 'Node.js', version: 'v20.10.0' }); }); test('should detect multiple runtimes from .tool-versions', () => { const files: ProcessedFile[] = [ { path: '.tool-versions', content: `nodejs 22.0.0 python 3.12.0 ruby 3.3.0 # this is a comment golang 1.22.0`, }, ]; const result = detectTechStack(files); expect(result).not.toBeNull(); expect(result?.runtimeVersions).toHaveLength(4); expect(result?.runtimeVersions).toContainEqual({ runtime: 'Node.js', version: '22.0.0' }); expect(result?.runtimeVersions).toContainEqual({ runtime: 'Python', version: '3.12.0' }); expect(result?.runtimeVersions).toContainEqual({ runtime: 'Ruby', version: '3.3.0' }); expect(result?.runtimeVersions).toContainEqual({ runtime: 'Go', version: '1.22.0' }); }); test('should detect Python version from .python-version', () => { const files: ProcessedFile[] = [{ path: '.python-version', content: '3.11.5' }]; const result = detectTechStack(files); expect(result).not.toBeNull(); expect(result?.runtimeVersions).toHaveLength(1); expect(result?.runtimeVersions[0]).toEqual({ runtime: 'Python', version: '3.11.5' }); }); test('should combine dependency files and version files', () => { const files: ProcessedFile[] = [ { path: 'package.json', content: JSON.stringify({ dependencies: { express: '^4.18.0' } }), }, { path: '.node-version', content: '22.0.0' }, ]; const result = detectTechStack(files); expect(result).not.toBeNull(); expect(result?.languages).toContain('Node.js'); expect(result?.dependencies).toHaveLength(1); expect(result?.runtimeVersions).toHaveLength(1); expect(result?.runtimeVersions[0]).toEqual({ runtime: 'Node.js', version: '22.0.0' }); }); }); describe('detectTechStack with configuration files', () => { test('should detect configuration files at root level', () => { const files: ProcessedFile[] = [ { path: 'package.json', content: JSON.stringify({ dependencies: {} }) }, { path: 'tsconfig.json', content: '{}' }, { path: 'vitest.config.ts', content: 'export default {}' }, { path: '.eslintrc.json', content: '{}' }, { path: 'biome.json', content: '{}' }, ]; const result = detectTechStack(files); expect(result).not.toBeNull(); expect(result?.configFiles).toContain('package.json'); expect(result?.configFiles).toContain('tsconfig.json'); expect(result?.configFiles).toContain('vitest.config.ts'); expect(result?.configFiles).toContain('.eslintrc.json'); expect(result?.configFiles).toContain('biome.json'); }); test('should not detect configuration files in subdirectories', () => { const files: ProcessedFile[] = [ { path: 'package.json', content: JSON.stringify({ dependencies: {} }) }, { path: 'packages/sub/tsconfig.json', content: '{}' }, ]; const result = detectTechStack(files); expect(result).not.toBeNull(); expect(result?.configFiles).toContain('package.json'); expect(result?.configFiles).not.toContain('tsconfig.json'); }); test('should detect docker and CI configuration files', () => { const files: ProcessedFile[] = [ { path: 'Dockerfile', content: 'FROM node:22' }, { path: 'docker-compose.yml', content: 'version: 3' }, { path: '.gitignore', content: 'node_modules' }, ]; const result = detectTechStack(files); expect(result).not.toBeNull(); expect(result?.configFiles).toContain('Dockerfile'); expect(result?.configFiles).toContain('docker-compose.yml'); expect(result?.configFiles).toContain('.gitignore'); }); }); });

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