cg-code-graph 0.23.7__tar.gz → 0.23.9__tar.gz

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 (418) hide show
  1. {cg_code_graph-0.23.7/cg_code_graph.egg-info → cg_code_graph-0.23.9}/PKG-INFO +1 -1
  2. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/__init__.py +1 -1
  3. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/cli.py +6 -3
  4. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/parity.py +77 -9
  5. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/parity_structure.py +119 -0
  6. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/platforms.py +35 -0
  7. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/kotlin/plugin.py +169 -5
  8. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/swift/plugin.py +200 -14
  9. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9/cg_code_graph.egg-info}/PKG-INFO +1 -1
  10. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph.egg-info/SOURCES.txt +3 -0
  11. cg_code_graph-0.23.9/tests/test_dispatch_part3.py +122 -0
  12. cg_code_graph-0.23.9/tests/test_parity_fields.py +125 -0
  13. cg_code_graph-0.23.9/tests/test_swift_platform_files.py +103 -0
  14. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/LICENSE +0 -0
  15. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/MANIFEST.in +0 -0
  16. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/README.md +0 -0
  17. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/__main__.py +0 -0
  18. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/affected.py +0 -0
  19. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/agent_rules.py +0 -0
  20. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/agents.py +0 -0
  21. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/aitools.py +0 -0
  22. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/android_ipc.py +0 -0
  23. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/apple_ipc.py +0 -0
  24. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/apps.py +0 -0
  25. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/blindspots.py +0 -0
  26. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/bridges.py +0 -0
  27. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/brokers.py +0 -0
  28. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/cmake_sources.py +0 -0
  29. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/concepts.py +0 -0
  30. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/config.py +0 -0
  31. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/__init__.py +0 -0
  32. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/cache.py +0 -0
  33. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/detect.py +0 -0
  34. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/env.py +0 -0
  35. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/extractors.py +0 -0
  36. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/fsutil.py +0 -0
  37. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/generated.py +0 -0
  38. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/model.py +0 -0
  39. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/paths.py +0 -0
  40. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/plugin.py +0 -0
  41. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/redact.py +0 -0
  42. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/store.py +0 -0
  43. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/syntax_errors.py +0 -0
  44. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/coverage.py +0 -0
  45. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/dart_isolates.py +0 -0
  46. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/doctor.py +0 -0
  47. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/explore.py +0 -0
  48. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/external.py +0 -0
  49. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/graphql.py +0 -0
  50. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/guard_facts.py +0 -0
  51. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/hooks.py +0 -0
  52. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/indexer.py +0 -0
  53. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/insecure_transport.py +0 -0
  54. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/install_rules.py +0 -0
  55. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/jobs.py +0 -0
  56. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/link.py +0 -0
  57. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/lint_async.py +0 -0
  58. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/local_ipc.py +0 -0
  59. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/local_sockets.py +0 -0
  60. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/mcp_graphs.py +0 -0
  61. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/mcp_install.py +0 -0
  62. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/mcp_server.py +0 -0
  63. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/payload.py +0 -0
  64. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plans.py +0 -0
  65. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/platform_scan.py +0 -0
  66. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/__init__.py +0 -0
  67. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/astro/__init__.py +0 -0
  68. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/astro/content.py +0 -0
  69. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/astro/plugin.py +0 -0
  70. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/cfamily/__init__.py +0 -0
  71. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/cfamily/plugin.py +0 -0
  72. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/cfamily/syntax.py +0 -0
  73. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/__init__.py +0 -0
  74. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/bridges.py +0 -0
  75. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/extractor/bin/extract.dart +0 -0
  76. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/extractor/pubspec.lock +0 -0
  77. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/extractor/pubspec.yaml +0 -0
  78. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/http.py +0 -0
  79. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/models.py +0 -0
  80. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/plugin.py +0 -0
  81. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/program.py +0 -0
  82. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/django/__init__.py +0 -0
  83. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/django/extras.py +0 -0
  84. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/django/models.py +0 -0
  85. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/django/plugin.py +0 -0
  86. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/django/schemas.py +0 -0
  87. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/django/shapes.py +0 -0
  88. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/django/urls.py +0 -0
  89. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/express/__init__.py +0 -0
  90. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/express/plugin.py +0 -0
  91. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/flutter/__init__.py +0 -0
  92. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/flutter/plugin.py +0 -0
  93. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/java/__init__.py +0 -0
  94. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/java/exact.py +0 -0
  95. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/java/plugin.py +0 -0
  96. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/jvm/__init__.py +0 -0
  97. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/jvm/interop.py +0 -0
  98. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/jvm/spring.py +0 -0
  99. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/kotlin/__init__.py +0 -0
  100. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/kotlin/exact.py +0 -0
  101. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/kotlin/reparse.py +0 -0
  102. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/laravel/__init__.py +0 -0
  103. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/laravel/broadcast.py +0 -0
  104. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/laravel/massassign.py +0 -0
  105. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/laravel/plugin.py +0 -0
  106. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/laravel/tests.py +0 -0
  107. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/laravel/values.py +0 -0
  108. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/native/__init__.py +0 -0
  109. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/native/gates.py +0 -0
  110. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/native/runner.py +0 -0
  111. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/native/scipread.py +0 -0
  112. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/native/ts.py +0 -0
  113. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/nest/__init__.py +0 -0
  114. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/nest/plugin.py +0 -0
  115. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/nextjs/__init__.py +0 -0
  116. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/nextjs/plugin.py +0 -0
  117. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/nuxt/__init__.py +0 -0
  118. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/nuxt/plugin.py +0 -0
  119. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/__init__.py +0 -0
  120. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/external.py +0 -0
  121. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/extractor/composer.json +0 -0
  122. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/extractor/composer.lock +0 -0
  123. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/extractor/extract.php +0 -0
  124. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/gating.py +0 -0
  125. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/http_client.py +0 -0
  126. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/inline_guards.py +0 -0
  127. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/plugin.py +0 -0
  128. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/strings.py +0 -0
  129. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/__init__.py +0 -0
  130. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/aitools.py +0 -0
  131. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/external.py +0 -0
  132. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/fields.py +0 -0
  133. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/plugin.py +0 -0
  134. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/refs.py +0 -0
  135. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/roots.py +0 -0
  136. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/socketio.py +0 -0
  137. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/subproc.py +0 -0
  138. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/tests.py +0 -0
  139. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/values.py +0 -0
  140. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/pyweb/__init__.py +0 -0
  141. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/pyweb/plugin.py +0 -0
  142. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/pyweb/values.py +0 -0
  143. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/rust/__init__.py +0 -0
  144. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/rust/cargo.py +0 -0
  145. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/rust/plugin.py +0 -0
  146. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/rust/syntax.py +0 -0
  147. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/scip/__init__.py +0 -0
  148. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/scip/importer.py +0 -0
  149. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/scip/scip.proto +0 -0
  150. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/scip/scip_pb2.py +0 -0
  151. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/stubs/__init__.py +0 -0
  152. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/stubs/plugins.py +0 -0
  153. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/swift/__init__.py +0 -0
  154. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/swift/baseurl.py +0 -0
  155. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/swift/exact.py +0 -0
  156. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/swift/indexstore.py +0 -0
  157. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/swift/packages.py +0 -0
  158. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/__init__.py +0 -0
  159. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/baseurl.py +0 -0
  160. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/extractor/extract.mjs +0 -0
  161. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/extractor/fw.mjs +0 -0
  162. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/extractor/package-lock.json +0 -0
  163. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/extractor/package.json +0 -0
  164. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/extractor/rr.mjs +0 -0
  165. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/nav.py +0 -0
  166. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/plugin.py +0 -0
  167. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/react_router.py +0 -0
  168. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/tsweb/__init__.py +0 -0
  169. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/tsweb/common.py +0 -0
  170. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/tsweb/data.py +0 -0
  171. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/__init__.py +0 -0
  172. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/c_cpp.yaml +0 -0
  173. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/common.yaml +0 -0
  174. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/dart.yaml +0 -0
  175. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/django-ninja.yaml +0 -0
  176. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/django.yaml +0 -0
  177. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/djangorestframework.yaml +0 -0
  178. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/express.yaml +0 -0
  179. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/java.yaml +0 -0
  180. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/kotlin.yaml +0 -0
  181. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/laravel.yaml +0 -0
  182. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/nest.yaml +0 -0
  183. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/nextjs.yaml +0 -0
  184. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/nuxt.yaml +0 -0
  185. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/php.yaml +0 -0
  186. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/python.yaml +0 -0
  187. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/react-router.yaml +0 -0
  188. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/rust.yaml +0 -0
  189. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/spring.yaml +0 -0
  190. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/swift.yaml +0 -0
  191. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/typescript.yaml +0 -0
  192. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/process_runs.py +0 -0
  193. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/protocols/__init__.py +0 -0
  194. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/protocols/builtin.py +0 -0
  195. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/protocols/matchers.py +0 -0
  196. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/protocols/view.py +0 -0
  197. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/query.py +0 -0
  198. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/realtime.py +0 -0
  199. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/realtime_events.py +0 -0
  200. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/realtime_native.py +0 -0
  201. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/realtime_ws.py +0 -0
  202. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/roundtrip.py +0 -0
  203. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/routes.py +0 -0
  204. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/rpc.py +0 -0
  205. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/sdk_systems.py +0 -0
  206. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/sockets.py +0 -0
  207. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/ssrf_input.py +0 -0
  208. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/starters.py +0 -0
  209. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/surface.py +0 -0
  210. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/tests_index.py +0 -0
  211. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/udp_apps.py +0 -0
  212. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/update_check.py +0 -0
  213. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/__init__.py +0 -0
  214. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/graph.py +0 -0
  215. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/server.py +0 -0
  216. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/app.css +0 -0
  217. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/app.js +0 -0
  218. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/index.html +0 -0
  219. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/layered.js +0 -0
  220. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/vendor/VERSIONS.txt +0 -0
  221. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/vendor/cose-base.js +0 -0
  222. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/vendor/cytoscape-fcose.js +0 -0
  223. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/vendor/cytoscape.min.js +0 -0
  224. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/vendor/layout-base.js +0 -0
  225. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/tools/package-lock.json +0 -0
  226. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/tools/package.json +0 -0
  227. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/tools/shoot.mjs +0 -0
  228. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/watch.py +0 -0
  229. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/webhook_subs.py +0 -0
  230. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/webhooks.py +0 -0
  231. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/xcode.py +0 -0
  232. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph.egg-info/dependency_links.txt +0 -0
  233. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph.egg-info/entry_points.txt +0 -0
  234. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph.egg-info/requires.txt +0 -0
  235. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph.egg-info/top_level.txt +0 -0
  236. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/pyproject.toml +0 -0
  237. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/setup.cfg +0 -0
  238. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_affected.py +0 -0
  239. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_agents_install.py +0 -0
  240. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_agents_md.py +0 -0
  241. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ai_tools.py +0 -0
  242. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_android_ipc.py +0 -0
  243. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_apple_ipc.py +0 -0
  244. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_astro.py +0 -0
  245. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_astro_content.py +0 -0
  246. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_astro_server.py +0 -0
  247. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_bridges.py +0 -0
  248. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_bridges_pigeon_monorepo.py +0 -0
  249. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_brokers.py +0 -0
  250. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_cache_clean.py +0 -0
  251. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_cache_invalidation.py +0 -0
  252. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_cache_migration.py +0 -0
  253. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_channels_tests.py +0 -0
  254. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_cli_output.py +0 -0
  255. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_cmake_sources.py +0 -0
  256. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_completeness.py +0 -0
  257. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_config_extras.py +0 -0
  258. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_coverage.py +0 -0
  259. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_coverage_ts_hint.py +0 -0
  260. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_dart_isolates.py +0 -0
  261. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_db_connections.py +0 -0
  262. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_dead_wrappers.py +0 -0
  263. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_dispatch_interfaces.py +0 -0
  264. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_django_flutter.py +0 -0
  265. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_docs_languages.py +0 -0
  266. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_docs_links.py +0 -0
  267. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_echo_ref.py +0 -0
  268. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_echo_wrapper.py +0 -0
  269. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_elysia.py +0 -0
  270. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_enum_constants.py +0 -0
  271. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_env.py +0 -0
  272. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_explore.py +0 -0
  273. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_external.py +0 -0
  274. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_fp_batch.py +0 -0
  275. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_gating.py +0 -0
  276. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_generated.py +0 -0
  277. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_graphql.py +0 -0
  278. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_hooks.py +0 -0
  279. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_impact_overrides.py +0 -0
  280. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_index_isolation.py +0 -0
  281. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_inherited_overrides.py +0 -0
  282. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_inline_guards.py +0 -0
  283. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_install_rules.py +0 -0
  284. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_192.py +0 -0
  285. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_201.py +0 -0
  286. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_202.py +0 -0
  287. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_203.py +0 -0
  288. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_204.py +0 -0
  289. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_205.py +0 -0
  290. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_206.py +0 -0
  291. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_207.py +0 -0
  292. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_208.py +0 -0
  293. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_209.py +0 -0
  294. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_210.py +0 -0
  295. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_211.py +0 -0
  296. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_211_used_at.py +0 -0
  297. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_212.py +0 -0
  298. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_212_langs.py +0 -0
  299. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_218.py +0 -0
  300. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_219.py +0 -0
  301. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_222.py +0 -0
  302. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_java.py +0 -0
  303. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_java_exact.py +0 -0
  304. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_jobs.py +0 -0
  305. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_js_refs.py +0 -0
  306. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_js_runtime.py +0 -0
  307. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_kotlin.py +0 -0
  308. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_kotlin_binding.py +0 -0
  309. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_kotlin_exact.py +0 -0
  310. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_kotlin_fields.py +0 -0
  311. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_kotlin_mixed.py +0 -0
  312. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_kotlin_nav_consts.py +0 -0
  313. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_kotlin_props.py +0 -0
  314. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_laravel_determinism.py +0 -0
  315. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_laravel_receiver_narrowing.py +0 -0
  316. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_laravel_resources.py +0 -0
  317. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_laravel_route_paths.py +0 -0
  318. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_link_origin.py +0 -0
  319. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_lint_async.py +0 -0
  320. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_listing_files.py +0 -0
  321. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_local_ipc.py +0 -0
  322. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_local_sockets.py +0 -0
  323. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_mass_assignment.py +0 -0
  324. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_mcp.py +0 -0
  325. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_mcp_index.py +0 -0
  326. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_mcp_install.py +0 -0
  327. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_mcp_instructions.py +0 -0
  328. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_mcp_multi_graph.py +0 -0
  329. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_native_cfamily.py +0 -0
  330. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_native_concurrency.py +0 -0
  331. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_native_rust.py +0 -0
  332. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_nuxt_i18n.py +0 -0
  333. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_nuxt_import_dirs.py +0 -0
  334. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_nuxt_nitro.py +0 -0
  335. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_nuxt_rootsrc.py +0 -0
  336. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_nuxt_side_dirs.py +0 -0
  337. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_packaging.py +0 -0
  338. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_parity.py +0 -0
  339. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_parity_structure.py +0 -0
  340. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_php_http.py +0 -0
  341. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_php_props.py +0 -0
  342. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_plain_js.py +0 -0
  343. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_plans.py +0 -0
  344. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_platform_gaps.py +0 -0
  345. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_platform_type_variants.py +0 -0
  346. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_platforms.py +0 -0
  347. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_platforms_apple.py +0 -0
  348. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_presets_config.py +0 -0
  349. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_process_ipc.py +0 -0
  350. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_process_runs.py +0 -0
  351. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_protocols.py +0 -0
  352. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_app_tests_module.py +0 -0
  353. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_collection_chains.py +0 -0
  354. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_compat.py +0 -0
  355. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_entry_refs.py +0 -0
  356. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_fields.py +0 -0
  357. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_infer_cycles.py +0 -0
  358. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_roots.py +0 -0
  359. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_subprocess_tests.py +0 -0
  360. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_tests.py +0 -0
  361. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_web_hosts.py +0 -0
  362. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_web_routes.py +0 -0
  363. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_web_routes_more.py +0 -0
  364. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_react_router.py +0 -0
  365. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_readers_writers_specs.py +0 -0
  366. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_realtime.py +0 -0
  367. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_realtime_native.py +0 -0
  368. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_redact_salt.py +0 -0
  369. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_request_keys.py +0 -0
  370. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_roundtrip.py +0 -0
  371. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_route_specs.py +0 -0
  372. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_route_tables.py +0 -0
  373. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_routes_search_explain.py +0 -0
  374. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_rpc.py +0 -0
  375. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_scip_health.py +0 -0
  376. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_sdk_external.py +0 -0
  377. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_sdk_external_infra.py +0 -0
  378. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_sdk_external_mail.py +0 -0
  379. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_snippet.py +0 -0
  380. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_sockets.py +0 -0
  381. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_spring.py +0 -0
  382. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ssrf.py +0 -0
  383. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_starters_budget.py +0 -0
  384. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_surface.py +0 -0
  385. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_surface_transport.py +0 -0
  386. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift.py +0 -0
  387. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_binding.py +0 -0
  388. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_exact.py +0 -0
  389. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_facts.py +0 -0
  390. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_fields.py +0 -0
  391. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_modules.py +0 -0
  392. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_more.py +0 -0
  393. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_nav_values.py +0 -0
  394. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_parse_errors.py +0 -0
  395. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_props.py +0 -0
  396. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_sdk.py +0 -0
  397. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_testing.py +0 -0
  398. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_values.py +0 -0
  399. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_tauri_events.py +0 -0
  400. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_tests_scope.py +0 -0
  401. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ts_fields.py +0 -0
  402. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ts_fields_js_vue.py +0 -0
  403. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ts_file_specs.py +0 -0
  404. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ts_frameworks.py +0 -0
  405. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ts_node_http.py +0 -0
  406. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ts_nuxt.py +0 -0
  407. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ts_src_tsconfig.py +0 -0
  408. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_unguarded.py +0 -0
  409. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_update_check.py +0 -0
  410. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_values.py +0 -0
  411. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_viz.py +0 -0
  412. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_vue_nav.py +0 -0
  413. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_watch.py +0 -0
  414. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_webhooks.py +0 -0
  415. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_webhooks_152.py +0 -0
  416. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_webhooks_152b.py +0 -0
  417. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_websockets.py +0 -0
  418. {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_workspace_link.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cg-code-graph
3
- Version: 0.23.7
3
+ Version: 0.23.9
4
4
  Summary: cg: a code graph of routes, calls, data access and platform boundaries for agents and humans (CLI + MCP server)
5
5
  Author: cyberchronos00
6
6
  License-Expression: MIT
@@ -1,2 +1,2 @@
1
1
  """code-graph: deterministic code knowledge graph (beta)."""
2
- __version__ = "0.23.7"
2
+ __version__ = "0.23.9"
@@ -301,9 +301,12 @@ def main(argv=None):
301
301
  p.add_argument("--strip-prefix", action="append", default=[], help="a name prefix one side adds (`Vault` in "
302
302
  "VaultAddEditState for AddEditState), ignored when matching (repeatable)")
303
303
  p.add_argument("--structure", action="store_true", help="also pair symbols whose names differ by what they use: "
304
- "shared strings, localization keys, endpoints and already-paired callees, plus rename rules learned "
305
- "from the pairs found (#93); matches carry their evidence")
304
+ "shared strings, localization keys, resources, endpoints and already-paired callees, then types by "
305
+ "their declared fields, plus rename rules learned from the pairs found (#93); matches carry their "
306
+ "evidence")
306
307
  p.add_argument("--no-learn", action="store_true", help="with --structure: no learned rename rules")
