Skip to content

Commit 8a1d3cb

Browse files
authored
Merge pull request #38 from syncable-dev/develop
Develop
2 parents 373f4b3 + 5c1d289 commit 8a1d3cb

10 files changed

Lines changed: 4271 additions & 2157 deletions

File tree

README.md

Lines changed: 88 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,29 @@
66
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
77
![Crates.io Downloads](https://img.shields.io/crates/d/syncable-cli)
88

9+
## 🎯 **260+ Technologies Supported**
10+
**The most comprehensive project analyzer supporting 5 major languages and their complete ecosystems:**
11+
-**Java/JVM**: 98 technologies (13 Spring components + enterprise stack)
12+
- 🐍 **Python**: 76 technologies (Django, FastAPI, ML/Data Science)
13+
- 🟨 **JavaScript/TypeScript**: 46 technologies (React, Next.js, Node.js)
14+
- 🐹 **Go**: 21 technologies (cloud-native & microservices)
15+
- 🦀 **Rust**: 20 technologies (high-performance web & systems)
16+
17+
## 🌟 Help Other Developers Discover This Tool
18+
19+
**If this tool saves you time, please consider giving it a ⭐ on GitHub!**
20+
21+
Stars help other developers find Syncable CLI, and the more builders who discover it early, the better we can make it for everyone. Every star helps us reach developers who could benefit from automated infrastructure analysis and generation.
22+
23+
[**Star on GitHub**](https://github.com/syncable-dev/syncable-cli)
24+
25+
926
## ✨ Features
1027

1128
### 🔍 Comprehensive Project Analysis
12-
- **Language Detection**: Automatically detects JavaScript/TypeScript, Python, Rust, Go, Java/Kotlin
13-
- **Framework Recognition**: Identifies 70+ frameworks including Express, React, Django, FastAPI, Spring Boot
14-
- **Dependency Analysis**: Parses all package managers and extracts version constraints
29+
- **Language Detection**: Automatically detects JavaScript/TypeScript, Python, Rust, Go, Java/Kotlin with precise version detection
30+
- **Framework Recognition**: Identifies **260+ technologies** across all major ecosystems including complete Spring, Django, React, and Express families
31+
- **Dependency Analysis**: Parses all package managers (npm/yarn/pnpm, pip/poetry, cargo, go mod, maven/gradle) and extracts version constraints
1532
- **Vulnerability Scanning**: Integrates with security databases for each language ecosystem
1633
- **Security Analysis**: Basic secret detection and environment variable security checks
1734
- **Context Extraction**: Discovers entry points, ports, environment variables, and build scripts
@@ -277,28 +294,74 @@ max_file_size = 2097152 # 2MB
277294
format = "json" # or "yaml", "toml"
278295
```
279296

280-
## 🧪 Supported Technologies
281-
282-
### Languages & Runtimes
283-
- JavaScript/TypeScript (Node.js)
284-
- Python (3.7+)
285-
- Rust
286-
- Go
287-
- Java/Kotlin
288-
289-
### Frameworks (70+ supported)
290-
- **JavaScript**: Express, Next.js, React, Vue, Angular, Nest.js
291-
- **Python**: Django, Flask, FastAPI, Pyramid
292-
- **Rust**: Actix-web, Rocket, Axum, Warp
293-
- **Go**: Gin, Echo, Fiber, Chi
294-
- **Java**: Spring Boot, Micronaut, Quarkus
295-
296-
### Package Managers
297-
- npm, yarn, pnpm
298-
- pip, poetry, pipenv
299-
- cargo
300-
- go mod
301-
- maven, gradle
297+
## 🧪 Comprehensive Technology Support (260+ Technologies)
298+
299+
### 📊 Coverage by Language
300+
- **☕ Java/JVM**: **98 technologies** - The most comprehensive JVM ecosystem coverage
301+
- **🐍 Python**: **76 technologies** - Complete Python web, data, and ML stack
302+
- **🟨 JavaScript/TypeScript**: **46 technologies** - Full-stack web development ecosystem
303+
- **🐹 Go**: **21 technologies** - Modern cloud-native and microservices tools
304+
- **🦀 Rust**: **20 technologies** - High-performance systems and web frameworks
305+
306+
### 🌟 Major Ecosystem Coverage
307+
308+
#### **Java/JVM Ecosystem** (98 technologies)
309+
**Spring Family** (13 technologies):
310+
- Spring Boot, Spring Framework, Spring Security, Spring Data
311+
- Spring Cloud (Gateway, Config, Netflix), Spring WebFlux, Spring MVC
312+
- Spring Batch, Spring Integration, Spring AOP, and more
313+
314+
**Enterprise & Microservices**: Quarkus, Micronaut, Dropwizard, Jakarta EE
315+
**Database & ORM**: Hibernate, MyBatis, JPA, JDBI, MongoDB Driver, Redis Jedis
316+
**Message Brokers**: Apache Kafka, RabbitMQ, ActiveMQ, Apache Pulsar
317+
**Search & Big Data**: Elasticsearch, Apache Solr, Apache Spark, Apache Flink
318+
**Security**: Apache Shiro, Keycloak, Bouncy Castle, JWT, OAuth2
319+
**Build Tools**: Maven, Gradle, Ant
320+
**Testing**: JUnit, TestNG, Mockito, Selenium, Cucumber, Testcontainers
321+
**Web Servers**: Tomcat, Jetty, Undertow, Netty
322+
323+
#### 🐍 **Python Ecosystem** (76 technologies)
324+
**Web Frameworks**: Django, Flask, FastAPI, Pyramid, CherryPy, Tornado, Falcon
325+
**Django Family**: Django REST Framework, Django ORM, Django-allauth
326+
**Data & ML**: NumPy, Pandas, Scikit-learn, TensorFlow, PyTorch, Keras
327+
**Database & ORM**: SQLAlchemy, Alembic, psycopg2, PyMongo, Redis-py
328+
**Async & Messaging**: Celery, asyncio, aiohttp, Dramatiq
329+
**Scientific**: Matplotlib, Seaborn, Jupyter, SciPy
330+
**WSGI/ASGI Servers**: Gunicorn, Uvicorn, Hypercorn, Daphne, Waitress
331+
**Testing**: pytest, unittest, nose2, behave, Robot Framework
332+
333+
#### 🟨 **JavaScript/TypeScript Ecosystem** (46 technologies)
334+
**Meta-Frameworks**: Next.js, Nuxt.js, SvelteKit, Astro, SolidStart, Tanstack Start
335+
**Frontend**: React, Vue.js, Angular, Svelte, SolidJS
336+
**Mobile**: React Native, Expo
337+
**Backend**: Express.js, Nest.js, Fastify, Hono, Elysia
338+
**Database/ORM**: Prisma, Drizzle ORM, TypeORM, Mongoose, Sequelize
339+
**Build Tools**: Vite, Webpack, Rollup, Parcel
340+
**Runtimes**: Node.js, Bun, Deno, Cloudflare Workers, Vercel Edge
341+
**Testing**: Jest, Vitest, Cypress, Playwright
342+
343+
#### 🐹 **Go Ecosystem** (21 technologies)
344+
**Web Frameworks**: Gin, Echo, Fiber, Chi, Gorilla Mux, Beego
345+
**Microservices**: gRPC, go-kit, go-micro
346+
**Database**: GORM, sqlx, pgx
347+
**Cloud Native**: Kubernetes client, Docker, Consul
348+
**Testing**: Testify, Ginkgo, GoConvey
349+
350+
#### 🦀 **Rust Ecosystem** (20 technologies)
351+
**Web Frameworks**: Actix-web, Axum, Rocket, Warp, Tide
352+
**Async Runtimes**: Tokio, async-std
353+
**Database/ORM**: SeaORM, Diesel, SQLx
354+
**Serialization**: Serde
355+
**Testing**: Built-in test framework, criterion (benchmarking)
356+
357+
### 📦 **Package Manager Support**
358+
- **JavaScript**: npm, yarn, pnpm, bun
359+
- **Python**: pip, poetry, pipenv, conda, pdm
360+
- **Java**: Maven, Gradle
361+
- **Rust**: Cargo
362+
- **Go**: go mod
363+
- **PHP**: Composer
364+
- **Ruby**: Bundler
302365

303366
## 🤝 Contributing
304367

src/analyzer/display.rs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -234,40 +234,40 @@ impl BoxDrawer {
234234

235235
if total_needed <= available_space {
236236
// Everything fits - right-align the value
237-
let padding_needed = available_space - label_width - value_width;
237+
let padding_needed = available_space.saturating_sub(label_width).saturating_sub(value_width);
238238
format!("{}{}{}", formatted_label, " ".repeat(padding_needed), formatted_value)
239239
} else {
240240
// Need to truncate value
241241
let max_value_width = available_space.saturating_sub(label_width + min_space_between);
242242
let truncated_value = truncate_to_width(&formatted_value, max_value_width);
243243
let truncated_value_width = visual_width(&truncated_value);
244-
let padding_needed = available_space - label_width - truncated_value_width;
244+
let padding_needed = available_space.saturating_sub(label_width).saturating_sub(truncated_value_width);
245245
format!("{}{}{}", formatted_label, " ".repeat(padding_needed), truncated_value)
246246
}
247247
} else if !line.value.is_empty() {
248248
// Value only - left-align it (for descriptions, etc.)
249249
let value_width = visual_width(&formatted_value);
250250
if value_width <= content_width {
251-
let padding_needed = content_width - value_width;
251+
let padding_needed = content_width.saturating_sub(value_width);
252252
format!("{}{}", formatted_value, " ".repeat(padding_needed))
253253
} else {
254254
// Truncate and ensure it fills exactly content_width
255255
let truncated = truncate_to_width(&formatted_value, content_width);
256256
let actual_width = visual_width(&truncated);
257-
let padding_needed = content_width - actual_width;
257+
let padding_needed = content_width.saturating_sub(actual_width);
258258
format!("{}{}", truncated, " ".repeat(padding_needed))
259259
}
260260
} else if !line.label.is_empty() {
261261
// Label only - left-align it
262262
let label_width = visual_width(&formatted_label);
263263
if label_width <= content_width {
264-
let padding_needed = content_width - label_width;
264+
let padding_needed = content_width.saturating_sub(label_width);
265265
format!("{}{}", formatted_label, " ".repeat(padding_needed))
266266
} else {
267267
// Truncate and ensure it fills exactly content_width
268268
let truncated = truncate_to_width(&formatted_label, content_width);
269269
let actual_width = visual_width(&truncated);
270-
let padding_needed = content_width - actual_width;
270+
let padding_needed = content_width.saturating_sub(actual_width);
271271
format!("{}{}", truncated, " ".repeat(padding_needed))
272272
}
273273
} else {
@@ -285,7 +285,7 @@ impl BoxDrawer {
285285
content
286286
} else {
287287
// Add padding to reach exact width for non-table content
288-
let padding_needed = content_width - actual_content_width;
288+
let padding_needed = content_width.saturating_sub(actual_content_width);
289289
format!("{}{}", content, " ".repeat(padding_needed))
290290
}
291291
} else {
@@ -624,10 +624,10 @@ fn display_single_project_matrix(analysis: &MonorepoAnalysis) {
624624
box_drawer.add_line("Name:", &project.name.yellow(), true);
625625
box_drawer.add_line("Type:", &format_project_category(&project.project_category).green(), true);
626626

627-
// Languages with confidence
627+
// Languages
628628
if !project.analysis.languages.is_empty() {
629629
let lang_info = project.analysis.languages.iter()
630-
.map(|l| format!("{} ({:.0}%)", l.name, l.confidence * 100.0))
630+
.map(|l| l.name.clone())
631631
.collect::<Vec<_>>()
632632
.join(", ");
633633
box_drawer.add_line("Languages:", &lang_info.blue(), true);
@@ -669,10 +669,7 @@ fn add_technologies_to_drawer(technologies: &[DetectedTechnology], box_drawer: &
669669

670670
// Display primary technology first
671671
if let Some(primary) = technologies.iter().find(|t| t.is_primary) {
672-
let primary_info = format!("{} {}",
673-
primary.name.bright_yellow().bold(),
674-
format!("({:.0}%)", primary.confidence * 100.0).dimmed()
675-
);
672+
let primary_info = primary.name.bright_yellow().bold().to_string();
676673
box_drawer.add_line("Primary Stack:", &primary_info, true);
677674
}
678675

@@ -687,7 +684,7 @@ fn add_technologies_to_drawer(technologies: &[DetectedTechnology], box_drawer: &
687684
for (category, label) in &categories {
688685
if let Some(techs) = by_category.get(category) {
689686
let tech_names = techs.iter()
690-
.map(|t| format!("{} ({:.0}%)", t.name, t.confidence * 100.0))
687+
.map(|t| t.name.clone())
691688
.collect::<Vec<_>>()
692689
.join(", ");
693690

@@ -698,16 +695,40 @@ fn add_technologies_to_drawer(technologies: &[DetectedTechnology], box_drawer: &
698695
}
699696
}
700697

701-
// Handle Library category separately since it's parameterized
698+
// Handle Library category separately since it's parameterized - use vertical layout for many items
699+
let mut all_libraries: Vec<&DetectedTechnology> = Vec::new();
702700
for (cat, techs) in &by_category {
703701
if matches!(cat, TechnologyCategory::Library(_)) {
704-
let tech_names = techs.iter()
705-
.map(|t| format!("{} ({:.0}%)", t.name, t.confidence * 100.0))
702+
all_libraries.extend(techs.iter().copied());
703+
}
704+
}
705+
706+
if !all_libraries.is_empty() {
707+
// Sort libraries by confidence for better display
708+
all_libraries.sort_by(|a, b| b.confidence.partial_cmp(&a.confidence).unwrap_or(std::cmp::Ordering::Equal));
709+
710+
if all_libraries.len() <= 3 {
711+
// For few libraries, keep horizontal layout
712+
let tech_names = all_libraries.iter()
713+
.map(|t| t.name.clone())
706714
.collect::<Vec<_>>()
707715
.join(", ");
716+
box_drawer.add_line("Libraries:", &tech_names.magenta(), true);
717+
} else {
718+
// For many libraries, use vertical layout with multiple rows
719+
box_drawer.add_line("Libraries:", "", true);
708720

709-
if !tech_names.is_empty() {
710-
box_drawer.add_line("Libraries:", &tech_names.magenta(), true);
721+
// Group libraries into rows of 3-4 items each
722+
let items_per_row = 3;
723+
for chunk in all_libraries.chunks(items_per_row) {
724+
let row_items = chunk.iter()
725+
.map(|t| t.name.clone())
726+
.collect::<Vec<_>>()
727+
.join(", ");
728+
729+
// Add indented row
730+
let indented_row = format!(" {}", row_items);
731+
box_drawer.add_value_only(&indented_row.magenta());
711732
}
712733
}
713734
}

0 commit comments

Comments
 (0)