cg-code-graph 0.23.3__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.
- {cg_code_graph-0.23.3/cg_code_graph.egg-info → cg_code_graph-0.23.5}/PKG-INFO +1 -1
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/__init__.py +1 -1
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/blindspots.py +26 -6
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/cli.py +3 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/core/plugin.py +3 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/link.py +28 -5
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/mcp_server.py +2 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plans.py +3 -6
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/platforms.py +1 -1
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/laravel/plugin.py +55 -2
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/laravel/tests.py +4 -6
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/nuxt/plugin.py +207 -11
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/extractor/extract.php +329 -2
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/plugin.py +11 -1
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/swift/plugin.py +24 -12
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/query.py +167 -10
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/routes.py +56 -3
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/webhook_subs.py +2 -3
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5/cg_code_graph.egg-info}/PKG-INFO +1 -1
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph.egg-info/SOURCES.txt +3 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_channels_tests.py +4 -4
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_external.py +1 -1
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_fp_batch.py +8 -8
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_inline_guards.py +65 -65
- cg_code_graph-0.23.5/tests/test_issue_219.py +125 -0
- cg_code_graph-0.23.5/tests/test_laravel_receiver_narrowing.py +130 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_laravel_resources.py +1 -1
- cg_code_graph-0.23.5/tests/test_laravel_route_paths.py +279 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_mass_assignment.py +1 -1
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_mcp_index.py +2 -2
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_nuxt_nitro.py +54 -2
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_nuxt_rootsrc.py +2 -2
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_php_http.py +2 -2
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_plans.py +3 -3
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_request_keys.py +8 -8
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_routes_search_explain.py +14 -14
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_surface.py +5 -5
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_ts_nuxt.py +2 -2
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_unguarded.py +10 -10
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_values.py +1 -1
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_webhooks.py +5 -5
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_webhooks_152.py +10 -10
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_webhooks_152b.py +8 -8
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/LICENSE +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/MANIFEST.in +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/README.md +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/__main__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/affected.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/agent_rules.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/agents.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/aitools.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/android_ipc.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/apple_ipc.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/apps.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/bridges.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/brokers.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/concepts.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/config.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/core/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/core/cache.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/core/detect.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/core/env.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/core/extractors.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/core/fsutil.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/core/generated.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/core/model.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/core/paths.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/core/redact.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/core/store.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/core/syntax_errors.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/coverage.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/dart_isolates.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/doctor.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/explore.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/external.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/graphql.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/guard_facts.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/hooks.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/indexer.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/insecure_transport.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/install_rules.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/jobs.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/lint_async.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/local_ipc.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/local_sockets.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/mcp_graphs.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/mcp_install.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/parity.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/parity_structure.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/payload.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/platform_scan.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/astro/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/astro/content.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/astro/plugin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/cfamily/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/cfamily/plugin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/cfamily/syntax.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/bridges.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/extractor/bin/extract.dart +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/extractor/pubspec.lock +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/extractor/pubspec.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/http.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/models.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/plugin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/dart/program.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/django/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/django/extras.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/django/models.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/django/plugin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/django/schemas.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/django/shapes.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/django/urls.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/express/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/express/plugin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/flutter/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/flutter/plugin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/java/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/java/exact.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/java/plugin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/jvm/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/jvm/interop.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/jvm/spring.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/kotlin/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/kotlin/exact.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/kotlin/plugin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/kotlin/reparse.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/laravel/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/laravel/broadcast.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/laravel/massassign.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/laravel/values.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/native/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/native/gates.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/native/runner.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/native/scipread.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/native/ts.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/nest/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/nest/plugin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/nextjs/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/nextjs/plugin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/nuxt/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/external.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/extractor/composer.json +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/extractor/composer.lock +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/gating.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/http_client.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/inline_guards.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/php/strings.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/aitools.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/external.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/fields.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/plugin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/refs.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/roots.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/socketio.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/subproc.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/tests.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/python/values.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/pyweb/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/pyweb/plugin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/pyweb/values.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/rust/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/rust/cargo.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/rust/plugin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/rust/syntax.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/scip/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/scip/importer.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/scip/scip.proto +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/scip/scip_pb2.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/stubs/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/stubs/plugins.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/swift/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/swift/baseurl.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/swift/exact.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/swift/indexstore.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/swift/packages.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/baseurl.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/extractor/extract.mjs +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/extractor/fw.mjs +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/extractor/package-lock.json +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/extractor/package.json +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/extractor/rr.mjs +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/nav.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/plugin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/ts/react_router.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/tsweb/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/tsweb/common.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/plugins/tsweb/data.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/c_cpp.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/common.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/dart.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/django-ninja.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/django.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/djangorestframework.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/express.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/java.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/kotlin.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/laravel.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/nest.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/nextjs.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/nuxt.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/php.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/python.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/react-router.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/rust.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/spring.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/swift.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/presets/typescript.yaml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/process_runs.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/protocols/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/protocols/builtin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/protocols/matchers.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/protocols/view.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/realtime.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/realtime_events.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/realtime_native.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/realtime_ws.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/roundtrip.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/rpc.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/sdk_systems.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/sockets.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/ssrf_input.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/starters.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/surface.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/tests_index.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/udp_apps.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/update_check.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/__init__.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/graph.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/server.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/app.css +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/app.js +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/index.html +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/layered.js +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/vendor/VERSIONS.txt +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/vendor/cose-base.js +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/vendor/cytoscape-fcose.js +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/vendor/cytoscape.min.js +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/static/vendor/layout-base.js +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/tools/package-lock.json +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/tools/package.json +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/viz/tools/shoot.mjs +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/watch.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/webhooks.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph/xcode.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph.egg-info/dependency_links.txt +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph.egg-info/entry_points.txt +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph.egg-info/requires.txt +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/cg_code_graph.egg-info/top_level.txt +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/pyproject.toml +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/setup.cfg +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_affected.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_agents_install.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_agents_md.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_ai_tools.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_android_ipc.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_apple_ipc.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_astro.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_astro_content.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_astro_server.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_bridges.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_bridges_pigeon_monorepo.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_brokers.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_cache_clean.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_cache_invalidation.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_cache_migration.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_cli_output.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_completeness.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_config_extras.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_coverage.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_coverage_ts_hint.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_dart_isolates.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_db_connections.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_dead_wrappers.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_dispatch_interfaces.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_django_flutter.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_docs_languages.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_docs_links.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_echo_ref.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_echo_wrapper.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_elysia.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_enum_constants.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_env.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_explore.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_gating.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_generated.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_graphql.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_hooks.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_impact_overrides.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_index_isolation.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_inherited_overrides.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_install_rules.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_issue_192.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_issue_201.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_issue_202.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_issue_203.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_issue_204.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_issue_205.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_issue_206.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_issue_207.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_issue_208.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_issue_209.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_issue_210.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_issue_211.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_issue_211_used_at.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_issue_212.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_java.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_java_exact.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_jobs.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_js_refs.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_js_runtime.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_kotlin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_kotlin_binding.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_kotlin_exact.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_kotlin_fields.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_kotlin_mixed.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_kotlin_nav_consts.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_kotlin_props.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_laravel_determinism.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_link_origin.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_lint_async.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_listing_files.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_local_ipc.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_local_sockets.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_mcp.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_mcp_install.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_mcp_instructions.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_mcp_multi_graph.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_native_cfamily.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_native_concurrency.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_native_rust.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_nuxt_i18n.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_nuxt_import_dirs.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_nuxt_side_dirs.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_packaging.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_parity.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_parity_structure.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_php_props.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_plain_js.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_platform_gaps.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_platform_type_variants.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_platforms.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_platforms_apple.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_presets_config.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_process_ipc.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_process_runs.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_protocols.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_python_app_tests_module.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_python_collection_chains.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_python_compat.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_python_entry_refs.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_python_fields.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_python_infer_cycles.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_python_roots.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_python_subprocess_tests.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_python_tests.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_python_web_hosts.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_python_web_routes.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_python_web_routes_more.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_react_router.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_readers_writers_specs.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_realtime.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_realtime_native.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_redact_salt.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_roundtrip.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_route_specs.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_route_tables.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_rpc.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_scip_health.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_sdk_external.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_sdk_external_infra.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_sdk_external_mail.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_snippet.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_sockets.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_spring.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_ssrf.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_starters_budget.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_surface_transport.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_swift.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_swift_binding.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_swift_exact.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_swift_facts.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_swift_fields.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_swift_modules.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_swift_more.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_swift_nav_values.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_swift_parse_errors.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_swift_props.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_swift_sdk.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_swift_testing.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_swift_values.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_tests_scope.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_ts_fields.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_ts_fields_js_vue.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_ts_file_specs.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_ts_frameworks.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_ts_node_http.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_ts_src_tsconfig.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_update_check.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_viz.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_vue_nav.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_watch.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_websockets.py +0 -0
- {cg_code_graph-0.23.3 → cg_code_graph-0.23.5}/tests/test_workspace_link.py +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""code-graph: deterministic code knowledge graph (beta)."""
|
|
2
|
-
__version__ = "0.23.
|
|
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(...)
|
|
227
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
15
|
-
prefix
|
|
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 = [
|
|
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])})
|
|
@@ -785,6 +785,8 @@ def _prop_lines(rows: list, limit: int) -> list[str]:
|
|
|
785
785
|
for r in rows[:limit]:
|
|
786
786
|
a = r.get("attrs") or {}
|
|
787
787
|
ex = " ".join(f"{k}={a[k]}" for k in ("receiver", "accessor", "storage") if k in a)
|
|
788
|
+
if a.get("variant_platforms"): # one of a property's per-platform declarations (#219)
|
|
789
|
+
ex = f"{ex} platforms={','.join(a['variant_platforms'])}".strip()
|
|
788
790
|
ek = ",".join(sorted(r["entry_kinds"])) or "-"
|
|
789
791
|
out.append(f" {'[test] ' if r.get('test') else ''}{r['fqn']} @{os.path.basename(r['file'] or '?')}:{r['line']}"
|
|
790
792
|
f" {ex} entries: {ek}")
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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"]
|
|
@@ -995,7 +995,7 @@ def _alt_groups(builder, nvals: dict) -> dict[str, list[str]]:
|
|
|
995
995
|
"""Rust / C / C++ / Swift alternative definitions of one symbol (one per `cfg` / `#if` branch), keyed by _vkey."""
|
|
996
996
|
alts: dict[str, list[str]] = defaultdict(list)
|
|
997
997
|
for nid, n in builder.nodes.items():
|
|
998
|
-
if n.lang in ("rust", "c", "cpp", "swift") and n.kind in ALT_KINDS:
|
|
998
|
+
if n.lang in ("rust", "c", "cpp", "swift") and n.kind in ALT_KINDS or n.lang == "swift" and n.kind == "field":
|
|
999
999
|
alts[_vkey(nid, n, nvals)].append(nid)
|
|
1000
1000
|
# a static C function and a macro / function of the same name visible in its file are variants too
|
|
1001
1001
|
for k in [k for k in alts if k.startswith("c-fn:") and "#" in k]:
|
|
@@ -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,
|
|
11
|
-
|
|
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 =
|
|
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
|
-
|
|
1189
|
-
|
|
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":
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
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
|
-
|
|
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."""
|