308
+ p.add_argument("--both-sides", action="store_true", help="also list the matched pairs and what only --against "
309
+ "has (target symbols no source symbol matched)")
307
310
  p.add_argument("--write-map", help="with --structure: write the inferred pairs as a --map JSON file to review")
308
311
  p.add_argument("--json", action="store_true"); p.add_argument("--max-items", type=int, default=200)
309
312
  p = sub.add_parser("lint", help="heuristic lints (#88): `lint async-state` flags stale async results, state with "
@@ -574,7 +577,7 @@ def main(argv=None):
574
577
  from . import parity as PA
575
578
  mapping = json.loads(open(a.map, encoding="utf-8").read()) if a.map else None
576
579
  res = PA.parity(a.db, a.against, mapping=mapping, fuzzy=not a.no_fuzzy, strip_prefixes=a.strip_prefix,
577
- structure=a.structure, learn=not a.no_learn)
580
+ structure=a.structure, learn=not a.no_learn, both_sides=a.both_sides)
578
581
  if a.write_map:
579
582
  with open(a.write_map, "w", encoding="utf-8") as fh:
580
583
  json.dump(PA.rename_map(res), fh, indent=1, sort_keys=True)
@@ -220,21 +220,27 @@ def _cat(sym: dict, is_type: bool) -> str:
220
220
  return "type" if is_type else "const" if sym["kind"] in ("constant", "enum_case") else "func"
