mirror of
https://github.com/unclebob/crapper.git
synced 2026-11-06 18:13:50 +00:00
Route function extraction through a Language type.
Each language implements functions. An unknown language returns nothing.
This commit is contained in:
@@ -1,22 +1,27 @@
|
||||
"""Per-language function extraction."""
|
||||
|
||||
from crapper.languages import clojure, golang, java, python, rust, typescript
|
||||
from crapper.languages.clojure import Clojure
|
||||
from crapper.languages.golang import Go
|
||||
from crapper.languages.java import Java
|
||||
from crapper.languages.language import Unknown
|
||||
from crapper.languages.python import Python
|
||||
from crapper.languages.rust import Rust
|
||||
from crapper.languages.typescript import TypeScript
|
||||
from crapper.model import Function
|
||||
|
||||
_LANGUAGES = {
|
||||
"clojure": Clojure(),
|
||||
"java": Java(),
|
||||
"go": Go(),
|
||||
"typescript": TypeScript(),
|
||||
"python": Python(),
|
||||
"rust": Rust(),
|
||||
}
|
||||
_UNKNOWN = Unknown()
|
||||
|
||||
|
||||
def functions_in_file(
|
||||
language: str, source: str, path: str, project_root: str
|
||||
) -> list[Function]:
|
||||
if language == "clojure":
|
||||
return clojure.functions_in_source(source, path, project_root)
|
||||
if language == "java":
|
||||
return java.functions_in_source(source, path)
|
||||
if language == "go":
|
||||
return golang.functions_in_source(source, path, project_root)
|
||||
if language == "typescript":
|
||||
return typescript.functions_in_source(source, path, project_root)
|
||||
if language == "python":
|
||||
return python.functions_in_source(source, path, project_root)
|
||||
if language == "rust":
|
||||
return rust.functions_in_source(source, path, project_root)
|
||||
return []
|
||||
chosen = _LANGUAGES.get(language, _UNKNOWN)
|
||||
return chosen.functions(source, path, project_root)
|
||||
|
||||
@@ -7,6 +7,7 @@ variants, `and`, `or`, `loop`, `catch`, and each clause of `cond`, `condp`,
|
||||
|
||||
import re
|
||||
|
||||
from crapper.languages.language import Language
|
||||
from crapper.model import Function
|
||||
|
||||
_DECISION = re.compile(
|
||||
@@ -285,3 +286,8 @@ def functions_in_source(
|
||||
)
|
||||
for item in extract_functions(source)
|
||||
]
|
||||
|
||||
|
||||
class Clojure(Language):
|
||||
def functions(self, source: str, path: str, project_root: str) -> list[Function]:
|
||||
return functions_in_source(source, path, project_root)
|
||||
|
||||
@@ -19,6 +19,7 @@ from crapper.languages.treesitter import (
|
||||
parse,
|
||||
start_line,
|
||||
)
|
||||
from crapper.languages.language import Language
|
||||
from crapper.model import Function
|
||||
|
||||
_DECISIONS = {
|
||||
@@ -149,3 +150,8 @@ def functions_in_source(
|
||||
)
|
||||
)
|
||||
return found
|
||||
|
||||
|
||||
class Go(Language):
|
||||
def functions(self, source: str, path: str, project_root: str) -> list[Function]:
|
||||
return functions_in_source(source, path, project_root)
|
||||
|
||||
@@ -17,6 +17,7 @@ from crapper.languages.treesitter import (
|
||||
parse,
|
||||
start_line,
|
||||
)
|
||||
from crapper.languages.language import Language
|
||||
from crapper.model import Function
|
||||
|
||||
_PACKAGE = re.compile(r"(?m)^\s*package\s+([a-zA-Z_][\w.]*)\s*;")
|
||||
@@ -114,3 +115,8 @@ def functions_in_source(source: str, path: str) -> list[Function]:
|
||||
|
||||
visit(tree.root_node)
|
||||
return found
|
||||
|
||||
|
||||
class Java(Language):
|
||||
def functions(self, source: str, path: str, project_root: str) -> list[Function]:
|
||||
return functions_in_source(source, path)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
"""The operation every language implements."""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from crapper.model import Function
|
||||
|
||||
|
||||
class Language(ABC):
|
||||
@abstractmethod
|
||||
def functions(self, source: str, path: str, project_root: str) -> list[Function]:
|
||||
"""Functions and methods defined in one source file."""
|
||||
|
||||
|
||||
class Unknown(Language):
|
||||
def functions(self, source: str, path: str, project_root: str) -> list[Function]:
|
||||
return []
|
||||
@@ -16,6 +16,7 @@ from crapper.languages.treesitter import (
|
||||
parse,
|
||||
start_line,
|
||||
)
|
||||
from crapper.languages.language import Language
|
||||
from crapper.model import Function
|
||||
|
||||
_DECISIONS = {
|
||||
@@ -131,3 +132,8 @@ def functions_in_source(
|
||||
)
|
||||
)
|
||||
return found
|
||||
|
||||
|
||||
class Python(Language):
|
||||
def functions(self, source: str, path: str, project_root: str) -> list[Function]:
|
||||
return functions_in_source(source, path, project_root)
|
||||
|
||||
@@ -20,6 +20,7 @@ from crapper.languages.treesitter import (
|
||||
parse,
|
||||
start_line,
|
||||
)
|
||||
from crapper.languages.language import Language
|
||||
from crapper.model import Function
|
||||
|
||||
_DECISIONS = {
|
||||
@@ -186,3 +187,8 @@ def functions_in_source(
|
||||
if recorded is not None:
|
||||
found.append(recorded)
|
||||
return found
|
||||
|
||||
|
||||
class Rust(Language):
|
||||
def functions(self, source: str, path: str, project_root: str) -> list[Function]:
|
||||
return functions_in_source(source, path, project_root)
|
||||
|
||||
@@ -17,6 +17,7 @@ from crapper.languages.treesitter import (
|
||||
parse,
|
||||
start_line,
|
||||
)
|
||||
from crapper.languages.language import Language
|
||||
from crapper.model import Function
|
||||
|
||||
_DECISIONS = {
|
||||
@@ -178,3 +179,8 @@ def functions_in_source(
|
||||
elif node.type == "lexical_declaration":
|
||||
_append_arrows(found, data, node, module, path)
|
||||
return found
|
||||
|
||||
|
||||
class TypeScript(Language):
|
||||
def functions(self, source: str, path: str, project_root: str) -> list[Function]:
|
||||
return functions_in_source(source, path, project_root)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import pytest
|
||||
|
||||
from crapper.languages import functions_in_file
|
||||
|
||||
_SOURCES = [
|
||||
("clojure", "(defn choose [x] x)\n", "src/demo/core.clj", "choose"),
|
||||
("java", "class Board { void place() { if (true) return; } }\n", "Board.java", "place"),
|
||||
("go", "package demo\nfunc Place() int { return 1 }\n", "board.go", "Place"),
|
||||
("typescript", "export function view() { return 1 }\n", "src/ui.ts", "view"),
|
||||
("python", "def run():\n return 1\n", "src/app.py", "run"),
|
||||
("rust", "pub fn open() {}\n", "src/lib.rs", "open"),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("language", "source", "path", "name"), _SOURCES)
|
||||
def test_each_language_answers_the_same_message(language, source, path, name):
|
||||
found = functions_in_file(language, source, path, "/proj")
|
||||
assert found[0].name == name
|
||||
assert found[0].language == language
|
||||
|
||||
|
||||
def test_unknown_language_has_no_functions():
|
||||
assert functions_in_file("ruby", "def x\nend\n", "a.rb", "/proj") == []
|
||||
Reference in New Issue
Block a user