substratum-cli 0.1.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.
- substratum_cli/README.md +51 -0
- substratum_cli/__init__.py +6 -0
- substratum_cli/__main__.py +7 -0
- substratum_cli/_vendor/__init__.py +0 -0
- substratum_cli/_vendor/_pro_test_derive.py +169 -0
- substratum_cli/account.py +62 -0
- substratum_cli/cli.py +185 -0
- substratum_cli/codes.py +114 -0
- substratum_cli/commands/__init__.py +0 -0
- substratum_cli/commands/apply.py +49 -0
- substratum_cli/commands/auth.py +37 -0
- substratum_cli/commands/commit.py +40 -0
- substratum_cli/commands/explain.py +63 -0
- substratum_cli/commands/failing.py +80 -0
- substratum_cli/commands/fix.py +48 -0
- substratum_cli/commands/history.py +15 -0
- substratum_cli/commands/init_cmd.py +155 -0
- substratum_cli/commands/replay.py +68 -0
- substratum_cli/commands/scaffold.py +71 -0
- substratum_cli/commands/show.py +18 -0
- substratum_cli/commands/undo.py +28 -0
- substratum_cli/commands/verify.py +193 -0
- substratum_cli/commands/write.py +42 -0
- substratum_cli/config.py +49 -0
- substratum_cli/diffs.py +106 -0
- substratum_cli/engine.py +154 -0
- substratum_cli/gitio.py +102 -0
- substratum_cli/langscan.py +110 -0
- substratum_cli/product_ops.py +639 -0
- substratum_cli/refusals.py +127 -0
- substratum_cli/remote.py +140 -0
- substratum_cli/render.py +332 -0
- substratum_cli/result.py +185 -0
- substratum_cli/run_store.py +162 -0
- substratum_cli/runid.py +69 -0
- substratum_cli/session.py +558 -0
- substratum_cli/style.py +128 -0
- substratum_cli-0.1.0.dist-info/METADATA +69 -0
- substratum_cli-0.1.0.dist-info/RECORD +42 -0
- substratum_cli-0.1.0.dist-info/WHEEL +5 -0
- substratum_cli-0.1.0.dist-info/entry_points.txt +2 -0
- substratum_cli-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Multi-language declaration scanner -- every language Substratum services, no gaps, no deps.
|
|
2
|
+
|
|
3
|
+
Grain: name the top-level definitions (functions / methods / classes / structs / interfaces / types
|
|
4
|
+
/ enums) per file, so the `summarize` surface describes a codebase in ANY serviced language, not just
|
|
5
|
+
Python. Stdlib-only (air-gapped): Python is exact via `ast`; Go and TS/JS use closed-class declaration
|
|
6
|
+
regexes. NOT a full parser -- summarize needs symbol NAMES + kind, which regex resolves faithfully at
|
|
7
|
+
this grain. Returns a flat list of {name, kind} declarations; the caller aggregates + glosses.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import ast
|
|
12
|
+
import re
|
|
13
|
+
from typing import Dict, List
|
|
14
|
+
|
|
15
|
+
# every extension we service -> language bucket
|
|
16
|
+
LANGS: Dict[str, str] = {
|
|
17
|
+
".py": "py", ".pyi": "py",
|
|
18
|
+
".go": "go",
|
|
19
|
+
".ts": "ts", ".tsx": "ts", ".mts": "ts", ".cts": "ts",
|
|
20
|
+
".js": "js", ".jsx": "js", ".mjs": "js", ".cjs": "js",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
_IDENT = r"[A-Za-z_$][\w$]*"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def scan(text: str, ext: str) -> List[dict]:
|
|
27
|
+
"""[{name, kind}] for one file. kind in {function, method, class, struct, interface, type, enum}."""
|
|
28
|
+
lang = LANGS.get(ext)
|
|
29
|
+
if lang == "py":
|
|
30
|
+
return _scan_py(text)
|
|
31
|
+
if lang == "go":
|
|
32
|
+
return _scan_go(text)
|
|
33
|
+
if lang in ("ts", "js"):
|
|
34
|
+
return _scan_ts(text)
|
|
35
|
+
return []
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _scan_py(text: str) -> List[dict]:
|
|
39
|
+
out: List[dict] = []
|
|
40
|
+
try:
|
|
41
|
+
tree = ast.parse(text)
|
|
42
|
+
except Exception:
|
|
43
|
+
return out
|
|
44
|
+
for node in tree.body:
|
|
45
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
46
|
+
out.append({"name": node.name, "kind": "function"})
|
|
47
|
+
elif isinstance(node, ast.ClassDef):
|
|
48
|
+
out.append({"name": node.name, "kind": "class"})
|
|
49
|
+
for m in node.body:
|
|
50
|
+
if isinstance(m, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
51
|
+
out.append({"name": m.name, "kind": "method"})
|
|
52
|
+
return out
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
_GO_FUNC = re.compile(r"^func\s+(" + _IDENT + r")\s*\(", re.M)
|
|
56
|
+
_GO_METHOD = re.compile(r"^func\s+\([^)]*\)\s+(" + _IDENT + r")\s*\(", re.M)
|
|
57
|
+
_GO_TYPE = re.compile(r"^type\s+(" + _IDENT + r")\s+(struct|interface)\b", re.M)
|
|
58
|
+
_GO_TYPE_OTHER = re.compile(r"^type\s+(" + _IDENT + r")\s+(?!struct|interface)\S", re.M)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _scan_go(text: str) -> List[dict]:
|
|
62
|
+
out: List[dict] = []
|
|
63
|
+
for m in _GO_FUNC.finditer(text):
|
|
64
|
+
out.append({"name": m.group(1), "kind": "function"})
|
|
65
|
+
for m in _GO_METHOD.finditer(text):
|
|
66
|
+
out.append({"name": m.group(1), "kind": "method"})
|
|
67
|
+
for m in _GO_TYPE.finditer(text):
|
|
68
|
+
out.append({"name": m.group(1), "kind": "struct" if m.group(2) == "struct" else "interface"})
|
|
69
|
+
for m in _GO_TYPE_OTHER.finditer(text):
|
|
70
|
+
out.append({"name": m.group(1), "kind": "type"})
|
|
71
|
+
return out
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
_TS_FUNC = re.compile(
|
|
75
|
+
r"^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s*\*?\s*(" + _IDENT + r")", re.M)
|
|
76
|
+
_TS_ARROW = re.compile(
|
|
77
|
+
r"^\s*(?:export\s+)?(?:default\s+)?(?:const|let|var)\s+(" + _IDENT +
|
|
78
|
+
r")\s*(?::[^=]+)?=\s*(?:async\s*)?(?:<[^>]*>\s*)?\([^)]*\)\s*(?::[^=]+?)?=>", re.M)
|
|
79
|
+
_TS_CLASS = re.compile(r"^\s*(?:export\s+)?(?:default\s+)?(?:abstract\s+)?class\s+(" + _IDENT + r")", re.M)
|
|
80
|
+
_TS_IFACE = re.compile(r"^\s*(?:export\s+)?interface\s+(" + _IDENT + r")", re.M)
|
|
81
|
+
_TS_TYPE = re.compile(r"^\s*(?:export\s+)?type\s+(" + _IDENT + r")\s*[=<]", re.M)
|
|
82
|
+
_TS_ENUM = re.compile(r"^\s*(?:export\s+)?(?:const\s+)?enum\s+(" + _IDENT + r")", re.M)
|
|
83
|
+
# a class-body member method: indented `name(args) {` or `name(args):` (not a control keyword)
|
|
84
|
+
_TS_METHOD = re.compile(
|
|
85
|
+
r"^\s+(?:public\s+|private\s+|protected\s+|static\s+|async\s+|readonly\s+|get\s+|set\s+|\*\s*)*"
|
|
86
|
+
r"(" + _IDENT + r")\s*\([^)]*\)\s*[:{]", re.M)
|
|
87
|
+
_TS_KEYWORDS = frozenset({"if", "for", "while", "switch", "catch", "return", "function",
|
|
88
|
+
"constructor", "super", "await", "yield", "typeof", "case", "do", "else"})
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _scan_ts(text: str) -> List[dict]:
|
|
92
|
+
out: List[dict] = []
|
|
93
|
+
top_fn = set()
|
|
94
|
+
for m in _TS_FUNC.finditer(text):
|
|
95
|
+
out.append({"name": m.group(1), "kind": "function"}); top_fn.add(m.group(1))
|
|
96
|
+
for m in _TS_ARROW.finditer(text):
|
|
97
|
+
out.append({"name": m.group(1), "kind": "function"}); top_fn.add(m.group(1))
|
|
98
|
+
for m in _TS_CLASS.finditer(text):
|
|
99
|
+
out.append({"name": m.group(1), "kind": "class"})
|
|
100
|
+
for m in _TS_IFACE.finditer(text):
|
|
101
|
+
out.append({"name": m.group(1), "kind": "interface"})
|
|
102
|
+
for m in _TS_TYPE.finditer(text):
|
|
103
|
+
out.append({"name": m.group(1), "kind": "type"})
|
|
104
|
+
for m in _TS_ENUM.finditer(text):
|
|
105
|
+
out.append({"name": m.group(1), "kind": "enum"})
|
|
106
|
+
for m in _TS_METHOD.finditer(text): # best-effort class methods (indented members)
|
|
107
|
+
nm = m.group(1)
|
|
108
|
+
if nm not in _TS_KEYWORDS and nm not in top_fn:
|
|
109
|
+
out.append({"name": nm, "kind": "method"})
|
|
110
|
+
return out
|