221
221
 
222
222
 
223
+ INFERRED = ("structure", "fields", "learned")
224
+ PREVIEW_NAME = re.compile(r"Preview")
225
+
226
+
223
227
  def parity(source_db: str, target_db: str, mapping: dict | None = None, fuzzy: bool = True,
224
- strip_prefixes: list[str] | None = None, structure: bool = False, learn: bool = True) -> dict:
228
+ strip_prefixes: list[str] | None = None, structure: bool = False, learn: bool = True,
229
+ both_sides: bool = False) -> dict:
225
230
  """See the module docstring. `strip_prefixes`: name prefixes one side adds (`Vault` in `VaultAddEditState`
226
231
  for `AddEditState`), dropped before normalized matching on both sides. `structure` (#93): after the name rules,
227
232
  pair the rest by shared strings, localization keys, endpoints and paired callees, and (`learn`) apply rename
228
- rules learned from the pairs found (cg_code_graph/parity_structure.py); off, the output is the name matching alone."""
233
+ rules learned from the pairs found (cg_code_graph/parity_structure.py); off, the output is the name matching alone.
234
+ `both_sides`: also list what only the target has (`target_only`)."""
229
235
  _PREFIXES[:] = [p.lower() for p in strip_prefixes or ()]
230
236
  try:
231
- return _parity(source_db, target_db, mapping, fuzzy, structure, learn)
237
+ return _parity(source_db, target_db, mapping, fuzzy, structure, learn, both_sides)
232
238
  finally:
233
239
  _PREFIXES.clear()
234
240
 
235
241
 
236
242
  def _parity(source_db: str, target_db: str, mapping: dict | None, fuzzy: bool, structure: bool = False,
237
- learn: bool = True) -> dict:
243
+ learn: bool = True, both_sides: bool = False) -> dict:
238
244
  S, T = load(source_db), load(target_db)
239
245
  mapping = mapping or {}
240
246
  exact_ix, norm_ix, comp_ix, all_short = defaultdict(list), defaultdict(list), defaultdict(list), defaultdict(list)
@@ -357,7 +363,7 @@ def _parity(source_db: str, target_db: str, mapping: dict | None, fuzzy: bool, s
357
363
  tm.setdefault(_short(nt), T["types"][nt])
358
364
  tm_norm = {norm_member(k): k for k in tm}
359
365
  for nm, sym in sorted(S["members"].get(sfq, {}).items()):
360
- if nm in ("body", "init", "deinit", "hash", "description", "encode", "hashValue") or sym["override"]:
366
+ if nm in BOILERPLATE or sym["override"]:
361
367
  out["skipped"] += 1 # lifecycle / platform overrides (viewDidLoad, onCreate) and boilerplate
362
368
  continue
363
369
  if nm in tm:
@@ -375,7 +381,7 @@ def _parity(source_db: str, target_db: str, mapping: dict | None, fuzzy: bool, s
375
381
  match_members(tmap)
376
382
  if structure:
377
383
  _structure(S, T, out, tmap, learn)
378
- inferred = {r["symbol"]: r["target"] for r in out["matched"] if r.get("confidence") in ("structure", "learned")
384
+ inferred = {r["symbol"]: r["target"] for r in out["matched"] if r.get("confidence") in INFERRED
379
385
  and r["symbol"] in S["types"] and r["target"] in T["types"]}
380
386
  match_members(inferred)
381
387
  counts = defaultdict(int)
@@ -387,10 +393,44 @@ def _parity(source_db: str, target_db: str, mapping: dict | None, fuzzy: bool, s
387
393
  "missing": len(out["missing"]), "unknown": len(out["unknown"]),
388
394
  "platform_only": len(out["platform_only"])}
389
395
  if structure:
390
- out["summary"]["inferred"] = sum(1 for r in out["matched"] if r["confidence"] in ("structure", "learned"))
396
+ out["summary"]["inferred"] = sum(1 for r in out["matched"] if r["confidence"] in INFERRED)
397
+ if both_sides:
398
+ _target_only(T, out, t_nested)
399
+ out["summary"]["target_only"] = len(out["target_only"])
391
400
  return out
392
401
 
393
402
 
403
+ BOILERPLATE = ("body", "init", "deinit", "hash", "description", "encode", "hashValue")
404
+
405
+
406
+ def _target_only(T, out, t_nested):
407
+ """`--both-sides`: target types and top-level symbols no source symbol matched, and the unmatched members of
408
+ target types that were matched. Members of an unmatched type are counted under it, not listed."""
409
+ used = {r["target"] for r in out["matched"]}
410
+ rows, hidden = [], 0
411
+ for coll in (T["types"], T["top"]):
412
+ for fq, sym in sorted(coll.items()):
413
+ if fq in used:
414
+ continue
415
+ owner = fq.rsplit(".", 1)[0] if "." in fq else None
416
+ if owner in T["types"] and owner not in used:
417
+ continue # a nested type of an unmatched type: the type is listed
418
+ if PREVIEW_NAME.search(_short(fq)) or sym["file"] in T["err_files"]:
419
+ hidden += 1
420
+ continue
421
+ rows.append(_row(sym, None, None))
422
+ for o in sorted(o for o in T["members"] if o in used):
423
+ for nm, sym in sorted(T["members"][o].items()):
424
+ if f"{o}.{nm}" in used:
425
+ continue
426
+ if nm in BOILERPLATE or sym["override"] or sym["file"] in T["err_files"]:
427
+ hidden += 1
428
+ continue
429
+ rows.append(_row(sym, None, None))
430
+ out["target_only"] = rows
431
+ out["target_only_hidden"] = hidden
432
+
433
+
394
434
  def _structure(S, T, out, tmap, learn):
395
435
  from . import parity_structure as PS
396
436
  sym_of, cat_of, t_syms, t_cat = {}, {}, {}, {}
@@ -409,7 +449,7 @@ def _structure(S, T, out, tmap, learn):
409
449
 
410
450
  def rename_map(res: dict) -> dict:
411
451
  """The structure / learned matches as a `--map` file ({source: target}) to review and commit."""
412
- return {r["symbol"]: r["target"] for r in res["matched"] if r.get("confidence") in ("structure", "learned")}
452
+ return {r["symbol"]: r["target"] for r in res["matched"] if r.get("confidence") in INFERRED}
413
453
 
414
454
 
415
455
  def _row(sym, target, how, owner_match=None) -> dict:
@@ -435,6 +475,25 @@ def _group(file: str) -> str:
435
475
  return "/".join(parts[:2]) if len(parts) > 2 else (parts[0] if parts else "")
436
476
 
437
477
 
478
+ def _grouped(lines, title, rows, total, max_items):
479
+ by = defaultdict(list)
480
+ for r in rows:
481
+ by[r["module"]].append(r)
482
+ if not by:
483
+ return
484
+ lines += ["", f"== {title}: {total}"]
485
+ shown = 0
486
+ for mod in sorted(by, key=lambda k: -len(by[k])):
487
+ lines.append(f" {mod or '.'} ({len(by[mod])})")
488
+ for r in by[mod]:
489
+ if shown >= max_items:
490
+ break
491
+ shown += 1
492
+ lines.append(f" {r['symbol']} [{r['kind']}] {r['file']}:{r['line']}")
493
+ if shown < total:
494
+ lines.append(f" ... {total - shown} more (--json for all)")
495
+
496
+
438
497
  def render(res: dict, max_items: int = 200) -> str:
439
498
  s = res["summary"]
440
499
  m = s["matched"]
@@ -457,7 +516,14 @@ def render(res: dict, max_items: int = 200) -> str:
457
516
  lines.append(f" {r['symbol']} [{r['kind']}] {r['file']}:{r['line']}")
458
517
  if shown < s["missing"]:
459
518
  lines.append(f" ... {s['missing'] - shown} more (--json for all)")
460
- inferred = [r for r in res["matched"] if r.get("confidence") in ("structure", "learned")]
519
+ if "target_only" in res:
520
+ lines[1] += f"; {s['target_only']} only in the target"
521
+ lines += ["", f"== MATCHED pairs: {sum(m.values())}"]
522
+ for r in sorted(res["matched"], key=lambda r: (r["confidence"] != "explicit", r["symbol"]))[:max_items]:
523
+ lines.append(f" {r['symbol']} -> {r['target']} [{r['confidence']}]")
524
+ if sum(m.values()) > max_items:
525
+ lines.append(f" ... {sum(m.values()) - max_items} more (--json for all)")
526
+ inferred = [r for r in res["matched"] if r.get("confidence") in INFERRED]
461
527
  if inferred:
462
528
  lines += ["", f"== INFERRED matches (not by name): {len(inferred)}"]
463
529
  for r in inferred[:max_items]:
@@ -467,6 +533,8 @@ def render(res: dict, max_items: int = 200) -> str:
467
533
  if rule is (res.get("learned_rules") or [None])[0]:
468
534
  lines += ["", "== LEARNED rename rules"]
469
535
  lines.append(f" {rule['at']}: {rule['from']!r} -> {rule['to']!r} (seen {rule['support']}x)")
536
+ if "target_only" in res:
537
+ _grouped(lines, "ONLY IN TARGET (no source counterpart)", res["target_only"], s["target_only"], max_items)
470
538
  if res["unknown"]:
471
539
  lines += ["", f"== UNKNOWN (file parsed with syntax errors): {s['unknown']}"]
472
540
  lines += [f" {r['symbol']} {r['file']}:{r['line']}" for r in res["unknown"][:max_items]]
@@ -11,8 +11,21 @@ its outgoing edges:
11
11
  sym:<target> symbols it calls / instantiates / navigates to that are already paired (the source side is
12
12
  rewritten to the target's name, so a call to a paired API on both sides is a shared feature)
13
13
  call:<name> the names of the members it calls (two words or more)
14
+ res:<name> image and raw resources it uses (`Image("ic_lock")`, `UIImage(named:)`, `Asset.Images.icLock`,
15
+ `Image(.icLock)`, `R.drawable.ic_lock`, `Res.drawable.x`), case and `_` folded; colors are design
16
+ tokens shared by every screen and are left out
14
17
  w:<stem> the stemmed content words of its own name
15
18
 
19
+ A use is specific when it appears in at most SPECIFIC_FILES files on each side (files, not symbols, since a type's span
20
+ holds its members'); a pair whose shared uses are all generic needs two shared name words, so two screens that only
21
+ share `l10n:cancel` / `l10n:yes` and one word do not pair.
22
+
23
+ Types that are still missing after that are paired by their declared fields (`fields`): stored properties, each under
24
+ its wire name when one is declared (Swift `CodingKeys` raw values, Kotlin `@SerialName` / `@SerializedName` /
25
+ `@Json(name =)`), and enum cases, kept apart from properties; case and `_` folded. A pair needs MIN_FIELDS shared
26
+ fields, an IDF-weighted overlap of at least MIN_FIELD_SCORE, a shared name word or a higher overlap, mutual best and
27
+ the margin.
28
+
16
29
  A pair is accepted when it shares a use (any feature but w:) and either two uses or two name words, its IDF-weighted
17
30
  cosine is at least MIN_SCORE, both symbols are each other's best candidate, the runner-up scores below MARGIN times
18
31
  the best, and category, UI-ness and architecture role agree (`compatible`). Learned rules come from the
@@ -21,6 +34,7 @@ MIN_SUPPORT times, two thirds of the time for that source tail, is applied to th
21
34
  top-level symbols. Every match carries its evidence; name matches are left as they are."""
