cg-code-graph 0.10.1__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.
- cg_code_graph-0.10.1.dist-info/METADATA +678 -0
- cg_code_graph-0.10.1.dist-info/RECORD +174 -0
- cg_code_graph-0.10.1.dist-info/WHEEL +5 -0
- cg_code_graph-0.10.1.dist-info/entry_points.txt +3 -0
- cg_code_graph-0.10.1.dist-info/licenses/LICENSE +21 -0
- cg_code_graph-0.10.1.dist-info/top_level.txt +1 -0
- codegraph/__init__.py +2 -0
- codegraph/aitools.py +129 -0
- codegraph/apps.py +76 -0
- codegraph/blindspots.py +428 -0
- codegraph/bridges.py +1701 -0
- codegraph/cli.py +725 -0
- codegraph/concepts.py +362 -0
- codegraph/config.py +559 -0
- codegraph/core/__init__.py +0 -0
- codegraph/core/cache.py +375 -0
- codegraph/core/detect.py +80 -0
- codegraph/core/extractors.py +187 -0
- codegraph/core/fsutil.py +61 -0
- codegraph/core/generated.py +575 -0
- codegraph/core/model.py +174 -0
- codegraph/core/paths.py +175 -0
- codegraph/core/plugin.py +160 -0
- codegraph/core/store.py +80 -0
- codegraph/core/syntax_errors.py +132 -0
- codegraph/coverage.py +928 -0
- codegraph/doctor.py +453 -0
- codegraph/external.py +613 -0
- codegraph/indexer.py +336 -0
- codegraph/link.py +434 -0
- codegraph/lint_async.py +524 -0
- codegraph/mcp_server.py +1303 -0
- codegraph/parity.py +473 -0
- codegraph/parity_structure.py +307 -0
- codegraph/payload.py +321 -0
- codegraph/plans.py +1285 -0
- codegraph/platform_scan.py +643 -0
- codegraph/platforms.py +1369 -0
- codegraph/plugins/__init__.py +0 -0
- codegraph/plugins/cfamily/__init__.py +0 -0
- codegraph/plugins/cfamily/plugin.py +930 -0
- codegraph/plugins/cfamily/syntax.py +881 -0
- codegraph/plugins/dart/__init__.py +0 -0
- codegraph/plugins/dart/bridges.py +345 -0
- codegraph/plugins/dart/extractor/bin/extract.dart +717 -0
- codegraph/plugins/dart/extractor/pubspec.lock +149 -0
- codegraph/plugins/dart/extractor/pubspec.yaml +7 -0
- codegraph/plugins/dart/http.py +904 -0
- codegraph/plugins/dart/models.py +308 -0
- codegraph/plugins/dart/plugin.py +625 -0
- codegraph/plugins/dart/program.py +907 -0
- codegraph/plugins/django/__init__.py +0 -0
- codegraph/plugins/django/extras.py +378 -0
- codegraph/plugins/django/models.py +508 -0
- codegraph/plugins/django/plugin.py +728 -0
- codegraph/plugins/django/schemas.py +339 -0
- codegraph/plugins/django/shapes.py +216 -0
- codegraph/plugins/django/urls.py +603 -0
- codegraph/plugins/express/__init__.py +0 -0
- codegraph/plugins/express/plugin.py +428 -0
- codegraph/plugins/flutter/__init__.py +0 -0
- codegraph/plugins/flutter/plugin.py +538 -0
- codegraph/plugins/kotlin/__init__.py +0 -0
- codegraph/plugins/kotlin/exact.py +457 -0
- codegraph/plugins/kotlin/plugin.py +1961 -0
- codegraph/plugins/kotlin/reparse.py +234 -0
- codegraph/plugins/laravel/__init__.py +0 -0
- codegraph/plugins/laravel/broadcast.py +351 -0
- codegraph/plugins/laravel/plugin.py +863 -0
- codegraph/plugins/laravel/tests.py +262 -0
- codegraph/plugins/laravel/values.py +728 -0
- codegraph/plugins/native/__init__.py +0 -0
- codegraph/plugins/native/gates.py +286 -0
- codegraph/plugins/native/runner.py +183 -0
- codegraph/plugins/native/scipread.py +194 -0
- codegraph/plugins/native/ts.py +54 -0
- codegraph/plugins/nest/__init__.py +0 -0
- codegraph/plugins/nest/plugin.py +654 -0
- codegraph/plugins/nextjs/__init__.py +0 -0
- codegraph/plugins/nextjs/plugin.py +336 -0
- codegraph/plugins/nuxt/__init__.py +0 -0
- codegraph/plugins/nuxt/plugin.py +308 -0
- codegraph/plugins/php/__init__.py +0 -0
- codegraph/plugins/php/extractor/composer.json +5 -0
- codegraph/plugins/php/extractor/composer.lock +76 -0
- codegraph/plugins/php/extractor/extract.php +743 -0
- codegraph/plugins/php/gating.py +573 -0
- codegraph/plugins/php/plugin.py +668 -0
- codegraph/plugins/php/strings.py +197 -0
- codegraph/plugins/python/__init__.py +0 -0
- codegraph/plugins/python/aitools.py +664 -0
- codegraph/plugins/python/external.py +245 -0
- codegraph/plugins/python/fields.py +107 -0
- codegraph/plugins/python/plugin.py +1733 -0
- codegraph/plugins/python/refs.py +485 -0
- codegraph/plugins/python/roots.py +412 -0
- codegraph/plugins/python/socketio.py +210 -0
- codegraph/plugins/python/subproc.py +864 -0
- codegraph/plugins/python/tests.py +1040 -0
- codegraph/plugins/python/values.py +179 -0
- codegraph/plugins/pyweb/__init__.py +0 -0
- codegraph/plugins/pyweb/plugin.py +1334 -0
- codegraph/plugins/pyweb/values.py +68 -0
- codegraph/plugins/rust/__init__.py +0 -0
- codegraph/plugins/rust/cargo.py +226 -0
- codegraph/plugins/rust/plugin.py +980 -0
- codegraph/plugins/rust/syntax.py +678 -0
- codegraph/plugins/scip/__init__.py +0 -0
- codegraph/plugins/scip/importer.py +129 -0
- codegraph/plugins/scip/scip.proto +962 -0
- codegraph/plugins/scip/scip_pb2.py +97 -0
- codegraph/plugins/stubs/__init__.py +0 -0
- codegraph/plugins/stubs/plugins.py +38 -0
- codegraph/plugins/swift/__init__.py +0 -0
- codegraph/plugins/swift/baseurl.py +109 -0
- codegraph/plugins/swift/exact.py +415 -0
- codegraph/plugins/swift/indexstore.py +209 -0
- codegraph/plugins/swift/packages.py +174 -0
- codegraph/plugins/swift/plugin.py +2890 -0
- codegraph/plugins/ts/__init__.py +0 -0
- codegraph/plugins/ts/baseurl.py +185 -0
- codegraph/plugins/ts/extractor/extract.mjs +2652 -0
- codegraph/plugins/ts/extractor/fw.mjs +685 -0
- codegraph/plugins/ts/extractor/package-lock.json +205 -0
- codegraph/plugins/ts/extractor/package.json +9 -0
- codegraph/plugins/ts/plugin.py +480 -0
- codegraph/plugins/tsweb/__init__.py +0 -0
- codegraph/plugins/tsweb/common.py +290 -0
- codegraph/plugins/tsweb/data.py +276 -0
- codegraph/presets/__init__.py +146 -0
- codegraph/presets/c_cpp.yaml +9 -0
- codegraph/presets/common.yaml +66 -0
- codegraph/presets/dart.yaml +9 -0
- codegraph/presets/django-ninja.yaml +15 -0
- codegraph/presets/django.yaml +25 -0
- codegraph/presets/djangorestframework.yaml +17 -0
- codegraph/presets/express.yaml +17 -0
- codegraph/presets/kotlin.yaml +11 -0
- codegraph/presets/laravel.yaml +40 -0
- codegraph/presets/nest.yaml +11 -0
- codegraph/presets/nextjs.yaml +15 -0
- codegraph/presets/nuxt.yaml +9 -0
- codegraph/presets/php.yaml +5 -0
- codegraph/presets/python.yaml +10 -0
- codegraph/presets/rust.yaml +5 -0
- codegraph/presets/swift.yaml +10 -0
- codegraph/presets/typescript.yaml +13 -0
- codegraph/process_runs.py +328 -0
- codegraph/protocols/__init__.py +299 -0
- codegraph/protocols/builtin.py +67 -0
- codegraph/protocols/matchers.py +144 -0
- codegraph/protocols/view.py +334 -0
- codegraph/query.py +2089 -0
- codegraph/realtime.py +260 -0
- codegraph/roundtrip.py +346 -0
- codegraph/routes.py +442 -0
- codegraph/starters.py +218 -0
- codegraph/tests_index.py +117 -0
- codegraph/viz/__init__.py +0 -0
- codegraph/viz/graph.py +369 -0
- codegraph/viz/server.py +198 -0
- codegraph/viz/static/app.css +148 -0
- codegraph/viz/static/app.js +1082 -0
- codegraph/viz/static/index.html +81 -0
- codegraph/viz/static/layered.js +237 -0
- codegraph/viz/static/vendor/VERSIONS.txt +4 -0
- codegraph/viz/static/vendor/cose-base.js +3214 -0
- codegraph/viz/static/vendor/cytoscape-fcose.js +1549 -0
- codegraph/viz/static/vendor/cytoscape.min.js +31 -0
- codegraph/viz/static/vendor/layout-base.js +5230 -0
- codegraph/viz/tools/package-lock.json +303 -0
- codegraph/viz/tools/package.json +7 -0
- codegraph/viz/tools/shoot.mjs +165 -0
- codegraph/xcode.py +251 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"""JSON wire shapes of Dart model classes.
|
|
2
|
+
|
|
3
|
+
Sources, strongest first:
|
|
4
|
+
* generated `*.g.dart` (`_$XFromJson` / `_$XToJson`, freezed `_$$XImplFromJson`): exact keys,
|
|
5
|
+
casts and nullability as compiled;
|
|
6
|
+
* json_serializable / freezed annotations when the generated file is absent: field names with
|
|
7
|
+
`@JsonKey(name:)`, `fieldRename` (annotation or build.yaml), `@Default`, `includeFromJson`;
|
|
8
|
+
* hand-written `fromJson`/`fromMap` constructors (`json['key']` reads) and `toJson`/`toMap`
|
|
9
|
+
map literals.
|
|
10
|
+
Enums: `@JsonValue('x')` values, `@JsonEnum(fieldRename:/valueField:)`, otherwise the value names.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import re
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from .program import Ctx, DartProgram, DClass, DFunc, DVar, last_name, split_type, walk_repr
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def rename(name: str, how: str | None) -> str:
|
|
21
|
+
if not how or how == "none":
|
|
22
|
+
return name
|
|
23
|
+
words = re.sub(r"([a-z0-9])([A-Z])", r"\1 \2", name).replace("_", " ").split()
|
|
24
|
+
if how == "snake":
|
|
25
|
+
return "_".join(w.lower() for w in words)
|
|
26
|
+
if how == "kebab":
|
|
27
|
+
return "-".join(w.lower() for w in words)
|
|
28
|
+
if how == "screamingSnake":
|
|
29
|
+
return "_".join(w.upper() for w in words)
|
|
30
|
+
if how == "pascal":
|
|
31
|
+
return name[:1].upper() + name[1:]
|
|
32
|
+
return name
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def ann_get(anns: list, *names: str) -> dict | None:
|
|
36
|
+
for a in anns or []:
|
|
37
|
+
if a["name"].split(".")[-1] in names:
|
|
38
|
+
return a
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def ann_str(a: dict | None, key: str):
|
|
43
|
+
if not a:
|
|
44
|
+
return None
|
|
45
|
+
v = (a.get("na") or {}).get(key)
|
|
46
|
+
if not v:
|
|
47
|
+
return None
|
|
48
|
+
if v.get("k") == "str":
|
|
49
|
+
return v["v"]
|
|
50
|
+
if v.get("k") in ("bool", "num"):
|
|
51
|
+
return v["v"]
|
|
52
|
+
if v.get("k") == "prop":
|
|
53
|
+
return v["n"]
|
|
54
|
+
if v.get("k") == "id":
|
|
55
|
+
return v["v"]
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ModelIndex:
|
|
60
|
+
def __init__(self, prog: DartProgram):
|
|
61
|
+
self.prog = prog
|
|
62
|
+
self.cache: dict[str, dict] = {}
|
|
63
|
+
self.build_rename: dict[str, str] = {}
|
|
64
|
+
for pk in prog.pkg_dirs:
|
|
65
|
+
p = (prog.root / pk.dir / "build.yaml") if pk.dir else prog.root / "build.yaml"
|
|
66
|
+
if p.exists():
|
|
67
|
+
m = re.search(r"field_rename:\s*(\w+)", p.read_text(errors="replace"))
|
|
68
|
+
if m:
|
|
69
|
+
self.build_rename[pk.dir] = m.group(1)
|
|
70
|
+
|
|
71
|
+
def keys(self, c: DClass, direction: str) -> list[dict]:
|
|
72
|
+
return self.model(c).get(direction) or []
|
|
73
|
+
|
|
74
|
+
def is_model(self, c: DClass) -> bool:
|
|
75
|
+
m = self.model(c)
|
|
76
|
+
return bool(m.get("from") or m.get("to") or m.get("enum_values"))
|
|
77
|
+
|
|
78
|
+
def field_type(self, c: DClass, name: str) -> str | None:
|
|
79
|
+
if name in c.fields:
|
|
80
|
+
return c.fields[name].type
|
|
81
|
+
for ct in c.ctors.values():
|
|
82
|
+
for p in ct.params:
|
|
83
|
+
if p["name"] == name and p.get("type"):
|
|
84
|
+
return p["type"]
|
|
85
|
+
for s in self.prog.mro(c):
|
|
86
|
+
if name in s.fields:
|
|
87
|
+
return s.fields[name].type
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
def ref_of(self, c: DClass, t: str | None):
|
|
91
|
+
tt = self.prog.type_of_text(t, c.lib) if t else None
|
|
92
|
+
many = False
|
|
93
|
+
if tt and tt[0] == "list":
|
|
94
|
+
many, tt = True, tt[1]
|
|
95
|
+
if tt and tt[0] == "inst" and tt[1] is not None:
|
|
96
|
+
return tt[1].id, many
|
|
97
|
+
return None, many
|
|
98
|
+
|
|
99
|
+
def model(self, c: DClass) -> dict:
|
|
100
|
+
if c.id in self.cache:
|
|
101
|
+
return self.cache[c.id]
|
|
102
|
+
self.cache[c.id] = {}
|
|
103
|
+
out = {"id": c.id, "name": c.name, "file": c.file, "line": c.line}
|
|
104
|
+
if c.kind == "enum":
|
|
105
|
+
out["enum_values"] = self.enum_values(c)
|
|
106
|
+
self.cache[c.id] = out
|
|
107
|
+
return out
|
|
108
|
+
anns = c.raw.get("ann") or []
|
|
109
|
+
js = ann_get(anns, "JsonSerializable")
|
|
110
|
+
fz = ann_get(anns, "freezed", "Freezed", "unfreezed")
|
|
111
|
+
how = ann_str(js, "fieldRename") or ann_str(fz, "fieldRename")
|
|
112
|
+
pk = c.lib.pkg.dir if c.lib.pkg else ""
|
|
113
|
+
if how is None and (js or fz):
|
|
114
|
+
how = self.build_rename.get(pk)
|
|
115
|
+
gen_from, gen_to = self.generated(c)
|
|
116
|
+
if gen_from is not None:
|
|
117
|
+
out["from"], out["from_source"] = self.from_fn(c, gen_from, "g.dart"), "generated"
|
|
118
|
+
if gen_to is not None:
|
|
119
|
+
out["to"], out["to_source"] = self.to_fn(c, gen_to, "g.dart"), "generated"
|
|
120
|
+
if "from" not in out or "to" not in out:
|
|
121
|
+
hand_from = c.ctors.get("fromJson") or c.ctors.get("fromMap") or c.methods.get("fromJson") or c.methods.get("fromMap")
|
|
122
|
+
if "from" not in out and hand_from is not None and not hand_from.raw.get("redirect") and not self._delegates(hand_from):
|
|
123
|
+
out["from"], out["from_source"] = self.from_fn(c, hand_from, "hand-written"), "hand-written"
|
|
124
|
+
hand_to = c.methods.get("toJson") or c.methods.get("toMap")
|
|
125
|
+
if "to" not in out and hand_to is not None and not self._delegates(hand_to):
|
|
126
|
+
out["to"], out["to_source"] = self.to_fn(c, hand_to, "hand-written"), "hand-written"
|
|
127
|
+
if ("from" not in out or "to" not in out) and (js or fz):
|
|
128
|
+
ann_keys = self.annotated(c, how, bool(fz))
|
|
129
|
+
out.setdefault("from", [k for k in ann_keys if k.get("from", True)])
|
|
130
|
+
out.setdefault("from_source", "annotations (no .g.dart)")
|
|
131
|
+
out.setdefault("to", [k for k in ann_keys if k.get("to", True)])
|
|
132
|
+
out.setdefault("to_source", "annotations (no .g.dart)")
|
|
133
|
+
if how:
|
|
134
|
+
out["field_rename"] = how
|
|
135
|
+
self.cache[c.id] = out
|
|
136
|
+
return out
|
|
137
|
+
|
|
138
|
+
def _delegates(self, f: DFunc) -> bool:
|
|
139
|
+
"""fromJson => _$XFromJson(json) : generated code holds the keys."""
|
|
140
|
+
for x in f.facts:
|
|
141
|
+
if x["ft"] == "return":
|
|
142
|
+
v = x["v"]
|
|
143
|
+
if v.get("k") == "call" and v.get("n") and v["n"].startswith("_$"):
|
|
144
|
+
return True
|
|
145
|
+
if v.get("k") == "call" and v.get("n") is None and (v.get("t") or {}).get("v", "").startswith("_$"):
|
|
146
|
+
return True
|
|
147
|
+
return bool(f.raw.get("redirect"))
|
|
148
|
+
|
|
149
|
+
def generated(self, c: DClass):
|
|
150
|
+
names_from = {f"_${c.name}FromJson", f"_$$_{c.name}FromJson", f"_$${c.name}ImplFromJson", f"_$_{c.name}FromJson"}
|
|
151
|
+
names_to = {f"_${c.name}ToJson", f"_$$_{c.name}ToJson", f"_$${c.name}ImplToJson", f"_$_{c.name}ToJson"}
|
|
152
|
+
gf = gt = None
|
|
153
|
+
for n in names_from:
|
|
154
|
+
v = c.lib.decls.get(n)
|
|
155
|
+
if isinstance(v, DFunc):
|
|
156
|
+
gf = v
|
|
157
|
+
for n in names_to:
|
|
158
|
+
v = c.lib.decls.get(n)
|
|
159
|
+
if isinstance(v, DFunc):
|
|
160
|
+
gt = v
|
|
161
|
+
return gf, gt
|
|
162
|
+
|
|
163
|
+
def from_fn(self, c: DClass, f: DFunc, source: str) -> list[dict]:
|
|
164
|
+
if not f.params:
|
|
165
|
+
return []
|
|
166
|
+
pn = f.params[0]["name"]
|
|
167
|
+
field_of: dict[int, str] = {}
|
|
168
|
+
# named args / initializer list / positional ctor args -> which field a key feeds
|
|
169
|
+
exprs = []
|
|
170
|
+
for x in f.facts:
|
|
171
|
+
if x["ft"] == "return":
|
|
172
|
+
exprs.append(x["v"])
|
|
173
|
+
for ini in f.raw.get("inits") or []:
|
|
174
|
+
if ini.get("field"):
|
|
175
|
+
for y in walk_repr(ini["v"]):
|
|
176
|
+
if y.get("k") == "idx":
|
|
177
|
+
field_of[id(y)] = ini["field"]
|
|
178
|
+
key_field: dict[tuple[str, int], str] = {}
|
|
179
|
+
for e in exprs:
|
|
180
|
+
for y in walk_repr(e):
|
|
181
|
+
if y.get("k") in ("new", "call") and (y.get("na") or y.get("a")):
|
|
182
|
+
tgt_cls = y.get("type") if y.get("k") == "new" else last_name(y.get("t")) if y.get("n") is None else None
|
|
183
|
+
for nm, val in (y.get("na") or {}).items():
|
|
184
|
+
for z in walk_repr(val):
|
|
185
|
+
if z.get("k") == "idx" and (z.get("i") or {}).get("k") == "str":
|
|
186
|
+
key_field.setdefault((z["i"]["v"], z.get("l") or 0), nm)
|
|
187
|
+
ct = c.ctors.get("new") if tgt_cls in (c.name, None) else None
|
|
188
|
+
if ct:
|
|
189
|
+
pos = [p for p in ct.params if not p.get("named")]
|
|
190
|
+
for i, val in enumerate(y.get("a") or []):
|
|
191
|
+
if i < len(pos):
|
|
192
|
+
for z in walk_repr(val):
|
|
193
|
+
if z.get("k") == "idx" and (z.get("i") or {}).get("k") == "str":
|
|
194
|
+
key_field.setdefault((z["i"]["v"], z.get("l") or 0), pos[i]["name"])
|
|
195
|
+
for ini in f.raw.get("inits") or []:
|
|
196
|
+
if ini.get("field"):
|
|
197
|
+
for z in walk_repr(ini["v"]):
|
|
198
|
+
if z.get("k") == "idx" and (z.get("i") or {}).get("k") == "str":
|
|
199
|
+
key_field.setdefault((z["i"]["v"], z.get("l") or 0), ini["field"])
|
|
200
|
+
out, seen = [], set()
|
|
201
|
+
for x in f.facts:
|
|
202
|
+
if x["ft"] != "index" or x.get("write") or (x.get("key") or {}).get("k") != "str":
|
|
203
|
+
continue
|
|
204
|
+
tg = x.get("target") or {}
|
|
205
|
+
if not (tg.get("k") == "id" and tg["v"] == pn):
|
|
206
|
+
continue
|
|
207
|
+
key = x["key"]["v"]
|
|
208
|
+
if key in seen:
|
|
209
|
+
continue
|
|
210
|
+
seen.add(key)
|
|
211
|
+
fld = key_field.get((key, x["l"])) or next((v for (k, _), v in key_field.items() if k == key), None)
|
|
212
|
+
ftype = self.field_type(c, fld) if fld else None
|
|
213
|
+
cast = x.get("cast")
|
|
214
|
+
nullable = None
|
|
215
|
+
if cast:
|
|
216
|
+
nullable = cast.endswith("?") or cast == "dynamic"
|
|
217
|
+
if x.get("coalesce") or (x.get("post") and x.get("post") in ("toString",) and False):
|
|
218
|
+
nullable = True
|
|
219
|
+
if nullable is None and ftype:
|
|
220
|
+
nullable = ftype.endswith("?") or ftype == "dynamic"
|
|
221
|
+
ref, many = self.ref_of(c, ftype)
|
|
222
|
+
out.append({"key": key, "field": fld, "type": ftype or cast, "cast": cast, "nullable": nullable,
|
|
223
|
+
"required": not nullable if nullable is not None else None, "coalesce": x.get("coalesce"),
|
|
224
|
+
"post": x.get("post"), "wrap": x.get("wrap"), "line": x["l"], "file": f.file, "source": source,
|
|
225
|
+
"ref": ref, "many": many or None})
|
|
226
|
+
return out
|
|
227
|
+
|
|
228
|
+
def to_fn(self, c: DClass, f: DFunc, source: str) -> list[dict]:
|
|
229
|
+
out = []
|
|
230
|
+
ctx = Ctx(self.prog, f.lib, f, f.cls)
|
|
231
|
+
for x in f.facts:
|
|
232
|
+
if x["ft"] != "return":
|
|
233
|
+
continue
|
|
234
|
+
v = x["v"]
|
|
235
|
+
maps = [y for y in walk_repr(v) if y.get("k") == "map"][:1]
|
|
236
|
+
for m in maps:
|
|
237
|
+
for el in m.get("entries") or []:
|
|
238
|
+
kk = el.get("key") or {}
|
|
239
|
+
if kk.get("k") != "str":
|
|
240
|
+
if el.get("k") == "if":
|
|
241
|
+
th = el.get("then") or {}
|
|
242
|
+
if (th.get("key") or {}).get("k") == "str":
|
|
243
|
+
fld = last_name(th.get("value"))
|
|
244
|
+
ft = self.field_type(c, fld) if fld else None
|
|
245
|
+
out.append({"key": th["key"]["v"], "field": fld, "type": ft, "nullable": True, "conditional": True,
|
|
246
|
+
"line": th.get("l") or m.get("l"), "file": f.file, "source": source})
|
|
247
|
+
continue
|
|
248
|
+
fld = last_name(el.get("value"))
|
|
249
|
+
ft = self.field_type(c, fld) if fld else None
|
|
250
|
+
ref, many = self.ref_of(c, ft)
|
|
251
|
+
out.append({"key": kk["v"], "field": fld, "type": ft, "nullable": (ft.endswith("?") if ft else None),
|
|
252
|
+
"line": el.get("l") or m.get("l"), "file": f.file, "source": source, "ref": ref, "many": many or None})
|
|
253
|
+
if maps:
|
|
254
|
+
break
|
|
255
|
+
return out
|
|
256
|
+
|
|
257
|
+
def annotated(self, c: DClass, how: str | None, freezed: bool) -> list[dict]:
|
|
258
|
+
items = []
|
|
259
|
+
if freezed:
|
|
260
|
+
for ct in c.ctors.values():
|
|
261
|
+
if ct.raw.get("factory") and ct.name not in ("fromJson", "fromMap") and ct.raw.get("redirect"):
|
|
262
|
+
for p in ct.params:
|
|
263
|
+
items.append((p["name"], p.get("type"), p.get("ann") or [], p.get("default"), ct.line, ct.file, p.get("required")))
|
|
264
|
+
break
|
|
265
|
+
else:
|
|
266
|
+
for fv in c.fields.values():
|
|
267
|
+
if fv.static:
|
|
268
|
+
continue
|
|
269
|
+
items.append((fv.name, fv.type, fv.ann, fv.init, fv.line, fv.file, None))
|
|
270
|
+
out = []
|
|
271
|
+
for name, t, anns, default, line, file, req in items:
|
|
272
|
+
jk = ann_get(anns, "JsonKey")
|
|
273
|
+
if jk and (ann_str(jk, "ignore") is True or (ann_str(jk, "includeFromJson") is False and ann_str(jk, "includeToJson") is False)):
|
|
274
|
+
continue
|
|
275
|
+
key = ann_str(jk, "name") or rename(name, how)
|
|
276
|
+
has_default = default is not None or ann_get(anns, "Default") is not None or (jk and "defaultValue" in (jk.get("na") or {}))
|
|
277
|
+
nullable = bool(t and (t.endswith("?") or t == "dynamic"))
|
|
278
|
+
ref, many = self.ref_of(c, t)
|
|
279
|
+
out.append({"key": key, "field": name, "type": t, "nullable": nullable, "required": not nullable and not has_default,
|
|
280
|
+
"default": bool(has_default) or None, "line": line, "file": file, "source": "annotation", "ref": ref,
|
|
281
|
+
"many": many or None, "from": not (jk and ann_str(jk, "includeFromJson") is False),
|
|
282
|
+
"to": not (jk and ann_str(jk, "includeToJson") is False)})
|
|
283
|
+
return out
|
|
284
|
+
|
|
285
|
+
def enum_values(self, c: DClass) -> list[dict]:
|
|
286
|
+
je = ann_get(c.raw.get("ann") or [], "JsonEnum")
|
|
287
|
+
how = ann_str(je, "fieldRename")
|
|
288
|
+
vf = ann_str(je, "valueField")
|
|
289
|
+
out = []
|
|
290
|
+
idx = None
|
|
291
|
+
if vf:
|
|
292
|
+
ct = c.ctors.get("new")
|
|
293
|
+
if ct:
|
|
294
|
+
for i, p in enumerate(ct.params):
|
|
295
|
+
if p["name"] == vf:
|
|
296
|
+
idx = i
|
|
297
|
+
for v in c.raw.get("values") or []:
|
|
298
|
+
jv = ann_get(v.get("ann") or [], "JsonValue")
|
|
299
|
+
wire, how_ = None, "name"
|
|
300
|
+
if jv and jv.get("a"):
|
|
301
|
+
a0 = jv["a"][0]
|
|
302
|
+
wire, how_ = a0.get("v"), "@JsonValue"
|
|
303
|
+
elif idx is not None and v.get("a") and idx < len(v["a"]):
|
|
304
|
+
wire, how_ = v["a"][idx].get("v"), f"valueField {vf}"
|
|
305
|
+
else:
|
|
306
|
+
wire = rename(v["name"], how)
|
|
307
|
+
out.append({"name": v["name"], "wire": wire, "how": how_, "line": v.get("l"), "file": c.file})
|
|
308
|
+
return out
|