what-is-my-tech-stack
Version:
Analyze project dependencies and generate a human-readable tech stack description
135 lines • 4.38 kB
JavaScript
import { FileReader } from '../utils/fileReader.js';
export class NodeAnalyzer {
packageJsonPath;
constructor(packageJsonPath) {
this.packageJsonPath = packageJsonPath;
}
/**
* Analyzes the package.json file and returns a list of dependencies
*/
async analyze() {
try {
const packageJson = await FileReader.readPackageJson(this.packageJsonPath);
const dependencies = [];
// Process regular dependencies
if (packageJson.dependencies) {
dependencies.push(...this.processDependencies(packageJson.dependencies, 'dependency'));
}
// Process dev dependencies
if (packageJson.devDependencies) {
dependencies.push(...this.processDependencies(packageJson.devDependencies, 'devDependency'));
}
return dependencies;
}
catch (error) {
process.stderr.write(`Error analyzing package.json: ${error.message}\n`);
return [];
}
}
/**
* Processes a dependency object and converts it to PackageDependency array
*/
processDependencies(deps, type) {
return Object.entries(deps).map(([name, version]) => ({
name,
version: this.normalizeVersion(version),
type,
}));
}
/**
* Normalizes version strings by removing special characters
*/
normalizeVersion(version) {
// Remove special characters like ^, ~, >, <, = and whitespace
return version.replace(/[\^~>=<\s]/g, '');
}
/**
* Categorizes dependencies into common tech categories
*/
categorizeDependencies(dependencies) {
const categories = {
framework: [],
testing: [],
bundler: [],
linter: [],
typescript: [],
utilities: [],
other: [],
};
dependencies.forEach((dep) => {
const name = dep.name.toLowerCase();
if (this.isFramework(name)) {
categories.framework.push(dep.name);
}
else if (this.isTestingTool(name)) {
categories.testing.push(dep.name);
}
else if (this.isBundler(name)) {
categories.bundler.push(dep.name);
}
else if (this.isLinter(name)) {
categories.linter.push(dep.name);
}
else if (this.isTypescript(name)) {
categories.typescript.push(dep.name);
}
else if (this.isUtility(name)) {
categories.utilities.push(dep.name);
}
else {
categories.other.push(dep.name);
}
});
// Remove empty categories
Object.keys(categories).forEach((key) => {
if (categories[key].length === 0) {
delete categories[key];
}
});
return categories;
}
isFramework(name) {
const frameworks = [
'react',
'vue',
'angular',
'next',
'nuxt',
'express',
'koa',
'fastify',
'nest',
];
return frameworks.some((framework) => name.includes(framework));
}
isTestingTool(name) {
const testingTools = [
'jest',
'mocha',
'chai',
'cypress',
'playwright',
'vitest',
'ava',
'karma',
];
return testingTools.some((tool) => name.includes(tool));
}
isBundler(name) {
const bundlers = ['webpack', 'rollup', 'parcel', 'vite', 'esbuild', 'babel'];
return bundlers.some((bundler) => name.includes(bundler));
}
isLinter(name) {
const linters = ['eslint', 'prettier', 'tslint', 'stylelint'];
return linters.some((linter) => name.includes(linter));
}
isTypescript(name) {
const typescript = ['typescript', '@types'];
return typescript.some((ts) => name.includes(ts));
}
isUtility(name) {
const utilities = ['lodash', 'moment', 'axios', 'chalk', 'commander', 'dotenv', 'uuid'];
return utilities.some((utility) => name.includes(utility));
}
}
//# sourceMappingURL=nodeAnalyzer.js.map