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.
Files changed (174) hide show
  1. cg_code_graph-0.10.1.dist-info/METADATA +678 -0
  2. cg_code_graph-0.10.1.dist-info/RECORD +174 -0
  3. cg_code_graph-0.10.1.dist-info/WHEEL +5 -0
  4. cg_code_graph-0.10.1.dist-info/entry_points.txt +3 -0
  5. cg_code_graph-0.10.1.dist-info/licenses/LICENSE +21 -0
  6. cg_code_graph-0.10.1.dist-info/top_level.txt +1 -0
  7. codegraph/__init__.py +2 -0
  8. codegraph/aitools.py +129 -0
  9. codegraph/apps.py +76 -0
  10. codegraph/blindspots.py +428 -0
  11. codegraph/bridges.py +1701 -0
  12. codegraph/cli.py +725 -0
  13. codegraph/concepts.py +362 -0
  14. codegraph/config.py +559 -0
  15. codegraph/core/__init__.py +0 -0
  16. codegraph/core/cache.py +375 -0
  17. codegraph/core/detect.py +80 -0
  18. codegraph/core/extractors.py +187 -0
  19. codegraph/core/fsutil.py +61 -0
  20. codegraph/core/generated.py +575 -0
  21. codegraph/core/model.py +174 -0
  22. codegraph/core/paths.py +175 -0
  23. codegraph/core/plugin.py +160 -0
  24. codegraph/core/store.py +80 -0
  25. codegraph/core/syntax_errors.py +132 -0
  26. codegraph/coverage.py +928 -0
  27. codegraph/doctor.py +453 -0
  28. codegraph/external.py +613 -0
  29. codegraph/indexer.py +336 -0
  30. codegraph/link.py +434 -0
  31. codegraph/lint_async.py +524 -0
  32. codegraph/mcp_server.py +1303 -0
  33. codegraph/parity.py +473 -0
  34. codegraph/parity_structure.py +307 -0
  35. codegraph/payload.py +321 -0
  36. codegraph/plans.py +1285 -0
  37. codegraph/platform_scan.py +643 -0
  38. codegraph/platforms.py +1369 -0
  39. codegraph/plugins/__init__.py +0 -0
  40. codegraph/plugins/cfamily/__init__.py +0 -0
  41. codegraph/plugins/cfamily/plugin.py +930 -0
  42. codegraph/plugins/cfamily/syntax.py +881 -0
  43. codegraph/plugins/dart/__init__.py +0 -0
  44. codegraph/plugins/dart/bridges.py +345 -0
  45. codegraph/plugins/dart/extractor/bin/extract.dart +717 -0
  46. codegraph/plugins/dart/extractor/pubspec.lock +149 -0
  47. codegraph/plugins/dart/extractor/pubspec.yaml +7 -0
  48. codegraph/plugins/dart/http.py +904 -0
  49. codegraph/plugins/dart/models.py +308 -0
  50. codegraph/plugins/dart/plugin.py +625 -0
  51. codegraph/plugins/dart/program.py +907 -0
  52. codegraph/plugins/django/__init__.py +0 -0
  53. codegraph/plugins/django/extras.py +378 -0
  54. codegraph/plugins/django/models.py +508 -0
  55. codegraph/plugins/django/plugin.py +728 -0
  56. codegraph/plugins/django/schemas.py +339 -0
  57. codegraph/plugins/django/shapes.py +216 -0
  58. codegraph/plugins/django/urls.py +603 -0
  59. codegraph/plugins/express/__init__.py +0 -0
  60. codegraph/plugins/express/plugin.py +428 -0
  61. codegraph/plugins/flutter/__init__.py +0 -0
  62. codegraph/plugins/flutter/plugin.py +538 -0
  63. codegraph/plugins/kotlin/__init__.py +0 -0
  64. codegraph/plugins/kotlin/exact.py +457 -0
  65. codegraph/plugins/kotlin/plugin.py +1961 -0
  66. codegraph/plugins/kotlin/reparse.py +234 -0
  67. codegraph/plugins/laravel/__init__.py +0 -0
  68. codegraph/plugins/laravel/broadcast.py +351 -0
  69. codegraph/plugins/laravel/plugin.py +863 -0
  70. codegraph/plugins/laravel/tests.py +262 -0
  71. codegraph/plugins/laravel/values.py +728 -0
  72. codegraph/plugins/native/__init__.py +0 -0
  73. codegraph/plugins/native/gates.py +286 -0
  74. codegraph/plugins/native/runner.py +183 -0
  75. codegraph/plugins/native/scipread.py +194 -0
  76. codegraph/plugins/native/ts.py +54 -0
  77. codegraph/plugins/nest/__init__.py +0 -0
  78. codegraph/plugins/nest/plugin.py +654 -0
  79. codegraph/plugins/nextjs/__init__.py +0 -0
  80. codegraph/plugins/nextjs/plugin.py +336 -0
  81. codegraph/plugins/nuxt/__init__.py +0 -0
  82. codegraph/plugins/nuxt/plugin.py +308 -0
  83. codegraph/plugins/php/__init__.py +0 -0
  84. codegraph/plugins/php/extractor/composer.json +5 -0
  85. codegraph/plugins/php/extractor/composer.lock +76 -0
  86. codegraph/plugins/php/extractor/extract.php +743 -0
  87. codegraph/plugins/php/gating.py +573 -0
  88. codegraph/plugins/php/plugin.py +668 -0
  89. codegraph/plugins/php/strings.py +197 -0
  90. codegraph/plugins/python/__init__.py +0 -0
  91. codegraph/plugins/python/aitools.py +664 -0
  92. codegraph/plugins/python/external.py +245 -0
  93. codegraph/plugins/python/fields.py +107 -0
  94. codegraph/plugins/python/plugin.py +1733 -0
  95. codegraph/plugins/python/refs.py +485 -0
  96. codegraph/plugins/python/roots.py +412 -0
  97. codegraph/plugins/python/socketio.py +210 -0
  98. codegraph/plugins/python/subproc.py +864 -0
  99. codegraph/plugins/python/tests.py +1040 -0
  100. codegraph/plugins/python/values.py +179 -0
  101. codegraph/plugins/pyweb/__init__.py +0 -0
  102. codegraph/plugins/pyweb/plugin.py +1334 -0
  103. codegraph/plugins/pyweb/values.py +68 -0
  104. codegraph/plugins/rust/__init__.py +0 -0
  105. codegraph/plugins/rust/cargo.py +226 -0
  106. codegraph/plugins/rust/plugin.py +980 -0
  107. codegraph/plugins/rust/syntax.py +678 -0
  108. codegraph/plugins/scip/__init__.py +0 -0
  109. codegraph/plugins/scip/importer.py +129 -0
  110. codegraph/plugins/scip/scip.proto +962 -0
  111. codegraph/plugins/scip/scip_pb2.py +97 -0
  112. codegraph/plugins/stubs/__init__.py +0 -0
  113. codegraph/plugins/stubs/plugins.py +38 -0
  114. codegraph/plugins/swift/__init__.py +0 -0
  115. codegraph/plugins/swift/baseurl.py +109 -0
  116. codegraph/plugins/swift/exact.py +415 -0
  117. codegraph/plugins/swift/indexstore.py +209 -0
  118. codegraph/plugins/swift/packages.py +174 -0
  119. codegraph/plugins/swift/plugin.py +2890 -0
  120. codegraph/plugins/ts/__init__.py +0 -0
  121. codegraph/plugins/ts/baseurl.py +185 -0
  122. codegraph/plugins/ts/extractor/extract.mjs +2652 -0
  123. codegraph/plugins/ts/extractor/fw.mjs +685 -0
  124. codegraph/plugins/ts/extractor/package-lock.json +205 -0
  125. codegraph/plugins/ts/extractor/package.json +9 -0
  126. codegraph/plugins/ts/plugin.py +480 -0
  127. codegraph/plugins/tsweb/__init__.py +0 -0
  128. codegraph/plugins/tsweb/common.py +290 -0
  129. codegraph/plugins/tsweb/data.py +276 -0
  130. codegraph/presets/__init__.py +146 -0
  131. codegraph/presets/c_cpp.yaml +9 -0
  132. codegraph/presets/common.yaml +66 -0
  133. codegraph/presets/dart.yaml +9 -0
  134. codegraph/presets/django-ninja.yaml +15 -0
  135. codegraph/presets/django.yaml +25 -0
  136. codegraph/presets/djangorestframework.yaml +17 -0
  137. codegraph/presets/express.yaml +17 -0
  138. codegraph/presets/kotlin.yaml +11 -0
  139. codegraph/presets/laravel.yaml +40 -0
  140. codegraph/presets/nest.yaml +11 -0
  141. codegraph/presets/nextjs.yaml +15 -0
  142. codegraph/presets/nuxt.yaml +9 -0
  143. codegraph/presets/php.yaml +5 -0
  144. codegraph/presets/python.yaml +10 -0
  145. codegraph/presets/rust.yaml +5 -0
  146. codegraph/presets/swift.yaml +10 -0
  147. codegraph/presets/typescript.yaml +13 -0
  148. codegraph/process_runs.py +328 -0
  149. codegraph/protocols/__init__.py +299 -0
  150. codegraph/protocols/builtin.py +67 -0
  151. codegraph/protocols/matchers.py +144 -0
  152. codegraph/protocols/view.py +334 -0
  153. codegraph/query.py +2089 -0
  154. codegraph/realtime.py +260 -0
  155. codegraph/roundtrip.py +346 -0
  156. codegraph/routes.py +442 -0
  157. codegraph/starters.py +218 -0
  158. codegraph/tests_index.py +117 -0
  159. codegraph/viz/__init__.py +0 -0
  160. codegraph/viz/graph.py +369 -0
  161. codegraph/viz/server.py +198 -0
  162. codegraph/viz/static/app.css +148 -0
  163. codegraph/viz/static/app.js +1082 -0
  164. codegraph/viz/static/index.html +81 -0
  165. codegraph/viz/static/layered.js +237 -0
  166. codegraph/viz/static/vendor/VERSIONS.txt +4 -0
  167. codegraph/viz/static/vendor/cose-base.js +3214 -0
  168. codegraph/viz/static/vendor/cytoscape-fcose.js +1549 -0
  169. codegraph/viz/static/vendor/cytoscape.min.js +31 -0
  170. codegraph/viz/static/vendor/layout-base.js +5230 -0
  171. codegraph/viz/tools/package-lock.json +303 -0
  172. codegraph/viz/tools/package.json +7 -0
  173. codegraph/viz/tools/shoot.mjs +165 -0
  174. 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