Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ To remove graphify from all platforms at once: `graphify uninstall` (add `--purg
| Code (37 tree-sitter grammars) | `.py .ts .mts .cts .js .jsx .tsx .mjs .go .rs .java .c .cpp .cc .cxx .h .hpp .cu .cuh .metal .rb .cs .kt .kts .scala .php .swift .lua .luau .toc .zig .ps1 .psm1 .psd1 .ex .exs .m .mm .ml .mli .jl .vue .svelte .astro .groovy .gradle .dart .v .sv .svh .sql .f .f90 .f95 .f03 .f08 .pas .pp .dpr .dpk .lpr .inc .dfm .lfm .lpk .sh .bash .json .dm .dme .dmi .dmm .dmf .sln .slnx .csproj .fsproj .vbproj .xaml .razor .cshtml` (`.dm`/`.dme` requires `uv tool install graphifyy[dm]`, `.ml`/`.mli` requires `uv tool install graphifyy[ocaml]`; `.mts`/`.cts` reuse the TypeScript grammar, `.cc`/`.cxx` and CUDA `.cu`/`.cuh` and Metal `.metal` reuse the C++ grammar) |
| Salesforce Apex | `.cls .trigger` (regex-based; classes, interfaces, enums, methods, triggers, SOQL/DML edges) |
| Terraform / HCL | `.tf .tfvars .hcl` (requires `uv tool install graphifyy[terraform]`) |
| Jenkins Pipeline | `Jenkinsfile` (Groovy DSL; extracts pipelines, stages, parallel branches, steps, functions, and Docker image facts) |
| OCaml | `.ml .mli` (requires `uv tool install graphifyy[ocaml]`) |
| MCP configs | `.mcp.json` `mcp.json` `mcp_servers.json` `claude_desktop_config.json` — extracts server nodes, package refs, env var requirements |
| Package manifests | `apm.yml` `pyproject.toml` `go.mod` `pom.xml` — one canonical package node per package (by name) plus `depends_on` edges, so a package referenced from many manifests is a single hub |
Expand Down
4 changes: 4 additions & 0 deletions graphify/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,10 @@ def classify_file(path: Path) -> FileType | None:
from graphify.manifest_ingest import is_package_manifest_path
if is_package_manifest_path(path):
return FileType.CODE
# Jenkins Pipeline files are conventionally extensionless, so they need a
# filename-based route before the generic shebang/suffix checks.
if path.name.lower() == "jenkinsfile":
return FileType.CODE
# Compound extensions must be checked before simple suffix lookup
if path.name.lower().endswith(".blade.php"):
return FileType.CODE
Expand Down
9 changes: 7 additions & 2 deletions graphify/extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
from graphify.extractors.fortran import _cpp_preprocess, extract_fortran # noqa: F401
from graphify.extractors.go import _GO_PREDECLARED_FUNCS, extract_go # noqa: F401
from graphify.extractors.json_config import extract_json # noqa: F401
from graphify.extractors.jenkins import extract_jenkinsfile # noqa: F401
from graphify.extractors.markdown import extract_markdown # noqa: F401
from graphify.extractors.ocaml import extract_ocaml # noqa: F401
from graphify.extractors.pascal_forms import extract_delphi_form, extract_lazarus_form # noqa: F401
Expand Down Expand Up @@ -4989,6 +4990,8 @@ def _is_cpp_header(path: Path) -> bool:

def _get_extractor(path: Path) -> Any | None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regression_get_extractor()

fans out to 6 callees (efferent coupling); 29 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

"""Return the correct extractor function for a file, or None if unsupported."""
if path.name.lower() == "jenkinsfile":
return extract_jenkinsfile
if path.name.lower().endswith(".blade.php"):
return extract_blade
# MCP config files (.mcp.json, claude_desktop_config.json, ...) are routed
Expand Down Expand Up @@ -6685,7 +6688,8 @@ def _ignored(p: Path) -> bool:
for fname in filenames:
p = dp / fname
suffix = p.suffix
if (suffix in _EXTENSIONS or suffix.lower() in _EXTENSIONS) and not _ignored(p) and _resolves_under_root(p, containment_root):
is_jenkinsfile = p.name.lower() == "jenkinsfile"
if (is_jenkinsfile or suffix in _EXTENSIONS or suffix.lower() in _EXTENSIONS) and not _ignored(p) and _resolves_under_root(p, containment_root):
results.append(p)
return sorted(results)
# Walk with symlink following + cycle detection
Expand All @@ -6706,7 +6710,8 @@ def _ignored(p: Path) -> bool:
for fname in filenames:
p = dp / fname
suffix = p.suffix
if (suffix in _EXTENSIONS or suffix.lower() in _EXTENSIONS) and not _ignored(p) and _resolves_under_root(p, containment_root):
is_jenkinsfile = p.name.lower() == "jenkinsfile"
if (is_jenkinsfile or suffix in _EXTENSIONS or suffix.lower() in _EXTENSIONS) and not _ignored(p) and _resolves_under_root(p, containment_root):
results.append(p)
return sorted(results)

Expand Down
2 changes: 2 additions & 0 deletions graphify/extractors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from graphify.extractors.fortran import extract_fortran
from graphify.extractors.go import extract_go
from graphify.extractors.json_config import extract_json
from graphify.extractors.jenkins import extract_jenkinsfile
from graphify.extractors.julia import extract_julia
from graphify.extractors.markdown import extract_markdown
from graphify.extractors.objc import extract_objc
Expand Down Expand Up @@ -47,6 +48,7 @@
"fortran": extract_fortran,
"go": extract_go,
"json": extract_json,
"jenkinsfile": extract_jenkinsfile,
"julia": extract_julia,
"lazarus_form": extract_lazarus_form,
"markdown": extract_markdown,
Expand Down
Loading