sourcecode 0.7.0__tar.gz → 0.9.0__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.
Files changed (98) hide show
  1. {sourcecode-0.7.0 → sourcecode-0.9.0}/PKG-INFO +1 -1
  2. {sourcecode-0.7.0 → sourcecode-0.9.0}/docs/schema.md +2 -2
  3. {sourcecode-0.7.0 → sourcecode-0.9.0}/pyproject.toml +1 -1
  4. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/__init__.py +1 -1
  5. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/cli.py +102 -1
  6. sourcecode-0.9.0/src/sourcecode/coverage_parser.py +539 -0
  7. sourcecode-0.9.0/src/sourcecode/metrics_analyzer.py +495 -0
  8. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/schema.py +124 -0
  9. sourcecode-0.9.0/src/sourcecode/semantic_analyzer.py +1887 -0
  10. sourcecode-0.9.0/tests/fixtures/coverage.xml +15 -0
  11. sourcecode-0.9.0/tests/fixtures/jacoco.xml +14 -0
  12. sourcecode-0.9.0/tests/fixtures/lcov.info +16 -0
  13. sourcecode-0.9.0/tests/test_coverage_parser.py +182 -0
  14. sourcecode-0.9.0/tests/test_integration_metrics.py +119 -0
  15. sourcecode-0.9.0/tests/test_integration_semantics.py +185 -0
  16. sourcecode-0.9.0/tests/test_metrics_analyzer.py +456 -0
  17. sourcecode-0.9.0/tests/test_semantic_analyzer_node.py +493 -0
  18. sourcecode-0.9.0/tests/test_semantic_analyzer_python.py +302 -0
  19. sourcecode-0.9.0/tests/test_semantic_import_resolution.py +355 -0
  20. sourcecode-0.9.0/tests/test_semantic_schema.py +129 -0
  21. {sourcecode-0.7.0 → sourcecode-0.9.0}/.gitignore +0 -0
  22. {sourcecode-0.7.0 → sourcecode-0.9.0}/.ruff.toml +0 -0
  23. {sourcecode-0.7.0 → sourcecode-0.9.0}/README.md +0 -0
  24. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/classifier.py +0 -0
  25. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/dependency_analyzer.py +0 -0
  26. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/__init__.py +0 -0
  27. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/base.py +0 -0
  28. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/dart.py +0 -0
  29. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/dotnet.py +0 -0
  30. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/elixir.py +0 -0
  31. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/go.py +0 -0
  32. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/heuristic.py +0 -0
  33. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/java.py +0 -0
  34. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  35. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/nodejs.py +0 -0
  36. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/parsers.py +0 -0
  37. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/php.py +0 -0
  38. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/project.py +0 -0
  39. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/python.py +0 -0
  40. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/ruby.py +0 -0
  41. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/rust.py +0 -0
  42. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/systems.py +0 -0
  43. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/terraform.py +0 -0
  44. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/detectors/tooling.py +0 -0
  45. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/doc_analyzer.py +0 -0
  46. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/graph_analyzer.py +0 -0
  47. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/redactor.py +0 -0
  48. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/scanner.py +0 -0
  49. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/serializer.py +0 -0
  50. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/summarizer.py +0 -0
  51. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/tree_utils.py +0 -0
  52. {sourcecode-0.7.0 → sourcecode-0.9.0}/src/sourcecode/workspace.py +0 -0
  53. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/__init__.py +0 -0
  54. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/conftest.py +0 -0
  55. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
  56. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/fixtures/fastapi_app/src/main.py +0 -0
  57. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/fixtures/go_service/cmd/api/main.go +0 -0
  58. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/fixtures/go_service/go.mod +0 -0
  59. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
  60. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/fixtures/nextjs_app/package.json +0 -0
  61. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
  62. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
  63. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
  64. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
  65. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
  66. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
  67. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_classifier.py +0 -0
  68. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_cli.py +0 -0
  69. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_dependency_analyzer_node_python.py +0 -0
  70. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_dependency_analyzer_polyglot.py +0 -0
  71. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_dependency_schema.py +0 -0
  72. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_detector_go_rust_java.py +0 -0
  73. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_detector_nodejs.py +0 -0
  74. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_detector_php_ruby_dart.py +0 -0
  75. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_detector_python.py +0 -0
  76. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_detector_universal_managed.py +0 -0
  77. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_detector_universal_systems.py +0 -0
  78. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_detectors_base.py +0 -0
  79. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_doc_analyzer_jsdom.py +0 -0
  80. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_doc_analyzer_python.py +0 -0
  81. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_graph_analyzer_polyglot.py +0 -0
  82. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_graph_analyzer_python_node.py +0 -0
  83. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_graph_schema.py +0 -0
  84. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_integration.py +0 -0
  85. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_integration_dependencies.py +0 -0
  86. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_integration_detection.py +0 -0
  87. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_integration_docs.py +0 -0
  88. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_integration_graph_modules.py +0 -0
  89. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_integration_lqn.py +0 -0
  90. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_integration_multistack.py +0 -0
  91. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_integration_universal.py +0 -0
  92. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_packaging.py +0 -0
  93. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_real_projects.py +0 -0
  94. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_redactor.py +0 -0
  95. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_scanner.py +0 -0
  96. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_schema.py +0 -0
  97. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_summarizer.py +0 -0
  98. {sourcecode-0.7.0 → sourcecode-0.9.0}/tests/test_workspace_analyzer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 0.7.0