22
35
  from __future__ import annotations
23
36
 
37
+ import json
24
38
  import math
25
39
  import re
26
40
  import sqlite3
@@ -32,9 +46,16 @@ MIN_SHARED = 2
32
46
  MARGIN = 0.8 # the runner-up must score below MARGIN * best
33
47
  MIN_SUPPORT = 2
34
48
  MAX_DF = 40
49
+ SPECIFIC_FILES = 3 # a shared use found in more files than this on either side is generic (`l10n:cancel`)
50
+ MIN_FIELDS = 3
51
+ MIN_FIELD_SCORE = 0.5
35
52
  PREVIEW = re.compile(r"Preview") # Compose @Preview functions / PreviewParameterProviders, SwiftUI previews # features shared by more symbols than this do not propose candidates
36
53
  L10N = re.compile(r"\b(?:Localizations|L10n|R\.string|BitwardenString|CommonStrings|[A-Z]\w*Strings)\.([A-Za-z_]\w*)")
37
54
  STR = re.compile(r'"((?:[^"\\\n]|\\.){5,80})"')
55
+ RES = re.compile(r"""\b(?:UI|NS)?Image\(\s*(?:named:\s*)?"([^"\n]+)"|\bAsset\.(?:Images|Assets)\.(\w+)|"""
56
+ r"""\bImage\(\s*\.(\w+)\s*\)|\b(?:R|Res)\.(?:drawable|mipmap|raw)\.(\w+)""")
57
+ WIRE = re.compile(r'@(?:SerialName|SerializedName|JsonProperty|Json\(\s*name\s*=)\s*\(?\s*(?:value\s*=\s*)?"([^"\n]+)"')
58
+ RAW_CASE = re.compile(r'\bcase\s+`?(\w+)`?\s*=\s*"([^"\n]+)"')
38
59
  EDGE_KINDS = ("CALLS", "INSTANTIATES", "NAVIGATES_TO", "HTTP_CALLS", "USES_VALUE", "REFERENCES_FN", "USES_TYPE")
