cg-code-graph 0.23.1__tar.gz → 0.23.2__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 (403) hide show
  1. {cg_code_graph-0.23.1/cg_code_graph.egg-info → cg_code_graph-0.23.2}/PKG-INFO +1 -1
  2. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/__init__.py +1 -1
  3. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/cli.py +20 -0
  4. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/core/model.py +1 -1
  5. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/doctor.py +13 -0
  6. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/nuxt/plugin.py +336 -19
  7. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/ts/extractor/extract.mjs +23 -3
  8. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/query.py +36 -5
  9. cg_code_graph-0.23.2/cg_code_graph/update_check.py +122 -0
  10. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2/cg_code_graph.egg-info}/PKG-INFO +1 -1
  11. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph.egg-info/SOURCES.txt +4 -0
  12. cg_code_graph-0.23.2/tests/test_nuxt_i18n.py +89 -0
  13. cg_code_graph-0.23.2/tests/test_nuxt_nitro.py +103 -0
  14. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_snippet.py +4 -1
  15. cg_code_graph-0.23.2/tests/test_update_check.py +96 -0
  16. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/LICENSE +0 -0
  17. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/MANIFEST.in +0 -0
  18. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/README.md +0 -0
  19. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/__main__.py +0 -0
  20. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/affected.py +0 -0
  21. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/agent_rules.py +0 -0
  22. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/agents.py +0 -0
  23. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/aitools.py +0 -0
  24. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/android_ipc.py +0 -0
  25. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/apple_ipc.py +0 -0
  26. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/apps.py +0 -0
  27. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/blindspots.py +0 -0
  28. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/bridges.py +0 -0
  29. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/brokers.py +0 -0
  30. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/concepts.py +0 -0
  31. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/config.py +0 -0
  32. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/core/__init__.py +0 -0
  33. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/core/cache.py +0 -0
  34. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/core/detect.py +0 -0
  35. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/core/env.py +0 -0
  36. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/core/extractors.py +0 -0
  37. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/core/fsutil.py +0 -0
  38. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/core/generated.py +0 -0
  39. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/core/paths.py +0 -0
  40. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/core/plugin.py +0 -0
  41. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/core/redact.py +0 -0
  42. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/core/store.py +0 -0
  43. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/core/syntax_errors.py +0 -0
  44. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/coverage.py +0 -0
  45. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/dart_isolates.py +0 -0
  46. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/explore.py +0 -0
  47. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/external.py +0 -0
  48. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/graphql.py +0 -0
  49. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/guard_facts.py +0 -0
  50. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/hooks.py +0 -0
  51. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/indexer.py +0 -0
  52. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/insecure_transport.py +0 -0
  53. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/install_rules.py +0 -0
  54. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/jobs.py +0 -0
  55. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/link.py +0 -0
  56. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/lint_async.py +0 -0
  57. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/local_ipc.py +0 -0
  58. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/local_sockets.py +0 -0
  59. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/mcp_graphs.py +0 -0
  60. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/mcp_install.py +0 -0
  61. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/mcp_server.py +0 -0
  62. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/parity.py +0 -0
  63. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/parity_structure.py +0 -0
  64. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/payload.py +0 -0
  65. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plans.py +0 -0
  66. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/platform_scan.py +0 -0
  67. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/platforms.py +0 -0
  68. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/__init__.py +0 -0
  69. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/astro/__init__.py +0 -0
  70. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/astro/content.py +0 -0
  71. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/astro/plugin.py +0 -0
  72. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/cfamily/__init__.py +0 -0
  73. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/cfamily/plugin.py +0 -0
  74. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/cfamily/syntax.py +0 -0
  75. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/dart/__init__.py +0 -0
  76. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/dart/bridges.py +0 -0
  77. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/dart/extractor/bin/extract.dart +0 -0
  78. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/dart/extractor/pubspec.lock +0 -0
  79. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/dart/extractor/pubspec.yaml +0 -0
  80. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/dart/http.py +0 -0
  81. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/dart/models.py +0 -0
  82. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/dart/plugin.py +0 -0
  83. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/dart/program.py +0 -0
  84. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/django/__init__.py +0 -0
  85. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/django/extras.py +0 -0
  86. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/django/models.py +0 -0
  87. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/django/plugin.py +0 -0
  88. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/django/schemas.py +0 -0
  89. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/django/shapes.py +0 -0
  90. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/django/urls.py +0 -0
  91. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/express/__init__.py +0 -0
  92. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/express/plugin.py +0 -0
  93. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/flutter/__init__.py +0 -0
  94. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/flutter/plugin.py +0 -0
  95. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/java/__init__.py +0 -0
  96. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/java/exact.py +0 -0
  97. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/java/plugin.py +0 -0
  98. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/jvm/__init__.py +0 -0
  99. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/jvm/interop.py +0 -0
  100. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/jvm/spring.py +0 -0
  101. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/kotlin/__init__.py +0 -0
  102. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/kotlin/exact.py +0 -0
  103. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/kotlin/plugin.py +0 -0
  104. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/kotlin/reparse.py +0 -0
  105. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/laravel/__init__.py +0 -0
  106. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/laravel/broadcast.py +0 -0
  107. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/laravel/massassign.py +0 -0
  108. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/laravel/plugin.py +0 -0
  109. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/laravel/tests.py +0 -0
  110. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/laravel/values.py +0 -0
  111. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/native/__init__.py +0 -0
  112. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/native/gates.py +0 -0
  113. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/native/runner.py +0 -0
  114. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/native/scipread.py +0 -0
  115. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/native/ts.py +0 -0
  116. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/nest/__init__.py +0 -0
  117. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/nest/plugin.py +0 -0
  118. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/nextjs/__init__.py +0 -0
  119. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/nextjs/plugin.py +0 -0
  120. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/nuxt/__init__.py +0 -0
  121. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/php/__init__.py +0 -0
  122. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/php/external.py +0 -0
  123. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/php/extractor/composer.json +0 -0
  124. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/php/extractor/composer.lock +0 -0
  125. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/php/extractor/extract.php +0 -0
  126. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/php/gating.py +0 -0
  127. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/php/http_client.py +0 -0
  128. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/php/inline_guards.py +0 -0
  129. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/php/plugin.py +0 -0
  130. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/php/strings.py +0 -0
  131. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/python/__init__.py +0 -0
  132. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/python/aitools.py +0 -0
  133. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/python/external.py +0 -0
  134. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/python/fields.py +0 -0
  135. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/python/plugin.py +0 -0
  136. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/python/refs.py +0 -0
  137. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/python/roots.py +0 -0
  138. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/python/socketio.py +0 -0
  139. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/python/subproc.py +0 -0
  140. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/python/tests.py +0 -0
  141. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/python/values.py +0 -0
  142. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/pyweb/__init__.py +0 -0
  143. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/pyweb/plugin.py +0 -0
  144. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/pyweb/values.py +0 -0
  145. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/rust/__init__.py +0 -0
  146. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/rust/cargo.py +0 -0
  147. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/rust/plugin.py +0 -0
  148. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/rust/syntax.py +0 -0
  149. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/scip/__init__.py +0 -0
  150. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/scip/importer.py +0 -0
  151. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/scip/scip.proto +0 -0
  152. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/scip/scip_pb2.py +0 -0
  153. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/stubs/__init__.py +0 -0
  154. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/stubs/plugins.py +0 -0
  155. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/swift/__init__.py +0 -0
  156. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/swift/baseurl.py +0 -0
  157. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/swift/exact.py +0 -0
  158. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/swift/indexstore.py +0 -0
  159. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/swift/packages.py +0 -0
  160. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/swift/plugin.py +0 -0
  161. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/ts/__init__.py +0 -0
  162. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/ts/baseurl.py +0 -0
  163. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/ts/extractor/fw.mjs +0 -0
  164. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/ts/extractor/package-lock.json +0 -0
  165. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/ts/extractor/package.json +0 -0
  166. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/ts/extractor/rr.mjs +0 -0
  167. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/ts/nav.py +0 -0
  168. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/ts/plugin.py +0 -0
  169. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/ts/react_router.py +0 -0
  170. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/tsweb/__init__.py +0 -0
  171. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/tsweb/common.py +0 -0
  172. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/plugins/tsweb/data.py +0 -0
  173. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/__init__.py +0 -0
  174. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/c_cpp.yaml +0 -0
  175. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/common.yaml +0 -0
  176. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/dart.yaml +0 -0
  177. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/django-ninja.yaml +0 -0
  178. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/django.yaml +0 -0
  179. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/djangorestframework.yaml +0 -0
  180. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/express.yaml +0 -0
  181. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/java.yaml +0 -0
  182. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/kotlin.yaml +0 -0
  183. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/laravel.yaml +0 -0
  184. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/nest.yaml +0 -0
  185. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/nextjs.yaml +0 -0
  186. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/nuxt.yaml +0 -0
  187. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/php.yaml +0 -0
  188. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/python.yaml +0 -0
  189. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/react-router.yaml +0 -0
  190. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/rust.yaml +0 -0
  191. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/spring.yaml +0 -0
  192. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/swift.yaml +0 -0
  193. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/presets/typescript.yaml +0 -0
  194. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/process_runs.py +0 -0
  195. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/protocols/__init__.py +0 -0
  196. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/protocols/builtin.py +0 -0
  197. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/protocols/matchers.py +0 -0
  198. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/protocols/view.py +0 -0
  199. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/realtime.py +0 -0
  200. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/realtime_events.py +0 -0
  201. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/realtime_native.py +0 -0
  202. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/realtime_ws.py +0 -0
  203. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/roundtrip.py +0 -0
  204. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/routes.py +0 -0
  205. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/rpc.py +0 -0
  206. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/sdk_systems.py +0 -0
  207. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/sockets.py +0 -0
  208. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/ssrf_input.py +0 -0
  209. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/starters.py +0 -0
  210. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/surface.py +0 -0
  211. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/tests_index.py +0 -0
  212. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/udp_apps.py +0 -0
  213. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/__init__.py +0 -0
  214. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/graph.py +0 -0
  215. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/server.py +0 -0
  216. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/static/app.css +0 -0
  217. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/static/app.js +0 -0
  218. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/static/index.html +0 -0
  219. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/static/layered.js +0 -0
  220. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/static/vendor/VERSIONS.txt +0 -0
  221. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/static/vendor/cose-base.js +0 -0
  222. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/static/vendor/cytoscape-fcose.js +0 -0
  223. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/static/vendor/cytoscape.min.js +0 -0
  224. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/static/vendor/layout-base.js +0 -0
  225. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/tools/package-lock.json +0 -0
  226. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/tools/package.json +0 -0
  227. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/viz/tools/shoot.mjs +0 -0
  228. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/watch.py +0 -0
  229. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/webhook_subs.py +0 -0
  230. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/webhooks.py +0 -0
  231. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph/xcode.py +0 -0
  232. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph.egg-info/dependency_links.txt +0 -0
  233. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph.egg-info/entry_points.txt +0 -0
  234. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph.egg-info/requires.txt +0 -0
  235. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/cg_code_graph.egg-info/top_level.txt +0 -0
  236. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/pyproject.toml +0 -0
  237. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/setup.cfg +0 -0
  238. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_affected.py +0 -0
  239. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_agents_install.py +0 -0
  240. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_agents_md.py +0 -0
  241. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_ai_tools.py +0 -0
  242. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_android_ipc.py +0 -0
  243. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_apple_ipc.py +0 -0
  244. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_astro.py +0 -0
  245. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_astro_content.py +0 -0
  246. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_astro_server.py +0 -0
  247. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_bridges.py +0 -0
  248. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_bridges_pigeon_monorepo.py +0 -0
  249. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_brokers.py +0 -0
  250. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_cache_clean.py +0 -0
  251. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_cache_invalidation.py +0 -0
  252. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_cache_migration.py +0 -0
  253. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_channels_tests.py +0 -0
  254. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_cli_output.py +0 -0
  255. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_completeness.py +0 -0
  256. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_config_extras.py +0 -0
  257. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_coverage.py +0 -0
  258. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_coverage_ts_hint.py +0 -0
  259. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_dart_isolates.py +0 -0
  260. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_db_connections.py +0 -0
  261. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_dead_wrappers.py +0 -0
  262. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_dispatch_interfaces.py +0 -0
  263. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_django_flutter.py +0 -0
  264. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_docs_languages.py +0 -0
  265. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_docs_links.py +0 -0
  266. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_echo_ref.py +0 -0
  267. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_echo_wrapper.py +0 -0
  268. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_elysia.py +0 -0
  269. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_enum_constants.py +0 -0
  270. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_env.py +0 -0
  271. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_explore.py +0 -0
  272. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_external.py +0 -0
  273. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_fp_batch.py +0 -0
  274. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_gating.py +0 -0
  275. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_generated.py +0 -0
  276. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_graphql.py +0 -0
  277. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_hooks.py +0 -0
  278. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_impact_overrides.py +0 -0
  279. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_index_isolation.py +0 -0
  280. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_inherited_overrides.py +0 -0
  281. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_inline_guards.py +0 -0
  282. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_install_rules.py +0 -0
  283. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_issue_192.py +0 -0
  284. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_issue_202.py +0 -0
  285. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_issue_203.py +0 -0
  286. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_issue_205.py +0 -0
  287. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_issue_206.py +0 -0
  288. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_issue_207.py +0 -0
  289. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_issue_208.py +0 -0
  290. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_issue_209.py +0 -0
  291. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_issue_210.py +0 -0
  292. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_issue_211.py +0 -0
  293. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_issue_211_used_at.py +0 -0
  294. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_java.py +0 -0
  295. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_java_exact.py +0 -0
  296. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_jobs.py +0 -0
  297. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_js_refs.py +0 -0
  298. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_js_runtime.py +0 -0
  299. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_kotlin.py +0 -0
  300. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_kotlin_binding.py +0 -0
  301. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_kotlin_exact.py +0 -0
  302. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_kotlin_fields.py +0 -0
  303. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_kotlin_mixed.py +0 -0
  304. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_kotlin_nav_consts.py +0 -0
  305. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_kotlin_props.py +0 -0
  306. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_laravel_determinism.py +0 -0
  307. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_laravel_resources.py +0 -0
  308. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_link_origin.py +0 -0
  309. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_lint_async.py +0 -0
  310. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_listing_files.py +0 -0
  311. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_local_ipc.py +0 -0
  312. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_local_sockets.py +0 -0
  313. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_mass_assignment.py +0 -0
  314. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_mcp.py +0 -0
  315. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_mcp_index.py +0 -0
  316. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_mcp_install.py +0 -0
  317. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_mcp_instructions.py +0 -0
  318. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_mcp_multi_graph.py +0 -0
  319. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_native_cfamily.py +0 -0
  320. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_native_concurrency.py +0 -0
  321. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_native_rust.py +0 -0
  322. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_nuxt_import_dirs.py +0 -0
  323. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_nuxt_rootsrc.py +0 -0
  324. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_nuxt_side_dirs.py +0 -0
  325. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_packaging.py +0 -0
  326. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_parity.py +0 -0
  327. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_parity_structure.py +0 -0
  328. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_php_http.py +0 -0
  329. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_php_props.py +0 -0
  330. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_plain_js.py +0 -0
  331. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_plans.py +0 -0
  332. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_platform_gaps.py +0 -0
  333. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_platform_type_variants.py +0 -0
  334. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_platforms.py +0 -0
  335. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_platforms_apple.py +0 -0
  336. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_presets_config.py +0 -0
  337. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_process_ipc.py +0 -0
  338. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_process_runs.py +0 -0
  339. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_protocols.py +0 -0
  340. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_python_app_tests_module.py +0 -0
  341. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_python_collection_chains.py +0 -0
  342. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_python_compat.py +0 -0
  343. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_python_entry_refs.py +0 -0
  344. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_python_fields.py +0 -0
  345. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_python_infer_cycles.py +0 -0
  346. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_python_roots.py +0 -0
  347. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_python_subprocess_tests.py +0 -0
  348. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_python_tests.py +0 -0
  349. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_python_web_hosts.py +0 -0
  350. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_python_web_routes.py +0 -0
  351. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_python_web_routes_more.py +0 -0
  352. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_react_router.py +0 -0
  353. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_readers_writers_specs.py +0 -0
  354. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_realtime.py +0 -0
  355. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_realtime_native.py +0 -0
  356. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_redact_salt.py +0 -0
  357. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_request_keys.py +0 -0
  358. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_roundtrip.py +0 -0
  359. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_route_specs.py +0 -0
  360. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_route_tables.py +0 -0
  361. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_routes_search_explain.py +0 -0
  362. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_rpc.py +0 -0
  363. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_scip_health.py +0 -0
  364. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_sdk_external.py +0 -0
  365. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_sdk_external_infra.py +0 -0
  366. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_sdk_external_mail.py +0 -0
  367. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_sockets.py +0 -0
  368. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_spring.py +0 -0
  369. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_ssrf.py +0 -0
  370. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_starters_budget.py +0 -0
  371. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_surface.py +0 -0
  372. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_surface_transport.py +0 -0
  373. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_swift.py +0 -0
  374. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_swift_binding.py +0 -0
  375. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_swift_exact.py +0 -0
  376. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_swift_facts.py +0 -0
  377. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_swift_fields.py +0 -0
  378. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_swift_modules.py +0 -0
  379. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_swift_more.py +0 -0
  380. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_swift_nav_values.py +0 -0
  381. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_swift_parse_errors.py +0 -0
  382. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_swift_props.py +0 -0
  383. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_swift_sdk.py +0 -0
  384. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_swift_testing.py +0 -0
  385. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_swift_values.py +0 -0
  386. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_tests_scope.py +0 -0
  387. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_ts_fields.py +0 -0
  388. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_ts_fields_js_vue.py +0 -0
  389. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_ts_file_specs.py +0 -0
  390. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_ts_frameworks.py +0 -0
  391. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_ts_node_http.py +0 -0
  392. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_ts_nuxt.py +0 -0
  393. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_ts_src_tsconfig.py +0 -0
  394. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_unguarded.py +0 -0
  395. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_values.py +0 -0
  396. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_viz.py +0 -0
  397. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_vue_nav.py +0 -0
  398. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_watch.py +0 -0
  399. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_webhooks.py +0 -0
  400. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_webhooks_152.py +0 -0
  401. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_webhooks_152b.py +0 -0
  402. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/tests/test_websockets.py +0 -0
  403. {cg_code_graph-0.23.1 → cg_code_graph-0.23.2}/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.1
