mirror of
https://github.com/safishamsi/graphify.git
synced 2026-07-12 10:27:11 +00:00
v8
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
d2d1f68ff9 |
fix: surface silently-skipped dirs in enumeration + dedup Pascal edges
Two correctness fixes found while analysing the reported 'graphify update occasionally writes a partial graph.json' bug. Enumeration (P0): detect()'s os.walk had no onerror handler, so any os.scandir failure -- a transient PermissionError, or a directory created/deleted mid-walk by concurrent writes (e.g. benchmarking racing the scan) -- was silently swallowed and that entire subtree dropped out of the file list with no log, no error. Downstream that becomes a silently partial graph.json. The walk now records each skipped directory (surfaced as walk_errors in detect()'s result) and warns to stderr, while still enumerating the rest of the tree. This stays visible even when a --force/GRAPHIFY_FORCE rebuild bypasses the shrink guards. Relatedly, to_json's #479 anti-shrink guard was fail-OPEN: a non-empty but unreadable existing graph.json (corrupt or mid-write) proceeded with the overwrite. It now fails SAFE -- refuse and point at force=True -- while an empty/whitespace existing file (no nodes to lose) still proceeds. The size-cap check keeps running before any read, so an oversized existing file is not loaded into memory. Pascal edges (P1): a class method declared in the interface section and defined in the implementation section each emitted a "method" edge to the same node id, and the edge helpers (unlike the node helpers) did not dedup, so ~half of a Pascal/Delphi graph's method edges were doubled -- inflating degree/centrality and tripping the #1739 cross-file resolver's single-owner god-node guard. Both extractors now dedup edges on (source, target, relation). Adds regression tests for all three behaviours. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
8e6483511d |
add Pascal regex fallback - extraction works without tree-sitter-pascal
tree-sitter-pascal is not on PyPI so extract_pascal() fell back to an empty error result for all users. _extract_pascal_regex() now handles unit/program/library headers, uses clauses, class/interface declarations with inheritance, forward method decls, qualified impl headers, balanced begin/end body extraction, and intra-file calls edges. All 15 previously skipped pascal_required tests now run unconditionally and pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
32bf8b4a37 |
feat(extract): add Pascal/Delphi and Lazarus IDE support (#781)
* feat(extract): add Pascal/Delphi language support Adds full AST extraction for Pascal and Delphi source files using tree-sitter-pascal (https://github.com/Isopod/tree-sitter-pascal). Supported file extensions: .pas, .pp, .dpr, .dpk, .inc Extracted nodes: - File node (the .pas file itself) - unit / program / library declarations - class, interface, and helper type declarations - procedure and function implementations Extracted edges: - file --contains--> module - module --imports--> dependency (via uses clause, resolved to path-based IDs) - class --inherits--> base class / interface - class/module --contains/method--> procedure or function - procedure --calls--> procedure (in-file call resolution) Key design: uses clause targets are resolved to path-based node IDs by scanning all Pascal files under the project root (_pascal_project_root + _pascal_resolve_unit helpers). This avoids dangling import edges that result from resolving bare unit names like "SysUtils" to IDs that never match any file node. Bare procedure calls (e.g. `Reset;` without parentheses) are detected by inspecting statement nodes whose sole named child is an identifier, in addition to the standard exprCall nodes used for calls with arguments. Requires: pip install tree-sitter-pascal (https://github.com/Isopod/tree-sitter-pascal) If not installed, extract_pascal returns {"nodes":[], "edges":[], "error": ...} so the rest of the pipeline is unaffected. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(extract): add Lazarus .lfm and .lpk file support Adds two new extractors for Lazarus IDE-specific file formats: extract_lazarus_form() — .lfm (Lazarus Form files) .lfm files are text-based UI component trees. The extractor parses `object Name: TClassName ... end` blocks to build a containment graph of form components, and captures `OnXxx = HandlerName` event bindings as `references` edges (context: "event") linking each component to its handler procedure. extract_lazarus_package() — .lpk (Lazarus Package files) .lpk files are XML package definitions. The extractor reads the package name, required package dependencies (→ imports edges), and listed unit files (→ contains edges). Unit names are resolved to path-based node IDs via _pascal_resolve_unit so they connect to the same nodes produced by extract_pascal on .pas files. Both extensions added to CODE_EXTENSIONS in detect.py and to _DISPATCH. 13 new tests in test_pascal.py cover both extractors. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(pascal): fix dangling inherits-edge targets and capture all base classes The declType/typeref handler built inherits edge targets with _make_id(_read(child)) — just the bare class name. But class nodes use _make_id(stem, type_name), so targets never matched, making the entire class hierarchy invisible in the graph. Add _pascal_class_stem_cache and _pascal_resolve_class(): strips the conventional T/I prefix, locates the defining file by stem lookup (same cache mechanism as _pascal_resolve_unit), and returns the correct _make_id(file_stem, class_name) ID. RTL/unresolvable bases (e.g. TObject) fall back to _make_id(bare_name) with an explicit stub node, following the same pattern as the Python extractor. Also remove the `break` that stopped after the first typeref, so all parents are captured (e.g. class(TBase, IInterface)). Extend test_pascal_no_dangling_edges to also assert that within-file edge targets (contains, method, inherits, calls) resolve to real nodes. * feat(extract): add Delphi .dfm form file support Adds extract_delphi_form() for Delphi Form files (.dfm), which use the same `object Name: TClassName ... end` text syntax as Lazarus .lfm files. Binary .dfm files (FF 0A magic header) are skipped gracefully with an informative error message so the pipeline is unaffected. Text .dfm files are parsed identically to .lfm: component containment (`contains` edges) and event handler references (`references`, context "event"). Adds .dfm to _DISPATCH and CODE_EXTENSIONS. 10 new tests in test_pascal.py, including a regression test for the binary-format detection. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add .lpr extension and fix removesuffix in Pascal extractor Address review feedback from @safishamsi: - Add .lpr (Lazarus program file, identical syntax to .dpr) to _DISPATCH in extract.py and CODE_EXTENSIONS in detect.py so Lazarus project entry points are indexed. Completes the promised Lazarus IDE support. - Replace rstrip("()") with removesuffix("()") in the call-resolution dict comprehension for precise suffix removal (rstrip strips individual characters, not the literal string "()"). - Add .lpr assertions to test_pascal_dispatch_registered and test_pascal_detect_extensions_registered. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Simeon Bodurov <simeon.bodurov@speedy.bg> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |