cg-code-graph 0.23.4__tar.gz → 0.23.5__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 (409) hide show
  1. {cg_code_graph-0.23.4/cg_code_graph.egg-info → cg_code_graph-0.23.5}/PKG-INFO +1 -1
  2. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/__init__.py +1 -1
  3. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/blindspots.py +26 -6
  4. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/cli.py +3 -0
  5. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/core/plugin.py +3 -0
  6. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/link.py +28 -5
  7. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plans.py +3 -6
  8. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/laravel/plugin.py +55 -2
  9. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/laravel/tests.py +4 -6
  10. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/nuxt/plugin.py +207 -11
  11. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/extractor/extract.php +329 -2
  12. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/plugin.py +11 -1
  13. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/query.py +165 -10
  14. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/routes.py +56 -3
  15. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/webhook_subs.py +2 -3
  16. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5/cg_code_graph.egg-info}/PKG-INFO +1 -1
  17. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph.egg-info/SOURCES.txt +2 -0
  18. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_channels_tests.py +4 -4
  19. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_external.py +1 -1
  20. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_fp_batch.py +8 -8
  21. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_inline_guards.py +65 -65
  22. cg_code_graph-0.23.5/tests/test_laravel_receiver_narrowing.py +130 -0
  23. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_laravel_resources.py +1 -1
  24. cg_code_graph-0.23.5/tests/test_laravel_route_paths.py +279 -0
  25. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_mass_assignment.py +1 -1
  26. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_mcp_index.py +2 -2
  27. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_nuxt_nitro.py +54 -2
  28. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_nuxt_rootsrc.py +2 -2
  29. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_php_http.py +2 -2
  30. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_plans.py +3 -3
  31. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_request_keys.py +8 -8
  32. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_routes_search_explain.py +14 -14
  33. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_surface.py +5 -5
  34. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_ts_nuxt.py +2 -2
  35. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_unguarded.py +10 -10
  36. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_values.py +1 -1
  37. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_webhooks.py +5 -5
  38. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_webhooks_152.py +10 -10
  39. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_webhooks_152b.py +8 -8
  40. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/LICENSE +0 -0
  41. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/MANIFEST.in +0 -0
  42. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/README.md +0 -0
  43. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/__main__.py +0 -0
  44. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/affected.py +0 -0
  45. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/agent_rules.py +0 -0
  46. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/agents.py +0 -0
  47. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/aitools.py +0 -0
  48. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/android_ipc.py +0 -0
  49. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/apple_ipc.py +0 -0
  50. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/apps.py +0 -0
  51. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/bridges.py +0 -0
  52. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/brokers.py +0 -0
  53. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/concepts.py +0 -0
  54. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/config.py +0 -0
  55. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/core/__init__.py +0 -0
  56. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/core/cache.py +0 -0
  57. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/core/detect.py +0 -0
  58. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/core/env.py +0 -0
  59. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/core/extractors.py +0 -0
  60. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/core/fsutil.py +0 -0
  61. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/core/generated.py +0 -0
  62. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/core/model.py +0 -0
  63. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/core/paths.py +0 -0
  64. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/core/redact.py +0 -0
  65. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/core/store.py +0 -0
  66. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/core/syntax_errors.py +0 -0
  67. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/coverage.py +0 -0
  68. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/dart_isolates.py +0 -0
  69. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/doctor.py +0 -0
  70. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/explore.py +0 -0
  71. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/external.py +0 -0
  72. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/graphql.py +0 -0
  73. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/guard_facts.py +0 -0
  74. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/hooks.py +0 -0
  75. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/indexer.py +0 -0
  76. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/insecure_transport.py +0 -0
  77. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/install_rules.py +0 -0
  78. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/jobs.py +0 -0
  79. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/lint_async.py +0 -0
  80. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/local_ipc.py +0 -0
  81. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/local_sockets.py +0 -0
  82. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/mcp_graphs.py +0 -0
  83. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/mcp_install.py +0 -0
  84. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/mcp_server.py +0 -0
  85. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/parity.py +0 -0
  86. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/parity_structure.py +0 -0
  87. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/payload.py +0 -0
  88. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/platform_scan.py +0 -0
  89. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/platforms.py +0 -0
  90. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/__init__.py +0 -0
  91. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/astro/__init__.py +0 -0
  92. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/astro/content.py +0 -0
  93. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/astro/plugin.py +0 -0
  94. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/cfamily/__init__.py +0 -0
  95. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/cfamily/plugin.py +0 -0
  96. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/cfamily/syntax.py +0 -0
  97. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/__init__.py +0 -0
  98. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/bridges.py +0 -0
  99. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/extractor/bin/extract.dart +0 -0
  100. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/extractor/pubspec.lock +0 -0
  101. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/extractor/pubspec.yaml +0 -0
  102. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/http.py +0 -0
  103. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/models.py +0 -0
  104. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/plugin.py +0 -0
  105. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/program.py +0 -0
  106. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/django/__init__.py +0 -0
  107. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/django/extras.py +0 -0
  108. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/django/models.py +0 -0
  109. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/django/plugin.py +0 -0
  110. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/django/schemas.py +0 -0
  111. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/django/shapes.py +0 -0
  112. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/django/urls.py +0 -0
  113. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/express/__init__.py +0 -0
  114. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/express/plugin.py +0 -0
  115. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/flutter/__init__.py +0 -0
  116. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/flutter/plugin.py +0 -0
  117. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/java/__init__.py +0 -0
  118. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/java/exact.py +0 -0
  119. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/java/plugin.py +0 -0
  120. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/jvm/__init__.py +0 -0
  121. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/jvm/interop.py +0 -0
  122. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/jvm/spring.py +0 -0
  123. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/kotlin/__init__.py +0 -0
  124. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/kotlin/exact.py +0 -0
  125. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/kotlin/plugin.py +0 -0
  126. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/kotlin/reparse.py +0 -0
  127. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/laravel/__init__.py +0 -0
  128. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/laravel/broadcast.py +0 -0
  129. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/laravel/massassign.py +0 -0
  130. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/laravel/values.py +0 -0
  131. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/native/__init__.py +0 -0
  132. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/native/gates.py +0 -0
  133. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/native/runner.py +0 -0
  134. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/native/scipread.py +0 -0
  135. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/native/ts.py +0 -0
  136. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/nest/__init__.py +0 -0
  137. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/nest/plugin.py +0 -0
  138. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/nextjs/__init__.py +0 -0
  139. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/nextjs/plugin.py +0 -0
  140. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/nuxt/__init__.py +0 -0
  141. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/__init__.py +0 -0
  142. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/external.py +0 -0
  143. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/extractor/composer.json +0 -0
  144. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/extractor/composer.lock +0 -0
  145. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/gating.py +0 -0
  146. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/http_client.py +0 -0
  147. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/inline_guards.py +0 -0
  148. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/strings.py +0 -0
  149. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/__init__.py +0 -0
  150. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/aitools.py +0 -0
  151. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/external.py +0 -0
  152. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/fields.py +0 -0
  153. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/plugin.py +0 -0
  154. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/refs.py +0 -0
  155. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/roots.py +0 -0
  156. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/socketio.py +0 -0
  157. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/subproc.py +0 -0
  158. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/tests.py +0 -0
  159. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/values.py +0 -0
  160. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/pyweb/__init__.py +0 -0
  161. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/pyweb/plugin.py +0 -0
  162. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/pyweb/values.py +0 -0
  163. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/rust/__init__.py +0 -0
  164. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/rust/cargo.py +0 -0
  165. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/rust/plugin.py +0 -0
  166. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/rust/syntax.py +0 -0
  167. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/scip/__init__.py +0 -0
  168. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/scip/importer.py +0 -0
  169. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/scip/scip.proto +0 -0
  170. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/scip/scip_pb2.py +0 -0
  171. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/stubs/__init__.py +0 -0
  172. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/stubs/plugins.py +0 -0
  173. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/swift/__init__.py +0 -0
  174. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/swift/baseurl.py +0 -0
  175. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/swift/exact.py +0 -0
  176. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/swift/indexstore.py +0 -0
  177. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/swift/packages.py +0 -0
  178. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/swift/plugin.py +0 -0
  179. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/__init__.py +0 -0
  180. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/baseurl.py +0 -0
  181. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/extractor/extract.mjs +0 -0
  182. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/extractor/fw.mjs +0 -0
  183. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/extractor/package-lock.json +0 -0
  184. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/extractor/package.json +0 -0
  185. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/extractor/rr.mjs +0 -0
  186. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/nav.py +0 -0
  187. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/plugin.py +0 -0
  188. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/react_router.py +0 -0
  189. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/tsweb/__init__.py +0 -0
  190. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/tsweb/common.py +0 -0
  191. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/plugins/tsweb/data.py +0 -0
  192. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/__init__.py +0 -0
  193. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/c_cpp.yaml +0 -0
  194. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/common.yaml +0 -0
  195. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/dart.yaml +0 -0
  196. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/django-ninja.yaml +0 -0
  197. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/django.yaml +0 -0
  198. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/djangorestframework.yaml +0 -0
  199. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/express.yaml +0 -0
  200. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/java.yaml +0 -0
  201. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/kotlin.yaml +0 -0
  202. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/laravel.yaml +0 -0
  203. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/nest.yaml +0 -0
  204. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/nextjs.yaml +0 -0
  205. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/nuxt.yaml +0 -0
  206. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/php.yaml +0 -0
  207. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/python.yaml +0 -0
  208. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/react-router.yaml +0 -0
  209. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/rust.yaml +0 -0
  210. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/spring.yaml +0 -0
  211. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/swift.yaml +0 -0
  212. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/presets/typescript.yaml +0 -0
  213. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/process_runs.py +0 -0
  214. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/protocols/__init__.py +0 -0
  215. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/protocols/builtin.py +0 -0
  216. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/protocols/matchers.py +0 -0
  217. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/protocols/view.py +0 -0
  218. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/realtime.py +0 -0
  219. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/realtime_events.py +0 -0
  220. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/realtime_native.py +0 -0
  221. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/realtime_ws.py +0 -0
  222. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/roundtrip.py +0 -0
  223. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/rpc.py +0 -0
  224. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/sdk_systems.py +0 -0
  225. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/sockets.py +0 -0
  226. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/ssrf_input.py +0 -0
  227. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/starters.py +0 -0
  228. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/surface.py +0 -0
  229. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/tests_index.py +0 -0
  230. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/udp_apps.py +0 -0
  231. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/update_check.py +0 -0
  232. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/__init__.py +0 -0
  233. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/graph.py +0 -0
  234. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/server.py +0 -0
  235. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/app.css +0 -0
  236. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/app.js +0 -0
  237. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/index.html +0 -0
  238. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/layered.js +0 -0
  239. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/vendor/VERSIONS.txt +0 -0
  240. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/vendor/cose-base.js +0 -0
  241. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/vendor/cytoscape-fcose.js +0 -0
  242. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/vendor/cytoscape.min.js +0 -0
  243. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/vendor/layout-base.js +0 -0
  244. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/tools/package-lock.json +0 -0
  245. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/tools/package.json +0 -0
  246. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/viz/tools/shoot.mjs +0 -0
  247. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/watch.py +0 -0
  248. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/webhooks.py +0 -0
  249. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph/xcode.py +0 -0
  250. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph.egg-info/dependency_links.txt +0 -0
  251. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph.egg-info/entry_points.txt +0 -0
  252. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph.egg-info/requires.txt +0 -0
  253. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/cg_code_graph.egg-info/top_level.txt +0 -0
  254. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/pyproject.toml +0 -0
  255. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/setup.cfg +0 -0
  256. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_affected.py +0 -0
  257. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_agents_install.py +0 -0
  258. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_agents_md.py +0 -0
  259. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_ai_tools.py +0 -0
  260. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_android_ipc.py +0 -0
  261. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_apple_ipc.py +0 -0
  262. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_astro.py +0 -0
  263. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_astro_content.py +0 -0
  264. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_astro_server.py +0 -0
  265. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_bridges.py +0 -0
  266. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_bridges_pigeon_monorepo.py +0 -0
  267. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_brokers.py +0 -0
  268. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_cache_clean.py +0 -0
  269. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_cache_invalidation.py +0 -0
  270. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_cache_migration.py +0 -0
  271. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_cli_output.py +0 -0
  272. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_completeness.py +0 -0
  273. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_config_extras.py +0 -0
  274. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_coverage.py +0 -0
  275. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_coverage_ts_hint.py +0 -0
  276. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_dart_isolates.py +0 -0
  277. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_db_connections.py +0 -0
  278. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_dead_wrappers.py +0 -0
  279. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_dispatch_interfaces.py +0 -0
  280. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_django_flutter.py +0 -0
  281. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_docs_languages.py +0 -0
  282. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_docs_links.py +0 -0
  283. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_echo_ref.py +0 -0
  284. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_echo_wrapper.py +0 -0
  285. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_elysia.py +0 -0
  286. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_enum_constants.py +0 -0
  287. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_env.py +0 -0
  288. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_explore.py +0 -0
  289. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_gating.py +0 -0
  290. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_generated.py +0 -0
  291. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_graphql.py +0 -0
  292. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_hooks.py +0 -0
  293. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_impact_overrides.py +0 -0
  294. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_index_isolation.py +0 -0
  295. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_inherited_overrides.py +0 -0
  296. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_install_rules.py +0 -0
  297. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_192.py +0 -0
  298. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_201.py +0 -0
  299. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_202.py +0 -0
  300. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_203.py +0 -0
  301. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_204.py +0 -0
  302. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_205.py +0 -0
  303. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_206.py +0 -0
  304. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_207.py +0 -0
  305. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_208.py +0 -0
  306. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_209.py +0 -0
  307. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_210.py +0 -0
  308. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_211.py +0 -0
  309. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_211_used_at.py +0 -0
  310. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_212.py +0 -0
  311. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_issue_219.py +0 -0
  312. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_java.py +0 -0
  313. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_java_exact.py +0 -0
  314. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_jobs.py +0 -0
  315. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_js_refs.py +0 -0
  316. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_js_runtime.py +0 -0
  317. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_kotlin.py +0 -0
  318. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_kotlin_binding.py +0 -0
  319. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_kotlin_exact.py +0 -0
  320. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_kotlin_fields.py +0 -0
  321. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_kotlin_mixed.py +0 -0
  322. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_kotlin_nav_consts.py +0 -0
  323. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_kotlin_props.py +0 -0
  324. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_laravel_determinism.py +0 -0
  325. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_link_origin.py +0 -0
  326. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_lint_async.py +0 -0
  327. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_listing_files.py +0 -0
  328. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_local_ipc.py +0 -0
  329. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_local_sockets.py +0 -0
  330. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_mcp.py +0 -0
  331. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_mcp_install.py +0 -0
  332. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_mcp_instructions.py +0 -0
  333. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_mcp_multi_graph.py +0 -0
  334. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_native_cfamily.py +0 -0
  335. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_native_concurrency.py +0 -0
  336. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_native_rust.py +0 -0
  337. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_nuxt_i18n.py +0 -0
  338. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_nuxt_import_dirs.py +0 -0
  339. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_nuxt_side_dirs.py +0 -0
  340. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_packaging.py +0 -0
  341. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_parity.py +0 -0
  342. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_parity_structure.py +0 -0
  343. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_php_props.py +0 -0
  344. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_plain_js.py +0 -0
  345. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_platform_gaps.py +0 -0
  346. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_platform_type_variants.py +0 -0
  347. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_platforms.py +0 -0
  348. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_platforms_apple.py +0 -0
  349. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_presets_config.py +0 -0
  350. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_process_ipc.py +0 -0
  351. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_process_runs.py +0 -0
  352. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_protocols.py +0 -0
  353. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_python_app_tests_module.py +0 -0
  354. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_python_collection_chains.py +0 -0
  355. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_python_compat.py +0 -0
  356. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_python_entry_refs.py +0 -0
  357. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_python_fields.py +0 -0
  358. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_python_infer_cycles.py +0 -0
  359. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_python_roots.py +0 -0
  360. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_python_subprocess_tests.py +0 -0
  361. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_python_tests.py +0 -0
  362. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_python_web_hosts.py +0 -0
  363. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_python_web_routes.py +0 -0
  364. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_python_web_routes_more.py +0 -0
  365. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_react_router.py +0 -0
  366. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_readers_writers_specs.py +0 -0
  367. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_realtime.py +0 -0
  368. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_realtime_native.py +0 -0
  369. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_redact_salt.py +0 -0
  370. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_roundtrip.py +0 -0
  371. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_route_specs.py +0 -0
  372. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_route_tables.py +0 -0
  373. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_rpc.py +0 -0
  374. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_scip_health.py +0 -0
  375. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_sdk_external.py +0 -0
  376. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_sdk_external_infra.py +0 -0
  377. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_sdk_external_mail.py +0 -0
  378. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_snippet.py +0 -0
  379. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_sockets.py +0 -0
  380. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_spring.py +0 -0
  381. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_ssrf.py +0 -0
  382. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_starters_budget.py +0 -0
  383. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_surface_transport.py +0 -0
  384. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_swift.py +0 -0
  385. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_swift_binding.py +0 -0
  386. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_swift_exact.py +0 -0
  387. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_swift_facts.py +0 -0
  388. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_swift_fields.py +0 -0
  389. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_swift_modules.py +0 -0
  390. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_swift_more.py +0 -0
  391. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_swift_nav_values.py +0 -0
  392. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_swift_parse_errors.py +0 -0
  393. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_swift_props.py +0 -0
  394. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_swift_sdk.py +0 -0
  395. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_swift_testing.py +0 -0
  396. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_swift_values.py +0 -0
  397. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_tests_scope.py +0 -0
  398. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_ts_fields.py +0 -0
  399. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_ts_fields_js_vue.py +0 -0
  400. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_ts_file_specs.py +0 -0
  401. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_ts_frameworks.py +0 -0
  402. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_ts_node_http.py +0 -0
  403. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_ts_src_tsconfig.py +0 -0
  404. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_update_check.py +0 -0
  405. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_viz.py +0 -0
  406. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_vue_nav.py +0 -0
  407. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_watch.py +0 -0
  408. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/tests/test_websockets.py +0 -0
  409. {cg_code_graph-0.23.4 → cg_code_graph-0.23.5}/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.4
3
+ Version: 0.23.5
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.4"
2
+ __version__ = "0.23.5"
@@ -222,11 +222,23 @@ def express_loop_routes(root: Path, files: list[str]) -> dict | None:
222
222
  _PHP_LOOPS = re.compile(r"\b(?:foreach|for|while)\s*\(|->\s*(?:each|map|flatMap|eachSpread)\s*\(|\barray_(?:map|walk)\s*\(")
223
223
 
224
224
 
225
- def laravel_loop_routes(root: Path, files: list[str]) -> dict | None:
226
- """Route::get(...) inside foreach / for / ->each(...) / array_map(...): the URIs come from data, so the Laravel
227
- plugin cannot list them."""
225
+ def laravel_loop_routes(root: Path, files: list[str], builder=None) -> dict | None:
226
+ """Route::get(...) inside foreach / for / ->each(...) / array_map(...) that the Laravel plugin did not unroll.
227
+
228
+ Loops over literal data in route files are unrolled (#184); the plugin records every loop it saw in
229
+ `builder.route_loops` ({file: [{line, end, unrolled, reason}]}). The ones it could not unroll are reported with
230
+ their reason (`iterable not literal`); the regex below still finds loops outside route files."""
228
231
  hits = []
232
+ reasons: dict[str, str] = {}
233
+ known = getattr(builder, "route_loops", None) or {}
234
+ for rel, loops in known.items():
235
+ for lp in loops:
236
+ if not lp.get("unrolled"):
237
+ hits.append((rel, lp["line"]))
238
+ if lp.get("reason"):
239
+ reasons[f"{rel}:{lp['line']}"] = lp["reason"]
229
240
  for rel in files:
241
+ spans = [(lp["line"], lp.get("end") or lp["line"]) for lp in known.get(rel, [])]
230
242
  src = _read(root, rel)
231
243
  if not src or "Route::" not in src:
232
244
  continue
@@ -237,9 +249,17 @@ def laravel_loop_routes(root: Path, files: list[str]) -> dict | None:
237
249
  continue
238
250
  if re.search(r"\bRoute::\s*(?:get|post|put|patch|delete|any|match|resource|apiResource|resources|apiResources|view|redirect)\s*\(",
239
251
  src[b0:b1]):
240
- hits.append((rel, _line(src, start)))
252
+ ln = _line(src, start)
253
+ if not any(lo <= ln <= hi for lo, hi in spans):
254
+ hits.append((rel, ln))
241
255
  done_until = b1
242
- return _finding("laravel_loop_routes", hits)
256
+ out = _finding("laravel_loop_routes", hits)
257
+ if out and reasons:
258
+ out["reasons"] = {k: reasons[k] for k in out["samples"] if k in reasons}
259
+ why = sorted(set(out["reasons"].values()))
260
+ if why:
261
+ out["what"] = f"{out['what']} ({'; '.join(why)})"
262
+ return out
243
263
 
244
264
 
245
265
  # ------------------------------------------------------------------------------------------- Django (AST)