39
60
 
40
61
 
@@ -123,8 +144,40 @@ class Side:
123
144
  for r in c.execute(q, EDGE_KINDS):
124
145
  self.out[r["src"]].append((r["dst"], r["kind"]))
125
146
  self.http = {r["id"]: (r["name"] or r["id"]) for r in c.execute("SELECT id, name FROM nodes WHERE kind='http'")}
147
+ self.decl = defaultdict(list) # owner fqn -> [(name, kind, file, line)] of stored fields / enum cases
148
+ for r in c.execute("SELECT kind, fqn, file, line, attrs FROM nodes WHERE kind IN ('field', 'enum_case') "
149
+ "AND fqn IS NOT NULL AND file IS NOT NULL"):
150
+ if ".Companion." in r["fqn"] or "." not in r["fqn"]:
151
+ continue
152
+ if r["kind"] == "field" and (json.loads(r["attrs"] or "{}").get("property") or "stored") != "stored":
153
+ continue
154
+ o, nm = r["fqn"].rsplit(".", 1)
155
+ self.decl[o].append((nm, r["kind"], r["file"], r["line"]))
126
156
  c.close()
127
157
 
158
+ def fields(self, fq: str) -> set:
159
+ """`field:<wire name>` for each stored property declared directly on the type: the explicit wire name
160
+ (`@SerialName("item_title")`, a `CodingKeys` case `title = "item_title"`) or else the property name; `case:<name>`
161
+ for each enum case, so an enum of field names does not meet the type that has those fields."""
162
+ raw = {}
163
+ for nm, kind, file, line in self.decl.get(fq + ".CodingKeys", ()):
164
+ m = RAW_CASE.search(self.text(file, line, line))
165
+ if m:
166
+ raw[m.group(1)] = m.group(2)
167
+ out = set()
168
+ for nm, kind, file, line in self.decl.get(fq, ()):
169
+ wire = raw.get(nm)
170
+ if not wire and kind == "field":
171
+ m = WIRE.search(self.text(file, line, line))
172
+ if not m and line > 1: # an annotation on its own line above
173
+ prev = self.text(file, line - 1, line - 1)
174
+ m = None if re.search(r"\b(?:val|var|let)\s", prev) else WIRE.search(prev)
175
+ wire = m.group(1) if m else None
176
+ k = _fold(wire or nm)
177
+ if len(k) > 1:
178
+ out.add(("case:" if kind == "enum_case" else "field:") + k)
179
+ return out
180
+
128
181
  def text(self, file: str, a: int, b: int) -> str:
129
182
  if file not in self.lines:
130
183
  try:
@@ -139,6 +192,9 @@ class Side:
139
192
  if file and a:
140
193
  src = self.text(file, a, b)
141
194
  f |= {"l10n:" + _fold(m) for m in L10N.findall(src)}
195
+ for m in RES.finditer(src):
196
+ f.add("res:" + _fold(next(g for g in m.groups() if g)))
197
+ src = RES.sub(" ", src)
142
198
  for m in STR.findall(src):
143
199
  s = m.strip().lstrip("/")
144
200
  if len(s) >= 5 and re.search(r"[A-Za-z]{3}", s) and not re.search(r"\\\(|\$\{|%[@sd]", s):
@@ -250,6 +306,60 @@ def _apply_rules(rules, out, sym_of, cat_of, t_syms, t_cat, used):
250
306
  out["missing"] = keep