3
+ Version: 0.23.2
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.1"
2
+ __version__ = "0.23.2"
@@ -100,9 +100,24 @@ def _impact_labels(rows: list[dict], name_of, group_of) -> list[str]:
100
100
  return labels
101
101
 
102
102
 
103
+ def _version_text(version: str) -> str:
104
+ """`cg X.Y.Z`, plus a second line when the cached newer-release check (written by `cg doctor`) knows of a newer
105
+ release. Reads the cache only: never connects (#98)."""
106
+ try:
107
+ from .update_check import check, notice
108
+ n = notice(check(version, network=False))
109
+ except Exception:
110
+ n = None
111
+ return f"cg {version}" + (f"\n{n}" if n else "")
112
+
113
+
103
114
  def main(argv=None):
104
115
  from . import __version__
105
116
  ap = argparse.ArgumentParser(prog="cg")
117
+ args_in = sys.argv[1:] if argv is None else list(argv)
118
+ if args_in[:1] == ["--version"]:
119
+ print(_version_text(__version__)) # printed here: argparse's version action re-wraps a second line
120
+ return 0
106
121
  ap.add_argument("--version", action="version", version=f"cg {__version__}")
107
122
  sub = ap.add_subparsers(dest="cmd", required=True)
108
123
  p = sub.add_parser("index", help="detect languages / frameworks under ROOT and build the graph DB (stats JSON on stdout, coverage on stderr)"); p.add_argument("root"); p.add_argument("--db", required=True); p.add_argument("--name"); p.add_argument("--scip", action="append"); p.add_argument("--gates", help="gate scenarios JSON (e.g. examples/bookstore.gates.json)")