@@ -549,7 +569,7 @@ def detect(root: str | Path, files_by_ext: dict[str, list[str]], builder=None, p
549
569
  run(nuxt_unevaluable_import_dirs, root)
550
570
  run(vue_unresolved_navigation, builder)
551
571
  run(ts_unrecognised_http_client, root, js, builder)
552
- run(laravel_loop_routes, root, php)
572
+ run(laravel_loop_routes, root, php, builder)
553
573
  py = programs.get("python")
554
574
  if py is not None:
555
575
  run(django_dynamic_urlpatterns, [(m.file, m.tree) for m in py.modules.values()])
@@ -826,6 +826,9 @@ def main(argv=None):
826
826
  def _unknown_route(st, spec: str, as_json: bool) -> bool:
827
827
  miss = Q.route_failure(st, spec)
828
828
  if not miss:
829
+ note = Q.route_declared_note(st, spec)
830
+ if note:
831
+ print(note, file=sys.stderr)
829
832
  return False
830
833
  if as_json:
831
834
  print(json.dumps({"error": miss["error"], "spec": miss["spec"], "suggestions": miss["suggestions"]}))
@@ -59,6 +59,9 @@ class GraphBuilder:
59
59
  # Pigeon API definitions found by the Dart plugin ({Api: {kind: host | flutter, methods, file}}): bridges.py
60
60
  # links their native implementations / native callers
61
61
  self.pigeon_apis: dict = {}
62
+ # loops around route registrations in Laravel route files ({file: [{line, end, unrolled, reason}]}, #184):
63
+ # the blind-spot detector reports the ones that were not unrolled
64
+ self.route_loops: dict = {}
62
65
  # keyed-hash salt for the markers that stand in for secret values (cg_code_graph/core/redact.py); the indexer
63
66
  # sets it from the graph DB before any plugin runs
64
67
  self.redact_salt: str | None = None
@@ -11,8 +11,11 @@ graphs (role backend, frontend or both):
11
11
  Matching is deterministic (no guessing):
12
12
  - the client path is the extractor's URL template with the origin (scheme://host or the
13
13
  unknown server-URL placeholder) and query string removed;
14
- - backend URIs are tried as declared and, for routes from routes/api.php, with the `/api`
15
- prefix Laravel adds;
14
+ - backend URIs are tried at the path the server serves them under: a Laravel route of routes/api.php is
15
+ stored with its API prefix (`apiPrefix` in bootstrap/app.php, a RouteServiceProvider group, `api` by
16
+ default) and keeps its declared path in attrs.declared_uri. When no prefix configuration was found
17
+ (the `api` default) the declared path is tried as well, and a route from an older graph without
18
+ declared_uri gets the `/api` + uri variant (see route_uri_variants);
16
19
  - segments match when literal == literal, client placeholder <-> route {param},
17
20
  client literal -> route {param} (resolved), or a client segment with an embedded
18
21
  placeholder fully matches a route literal (heuristic, e.g. export.{format} ~ export.csv);
@@ -39,6 +42,28 @@ from types import SimpleNamespace
39
42
  from .core.model import CONFIDENCE_RANK
40
43
  from .core.store import GraphStore
41
44
 
45
+
46
+ _API_ROUTE_FILE = re.compile(r"(^|/)routes/api(\.php$|/)")
47
+
48
+
49
+ def route_uri_variants(file: str | None, attrs: dict) -> list[tuple[str, str]]:
50
+ """(variant, uri) pairs a route answers to. `file` is the route node's file (with or without a repo prefix).
51
+
52
+ A Laravel route stores the served path (#191): attrs.uri carries the API prefix and attrs.declared_uri the
53
+ path as written. The declared path is also tried when the prefix is Laravel's default rather than read from
54
+ configuration. A route without declared_uri from routes/api.php (an older graph) gets the `/api` variant."""
55
+ uri = attrs.get("uri")
56
+ out = [("as-declared", uri)]
57
+ declared = attrs.get("declared_uri")
58
+ if declared:
59
+ out = [("served", uri)]
60
+ if attrs.get("prefix_from") == "laravel-default" and declared != uri:
61
+ out.append(("declared, without the default /api prefix", declared))
62
+ return out
63
+ if _API_ROUTE_FILE.search(file or "") and uri and not uri.startswith("/api/"):
64
+ out.append(("api-prefixed", "/api" + uri))
65
+ return out
66
+
42
67
  PARAM = re.compile(r"^\{(\w+)(\?)?\}$")
43
68
  CATCH_ALL = re.compile(r"^\{(\w+)\*(\?)?\}$") # {rest*} one or more segments, {rest*?} zero or more (TS routers, Next.js)
44
69
  PH = re.compile(r"\{[^{}]*\}")
