sourcecode 0.1.1__py3-none-any.whl → 0.3.0__py3-none-any.whl

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/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """sourcecode — Genera mapas de contexto estructurado para agentes IA."""
2
2
 
3
- __version__ = "0.1.0"
3
+ __version__ = "0.3.0"
sourcecode/classifier.py CHANGED
@@ -9,6 +9,7 @@ from sourcecode.schema import EntryPoint, StackDetection
9
9
  from sourcecode.tree_utils import flatten_file_tree
10
10
 
11
11
  _API_FRAMEWORKS = {
12
+ "ASP.NET Core",
12
13
  "FastAPI",
13
14
  "Django",
14
15
  "Flask",
@@ -22,9 +23,12 @@ _API_FRAMEWORKS = {
22
23
  "Quarkus",
23
24
  "Laravel",
24
25
  "Symfony",
26
+ "Ktor",
27
+ "Play",
25
28
  }
26
- _WEB_FRAMEWORKS = {"Next.js", "React", "Vue", "Svelte", "Vite", "Flutter"}
29
+ _WEB_FRAMEWORKS = {"Next.js", "React", "Vue", "Svelte", "Vite", "Flutter", "Phoenix"}
27
30
  _CLI_FRAMEWORKS = {"Typer", "Cobra", "Clap"}
31
+ _API_STACKS = {"python", "go", "java", "php", "ruby", "dotnet", "kotlin", "scala"}
28
32
  ConfidenceLevel = Literal["high", "medium", "low"]
29
33
 
30
34
 
@@ -113,8 +117,10 @@ class TypeClassifier:
113
117
 
114
118
  if stack_names:
115
119
  single = next(iter(stack_names))
116
- if single in {"python", "go", "java", "php", "ruby"} and framework_names & _API_FRAMEWORKS:
120
+ if single in _API_STACKS and framework_names & _API_FRAMEWORKS:
117
121
  return "api"
122
+ if single in {"cpp", "dotnet"} and any(entry.kind == "cli" for entry in entry_points):
123
+ return "cli"
118
124
 
119
125
  return "unknown" if stacks else None
120
126
 
@@ -125,7 +131,7 @@ class TypeClassifier:
125
131
  frameworks = {framework.name for framework in stack.frameworks}
126
132
  if frameworks & _WEB_FRAMEWORKS or stack.stack == "nodejs":
127
133
  has_web = True
128
- if frameworks & _API_FRAMEWORKS or stack.stack in {"python", "go", "java", "php", "ruby"}:
134
+ if frameworks & _API_FRAMEWORKS or stack.stack in _API_STACKS:
129
135
  has_api = True
130
136
  return has_web and has_api
131
137
 
@@ -139,9 +145,9 @@ class TypeClassifier:
139
145
  score = {"low": 0, "medium": 1, "high": 2}.get(stack.confidence, 0)
140
146
  manifest_weight = 1 if stack.manifests else 0
141
147
  priority = 0
142
- if project_type in {"webapp", "fullstack"} and stack.stack == "nodejs" or project_type == "api" and stack.stack in {"python", "go", "java", "php", "ruby"} or project_type == "cli" and any(
148
+ if project_type in {"webapp", "fullstack"} and stack.stack in {"nodejs", "elixir"} or project_type == "api" and stack.stack in _API_STACKS or project_type == "cli" and any(
143
149
  framework.name in _CLI_FRAMEWORKS for framework in stack.frameworks
144
- ):
150
+ ) or project_type == "cli" and stack.stack in {"cpp", "dotnet"}:
145
151
  priority = 3
146
152
  return (priority, score, manifest_weight)
147
153
 
@@ -157,6 +163,12 @@ class TypeClassifier:
157
163
  "php": (".php",),
158
164
  "ruby": (".rb",),
159
165
  "dart": (".dart",),
166
+ "dotnet": (".cs", ".fs"),
167
+ "elixir": (".ex", ".exs"),
168
+ "kotlin": (".kt", ".kts"),
169
+ "scala": (".scala",),
170
+ "terraform": (".tf",),
171
+ "cpp": (".c", ".cc", ".cpp", ".cxx", ".hpp", ".h"),
160
172
  }.get(stack, ())
