diff --git a/graphify/detect.py b/graphify/detect.py index 630c638f..a7a31b5d 100644 --- a/graphify/detect.py +++ b/graphify/detect.py @@ -24,7 +24,7 @@ class FileType(str, Enum): _MANIFEST_PATH = "graphify-out/manifest.json" -CODE_EXTENSIONS = {'.py', '.ts', '.js', '.jsx', '.tsx', '.mjs', '.ejs', '.go', '.rs', '.java', '.groovy', '.gradle', '.cpp', '.cc', '.cxx', '.c', '.h', '.hpp', '.rb', '.swift', '.kt', '.kts', '.cs', '.scala', '.php', '.lua', '.luau', '.toc', '.zig', '.ps1', '.ex', '.exs', '.m', '.mm', '.jl', '.vue', '.svelte', '.dart', '.v', '.sv', '.sql', '.r', '.f', '.F', '.f90', '.F90', '.f95', '.F95', '.f03', '.F03', '.f08', '.F08', '.pas', '.pp', '.dpr', '.dpk', '.lpr', '.inc', '.dfm', '.lfm', '.lpk'} +CODE_EXTENSIONS = {'.py', '.ts', '.js', '.jsx', '.tsx', '.mjs', '.ejs', '.go', '.rs', '.java', '.groovy', '.gradle', '.cpp', '.cc', '.cxx', '.c', '.h', '.hpp', '.rb', '.swift', '.kt', '.kts', '.cs', '.scala', '.php', '.lua', '.luau', '.toc', '.zig', '.ps1', '.ex', '.exs', '.m', '.mm', '.jl', '.vue', '.svelte', '.astro', '.dart', '.v', '.sv', '.sql', '.r', '.f', '.F', '.f90', '.F90', '.f95', '.F95', '.f03', '.F03', '.f08', '.F08', '.pas', '.pp', '.dpr', '.dpk', '.lpr', '.inc', '.dfm', '.lfm', '.lpk'} DOC_EXTENSIONS = {'.md', '.mdx', '.qmd', '.txt', '.rst', '.html', '.yaml', '.yml'} PAPER_EXTENSIONS = {'.pdf'} IMAGE_EXTENSIONS = {'.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg'} diff --git a/graphify/extract.py b/graphify/extract.py index 80da56ad..fe2916ff 100644 --- a/graphify/extract.py +++ b/graphify/extract.py @@ -2123,6 +2123,142 @@ def extract_svelte(path: Path) -> dict: return result +def extract_astro(path: Path) -> dict: + """Extract imports from .astro files: frontmatter (TS) + template regex fallback. + + Astro files start with a ``---\\n...\\n---`` frontmatter block of TypeScript + setup code (where almost all imports live), followed by an HTML-with-expressions + template body, and optionally `` +""", + ) + layout = _write(tmp_path / "src/layouts/Layout.astro", "---\n---\n\n") + hydrate = _write(tmp_path / "src/client/hydrate.ts", "export function hydrate(){}\n") + + result = extract_astro(page) + targets = _import_targets(result, relation="imports_from") + assert _make_id(str(layout)) in targets + assert _make_id(str(hydrate)) in targets + + +def test_extract_astro_no_frontmatter_does_not_crash(tmp_path): + """Astro permits frontmatter-less files (pure-HTML pages). Must not raise.""" + page = _write( + tmp_path / "src/pages/plain.astro", + "

no frontmatter here

\n", + ) + result = extract_astro(page) + # Empty/no-imports result is acceptable; the extractor must just not crash. + assert isinstance(result, dict) + assert _import_targets(result, relation="imports_from") == set() + + +def test_extract_astro_handles_tsconfig_path_alias(tmp_path): + _write( + tmp_path / "tsconfig.json", + """{ + "compilerOptions": { + "baseUrl": ".", + "paths": { "@components/*": ["src/components/*"] } + } +} +""", + ) + page = _write( + tmp_path / "src/pages/alias.astro", + """--- +import Hero from '@components/Hero.astro'; +--- + + +""", + ) + hero = _write(tmp_path / "src/components/Hero.astro", "---\n---\n

h

\n") + + result = extract_astro(page) + targets = _import_targets(result, relation="imports_from") + assert _make_id(str(hero)) in targets