@@ -862,6 +877,11 @@ def render_node(d: dict) -> str:
862
877
  unk = at.get("platform_unknown") or []
863
878
  ps = ", ".join(p + ("?" if p in unk else "") for p in at["platforms"]) or "none of the targets"
864
879
  out.append(f" platforms: {ps}" + (f" ({at['platform_expr']})" if at.get("platform_expr") else ""))
880
+ if n.get("kind") == "i18n" and at.get("definitions"):
881
+ out.append(" definitions: " + ", ".join(f"{x.get('locale') or '-'} {x['file']}:{x['line']}" for x in at["definitions"]))
882
+ if at.get("missing_locales"):
883
+ out.append(" missing locales: " + ", ".join(at["missing_locales"]))
884
+ at = {k: v for k, v in at.items() if k not in ("definitions", "defined_in", "missing_locales")}
865
885
  rest = {k: v for k, v in at.items() if k not in ("platforms", "platform_unknown", "platform_expr", "platform_at", "platforms_other")}
866
886
  if rest:
867
887
  out.append(" attrs: " + ", ".join(f"{k}={v if isinstance(v, str) else json.dumps(v, default=str, ensure_ascii=False)}"
@@ -56,7 +56,7 @@ EDGE_KINDS: dict[str, tuple[bool, str]] = {
56
56
  "HTTP_CALLS": (True, "client code calls an HTTP endpoint (method + path template)"),
57
57
  "MATCHES_ROUTE": (True, "client endpoint matched to a backend route (cross-repo link)"),
58
58
  "USES_LAYOUT": (False, "page uses layout"),
59
- "USES_I18N": (False, "code/template uses i18n key"),
59
+ "USES_I18N": (True, "code/template uses i18n key (propagating: a key's users are its dependents in reaches / impact, #182)"),
60
60
  "REFERENCES_TYPE": (False, "code references a type/interface"),
61
61
  # value facts
62
62
  "READS_SETTING": (True, "code reads a JSON settings key (getSetting('a.b', default))"),
@@ -407,12 +407,25 @@ def report(root: str | Path | None = None, scip: list | None = None) -> dict:
407
407
  "legacy_cache": cache.legacy_report(),
408
408
  **({"hooks_outdated": _outdated_hooks(rootp)} if rootp is not None else {}),
409
409
  "update": "uv tool upgrade cg-code-graph | pipx upgrade cg-code-graph | install.sh --update",
410
+ "latest": _latest(),
410
411
  **({"scip": [scip_health(x) for x in scip]} if scip else {}),
411
412
  }
412
413
 
413
414
 
415
+ def _latest() -> dict:
416
+ """Newer-release check (#98): PyPI at most once a day, cached; never fails or blocks for long."""
417
+ from .update_check import check
418
+ try:
419
+ return check()
420
+ except Exception:
421
+ return {"current": __version__, "latest": None, "newer": False, "source": "none", "disabled": None}
422
+
423
+
414
424
  def render(r: dict) -> str:
415
425
  out = [f"cg {r['cg']} (Python {r['python']}, {r['os']}; {r['package']}{', checkout' if r['checkout'] else ''})"]
426
+ from .update_check import notice
427
+ if (n := notice(r.get("latest") or {})):
428
+ out.append(f"newer release: {n}")
416
429
  out.append("tools:")
417
430
  for k, v in r["tools"].items():
418
431
  out.append(f" {k:<14} {v['version'] or 'not found'}" + (f" ({v['path']})" if v["path"] else "")
@@ -11,7 +11,9 @@ register_hooks: finds the source dir (nuxt.config `srcDir`, else `app/` (Nuxt 4)
11
11
  say which one was used (`prepared`: nuxi | generated).
12
12
  contribute: file-based routing (route path per page), entry points (pages = ui_page; app.vue,
13
13
  layouts, global middleware, plugins = ui_global), USES_LAYOUT, i18n keys (USES_I18N; defining
14
- locale files).
14
+ locale files), Nitro server routes (server/api/** -> `route:<METHOD> /api/...`, server/routes/** without the
15
+ prefix; ROUTES_TO the default-export handler, USES_MIDDLEWARE every server/middleware handler, MATCHES_ROUTE
16
+ from same-origin $fetch / useFetch / useLazyFetch calls of the app) (#216).
15
17
  """
16
18
  from __future__ import annotations
17
19
 
@@ -851,6 +853,229 @@ def generate_types(root: Path, src_dir: str) -> tuple[Path, dict]:
851
853
  "import_scan": plan["scan"], "import_global": plan["global"], "auto_import": plan["auto_import"]}
852
854
 
853
855
 
856
+ # Nitro file-based routing (https://nitro.build/guide/routing): <name>[.<method>][.<env>].<ext>
857
+ NITRO_METHODS = ("get", "post", "put", "patch", "delete", "head", "options", "connect", "trace")
858
+ _NITRO_EXT = re.compile(r"\.(ts|mts|cts|js|mjs|cjs)$")
859
+ _NITRO_SKIP = re.compile(r"\.(test|spec)\.[cm]?[jt]s$|\.d\.ts$")
860
+ _PROXY_CALL = re.compile(r"\b(proxyRequest|sendProxy)\s*\(")
861
+
862
+
863
+ def nitro_route(rel: str, prefix: str = "") -> tuple[str, str] | None:
864
+ """Path of a file inside server/api or server/routes -> (METHOD, uri), or None for a non-route file.
865
+
866
+ `plants/[id].get.ts` with prefix `/api` -> (GET, /api/plants/{id}); no method suffix -> ANY; `index` is the
867
+ directory; `[...slug]` -> {slug*}, `[...]` -> {_*}; `(group)` directories are dropped; `.dev` / `.prod` /
868
+ `.prerender` env suffixes are ignored."""
869
+ if not _NITRO_EXT.search(rel) or _NITRO_SKIP.search(rel):
870
+ return None
871
+ parts = [p for p in _NITRO_EXT.sub("", rel).split("/") if p]
872
+ if not parts:
873
+ return None
874
+ last = parts[-1]
875
+ last = re.sub(r"\.(dev|prod|prerender)$", "", last)
876
+ method = "ANY"
877
+ m = re.match(r"^(.+)\.(%s)$" % "|".join(NITRO_METHODS), last)
878
+ if m:
879
+ last, method = m.group(1), m.group(2).upper()
880
+ parts[-1] = last
881
+ segs = []
882
+ for i, s in enumerate(parts):
883
+ if re.fullmatch(r"\(.*\)", s):
884
+ continue
885
+ if s == "index" and i == len(parts) - 1:
886
+ continue
887
+ if s == "[...]":
888
+ segs.append("{_*}")
889
+ continue
890
+ mm = re.fullmatch(r"\[\.\.\.(\w+)\]", s)
891
+ if mm:
892
+ segs.append("{%s*}" % mm.group(1))
893
+ continue
894
+ segs.append(re.sub(r"\[(\w+)\]", r"{\1}", s))
895
+ return method, "/" + "/".join(s.strip("/") for s in [prefix.strip("/")] + segs if s.strip("/"))
896
+
897
+
898
+ def server_dirs(root: Path, src_dir: str) -> list[str]:
899
+ """Nitro server dirs of a Nuxt project: the root server/ (Nuxt 4 serverDir) and <srcDir>/server (Nuxt 3)."""
900
+ cands = ["server"] + ([] if src_dir in ("", ".") else [f"{src_dir.strip('/')}/server"])
901
+ return [d for d in dict.fromkeys(cands) if (root / d).is_dir()]
902
+
903
+
904
+ # ------------------------------------------------------------ i18n locale files (#182)
905
+ # a top-level key shaped like a locale code: en, pt-BR, zh_Hant, es-419
906
+ LOCALE_RE = re.compile(r"^[a-z]{2,3}(?:[-_](?:[A-Z]{2}|[A-Z][a-z]{3}|\d{3}))*$")
907
+ _KNOWN_LOCALES = {"en", "ar", "ku", "fr", "de"}
908
+ LOCALE_EXTS = (".json", ".yaml", ".yml")
909
+
910
+
911
+ def json_key_lines(text: str) -> dict[str, int]:
912
+ """Dotted key path -> line of the key, for the objects of a JSON document (keys inside arrays are skipped,
913
+ as flatten() treats arrays as values)."""
914
+ out: dict[str, int] = {}
915
+ stack: list[list] = [] # [type, current key, expecting a key]
916
+ pending = None
917
+ i, n, line = 0, len(text), 1
918
+ while i < n:
919
+ c = text[i]
920
+ if c == "\n":
921
+ line += 1
922
+ elif c == '"':
923
+ j = i + 1
924
+ while j < n and text[j] != '"':
925
+ j += 2 if text[j] == "\\" else 1
926
+ raw = text[i:j + 1]
927
+ if stack and stack[-1][0] == "obj" and stack[-1][2]:
928
+ try:
929
+ pending = (json.loads(raw), line)
930
+ except ValueError:
931
+ pending = (raw.strip('"'), line)
932
+ line += raw.count("\n")
933
+ i = j + 1
934
+ continue
935
+ elif c == ":" and pending is not None and stack and stack[-1][0] == "obj":
936
+ stack[-1][1], stack[-1][2] = pending[0], False
937
+ if all(f[0] == "obj" for f in stack):
938
+ out.setdefault(".".join(str(f[1]) for f in stack), pending[1])
939
+ pending = None
940
+ elif c == "{":
941
+ stack.append(["obj", None, True])
942
+ elif c == "[":
943
+ stack.append(["arr", None, False])
944
+ elif c in "}]":
945
+ if stack:
946
+ stack.pop()
947
+ elif c == "," and stack and stack[-1][0] == "obj":
948
+ stack[-1][2] = True
949
+ i += 1
950
+ return out
951
+
952
+
953
+ def yaml_key_lines(text: str) -> dict[str, int]:
954
+ import yaml
955
+ out: dict[str, int] = {}
956
+
957
+ def walk(node, prefix):
958
+ if isinstance(node, yaml.MappingNode):
959
+ for k, v in node.value:
960
+ key = f"{prefix}.{k.value}" if prefix else str(k.value)
961
+ out.setdefault(key, k.start_mark.line + 1)
962
+ walk(v, key)
963
+ try:
964
+ walk(yaml.compose(text), "")
965
+ except Exception:
966
+ pass
967
+ return out
968
+
969
+
970
+ def load_locale_file(f: Path) -> tuple[object, dict[str, int]]:
971
+ """(data, key path -> line) of a JSON / YAML locale file; (None, {}) when it does not parse."""
972
+ try:
973
+ text = f.read_text(errors="replace")
974
+ if f.suffix == ".json":
975
+ return json.loads(text), json_key_lines(text)
976
+ import yaml
977
+ return yaml.safe_load(text), yaml_key_lines(text)
978
+ except Exception:
979
+ return None, {}
980
+
981
+
982
+ def nuxt_i18n_config(root: Path) -> dict:
983
+ """Literal slice of nuxt.config `i18n`: defaultLocale, langDir, locale codes and their files."""
984
+ cfg = _config_path(root)
985
+ if not cfg:
986
+ return {}
987
+ try:
988
+ obj = _find_config_object(cfg.read_text(errors="replace"))
989
+ except Exception:
990
+ return {}
991
+ i18n = obj.get("i18n") if isinstance(obj.get("i18n"), dict) else {}
992
+ codes, files = [], {}
993
+ for loc in i18n.get("locales") or [] if isinstance(i18n.get("locales"), list) else []:
994
+ if isinstance(loc, str):
995
+ codes.append(loc)
996
+ elif isinstance(loc, dict) and isinstance(loc.get("code"), str):
997
+ codes.append(loc["code"])
998
+ fs = [loc["file"]] if isinstance(loc.get("file"), str) else []
999
+ fs += [x for x in loc.get("files") or [] if isinstance(x, str)] if isinstance(loc.get("files"), list) else []
1000
+ fs += [x["path"] for x in loc.get("files") or [] if isinstance(x, dict) and isinstance(x.get("path"), str)] \
1001
+ if isinstance(loc.get("files"), list) else []
1002
+ for x in fs:
1003
+ files[x.lstrip("./")] = loc["code"]
1004
+ return {"default_locale": i18n.get("defaultLocale") if isinstance(i18n.get("defaultLocale"), str) else None,
1005
+ "lang_dir": i18n.get("langDir") if isinstance(i18n.get("langDir"), str) else None,
1006
+ "locales": codes, "files": files}
1007
+
1008
+
1009
+ def locale_dirs(root: Path, src_dir: str, lang_dir: str | None) -> list[str]:
1010
+ dirs = ["i18n/locales", f"{src_dir}/locales" if src_dir not in ("", ".") else "locales", "app/locales", "locales"]
1011
+ if lang_dir:
1012
+ ld = lang_dir.strip().lstrip("./").rstrip("/")
1013
+ dirs = [f"i18n/{ld}", (f"{src_dir}/{ld}" if src_dir not in ("", ".") else ld), ld] + dirs
1014
+ return [d for d in dict.fromkeys(dirs) if d and (root / d).is_dir()]
1015
+
1016
+
1017
+ def _sfc_key_lines(text: str, keys: list[str]) -> dict[str, int]:
1018
+ """Line of each key's last segment inside the SFC's <i18n> block (the block's line when it is not found)."""
1019
+ m = re.search(r"<i18n\b[^>]*>", text)
1020
+ if not m:
1021
+ return {}
1022
+ base = text.count("\n", 0, m.start()) + 1
1023
+ body = text[m.end():]
1024
+ end = body.find("</i18n>")
1025
+ body = body if end < 0 else body[:end]
1026
+ out = {}
1027
+ for k in keys:
1028
+ last = k.split(".")[-1]
1029
+ km = re.search(r"[\"']?%s[\"']?\s*:" % re.escape(last), body)
1030
+ out[k] = base + (body.count("\n", 0, km.start()) if km else 0)
1031
+ return out
1032
+
1033
+
1034
+ def i18n_definitions(root: Path, src_dir: str, sfc_i18n: dict) -> tuple[dict, list[str], str | None]:
1035
+ """key -> [{locale, file, line}], the project's locales, and the default locale (nuxt.config defaultLocale, else
1036
+ the first locale found). A file keyed by locale codes ({"en": {...}, "pt-BR": {...}}) defines every locale."""
1037
+ cfg = nuxt_i18n_config(root)
1038
+ configured = set(cfg.get("locales") or [])
1039
+ defs: dict[str, list[dict]] = {}
1040
+ seen_locales: list[str] = []
1041
+
1042
+ def add(key, locale, rel, line):
1043
+ defs.setdefault(key, []).append({"locale": locale, "file": rel, "line": line or 1})
1044
+ if locale and locale not in seen_locales:
1045
+ seen_locales.append(locale)
1046
+
1047
+ for d in locale_dirs(root, src_dir, cfg.get("lang_dir")):
1048
+ for f in sorted(p for p in (root / d).glob("*") if p.suffix in LOCALE_EXTS and p.is_file()):
1049
+ data, lines = load_locale_file(f)
1050
+ if not isinstance(data, dict) or not data:
1051
+ continue
1052
+ rel = f.relative_to(root).as_posix()
1053
+ top = list(data)
1054
+ stem_locale = f.stem if (LOCALE_RE.match(f.stem) or f.stem in configured) else None
1055
+ keyed = all(isinstance(data[k], dict) and isinstance(k, str) for k in top) and (
1056
+ set(top) <= (configured or _KNOWN_LOCALES) or set(top) <= _KNOWN_LOCALES
1057
+ or (stem_locale is None and all(LOCALE_RE.match(k) for k in top)))
1058
+ if keyed:
1059
+ for loc in top:
1060
+ for k in flatten(data[loc]):
1061
+ add(k, loc, rel, lines.get(f"{loc}.{k}"))
1062
+ else:
1063
+ loc = cfg.get("files", {}).get(f.name) or cfg.get("files", {}).get(rel) or stem_locale
1064
+ for k in flatten(data):
1065
+ add(k, loc, rel, lines.get(k))
1066
+ for f, keys in sfc_i18n.items():
1067
+ try:
1068
+ text = (root / f).read_text(errors="replace")
1069
+ except OSError:
1070
+ text = ""
1071
+ kl = _sfc_key_lines(text, keys)
1072
+ for k in keys:
1073
+ add(k, None, f, kl.get(k, 1))
1074
+ default = cfg.get("default_locale") or (seen_locales[0] if seen_locales else None)
1075
+ locales = list(dict.fromkeys([*configured, *seen_locales]))
1076
+ return defs, locales, default
1077
+
1078
+
854
1079
  def flatten(d, prefix=""):
855
1080
  if isinstance(d, dict):
856
1081
  for k, v in d.items():
@@ -928,27 +1153,119 @@ class NuxtPlugin(FrameworkPlugin):
928
1153
  if lay in layouts:
929
1154
  builder.add_edge(n.id, layouts[lay], "USES_LAYOUT", file=n.file, line=1,
930
1155
  confidence="exact" if n.file in meta and meta[n.file].get("layout") else "resolved")
931
- # i18n: keys used in code/templates, and where they are defined
932
- defined = {}
933
- for d in dict.fromkeys(("i18n/locales", f"{self.src_dir}/locales", "app/locales", "locales")):
934
- for f in sorted((project.root / d).glob("*.json")) if (project.root / d).exists() else []:
935
- try:
936
- data = json.loads(f.read_text())
937
- except Exception:
938
- continue
939
- locs = {"en", "ar", "ku", "fr", "de"}
940
- if isinstance(data, dict) and set(data) and set(data) <= locs:
941
- data = next(iter(data.values()))
942
- for k in flatten(data):
943
- defined.setdefault(k, []).append(str(f.relative_to(project.root)))
944
- for f, keys in (ctx.facts.get("sfc_i18n") or {}).items():
945
- for k in keys:
946
- defined.setdefault(k, []).append(f)
1156
+ # i18n: keys used in code/templates, and where they are defined (#182)
1157
+ defs, locales, default = i18n_definitions(project.root, self.src_dir, ctx.facts.get("sfc_i18n") or {})
1158
+ used: dict[str, int] = {}
947
1159
  for u in ctx.facts.get("i18n") or []:
948
- nid = builder.add_node("i18n", u["key"], u["key"], lang="ts", attrs={"defined_in": defined.get(u["key"], [])})
1160
+ used[u["key"]] = used.get(u["key"], 0) + 1
1161
+ for u in ctx.facts.get("i18n") or []:
1162
+ key = u["key"]
1163
+ ds = defs.get(key) or []
1164
+ home = next((d for d in ds if default and d["locale"] == default), ds[0] if ds else None)
1165
+ attrs = {"defined_in": list(dict.fromkeys(d["file"] for d in ds)), "definitions": ds, "uses": used[key]}
1166
+ have = {d["locale"] for d in ds if d["locale"]}
1167
+ if default and default in have:
1168
+ missing = sorted(set(locales) - have)
1169
+ if missing:
1170
+ attrs["missing_locales"] = missing
1171
+ nid = builder.add_node("i18n", key, key, lang="ts", file=home["file"] if home else None,
1172
+ line=home["line"] if home else None, attrs=attrs)
949
1173
  builder.add_edge(u["src"], nid, "USES_I18N", file=u["file"], line=u["line"],
950
- confidence="exact" if u["key"] in defined else "heuristic")
1174
+ confidence="exact" if key in defs else "heuristic")
1175
+ defined = defs
1176
+ st["i18n_locales"] = sorted(locales)
1177
+ st["i18n_default_locale"] = default
951
1178
  st["i18n_keys_used"] = len({u["key"] for u in ctx.facts.get("i18n") or []})
1179
+ st["nitro"] = self._nitro(project, builder)
952
1180
  st["i18n_keys_defined"] = len(defined)
953
1181
  st["i18n_used_but_undefined"] = len({u["key"] for u in ctx.facts.get("i18n") or []} - set(defined))
954
1182
  return st
1183
+
1184
+ # ------------------------------------------------------------ Nitro server routes (#216)
1185
+ def _nitro(self, project: Project, b: GraphBuilder) -> dict:
1186
+ from ..tsweb.common import add_route
1187
+ st = {"routes": 0, "middleware": 0, "plugins": 0, "proxy_routes": 0, "linked_calls": 0}
1188
+ dirs = server_dirs(project.root, self.src_dir)
1189
+ if not dirs:
1190
+ return st
1191
+ files = sorted({n.file for n in b.nodes.values() if n.lang == "ts" and n.kind == "module" and n.file})
1192
+
1193
+ def handler(f: str) -> tuple[str | None, str]:
1194
+ for nid in (f"function:{f}#default", f"function:{f}#handler"):
1195
+ if b.has(nid):
1196
+ return nid, "exact"
1197
+ return (f"module:{f}", "resolved") if b.has(f"module:{f}") else (None, "heuristic")
1198
+
1199
+ def label(f: str, kind: str):
1200
+ for nid in (f"module:{f}", handler(f)[0]):
1201
+ if nid and b.has(nid):
1202
+ b.nodes[nid].attrs["nitro"] = kind
1203
+
1204
+ middleware, routes = [], []
1205
+ for d in dirs:
1206
+ for f in files:
1207
+ if not f.startswith(d + "/"):
1208
+ continue
1209
+ rest = f[len(d) + 1:]
1210
+ top, _, inner = rest.partition("/")
1211
+ if top == "middleware" and inner and nitro_route(inner) is not None:
1212
+ h, _c = handler(f)
1213
+ if h:
1214
+ label(f, "middleware")
1215
+ middleware.append((h, f"nitro:{_NITRO_EXT.sub('', inner)}", "resolved"))
1216
+ st["middleware"] += 1
1217
+ elif top == "plugins" and inner and nitro_route(inner) is not None:
1218
+ h, _c = handler(f)
1219
+ if h:
1220
+ label(f, "plugin")
1221
+ b.nodes[h].entry_kind = b.nodes[h].entry_kind or "main"
1222
+ st["plugins"] += 1
1223
+ elif top in ("api", "routes") and inner:
1224
+ r = nitro_route(inner, "/api" if top == "api" else "")
1225
+ if r:
1226
+ routes.append((f, top, r))
1227
+ for f, top, (method, uri) in routes:
1228
+ h, conf = handler(f)
1229
+ line = (b.nodes[h].line or 1) if h else 1
1230
+ attrs = {"file_route": True, "nitro_dir": top, "method_from": "file suffix" if method != "ANY" else "any"}
1231
+ try:
1232
+ src = (project.root / f).read_text(errors="replace")
1233
+ except OSError:
1234
+ src = ""
1235
+ if _PROXY_CALL.search(src):
1236
+ attrs["proxy"] = True
1237
+ st["proxy_routes"] += 1
1238
+ if not h or h.startswith("module:"):
1239
+ attrs["handler_unresolved"] = True
1240
+ add_route(b, method, uri, [h] if h else [], f, line, "nuxt", conf, attrs, middleware)
1241
+ label(f, "route")
1242
+ st["routes"] += 1
1243
+ st["linked_calls"] = self._link_nitro(b)
1244
+ return st
1245
+
1246
+ def _link_nitro(self, b: GraphBuilder) -> int:
1247
+ """Same-origin client calls of this app (relative URLs: `$fetch('/api/x')`, `useFetch`) -> its Nitro routes.
1248
+ Proxy routes (proxyRequest / sendProxy) forward elsewhere and are not link targets."""
1249
+ from ...link import match_endpoint
1250
+ routes = []
1251
+ for n in b.nodes.values():
1252
+ a = n.attrs
1253
+ if n.kind == "route" and a.get("framework") == "nuxt" and a.get("uri") and not a.get("proxy"):
1254
+ routes.append({"id": n.id, "uri": a["uri"], "method": a["method"], "uris": [("as-declared", a["uri"])],
1255
+ "file": n.file, "line": n.line})
1256
+ if not routes:
1257
+ return 0
1258
+ rmap = {r["id"]: r for r in routes}
1259
+ linked = 0
1260
+ for n in list(b.nodes.values()):
1261
+ a = n.attrs
1262
+ if n.kind != "http" or n.lang != "ts" or a.get("origin_kind") != "same-origin":
1263
+ continue
1264
+ res = match_endpoint(a.get("method", "GET"), a.get("path", ""), routes, "api", None)
1265
+ for m in res["matched"]:
1266
+ r = rmap[m["route"]]
1267
+ b.add_edge(n.id, m["route"], "MATCHES_ROUTE", file=r["file"], line=r["line"], confidence=m["confidence"],
1268
+ client_path=a.get("path"), uri_variant=m["uri_variant"], segments=m["segments"], in_repo=True)
1269
+ if res["matched"]:
1270
+ linked += 1
1271
+ return linked
@@ -63,7 +63,11 @@ const INDEX_TESTS = cfg.index_tests !== false
63
63
  const TEST_FILE_RE = /\.(test|spec|e2e-spec|e2e|cy)\.(t|j)sx?$/
64
64
  const TEST_DIR_RE = /(^|\/)(__tests__|e2e|tests?|cypress|playwright)\//
65
65
  const TEST_ROOTS = ['e2e', 'test', 'tests', 'cypress', 'playwright', 'src/test', 'src/tests', 'src/e2e']
66
- const isTestRel = r => TEST_FILE_RE.test(r) || /(^|\/)__tests__\//.test(r) || TEST_ROOTS.some(d => r.startsWith(d + '/'))
66
+ // nested test trees (#156): a `playwright/` or `cypress/` directory below the top level (help/playwright/), and a nested
67
+ // `e2e/` outside the source dirs, are test roots like the top-level ones (filled once the source dirs are known)
68
+ const NESTED_TEST_NAMES = new Set(['playwright', 'cypress', 'e2e'])
69
+ const nestedTestRoots = []
70
+ const isTestRel = r => TEST_FILE_RE.test(r) || /(^|\/)__tests__\//.test(r) || TEST_ROOTS.some(d => r.startsWith(d + '/')) || nestedTestRoots.some(d => r.startsWith(d + '/'))
67
71
 
68
72
  // ---------- file kinds (from the framework plugin: [[prefix, kind], ...]) ----------
69
73
  function fileKind(r) {
@@ -270,9 +274,25 @@ function walkTests(d, all, forced = false) {
270
274
  else if (SRC_EXT.test(e.name) && (e.isFile() || (e.isSymbolicLink() && !skippedLinks.includes(rel(p)) && fileEntry(e, p))) && !e.name.endsWith('.d.ts') && (all || isTestRel(rel(p)))) testFiles.add(p)
271
275
  }
272
276
  }
277
+ function findNestedTestRoots(d, depth) {
278
+ if (depth > 6) return
279
+ let ents = []
280
+ try { ents = fs.readdirSync(d, { withFileTypes: true }) } catch { return }
281
+ for (const e of ents) {
282
+ if (!e.isDirectory()) continue
283
+ const p = path.join(d, e.name), r = rel(p)
284
+ if (skipDir(e.name, r, TEST_SKIP_NAMES, false) || excludedRel(r + '/') || TEST_ROOTS.includes(r)) continue
285
+ if (depth > 0 && NESTED_TEST_NAMES.has(e.name) && (e.name !== 'e2e' || !srcDirs.some(s => p === s || p.startsWith(s + path.sep)))) {
286
+ nestedTestRoots.push(r)
287
+ continue
288
+ }
289
+ findNestedTestRoots(p, depth + 1)
290
+ }
291
+ }
273
292
  if (INDEX_TESTS) {
293
+ findNestedTestRoots(ROOT, 0)
274
294
  for (const d of srcDirs) walkTests(d, false)
275
- for (const d of TEST_ROOTS) { const p = path.resolve(ROOT, d); if (fs.existsSync(p) && fs.statSync(p).isDirectory()) walkTests(p, true) }
295
+ for (const d of [...TEST_ROOTS, ...nestedTestRoots]) { const p = path.resolve(ROOT, d); if (fs.existsSync(p) && fs.statSync(p).isDirectory()) walkTests(p, true) }
276
296
  }
277
297
  // scripts the tests run in a subprocess (`spawnSync('node', [path.join(__dirname, '..', 'tools', 'gen.js')])`,
278
298
  // `execSync('node tools/gen.js')`) outside every source dir are source files too, so the subprocess link
@@ -3728,6 +3748,6 @@ fs.writeFileSync(cfg.out, JSON.stringify({ nodes, edges, api_calls: apiCalls, i1
3728
3748
  // for `cg coverage` (#106): the files analysed, and the roots they come from (source dirs, source files, test trees);
3729
3749
  // a discovered file outside every root was never read, so it is not indexed rather than exact
3730
3750
  seen_files: [...new Set(sourceFiles.map(sf => rel(realFile(sf))))].sort(),
3731
- roots: [...srcDirs.map(d => rel(d) + '/'), ...[...srcFiles].map(rel), ...TEST_ROOTS.map(d => d + '/')].filter(r => r && r !== '/' && !r.startsWith('..')),
3751
+ roots: [...srcDirs.map(d => rel(d) + '/'), ...[...srcFiles].map(rel), ...TEST_ROOTS.map(d => d + '/'), ...nestedTestRoots.map(d => d + '/')].filter(r => r && r !== '/' && !r.startsWith('..')),
3732
3752
  stats }))
3733
3753
  console.log(JSON.stringify(stats))
@@ -44,6 +44,14 @@ def resolve_targets(st: GraphStore, spec: str) -> list[str]:
44
44
 
45
45
 
46
46
 
47
+ def _search_hint(spec: str, ambiguous: bool = False) -> str:
48
+ """One line pointing at `cg search` (the MCP `search` tool) for a snippet spec that matched several nodes or none (#156)."""
49
+ q = spec if re.fullmatch(r"[\w.:#/$-]+", spec or "") else repr(spec)
50
+ if ambiguous:
51
+ return f"run `cg search {q}` (MCP: search) to see the matches with file:line, then snippet one id or FQN"
52
+ return f"try `cg search {q}` (MCP: search) with part of the name, then snippet a listed id or FQN"
53
+
54
+
47
55
  def snippet(st: GraphStore, spec: str, context: int = 0, max_lines: int = 200) -> dict:
48
56
  """Source of one symbol, read from disk via the node file / line / end_line. Returns a dict
49
57
  whose "status" is one of: ok (id, kind, file, start, end, shown_start, shown_end,
@@ -52,14 +60,15 @@ def snippet(st: GraphStore, spec: str, context: int = 0, max_lines: int = 200) -
52
60
  disk, with the paths tried). context adds lines around the span; max_lines caps the body."""
53
61
  ids = list(dict.fromkeys(resolve_targets(st, spec)))
54
62
  if not ids:
55
- return {"status": "none", "spec": spec}
63
+ return {"status": "none", "spec": spec, "hint": _search_hint(spec)}
56
64
  if len(ids) > 1:
57
65
  cands = []
58
66
  for nid in ids[:20]:
59
67
  n = st.node(nid)
60
68
  cands.append({"id": nid, "kind": n["kind"] if n else "?",
61
69
  "file": n["file"] if n else None, "line": n["line"] if n else None})
62
- return {"status": "ambiguous", "spec": spec, "count": len(ids), "candidates": cands}
70
+ return {"status": "ambiguous", "spec": spec, "count": len(ids), "candidates": cands,
71
+ "hint": _search_hint(spec, ambiguous=True)}
63
72
  nid = ids[0]
64
73
  n = st.node(nid)
65
74
  if not n or not n["file"] or not n["line"]:
@@ -95,7 +104,7 @@ def render_snippet(res: dict) -> str:
95
104
  error line for a non-ok status."""
96
105
  status = res.get("status")
97
106
  if status == "none":
98
- return f"no node matches {res['spec']!r}; try `search` with part of the name"
107
+ return f"no node matches {res['spec']!r}; {res.get('hint') or _search_hint(res['spec'])}"
99
108
  if status == "no_source":
100
109
  return f"{res['id']}: no source location recorded (nothing to show)"
101
110
  if status == "missing":
@@ -106,6 +115,7 @@ def render_snippet(res: dict) -> str:
106
115
  for c in res["candidates"]:
107
116
  loc = f"{c['file']}:{c['line']}" if c.get("file") else "(no source location)"
108
117
  out.append(f" {c['id']} [{c['kind']}] {loc}")
118
+ out.append(res.get("hint") or _search_hint(res["spec"], ambiguous=True))
109
119
  return "\n".join(out)
110
120
  lines = res["lines"]
111
121
  out = [f"{res['file']}:{res['start']}-{res['end']}"]
@@ -1301,6 +1311,13 @@ def with_generated(row: dict) -> dict:
1301
1311
  """A node row without its raw attrs, plus `generated` (the reason) for a node from a generated / copied / vendored
1302
1312
  file (indexed with --include-generated)."""
1303
1313
  raw = row.pop("attrs", None)
1314
+ if raw and row.get("kind") == "i18n":
1315
+ try:
1316
+ a = json.loads(raw) or {}
1317
+ except ValueError:
1318
+ a = {}
1319
+ row["i18n"] = {"locales": len({d.get("locale") or d.get("file") for d in a.get("definitions") or []}),
1320
+ "uses": a.get("uses") or 0, "missing_locales": a.get("missing_locales") or []}
1304
1321
  if raw and ('"platforms"' in raw or '"available"' in raw):
1305
1322
  from .platforms import node_platforms
1306
1323
  row.update(node_platforms(raw))
@@ -1592,10 +1609,12 @@ def _impact(st: GraphStore, spec: str, min_conf: str, platform: str | None) -> d
1592
1609
  built = [t for t in targets if t not in set(not_built)]
1593
1610
  targets = built
1594
1611
  kinds = CALL_LIKE + DATA_USE if any(t.startswith(DATA_TARGET) for t in targets) else CALL_LIKE
1612
+ if any(t.startswith("i18n:") for t in targets):
1613
+ kinds = kinds + ["USES_I18N"] # the components / pages showing a translation key are its callers (#182)
1595
1614
  si = _has_class_target(targets)
1596
1615
  rel = override_relations(st, targets, min_conf)
1597
1616
  below = override_seeds(st, spec, targets, min_conf)
1598
- cols = _table_columns(st, targets) if kinds is not CALL_LIKE else []
1617
+ cols = _table_columns(st, targets) if any(t.startswith(DATA_TARGET) for t in targets) else []
1599
1618
  seeds = targets + cols + below
1600
1619
  depth = reverse_closure(st, seeds, kinds=kinds, min_conf=min_conf, seed_inst=si, platform=platform)
1601
1620
  own = reverse_closure(st, targets + cols, kinds=kinds, min_conf=min_conf, seed_inst=si, platform=platform) if below else depth
@@ -2517,6 +2536,18 @@ def search(st: GraphStore, name: str, kind: str | None = None, limit: int = 20,
2517
2536
  return out
2518
2537
 
2519
2538
 
2539
+ def _i18n_label(r: dict) -> str:
2540
+ """` (2 locales, 1 use)` for an i18n key row of search (#182)."""
2541
+ a = r.get("i18n")
2542
+ if not a:
2543
+ return ""
2544
+ locs, uses = a.get("locales") or 0, a.get("uses") or 0
2545
+ out = f" ({locs} locale{'s' if locs != 1 else ''}, {uses} use{'s' if uses != 1 else ''})"
2546
+ if a.get("missing_locales"):
2547
+ out += f" missing: {', '.join(a['missing_locales'])}"
2548
+ return out
2549
+
2550
+
2520
2551
  def render_search(res: dict, limit_routes: int = 8) -> str:
2521
2552
  out = []
2522
2553
  if res.get("platform"):
@@ -2526,7 +2557,7 @@ def render_search(res: dict, limit_routes: int = 8) -> str:
2526
2557
  out.append(f"{res['platform']['matches_not_built']} matching symbols are not built for {res['platform']['platform']} "
2527
2558
  f"(search without platform lists them)")
2528
2559
  for r in res["nodes"]:
2529
- out.append(f"{r['kind']:10} {r['id']} {r['file'] or '?'}:{r['line']}{platform_label(r)}")
2560
+ out.append(f"{r['kind']:10} {r['id']} {r['file'] or '?'}:{r['line']}{platform_label(r)}{_i18n_label(r)}")
2530
2561
  if res["guards"]:
2531
2562
  if out:
2532
2563
  out.append("")