sourcecode 1.35.33__tar.gz → 1.35.34__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sourcecode-1.35.33 → sourcecode-1.35.34}/PKG-INFO +148 -8
- {sourcecode-1.35.33 → sourcecode-1.35.34}/README.md +147 -7
- {sourcecode-1.35.33 → sourcecode-1.35.34}/pyproject.toml +1 -1
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/__init__.py +1 -1
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/cli.py +72 -13
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/java.py +30 -1
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/prepare_context.py +1 -1
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/rename_refactor.py +15 -2
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/repository_ir.py +32 -7
- {sourcecode-1.35.33 → sourcecode-1.35.34}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/.gitignore +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/.ruff.toml +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/CHANGELOG.md +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/CONTRIBUTING.md +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/LICENSE +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/SECURITY.md +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/raw +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/cache.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/classifier.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/explain.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/flow_analyzer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/license.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/migrate_check.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/progress.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/redactor.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/ris.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/scanner.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/schema.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/serializer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/spring_findings.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/spring_impact.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/spring_security_audit.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/spring_tx_analyzer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-1.35.33 → sourcecode-1.35.34}/src/sourcecode/workspace.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 1.35.
|
|
3
|
+
Version: 1.35.34
|
|
4
4
|
Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Keywords: agents,ai,codebase,context,developer-tools,llm
|
|
@@ -114,9 +114,7 @@ pipx install sourcecode
|
|
|
114
114
|
|
|
115
115
|
```bash
|
|
116
116
|
sourcecode version
|
|
117
|
-
# sourcecode 1.35.
|
|
118
|
-
|
|
119
|
-
**v1.35.28** — 7 bug fixes: `rename-class` cross-package disambiguation (BUG-4), `rename-class` collision detection (BUG-2), `find_java_files` false positive on `com/test/` package paths (BUG-1), `cold-start --compact` correct key names (BUG-6), `@EnableMethodSecurity` no longer suppresses SEC-001 (BUG-3), `explain` @Entity stereotype detection (BUG-5), XML+annotation mixed security retagging (BUG-7).
|
|
117
|
+
# sourcecode 1.35.34
|
|
120
118
|
```
|
|
121
119
|
|
|
122
120
|
---
|
|
@@ -136,6 +134,9 @@ sourcecode --agent
|
|
|
136
134
|
# Blast radius: what breaks if this class changes?
|
|
137
135
|
sourcecode impact OrderService /path/to/repo
|
|
138
136
|
|
|
137
|
+
# Spring Boot 2→3 migration readiness: javax→jakarta blockers, removed APIs
|
|
138
|
+
sourcecode migrate-check /path/to/repo
|
|
139
|
+
|
|
139
140
|
# Spring semantic audit: TX anomalies + security surface (free)
|
|
140
141
|
sourcecode spring-audit /path/to/repo
|
|
141
142
|
|
|
@@ -180,6 +181,9 @@ sourcecode cache warm
|
|
|
180
181
|
|
|
181
182
|
# Clear cache
|
|
182
183
|
sourcecode cache clear
|
|
184
|
+
|
|
185
|
+
# Check RIS freshness relative to current git HEAD
|
|
186
|
+
sourcecode cache freshness
|
|
183
187
|
```
|
|
184
188
|
|
|
185
189
|
**`--no-cache`** bypasses both layers and forces a fresh scan. Use in CI or when you need to verify a fresh result.
|
|
@@ -337,9 +341,14 @@ Extracts all Spring MVC (`@GetMapping`, `@PostMapping`, `@RequestMapping`, etc.)
|
|
|
337
341
|
|
|
338
342
|
```bash
|
|
339
343
|
sourcecode spring-audit /path/to/repo
|
|
340
|
-
sourcecode spring-audit /path/to/repo --scope tx
|
|
344
|
+
sourcecode spring-audit /path/to/repo --scope tx # TX anomalies only
|
|
341
345
|
sourcecode spring-audit /path/to/repo --scope security # security surface only
|
|
342
346
|
sourcecode spring-audit /path/to/repo --min-severity high
|
|
347
|
+
|
|
348
|
+
# CI/CD gate: exit 1 on any finding
|
|
349
|
+
sourcecode spring-audit . --ci
|
|
350
|
+
sourcecode spring-audit . --ci --min-severity high # exit 1 only on high/critical
|
|
351
|
+
sourcecode spring-audit . --ci --format github-comment # Markdown output + exit 1
|
|
343
352
|
```
|
|
344
353
|
|
|
345
354
|
Detects structural Spring anomalies that survive code review and tests, but cause production failures:
|
|
@@ -406,20 +415,59 @@ sourcecode cold-start /path/to/repo --compact # ~10K token subset
|
|
|
406
415
|
|
|
407
416
|
Returns the Repository Intelligence Snapshot (RIS) instantly — zero re-analysis. The RIS is built by a prior warm cache pass and includes stacks, entry points, endpoint surface, and Spring semantic signals. Status field: `cold_start_ready` | `cold_start_stale` | `no_ris`.
|
|
408
417
|
|
|
409
|
-
Use `--compact` to get a ~10K token subset safe for direct LLM injection. Full snapshot
|
|
418
|
+
Use `--compact` to get a ~10K token subset safe for direct LLM injection. Full snapshot ranges from ~100K–200K tokens on medium repos — use `--output FILE` for local search tooling.
|
|
410
419
|
|
|
411
420
|
### `repo-ir` — symbol-level IR
|
|
412
421
|
|
|
413
422
|
```bash
|
|
414
|
-
sourcecode repo-ir /path/to/repo --summary-only
|
|
415
|
-
sourcecode repo-ir /path/to/repo --since HEAD~1
|
|
423
|
+
sourcecode repo-ir /path/to/repo --summary-only # ~20K tokens
|
|
424
|
+
sourcecode repo-ir /path/to/repo --since HEAD~1 # symbol-level diff
|
|
416
425
|
sourcecode repo-ir /path/to/repo --files src/.../OrderService.java
|
|
426
|
+
sourcecode repo-ir /path/to/repo --max-nodes 200 --max-edges 500 # limit graph size
|
|
427
|
+
sourcecode repo-ir /path/to/repo --output ir.json.gz --gzip # compressed output (~70-80% smaller)
|
|
428
|
+
sourcecode repo-ir /path/to/repo --include-tests # include test files
|
|
417
429
|
```
|
|
418
430
|
|
|
419
431
|
Builds a deterministic symbol graph: classes, methods, import/injection edges, Spring roles, subsystems.
|
|
420
432
|
|
|
433
|
+
**Size control flags:**
|
|
434
|
+
|
|
435
|
+
| Flag | Description |
|
|
436
|
+
|------|-------------|
|
|
437
|
+
| `--summary-only` | Omit full graph nodes/edges; keep analysis summary, impact, and change_set (<300KB typical) |
|
|
438
|
+
| `--max-nodes N` | Keep top N nodes by impact score |
|
|
439
|
+
| `--max-edges N` | Keep top N edges (priority: edges between kept nodes) |
|
|
440
|
+
| `--gzip` | Compress output with gzip. Requires `--output`. ~70–80% smaller. |
|
|
441
|
+
| `--force` | Bypass the 50K-token size guard and emit output anyway |
|
|
442
|
+
| `--include-tests` | Include test source files (excluded by default) |
|
|
443
|
+
|
|
421
444
|
**Size warning:** Without `--summary-only`, output can exceed 1MB for mid-size repos. Always use `--summary-only` unless you need the full graph for downstream tooling.
|
|
422
445
|
|
|
446
|
+
### `explain` — architectural summary for a class
|
|
447
|
+
|
|
448
|
+
```bash
|
|
449
|
+
sourcecode explain UserService
|
|
450
|
+
sourcecode explain OrderController /path/to/repo
|
|
451
|
+
sourcecode explain UserService --format json
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
Human-readable architectural summary derived entirely from static analysis: Spring stereotype, public methods, incoming callers, outgoing dependencies, events published/consumed, `@Transactional` boundaries, security constraints, and related REST endpoints. JAVA/SPRING ONLY.
|
|
455
|
+
|
|
456
|
+
### `pr-impact` — PR blast-radius report
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
sourcecode pr-impact --files changed_files.txt
|
|
460
|
+
sourcecode pr-impact /path/to/repo --files diff.txt --format json
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
Takes a file listing changed Java files (one path per line) and produces a consolidated report: modified classes, affected REST endpoints reachable through the call chain, direct callers of each changed class, event publishers/consumers triggered, `@Transactional` methods in changed classes, and a consolidated risk level (`CRITICAL` / `HIGH` / `MEDIUM` / `LOW`). JAVA/SPRING ONLY.
|
|
464
|
+
|
|
465
|
+
```bash
|
|
466
|
+
# Typical CI usage: pipe git diff to a file, then run
|
|
467
|
+
git diff --name-only main | grep '\.java$' > changed.txt
|
|
468
|
+
sourcecode pr-impact . --files changed.txt --format json
|
|
469
|
+
```
|
|
470
|
+
|
|
423
471
|
### `onboard` — codebase orientation
|
|
424
472
|
|
|
425
473
|
```bash
|
|
@@ -453,6 +501,98 @@ sourcecode modernize /path/to/repo
|
|
|
453
501
|
|
|
454
502
|
High-coupling nodes (high fan-in = risky to change), dead zone candidates (isolated symbols), subsystem tangles.
|
|
455
503
|
|
|
504
|
+
### `migrate-check` — Spring Boot 2→3 migration readiness
|
|
505
|
+
|
|
506
|
+
```bash
|
|
507
|
+
sourcecode migrate-check /path/to/repo
|
|
508
|
+
sourcecode migrate-check . --min-severity high
|
|
509
|
+
sourcecode migrate-check . --format text
|
|
510
|
+
sourcecode migrate-check . --output migration.json
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Detects migration blockers across Java source files, Spring XML config files, and Maven/Gradle build files. 27 rules organized by target:
|
|
514
|
+
|
|
515
|
+
**Jakarta namespace (MIG-001..009) — javax→jakarta**
|
|
516
|
+
|
|
517
|
+
| Rule | Severity | Pattern |
|
|
518
|
+
|------|----------|---------|
|
|
519
|
+
| `MIG-001` | critical | `javax.persistence` import — JPA will not compile |
|
|
520
|
+
| `MIG-002` | high | `javax.servlet` import — Servlet API changed |
|
|
521
|
+
| `MIG-003` | high | `javax.validation` import — Bean Validation changed |
|
|
522
|
+
| `MIG-004` | high | `javax.transaction` import — TX API changed |
|
|
523
|
+
| `MIG-006` | medium | `javax.annotation` import — CDI annotations changed |
|
|
524
|
+
| `MIG-007` | medium | `javax.inject` import — DI annotations changed |
|
|
525
|
+
| `MIG-008` | medium | `javax.ws.rs` import — JAX-RS changed |
|
|
526
|
+
| `MIG-009` | medium | `javax.jms` import — JMS API changed |
|
|
527
|
+
|
|
528
|
+
**Spring Security 6 (MIG-005, MIG-019, MIG-020)**
|
|
529
|
+
|
|
530
|
+
| Rule | Severity | Pattern |
|
|
531
|
+
|------|----------|---------|
|
|
532
|
+
| `MIG-005` | high | `extends WebSecurityConfigurerAdapter` — removed in Spring Security 6 |
|
|
533
|
+
| `MIG-019` | high | SpringFox / `@EnableSwagger2` — incompatible with Spring Boot 3 |
|
|
534
|
+
| `MIG-020` | high | `antMatchers()` / `authorizeRequests()` — replaced in Spring Security 6 |
|
|
535
|
+
|
|
536
|
+
**Java version compatibility (MIG-010..025)**
|
|
537
|
+
|
|
538
|
+
| Rule | Severity | Pattern |
|
|
539
|
+
|------|----------|---------|
|
|
540
|
+
| `MIG-010` | critical | `SecurityManager` / `AccessController` — removed in Java 17 (JEP 411) |
|
|
541
|
+
| `MIG-011` | high | `sun.*` / `com.sun.net.*` internal API imports — strong encapsulation since Java 9 |
|
|
542
|
+
| `MIG-012` | high | Nashorn `ScriptEngine` — removed in Java 15 |
|
|
543
|
+
| `MIG-013` | high | `sun.misc.Unsafe` — requires `--add-opens` on Java 9+ |
|
|
544
|
+
| `MIG-014` | medium | `setAccessible(true)` — may throw `InaccessibleObjectException` on Java 17+ |
|
|
545
|
+
| `MIG-015` | medium | `finalize()` override — deprecated for removal since Java 18 |
|
|
546
|
+
| `MIG-016` | low | `java.util.Date` / `Calendar` / `SimpleDateFormat` — use `java.time` |
|
|
547
|
+
| `MIG-021` | high | `javax.xml.bind` (JAXB) — removed from JDK in Java 11 |
|
|
548
|
+
| `MIG-022` | high | `javax.xml.ws` (JAX-WS) — removed from JDK in Java 11 |
|
|
549
|
+
| `MIG-023` | critical | `org.omg.*` / CORBA APIs — removed from JDK in Java 11 |
|
|
550
|
+
| `MIG-024` | medium | `Thread.stop()` / `Thread.suspend()` / `Thread.resume()` — deprecated for removal |
|
|
551
|
+
| `MIG-025` | medium | `ReflectionFactory` / `MethodHandles.privateLookupIn` — JPMS deep-reflection risk |
|
|
552
|
+
|
|
553
|
+
**Spring XML config (MIG-030..032)**
|
|
554
|
+
|
|
555
|
+
| Rule | Severity | Pattern |
|
|
556
|
+
|------|----------|---------|
|
|
557
|
+
| `MIG-030` | high | `javax.*` class reference in Spring XML bean definitions |
|
|
558
|
+
| `MIG-031` | high | `<http auto-config>` or versioned spring-security ≤5 schema in XML |
|
|
559
|
+
| `MIG-032` | high | `web.xml` with Servlet ≤4 namespace — must migrate to `jakarta.ee` |
|
|
560
|
+
|
|
561
|
+
**Build file dependencies (MIG-040..043)**
|
|
562
|
+
|
|
563
|
+
| Rule | Severity | Pattern |
|
|
564
|
+
|------|----------|---------|
|
|
565
|
+
| `MIG-040` | high | `io.springfox` dependency — incompatible with Spring Boot 3 |
|
|
566
|
+
| `MIG-041` | high | Hibernate 5.x explicitly pinned — Spring Boot 3 requires Hibernate 6 |
|
|
567
|
+
| `MIG-042` | medium | ByteBuddy < 1.12.x — may not support Java 17+ strong encapsulation |
|
|
568
|
+
| `MIG-043` | high | EhCache 2.x (`net.sf.ehcache`) — incompatible with Spring Boot 3 |
|
|
569
|
+
|
|
570
|
+
Each finding includes `severity`, `title`, `source_file`, `first_line`, `explanation`, `fix_hint`, `migration_target`, and `openrewrite_recipe` (when an automated recipe exists).
|
|
571
|
+
|
|
572
|
+
### `rename-class` — Java class rename
|
|
573
|
+
|
|
574
|
+
```bash
|
|
575
|
+
sourcecode rename-class . --from ServiceA --to ServiceB
|
|
576
|
+
sourcecode rename-class /path/to/repo --from OrderManager --to OrderService
|
|
577
|
+
sourcecode rename-class . --from OldName --to NewName --dry-run
|
|
578
|
+
sourcecode rename-class . --from OldName --to NewName --no-tests # src/main only
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
Renames a Java class safely throughout the repository: declaration, constructor, all import statements, type references (fields, params, return types), `extends`/`implements`, generics, casts, and Spring `@Qualifier` names. Renames the physical `.java` file. Emits a structured change audit trail (`file`, `before_lines`, `after_lines`, `intent`, `diff`).
|
|
582
|
+
|
|
583
|
+
Use `--dry-run` to preview changes without writing to disk.
|
|
584
|
+
|
|
585
|
+
### `chunk-file` — split large Java files for agent consumption
|
|
586
|
+
|
|
587
|
+
```bash
|
|
588
|
+
sourcecode chunk-file BigService.java
|
|
589
|
+
sourcecode chunk-file BigService.java --max-lines 300
|
|
590
|
+
sourcecode chunk-file BigService.java --chunk 5 # read chunk 5 only
|
|
591
|
+
sourcecode chunk-file BigService.java --metadata-only # boundaries only, no content
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
Splits a large Java file at method/class boundaries so AI agents can read files with 10K–25K+ lines in context-sized pieces. Each chunk includes `chunk_id`, `start_line`, `end_line`, `chunk_type`, symbol name, a `context_header` (package + class + imports summary), and `content`. A `size_warning` flag marks methods that exceed `--max-lines` and cannot be split further.
|
|
595
|
+
|
|
456
596
|
### `prepare-context` — task-specific context
|
|
457
597
|
|
|
458
598
|
Low-level access to all tasks with full options:
|
|
@@ -76,9 +76,7 @@ pipx install sourcecode
|
|
|
76
76
|
|
|
77
77
|
```bash
|
|
78
78
|
sourcecode version
|
|
79
|
-
# sourcecode 1.35.
|
|
80
|
-
|
|
81
|
-
**v1.35.28** — 7 bug fixes: `rename-class` cross-package disambiguation (BUG-4), `rename-class` collision detection (BUG-2), `find_java_files` false positive on `com/test/` package paths (BUG-1), `cold-start --compact` correct key names (BUG-6), `@EnableMethodSecurity` no longer suppresses SEC-001 (BUG-3), `explain` @Entity stereotype detection (BUG-5), XML+annotation mixed security retagging (BUG-7).
|
|
79
|
+
# sourcecode 1.35.34
|
|
82
80
|
```
|
|
83
81
|
|
|
84
82
|
---
|
|
@@ -98,6 +96,9 @@ sourcecode --agent
|
|
|
98
96
|
# Blast radius: what breaks if this class changes?
|
|
99
97
|
sourcecode impact OrderService /path/to/repo
|
|
100
98
|
|
|
99
|
+
# Spring Boot 2→3 migration readiness: javax→jakarta blockers, removed APIs
|
|
100
|
+
sourcecode migrate-check /path/to/repo
|
|
101
|
+
|
|
101
102
|
# Spring semantic audit: TX anomalies + security surface (free)
|
|
102
103
|
sourcecode spring-audit /path/to/repo
|
|
103
104
|
|
|
@@ -142,6 +143,9 @@ sourcecode cache warm
|
|
|
142
143
|
|
|
143
144
|
# Clear cache
|
|
144
145
|
sourcecode cache clear
|
|
146
|
+
|
|
147
|
+
# Check RIS freshness relative to current git HEAD
|
|
148
|
+
sourcecode cache freshness
|
|
145
149
|
```
|
|
146
150
|
|
|
147
151
|
**`--no-cache`** bypasses both layers and forces a fresh scan. Use in CI or when you need to verify a fresh result.
|
|
@@ -299,9 +303,14 @@ Extracts all Spring MVC (`@GetMapping`, `@PostMapping`, `@RequestMapping`, etc.)
|
|
|
299
303
|
|
|
300
304
|
```bash
|
|
301
305
|
sourcecode spring-audit /path/to/repo
|
|
302
|
-
sourcecode spring-audit /path/to/repo --scope tx
|
|
306
|
+
sourcecode spring-audit /path/to/repo --scope tx # TX anomalies only
|
|
303
307
|
sourcecode spring-audit /path/to/repo --scope security # security surface only
|
|
304
308
|
sourcecode spring-audit /path/to/repo --min-severity high
|
|
309
|
+
|
|
310
|
+
# CI/CD gate: exit 1 on any finding
|
|
311
|
+
sourcecode spring-audit . --ci
|
|
312
|
+
sourcecode spring-audit . --ci --min-severity high # exit 1 only on high/critical
|
|
313
|
+
sourcecode spring-audit . --ci --format github-comment # Markdown output + exit 1
|
|
305
314
|
```
|
|
306
315
|
|
|
307
316
|
Detects structural Spring anomalies that survive code review and tests, but cause production failures:
|
|
@@ -368,20 +377,59 @@ sourcecode cold-start /path/to/repo --compact # ~10K token subset
|
|
|
368
377
|
|
|
369
378
|
Returns the Repository Intelligence Snapshot (RIS) instantly — zero re-analysis. The RIS is built by a prior warm cache pass and includes stacks, entry points, endpoint surface, and Spring semantic signals. Status field: `cold_start_ready` | `cold_start_stale` | `no_ris`.
|
|
370
379
|
|
|
371
|
-
Use `--compact` to get a ~10K token subset safe for direct LLM injection. Full snapshot
|
|
380
|
+
Use `--compact` to get a ~10K token subset safe for direct LLM injection. Full snapshot ranges from ~100K–200K tokens on medium repos — use `--output FILE` for local search tooling.
|
|
372
381
|
|
|
373
382
|
### `repo-ir` — symbol-level IR
|
|
374
383
|
|
|
375
384
|
```bash
|
|
376
|
-
sourcecode repo-ir /path/to/repo --summary-only
|
|
377
|
-
sourcecode repo-ir /path/to/repo --since HEAD~1
|
|
385
|
+
sourcecode repo-ir /path/to/repo --summary-only # ~20K tokens
|
|
386
|
+
sourcecode repo-ir /path/to/repo --since HEAD~1 # symbol-level diff
|
|
378
387
|
sourcecode repo-ir /path/to/repo --files src/.../OrderService.java
|
|
388
|
+
sourcecode repo-ir /path/to/repo --max-nodes 200 --max-edges 500 # limit graph size
|
|
389
|
+
sourcecode repo-ir /path/to/repo --output ir.json.gz --gzip # compressed output (~70-80% smaller)
|
|
390
|
+
sourcecode repo-ir /path/to/repo --include-tests # include test files
|
|
379
391
|
```
|
|
380
392
|
|
|
381
393
|
Builds a deterministic symbol graph: classes, methods, import/injection edges, Spring roles, subsystems.
|
|
382
394
|
|
|
395
|
+
**Size control flags:**
|
|
396
|
+
|
|
397
|
+
| Flag | Description |
|
|
398
|
+
|------|-------------|
|
|
399
|
+
| `--summary-only` | Omit full graph nodes/edges; keep analysis summary, impact, and change_set (<300KB typical) |
|
|
400
|
+
| `--max-nodes N` | Keep top N nodes by impact score |
|
|
401
|
+
| `--max-edges N` | Keep top N edges (priority: edges between kept nodes) |
|
|
402
|
+
| `--gzip` | Compress output with gzip. Requires `--output`. ~70–80% smaller. |
|
|
403
|
+
| `--force` | Bypass the 50K-token size guard and emit output anyway |
|
|
404
|
+
| `--include-tests` | Include test source files (excluded by default) |
|
|
405
|
+
|
|
383
406
|
**Size warning:** Without `--summary-only`, output can exceed 1MB for mid-size repos. Always use `--summary-only` unless you need the full graph for downstream tooling.
|
|
384
407
|
|
|
408
|
+
### `explain` — architectural summary for a class
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
sourcecode explain UserService
|
|
412
|
+
sourcecode explain OrderController /path/to/repo
|
|
413
|
+
sourcecode explain UserService --format json
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
Human-readable architectural summary derived entirely from static analysis: Spring stereotype, public methods, incoming callers, outgoing dependencies, events published/consumed, `@Transactional` boundaries, security constraints, and related REST endpoints. JAVA/SPRING ONLY.
|
|
417
|
+
|
|
418
|
+
### `pr-impact` — PR blast-radius report
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
sourcecode pr-impact --files changed_files.txt
|
|
422
|
+
sourcecode pr-impact /path/to/repo --files diff.txt --format json
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
Takes a file listing changed Java files (one path per line) and produces a consolidated report: modified classes, affected REST endpoints reachable through the call chain, direct callers of each changed class, event publishers/consumers triggered, `@Transactional` methods in changed classes, and a consolidated risk level (`CRITICAL` / `HIGH` / `MEDIUM` / `LOW`). JAVA/SPRING ONLY.
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
# Typical CI usage: pipe git diff to a file, then run
|
|
429
|
+
git diff --name-only main | grep '\.java$' > changed.txt
|
|
430
|
+
sourcecode pr-impact . --files changed.txt --format json
|
|
431
|
+
```
|
|
432
|
+
|
|
385
433
|
### `onboard` — codebase orientation
|
|
386
434
|
|
|
387
435
|
```bash
|
|
@@ -415,6 +463,98 @@ sourcecode modernize /path/to/repo
|
|
|
415
463
|
|
|
416
464
|
High-coupling nodes (high fan-in = risky to change), dead zone candidates (isolated symbols), subsystem tangles.
|
|
417
465
|
|
|
466
|
+
### `migrate-check` — Spring Boot 2→3 migration readiness
|
|
467
|
+
|
|
468
|
+
```bash
|
|
469
|
+
sourcecode migrate-check /path/to/repo
|
|
470
|
+
sourcecode migrate-check . --min-severity high
|
|
471
|
+
sourcecode migrate-check . --format text
|
|
472
|
+
sourcecode migrate-check . --output migration.json
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
Detects migration blockers across Java source files, Spring XML config files, and Maven/Gradle build files. 27 rules organized by target:
|
|
476
|
+
|
|
477
|
+
**Jakarta namespace (MIG-001..009) — javax→jakarta**
|
|
478
|
+
|
|
479
|
+
| Rule | Severity | Pattern |
|
|
480
|
+
|------|----------|---------|
|
|
481
|
+
| `MIG-001` | critical | `javax.persistence` import — JPA will not compile |
|
|
482
|
+
| `MIG-002` | high | `javax.servlet` import — Servlet API changed |
|
|
483
|
+
| `MIG-003` | high | `javax.validation` import — Bean Validation changed |
|
|
484
|
+
| `MIG-004` | high | `javax.transaction` import — TX API changed |
|
|
485
|
+
| `MIG-006` | medium | `javax.annotation` import — CDI annotations changed |
|
|
486
|
+
| `MIG-007` | medium | `javax.inject` import — DI annotations changed |
|
|
487
|
+
| `MIG-008` | medium | `javax.ws.rs` import — JAX-RS changed |
|
|
488
|
+
| `MIG-009` | medium | `javax.jms` import — JMS API changed |
|
|
489
|
+
|
|
490
|
+
**Spring Security 6 (MIG-005, MIG-019, MIG-020)**
|
|
491
|
+
|
|
492
|
+
| Rule | Severity | Pattern |
|
|
493
|
+
|------|----------|---------|
|
|
494
|
+
| `MIG-005` | high | `extends WebSecurityConfigurerAdapter` — removed in Spring Security 6 |
|
|
495
|
+
| `MIG-019` | high | SpringFox / `@EnableSwagger2` — incompatible with Spring Boot 3 |
|
|
496
|
+
| `MIG-020` | high | `antMatchers()` / `authorizeRequests()` — replaced in Spring Security 6 |
|
|
497
|
+
|
|
498
|
+
**Java version compatibility (MIG-010..025)**
|
|
499
|
+
|
|
500
|
+
| Rule | Severity | Pattern |
|
|
501
|
+
|------|----------|---------|
|
|
502
|
+
| `MIG-010` | critical | `SecurityManager` / `AccessController` — removed in Java 17 (JEP 411) |
|
|
503
|
+
| `MIG-011` | high | `sun.*` / `com.sun.net.*` internal API imports — strong encapsulation since Java 9 |
|
|
504
|
+
| `MIG-012` | high | Nashorn `ScriptEngine` — removed in Java 15 |
|
|
505
|
+
| `MIG-013` | high | `sun.misc.Unsafe` — requires `--add-opens` on Java 9+ |
|
|
506
|
+
| `MIG-014` | medium | `setAccessible(true)` — may throw `InaccessibleObjectException` on Java 17+ |
|
|
507
|
+
| `MIG-015` | medium | `finalize()` override — deprecated for removal since Java 18 |
|
|
508
|
+
| `MIG-016` | low | `java.util.Date` / `Calendar` / `SimpleDateFormat` — use `java.time` |
|
|
509
|
+
| `MIG-021` | high | `javax.xml.bind` (JAXB) — removed from JDK in Java 11 |
|
|
510
|
+
| `MIG-022` | high | `javax.xml.ws` (JAX-WS) — removed from JDK in Java 11 |
|
|
511
|
+
| `MIG-023` | critical | `org.omg.*` / CORBA APIs — removed from JDK in Java 11 |
|
|
512
|
+
| `MIG-024` | medium | `Thread.stop()` / `Thread.suspend()` / `Thread.resume()` — deprecated for removal |
|
|
513
|
+
| `MIG-025` | medium | `ReflectionFactory` / `MethodHandles.privateLookupIn` — JPMS deep-reflection risk |
|
|
514
|
+
|
|
515
|
+
**Spring XML config (MIG-030..032)**
|
|
516
|
+
|
|
517
|
+
| Rule | Severity | Pattern |
|
|
518
|
+
|------|----------|---------|
|
|
519
|
+
| `MIG-030` | high | `javax.*` class reference in Spring XML bean definitions |
|
|
520
|
+
| `MIG-031` | high | `<http auto-config>` or versioned spring-security ≤5 schema in XML |
|
|
521
|
+
| `MIG-032` | high | `web.xml` with Servlet ≤4 namespace — must migrate to `jakarta.ee` |
|
|
522
|
+
|
|
523
|
+
**Build file dependencies (MIG-040..043)**
|
|
524
|
+
|
|
525
|
+
| Rule | Severity | Pattern |
|
|
526
|
+
|------|----------|---------|
|
|
527
|
+
| `MIG-040` | high | `io.springfox` dependency — incompatible with Spring Boot 3 |
|
|
528
|
+
| `MIG-041` | high | Hibernate 5.x explicitly pinned — Spring Boot 3 requires Hibernate 6 |
|
|
529
|
+
| `MIG-042` | medium | ByteBuddy < 1.12.x — may not support Java 17+ strong encapsulation |
|
|
530
|
+
| `MIG-043` | high | EhCache 2.x (`net.sf.ehcache`) — incompatible with Spring Boot 3 |
|
|
531
|
+
|
|
532
|
+
Each finding includes `severity`, `title`, `source_file`, `first_line`, `explanation`, `fix_hint`, `migration_target`, and `openrewrite_recipe` (when an automated recipe exists).
|
|
533
|
+
|
|
534
|
+
### `rename-class` — Java class rename
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
sourcecode rename-class . --from ServiceA --to ServiceB
|
|
538
|
+
sourcecode rename-class /path/to/repo --from OrderManager --to OrderService
|
|
539
|
+
sourcecode rename-class . --from OldName --to NewName --dry-run
|
|
540
|
+
sourcecode rename-class . --from OldName --to NewName --no-tests # src/main only
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
Renames a Java class safely throughout the repository: declaration, constructor, all import statements, type references (fields, params, return types), `extends`/`implements`, generics, casts, and Spring `@Qualifier` names. Renames the physical `.java` file. Emits a structured change audit trail (`file`, `before_lines`, `after_lines`, `intent`, `diff`).
|
|
544
|
+
|
|
545
|
+
Use `--dry-run` to preview changes without writing to disk.
|
|
546
|
+
|
|
547
|
+
### `chunk-file` — split large Java files for agent consumption
|
|
548
|
+
|
|
549
|
+
```bash
|
|
550
|
+
sourcecode chunk-file BigService.java
|
|
551
|
+
sourcecode chunk-file BigService.java --max-lines 300
|
|
552
|
+
sourcecode chunk-file BigService.java --chunk 5 # read chunk 5 only
|
|
553
|
+
sourcecode chunk-file BigService.java --metadata-only # boundaries only, no content
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
Splits a large Java file at method/class boundaries so AI agents can read files with 10K–25K+ lines in context-sized pieces. Each chunk includes `chunk_id`, `start_line`, `end_line`, `chunk_type`, symbol name, a `context_header` (package + class + imports summary), and `content`. A `size_warning` flag marks methods that exceed `--max-lines` and cannot be split further.
|
|
557
|
+
|
|
418
558
|
### `prepare-context` — task-specific context
|
|
419
559
|
|
|
420
560
|
Low-level access to all tasks with full options:
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sourcecode"
|
|
7
|
-
version = "1.35.
|
|
7
|
+
version = "1.35.34"
|
|
8
8
|
description = "Persistent structural context and ultra-fast repeated analysis for AI coding agents"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -3466,21 +3466,34 @@ def repo_ir_cmd(
|
|
|
3466
3466
|
_ir_tokens_est = _ir_size // 4
|
|
3467
3467
|
# P1-C: abort when estimated tokens > 50K unless --force or --output is given.
|
|
3468
3468
|
if _ir_tokens_est > 50_000 and not force:
|
|
3469
|
+
if summary_only:
|
|
3470
|
+
_hint = (
|
|
3471
|
+
"Use --max-nodes N --max-edges N to cap graph size, "
|
|
3472
|
+
"--output FILE to save to disk, or --force to bypass this guard."
|
|
3473
|
+
)
|
|
3474
|
+
else:
|
|
3475
|
+
_hint = (
|
|
3476
|
+
"Use --summary-only (~5K tokens), --max-nodes N --max-edges N, "
|
|
3477
|
+
"--output FILE to save to disk, or --force to bypass this guard."
|
|
3478
|
+
)
|
|
3469
3479
|
_emit_error_json(
|
|
3470
3480
|
"OUTPUT_TOO_LARGE",
|
|
3471
3481
|
f"Estimated output is ~{_ir_tokens_est // 1000}K tokens — too large for most LLM context windows.",
|
|
3472
|
-
hint=
|
|
3473
|
-
"Use --summary-only (~5K tokens), --max-nodes N --max-edges N, "
|
|
3474
|
-
"--output FILE to save to disk, or --force to bypass this guard."
|
|
3475
|
-
),
|
|
3482
|
+
hint=_hint,
|
|
3476
3483
|
expected="Output under 50K estimated tokens.",
|
|
3477
3484
|
)
|
|
3478
3485
|
raise typer.Exit(1)
|
|
3479
3486
|
if _ir_tokens_est > 10_000:
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3487
|
+
if summary_only:
|
|
3488
|
+
sys.stderr.write(
|
|
3489
|
+
f"[repo-ir] ~{_ir_tokens_est // 1000}K tokens — "
|
|
3490
|
+
"use --max-nodes N --max-edges N or --output FILE for smaller output.\n"
|
|
3491
|
+
)
|
|
3492
|
+
else:
|
|
3493
|
+
sys.stderr.write(
|
|
3494
|
+
f"[repo-ir] ~{_ir_tokens_est // 1000}K tokens — "
|
|
3495
|
+
"use --summary-only or --output FILE for smaller output.\n"
|
|
3496
|
+
)
|
|
3484
3497
|
sys.stderr.flush()
|
|
3485
3498
|
try:
|
|
3486
3499
|
sys.stdout.buffer.write(output.encode("utf-8"))
|
|
@@ -3590,6 +3603,15 @@ def impact_cmd(
|
|
|
3590
3603
|
sys.stderr.flush()
|
|
3591
3604
|
target, path = str(path), _target_as_path
|
|
3592
3605
|
|
|
3606
|
+
if not target.strip():
|
|
3607
|
+
_emit_error_json(
|
|
3608
|
+
INVALID_INPUT_CODE,
|
|
3609
|
+
"Class name must not be empty.",
|
|
3610
|
+
hint="Pass a class name or FQN. Example: sourcecode impact OrderService .",
|
|
3611
|
+
expected="A non-empty class name or FQN.",
|
|
3612
|
+
)
|
|
3613
|
+
raise typer.Exit(1)
|
|
3614
|
+
|
|
3593
3615
|
root = path.resolve()
|
|
3594
3616
|
if not root.is_dir():
|
|
3595
3617
|
_emit_error_json(
|
|
@@ -3718,6 +3740,15 @@ def endpoints_cmd(
|
|
|
3718
3740
|
sourcecode endpoints . --controller LiquidacionJornada
|
|
3719
3741
|
sourcecode endpoints . --limit 10
|
|
3720
3742
|
"""
|
|
3743
|
+
if format not in ("json", "yaml"):
|
|
3744
|
+
_emit_error_json(
|
|
3745
|
+
INVALID_INPUT_CODE,
|
|
3746
|
+
f"Invalid format '{format}'.",
|
|
3747
|
+
hint="format must be: json or yaml.",
|
|
3748
|
+
expected="json | yaml",
|
|
3749
|
+
)
|
|
3750
|
+
raise typer.Exit(code=1)
|
|
3751
|
+
|
|
3721
3752
|
target = path.resolve()
|
|
3722
3753
|
if not target.exists() or not target.is_dir():
|
|
3723
3754
|
_emit_error_json(
|
|
@@ -4258,6 +4289,15 @@ def impact_chain_cmd(
|
|
|
4258
4289
|
from sourcecode.spring_impact import run_impact_chain
|
|
4259
4290
|
from sourcecode.spring_findings import SpringAuditResult
|
|
4260
4291
|
|
|
4292
|
+
if not symbol.strip():
|
|
4293
|
+
_emit_error_json(
|
|
4294
|
+
INVALID_INPUT_CODE,
|
|
4295
|
+
"Symbol name must not be empty.",
|
|
4296
|
+
hint="Pass a class name or FQN. Example: sourcecode impact-chain OrderService .",
|
|
4297
|
+
expected="A non-empty class name or FQN.",
|
|
4298
|
+
)
|
|
4299
|
+
raise typer.Exit(code=1)
|
|
4300
|
+
|
|
4261
4301
|
_VALID_TYPES = ("impact", "events")
|
|
4262
4302
|
if query_type not in _VALID_TYPES:
|
|
4263
4303
|
_emit_error_json(
|
|
@@ -4427,10 +4467,10 @@ def pr_impact_cmd(
|
|
|
4427
4467
|
)
|
|
4428
4468
|
raise typer.Exit(code=1)
|
|
4429
4469
|
|
|
4430
|
-
if not files.exists():
|
|
4470
|
+
if not files.exists() or files.is_dir():
|
|
4431
4471
|
_emit_error_json(
|
|
4432
4472
|
INVALID_INPUT_CODE,
|
|
4433
|
-
f"--files '{files}' does not exist. Expected a text file listing changed file paths (one per line)
|
|
4473
|
+
f"--files '{files}' does not exist or is a directory. Expected a text file listing changed file paths (one per line).",
|
|
4434
4474
|
path=str(files),
|
|
4435
4475
|
hint=(
|
|
4436
4476
|
"Create a file with one changed Java file path per line, then pass it with --files. "
|
|
@@ -4568,6 +4608,15 @@ def explain_cmd(
|
|
|
4568
4608
|
from sourcecode.spring_model import SpringSemanticModel
|
|
4569
4609
|
from sourcecode.explain import explain_class
|
|
4570
4610
|
|
|
4611
|
+
if not class_name.strip():
|
|
4612
|
+
_emit_error_json(
|
|
4613
|
+
INVALID_INPUT_CODE,
|
|
4614
|
+
"Class name must not be empty.",
|
|
4615
|
+
hint="Pass a class name. Example: sourcecode explain UserService .",
|
|
4616
|
+
expected="A non-empty class name.",
|
|
4617
|
+
)
|
|
4618
|
+
raise typer.Exit(code=1)
|
|
4619
|
+
|
|
4571
4620
|
target = path.resolve()
|
|
4572
4621
|
if not target.exists() or not target.is_dir():
|
|
4573
4622
|
_emit_error_json(
|
|
@@ -5122,7 +5171,7 @@ def rename_class_cmd(
|
|
|
5122
5171
|
help="Output format: json (default) or yaml.",
|
|
5123
5172
|
),
|
|
5124
5173
|
) -> None:
|
|
5125
|
-
"""Rename a Java class throughout the repository
|
|
5174
|
+
"""Rename a Java class throughout the repository.
|
|
5126
5175
|
|
|
5127
5176
|
\b
|
|
5128
5177
|
Renames a Java class safely:
|
|
@@ -5133,7 +5182,7 @@ def rename_class_cmd(
|
|
|
5133
5182
|
- Updates extends / implements
|
|
5134
5183
|
- Updates generics, casts, Spring @Qualifier names
|
|
5135
5184
|
- Renames the physical .java file
|
|
5136
|
-
- Emits a structured change audit trail
|
|
5185
|
+
- Emits a structured change audit trail
|
|
5137
5186
|
|
|
5138
5187
|
\b
|
|
5139
5188
|
Examples:
|
|
@@ -5244,7 +5293,7 @@ def chunk_file_cmd(
|
|
|
5244
5293
|
help="Copy output to clipboard after a successful run.",
|
|
5245
5294
|
),
|
|
5246
5295
|
) -> None:
|
|
5247
|
-
"""Split a large Java file into semantic chunks for AI agent consumption
|
|
5296
|
+
"""Split a large Java file into semantic chunks for AI agent consumption.
|
|
5248
5297
|
|
|
5249
5298
|
\b
|
|
5250
5299
|
Splits a Java file at method/class boundaries so AI agents can read
|
|
@@ -5278,6 +5327,16 @@ def chunk_file_cmd(
|
|
|
5278
5327
|
)
|
|
5279
5328
|
raise typer.Exit(1)
|
|
5280
5329
|
|
|
5330
|
+
if abs_file.suffix != ".java":
|
|
5331
|
+
_emit_error_json(
|
|
5332
|
+
INVALID_INPUT_CODE,
|
|
5333
|
+
f"'{abs_file.name}' is not a Java file. chunk-file only supports .java files.",
|
|
5334
|
+
path=str(abs_file),
|
|
5335
|
+
hint="Pass a .java source file.",
|
|
5336
|
+
expected="A .java file path.",
|
|
5337
|
+
)
|
|
5338
|
+
raise typer.Exit(1)
|
|
5339
|
+
|
|
5281
5340
|
result = chunk_java_file(abs_file, max_lines=max_lines, include_content=not metadata_only)
|
|
5282
5341
|
|
|
5283
5342
|
if chunk_id is not None:
|
|
@@ -111,6 +111,8 @@ class JavaDetector(AbstractDetector):
|
|
|
111
111
|
manifests.append("pom.xml")
|
|
112
112
|
pom_path = context.root / "pom.xml"
|
|
113
113
|
frameworks.extend(self._frameworks_from_pom(pom_path))
|
|
114
|
+
for child_pom in self._get_child_pom_paths(pom_path):
|
|
115
|
+
frameworks.extend(self._frameworks_from_pom(child_pom))
|
|
114
116
|
meta = self._parse_pom_metadata(pom_path)
|
|
115
117
|
if meta.get("language_version"):
|
|
116
118
|
language_version = meta["language_version"]
|
|
@@ -232,6 +234,26 @@ class JavaDetector(AbstractDetector):
|
|
|
232
234
|
_SKIP = frozenset({"test", "it", "integration"})
|
|
233
235
|
return [p for p in profiles if p.lower() not in _SKIP]
|
|
234
236
|
|
|
237
|
+
def _get_child_pom_paths(self, root_pom: Path) -> list[Path]:
|
|
238
|
+
"""Return pom.xml paths for direct Maven child modules declared in <modules>."""
|
|
239
|
+
try:
|
|
240
|
+
tree = ElementTree.parse(root_pom)
|
|
241
|
+
except (OSError, ElementTree.ParseError):
|
|
242
|
+
return []
|
|
243
|
+
root_elem = tree.getroot()
|
|
244
|
+
ns_match = _NS_TAG_RE.match(root_elem.tag)
|
|
245
|
+
ns = ns_match.group(0) if ns_match else ""
|
|
246
|
+
modules_elem = root_elem.find(f"{ns}modules")
|
|
247
|
+
if modules_elem is None:
|
|
248
|
+
return []
|
|
249
|
+
result = []
|
|
250
|
+
for mod in modules_elem.findall(f"{ns}module"):
|
|
251
|
+
if mod.text:
|
|
252
|
+
child_pom = root_pom.parent / mod.text.strip() / "pom.xml"
|
|
253
|
+
if child_pom.exists():
|
|
254
|
+
result.append(child_pom)
|
|
255
|
+
return result
|
|
256
|
+
|
|
235
257
|
def _frameworks_from_pom(self, path: Path) -> list[FrameworkDetection]:
|
|
236
258
|
try:
|
|
237
259
|
tree = ElementTree.parse(path)
|
|
@@ -289,7 +311,14 @@ class JavaDetector(AbstractDetector):
|
|
|
289
311
|
frameworks.append(FrameworkDetection(name="Micronaut", source=source))
|
|
290
312
|
if "io.vertx" in text or "vertx" in text:
|
|
291
313
|
frameworks.append(FrameworkDetection(name="Vert.x", source=source))
|
|
292
|
-
if
|
|
314
|
+
if (
|
|
315
|
+
"jakarta.ee" in text
|
|
316
|
+
or "javax.ws.rs-api" in text # JAX-RS 2.x spec; excludes jsr311-api (1.x API-only jar)
|
|
317
|
+
or "jakarta.ws.rs" in text # Jakarta namespace (EE 9+)
|
|
318
|
+
or "javaee-api" in text # full Java EE platform
|
|
319
|
+
or "jakartaee-api" in text # full Jakarta EE platform
|
|
320
|
+
or "resteasy" in text # RESTEasy (JBoss JAX-RS impl)
|
|
321
|
+
):
|
|
293
322
|
frameworks.append(FrameworkDetection(name="Jakarta EE", source=source))
|
|
294
323
|
if "mybatis" in text:
|
|
295
324
|
frameworks.append(FrameworkDetection(name="MyBatis", source=source))
|
|
@@ -2464,7 +2464,7 @@ class TaskContextBuilder:
|
|
|
2464
2464
|
# Java-aware algorithm (Fix #2): find Service/RestController/Repository/Mapper
|
|
2465
2465
|
# files with no matching test pair in src/test/**
|
|
2466
2466
|
_JAVA_TARGET_SUFFIXES = (
|
|
2467
|
-
"Service.java", "RestController.java",
|
|
2467
|
+
"Service.java", "Controller.java", "RestController.java",
|
|
2468
2468
|
"Repository.java", "Mapper.java",
|
|
2469
2469
|
)
|
|
2470
2470
|
# Build set of test stems (FooTest → Foo, FooIT → Foo, etc.)
|
|
@@ -152,6 +152,9 @@ def _find_class_file(
|
|
|
152
152
|
return None
|
|
153
153
|
|
|
154
154
|
|
|
155
|
+
_PKG_IMPORT_RE = re.compile(r'^\s*(?:package|import)\s')
|
|
156
|
+
|
|
157
|
+
|
|
155
158
|
def _apply_rename(source: str, old_name: str, new_name: str) -> str:
|
|
156
159
|
"""Apply word-boundary replacement for class name (PascalCase and camelCase forms)."""
|
|
157
160
|
result = re.sub(r'\b' + re.escape(old_name) + r'\b', new_name, source)
|
|
@@ -159,7 +162,12 @@ def _apply_rename(source: str, old_name: str, new_name: str) -> str:
|
|
|
159
162
|
old_camel = _to_camel(old_name)
|
|
160
163
|
new_camel = _to_camel(new_name)
|
|
161
164
|
if old_camel != old_name and old_camel in result:
|
|
162
|
-
|
|
165
|
+
camel_re = re.compile(r'\b' + re.escape(old_camel) + r'\b')
|
|
166
|
+
lines = result.splitlines(keepends=True)
|
|
167
|
+
result = ''.join(
|
|
168
|
+
line if _PKG_IMPORT_RE.match(line) else camel_re.sub(new_camel, line)
|
|
169
|
+
for line in lines
|
|
170
|
+
)
|
|
163
171
|
|
|
164
172
|
return result
|
|
165
173
|
|
|
@@ -193,7 +201,12 @@ def _apply_rename_refs_only(source: str, old_name: str, new_name: str) -> str:
|
|
|
193
201
|
old_camel = _to_camel(old_name)
|
|
194
202
|
new_camel = _to_camel(new_name)
|
|
195
203
|
if old_camel != old_name and old_camel in result:
|
|
196
|
-
|
|
204
|
+
camel_re = re.compile(r'\b' + re.escape(old_camel) + r'\b')
|
|
205
|
+
lines = result.splitlines(keepends=True)
|
|
206
|
+
result = ''.join(
|
|
207
|
+
line if _PKG_IMPORT_RE.match(line) else camel_re.sub(new_camel, line)
|
|
208
|
+
for line in lines
|
|
209
|
+
)
|
|
197
210
|
|
|
198
211
|
return result
|
|
199
212
|
|
|
@@ -23,6 +23,7 @@ from pathlib import Path
|
|
|
23
23
|
from typing import Any, Optional
|
|
24
24
|
|
|
25
25
|
from sourcecode.fqn_utils import normalize_owner_fqn as _normalize_owner_fqn
|
|
26
|
+
from sourcecode.path_filters import is_test_path as _is_test_path
|
|
26
27
|
|
|
27
28
|
# ---------------------------------------------------------------------------
|
|
28
29
|
# Data classes — Phases 1–4
|
|
@@ -3582,13 +3583,37 @@ def find_java_files(root: Path, *, max_files: int = 8000, limitations: list[str]
|
|
|
3582
3583
|
except ValueError:
|
|
3583
3584
|
continue
|
|
3584
3585
|
parts = rel.split("/")
|
|
3585
|
-
# Skip test dirs
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3586
|
+
# Skip test dirs — use centralised is_test_path (consistent with
|
|
3587
|
+
# extract_java_endpoints), guarded against false positives where a Java
|
|
3588
|
+
# *package* is named "test" inside a production src/main/ source root.
|
|
3589
|
+
if _is_test_path(rel):
|
|
3590
|
+
_skip = True
|
|
3591
|
+
# Prepend "/" so the check works whether or not rel has a leading slash.
|
|
3592
|
+
_rel_sl = "/" + rel
|
|
3593
|
+
if "/src/main/" in _rel_sl:
|
|
3594
|
+
# is_test_path may fire on a package segment (e.g. com.example.test)
|
|
3595
|
+
# rather than a true test module directory. Only skip when the path
|
|
3596
|
+
# prefix BEFORE src/main/ is itself a test path (meaning the whole
|
|
3597
|
+
# module is a test module, not just a package named "test").
|
|
3598
|
+
_prefix = _rel_sl.split("/src/main/")[0]
|
|
3599
|
+
_prefix_parts = [p for p in _prefix.split("/") if p]
|
|
3600
|
+
# A module is a test module if is_test_path says so OR if any
|
|
3601
|
+
# module directory component starts with "test" (e.g. "test-framework",
|
|
3602
|
+
# "test-providers", "testsuite") OR contains "test"/"tests" as a
|
|
3603
|
+
# hyphen/underscore-separated word (e.g. "jobrunr-micronaut-tests").
|
|
3604
|
+
_prefix_is_test = (
|
|
3605
|
+
_is_test_path(_prefix + "/x.java")
|
|
3606
|
+
or any(p.lower().startswith("test") for p in _prefix_parts)
|
|
3607
|
+
or any(
|
|
3608
|
+
w in {"test", "tests", "spec", "specs"}
|
|
3609
|
+
for p in _prefix_parts
|
|
3610
|
+
for w in p.lower().replace("-", " ").replace("_", " ").split()
|
|
3611
|
+
)
|
|
3612
|
+
)
|
|
3613
|
+
if not _prefix_is_test:
|
|
3614
|
+
_skip = False
|
|
3615
|
+
if _skip:
|
|
3616
|
+
continue
|
|
3592
3617
|
# Skip vendor/generated/build dirs
|
|
3593
3618
|
if any(part in _VENDOR_DIRS for part in parts[:-1]):
|
|
3594
3619
|
continue
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|