graphitect 0.2.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.
- graphify/__init__.py +30 -0
- graphify/__main__.py +757 -0
- graphify/_minhash.py +107 -0
- graphify/affected.py +318 -0
- graphify/always_on/agents-md.md +12 -0
- graphify/always_on/antigravity-rules.md +14 -0
- graphify/always_on/claude-md.md +9 -0
- graphify/always_on/gemini-md.md +9 -0
- graphify/always_on/kiro-steering.md +5 -0
- graphify/always_on/vscode-instructions.md +17 -0
- graphify/analyze.py +769 -0
- graphify/benchmark.py +152 -0
- graphify/build.py +2300 -0
- graphify/cache.py +1746 -0
- graphify/callflow_html.py +2051 -0
- graphify/cargo_introspect.py +109 -0
- graphify/cli.py +4745 -0
- graphify/cluster.py +409 -0
- graphify/command-kilo.md +15 -0
- graphify/cross_repo_calls.py +216 -0
- graphify/cross_repo_types.py +75 -0
- graphify/csharp_dispatch.py +154 -0
- graphify/dedup.py +1213 -0
- graphify/detect.py +2566 -0
- graphify/diagnostics.py +406 -0
- graphify/export.py +1349 -0
- graphify/exporters/__init__.py +1 -0
- graphify/exporters/base.py +14 -0
- graphify/exporters/graphdb.py +173 -0
- graphify/exporters/html.py +637 -0
- graphify/extract.py +7856 -0
- graphify/extractors/MIGRATION.md +107 -0
- graphify/extractors/__init__.py +66 -0
- graphify/extractors/apex.py +215 -0
- graphify/extractors/base.py +85 -0
- graphify/extractors/bash.py +579 -0
- graphify/extractors/blade.py +53 -0
- graphify/extractors/commonlisp.py +540 -0
- graphify/extractors/csharp.py +448 -0
- graphify/extractors/dart.py +564 -0
- graphify/extractors/dm.py +494 -0
- graphify/extractors/elixir.py +241 -0
- graphify/extractors/engine.py +6509 -0
- graphify/extractors/fortran.py +311 -0
- graphify/extractors/go.py +527 -0
- graphify/extractors/json_config.py +240 -0
- graphify/extractors/julia.py +289 -0
- graphify/extractors/markdown.py +408 -0
- graphify/extractors/models.py +131 -0
- graphify/extractors/objc.py +566 -0
- graphify/extractors/ocaml.py +289 -0
- graphify/extractors/pascal.py +688 -0
- graphify/extractors/pascal_forms.py +196 -0
- graphify/extractors/powershell.py +522 -0
- graphify/extractors/razor.py +192 -0
- graphify/extractors/resolution.py +3584 -0
- graphify/extractors/robot.py +296 -0
- graphify/extractors/rust.py +470 -0
- graphify/extractors/sln.py +92 -0
- graphify/extractors/sql.py +720 -0
- graphify/extractors/terraform.py +181 -0
- graphify/extractors/verilog.py +329 -0
- graphify/extractors/zig.py +181 -0
- graphify/file_slice.py +246 -0
- graphify/global_graph.py +194 -0
- graphify/google_workspace.py +237 -0
- graphify/hooks.py +933 -0
- graphify/ids.py +93 -0
- graphify/ingest.py +358 -0
- graphify/install.py +2366 -0
- graphify/llm.py +3544 -0
- graphify/manifest.py +4 -0
- graphify/manifest_ingest.py +311 -0
- graphify/mcp_ingest.py +386 -0
- graphify/multigraph_compat.py +212 -0
- graphify/pascal_resolution.py +129 -0
- graphify/paths.py +436 -0
- graphify/pg_introspect.py +165 -0
- graphify/prs.py +770 -0
- graphify/querylog.py +80 -0
- graphify/reflect.py +882 -0
- graphify/report.py +346 -0
- graphify/resolver_registry.py +85 -0
- graphify/ruby_resolution.py +242 -0
- graphify/scip_ingest.py +363 -0
- graphify/security.py +460 -0
- graphify/semantic_cleanup.py +336 -0
- graphify/serve.py +2608 -0
- graphify/skill-agents.md +710 -0
- graphify/skill-aider.md +1283 -0
- graphify/skill-amp.md +710 -0
- graphify/skill-claw.md +713 -0
- graphify/skill-codex.md +710 -0
- graphify/skill-copilot.md +713 -0
- graphify/skill-devin.md +1410 -0
- graphify/skill-droid.md +710 -0
- graphify/skill-kilo.md +722 -0
- graphify/skill-kiro.md +713 -0
- graphify/skill-opencode.md +705 -0
- graphify/skill-pi.md +713 -0
- graphify/skill-trae.md +711 -0
- graphify/skill-vscode.md +709 -0
- graphify/skill-windows.md +755 -0
- graphify/skill.md +713 -0
- graphify/skills/agents/references/add-watch.md +56 -0
- graphify/skills/agents/references/exports.md +87 -0
- graphify/skills/agents/references/extraction-spec.md +70 -0
- graphify/skills/agents/references/github-and-merge.md +46 -0
- graphify/skills/agents/references/hooks.md +33 -0
- graphify/skills/agents/references/query.md +311 -0
- graphify/skills/agents/references/transcribe.md +52 -0
- graphify/skills/agents/references/update.md +210 -0
- graphify/skills/amp/references/add-watch.md +56 -0
- graphify/skills/amp/references/exports.md +87 -0
- graphify/skills/amp/references/extraction-spec.md +70 -0
- graphify/skills/amp/references/github-and-merge.md +46 -0
- graphify/skills/amp/references/hooks.md +33 -0
- graphify/skills/amp/references/query.md +311 -0
- graphify/skills/amp/references/transcribe.md +52 -0
- graphify/skills/amp/references/update.md +210 -0
- graphify/skills/claude/references/add-watch.md +56 -0
- graphify/skills/claude/references/exports.md +87 -0
- graphify/skills/claude/references/extraction-spec.md +70 -0
- graphify/skills/claude/references/github-and-merge.md +46 -0
- graphify/skills/claude/references/hooks.md +33 -0
- graphify/skills/claude/references/query.md +311 -0
- graphify/skills/claude/references/transcribe.md +52 -0
- graphify/skills/claude/references/update.md +210 -0
- graphify/skills/claw/references/add-watch.md +56 -0
- graphify/skills/claw/references/exports.md +87 -0
- graphify/skills/claw/references/extraction-spec.md +31 -0
- graphify/skills/claw/references/github-and-merge.md +46 -0
- graphify/skills/claw/references/hooks.md +33 -0
- graphify/skills/claw/references/query.md +311 -0
- graphify/skills/claw/references/transcribe.md +52 -0
- graphify/skills/claw/references/update.md +210 -0
- graphify/skills/codex/references/add-watch.md +56 -0
- graphify/skills/codex/references/exports.md +87 -0
- graphify/skills/codex/references/extraction-spec.md +31 -0
- graphify/skills/codex/references/github-and-merge.md +46 -0
- graphify/skills/codex/references/hooks.md +33 -0
- graphify/skills/codex/references/query.md +311 -0
- graphify/skills/codex/references/transcribe.md +52 -0
- graphify/skills/codex/references/update.md +210 -0
- graphify/skills/copilot/references/add-watch.md +56 -0
- graphify/skills/copilot/references/exports.md +87 -0
- graphify/skills/copilot/references/extraction-spec.md +70 -0
- graphify/skills/copilot/references/github-and-merge.md +46 -0
- graphify/skills/copilot/references/hooks.md +33 -0
- graphify/skills/copilot/references/query.md +311 -0
- graphify/skills/copilot/references/transcribe.md +52 -0
- graphify/skills/copilot/references/update.md +210 -0
- graphify/skills/droid/references/add-watch.md +56 -0
- graphify/skills/droid/references/exports.md +87 -0
- graphify/skills/droid/references/extraction-spec.md +70 -0
- graphify/skills/droid/references/github-and-merge.md +46 -0
- graphify/skills/droid/references/hooks.md +33 -0
- graphify/skills/droid/references/query.md +311 -0
- graphify/skills/droid/references/transcribe.md +52 -0
- graphify/skills/droid/references/update.md +210 -0
- graphify/skills/kilo/references/add-watch.md +56 -0
- graphify/skills/kilo/references/exports.md +87 -0
- graphify/skills/kilo/references/extraction-spec.md +70 -0
- graphify/skills/kilo/references/github-and-merge.md +46 -0
- graphify/skills/kilo/references/hooks.md +33 -0
- graphify/skills/kilo/references/query.md +311 -0
- graphify/skills/kilo/references/transcribe.md +52 -0
- graphify/skills/kilo/references/update.md +210 -0
- graphify/skills/kiro/references/add-watch.md +56 -0
- graphify/skills/kiro/references/exports.md +87 -0
- graphify/skills/kiro/references/extraction-spec.md +31 -0
- graphify/skills/kiro/references/github-and-merge.md +46 -0
- graphify/skills/kiro/references/hooks.md +33 -0
- graphify/skills/kiro/references/query.md +311 -0
- graphify/skills/kiro/references/transcribe.md +52 -0
- graphify/skills/kiro/references/update.md +210 -0
- graphify/skills/opencode/references/add-watch.md +56 -0
- graphify/skills/opencode/references/exports.md +87 -0
- graphify/skills/opencode/references/extraction-spec.md +70 -0
- graphify/skills/opencode/references/github-and-merge.md +46 -0
- graphify/skills/opencode/references/hooks.md +33 -0
- graphify/skills/opencode/references/query.md +311 -0
- graphify/skills/opencode/references/transcribe.md +52 -0
- graphify/skills/opencode/references/update.md +210 -0
- graphify/skills/pi/references/add-watch.md +56 -0
- graphify/skills/pi/references/exports.md +87 -0
- graphify/skills/pi/references/extraction-spec.md +31 -0
- graphify/skills/pi/references/github-and-merge.md +46 -0
- graphify/skills/pi/references/hooks.md +33 -0
- graphify/skills/pi/references/query.md +311 -0
- graphify/skills/pi/references/transcribe.md +52 -0
- graphify/skills/pi/references/update.md +210 -0
- graphify/skills/trae/references/add-watch.md +56 -0
- graphify/skills/trae/references/exports.md +87 -0
- graphify/skills/trae/references/extraction-spec.md +70 -0
- graphify/skills/trae/references/github-and-merge.md +46 -0
- graphify/skills/trae/references/hooks.md +35 -0
- graphify/skills/trae/references/query.md +311 -0
- graphify/skills/trae/references/transcribe.md +52 -0
- graphify/skills/trae/references/update.md +210 -0
- graphify/skills/vscode/references/add-watch.md +56 -0
- graphify/skills/vscode/references/exports.md +87 -0
- graphify/skills/vscode/references/extraction-spec.md +70 -0
- graphify/skills/vscode/references/github-and-merge.md +46 -0
- graphify/skills/vscode/references/hooks.md +33 -0
- graphify/skills/vscode/references/query.md +311 -0
- graphify/skills/vscode/references/transcribe.md +52 -0
- graphify/skills/vscode/references/update.md +210 -0
- graphify/skills/windows/references/add-watch.md +56 -0
- graphify/skills/windows/references/exports.md +87 -0
- graphify/skills/windows/references/extraction-spec.md +70 -0
- graphify/skills/windows/references/github-and-merge.md +46 -0
- graphify/skills/windows/references/hooks.md +33 -0
- graphify/skills/windows/references/query.md +311 -0
- graphify/skills/windows/references/transcribe.md +52 -0
- graphify/skills/windows/references/update.md +210 -0
- graphify/symbol_resolution.py +556 -0
- graphify/transcribe.py +186 -0
- graphify/tree_html.py +603 -0
- graphify/validate.py +95 -0
- graphify/watch.py +2280 -0
- graphify/wiki.py +405 -0
- graphitect/__init__.py +28 -0
- graphitect/__main__.py +4 -0
- graphitect/_vendor/__init__.py +2 -0
- graphitect/_vendor/archify/LICENSE +22 -0
- graphitect/_vendor/archify/SKILL.md +137 -0
- graphitect/_vendor/archify/THIRD_PARTY_NOTICES.md +69 -0
- graphitect/_vendor/archify/assets/JetBrainsMono-OFL.txt +93 -0
- graphitect/_vendor/archify/assets/template.html +14935 -0
- graphitect/_vendor/archify/bin/archify.mjs +2091 -0
- graphitect/_vendor/archify/bin/open-artifact.mjs +86 -0
- graphitect/_vendor/archify/bin/preview.mjs +653 -0
- graphitect/_vendor/archify/bin/visual-check.mjs +829 -0
- graphitect/_vendor/archify/brand-marks/README.md +31 -0
- graphitect/_vendor/archify/brand-marks/catalog.json +131 -0
- graphitect/_vendor/archify/delta/architecture-delta.mjs +1221 -0
- graphitect/_vendor/archify/examples/agent-run.lifecycle.json +60 -0
- graphitect/_vendor/archify/examples/agent-tool-call.workflow.json +94 -0
- graphitect/_vendor/archify/examples/async-job-roundtrip.sequence.json +61 -0
- graphitect/_vendor/archify/examples/brand-aware-delivery.architecture.json +47 -0
- graphitect/_vendor/archify/examples/cache-miss-request.sequence.json +82 -0
- graphitect/_vendor/archify/examples/checkout-platform.base.architecture.json +31 -0
- graphitect/_vendor/archify/examples/checkout-platform.head.architecture.json +31 -0
- graphitect/_vendor/archify/examples/dataflow-product-analytics.html +15045 -0
- graphitect/_vendor/archify/examples/deployment-release.lifecycle.json +49 -0
- graphitect/_vendor/archify/examples/event-stream.dataflow.json +57 -0
- graphitect/_vendor/archify/examples/incident-response.workflow.json +64 -0
- graphitect/_vendor/archify/examples/lifecycle-agent-run.html +14980 -0
- graphitect/_vendor/archify/examples/product-analytics.dataflow.json +76 -0
- graphitect/_vendor/archify/examples/production-deployment.architecture.json +71 -0
- graphitect/_vendor/archify/examples/release-delivery.workflow.json +62 -0
- graphitect/_vendor/archify/examples/sequence-cache-miss-request.html +15060 -0
- graphitect/_vendor/archify/examples/web-app-rendered.html +15009 -0
- graphitect/_vendor/archify/examples/web-app.architecture.json +46 -0
- graphitect/_vendor/archify/examples/workflow-agent-tool-call-rendered.html +15051 -0
- graphitect/_vendor/archify/migrations/workflow-v2.mjs +279 -0
- graphitect/_vendor/archify/package-lock.json +149 -0
- graphitect/_vendor/archify/package.json +39 -0
- graphitect/_vendor/archify/recipes/scenarios.mjs +391 -0
- graphitect/_vendor/archify/references/authoring-contract.md +243 -0
- graphitect/_vendor/archify/references/brand-marks.md +65 -0
- graphitect/_vendor/archify/references/delivery-contract.md +120 -0
- graphitect/_vendor/archify/references/viewer-runtime.md +45 -0
- graphitect/_vendor/archify/renderers/architecture/grid.mjs +62 -0
- graphitect/_vendor/archify/renderers/architecture/render-architecture.mjs +1078 -0
- graphitect/_vendor/archify/renderers/dataflow/README.md +104 -0
- graphitect/_vendor/archify/renderers/dataflow/render-dataflow.mjs +483 -0
- graphitect/_vendor/archify/renderers/lifecycle/README.md +115 -0
- graphitect/_vendor/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
- graphitect/_vendor/archify/renderers/sequence/README.md +114 -0
- graphitect/_vendor/archify/renderers/sequence/render-sequence.mjs +464 -0
- graphitect/_vendor/archify/renderers/shared/brand-marks.mjs +563 -0
- graphitect/_vendor/archify/renderers/shared/cli.mjs +218 -0
- graphitect/_vendor/archify/renderers/shared/desktop-readability.mjs +26 -0
- graphitect/_vendor/archify/renderers/shared/diagnostics.mjs +127 -0
- graphitect/_vendor/archify/renderers/shared/engineering-profiles.mjs +157 -0
- graphitect/_vendor/archify/renderers/shared/generated-brand-marks.mjs +2003 -0
- graphitect/_vendor/archify/renderers/shared/generated-validators.mjs +13 -0
- graphitect/_vendor/archify/renderers/shared/geometry.mjs +1423 -0
- graphitect/_vendor/archify/renderers/shared/i18n.mjs +595 -0
- graphitect/_vendor/archify/renderers/shared/layout-report.mjs +40 -0
- graphitect/_vendor/archify/renderers/shared/legend.mjs +217 -0
- graphitect/_vendor/archify/renderers/shared/output-path.mjs +340 -0
- graphitect/_vendor/archify/renderers/shared/repository-evidence.mjs +238 -0
- graphitect/_vendor/archify/renderers/shared/repository-location.mjs +58 -0
- graphitect/_vendor/archify/renderers/shared/text-fit.mjs +49 -0
- graphitect/_vendor/archify/renderers/shared/utils.mjs +232 -0
- graphitect/_vendor/archify/renderers/shared/validator.mjs +86 -0
- graphitect/_vendor/archify/renderers/workflow/README.md +223 -0
- graphitect/_vendor/archify/renderers/workflow/render-workflow.mjs +35 -0
- graphitect/_vendor/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
- graphitect/_vendor/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
- graphitect/_vendor/archify/schemas/README.md +211 -0
- graphitect/_vendor/archify/schemas/architecture.schema.json +178 -0
- graphitect/_vendor/archify/schemas/common.schema.json +115 -0
- graphitect/_vendor/archify/schemas/dataflow.schema.json +243 -0
- graphitect/_vendor/archify/schemas/lifecycle.schema.json +266 -0
- graphitect/_vendor/archify/schemas/sequence.schema.json +223 -0
- graphitect/_vendor/archify/schemas/workflow.schema.json +428 -0
- graphitect/_vendor/archify/scripts/check-render-output.mjs +836 -0
- graphitect/_vendor/archify/scripts/check-update.mjs +1667 -0
- graphitect/_vendor/archify/scripts/generate-brand-marks.mjs +141 -0
- graphitect/_vendor/archify/scripts/generate-validators.mjs +66 -0
- graphitect/_vendor/archify/scripts/render-examples.mjs +26 -0
- graphitect/_vendor/archify/scripts/update-contract.mjs +182 -0
- graphitect/_vendor/archify/skill-release.json +10 -0
- graphitect/cli.py +981 -0
- graphitect/deliver/__init__.py +5 -0
- graphitect/deliver/archify_adapter.py +1877 -0
- graphitect/deliver/archify_ir.py +160 -0
- graphitect/deliver/archify_repair.py +135 -0
- graphitect/deliver/doc_compiler.py +916 -0
- graphitect/ground/__init__.py +5 -0
- graphitect/ground/describe_source.py +27 -0
- graphitect/ground/fullread_source.py +56 -0
- graphitect/ground/graphify_source.py +107 -0
- graphitect/models.py +118 -0
- graphitect/skill/SKILL.md +80 -0
- graphitect/skill/agents/openai.yaml +4 -0
- graphitect/synthesize/__init__.py +5 -0
- graphitect/synthesize/engine.py +281 -0
- graphitect/synthesize/llm_backend.py +331 -0
- graphitect/synthesize/questions.py +139 -0
- graphitect/synthesize/rubric.py +104 -0
- graphitect-0.2.0.dist-info/METADATA +284 -0
- graphitect-0.2.0.dist-info/RECORD +336 -0
- graphitect-0.2.0.dist-info/WHEEL +5 -0
- graphitect-0.2.0.dist-info/entry_points.txt +2 -0
- graphitect-0.2.0.dist-info/licenses/LICENSE +21 -0
- graphitect-0.2.0.dist-info/licenses/LICENSE-ARCHIFY-MIT +22 -0
- graphitect-0.2.0.dist-info/licenses/LICENSE-GRAPHIFY-APACHE-2.0 +202 -0
- graphitect-0.2.0.dist-info/licenses/LICENSE-GRAPHIFY-MIT +21 -0
- graphitect-0.2.0.dist-info/licenses/NOTICE-ARCHIFY-THIRD-PARTY.md +69 -0
- graphitect-0.2.0.dist-info/licenses/NOTICE-GRAPHIFY +8 -0
- graphitect-0.2.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"""OCaml extractor (own module, optional tree-sitter-ocaml dependency).
|
|
2
|
+
|
|
3
|
+
Handles implementation files (.ml, `language_ocaml`) and interface files
|
|
4
|
+
(.mli, `language_ocaml_interface`). Interfaces have no expression bodies, so
|
|
5
|
+
they contribute definitions and `open` imports but no `calls` edges.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from graphify.extractors.base import _file_stem, _make_id, _read_text
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def extract_ocaml(path: Path) -> dict:
|
|
15
|
+
"""Extract modules, values, functions, types, variant constructors, `open`
|
|
16
|
+
imports, and (for .ml) function calls from an OCaml source file."""
|
|
17
|
+
try:
|
|
18
|
+
import tree_sitter_ocaml as tsocaml
|
|
19
|
+
from tree_sitter import Language, Parser
|
|
20
|
+
except ImportError:
|
|
21
|
+
return {"nodes": [], "edges": [], "error": "tree-sitter-ocaml not installed"}
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
if path.suffix == ".mli":
|
|
25
|
+
language = Language(tsocaml.language_ocaml_interface())
|
|
26
|
+
else:
|
|
27
|
+
language = Language(tsocaml.language_ocaml())
|
|
28
|
+
parser = Parser(language)
|
|
29
|
+
source = path.read_bytes()
|
|
30
|
+
tree = parser.parse(source)
|
|
31
|
+
root = tree.root_node
|
|
32
|
+
except Exception as e:
|
|
33
|
+
return {"nodes": [], "edges": [], "error": str(e)}
|
|
34
|
+
|
|
35
|
+
stem = _file_stem(path)
|
|
36
|
+
str_path = str(path)
|
|
37
|
+
nodes: list[dict] = []
|
|
38
|
+
edges: list[dict] = []
|
|
39
|
+
seen_ids: set[str] = set()
|
|
40
|
+
|
|
41
|
+
# Same-file definition table for call resolution. A name defined more than
|
|
42
|
+
# once in the file is marked ambiguous and never resolved locally.
|
|
43
|
+
local_defs: dict[str, str] = {}
|
|
44
|
+
ambiguous: set[str] = set()
|
|
45
|
+
# Names of modules DEFINED in this file. Used to decide whether a qualified
|
|
46
|
+
# call `M.f` may bind to a local `f`: if `M` is not a local module it is an
|
|
47
|
+
# external library (e.g. `Reg_spec.create`), so binding to a same-named local
|
|
48
|
+
# `f` would be a false edge (and a self-loop when the caller is that `f`).
|
|
49
|
+
local_modules: set[str] = set()
|
|
50
|
+
# (caller_nid, callee_name, qualifier_root_module_or_None, full_path_text,
|
|
51
|
+
# line) recorded on pass 1, resolved on pass 2 so that forward references
|
|
52
|
+
# (e.g. `let rec ... and ...`) resolve correctly.
|
|
53
|
+
call_sites: list[tuple[str, str, str | None, str, int]] = []
|
|
54
|
+
|
|
55
|
+
def add_node(nid: str, label: str, line: int) -> None:
|
|
56
|
+
if nid not in seen_ids:
|
|
57
|
+
seen_ids.add(nid)
|
|
58
|
+
nodes.append({
|
|
59
|
+
"id": nid,
|
|
60
|
+
"label": label,
|
|
61
|
+
"file_type": "code",
|
|
62
|
+
"source_file": str_path,
|
|
63
|
+
"source_location": f"L{line}",
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
def add_edge(src: str, tgt: str, relation: str, line: int,
|
|
67
|
+
confidence: str = "EXTRACTED", weight: float = 1.0) -> None:
|
|
68
|
+
edges.append({
|
|
69
|
+
"source": src,
|
|
70
|
+
"target": tgt,
|
|
71
|
+
"relation": relation,
|
|
72
|
+
"confidence": confidence,
|
|
73
|
+
"source_file": str_path,
|
|
74
|
+
"source_location": f"L{line}",
|
|
75
|
+
"weight": weight,
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
file_nid = _make_id(str(path))
|
|
79
|
+
add_node(file_nid, path.name, 1)
|
|
80
|
+
|
|
81
|
+
def ref_stub(name: str) -> str:
|
|
82
|
+
"""Mint a SOURCELESS stub for a cross-file reference target (an `open`ed
|
|
83
|
+
module or a call to a name not defined in this file). The corpus-level
|
|
84
|
+
rewire collapses it onto the unique real definition of that name;
|
|
85
|
+
external names (Stdlib, Core, ...) dangle and are pruned. A *sourced*
|
|
86
|
+
stub here would bake this file's path into the id and block the rewire
|
|
87
|
+
(the #1402 phantom-duplicate bug)."""
|
|
88
|
+
nid = _make_id(name)
|
|
89
|
+
if nid not in seen_ids:
|
|
90
|
+
seen_ids.add(nid)
|
|
91
|
+
nodes.append({
|
|
92
|
+
"id": nid,
|
|
93
|
+
"label": name,
|
|
94
|
+
"file_type": "code",
|
|
95
|
+
"source_file": "",
|
|
96
|
+
"source_location": "",
|
|
97
|
+
"origin_file": str_path,
|
|
98
|
+
})
|
|
99
|
+
return nid
|
|
100
|
+
|
|
101
|
+
def line_of(node) -> int:
|
|
102
|
+
return node.start_point[0] + 1
|
|
103
|
+
|
|
104
|
+
def named_child_text(node, child_type: str) -> str | None:
|
|
105
|
+
for child in node.children:
|
|
106
|
+
if child.type == child_type:
|
|
107
|
+
return _read_text(child, source)
|
|
108
|
+
return None
|
|
109
|
+
|
|
110
|
+
def last_name(path_node) -> str | None:
|
|
111
|
+
"""Final component of a *_path node: `Geo.area` -> `area`,
|
|
112
|
+
`Stdlib.List` -> `List`. The qualifier is nested under a child
|
|
113
|
+
`module_path`, so the final name is always a *direct* child of the path
|
|
114
|
+
node -- a deep search would wrongly return the module qualifier."""
|
|
115
|
+
found: str | None = None
|
|
116
|
+
for n in path_node.children:
|
|
117
|
+
if n.type in ("value_name", "module_name", "constructor_name"):
|
|
118
|
+
found = _read_text(n, source)
|
|
119
|
+
return found
|
|
120
|
+
|
|
121
|
+
def path_root_module(path_node) -> str | None:
|
|
122
|
+
"""Leftmost (outermost) module segment qualifying a *_path node:
|
|
123
|
+
`Reg_spec.create` -> `Reg_spec`, `Stdlib.List.map` -> `Stdlib`. Returns
|
|
124
|
+
None when the path is unqualified (`create`), which has no child
|
|
125
|
+
module_path."""
|
|
126
|
+
mp = next((c for c in path_node.children if c.type == "module_path"), None)
|
|
127
|
+
if mp is None:
|
|
128
|
+
return None
|
|
129
|
+
node = mp
|
|
130
|
+
while True:
|
|
131
|
+
inner = next((c for c in node.children if c.type == "module_path"), None)
|
|
132
|
+
if inner is None:
|
|
133
|
+
break
|
|
134
|
+
node = inner
|
|
135
|
+
mn = next((c for c in node.children if c.type == "module_name"), None)
|
|
136
|
+
return _read_text(mn, source) if mn is not None else None
|
|
137
|
+
|
|
138
|
+
def register_def(name: str, nid: str) -> None:
|
|
139
|
+
if name in ambiguous:
|
|
140
|
+
return
|
|
141
|
+
if name in local_defs and local_defs[name] != nid:
|
|
142
|
+
ambiguous.add(name)
|
|
143
|
+
local_defs.pop(name, None)
|
|
144
|
+
return
|
|
145
|
+
local_defs[name] = nid
|
|
146
|
+
|
|
147
|
+
def emit_type(binding, container_nid: str) -> None:
|
|
148
|
+
type_name = named_child_text(binding, "type_constructor")
|
|
149
|
+
if not type_name:
|
|
150
|
+
return
|
|
151
|
+
line = line_of(binding)
|
|
152
|
+
nid = _make_id(stem, type_name)
|
|
153
|
+
add_node(nid, type_name, line)
|
|
154
|
+
add_edge(container_nid, nid, "defines" if container_nid == file_nid else "contains", line)
|
|
155
|
+
register_def(type_name, nid)
|
|
156
|
+
# Variant constructors: variant_declaration -> constructor_declaration -> constructor_name
|
|
157
|
+
for vd in binding.children:
|
|
158
|
+
if vd.type != "variant_declaration":
|
|
159
|
+
continue
|
|
160
|
+
for cd in vd.children:
|
|
161
|
+
if cd.type != "constructor_declaration":
|
|
162
|
+
continue
|
|
163
|
+
cname = named_child_text(cd, "constructor_name")
|
|
164
|
+
if not cname:
|
|
165
|
+
continue
|
|
166
|
+
cnid = _make_id(stem, type_name, cname)
|
|
167
|
+
add_node(cnid, cname, line_of(cd))
|
|
168
|
+
add_edge(nid, cnid, "contains", line_of(cd))
|
|
169
|
+
|
|
170
|
+
def walk(node, container_nid: str, enclosing_value: str) -> None:
|
|
171
|
+
t = node.type
|
|
172
|
+
|
|
173
|
+
if t == "open_module":
|
|
174
|
+
mp = next((c for c in node.children if c.type == "module_path"), None)
|
|
175
|
+
name = last_name(mp) if mp is not None else None
|
|
176
|
+
if name:
|
|
177
|
+
add_edge(container_nid, ref_stub(name), "imports_from", line_of(node),
|
|
178
|
+
confidence="INFERRED")
|
|
179
|
+
return
|
|
180
|
+
|
|
181
|
+
if t == "module_definition":
|
|
182
|
+
binding = next((c for c in node.children if c.type == "module_binding"), None)
|
|
183
|
+
if binding is not None:
|
|
184
|
+
mname = named_child_text(binding, "module_name")
|
|
185
|
+
if mname:
|
|
186
|
+
line = line_of(node)
|
|
187
|
+
mnid = _make_id(stem, mname)
|
|
188
|
+
add_node(mnid, mname, line)
|
|
189
|
+
add_edge(container_nid, mnid,
|
|
190
|
+
"defines" if container_nid == file_nid else "contains", line)
|
|
191
|
+
register_def(mname, mnid)
|
|
192
|
+
local_modules.add(mname)
|
|
193
|
+
for child in binding.children:
|
|
194
|
+
walk(child, mnid, enclosing_value)
|
|
195
|
+
return
|
|
196
|
+
|
|
197
|
+
if t == "module_type_definition": # .mli
|
|
198
|
+
mname = named_child_text(node, "module_type_name")
|
|
199
|
+
if mname:
|
|
200
|
+
line = line_of(node)
|
|
201
|
+
mnid = _make_id(stem, mname)
|
|
202
|
+
add_node(mnid, mname, line)
|
|
203
|
+
add_edge(container_nid, mnid,
|
|
204
|
+
"defines" if container_nid == file_nid else "contains", line)
|
|
205
|
+
register_def(mname, mnid)
|
|
206
|
+
local_modules.add(mname)
|
|
207
|
+
for child in node.children:
|
|
208
|
+
walk(child, mnid, enclosing_value)
|
|
209
|
+
return
|
|
210
|
+
|
|
211
|
+
if t == "value_definition": # .ml
|
|
212
|
+
# Only structure/top-level bindings are real definitions. A local
|
|
213
|
+
# `let x = e in body` is also a value_definition, but nested under a
|
|
214
|
+
# let_expression; it must NOT mint a node or steal call attribution
|
|
215
|
+
# from the enclosing named function.
|
|
216
|
+
is_toplevel = node.parent is not None and node.parent.type in (
|
|
217
|
+
"compilation_unit", "structure")
|
|
218
|
+
for lb in node.children:
|
|
219
|
+
if lb.type != "let_binding":
|
|
220
|
+
continue
|
|
221
|
+
vname = named_child_text(lb, "value_name")
|
|
222
|
+
new_scope = enclosing_value
|
|
223
|
+
if vname and is_toplevel:
|
|
224
|
+
line = line_of(lb)
|
|
225
|
+
nid = _make_id(stem, vname)
|
|
226
|
+
add_node(nid, vname, line)
|
|
227
|
+
add_edge(container_nid, nid,
|
|
228
|
+
"defines" if container_nid == file_nid else "contains", line)
|
|
229
|
+
register_def(vname, nid)
|
|
230
|
+
new_scope = nid
|
|
231
|
+
# Descend into the body (unit/pattern/local bindings keep the
|
|
232
|
+
# outer scope) to collect nested definitions and call sites.
|
|
233
|
+
for child in lb.children:
|
|
234
|
+
walk(child, container_nid, new_scope)
|
|
235
|
+
return
|
|
236
|
+
|
|
237
|
+
if t == "value_specification": # .mli
|
|
238
|
+
vname = named_child_text(node, "value_name")
|
|
239
|
+
if vname:
|
|
240
|
+
line = line_of(node)
|
|
241
|
+
nid = _make_id(stem, vname)
|
|
242
|
+
add_node(nid, vname, line)
|
|
243
|
+
add_edge(container_nid, nid,
|
|
244
|
+
"defines" if container_nid == file_nid else "contains", line)
|
|
245
|
+
register_def(vname, nid)
|
|
246
|
+
return
|
|
247
|
+
|
|
248
|
+
if t == "type_definition":
|
|
249
|
+
for binding in node.children:
|
|
250
|
+
if binding.type == "type_binding":
|
|
251
|
+
emit_type(binding, container_nid)
|
|
252
|
+
return
|
|
253
|
+
|
|
254
|
+
if t == "application_expression":
|
|
255
|
+
fn = node.named_children[0] if node.named_children else None
|
|
256
|
+
if fn is not None and fn.type == "value_path":
|
|
257
|
+
callee = last_name(fn)
|
|
258
|
+
if callee:
|
|
259
|
+
caller = enclosing_value if enclosing_value else file_nid
|
|
260
|
+
call_sites.append((caller, callee, path_root_module(fn),
|
|
261
|
+
_read_text(fn, source), line_of(node)))
|
|
262
|
+
# Fall through: arguments may contain further applications/definitions.
|
|
263
|
+
|
|
264
|
+
for child in node.children:
|
|
265
|
+
walk(child, container_nid, enclosing_value)
|
|
266
|
+
|
|
267
|
+
walk(root, file_nid, "")
|
|
268
|
+
|
|
269
|
+
for caller, callee, qualifier, full_path, line in call_sites:
|
|
270
|
+
# A qualified call `M.f` where `M` is NOT a module defined in this file
|
|
271
|
+
# is an external-library call (e.g. `Reg_spec.create`). Binding it to a
|
|
272
|
+
# same-named local `f` would be a false edge (and a `create -> create`
|
|
273
|
+
# self-loop when the caller is that local `f`), so keep it distinct: a
|
|
274
|
+
# stub keyed by the FULL qualified name (`Reg_spec.create`) never
|
|
275
|
+
# collapses onto the local `f` in the corpus rewire. Unqualified calls,
|
|
276
|
+
# and qualified calls into a locally-defined module, still resolve to a
|
|
277
|
+
# local definition; a bare-name stub still allows the cross-file rewire
|
|
278
|
+
# to collapse `Geo.area` onto another file's `area` (#hardcaml).
|
|
279
|
+
if qualifier is not None and qualifier not in local_modules:
|
|
280
|
+
if callee in local_defs:
|
|
281
|
+
add_edge(caller, ref_stub(full_path), "calls", line, confidence="INFERRED")
|
|
282
|
+
else:
|
|
283
|
+
add_edge(caller, ref_stub(callee), "calls", line, confidence="INFERRED")
|
|
284
|
+
elif callee in local_defs:
|
|
285
|
+
add_edge(caller, local_defs[callee], "calls", line)
|
|
286
|
+
else:
|
|
287
|
+
add_edge(caller, ref_stub(callee), "calls", line, confidence="INFERRED")
|
|
288
|
+
|
|
289
|
+
return {"nodes": nodes, "edges": edges}
|