Files
graphify/graphify/extractors/blade.py
T
TheFedaikinandClaude Opus 4.8 b3ab221762 refactor(extract): begin per-language extractor split (#1212)
Move the blade/elixir/razor/zig extractors and the shared primitives
(_make_id, _file_stem, _read_text, _LANGUAGE_BUILTIN_GLOBALS) out of the
13k-line extract.py into a graphify/extractors/ package: base.py holds the
shared pieces, one module per language, and __init__ seeds a
LANGUAGE_EXTRACTORS registry for future dispatch. Import direction is strictly
extract.py -> extractors/ (extractors never import extract), so there is no
cycle. extract.py re-exports every moved name, leaving all callers and the
dispatch table unchanged.

Ported from PR #1291 by @TheFedaikin onto current v8 as a thin, behavior-neutral
slice (the PR itself was branched 31 commits behind and entangled with unrelated
files). Verified the moved code is byte-identical to current v8 before porting;
full suite 2393 passed, the zig/elixir/razor/blade extractor tests pass, ruff and
skillgen --check clean. Also gitignores .DS_Store.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 17:51:04 +01:00

54 lines
2.5 KiB
Python

"""Laravel Blade template extractor. Moved verbatim from graphify/extract.py."""
from __future__ import annotations
from pathlib import Path
from graphify.extractors.base import _make_id
def extract_blade(path: Path) -> dict:
"""Extract @include, <livewire:> components, and wire:click bindings from Blade templates."""
import re
try:
src = path.read_text(encoding="utf-8", errors="replace")
except OSError:
return {"error": f"cannot read {path}"}
file_nid = _make_id(str(path))
nodes = [{"id": file_nid, "label": path.name, "file_type": "code",
"source_file": str(path), "source_location": None}]
edges = []
# @include('path.to.partial') or @include("path.to.partial")
for m in re.finditer(r"@include\(['\"]([^'\"]+)['\"]", 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": "includes",
"confidence": "EXTRACTED", "confidence_score": 1.0,
"source_file": str(path), "source_location": None, "weight": 1.0})
# <livewire:component.name /> or <livewire:component.name>
for m in re.finditer(r"<livewire:([\w.\-]+)", src):
tgt_nid = _make_id(m.group(1))
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": "uses_component",
"confidence": "EXTRACTED", "confidence_score": 1.0,
"source_file": str(path), "source_location": None, "weight": 1.0})
# wire:click="methodName"
for m in re.finditer(r'wire:click=["\']([^"\']+)["\']', src):
tgt_nid = _make_id(m.group(1))
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": "binds_method",
"confidence": "EXTRACTED", "confidence_score": 1.0,
"source_file": str(path), "source_location": None, "weight": 1.0})
return {"nodes": nodes, "edges": edges}