@@ -401,9 +426,7 @@ def link_many(repos: list[tuple[str, str, str]], out_db: str, *, allow: dict | N
401
426
  uri, method = a.get("uri"), a.get("method")
402
427
  if not uri or not method:
403
428
  continue
404
- uris = [("as-declared", uri)]
405
- if (r[1] or "").startswith("routes/api.php") or (r[1] or "").startswith("routes/api/"):
406
- uris.append(("api-prefixed", "/api" + uri))
429
+ uris = route_uri_variants(r[1], a)
407
430
  routes.append({"id": mid(name, r[0]), "uri": uri, "method": method, "uris": uris, "server": name,
408
431
  "file": f"{name}/{r[1]}" if r[1] else None, "line": r[3],
409
432
  "attrs": dict(a, _file=r[1], _line=r[3])})
@@ -21,6 +21,7 @@ from . import presets
21
21
  from . import query as Q
22
22
  from .core.model import PROPAGATING
23
23
  from .core.store import GraphStore
24
+ from .link import route_uri_variants
24
25
 
25
26
  PLAN_VERSION = 1
26
27
  STATUSES = ("draft", "agreed", "in_progress", "implemented", "abandoned")
@@ -419,10 +420,8 @@ class Ctx:
419
420
  a = json.loads(r["attrs"] or "{}")
420
421
  if not a.get("uri") or not a.get("method"):
421
422
  continue
422
- uris = [("as-declared", a["uri"])]
423
423
  f = (r["file"] or "").split("/", 1)[-1] if self.combined else (r["file"] or "")
424
- if f.startswith("routes/api"):
425
- uris.append(("api-prefixed", "/api" + a["uri"]))
424
+ uris = route_uri_variants(f, a)
426
425
  out.append({"id": r["id"], "uri": a["uri"], "method": a["method"], "uris": uris, "file": r["file"], "line": r["line"]})
427
426
  return out
428
427
 
@@ -796,10 +795,8 @@ def snapshot_clients(st, route_ids, root: str | Path | None = None) -> list[dict
796
795
  a = json.loads(r["attrs"] or "{}")
797
796
  if not a.get("uri") or not a.get("method"):
798
797
  continue
799
- uris = [("as-declared", a["uri"])]
800
798
  rf = (r["file"] or "").split("/", 1)[-1] if combined else (r["file"] or "")
801
- if rf.startswith("routes/api"):
802
- uris.append(("api-prefixed", "/api" + a["uri"]))
799
+ uris = route_uri_variants(rf, a)
803
800
  routes.append({"id": r["id"], "uri": a["uri"], "method": a["method"], "uris": uris,
804
801
  "file": r["file"], "line": r["line"]})
805
802
  hit = [m["route"] for m in match_endpoint(c.get("method") or "GET", base + c["path"], routes)["matched"]
@@ -180,6 +180,7 @@ class LaravelPlugin(FrameworkPlugin):
180
180
  self.observers, self.listeners, self.schedules, self.bindings = [], [], [], []
181
181
  self.seen_cols = set()
182
182
  self.records = {r["file"]: r for r in prog.records}
183
+ self._apply_route_mounts()
183
184
  self._parse_config()
184
185
  self._parse_migrations()
185
186
  self._parse_models()
@@ -196,6 +197,40 @@ class LaravelPlugin(FrameworkPlugin):
196
197
  self.tests = LaravelTests(self, prog)
197
198
  prog.test_fact_handlers.append(self.tests.handle_fact)
198
199
 
200
+ # ---- route files: served path (#191)
201
+ def _route_mounts(self) -> dict[str, tuple[str, str]]:
202
+ """routes file -> (prefix, where it comes from): `withRouting(api:, apiPrefix:)` / `then:` groups in
203
+ bootstrap/app.php, `Route::prefix(..)->group(base_path(..))` in a (Laravel <= 10) RouteServiceProvider."""
204
+ out: dict[str, tuple[str, str]] = {}
205
+ order = sorted(self.records, key=lambda f: (not f.startswith("bootstrap/"), f))
206
+ for f in order:
207
+ for m in self.records[f].get("route_mounts") or []:
208
+ rf = m.get("file")
209
+ if isinstance(rf, str) and rf not in out and isinstance(m.get("prefix"), str):
210
+ out[rf] = (m["prefix"].strip("/"), f)
211
+ return out
212
+
213
+ def _apply_route_mounts(self):
214
+ """Every route of routes/api.php (and routes/api/) is stored at the path Laravel serves it under: the configured
215
+ API prefix, `api` when nothing configures it. The declared path stays in `declared_uri`."""
216
+ mounts = self._route_mounts()
217
+ for f, r in self.records.items():
218
+ if not f.startswith("routes/") or not r.get("routes"):
219
+ continue
220
+ hit = mounts.get(f)
221
+ if hit is None and f.startswith("routes/api/"):
222
+ hit = mounts.get("routes/api.php")
223
+ if hit is None and (f == "routes/api.php" or f.startswith("routes/api/")):
224
+ hit = ("api", "laravel-default")
225
+ if hit is None or not hit[0]:
226
+ continue
227
+ prefix, src = hit
228
+ for rt in r["routes"]:
229
+ declared = rt.get("full_uri") or "/"
230
+ rt["declared_uri"] = declared
231
+ rt["full_uri"] = "/" + "/".join(p for p in (prefix.strip("/"), declared.strip("/")) if p)
232
+ rt["prefix_from"] = src
233
+
199
234
  # ---- config/*.php
200
235
  def _parse_config(self):
201
236
  b = self.b
@@ -916,13 +951,20 @@ class LaravelPlugin(FrameworkPlugin):
916
951
  cid = self.b.add_node("config", key, lang="php")
917
952
  self.b.add_edge(fn.id, cid, "READS_CONFIG", fn.file, line, conf)
918
953
 
954
+ def _recv_of(self, c, h) -> dict:
955
+ """attrs.recv for an edge into a job's handle() inherited from a base class: the job class, so the base
956
+ handle()'s `$this->execute()` reaches only this job's override (#148)."""
957
+ if c.methods.get("handle") is h or c.methods.get("__invoke") is h:
958
+ return {}
959
+ return {"recv": [f"{c.kind}:{c.fqcn}"]}
960
+
919
961
  def _dispatch(self, fn, cls, line, conf):
920
962
  c = self.prog.cls(cls)
921
963
  if not c:
922
964
  return
923
965
  h = self.prog.find_method(c.fqcn, "handle") or self.prog.find_method(c.fqcn, "__invoke")
924
966
  if self._is_job(c.fqcn) and h:
925
- self.b.add_edge(fn.id, h.id, "DISPATCHES", fn.file, line, conf, via="job")
967
+ self.b.add_edge(fn.id, h.id, "DISPATCHES", fn.file, line, conf, via="job", **self._recv_of(c, h))
926
968
  else:
927
969
  eid = self.b.add_node("event", c.fqcn, name=c.fqcn.split("\\")[-1], fqn=c.fqcn, file=c.file, line=c.line,
928
970
  module=module_of(c.file), lang="php")
@@ -1011,6 +1053,8 @@ class LaravelPlugin(FrameworkPlugin):
1011
1053
  from ..php.inline_guards import for_action
1012
1054
  n = 0
1013
1055
  for f, r in self.records.items():
1056
+ if r.get("route_loops"):
1057
+ b.route_loops[f] = r["route_loops"]
1014
1058
  for rt in r.get("routes") or []:
1015
1059
  for verb in rt["methods"]:
1016
1060
  key = f"{verb.upper()} {rt['full_uri']}"
@@ -1021,6 +1065,15 @@ class LaravelPlugin(FrameworkPlugin):
1021
1065
  self.stats["route_middleware_unresolved"] = self.stats.get("route_middleware_unresolved", 0) + 1
1022
1066
  attrs = {"name": rt.get("name") or None, "middleware": mws if rt.get("middleware") is not None else None,
1023
1067
  "uri": rt["full_uri"], "method": verb.upper()}
1068
+ if rt.get("declared_uri"):
1069
+ attrs["declared_uri"] = rt["declared_uri"]
1070
+ attrs["prefix_from"] = rt.get("prefix_from")
1071
+ for k, ak in (("defaults", "defaults"), ("wheres", "where")):
1072
+ if rt.get(k):
1073
+ attrs[ak] = rt[k]
1074
+ if rt.get("unrolled_from"):
1075
+ u = rt["unrolled_from"]
1076
+ attrs["unrolled_from"] = {"file": f, "line": u.get("line"), "binding": u.get("binding") or {}}
1024
1077
  if rt.get("webhook_client"):
1025
1078
  attrs["webhook_client"] = rt["webhook_client"]
1026
1079
  attrs["webhook_framework"] = "laravel-webhook-client"
@@ -1197,7 +1250,7 @@ class LaravelPlugin(FrameworkPlugin):
1197
1250
  if h:
1198
1251
  jid = b.add_node("job", c.fqcn, name=c.fqcn.split("\\")[-1], fqn=c.fqcn, file=c.file, line=c.line,
1199
1252
  module=module_of(c.file), lang="php", entry_kind="queue_job")
1200
- b.add_edge(jid, h.id, "HANDLED_BY", c.file, h.line, EXACT)
1253
+ b.add_edge(jid, h.id, "HANDLED_BY", c.file, h.line, EXACT, **self._recv_of(c, h))
1201
1254
  self.stats["jobs"] += 1
1202
1255
  if c.fqcn.startswith("App\\Listeners\\"):
1203
1256
  h = prog.find_method(c.fqcn, "handle")
@@ -7,8 +7,8 @@
7
7
  TEST_CALLS -> the file (beforeEach, uses(...) and other file-level setup);
8
8
  * HTTP test calls (`$this->getJson('/api/x')`, `->actingAs($u)->post(route('x.store'))`, Pest `get('/x')`,
9
9
  `$this->json('PATCH', '/x')`, and the same calls through project helpers such as `$this->getAs('/x')` whose URL /
10
- verb are parameters) -> TEST_HTTP -> the matching route (URIs matched like cross-repo links, with the
11
- `/api` prefix Laravel adds to routes/api.php; `route('name')` by route name).
10
+ verb are parameters) -> TEST_HTTP -> the matching route (URIs matched like cross-repo links, on the served path: routes/api.php routes
11
+ carry the API prefix Laravel adds; `route('name')` by route name).
12
12
 
13
13
  Edges made by test code are retyped to non-propagating TEST_* kinds afterwards (cg_code_graph/tests_index.py), so
14
14
  tests never change blast radius, caller counts or entry tagging. `cg tests <symbol|route>` walks them on purpose.
@@ -154,7 +154,7 @@ class LaravelTests:
154
154
 
155
155
  # ---- after reference emission
156
156
  def contribute(self) -> dict:
157
- from ...link import match_endpoint
157
+ from ...link import match_endpoint, route_uri_variants
158
158
  b, prog = self.lp.b, self.prog
159
159
  st = defaultdict(int)
160
160
  self._expand_helpers(st)
@@ -162,9 +162,7 @@ class LaravelTests:
162
162
  for nid, n in b.nodes.items():
163
163
  if n.kind != "route" or not n.attrs.get("uri") or not n.attrs.get("method"):
164
164
  continue
165
- uris = [("as-declared", n.attrs["uri"])]
166
- if (n.file or "").startswith(("routes/api.php", "routes/api/")):
167
- uris.append(("api-prefixed", "/api" + n.attrs["uri"]))
165
+ uris = route_uri_variants(n.file, n.attrs)
168
166
  routes.append({"id": nid, "uri": n.attrs["uri"], "method": n.attrs["method"], "uris": uris})
169
167
  if n.attrs.get("name"):
170
168
  by_name[n.attrs["name"]].append(n)
@@ -18,6 +18,7 @@ contribute: file-based routing (route path per page), entry points (pages = ui_p
18
18
  from __future__ import annotations
19
19
 
20
20
  import atexit
21
+ from collections import defaultdict
21
22
  import json
22
23
  import re
23
24
  import shutil
@@ -98,10 +99,30 @@ _SIDE_SKIP = re.compile(r"\.(test|spec)\.[cm]?[jt]sx?$|\.d\.ts$")
98
99
 
99
100
  def side_dirs(root: Path, src_dir: str) -> list[str]:
100
101
  """Root-level server/ and shared/ of a Nuxt project whose srcDir is not the root (with a root srcDir they are
101
- already inside it; Nuxt 3's src/server sits inside a src/ srcDir)."""
102
+ already inside it; Nuxt 3's src/server sits inside a src/ srcDir), and the server/ dirs of local layers."""
102
103
  if src_dir in ("", "."):
103
104
  return []
104
- return [d for d in SIDE_DIRS if (root / d).is_dir()]
105
+ return [d for d in SIDE_DIRS if (root / d).is_dir()] + layer_server_dirs(root, src_dir)
106
+
107
+
108
+ def layer_server_dirs(root: Path, src_dir: str | None = None) -> list[str]:
109
+ """server/ dirs of local layers (#217): `extends: ['./layers/admin']` and the auto-registered layers/*/."""
110
+ out: list[str] = []
111
+ try:
112
+ plan_layers = nuxt_import_plan(root, src_dir)["layers"][1:]
113
+ except Exception: # noqa: BLE001 (a config the scanner cannot read: no extends)
114
+ plan_layers = []
115
+ cands = [ly["dir"] for ly in plan_layers]
116
+ if (root / "layers").is_dir():
117
+ cands += sorted(d for d in (root / "layers").iterdir() if d.is_dir())
118
+ for d in cands:
119
+ try:
120
+ rel = d.resolve().relative_to(root.resolve()).as_posix()
121
+ except ValueError:
122
+ continue
123
+ if rel and rel != "." and (root / rel / "server").is_dir() and f"{rel}/server" not in out:
124
+ out.append(f"{rel}/server")
125
+ return out
105
126
 
106
127
 
107
128
  def side_files(root: Path, dirs: list[str]) -> list[str]:
@@ -895,6 +916,83 @@ def nitro_route(rel: str, prefix: str = "") -> tuple[str, str] | None:
895
916
  return method, "/" + "/".join(s.strip("/") for s in [prefix.strip("/")] + segs if s.strip("/"))
896
917
 
897
918
 
919
+ _OBJ_HOOK = re.compile(r"\b(onRequest|onBeforeResponse)\s*:\s*(\[[^\]]*\]|[A-Za-z_$][\w$]*|\(|async\b|function\b)")
920
+ _OBJ_HANDLER_REF = re.compile(r"\bhandler\s*:\s*([A-Za-z_$][\w$]*)\s*[,}\n]")
921
+ _PATH_GUARD = re.compile(r"if\s*\(\s*!\s*(?:event\.path|event\.node\.req\.url|getRequestURL\(\s*event\s*\)\.pathname)"
922
+ r"(?:\?)?\.startsWith\(\s*['\"`]([^'\"`]+)['\"`]\s*\)\s*\)\s*\{?\s*return\b")
923
+
924
+
925
+ def object_hooks(src: str) -> tuple[list[tuple[str, str]], str | None]:
926
+ """`defineEventHandler({ onRequest: [auth], onBeforeResponse: fn, handler })` (#217): [(hook, name)] where name is
927
+ an identifier or `<inline>`, and the identifier given as `handler` (None when it is an inline function)."""
928
+ i = src.find("defineEventHandler(")
929
+ if i < 0:
930
+ return [], None
931
+ j = i + len("defineEventHandler(")
932
+ while j < len(src) and src[j] in " \t\r\n":
933
+ j += 1
934
+ if j >= len(src) or src[j] != "{":
935
+ return [], None
936
+ body = src[j:]
937
+ hooks = []
938
+ for m in _OBJ_HOOK.finditer(body):
939
+ hook, val = m.group(1), m.group(2)
940
+ if val.startswith("["):
941
+ for name in re.findall(r"[A-Za-z_$][\w$]*", val[1:-1]):
942
+ hooks.append((hook, name))
943
+ elif val in ("(", "async", "function"):
944
+ hooks.append((hook, "<inline>"))
945
+ else:
946
+ hooks.append((hook, val))
947
+ ref = _OBJ_HANDLER_REF.search(body)
948
+ return hooks, ref.group(1) if ref and ref.group(1) not in ("async", "function") else None
949
+
950
+
951
+ def path_guard(src: str) -> str | None:
952
+ """Prefix of `if (!event.path.startsWith('/api/admin')) return` at the top of a Nitro middleware (#217)."""
953
+ m = _PATH_GUARD.search(src)
954
+ return m.group(1) if m else None
955
+
956
+
957
+ def rule_covers(pattern: str, uri: str) -> bool:
958
+ """Nitro routeRules pattern (`/api/legacy/**`, `/blog/*`, exact) against a route uri with {param} segments."""
959
+ pat = pattern.rstrip("/") or "/"
960
+ if pat.endswith("/**"):
961
+ base = pat[:-3]
962
+ return uri == base or uri.startswith(base + "/")
963
+ ps, us = pat.strip("/").split("/"), uri.strip("/").split("/")
964
+ if len(ps) != len(us):
965
+ return False
966
+ return all(p == "*" or p == u or (u.startswith("{") and p.startswith(":")) for p, u in zip(ps, us))
967
+
968
+
969
+ def config_handlers(cfg: dict) -> list[dict]:
970
+ """`serverHandlers` and `nitro.handlers` entries of a parsed nuxt.config: [{route, method, handler, middleware}]."""
971
+ out = []
972
+ nitro = cfg.get("nitro") if isinstance(cfg.get("nitro"), dict) else {}
973
+ for where, items in (("serverHandlers", cfg.get("serverHandlers")), ("nitro.handlers", nitro.get("handlers"))):
974
+ for it in items if isinstance(items, list) else []:
975
+ if not isinstance(it, dict) or not isinstance(it.get("handler"), str):
976
+ continue
977
+ out.append({"route": it.get("route") if isinstance(it.get("route"), str) else None,
978
+ "method": it.get("method") if isinstance(it.get("method"), str) else None,
979
+ "handler": it["handler"], "middleware": it.get("middleware") is True, "from": where})
980
+ return out
981
+
982
+
983
+ def proxy_rules(cfg: dict) -> dict[str, str]:
984
+ """routeRules / nitro.routeRules patterns with a `proxy` -> proxy target (or '?' when not a literal)."""
985
+ out = {}
986
+ nitro = cfg.get("nitro") if isinstance(cfg.get("nitro"), dict) else {}
987
+ for rules in (cfg.get("routeRules"), nitro.get("routeRules")):
988
+ for pat, rule in (rules.items() if isinstance(rules, dict) else ()):
989
+ if isinstance(rule, dict) and "proxy" in rule:
990
+ p = rule["proxy"]
991
+ target = p if isinstance(p, str) else (p.get("to") if isinstance(p, dict) and isinstance(p.get("to"), str) else "?")
992
+ out[pat] = target
993
+ return out
994
+
995
+
898
996
  def server_dirs(root: Path, src_dir: str) -> list[str]:
899
997
  """Nitro server dirs of a Nuxt project: the root server/ (Nuxt 4 serverDir) and <srcDir>/server (Nuxt 3)."""
900
998
  cands = ["server"] + ([] if src_dir in ("", ".") else [f"{src_dir.strip('/')}/server"])
@@ -1185,11 +1283,29 @@ class NuxtPlugin(FrameworkPlugin):
1185
1283
  def _nitro(self, project: Project, b: GraphBuilder) -> dict:
1186
1284
  from ..tsweb.common import add_route
1187
1285
  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:
1286
+ self._mod_refs = None
1287
+ root = project.root
1288
+ dirs = server_dirs(root, self.src_dir)
1289
+ layer_dirs = [d for d in layer_server_dirs(root, self.src_dir) if d not in dirs]
1290
+ cfg_path = _config_path(root)
1291
+ cfg = {}
1292
+ if cfg_path:
1293
+ try:
1294
+ cfg = _find_config_object(cfg_path.read_text(errors="replace"))
1295
+ except Exception: # noqa: BLE001
1296
+ cfg = {}
1297
+ cfg_handlers = config_handlers(cfg)
1298
+ if not dirs and not layer_dirs and not cfg_handlers:
1190
1299
  return st
1300
+ dirs = dirs + layer_dirs
1191
1301
  files = sorted({n.file for n in b.nodes.values() if n.lang == "ts" and n.kind == "module" and n.file})
1192
1302
 
1303
+ def read(f: str) -> str:
1304
+ try:
1305
+ return (root / f).read_text(errors="replace")
1306
+ except OSError:
1307
+ return ""
1308
+
1193
1309
  def handler(f: str) -> tuple[str | None, str]:
1194
1310
  for nid in (f"function:{f}#default", f"function:{f}#handler"):
1195
1311
  if b.has(nid):
@@ -1212,7 +1328,7 @@ class NuxtPlugin(FrameworkPlugin):
1212
1328
  h, _c = handler(f)
1213
1329
  if h:
1214
1330
  label(f, "middleware")
1215
- middleware.append((h, f"nitro:{_NITRO_EXT.sub('', inner)}", "resolved"))
1331
+ middleware.append((h, f"nitro:{_NITRO_EXT.sub('', inner)}", "resolved", path_guard(read(f))))
1216
1332
  st["middleware"] += 1
1217
1333
  elif top == "plugins" and inner and nitro_route(inner) is not None:
1218
1334
  h, _c = handler(f)
@@ -1224,25 +1340,105 @@ class NuxtPlugin(FrameworkPlugin):
1224
1340
  r = nitro_route(inner, "/api" if top == "api" else "")
1225
1341
  if r:
1226
1342
  routes.append((f, top, r))
1343
+ # nuxt.config serverHandlers / nitro.handlers: { route, method, handler: '~~/server/handlers/x.ts' }
1344
+ for ch in cfg_handlers:
1345
+ hf = self._config_handler_file(root, ch["handler"], set(files))
1346
+ if not hf:
1347
+ st["config_handlers_unresolved"] = st.get("config_handlers_unresolved", 0) + 1
1348
+ continue
1349
+ if ch["middleware"] or not ch["route"]:
1350
+ h, _c = handler(hf)
1351
+ if h:
1352
+ label(hf, "middleware")
1353
+ middleware.append((h, f"nitro:{ch['handler']}", "resolved", path_guard(read(hf))))
1354
+ st["middleware"] += 1
1355
+ continue
1356
+ method = (ch["method"] or "ANY").upper()
1357
+ uri = re.sub(r":(\w+)", r"{\1}", "/" + ch["route"].strip("/"))
1358
+ routes.append((hf, ch["from"], (method, uri)))
1359
+ rules = proxy_rules(cfg)
1360
+
1361
+ def scoped(uri: str) -> list[tuple]:
1362
+ out = []
1363
+ for m in middleware:
1364
+ prefix = m[3] if len(m) > 3 else None
1365
+ if prefix is None:
1366
+ out.append(m[:3])
1367
+ elif uri == prefix.rstrip("/") or uri.startswith(prefix.rstrip("/") + "/"):
1368
+ out.append((m[0], m[1], "heuristic")) # early return outside the prefix (#217)
1369
+ return out
1370
+
1227
1371
  for f, top, (method, uri) in routes:
1228
1372
  h, conf = handler(f)
1373
+ src = read(f)
1374
+ hooks, ref = object_hooks(src)
1375
+ if ref and b.has(f"function:{f}#{ref}"):
1376
+ h, conf = f"function:{f}#{ref}", "exact"
1229
1377
  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 = ""
1378
+ attrs = {"file_route": top in ("api", "routes"), "nitro_dir": top,
1379
+ "method_from": ("file suffix" if top in ("api", "routes") else "config") if method != "ANY" else "any"}
1380
+ if top not in ("api", "routes"):
1381
+ attrs["registered_in"] = top
1235
1382
  if _PROXY_CALL.search(src):
1236
1383
  attrs["proxy"] = True
1384
+ for pat, target in rules.items():
1385
+ if rule_covers(pat, uri):
1386
+ attrs["proxy"] = True
1387
+ attrs["proxy_rule"] = pat
1388
+ if target != "?":
1389
+ attrs["proxy_target"] = target
1390
+ break
1391
+ if attrs.get("proxy"):
1237
1392
  st["proxy_routes"] += 1
1238
1393
  if not h or h.startswith("module:"):
1239
1394
  attrs["handler_unresolved"] = True
1240
- add_route(b, method, uri, [h] if h else [], f, line, "nuxt", conf, attrs, middleware)
1395
+ mws = scoped(uri)
1396
+ for hook, name in hooks:
1397
+ nid = self._hook_node(b, f, hook, name)
1398
+ if nid:
1399
+ mws.append((nid, f"{hook}:{name if name != '<inline>' else 'inline'}", "exact"))
1400
+ add_route(b, method, uri, [h] if h else [], f, line, "nuxt", conf, attrs, mws)
1241
1401
  label(f, "route")
1242
1402
  st["routes"] += 1
1243
1403
  st["linked_calls"] = self._link_nitro(b)
1244
1404
  return st
1245
1405
 
1406
+ def _config_handler_file(self, root: Path, spec: str, files: set[str]) -> str | None:
1407
+ """A nuxt.config handler path (`~~/server/x.ts`, `~/server/x`, `./server/x.ts`) -> indexed file."""
1408
+ s = spec.strip()
1409
+ src = self.src_dir.strip("/") if self.src_dir not in ("", ".") else ""
1410
+ bases = []
1411
+ for alias, base in (("~~/", ""), ("@@/", ""), ("~/", src), ("@/", src), ("./", ""), ("/", "")):
1412
+ if s.startswith(alias):
1413
+ bases = [base, ""] if base else [""]
1414
+ s = s[len(alias):]
1415
+ break
1416
+ else:
1417
+ bases = [""]
1418
+ for base in bases:
1419
+ stem = f"{base}/{s}" if base else s
1420
+ for cand in [stem] + [stem + ext for ext in (".ts", ".js", ".mjs", ".mts")] + [f"{stem}/index.ts"]:
1421
+ if cand in files:
1422
+ return cand
1423
+ return None
1424
+
1425
+ def _hook_node(self, b: GraphBuilder, f: str, hook: str, name: str) -> str | None:
1426
+ """onRequest / onBeforeResponse function of an object-form handler: inline, local, or an imported function."""
1427
+ local = f"function:{f}#{hook if name == '<inline>' else name}"
1428
+ if b.has(local):
1429
+ return local
1430
+ if name == "<inline>":
1431
+ return None
1432
+ if getattr(self, "_mod_refs", None) is None:
1433
+ self._mod_refs = defaultdict(list)
1434
+ for e in b.edges.values():
1435
+ if e.kind in ("CALLS", "REFERENCES") and e.src.startswith("module:"):
1436
+ self._mod_refs[e.src].append(e.dst)
1437
+ for dst in self._mod_refs.get(f"module:{f}", ()):
1438
+ if dst.endswith(f"#{name}") and b.has(dst):
1439
+ return dst
1440
+ return None
1441
+
1246
1442
  def _link_nitro(self, b: GraphBuilder) -> int:
1247
1443
  """Same-origin client calls of this app (relative URLs: `$fetch('/api/x')`, `useFetch`) -> its Nitro routes.
1248
1444
  Proxy routes (proxyRequest / sendProxy) forward elsewhere and are not link targets."""