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,196 @@
|
|
|
1
|
+
"""Pascal_forms extractor. Moved verbatim from graphify/extract.py."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
from graphify.extractors.base import _file_stem, _make_id
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def extract_lazarus_form(path: Path) -> dict:
|
|
11
|
+
"""Extract component hierarchy from Lazarus .lfm form files.
|
|
12
|
+
|
|
13
|
+
.lfm is a text-based declarative format for UI component trees, structured as:
|
|
14
|
+
object ComponentName: TClassName
|
|
15
|
+
PropertyName = Value
|
|
16
|
+
OnEvent = HandlerName
|
|
17
|
+
object ChildName: TChildClass
|
|
18
|
+
...
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
Produces nodes for:
|
|
23
|
+
- The form file itself
|
|
24
|
+
- Each component class encountered (TForm1, TButton, TPanel, ...)
|
|
25
|
+
- Event handler names referenced by OnXxx properties
|
|
26
|
+
|
|
27
|
+
Produces edges for:
|
|
28
|
+
- file --contains--> root form class
|
|
29
|
+
- parent component --contains--> child component class
|
|
30
|
+
- component --references--> event handler (context: "event")
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
text = path.read_text(encoding="utf-8", errors="replace")
|
|
34
|
+
except Exception as e:
|
|
35
|
+
return {"nodes": [], "edges": [], "error": str(e)}
|
|
36
|
+
|
|
37
|
+
import re
|
|
38
|
+
str_path = str(path)
|
|
39
|
+
stem = _file_stem(path)
|
|
40
|
+
nodes: list[dict] = []
|
|
41
|
+
edges: list[dict] = []
|
|
42
|
+
seen_ids: set[str] = set()
|
|
43
|
+
seen_edge_pairs: set[tuple[str, str, str]] = set()
|
|
44
|
+
|
|
45
|
+
def add_node(nid: str, label: str, line: int) -> None:
|
|
46
|
+
if nid not in seen_ids:
|
|
47
|
+
seen_ids.add(nid)
|
|
48
|
+
nodes.append({
|
|
49
|
+
"id": nid, "label": label, "file_type": "code",
|
|
50
|
+
"source_file": str_path, "source_location": f"L{line}",
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
def add_edge(
|
|
54
|
+
src: str, tgt: str, relation: str, line: int,
|
|
55
|
+
context: str | None = None,
|
|
56
|
+
) -> None:
|
|
57
|
+
key = (src, tgt, relation)
|
|
58
|
+
if key in seen_edge_pairs:
|
|
59
|
+
return
|
|
60
|
+
seen_edge_pairs.add(key)
|
|
61
|
+
edge: dict[str, Any] = {
|
|
62
|
+
"source": src, "target": tgt, "relation": relation,
|
|
63
|
+
"confidence": "EXTRACTED", "source_file": str_path,
|
|
64
|
+
"source_location": f"L{line}", "weight": 1.0,
|
|
65
|
+
}
|
|
66
|
+
if context:
|
|
67
|
+
edge["context"] = context
|
|
68
|
+
edges.append(edge)
|
|
69
|
+
|
|
70
|
+
file_nid = _make_id(str(path))
|
|
71
|
+
add_node(file_nid, path.name, 1)
|
|
72
|
+
|
|
73
|
+
obj_re = re.compile(r"^\s*object\s+\w+\s*:\s*(\w+)", re.IGNORECASE)
|
|
74
|
+
event_re = re.compile(r"^\s*On\w+\s*=\s*(\w+)", re.IGNORECASE)
|
|
75
|
+
end_re = re.compile(r"^\s*end\s*$", re.IGNORECASE)
|
|
76
|
+
|
|
77
|
+
# Stack of node IDs representing the nesting of object...end blocks
|
|
78
|
+
stack: list[str] = [file_nid]
|
|
79
|
+
|
|
80
|
+
for lineno, line in enumerate(text.splitlines(), 1):
|
|
81
|
+
m = obj_re.match(line)
|
|
82
|
+
if m:
|
|
83
|
+
class_name = m.group(1)
|
|
84
|
+
nid = _make_id(stem, class_name)
|
|
85
|
+
add_node(nid, class_name, lineno)
|
|
86
|
+
add_edge(stack[-1], nid, "contains", lineno)
|
|
87
|
+
stack.append(nid)
|
|
88
|
+
continue
|
|
89
|
+
|
|
90
|
+
m = event_re.match(line)
|
|
91
|
+
if m and len(stack) > 1:
|
|
92
|
+
handler = m.group(1)
|
|
93
|
+
handler_nid = _make_id(stem, handler)
|
|
94
|
+
add_node(handler_nid, f"{handler}()", lineno)
|
|
95
|
+
add_edge(stack[-1], handler_nid, "references", lineno, context="event")
|
|
96
|
+
continue
|
|
97
|
+
|
|
98
|
+
if end_re.match(line) and len(stack) > 1:
|
|
99
|
+
stack.pop()
|
|
100
|
+
|
|
101
|
+
return {"nodes": nodes, "edges": edges, "input_tokens": 0, "output_tokens": 0}
|
|
102
|
+
|
|
103
|
+
def extract_delphi_form(path: Path) -> dict:
|
|
104
|
+
"""Extract component hierarchy from Delphi .dfm form files.
|
|
105
|
+
|
|
106
|
+
.dfm files come in two formats:
|
|
107
|
+
- Text (same `object Name: TClassName ... end` syntax as .lfm)
|
|
108
|
+
- Binary (starts with a TPF0/FF0A magic header — unreadable as text)
|
|
109
|
+
|
|
110
|
+
Binary .dfm files are skipped gracefully: an empty result is returned
|
|
111
|
+
so the rest of the pipeline is unaffected. Convert binary forms to
|
|
112
|
+
text in the Delphi IDE via File → Save As (Text DFM) if you want them
|
|
113
|
+
indexed.
|
|
114
|
+
|
|
115
|
+
Text .dfm files are parsed identically to .lfm: component containment
|
|
116
|
+
(`contains`) and event handler references (`references`, context "event").
|
|
117
|
+
"""
|
|
118
|
+
try:
|
|
119
|
+
raw = path.read_bytes()
|
|
120
|
+
except Exception as e:
|
|
121
|
+
return {"nodes": [], "edges": [], "error": str(e)}
|
|
122
|
+
|
|
123
|
+
# Detect binary DFM: Delphi binary resource streams start with FF 0A
|
|
124
|
+
if raw[:2] == b"\xff\x0a":
|
|
125
|
+
return {
|
|
126
|
+
"nodes": [], "edges": [],
|
|
127
|
+
"error": f"binary DFM (convert to text in Delphi IDE to index): {path.name}",
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
# Text DFM — delegate to the shared form parser (same syntax as .lfm)
|
|
131
|
+
try:
|
|
132
|
+
text = raw.decode("utf-8", errors="replace")
|
|
133
|
+
except Exception as e:
|
|
134
|
+
return {"nodes": [], "edges": [], "error": str(e)}
|
|
135
|
+
|
|
136
|
+
import re
|
|
137
|
+
str_path = str(path)
|
|
138
|
+
stem = _file_stem(path)
|
|
139
|
+
nodes: list[dict] = []
|
|
140
|
+
edges: list[dict] = []
|
|
141
|
+
seen_ids: set[str] = set()
|
|
142
|
+
seen_edge_pairs: set[tuple[str, str, str]] = set()
|
|
143
|
+
|
|
144
|
+
def add_node(nid: str, label: str, line: int) -> None:
|
|
145
|
+
if nid not in seen_ids:
|
|
146
|
+
seen_ids.add(nid)
|
|
147
|
+
nodes.append({
|
|
148
|
+
"id": nid, "label": label, "file_type": "code",
|
|
149
|
+
"source_file": str_path, "source_location": f"L{line}",
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
def add_edge(
|
|
153
|
+
src: str, tgt: str, relation: str, line: int,
|
|
154
|
+
context: str | None = None,
|
|
155
|
+
) -> None:
|
|
156
|
+
key = (src, tgt, relation)
|
|
157
|
+
if key in seen_edge_pairs:
|
|
158
|
+
return
|
|
159
|
+
seen_edge_pairs.add(key)
|
|
160
|
+
edge: dict[str, Any] = {
|
|
161
|
+
"source": src, "target": tgt, "relation": relation,
|
|
162
|
+
"confidence": "EXTRACTED", "source_file": str_path,
|
|
163
|
+
"source_location": f"L{line}", "weight": 1.0,
|
|
164
|
+
}
|
|
165
|
+
if context:
|
|
166
|
+
edge["context"] = context
|
|
167
|
+
edges.append(edge)
|
|
168
|
+
|
|
169
|
+
file_nid = _make_id(str(path))
|
|
170
|
+
add_node(file_nid, path.name, 1)
|
|
171
|
+
|
|
172
|
+
obj_re = re.compile(r"^\s*object\s+\w+\s*:\s*(\w+)", re.IGNORECASE)
|
|
173
|
+
event_re = re.compile(r"^\s*On\w+\s*=\s*(\w+)", re.IGNORECASE)
|
|
174
|
+
end_re = re.compile(r"^\s*end\s*$", re.IGNORECASE)
|
|
175
|
+
stack: list[str] = [file_nid]
|
|
176
|
+
|
|
177
|
+
for lineno, line in enumerate(text.splitlines(), 1):
|
|
178
|
+
m = obj_re.match(line)
|
|
179
|
+
if m:
|
|
180
|
+
class_name = m.group(1)
|
|
181
|
+
nid = _make_id(stem, class_name)
|
|
182
|
+
add_node(nid, class_name, lineno)
|
|
183
|
+
add_edge(stack[-1], nid, "contains", lineno)
|
|
184
|
+
stack.append(nid)
|
|
185
|
+
continue
|
|
186
|
+
m = event_re.match(line)
|
|
187
|
+
if m and len(stack) > 1:
|
|
188
|
+
handler = m.group(1)
|
|
189
|
+
handler_nid = _make_id(stem, handler)
|
|
190
|
+
add_node(handler_nid, f"{handler}()", lineno)
|
|
191
|
+
add_edge(stack[-1], handler_nid, "references", lineno, context="event")
|
|
192
|
+
continue
|
|
193
|
+
if end_re.match(line) and len(stack) > 1:
|
|
194
|
+
stack.pop()
|
|
195
|
+
|
|
196
|
+
return {"nodes": nodes, "edges": edges, "input_tokens": 0, "output_tokens": 0}
|