3
+ Version: 0.9.0
4
4
  Summary: Genera un mapa de contexto estructurado de proyectos de software para agentes IA
5
5
  License: MIT
6
6
  Requires-Python: >=3.9
@@ -61,7 +61,7 @@ Campos:
61
61
  {
62
62
  "schema_version": "1.0",
63
63
  "generated_at": "2026-04-07T19:41:05.686277+00:00",
64
- "sourcecode_version": "0.7.0",
64
+ "sourcecode_version": "0.9.0",
65
65
  "analyzed_path": "/abs/path/to/project"
66
66
  }
67
67
  ```
@@ -582,7 +582,7 @@ Ejemplo de salida para un monorepo con web Node.js y API Python con `--dependenc
582
582
  "metadata": {
583
583
  "schema_version": "1.0",
584
584
  "generated_at": "2026-04-07T19:41:05.686277+00:00",
585
- "sourcecode_version": "0.7.0",
585
+ "sourcecode_version": "0.9.0",
586
586
  "analyzed_path": "/abs/path/to/project"
587
587
  },
588
588
  "file_tree": {
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "0.7.0"
7
+ version = "0.9.0"
8
8
  description = "Genera un mapa de contexto estructurado de proyectos de software para agentes IA"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1,3 +1,3 @@
1
1
  """sourcecode — Genera mapas de contexto estructurado para agentes IA."""
2
2
 
3
- __version__ = "0.7.0"
3
+ __version__ = "0.9.0"
@@ -107,6 +107,16 @@ def main(
107
107
  help="Profundidad de extraccion de docs: module|symbols|full",
108
108
  show_default=True,
109
109
  ),
110
+ full_metrics: bool = typer.Option(
111
+ False,
112
+ "--full-metrics",
113
+ help="Incluir metricas de calidad: LOC, simbolos, complejidad, tests y cobertura por fichero",
114
+ ),
115
+ semantics: bool = typer.Option(
116
+ False,
117
+ "--semantics",
118
+ help="Incluir call graph semantico, linking cross-file de simbolos y resolucion avanzada de imports",
119
+ ),
110
120
  ) -> None:
111
121
  """Genera un mapa de contexto estructurado del proyecto en formato JSON o YAML."""
112
122
  # Validar formato
