"""Detect the language of a changed file from its path.""" from __future__ import annotations from pathlib import PurePosixPath SOURCE_EXTENSIONS: dict[str, str] = { ".py": "python", ".js": "javascript", ".jsx": "javascript", ".mjs": "javascript", ".cjs": "javascript", ".ts": "typescript", ".tsx": "typescript", ".cs": "csharp", ".lua": "lua", ".ps1": "powershell", ".psm1": "powershell", ".psd1": "powershell", } DEP_MANIFESTS: set[str] = { "requirements.txt", "pyproject.toml", "poetry.lock", "Pipfile.lock", "Pipfile", "setup.py", "setup.cfg", "package.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml", "packages.config", } DEP_MANIFEST_PREFIXES: tuple[str, ...] = ("requirements",) DEP_MANIFEST_EXTENSIONS: tuple[str, ...] = (".csproj", ".sln") KNOWN_UNSUPPORTED_LANGUAGES: dict[str, str] = { ".go": "Go", ".rb": "Ruby", ".java": "Java", ".kt": "Kotlin", ".kts": "Kotlin", ".rs": "Rust", ".swift": "Swift", ".php": "PHP", ".scala": "Scala", ".sc": "Scala", ".clj": "Clojure", ".cljs": "ClojureScript", ".ex": "Elixir", ".exs": "Elixir", ".erl": "Erlang", ".hrl": "Erlang", ".dart": "Dart", ".r": "R", ".jl": "Julia", ".zig": "Zig", ".nim": "Nim", ".hs": "Haskell", ".ml": "OCaml", ".mli": "OCaml", ".fs": "F#", ".fsi": "F#", ".fsx": "F#", ".vb": "Visual Basic", ".pl": "Perl", ".pm": "Perl", ".c": "C", ".h": "C/C++ header", ".cpp": "C++", ".cc": "C++", ".cxx": "C++", ".hpp": "C++", ".m": "Objective-C", ".mm": "Objective-C++", ".groovy": "Groovy", } _GHA_YAML_EXTS: frozenset[str] = frozenset((".yml", ".yaml")) _GHA_PATH_PREFIXES: tuple[str, ...] = (".github/workflows/", ".github/actions/") def detect_language(path: str) -> str | None: suffix = PurePosixPath(path).suffix return SOURCE_EXTENSIONS.get(suffix) def is_supported_source(path: str) -> bool: return detect_language(path) is not None def is_gha_file(path: str) -> bool: """Return True if path is a GitHub Actions workflow or action definition.""" normalized = path.replace("\\", "/") if PurePosixPath(normalized).suffix.lower() not in _GHA_YAML_EXTS: return False return normalized.startswith(_GHA_PATH_PREFIXES) def known_unsupported_language(path: str) -> str | None: """Return the display name of a recognized-but-unsupported source language, or None if the path isn't one we recognize as source code. """ suffix = PurePosixPath(path).suffix.lower() return KNOWN_UNSUPPORTED_LANGUAGES.get(suffix) def is_dep_manifest(path: str) -> bool: name = PurePosixPath(path).name if name in DEP_MANIFESTS: return True if any(name.startswith(p) and name.endswith(".txt") for p in DEP_MANIFEST_PREFIXES): return True return any(name.endswith(ext) for ext in DEP_MANIFEST_EXTENSIONS)