ts-backend-check 1.2.1__py3-none-any.whl → 1.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ts_backend_check/checker.py +209 -54
- ts_backend_check/cli/generate_config_file.py +235 -0
- ts_backend_check/cli/generate_test_project.py +54 -0
- ts_backend_check/cli/main.py +212 -51
- ts_backend_check/parsers/django_parser.py +22 -7
- ts_backend_check/parsers/typescript_parser.py +46 -14
- ts_backend_check/test_project/backend/models.py +31 -0
- ts_backend_check/test_project/frontend/invalid_interfaces.ts +21 -0
- ts_backend_check/test_project/frontend/valid_interfaces.ts +18 -0
- ts_backend_check/utils.py +25 -1
- {ts_backend_check-1.2.1.dist-info → ts_backend_check-1.3.0.dist-info}/METADATA +175 -57
- ts_backend_check-1.3.0.dist-info/RECORD +21 -0
- {ts_backend_check-1.2.1.dist-info → ts_backend_check-1.3.0.dist-info}/WHEEL +1 -1
- ts_backend_check/cli/check_blank.py +0 -111
- ts_backend_check/cli/config.py +0 -164
- ts_backend_check/django_parser.py +0 -113
- ts_backend_check/typescript_parser.py +0 -105
- ts_backend_check-1.2.1.data/data/requirements.txt +0 -26
- ts_backend_check-1.2.1.dist-info/RECORD +0 -21
- {ts_backend_check-1.2.1.dist-info → ts_backend_check-1.3.0.dist-info}/entry_points.txt +0 -0
- {ts_backend_check-1.2.1.dist-info → ts_backend_check-1.3.0.dist-info}/licenses/LICENSE.txt +0 -0
- {ts_backend_check-1.2.1.dist-info → ts_backend_check-1.3.0.dist-info}/top_level.txt +0 -0
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
-
"""
|
|
3
|
-
Module for parsing Django models and extracting field information.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import ast
|
|
7
|
-
from typing import Dict, Set
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class DjangoModelVisitor(ast.NodeVisitor):
|
|
11
|
-
"""
|
|
12
|
-
AST visitor to extract fields from Django models.
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
DJANGO_FIELD_TYPES = {
|
|
16
|
-
"Field",
|
|
17
|
-
"CharField",
|
|
18
|
-
"TextField",
|
|
19
|
-
"IntegerField",
|
|
20
|
-
"BooleanField",
|
|
21
|
-
"DateTimeField",
|
|
22
|
-
"ForeignKey",
|
|
23
|
-
"ManyToManyField",
|
|
24
|
-
"OneToOneField",
|
|
25
|
-
"EmailField",
|
|
26
|
-
"URLField",
|
|
27
|
-
"FileField",
|
|
28
|
-
"ImageField",
|
|
29
|
-
"DecimalField",
|
|
30
|
-
"AutoField",
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
def __init__(self) -> None:
|
|
34
|
-
self.models: Dict[str, Set[str]] = {}
|
|
35
|
-
self.current_model: str | None = None
|
|
36
|
-
|
|
37
|
-
def visit_ClassDef(self, node: ast.ClassDef) -> None:
|
|
38
|
-
"""
|
|
39
|
-
Check class definitions, specifically those that inherit from other classes.
|
|
40
|
-
|
|
41
|
-
Parameters
|
|
42
|
-
----------
|
|
43
|
-
node : ast.ClassDef
|
|
44
|
-
A class definition from Python AST (Abstract Syntax Tree).
|
|
45
|
-
It contains information about the class, such as its name, base classes, body, decorators, etc.
|
|
46
|
-
"""
|
|
47
|
-
# Only process classes that inherit from something.
|
|
48
|
-
if node.bases:
|
|
49
|
-
self.current_model = node.name
|
|
50
|
-
if self.current_model not in self.models:
|
|
51
|
-
self.models[self.current_model] = set()
|
|
52
|
-
|
|
53
|
-
self.generic_visit(node)
|
|
54
|
-
|
|
55
|
-
self.current_model = None
|
|
56
|
-
|
|
57
|
-
def visit_Assign(self, node: ast.Assign) -> None:
|
|
58
|
-
"""
|
|
59
|
-
Check assignment statements within a class.
|
|
60
|
-
|
|
61
|
-
Parameters
|
|
62
|
-
----------
|
|
63
|
-
node : ast.Assign
|
|
64
|
-
An assignment definition from Python AST (Abstract Syntax Tree).
|
|
65
|
-
It represents an assignment statement (e.g., x = 42).
|
|
66
|
-
"""
|
|
67
|
-
if not self.current_model:
|
|
68
|
-
return
|
|
69
|
-
|
|
70
|
-
for target in node.targets:
|
|
71
|
-
if (
|
|
72
|
-
isinstance(target, ast.Name)
|
|
73
|
-
and not target.id.startswith("_")
|
|
74
|
-
and isinstance(node.value, ast.Call)
|
|
75
|
-
and hasattr(node.value.func, "attr")
|
|
76
|
-
) and any(
|
|
77
|
-
field_type in node.value.func.attr
|
|
78
|
-
for field_type in self.DJANGO_FIELD_TYPES
|
|
79
|
-
):
|
|
80
|
-
self.models[self.current_model].add(target.id)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def extract_model_fields(models_file: str) -> Dict[str, Set[str]]:
|
|
84
|
-
"""
|
|
85
|
-
Extract fields from Django models file.
|
|
86
|
-
|
|
87
|
-
Parameters
|
|
88
|
-
----------
|
|
89
|
-
models_file : str
|
|
90
|
-
A models.py file that defines Django models.
|
|
91
|
-
|
|
92
|
-
Returns
|
|
93
|
-
-------
|
|
94
|
-
Dict[str, Set[str]]
|
|
95
|
-
The fields from the models file extracted into a dictionary for future processing.
|
|
96
|
-
"""
|
|
97
|
-
with open(models_file, "r", encoding="utf-8") as f:
|
|
98
|
-
content = f.read().strip()
|
|
99
|
-
# Skip any empty lines at the beginning
|
|
100
|
-
while content.startswith("\n"):
|
|
101
|
-
content = content[1:]
|
|
102
|
-
|
|
103
|
-
try:
|
|
104
|
-
tree = ast.parse(content)
|
|
105
|
-
except SyntaxError as e:
|
|
106
|
-
raise SyntaxError(
|
|
107
|
-
f"Failed to parse {models_file}. Make sure it's a valid Python file. Error: {str(e)}"
|
|
108
|
-
) from e
|
|
109
|
-
|
|
110
|
-
visitor = DjangoModelVisitor()
|
|
111
|
-
visitor.visit(tree)
|
|
112
|
-
|
|
113
|
-
return visitor.models
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
-
"""
|
|
3
|
-
Module for parsing TypeScript interfaces and types.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import re
|
|
7
|
-
from dataclasses import dataclass
|
|
8
|
-
from typing import Dict, List, Set
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@dataclass
|
|
12
|
-
class TypeScriptInterface:
|
|
13
|
-
"""
|
|
14
|
-
Represents a TypeScript interface with its fields and parent interfaces.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
name: str
|
|
18
|
-
fields: Set[str]
|
|
19
|
-
parents: List[str]
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class TypeScriptParser:
|
|
23
|
-
"""
|
|
24
|
-
Parser for TypeScript interface files.
|
|
25
|
-
|
|
26
|
-
Parameters
|
|
27
|
-
----------
|
|
28
|
-
file_path : str
|
|
29
|
-
The file path for the TypeScript file to parse.
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
def __init__(self, file_path: str) -> None:
|
|
33
|
-
self.file_path = file_path
|
|
34
|
-
with open(file_path, "r", encoding="utf-8") as f:
|
|
35
|
-
self.content = f.read()
|
|
36
|
-
|
|
37
|
-
def parse_interfaces(self) -> Dict[str, TypeScriptInterface]:
|
|
38
|
-
"""
|
|
39
|
-
Parse TypeScript interfaces from the file.
|
|
40
|
-
|
|
41
|
-
Returns
|
|
42
|
-
-------
|
|
43
|
-
Dict[str, TypeScriptInterface]
|
|
44
|
-
The interface parsed into a dictionary for future processing.
|
|
45
|
-
"""
|
|
46
|
-
interfaces = {}
|
|
47
|
-
interface_pattern = (
|
|
48
|
-
r"(?:export\s+|declare\s+)?interface\s+(\w+)"
|
|
49
|
-
r"(?:\s+extends\s+([^{]+))?\s*{([\s\S]*?)}"
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
for match in re.finditer(interface_pattern, self.content):
|
|
53
|
-
name = match.group(1)
|
|
54
|
-
parents = (
|
|
55
|
-
[p.strip() for p in match.group(2).split(",")] if match.group(2) else []
|
|
56
|
-
)
|
|
57
|
-
fields = self._extract_fields(match.group(3))
|
|
58
|
-
|
|
59
|
-
interfaces[name] = TypeScriptInterface(name, fields, parents)
|
|
60
|
-
|
|
61
|
-
return interfaces
|
|
62
|
-
|
|
63
|
-
def get_backend_only_fields(self) -> Set[str]:
|
|
64
|
-
"""
|
|
65
|
-
Extract fields marked as backend-only in comments.
|
|
66
|
-
|
|
67
|
-
Returns
|
|
68
|
-
-------
|
|
69
|
-
Set[str]
|
|
70
|
-
The field names that are marked with a backend-only identifier to ignore them.
|
|
71
|
-
"""
|
|
72
|
-
patterns = [
|
|
73
|
-
r"//.*?Note:\s*(\w+)\s+is\s+backend\s+only",
|
|
74
|
-
r"//.*?(\w+)\s+is\s+backend\s+only",
|
|
75
|
-
r"//\s*@backend-only\s+(\w+)",
|
|
76
|
-
r"//.*?backend-only:\s*(\w+)",
|
|
77
|
-
]
|
|
78
|
-
return {
|
|
79
|
-
match for pattern in patterns for match in re.findall(pattern, self.content)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
@staticmethod
|
|
83
|
-
def _extract_fields(interface_body: str) -> Set[str]:
|
|
84
|
-
"""
|
|
85
|
-
Extract field names from interface body.
|
|
86
|
-
|
|
87
|
-
Parameters
|
|
88
|
-
----------
|
|
89
|
-
interface_body : str
|
|
90
|
-
A string representation of the interface body of the model.
|
|
91
|
-
|
|
92
|
-
Returns
|
|
93
|
-
-------
|
|
94
|
-
Set[str]
|
|
95
|
-
The field names from the model interface body.
|
|
96
|
-
"""
|
|
97
|
-
fields = set()
|
|
98
|
-
|
|
99
|
-
# Regular fields
|
|
100
|
-
fields.update(re.findall(r"(?://[^\n]*\n)*\s*(\w+)\s*[?]?\s*:", interface_body))
|
|
101
|
-
|
|
102
|
-
# Readonly fields
|
|
103
|
-
fields.update(re.findall(r"readonly\s+(\w+)\s*[?]?\s*:", interface_body))
|
|
104
|
-
|
|
105
|
-
return fields
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# This file is autogenerated by pip-compile with Python 3.13
|
|
3
|
-
# by the following command:
|
|
4
|
-
#
|
|
5
|
-
# pip-compile requirements.in
|
|
6
|
-
#
|
|
7
|
-
certifi>=2025.11.12
|
|
8
|
-
# via requests
|
|
9
|
-
charset-normalizer>=3.4.4
|
|
10
|
-
# via requests
|
|
11
|
-
idna>=3.11
|
|
12
|
-
# via requests
|
|
13
|
-
markdown-it-py>=4.0.0
|
|
14
|
-
# via rich
|
|
15
|
-
mdurl>=0.1.2
|
|
16
|
-
# via markdown-it-py
|
|
17
|
-
pygments>=2.19.2
|
|
18
|
-
# via rich
|
|
19
|
-
pyyaml>=6.0.3
|
|
20
|
-
# via -r requirements.in
|
|
21
|
-
requests>=2.32.5
|
|
22
|
-
# via -r requirements.in
|
|
23
|
-
rich>=14.2.0
|
|
24
|
-
# via -r requirements.in
|
|
25
|
-
urllib3>=2.6.2
|
|
26
|
-
# via requests
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
ts_backend_check/__init__.py,sha256=HSiEqWvU3Q4a6D7tYsoq3-B-g1HdUOGngEeGV45j8ak,172
|
|
2
|
-
ts_backend_check/checker.py,sha256=4QtPdiEnpRVIO4BpcHeCz-sjG2bqTg43M4gfntRnHj4,5956
|
|
3
|
-
ts_backend_check/django_parser.py,sha256=CFg4-zV5BsVhuq-nVQEYD9nS25JSaHbIs2Xr3LE3KWY,3241
|
|
4
|
-
ts_backend_check/typescript_parser.py,sha256=BqBGOjsf-Wlh6ceaK-G2vLm5AMiEiwX-XnJQrr8P-gQ,2885
|
|
5
|
-
ts_backend_check/utils.py,sha256=N9_25_wW2g3dkmGGLWHQj_AHsXI9Rx2XqRnYxT5i2Rk,897
|
|
6
|
-
ts_backend_check/cli/__init__.py,sha256=wJK9tO9MtI10L0xRjrk7WP_qZZRBjbFw1U9jJbIbX7I,108
|
|
7
|
-
ts_backend_check/cli/check_blank.py,sha256=gg6v01UYNmzs8eLasxauCaBCfN9esUtiAwqhqNTzE3w,3377
|
|
8
|
-
ts_backend_check/cli/config.py,sha256=AgzjY3qbgW4ya5JJEdKaBQ9J8h0Ip-39xJNbAjFpA6s,4463
|
|
9
|
-
ts_backend_check/cli/main.py,sha256=uDG-Tzc0avs_2Rug-XkUvRf3OFZO1clr7QSrAPqXVos,4405
|
|
10
|
-
ts_backend_check/cli/upgrade.py,sha256=P2LdIDCLdOFs-fOMuKLQoUMijQIyKEIA5PFZVsAUwDg,2952
|
|
11
|
-
ts_backend_check/cli/version.py,sha256=lsocMaxAfF-FHW9O-NGH1sAo6svjuLgdGFxaC-XVoZc,2845
|
|
12
|
-
ts_backend_check/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
ts_backend_check/parsers/django_parser.py,sha256=U5OP6IyrSdwI9rDUGU4GbWTDfozwhretWg7lmF6QGB8,3242
|
|
14
|
-
ts_backend_check/parsers/typescript_parser.py,sha256=UAExnEKxuFREFY6bJgQreG0b7SyVhWRaHw5TjN0CSU4,2680
|
|
15
|
-
ts_backend_check-1.2.1.data/data/requirements.txt,sha256=ixdwNPm86WRSX0oBBaNegCQL7HQP8evsCRAdEFHLxGk,540
|
|
16
|
-
ts_backend_check-1.2.1.dist-info/licenses/LICENSE.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
17
|
-
ts_backend_check-1.2.1.dist-info/METADATA,sha256=q5Mm6sTE9Ga3EJEJ65VdSaED1leRiOGTxxEplGKUbxs,11259
|
|
18
|
-
ts_backend_check-1.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
19
|
-
ts_backend_check-1.2.1.dist-info/entry_points.txt,sha256=QeY7RJu20otBnQlhMMZxPL8nB3mP3M3U3h3nOlSFWSU,68
|
|
20
|
-
ts_backend_check-1.2.1.dist-info/top_level.txt,sha256=VzfNWQ3fPNdl-OBdtUKsUWR8Asdd27E3OJNUg2oQU8Y,17
|
|
21
|
-
ts_backend_check-1.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|