251
307
 
252
308
 
309
+ def _by_fields(sS, sT, out, sym_of, cat_of, t_syms, t_cat, used, S, T):
310
+ """Types still missing, paired by the fields they declare (`ViewItemState` / `VaultItemState`, a Swift
311
+ `Codable` model and its Kotlin `@Serializable` port)."""
312
+ src = {r["symbol"]: sS.fields(r["symbol"]) for r in out["missing"] if cat_of.get(r["symbol"]) == "type"
313
+ and "owner_matched" not in r}
314
+ src = {k: v for k, v in src.items() if len(v) >= MIN_FIELDS and _short(k) != "CodingKeys"}
315
+ tgt = {fq: sT.fields(fq) for fq in t_syms if t_cat.get(fq) == "type" and fq not in used}
316
+ tgt = {k: v for k, v in tgt.items() if len(v) >= MIN_FIELDS and _short(k) != "CodingKeys"}
317
+ if not src or not tgt:
318
+ return
319
+ df = Counter()
320
+ for fs in list(src.values()) + list(tgt.values()):
321
+ df.update(fs)
322
+ n = len(src) + len(tgt)
323
+ w = {f: math.log(1 + n / c) for f, c in df.items()}
324
+ inv = defaultdict(list)
325
+ for fq, fs in tgt.items():
326
+ for f in fs:
327
+ inv[f].append(fq)
328
+
329
+ def score(fq, t):
330
+ a, b = src[fq], tgt[t]
331
+ sh = a & b
332
+ if len(sh) < MIN_FIELDS:
333
+ return 0.0, sh
334
+ sc = sum(w[f] for f in sh) / sum(w[f] for f in a | b)
335
+ words = name_words(fq) & name_words(t)
336
+ if sc < MIN_FIELD_SCORE or (not words and sc < 0.75):
337
+ return 0.0, sh
338
+ return sc, sh | words
339
+
340
+ best = {}
341
+ for fq, fs in src.items():
342
+ cands = {t for f in fs if df[f] <= MAX_DF for t in inv[f]
343
+ if compatible(fq, "type", t, "type", S["_ui"].get(fq), T["_ui"].get(t))}
344
+ scored = sorted(((score(fq, t), t) for t in cands), key=lambda x: -x[0][0])
345
+ if scored and scored[0][0][0] > 0 and (len(scored) == 1 or scored[1][0][0] < MARGIN * scored[0][0][0]):
346
+ best[fq] = (scored[0][1], scored[0][0][0], scored[0][0][1])
347
+ by_t = defaultdict(list)
348
+ for fq, (t, sc, sh) in best.items():
349
+ by_t[t].append((sc, fq))
350
+ keep = []
351
+ for row in out["missing"]:
352
+ got = best.get(row["symbol"])
353
+ if got and max(by_t[got[0]])[1] == row["symbol"] and got[0] not in used:
354
+ t, sc, sh = got
355
+ used.add(t)
356
+ ev = sorted(sh, key=lambda f: (f.startswith("w:"), -w.get(f, 0), f))[:6]
357
+ out["matched"].append(dict(row, target=t, confidence="fields", score=round(sc, 2), evidence=ev))
358
+ else:
359
+ keep.append(row)
360
+ out["missing"] = keep
361
+
362
+
253
363
  def _structure(S, T, out, sym_of, cat_of, t_syms, t_cat, used):
254
364
  sS, sT = Side(S), Side(T)
255
365
  pairs = {r["symbol"]: r["target"] for r in out["matched"]}
@@ -264,6 +374,12 @@ def _structure(S, T, out, sym_of, cat_of, t_syms, t_cat, used):
264
374
  df = Counter()
265
375
  for fs in list(src_f.values()) + list(tgt_f.values()):
266
376
  df.update(fs)
377
+ spread = [defaultdict(set), defaultdict(set)] # feature -> files having it, per side
378
+ for k, (fsets, syms) in enumerate(((src_f, sym_of), (tgt_f, t_syms))):
379
+ for fq, fs in fsets.items():
380
+ for f in fs:
381
+ spread[k][f].add(syms[fq]["file"])
382
+ specific = {f for f in df if len(spread[0][f]) <= SPECIFIC_FILES and len(spread[1][f]) <= SPECIFIC_FILES}
267
383
  n = max(1, len(src_f) + len(tgt_f))
268
384
  w = {f: math.log(1 + n / c) for f, c in df.items()}
269
385
  inv = defaultdict(list)
@@ -278,6 +394,8 @@ def _structure(S, T, out, sym_of, cat_of, t_syms, t_cat, used):
278
394
  # what they use must carry the match: two shared uses, or one use and two shared name words
279
395
  if nw < 1 or (nw < MIN_SHARED and len(sh) - nw < 2):
280
396
  return 0.0, sh
397
+ if len(sh) - nw < 2 and not any(f in specific for f in sh if not f.startswith("w:")):
398
+ return 0.0, sh # only generic uses (`l10n:cancel`, `l10n:yes`) and one name word
281
399
  return sum(w[f] for f in sh) / math.sqrt(sum(w[f] for f in a) * sum(w[f] for f in b)), sh
282
400
 
283
401
  best_s = {}
@@ -305,3 +423,4 @@ def _structure(S, T, out, sym_of, cat_of, t_syms, t_cat, used):
305
423
  else:
306
424
  keep.append(row)
307
425
  out["missing"] = keep
426
+ _by_fields(sS, sT, out, sym_of, cat_of, t_syms, t_cat, used, S, T)
@@ -254,6 +254,29 @@ OTHER_OS_STEM = re.compile(r"(?:^|[_-])(aix|sunos|solaris|os390|zos|ibmi|freebsd
254
254
  r"cygwin|hurd|illumos|pase)$", re.I)
255
255
 
256
256
 
257
+ # Swift platform files (#225): `Foo+iOS.swift`, `Foo.macOS.swift`, `Foo_watchOS.swift`, or a folder `macOS/` / `iOS/`
258
+ # of a multiplatform app. A guess: built for that platform, unknown on the other Apple platforms, absent elsewhere
259
+ SWIFT_PLAT = {"ios": "ios", "iphone": "ios", "ipados": "ios", "macos": "macos", "osx": "macos", "mac": "macos",
260
+ "appkit": "macos", "tvos": "tvos", "watchos": "watchos", "visionos": "visionos", "xros": "visionos"}
261
+ SWIFT_STEM = re.compile(r"[+._-](iOS|iPhone|iPadOS|macOS|OSX|Mac|AppKit|tvOS|watchOS|visionOS|xrOS)$")
262
+ SWIFT_DIR = re.compile(r"^(iOS|iPadOS|macOS|OSX|tvOS|watchOS|visionOS|xrOS)$")
263
+ APPLE = ("ios", "macos", "tvos", "watchos", "visionos")
264
+
265
+
266
+ def swift_path_convention(rel: str) -> tuple[str, str] | None:
267
+ parts = rel.split("/")
268
+ stem = parts[-1][:-len(".swift")] if parts[-1].endswith(".swift") else None
269
+ if stem is None:
270
+ return None
271
+ m = SWIFT_STEM.search(stem)
272
+ if m:
273
+ return SWIFT_PLAT[m.group(1).lower()], f"file name {parts[-1]}"
274
+ for d in parts[:-1]:
275
+ if SWIFT_DIR.match(d):
276
+ return SWIFT_PLAT[d.lower()], f"directory {d}/"
277
+ return None
278
+
279
+
257
280
  def _plat_atom(name: str):
258
281
  if name == "other": # an OS outside the known targets
259
282
  return ("atom", "platform", "__other__")
@@ -655,6 +678,18 @@ def apply(project, builder) -> dict:
655
678
  tree = ("any", [_plat_atom(p) for p in ps]) if len(ps) > 1 else _plat_atom(ps[0])
656
679
  names = ", ".join(m["targets"][:3]) + (" …" if len(m["targets"]) > 3 else "")
657
680
  mark(builder, f, 1, BIG, Cond("tree", tree, f"Xcode target membership ({names})"), line=1)
681
+ if "swift" in langs and pc.get("path_conventions", True):
682
+ whole = {m["file"] for m in builder.platform_marks if m["start"] <= 1 and m.get("end") in (None, BIG)}
683
+ for f, ns in nodes_by_file.items():
684
+ if f in whole or ns[0].lang != "swift":
685
+ continue # Xcode membership (or .cg.yaml paths) already says where it is built
686
+ pcv = swift_path_convention(f)
687
+ if pcv:
688
+ n0 = len(builder.platform_marks)
689
+ tree = ("any", [_plat_atom(pcv[0])] + [("atom", "unknown_on", p) for p in APPLE if p != pcv[0]])
690
+ mark(builder, f, 1, BIG, Cond("tree", tree, f"{pcv[1]} (platform file name)"), line=1)
691
+ if len(builder.platform_marks) > n0:
692
+ builder.platform_marks[-1]["convention"] = True
658
693
  marks = builder.platform_marks
659
694
  if not marks:
660
695
  return {}
@@ -296,6 +296,8 @@ class KotlinPlugin(LanguagePlugin):
296
296
  if files is None:
297
297
  files = source_files(project.root, project)
298
298
  self.decls: dict[str, Decl] = {}
299
+ self.rets: dict[str, str] = {} # function / method id -> declared (or constructed) result type text (#109)
300
+ self._ksrc: dict[str, bytes] = {}
299
301
  self.test_fw: dict[str, str | None] = {}
300
302
  self._fd = None
301
303
  self.by_name: dict[str, list[Decl]] = defaultdict(list)
@@ -361,7 +363,8 @@ class KotlinPlugin(LanguagePlugin):
361
363
  tree = nt
362
364
  self.st["files_reparsed_by_member"] += 1
363
365
  self.st["members_dropped_by_reparse"] += len(dropped)
364
- kf = KFile(rel, src, tree) # names and text from the original bytes; offsets are unchanged
366
+ kf = KFile(rel, src, tree)
367
+ self._ksrc[rel] = src # names and text from the original bytes; offsets are unchanged
365
368
  if tree.root_node.has_error or dropped:
366
369
  self.st["files_with_syntax_errors"] += 1
367
370
  errs[rel] = merge(tree_spans(tree.root_node) + [list(x) for x in dropped])
@@ -608,6 +611,9 @@ class KotlinPlugin(LanguagePlugin):
608
611
  self._params(params) if params is not None else {}, kf.test, self._name_line(c),
609
612
  slots=self._fn_slots(params))
610
613
  self._local_types(c, dc.types)
614
+ rt = self._ret_text(c)
615
+ if rt is not None:
616
+ self.rets[dc.id] = rt if self.rets.get(dc.id, rt) == rt else ""
611
617
  if any(dflt for _n, dflt, _f in fparams):
612
618
  self.fn_params[dc.id] = fparams
613
619
  self._add_decl(dc, kind)
@@ -1970,11 +1976,28 @@ class KotlinPlugin(LanguagePlugin):
1970
1976
  **({"via": write} if isinstance(write, str) else {}))
1971
1977
  self.st["stored_property_writes" if write else "stored_property_reads"] += 1
1972
1978
 
1973
- def _local_type(self, decl: Decl, name: str, kf: KFile) -> str | None:
1974
- """`val d = Cart(...)` inside the function body: the constructed type of a local."""
1979
+ def _local_type(self, decl: Decl, name: str, kf: KFile, depth: int = 0) -> str | None:
1980
+ """`val d = Cart(...)` inside the function body: the constructed type of a local; also `val g: Garage<E>`,
1981
+ `val g = Garage<E>(..)` and `val e = shop.engine()` through the call chain's declared result (#109)."""
1975
1982
  src = "\n".join(kf.src.decode("utf-8", "replace").split("\n")[decl.line - 1:decl.end])
1976
- m = re.search(r"\b(?:val|var)\s+" + re.escape(name) + r"\s*(?::\s*([A-Z][\w.]*))?\s*=\s*([A-Z][\w.]*)\s*\(", src)
1977
- return (m.group(1) or m.group(2)) if m else None
1983
+ m = re.search(r"\b(?:val|var)\s+" + re.escape(name) +
1984
+ r"\s*(?::\s*([A-Z][\w.]*(?:<[^=\n]*?>)?))?\s*=\s*([A-Z][\w.]*(?:<[^=\n(){}]*?>)?)\s*\(", src)
1985
+ if m:
1986
+ return m.group(1) or m.group(2)
1987
+ m = re.search(r"\b(?:val|var)\s+" + re.escape(name) + r"\s*(?::\s*([A-Z][\w.]*(?:<[^=\n]*?>)?)\s*\??)?\s*="
1988
+ r"\s*([^\n;]*)", src)
1989
+ if not m:
1990
+ return None
1991
+ if m.group(1):
1992
+ return m.group(1)
1993
+ rhs = m.group(2).strip()
1994
+ if depth > 2 or not re.fullmatch(r"[a-z_][\w]*(?:\([^()]*\))?(?:\s*[?!]*\.\s*\w+(?:\([^()]*\))?)*", rhs) \
1995
+ or rhs.split(".")[0].split("(")[0] == name:
1996
+ return None
1997
+ if "(" not in rhs and "." not in rhs:
1998
+ return None
1999
+ c, args = self._expr_type(rhs, kf, decl, depth + 1)
2000
+ return (c.name + (f"<{', '.join(args)}>" if args else "")) if c is not None else None
1978
2001
 
1979
2002
  def _prop_member(self, cls: Decl, name: str, depth: int = 0) -> list[Decl]:
1980
2003
  hit = self.prop_members.get(cls.fqn, {}).get(name)
@@ -2056,6 +2079,140 @@ class KotlinPlugin(LanguagePlugin):
2056
2079
  **({"binding": how} if how else {}))
2057
2080
  self.st[{"read": "property_reads", "write": "property_writes"}.get(m, "property_read_writes")] += 1
2058
2081
 
