woaru
Version:
Universal Project Setup Autopilot - Analyze and automatically configure development tools for ANY programming language
218 lines (211 loc) • 8.44 kB
JavaScript
import axios from 'axios';
import fs from 'fs-extra';
import * as path from 'path';
export class ToolsUpdater {
npmRegistry = 'https://registry.npmjs.org';
githubApi = 'https://api.github.com';
updateInterval = 7 * 24 * 60 * 60 * 1000; // 7 days
async checkForUpdates(currentDb) {
const lastUpdate = new Date(currentDb.lastUpdated);
const now = new Date();
// Check if update is needed
if (now.getTime() - lastUpdate.getTime() < this.updateInterval) {
console.log('Database is up to date');
return false;
}
return true;
}
async updateToolStats(toolName, packageManager) {
try {
switch (packageManager) {
case 'npm':
return await this.getNpmStats(toolName);
case 'pypi':
return await this.getPyPiStats(toolName);
case 'nuget':
return await this.getNuGetStats(toolName);
default:
return null;
}
}
catch (error) {
console.error(`Failed to get stats for ${toolName}:`, error);
return null;
}
}
async getNpmStats(packageName) {
// Get package info
const packageInfo = await axios.get(`${this.npmRegistry}/${packageName}`);
const latest = packageInfo.data['dist-tags'].latest;
const packageData = packageInfo.data.versions[latest];
// Get download stats
const downloads = await axios.get(`https://api.npmjs.org/downloads/point/last-month/${packageName}`);
// Get GitHub stars if repository is listed
let stars = 0;
if (packageData.repository?.url) {
const repoUrl = packageData.repository.url;
const match = repoUrl.match(/github\.com\/([^/]+)\/([^/]+)/);
if (match) {
try {
const ghResponse = await axios.get(`${this.githubApi}/repos/${match[1]}/${match[2]}`, { headers: { Accept: 'application/vnd.github.v3+json' } });
stars = ghResponse.data.stargazers_count;
}
catch {
// GitHub API might be rate limited
}
}
}
return {
name: packageName,
downloads: downloads.data.downloads || 0,
stars,
lastUpdate: packageData.time || new Date().toISOString(),
deprecated: packageData.deprecated || false,
};
}
async getPyPiStats(packageName) {
const response = await axios.get(`https://pypi.org/pypi/${packageName}/json`);
const info = response.data.info;
// PyPI doesn't provide download stats in the API anymore
// We'd need to use BigQuery for accurate stats
return {
name: packageName,
downloads: 0, // Would need BigQuery
stars: 0, // Would need to parse home_page for GitHub
lastUpdate: response.data.releases[info.version]?.[0]?.upload_time ||
new Date().toISOString(),
};
}
async getNuGetStats(packageName) {
await axios.get(`https://api.nuget.org/v3-flatcontainer/${packageName.toLowerCase()}/index.json`);
return {
name: packageName,
downloads: 0, // Would need additional API call
stars: 0,
lastUpdate: new Date().toISOString(),
};
}
async findBetterAlternatives(toolName, _category) {
// This would query various sources to find alternatives
const alternatives = [];
// Known replacements
const knownReplacements = {
tslint: ['eslint', '@typescript-eslint/eslint-plugin'],
request: ['axios', 'node-fetch', 'got'],
moment: ['date-fns', 'dayjs'],
gulp: ['vite', 'webpack', 'rollup'],
bower: ['npm', 'yarn'],
coffeescript: ['typescript'],
'node-sass': ['sass', 'dart-sass'],
};
if (knownReplacements[toolName.toLowerCase()]) {
alternatives.push(...knownReplacements[toolName.toLowerCase()]);
}
return alternatives;
}
async generateUpdatedDatabase(currentDb) {
const updatedDb = JSON.parse(JSON.stringify(currentDb));
updatedDb.lastUpdated = new Date().toISOString().split('T')[0];
// Update tool stats for each category
for (const [categoryName, categoryTools] of Object.entries(updatedDb.categories)) {
for (const [toolName, toolConfig] of Object.entries(categoryTools)) {
// Get latest stats
const stats = await this.updateToolStats(toolName, 'npm');
if (stats) {
toolConfig.metadata = {
popularity: stats.downloads,
lastChecked: new Date().toISOString(),
githubStars: stats.stars,
deprecated: stats.deprecated,
alternatives: await this.findBetterAlternatives(toolName, categoryName),
};
// Mark deprecated tools
if (stats.deprecated) {
toolConfig.description = `[DEPRECATED] ${toolConfig.description || ''}`;
}
}
}
}
// Add new trending tools
await this.addTrendingTools(updatedDb);
return updatedDb;
}
async addTrendingTools(db) {
// This would query trending tools from various sources
// For now, let's add some known modern tools
// Add Biome (successor to Rome, alternative to ESLint+Prettier)
if (!('biome' in db.categories.linting)) {
db.categories.linting.biome = {
description: 'Fast formatter and linter for JavaScript, TypeScript, JSON, and more',
packages: ['@biomejs/biome'],
configs: {
default: ['@biomejs/biome'],
},
configFiles: ['biome.json'],
metadata: {
popularity: 50000,
lastChecked: new Date().toISOString(),
alternatives: [],
},
};
}
// Add Bun as alternative to Node.js
if (!('runtime' in db.categories)) {
db.categories.runtime =
{};
}
if (!('bun' in db.categories.runtime)) {
db.categories.runtime.bun = {
description: 'Fast all-in-one JavaScript runtime',
packages: [],
configs: {},
configFiles: ['bunfig.toml'],
metadata: {
popularity: 100000,
lastChecked: new Date().toISOString(),
alternatives: ['node', 'deno'],
},
};
}
}
async createUpdateScript() {
// Create a GitHub Action workflow for automatic updates
const workflow = `name: Update Tools Database
on:
schedule:
- cron: '0 0 * * 0' # Weekly on Sunday
workflow_dispatch:
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Update tools database
run: npm run update-tools-db
env:
GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5
with:
commit-message: 'chore: update tools database'
title: 'Update Tools Database'
body: |
Automated update of tools database with latest versions and statistics.
- Updated download statistics
- Checked for deprecated packages
- Added new trending tools
- Updated alternative recommendations
branch: update-tools-db
delete-branch: true
`;
const workflowPath = path.join(process.cwd(), '.github', 'workflows', 'update-tools.yml');
await fs.ensureDir(path.dirname(workflowPath));
await fs.writeFile(workflowPath, workflow);
}
}
//# sourceMappingURL=ToolsUpdater.js.map