Skip to content
Closed
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
15 changes: 5 additions & 10 deletions graphify/analyze.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Graph analysis: god nodes (most connected), surprising connections (cross-community), suggested questions."""
from __future__ import annotations
import networkx as nx
from .detect import CODE_EXTENSIONS, DOC_EXTENSIONS, PAPER_EXTENSIONS, IMAGE_EXTENSIONS


def _node_community_map(communities: dict[int, list[str]]) -> dict[str, int]:
Expand Down Expand Up @@ -109,19 +110,13 @@ def _is_concept_node(G: nx.Graph, node_id: str) -> bool:
return False


_CODE_EXTENSIONS = {"py", "ts", "tsx", "js", "go", "rs", "java", "rb", "cpp", "c", "h", "cs", "kt", "scala", "php"}
_DOC_EXTENSIONS = {"md", "txt", "rst"}
_PAPER_EXTENSIONS = {"pdf"}
_IMAGE_EXTENSIONS = {"png", "jpg", "jpeg", "webp", "gif", "svg"}


def _file_category(path: str) -> str:
ext = path.rsplit(".", 1)[-1].lower() if "." in path else ""
if ext in _CODE_EXTENSIONS:
ext = ("." + path.rsplit(".", 1)[-1].lower()) if "." in path else ""
if ext in CODE_EXTENSIONS:
return "code"
if ext in _PAPER_EXTENSIONS:
if ext in PAPER_EXTENSIONS:
return "paper"
if ext in _IMAGE_EXTENSIONS:
if ext in IMAGE_EXTENSIONS:
return "image"
return "doc"

Expand Down
17 changes: 0 additions & 17 deletions graphify/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,23 +52,6 @@ def _partition(G: nx.Graph) -> dict[str, int]:
return {node: cid for cid, nodes in enumerate(communities) for node in nodes}


def build_graph(nodes: list[dict], edges: list[dict]) -> nx.Graph:
"""Build a NetworkX graph from graphify node/edge dicts.

Preserves original edge direction as _src/_tgt attributes so that
display functions can show relationships in the correct direction,
even though the graph is undirected for structural analysis.
"""
G = nx.Graph()
for n in nodes:
G.add_node(n["id"], **{k: v for k, v in n.items() if k != "id"})
for e in edges:
attrs = {k: v for k, v in e.items() if k not in ("source", "target")}
attrs["_src"] = e["source"]
attrs["_tgt"] = e["target"]
G.add_edge(e["source"], e["target"], **attrs)
return G

_MAX_COMMUNITY_FRACTION = 0.25 # communities larger than 25% of graph get split
_MIN_SPLIT_SIZE = 10 # only split if community has at least this many nodes

Expand Down
15 changes: 3 additions & 12 deletions graphify/watch.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,10 @@
import json
import time
from pathlib import Path
from .detect import CODE_EXTENSIONS, DOC_EXTENSIONS, PAPER_EXTENSIONS, IMAGE_EXTENSIONS


_WATCHED_EXTENSIONS = {
".py", ".ts", ".js", ".go", ".rs", ".java", ".cpp", ".c", ".rb", ".swift", ".kt",
".cs", ".scala", ".php", ".cc", ".cxx", ".hpp", ".h", ".kts",
".md", ".txt", ".rst", ".pdf",
".png", ".jpg", ".jpeg", ".webp", ".gif", ".svg",
}

_CODE_EXTENSIONS = {
".py", ".ts", ".js", ".go", ".rs", ".java", ".cpp", ".c", ".rb", ".swift", ".kt",
".cs", ".scala", ".php", ".cc", ".cxx", ".hpp", ".h", ".kts",
}
_WATCHED_EXTENSIONS = CODE_EXTENSIONS | DOC_EXTENSIONS | PAPER_EXTENSIONS | IMAGE_EXTENSIONS
_CODE_EXTENSIONS = CODE_EXTENSIONS


def _rebuild_code(watch_path: Path, *, follow_symlinks: bool = False) -> bool:
Expand Down
9 changes: 9 additions & 0 deletions tests/test_analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,15 @@ def test_file_category():
assert _file_category("flash.pdf") == "paper"
assert _file_category("diagram.png") == "image"
assert _file_category("notes.md") == "doc"
# Languages that were previously misclassified as "doc"
assert _file_category("main.swift") == "code"
assert _file_category("lib.lua") == "code"
assert _file_category("build.zig") == "code"
assert _file_category("script.ps1") == "code"
assert _file_category("app.ex") == "code"
assert _file_category("view.jsx") == "code"
assert _file_category("solver.jl") == "code"
assert _file_category("bridge.m") == "code"


def test_is_concept_node_empty_source():
Expand Down