mirror of
https://github.com/unclebob/crapper.git
synced 2026-11-07 10:33: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."""
|
"""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
|
from crapper.model import Function
|
||||||
|
|
||||||
|
_LANGUAGES = {
|
||||||
|
"clojure": Clojure(),
|
||||||
|
"java": Java(),
|
||||||
|
"go": Go(),
|
||||||
|
"typescript": TypeScript(),
|
||||||
|
"python": Python(),
|
||||||
|
"rust": Rust(),
|
||||||
|
}
|
||||||
|
_UNKNOWN = Unknown()
|
||||||
|
|
||||||
|
|
||||||
def functions_in_file(
|
def functions_in_file(
|
||||||
language: str, source: str, path: str, project_root: str
|
language: str, source: str, path: str, project_root: str
|
||||||
) -> list[Function]:
|
) -> list[Function]:
|
||||||
if language == "clojure":
|
chosen = _LANGUAGES.get(language, _UNKNOWN)
|
||||||
return clojure.functions_in_source(source, path, project_root)
|
return chosen.functions(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 []
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ variants, `and`, `or`, `loop`, `catch`, and each clause of `cond`, `condp`,
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from crapper.languages.language import Language
|
||||||
from crapper.model import Function
|
from crapper.model import Function
|
||||||
|
|
||||||
_DECISION = re.compile(
|
_DECISION = re.compile(
|
||||||
@@ -285,3 +286,8 @@ def functions_in_source(
|
|||||||
)
|
)
|
||||||
for item in extract_functions(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,
|
parse,
|
||||||
start_line,
|
start_line,
|
||||||
)
|
)
|
||||||
|
from crapper.languages.language import Language
|
||||||
from crapper.model import Function
|
from crapper.model import Function
|
||||||
|
|
||||||
_DECISIONS = {
|
_DECISIONS = {
|
||||||
@@ -149,3 +150,8 @@ def functions_in_source(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
return found
|
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,
|
parse,
|
||||||
start_line,
|
start_line,
|
||||||
)
|
)
|
||||||
|
from crapper.languages.language import Language
|
||||||
from crapper.model import Function
|
from crapper.model import Function
|
||||||
|
|
||||||
_PACKAGE = re.compile(r"(?m)^\s*package\s+([a-zA-Z_][\w.]*)\s*;")
|
_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)
|
visit(tree.root_node)
|
||||||
return found
|
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,
|
parse,
|
||||||
start_line,
|
start_line,
|
||||||
)
|
)
|
||||||
|
from crapper.languages.language import Language
|
||||||
from crapper.model import Function
|
from crapper.model import Function
|
||||||
|
|
||||||
_DECISIONS = {
|
_DECISIONS = {
|
||||||
@@ -131,3 +132,8 @@ def functions_in_source(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
return found
|
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,
|
parse,
|
||||||
start_line,
|
start_line,
|
||||||
)
|
)
|
||||||
|
from crapper.languages.language import Language
|
||||||
from crapper.model import Function
|
from crapper.model import Function
|
||||||
|
|
||||||
_DECISIONS = {
|
_DECISIONS = {
|
||||||
@@ -186,3 +187,8 @@ def functions_in_source(
|
|||||||
if recorded is not None:
|
if recorded is not None:
|
||||||
found.append(recorded)
|
found.append(recorded)
|
||||||
return found
|
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,
|
parse,
|
||||||
start_line,
|
start_line,
|
||||||
)
|
)
|
||||||
|
from crapper.languages.language import Language
|
||||||
from crapper.model import Function
|
from crapper.model import Function
|
||||||
|
|
||||||
_DECISIONS = {
|
_DECISIONS = {
|
||||||
@@ -178,3 +179,8 @@ def functions_in_source(
|
|||||||
elif node.type == "lexical_declaration":
|
elif node.type == "lexical_declaration":
|
||||||
_append_arrows(found, data, node, module, path)
|
_append_arrows(found, data, node, module, path)
|
||||||
return found
|
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