@@ -145,9 +155,18 @@ def main(
145
155
  from sourcecode.detectors import ProjectDetector, build_default_detectors
146
156
  from sourcecode.doc_analyzer import DocAnalyzer
147
157
  from sourcecode.graph_analyzer import GraphAnalyzer, GraphDetail
158
+ from sourcecode.metrics_analyzer import MetricsAnalyzer
148
159
  from sourcecode.redactor import SecretRedactor, redact_dict
149
160
  from sourcecode.scanner import FileScanner
150
- from sourcecode.schema import AnalysisMetadata, DocRecord, DocSummary, DocsDepth, EntryPoint, SourceMap, StackDetection
161
+ from sourcecode.schema import (
162
+ AnalysisMetadata,
163
+ DocRecord,
164
+ DocsDepth,
165
+ DocSummary,
166
+ EntryPoint,
167
+ SourceMap,
168
+ StackDetection,
169
+ )
151
170
  from sourcecode.serializer import compact_view, write_output
152
171
  from sourcecode.workspace import WorkspaceAnalyzer
153
172
 
@@ -212,6 +231,10 @@ def main(
212
231
  graph_detail_typed = cast(GraphDetail, graph_detail)
213
232
  docs_depth_typed = cast(DocsDepth, docs_depth)
214
233
  doc_analyzer = DocAnalyzer() if docs else None
234
+ metrics_analyzer = MetricsAnalyzer() if full_metrics else None
235
+
236
+ from sourcecode.semantic_analyzer import SemanticAnalyzer
237
+ semantic_analyzer = SemanticAnalyzer() if semantics else None
215
238
 
216
239
  root_manifests = [
217
240
  manifest
@@ -269,6 +292,24 @@ def main(
269
292
  doc_records.extend(root_doc_records)
270
293
  doc_summaries.append(root_doc_summary)
271
294
 
295
+ file_metrics_records: list = []
296
+ metrics_summaries = []
297
+ if metrics_analyzer is not None:
298
+ root_metrics_tree = (
299
+ prune_workspace_paths(
300
+ file_tree,
301
+ [workspace.path for workspace in workspace_analysis.workspaces],
302
+ )
303
+ if workspace_analysis.workspaces
304
+ else file_tree
305
+ )
306
+ root_file_metrics, root_metrics_summary = metrics_analyzer.analyze(
307
+ target,
308
+ root_metrics_tree,
309
+ )
310
+ file_metrics_records.extend(root_file_metrics)
311
+ metrics_summaries.append(root_metrics_summary)
312
+
272
313
  for workspace in workspace_analysis.workspaces:
273
314
  workspace_root = target / workspace.path
274
315
  if not workspace_root.exists() or not workspace_root.is_dir():
@@ -327,6 +368,18 @@ def main(
327
368
  ]
328
369
  doc_records.extend(prefixed_doc_records)
329
370
  doc_summaries.append(workspace_doc_summary)
371
+ if metrics_analyzer is not None:
372
+ ws_file_metrics, ws_metrics_summary = metrics_analyzer.analyze(
373
+ workspace_root,
374
+ workspace_tree,
375
+ workspace=workspace.path,
376
+ )
377
+ prefixed_file_metrics = [
378
+ replace(m, path=f"{workspace.path}/{m.path}")
379
+ for m in ws_file_metrics
380
+ ]
381
+ file_metrics_records.extend(prefixed_file_metrics)
382
+ metrics_summaries.append(ws_metrics_summary)
330
383
 
331
384
  stacks, project_type = detector.classify_results(
332
385
  file_tree,
@@ -355,6 +408,11 @@ def main(
355
408
  if doc_analyzer is not None
356
409
  else None
357
410
  )
411
+ metrics_summary = (
412
+ metrics_analyzer.merge_summaries(metrics_summaries)
413
+ if metrics_analyzer is not None
414
+ else None
415
+ )
358
416
 
359
417
  # 3. Construir el schema
360
418
  metadata = AnalysisMetadata(analyzed_path=str(target))
@@ -370,8 +428,51 @@ def main(
370
428
  module_graph_summary=module_graph.summary if module_graph is not None else None,
371
429
  docs=doc_records,
372
430
  doc_summary=doc_summary,
431
+ file_metrics=file_metrics_records,
432
+ metrics_summary=metrics_summary,
373
433
  )
374
434
 
435
+ # Semantic analysis (--semantics flag)
436
+ if semantic_analyzer is not None:
437
+ if workspace_analysis.workspaces:
438
+ all_sem_calls: list[Any] = []
439
+ all_sem_symbols: list[Any] = []
440
+ all_sem_links: list[Any] = []
441
+ all_sem_summaries: list[Any] = []
442
+ for ws in workspace_analysis.workspaces:
443
+ ws_calls, ws_syms, ws_links, ws_sum = semantic_analyzer.analyze(
444
+ target / ws.path,
445
+ (
446
+ filter_sensitive_files(
447
+ FileScanner(target / ws.path, max_depth=depth).scan_tree()
448
+ )
449
+ ),
450
+ workspace=ws.path,
451
+ )
452
+ all_sem_calls.extend(ws_calls)
453
+ all_sem_symbols.extend(ws_syms)
454
+ all_sem_links.extend(ws_links)
455
+ all_sem_summaries.append(ws_sum)
456
+ merged_sem = semantic_analyzer.merge_summaries(all_sem_summaries)
457
+ sm = replace(
458
+ sm,
459
+ semantic_calls=all_sem_calls,
460
+ semantic_symbols=all_sem_symbols,
461
+ semantic_links=all_sem_links,
462
+ semantic_summary=merged_sem,
463
+ )
464
+ else:
465
+ sem_calls, sem_syms, sem_links, sem_sum = semantic_analyzer.analyze(
466
+ target, file_tree
467
+ )
468
+ sm = replace(
469
+ sm,
470
+ semantic_calls=sem_calls,
471
+ semantic_symbols=sem_syms,
472
+ semantic_links=sem_links,
473
+ semantic_summary=sem_sum,
474
+ )
475
+
375
476
  # Phase 9: LLM Output Quality — poblar campos derivados
376
477
  from sourcecode.summarizer import ProjectSummarizer
377
478
  from sourcecode.tree_utils import flatten_file_tree