161
173
  return sum(1 for path in flatten_file_tree(file_tree) if path.endswith(extensions))
162
174
 
sourcecode/cli.py CHANGED
@@ -46,6 +46,11 @@ def main(
46
46
  "--compact",
47
47
  help="Output reducido (~500 tokens): tipo de proyecto, stacks, entradas y arbol nivel 1",
48
48
  ),
49
+ dependencies: bool = typer.Option(
50
+ False,
51
+ "--dependencies",
52
+ help="Incluir dependencias directas, versiones exactas y transitivas cuando haya lockfiles compatibles",
53
+ ),
49
54
  no_redact: bool = typer.Option(
50
55
  False,
51
56
  "--no-redact",
@@ -88,6 +93,7 @@ def main(
88
93
  # --- Importar modulos de logica ---
89
94
  from dataclasses import asdict, replace
90
95
 
96
+ from sourcecode.dependency_analyzer import DependencyAnalyzer
91
97
  from sourcecode.detectors import ProjectDetector, build_default_detectors
92
98
  from sourcecode.redactor import SecretRedactor, redact_dict
93
99
  from sourcecode.scanner import FileScanner
@@ -116,6 +122,7 @@ def main(
116
122
  manifests = scanner.find_manifests()
117
123
  detector = ProjectDetector(build_default_detectors())
118
124
  workspace_analysis = WorkspaceAnalyzer().analyze(target, manifests)
125
+ dependency_analyzer = DependencyAnalyzer() if dependencies else None
119
126
 
120
127
  root_manifests = [
121
128
  manifest
@@ -129,6 +136,13 @@ def main(
129
136
  else:
130
137
  stacks, entry_points, _project_type = detector.detect(target, file_tree, detection_manifests)
131
138
 
139
+ dependency_records = []
140
+ dependency_summaries = []
141
+ if dependency_analyzer is not None:
142
+ root_dependencies, root_summary = dependency_analyzer.analyze(target)
143
+ dependency_records.extend(root_dependencies)
144
+ dependency_summaries.append(root_summary)
145
+
132
146
  for workspace in workspace_analysis.workspaces:
133
147
  workspace_root = target / workspace.path
134
148
  if not workspace_root.exists() or not workspace_root.is_dir():
@@ -153,6 +167,13 @@ def main(
153
167
  )
154
168
  for entry_point in workspace_entry_points
155
169
  )
170
+ if dependency_analyzer is not None:
171
+ workspace_dependencies, workspace_summary = dependency_analyzer.analyze(
172
+ workspace_root,
173
+ workspace=workspace.path,
174
+ )
175
+ dependency_records.extend(workspace_dependencies)
176
+ dependency_summaries.append(workspace_summary)
156
177
 
157
178
  stacks, project_type = detector.classify_results(
158
179
  file_tree,
@@ -160,6 +181,11 @@ def main(
160
181
  entry_points,
161
182
  project_type_override="monorepo" if workspace_analysis.is_monorepo else None,
162
183
  )
184
+ dependency_summary = (
185
+ dependency_analyzer.merge_summaries(dependency_summaries)
186
+ if dependency_analyzer is not None
187
+ else None
188
+ )
163
189
 
164
190
  # 3. Construir el schema
165
191
  metadata = AnalysisMetadata(analyzed_path=str(target))
@@ -169,6 +195,8 @@ def main(
169
195
  stacks=stacks,
170
196
  project_type=project_type,
171
197
  entry_points=entry_points,
198
+ dependencies=dependency_records,
199
+ dependency_summary=dependency_summary,
172
200
  )
173
201
 
174
202
  # 4. Serializar (con o sin modo compact)