2082
+ def _ret_text(self, c) -> str | None:
2083
+ """`fun f(): Garage<Engine>?` -> 'Garage<Engine>'; `fun f() = Engine(..)` -> 'Engine' (#109)."""
2084
+ kids = c.children
2085
+ seen_params = False
2086
+ for i, x in enumerate(kids):
2087
+ if x.type == "function_value_parameters":
2088
+ seen_params = True
2089
+ elif seen_params and x.type == ":" and i + 1 < len(kids):
2090
+ return self.t(kids[i + 1]).rstrip("?! ").strip()
2091
+ elif seen_params and x.type == "function_body":
2092
+ m = re.match(r"=\s*([A-Z]\w*(?:<[^=\n(){}]*?>)?)\s*\(", self.t(x))
2093
+ return m.group(1) if m else None
2094
+ return None
2095
+
2096
+ @staticmethod
2097
+ def _split_type(txt: str | None) -> tuple[str | None, list]:
2098
+ """'Garage<Engine, Map<A, B>>?' -> ('Garage', ['Engine', 'Map'])."""
2099
+ if not txt:
2100
+ return None, []
2101
+ m = re.match(r"\s*([A-Z][\w.]*)\s*(?:<(.*)>)?", txt, re.S)
2102
+ if not m:
2103
+ return None, []
2104
+ args, depth, cur = [], 0, ""
2105
+ for ch in (m.group(2) or "") + ("," if m.group(2) else ""):
2106
+ if ch in "<([":
2107
+ depth += 1
2108
+ elif ch in ">)]":
2109
+ depth -= 1
2110
+ if ch == "," and depth == 0:
2111
+ a = re.match(r"\s*(?:out\s+|in\s+)?([A-Z][\w.]*)", cur)
2112
+ args.append(a.group(1).split(".")[-1] if a else "")
2113
+ cur = ""
2114
+ else:
2115
+ cur += ch
2116
+ return m.group(1).split(".")[-1], args
2117
+
2118
+ def _gparams(self, cls: Decl) -> list[str]:
2119
+ cache = self.__dict__.setdefault("_gp_cache", {})
2120
+ if cls.id not in cache:
2121
+ src = self._ksrc.get(cls.file, b"").decode("utf-8", "replace").split("\n")[cls.line - 1:cls.line + 2]
2122
+ m = re.search(r"\b(?:class|interface)\s+" + re.escape(cls.name) + r"\s*<([^>{(]*)>", "\n".join(src))
2123
+ cache[cls.id] = [re.split(r"[:\s]", re.sub(r"^\s*(?:out|in|reified)\s+", "", x).strip())[0]
2124
+ for x in m.group(1).split(",")] if m else []
2125
+ return cache[cls.id]
2126
+
2127
+ def _full_type(self, where: Decl | None, name: str, ty: str | None) -> str | None:
2128
+ """Parameter / property types are kept without their generic arguments; read them back from the declaring
2129
+ span (`val garage: Garage<Engine>`, `fun f(g: Garage<Engine>)`) when the stored type is generic there."""
2130
+ if where is None or not ty or "<" in ty:
2131
+ return ty
2132
+ src = "\n".join(self._ksrc.get(where.file, b"").decode("utf-8", "replace").split("\n")[where.line - 1:where.end])
2133
+ m = re.search(r"\b" + re.escape(name) + r"\s*:\s*((?:[\w]+\.)*" + re.escape(ty) + r"\s*<[^=\n(){}]*>)", src)
2134
+ return m.group(1) if m else ty
2135
+
2136
+ def _as_class(self, txt: str | None, owner: Decl | None, args: list, kf: KFile) -> tuple:
2137
+ """A declared type text read on a receiver: a generic parameter of `owner` becomes the receiver's argument."""
2138
+ name, targs = self._split_type(txt)
2139
+ if name is None:
2140
+ return None, []
2141
+ if owner is not None:
2142
+ gp = self._gparams(owner)
2143
+ if name in gp:
2144
+ i = gp.index(name)
2145
+ name, targs = (args[i] if i < len(args) and args[i] else None), []
2146
+ if name is None:
2147
+ return None, []
2148
+ c = self._class_of(name, kf)
2149
+ return c, targs
2150
+
2151
+ def _expr_type(self, txt: str, kf: KFile, decl: Decl | None, depth: int = 0) -> tuple:
2152
+ """The project class of a receiver expression (`shop.engine()`, `Garage<E>(e).get()`, `makeShop().engine()`,
2153
+ `repo.items.first()`), with its generic arguments; (None, []) when a step is not known (#109)."""
2154
+ if depth > 3 or not txt:
2155
+ return None, []
2156
+ segs, d, cut, q = [], 0, 0, False
2157
+ t = txt.strip()
2158
+ for i, ch in enumerate(t):
2159
+ if ch == '"':
2160
+ q = not q
2161
+ if q:
2162
+ continue
2163
+ if ch in "([{<" and not (ch == "<" and not t[cut:i].strip()[:1].isupper()):
2164
+ d += 1
2165
+ elif ch in ")]}>" and d > 0:
2166
+ d -= 1
2167
+ elif ch == "." and d == 0:
2168
+ segs.append(t[cut:i])
2169
+ cut = i + 1
2170
+ segs.append(t[cut:])
2171
+ segs = [x.strip().rstrip("?!").strip() for x in segs]
2172
+ cls = self.classes.get(decl.cls) if decl is not None and decl.cls else None
2173
+ cur, args = None, []
2174
+ for i, seg in enumerate(segs):
2175
+ m = re.match(r"^([A-Za-z_]\w*)\s*(<[^=\n(){}]*?>)?\s*(\(|\{)?", seg)
2176
+ if not m:
2177
+ return None, []
2178
+ ident, ga, called = m.group(1), m.group(2), m.group(3)
2179
+ if i == 0:
2180
+ if ident == "this":
2181
+ cur = cls
2182
+ elif ident[:1].isupper():
2183
+ cur = self._class_of(ident, kf)
2184
+ args = self._split_type(ident + (ga or ""))[1]
2185
+ elif called:
2186
+ ds = [x for x in self._member(cls, ident) if x.kind != "class"] if cls is not None else []
2187
+ if not ds:
2188
+ ds = [x for x in self.by_name.get(ident, []) if x.kind == "function"]
2189
+ rets = {self.rets.get(x.id) for x in ds}
2190
+ if len(rets) != 1 or not next(iter(rets)):
2191
+ return None, []
2192
+ cur, args = self._as_class(next(iter(rets)), None, [], kf)
2193
+ else:
2194
+ ty = (self._full_type(decl, ident, decl.types.get(ident)) if decl is not None else None) or \
2195
+ (self._full_type(cls, ident, self._field_type(cls, ident)) if cls is not None else None) or \
2196
+ (self._local_type(decl, ident, kf, depth + 1) if decl is not None and decl.kind != "class" else None)
2197
+ cur, args = self._as_class(ty, None, [], kf)
2198
+ if cur is None:
2199
+ return None, []
2200
+ continue
2201
+ owner = cur
2202
+ if called:
2203
+ ds = [x for x in self._member(cur, ident) if x.kind != "class"]
2204
+ rets = {self.rets.get(x.id) for x in ds}
2205
+ if len(rets) != 1 or not next(iter(rets)):
2206
+ return None, []
2207
+ dcls = self.classes.get(ds[0].cls) if ds[0].cls else cur
2208
+ cur, args = self._as_class(next(iter(rets)), dcls, args, kf)
2209
+ else:
2210
+ ty = self._full_type(cur, ident, self._field_type(cur, ident))
2211
+ cur, args = self._as_class(ty, owner, args, kf)
2212
+ if cur is None:
2213
+ return None, []
2214
+ return cur, args
2215
+
2059
2216
  def _targets(self, name: str, recv: str | None, kf: KFile, decl: Decl | None) -> list[Decl]:
2060
2217
  cls = self.classes.get(decl.cls) if decl is not None and decl.cls else None
2061
2218
  if recv is None or recv == "this":
@@ -2098,6 +2255,13 @@ class KotlinPlugin(LanguagePlugin):
2098
2255
  tyname = decl.types.get(rname)
2099
2256
  if tyname is None and cls is not None:
2100
2257
  tyname = self._field_type(cls, rname)
2258
+ if tyname is None and ("." in recv.strip("?!") or "(" in recv or rname[:1].islower()):
2259
+ tc, _args = self._expr_type(recv, kf, decl) # `shop.engine().run()`, a local from a call (#109)
2260
+ if tc is not None:
2261
+ r = self._member(tc, name)
2262
+ if r:
2263
+ self._recv = tc
2264
+ return self._same_set(r, kf)
2101
2265
  if tyname is None and rname[:1].isupper():
2102
2266
  tyname = re.sub(r"\s*[({].*$", "", rname, flags=re.S) # `WishController().add(x)`: a WishController
2103
2267
  if tyname: