mirror of
https://github.com/safishamsi/graphify.git
synced 2026-10-13 07:29:33 +00:00
fix(blade): link a view to the layout it @extends
The Blade extractor recognised @include, <livewire:> components, and
wire:click bindings, but not @extends. Template inheritance is the primary
structural relationship in a Blade view — most page templates render inside
a layout via @extends('layouts.app') — so the child was left with no edge
to its parent layout in the graph.
Emit an 'extends' edge from the view to the named layout, mirroring the
existing @include handling (dotted view name -> path). Adds the first test
coverage for the Blade extractor.
(cherry picked from commit efeeeefa53)
This commit is contained in:
1 parent
4f6a4efd1f
commit
494c08452c
2 files changed
+48
-1
No files matched your search
@@ -7,7 +7,7 @@ from graphify.extractors.base import _make_id
|
||||
|
||||
|
||||
def extract_blade(path: Path) -> dict:
|
||||
"""Extract @include, <livewire:> components, and wire:click bindings from Blade templates."""
|
||||
"""Extract @extends, @include, <livewire:> components, and wire:click bindings from Blade templates."""
|
||||
import re
|
||||
try:
|
||||
src = path.read_text(encoding="utf-8", errors="replace")
|
||||
@@ -19,6 +19,20 @@ def extract_blade(path: Path) -> dict:
|
||||
"source_file": str(path), "source_location": None}]
|
||||
edges = []
|
||||
|
||||
# @extends('layouts.app') — template inheritance: this view renders inside
|
||||
# the named parent layout. It is the primary structural relationship in a
|
||||
# Blade view (most page templates extend a layout), so dropping it left the
|
||||
# child disconnected from its layout in the graph.
|
||||
for m in re.finditer(r"@extends\(['\"]([^'\"]+)['\"]", src):
|
||||
tgt = m.group(1).replace(".", "/")
|
||||
tgt_nid = _make_id(tgt)
|
||||
if tgt_nid not in {n["id"] for n in nodes}:
|
||||
nodes.append({"id": tgt_nid, "label": m.group(1), "file_type": "code",
|
||||
"source_file": str(path), "source_location": None})
|
||||
edges.append({"source": file_nid, "target": tgt_nid, "relation": "extends",
|
||||
"confidence": "EXTRACTED", "confidence_score": 1.0,
|
||||
"source_file": str(path), "source_location": None, "weight": 1.0})
|
||||
|
||||
# @include('path.to.partial') or @include("path.to.partial")
|
||||
for m in re.finditer(r"@include\(['\"]([^'\"]+)['\"]", src):
|
||||
tgt = m.group(1).replace(".", "/")
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
"""Extraction coverage for Laravel Blade templates."""
|
||||
from __future__ import annotations
|
||||
|
||||
from graphify.extract import extract
|
||||
|
||||
|
||||
def _edge_labels(result: dict, relation: str) -> set[tuple[str, str]]:
|
||||
labels = {node["id"]: node["label"] for node in result["nodes"]}
|
||||
return {
|
||||
(labels.get(edge["source"], edge["source"]), labels.get(edge["target"], edge["target"]))
|
||||
for edge in result["edges"]
|
||||
if edge["relation"] == relation
|
||||
}
|
||||
|
||||
|
||||
def test_blade_extends_links_view_to_its_layout(tmp_path):
|
||||
# @extends is template inheritance — the primary structural relationship in a
|
||||
# Blade view. Before the fix only @include was recognised, so a page that
|
||||
# extends a layout produced no edge to that layout at all.
|
||||
page = tmp_path / "page.blade.php"
|
||||
page.write_text(
|
||||
"@extends('layouts.app')\n"
|
||||
"@section('content')\n"
|
||||
" @include('partials.nav')\n"
|
||||
"@endsection\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
result = extract([page], cache_root=tmp_path)
|
||||
|
||||
assert ("page.blade.php", "layouts.app") in _edge_labels(result, "extends")
|
||||
# existing @include behaviour is preserved
|
||||
assert ("page.blade.php", "partials.nav") in _edge_labels(result, "includes")
|
||||
Reference in new issue
Block a user