cg-code-graph 0.23.10__tar.gz → 0.23.11__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.10/cg_code_graph.egg-info → cg_code_graph-0.23.11}/PKG-INFO +1 -1
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/__init__.py +1 -1
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/cli.py +10 -3
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/lint_async.py +47 -10
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/mcp_server.py +5 -2
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/kotlin/plugin.py +39 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/ts/extractor/extract.mjs +17 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/roundtrip.py +71 -7
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11/cg_code_graph.egg-info}/PKG-INFO +1 -1
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph.egg-info/SOURCES.txt +1 -0
- cg_code_graph-0.23.11/tests/test_kotlin_local_state.py +77 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_lint_async.py +21 -4
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_roundtrip.py +12 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_ts_fields_js_vue.py +15 -4
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/LICENSE +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/MANIFEST.in +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/README.md +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/__main__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/affected.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/agent_rules.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/agents.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/aitools.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/android_ipc.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/apple_ipc.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/apps.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/blindspots.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/bridges.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/brokers.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/cmake_sources.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/concepts.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/config.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/core/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/core/cache.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/core/detect.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/core/env.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/core/extractors.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/core/fsutil.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/core/generated.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/core/model.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/core/paths.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/core/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/core/redact.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/core/store.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/core/syntax_errors.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/coverage.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/dart_isolates.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/doctor.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/explore.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/external.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/graphql.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/guard_facts.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/hooks.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/indexer.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/insecure_transport.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/install_rules.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/jobs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/link.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/local_ipc.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/local_sockets.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/mcp_graphs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/mcp_install.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/parity.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/parity_structure.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/payload.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plans.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/platform_scan.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/platforms.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/astro/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/astro/content.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/astro/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/cfamily/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/cfamily/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/cfamily/syntax.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/dart/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/dart/bridges.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/dart/extractor/bin/extract.dart +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/dart/extractor/pubspec.lock +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/dart/extractor/pubspec.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/dart/http.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/dart/models.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/dart/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/dart/program.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/django/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/django/extras.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/django/models.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/django/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/django/schemas.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/django/shapes.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/django/urls.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/express/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/express/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/flutter/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/flutter/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/java/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/java/exact.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/java/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/jvm/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/jvm/interop.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/jvm/spring.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/kotlin/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/kotlin/exact.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/kotlin/reparse.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/laravel/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/laravel/broadcast.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/laravel/massassign.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/laravel/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/laravel/tests.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/laravel/values.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/native/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/native/gates.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/native/runner.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/native/scipread.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/native/ts.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/nest/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/nest/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/nextjs/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/nextjs/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/nuxt/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/nuxt/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/php/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/php/external.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/php/extractor/composer.json +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/php/extractor/composer.lock +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/php/extractor/extract.php +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/php/gating.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/php/http_client.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/php/inline_guards.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/php/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/php/strings.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/python/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/python/aitools.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/python/external.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/python/fields.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/python/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/python/refs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/python/roots.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/python/socketio.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/python/subproc.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/python/tests.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/python/values.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/pyweb/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/pyweb/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/pyweb/values.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/rust/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/rust/cargo.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/rust/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/rust/syntax.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/scip/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/scip/importer.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/scip/scip.proto +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/scip/scip_pb2.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/stubs/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/stubs/plugins.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/swift/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/swift/baseurl.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/swift/exact.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/swift/indexstore.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/swift/packages.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/swift/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/ts/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/ts/baseurl.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/ts/extractor/fw.mjs +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/ts/extractor/package-lock.json +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/ts/extractor/package.json +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/ts/extractor/rr.mjs +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/ts/nav.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/ts/plugin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/ts/react_router.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/tsweb/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/tsweb/common.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/tsweb/data.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/c_cpp.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/common.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/dart.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/django-ninja.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/django.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/djangorestframework.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/express.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/java.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/kotlin.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/laravel.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/nest.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/nextjs.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/nuxt.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/php.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/python.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/react-router.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/rust.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/spring.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/swift.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/presets/typescript.yaml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/process_runs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/protocols/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/protocols/builtin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/protocols/matchers.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/protocols/view.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/query.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/realtime.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/realtime_events.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/realtime_native.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/realtime_ws.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/routes.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/rpc.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/sdk_systems.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/sockets.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/ssrf_input.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/starters.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/surface.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/tests_index.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/udp_apps.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/update_check.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/__init__.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/graph.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/server.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/static/app.css +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/static/app.js +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/static/index.html +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/static/layered.js +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/static/vendor/VERSIONS.txt +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/static/vendor/cose-base.js +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/static/vendor/cytoscape-fcose.js +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/static/vendor/cytoscape.min.js +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/static/vendor/layout-base.js +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/tools/package-lock.json +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/tools/package.json +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/viz/tools/shoot.mjs +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/watch.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/webhook_subs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/webhooks.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/xcode.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph.egg-info/dependency_links.txt +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph.egg-info/entry_points.txt +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph.egg-info/requires.txt +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph.egg-info/top_level.txt +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/pyproject.toml +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/setup.cfg +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_affected.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_agents_install.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_agents_md.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_ai_tools.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_android_ipc.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_apple_ipc.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_astro.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_astro_content.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_astro_server.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_bridges.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_bridges_pigeon_monorepo.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_brokers.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_cache_clean.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_cache_invalidation.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_cache_migration.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_channels_tests.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_cli_output.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_cmake_sources.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_completeness.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_config_extras.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_coverage.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_coverage_ts_hint.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_dart_isolates.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_db_connections.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_dead_wrappers.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_dispatch_interfaces.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_dispatch_part3.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_django_flutter.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_docs_languages.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_docs_links.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_echo_ref.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_echo_wrapper.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_elysia.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_enum_constants.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_env.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_explore.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_external.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_fp_batch.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_gating.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_generated.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_graphql.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_hooks.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_impact_overrides.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_index_isolation.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_inherited_overrides.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_inline_guards.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_install_rules.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_192.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_201.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_202.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_203.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_204.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_205.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_206.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_207.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_208.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_209.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_210.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_211.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_211_used_at.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_212.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_212_langs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_218.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_219.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_issue_222.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_java.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_java_exact.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_jobs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_js_refs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_js_runtime.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_kotlin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_kotlin_binding.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_kotlin_exact.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_kotlin_fields.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_kotlin_mixed.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_kotlin_nav_consts.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_kotlin_props.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_laravel_determinism.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_laravel_receiver_narrowing.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_laravel_resources.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_laravel_route_paths.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_link_origin.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_listing_files.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_local_ipc.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_local_sockets.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_mass_assignment.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_mcp.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_mcp_index.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_mcp_install.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_mcp_instructions.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_mcp_multi_graph.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_native_cfamily.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_native_concurrency.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_native_rust.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_nuxt_i18n.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_nuxt_import_dirs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_nuxt_nitro.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_nuxt_rootsrc.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_nuxt_side_dirs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_packaging.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_parity.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_parity_fields.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_parity_members.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_parity_structure.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_php_http.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_php_props.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_plain_js.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_plans.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_platform_gaps.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_platform_type_variants.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_platforms.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_platforms_apple.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_presets_config.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_process_ipc.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_process_runs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_protocols.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_python_app_tests_module.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_python_collection_chains.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_python_compat.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_python_entry_refs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_python_fields.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_python_infer_cycles.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_python_roots.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_python_subprocess_tests.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_python_tests.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_python_web_hosts.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_python_web_routes.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_python_web_routes_more.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_react_router.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_readers_writers_specs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_realtime.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_realtime_native.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_redact_salt.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_request_keys.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_route_specs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_route_tables.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_routes_search_explain.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_rpc.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_scip_health.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_sdk_external.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_sdk_external_infra.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_sdk_external_mail.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_snippet.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_sockets.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_spring.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_ssrf.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_starters_budget.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_surface.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_surface_transport.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_swift.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_swift_binding.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_swift_exact.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_swift_facts.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_swift_fields.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_swift_modules.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_swift_more.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_swift_nav_values.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_swift_parse_errors.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_swift_platform_files.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_swift_props.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_swift_sdk.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_swift_testing.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_swift_values.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_tauri_events.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_tests_scope.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_ts_fields.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_ts_file_specs.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_ts_frameworks.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_ts_node_http.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_ts_nuxt.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_ts_src_tsconfig.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_unguarded.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_update_check.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_values.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_viz.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_vue_nav.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_watch.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_webhooks.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_webhooks_152.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_webhooks_152b.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/tests/test_websockets.py +0 -0
- {cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/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.11"
|
|
@@ -317,7 +317,8 @@ def main(argv=None):
|
|
|
317
317
|
p.add_argument("--json", action="store_true"); p.add_argument("--tests", action="store_true", help="include test code")
|
|
318
318
|
p = sub.add_parser("roundtrip", help="heuristic: writes of a stored property `Type.prop` through a lossy transform, "
|
|
319
319
|
"read back to seed UI state (#88)")
|
|
320
|
-
p.add_argument("spec"); p.add_argument("--db", required=True); p.add_argument("--json", action="store_true")
|
|
320
|
+
p.add_argument("spec", nargs="?"); p.add_argument("--db", required=True); p.add_argument("--json", action="store_true")
|
|
321
|
+
p.add_argument("--all", action="store_true", help="every stored property in one pass: only the round trips")
|
|
321
322
|
p.add_argument("--tests", action="store_true", help="include test code's reads and writes")
|
|
322
323
|
p = sub.add_parser("viz-plan", help="self-contained HTML overlay of a plan on the real graph")
|
|
323
324
|
p.add_argument("name"); p.add_argument("--db", required=True); p.add_argument("-o", "--out", required=True); p.add_argument("--plans-dir")
|
|
@@ -769,8 +770,14 @@ def main(argv=None):
|
|
|
769
770
|
print(json.dumps(res, indent=1) if a.json else LA.render(res))
|
|
770
771
|
elif a.cmd == "roundtrip":
|
|
771
772
|
from . import roundtrip as RT
|
|
772
|
-
|
|
773
|
-
|
|
773
|
+
if a.all or not a.spec:
|
|
774
|
+
if not a.all:
|
|
775
|
+
sys.exit("cg roundtrip: give a property `Type.prop`, or --all")
|
|
776
|
+
res = RT.roundtrip_all(st, include_tests=a.tests)
|
|
777
|
+
print(RT.to_json(res) if a.json else RT.render_all(res))
|
|
778
|
+
else:
|
|
779
|
+
res = RT.roundtrip(st, a.spec, include_tests=a.tests)
|
|
780
|
+
print(RT.to_json(res) if a.json else RT.render(res))
|
|
774
781
|
elif a.cmd in ("writers", "readers"):
|
|
775
782
|
groups = Q.access(st, a.spec, a.cmd, a.connection)
|
|
776
783
|
rows = [r for g in groups for r in g["rows"]]
|
|
@@ -61,6 +61,24 @@ def _input_dependent(text: str) -> bool:
|
|
|
61
61
|
t = re.sub(r"(?<![\w$])[A-Za-z_$][\w$]*\s*(?:<[^<>]*>)?\s*\(", " (", t) # call names
|
|
62
62
|
ids = re.findall(r"(?<![\w$])[A-Za-z_$][\w$]*", t)
|
|
63
63
|
return any(i.startswith("SELFREF_") or (i not in KEYWORDS and not i[0].isupper()) for i in ids)
|
|
64
|
+
_SUSP: dict = {} # file -> lines with a call of a Kotlin `suspend` function (an await point with no marker)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _load_suspend(st: GraphStore) -> None:
|
|
68
|
+
"""A plain call of a project `suspend` function inside `launch { }` (`val x = repo.load()`) suspends like
|
|
69
|
+
`.await()`: the indexed CALLS edges to nodes marked `suspend` give those lines."""
|
|
70
|
+
_SUSP.clear()
|
|
71
|
+
for r in st.q("""SELECT e.file, e.line FROM edges e JOIN nodes n ON n.id = e.dst
|
|
72
|
+
WHERE e.kind = 'CALLS' AND n.attrs LIKE '%"suspend": true%' AND e.file IS NOT NULL"""):
|
|
73
|
+
_SUSP.setdefault(r["file"], set()).add(r["line"])
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _aw(t: str, file: str | None = None, line: int | None = None) -> bool:
|
|
77
|
+
"""Is there an await point in this line of source: a marker (`await`, `.await()`, `withContext`, `delay`) or,
|
|
78
|
+
in Kotlin, a call of a `suspend` function?"""
|
|
79
|
+
return bool(AWAIT_RE.search(t)) or (line is not None and line in _SUSP.get(file, ()))
|
|
80
|
+
|
|
81
|
+
|
|
64
82
|
TEST_PATH_RE = re.compile(r"(?:^|/)(?:tests?|__tests__|spec|testing|fixtures?|factories|Tests|UITests)/|"
|
|
65
83
|
r"[._-](?:test|spec)s?\.\w+:|Tests?\.swift:|Test\.kt:|(?:^|/)test_\w+\.py:")
|
|
66
84
|
|
|
@@ -104,6 +122,7 @@ def _opener(ls: list[str], line: int, lo: int):
|
|
|
104
122
|
|
|
105
123
|
|
|
106
124
|
def stale_async(st: GraphStore, include_tests: bool = False, limit: int = 500) -> list[dict]:
|
|
125
|
+
_load_suspend(st)
|
|
107
126
|
root = st.meta().get("root")
|
|
108
127
|
cache: dict = {}
|
|
109
128
|
fields = {r["id"]: json.loads(r["attrs"] or "{}") for r in st.q("SELECT id, attrs FROM nodes WHERE kind IN ('field','property')")}
|
|
@@ -122,7 +141,8 @@ def stale_async(st: GraphStore, include_tests: bool = False, limit: int = 500) -
|
|
|
122
141
|
continue
|
|
123
142
|
kind, o = op
|
|
124
143
|
body = ls[o - 1:r["line"] - 1]
|
|
125
|
-
aw = next((o + i for i, t in enumerate(body) if
|
|
144
|
+
aw = next((o + i for i, t in enumerate(body) if _aw(t if i else t[t.find("{") + 1:] if "{" in t else t,
|
|
145
|
+
r["file"], o + i if i else None)), None)
|
|
126
146
|
if aw is None:
|
|
127
147
|
continue
|
|
128
148
|
before = "\n".join(ls[o - 1:aw - 1]) + "\n" + ls[aw - 1].split("await")[0]
|
|
@@ -131,7 +151,10 @@ def stale_async(st: GraphStore, include_tests: bool = False, limit: int = 500) -
|
|
|
131
151
|
if GUARD_RE.search(after) or SINGLE_FLIGHT_RE.search(ls[o - 1]):
|
|
132
152
|
continue
|
|
133
153
|
aw_line = ls[aw - 1]
|
|
134
|
-
k =
|
|
154
|
+
k = aw_line.find("await")
|
|
155
|
+
if k < 0: # a Kotlin suspend call: the request is the right-hand side
|
|
156
|
+
m = re.search(r"(?<![=!<>])=(?!=)", aw_line)
|
|
157
|
+
k = m.end() if m else 0
|
|
135
158
|
stmt, depth = [], 0
|
|
136
159
|
for i in range(aw - 1, min(len(ls), aw + 5)):
|
|
137
160
|
x = ls[i][k:] if i == aw - 1 else ls[i]
|
|
@@ -144,10 +167,10 @@ def stale_async(st: GraphStore, include_tests: bool = False, limit: int = 500) -
|
|
|
144
167
|
# the written value must come from the awaited result: a name bound on the await line (or derived from one
|
|
145
168
|
# after it), or the await itself on the write line; a loading flag reset after the await is not a stale result
|
|
146
169
|
res_vars = set()
|
|
147
|
-
for t in ls[aw - 1:r["line"] - 1]:
|
|
170
|
+
for j, t in enumerate(ls[aw - 1:r["line"] - 1]):
|
|
148
171
|
m = DECL_RE.search(t) or re.search(r"^\s*(?:self\.)?([A-Za-z_$][\w$]*)\s*=(?!=)", t)
|
|
149
172
|
nm = m and (m.group(1) or (m.group(2) if m.lastindex and m.lastindex >= 2 else None))
|
|
150
|
-
if nm and (
|
|
173
|
+
if nm and (_aw(t, r["file"], aw + j) or any(re.search(rf"(?<![\w$.]){re.escape(v)}\b", t.split("=", 1)[-1]) for v in res_vars)):
|
|
151
174
|
res_vars.add(nm)
|
|
152
175
|
wl = ls[r["line"] - 1]
|
|
153
176
|
if r["line"] - 1 == aw - 1:
|
|
@@ -182,7 +205,8 @@ LIFECYCLE_RE = re.compile(r"\.onAppear\b|\bonAppear\s*\(|\.task\s*[({]|\bonMount
|
|
|
182
205
|
CALLBACK_RE = re.compile(r"\.sink\s*\{|\.onReceive\s*\(|\.subscribe\s*[({]|\.collect(?:Latest)?\s*\{|\.observe\w*\s*\(|"
|
|
183
206
|
r"\bcompletion(?:Handler)?\s*:\s*\{|\{\s*\[?\s*(?:weak|unowned)\s+self\s*\]?|\.then\s*\(|\.on\s*\(\s*['\"]")
|
|
184
207
|
LITERAL_RHS_RE = re.compile(r"(?<![=!<>])=\s*(?:\[\s*\]|\[:\]|\{\s*\}|nil|null|None|undefined|0(?:\.0+)?[fFdDL]?|false|False|true|True|"
|
|
185
|
-
r"''|\"\"|emptyList\(\)|emptyMap\(\)|mutableListOf\(\)|\.init\(\)|\w+\(\)|\.\w
|
|
208
|
+
r"''|\"\"|emptyList\(\)|emptyMap\(\)|mutableListOf\(\)|\.init\(\)|\w+\(\)|\.\w+|"
|
|
209
|
+
r"[A-Z]\w*(?:\.[A-Z]\w*)+(?:\(\))?)\s*;?\s*$") # a sentinel: `AsyncData.Loading()`, `UiState.Idle`
|
|
186
210
|
LITERAL_ARG_RE = re.compile(r"\(\s*(?:nil|null|None|undefined|true|false|True|False|-?\d+(?:\.\d+)?|'[^']*'|\"[^\"]*\"|\[\s*\]|\{\s*\})\s*\)\s*;?\s*$")
|
|
187
211
|
INIT_NAMES = {"init", "__init__", "constructor", "<init>", "viewDidLoad", "onCreate", "initState", "mounted", "created", "setup"}
|
|
188
212
|
|
|
@@ -198,7 +222,7 @@ def _lifecycle(st, ls, r, node) -> str | None:
|
|
|
198
222
|
"""Is this write lifecycle code: an initializer with a real (non-default) value, or code directly inside
|
|
199
223
|
onAppear / .task (before any await) / onMounted / LaunchedEffect / useEffect / viewDidLoad?"""
|
|
200
224
|
t = ls[r["line"] - 1]
|
|
201
|
-
if
|
|
225
|
+
if _aw(t, r["file"], r["line"]):
|
|
202
226
|
return None
|
|
203
227
|
nm = ((node["name"] if node is not None else "") or "").split(".")[-1]
|
|
204
228
|
if nm in INIT_NAMES or (node is not None and node["kind"] == "class"):
|
|
@@ -212,7 +236,7 @@ def _lifecycle(st, ls, r, node) -> str | None:
|
|
|
212
236
|
lo = max(1, r["line"] - 6)
|
|
213
237
|
for i in range(r["line"], lo - 1, -1):
|
|
214
238
|
x = ls[i - 1]
|
|
215
|
-
if i < r["line"] and
|
|
239
|
+
if i < r["line"] and _aw(x, r["file"], i):
|
|
216
240
|
return None
|
|
217
241
|
m = LIFECYCLE_RE.search(x)
|
|
218
242
|
if m:
|
|
@@ -225,7 +249,8 @@ def _async_callback(ls, r, lo) -> str | None:
|
|
|
225
249
|
op = _opener(ls, r["line"], lo)
|
|
226
250
|
if op is not None:
|
|
227
251
|
body = ls[op[1] - 1:r["line"] - 1]
|
|
228
|
-
if any(
|
|
252
|
+
if any(_aw(x, r["file"], op[1] + j) for j, x in enumerate(body) if j) or \
|
|
253
|
+
(body and AWAIT_RE.search(body[0][body[0].find("{") + 1:])):
|
|
229
254
|
return f"after await in {op[0]}"
|
|
230
255
|
for i in range(r["line"] - 1, max(lo, r["line"] - 8) - 1, -1):
|
|
231
256
|
m = CALLBACK_RE.search(ls[i - 1]) if i >= 1 else None
|
|
@@ -235,6 +260,7 @@ def _async_callback(ls, r, lo) -> str | None:
|
|
|
235
260
|
|
|
236
261
|
|
|
237
262
|
def two_writers(st: GraphStore, include_tests: bool = False) -> list[dict]:
|
|
263
|
+
_load_suspend(st)
|
|
238
264
|
root = st.meta().get("root")
|
|
239
265
|
cache: dict = {}
|
|
240
266
|
rows = st.q("""SELECT e.src, e.dst, e.file, e.line, e.attrs, n.line AS fl FROM edges e JOIN nodes n ON n.id = e.src
|
|
@@ -361,6 +387,14 @@ def incomplete_cache_key(st: GraphStore, include_tests: bool = False) -> list[di
|
|
|
361
387
|
sig = "\n".join(body[:3])
|
|
362
388
|
sig = sig[sig.find("("):] if "(" in sig else ""
|
|
363
389
|
params = _idents(_split_args(sig[1:]) and ",".join(re.sub(r"[:=].*", "", a, flags=re.S) for a in _split_args(sig[1:])) or "")
|
|
390
|
+
# instance fields used without `self.` / `this.` (Swift, Kotlin): the READS_PROP edges bind them
|
|
391
|
+
own = {e["dst"].rsplit(".", 1)[-1] for e in st.q("SELECT dst, attrs FROM edges WHERE kind = 'READS_PROP' AND src = ?",
|
|
392
|
+
(fn["id"],))
|
|
393
|
+
if json.loads(e["attrs"] or "{}").get("receiver") in (None, "self", "this")}
|
|
394
|
+
text = "\n".join(body)
|
|
395
|
+
# ... unless the field is an object the function calls (`client.get(…)`, `mediaLoader.load(…)`): a dependency,
|
|
396
|
+
# not an input of the cached value
|
|
397
|
+
own = {f for f in own if not re.search(rf"(?<![\w$.]){re.escape(f)}\s*[?!]?\.\s*\w+\s*[({{]", text)}
|
|
364
398
|
assigns: dict = {}
|
|
365
399
|
for off, t in enumerate(body):
|
|
366
400
|
m = re.search(r"\b(?:let|var|val|const)\s+([A-Za-z_$][\w$]*)\s*(?::[^=]+)?=(?!=)(.*)|^\s*([a-z_$][\w$]*)\s*=(?!=)(.*)", t)
|
|
@@ -384,8 +418,10 @@ def incomplete_cache_key(st: GraphStore, include_tests: bool = False) -> list[di
|
|
|
384
418
|
vb = val.strip().rstrip(";")
|
|
385
419
|
if re.fullmatch(r"[A-Za-z_$][\w$]*", vb) and vb not in assigns:
|
|
386
420
|
continue # `put(key, value)` passes a value through; nothing is computed here
|
|
387
|
-
|
|
388
|
-
|
|
421
|
+
bare = lambda ids: {f"self_{i}" if i in own and i not in params and i not in assigns else i # noqa: E731
|
|
422
|
+
for i in ids}
|
|
423
|
+
kids = bare(_expand(_idents(key), assigns))
|
|
424
|
+
vids = bare(_expand(_idents(val), assigns)) - {vb}
|
|
389
425
|
setter = re.match(r"(?:set|put|insert|store|save|cache|add|update|write|remember|record)(?![a-z])",
|
|
390
426
|
(fn["fqn"] or "").split(".")[-1].split("(")[0])
|
|
391
427
|
inputs = {i for i in vids if (i in params and not setter and not PAYLOAD_RE.fullmatch(i.lstrip("$")))
|
|
@@ -421,6 +457,7 @@ def echo_suppression(st: GraphStore, include_tests: bool = False, patterns: list
|
|
|
421
457
|
programmatic writes of some state so the change observer, which checks the guard and returns early, does not
|
|
422
458
|
echo them back. Reports state of that pattern that is also written from an async path / callback *without*
|
|
423
459
|
setting the guard: that write reaches the observer and is sent back (a loop or a clobbered edit)."""
|
|
460
|
+
_load_suspend(st)
|
|
424
461
|
root = st.meta().get("root")
|
|
425
462
|
cache: dict = {}
|
|
426
463
|
guards = [r["id"] for r in st.q("SELECT id, name FROM nodes WHERE kind = 'field'") if GUARD_FIELD_RE.fullmatch((r["name"] or "").rsplit(".", 1)[-1].replace("_", ""))]
|
|
@@ -877,13 +877,16 @@ def _access_text(st, spec: str, what: str, limit: int, connection: str | None =
|
|
|
877
877
|
|
|
878
878
|
|
|
879
879
|
@tool
|
|
880
|
-
def roundtrip(prop: str, include_tests: bool = False) -> str:
|
|
880
|
+
def roundtrip(prop: str = "", include_tests: bool = False) -> str:
|
|
881
881
|
"""Heuristic (#88): does a stored property `Type.prop` round-trip through a lossy transform? Each write site with
|
|
882
882
|
the lossy call it passes through (clamp, min/max, round, truncating casts, `fit*`, `.cg.yaml` `lossy:` names,
|
|
883
883
|
`@cg-lossy` functions; within the function plus one hop through direct callers), each read site that seeds UI
|
|
884
884
|
state (init, onAppear, remember, useState(initial), mounted), and un-narrowed ranges drawn next to such a read.
|
|
885
|
-
Findings are heuristic evidence with file:line, not proof.
|
|
885
|
+
Findings are heuristic evidence with file:line, not proof. An empty `prop` (or `*`) checks every stored property
|
|
886
|
+
in one pass and lists only the round trips."""
|
|
886
887
|
from . import roundtrip as RT
|
|
888
|
+
if prop.strip() in ("", "*"):
|
|
889
|
+
return RT.render_all(RT.roundtrip_all(_st(), include_tests=include_tests))
|
|
887
890
|
return RT.render(RT.roundtrip(_st(), prop, include_tests=include_tests))
|
|
888
891
|
|
|
889
892
|
|
|
@@ -207,6 +207,12 @@ def _suspend_lambdas(src: bytes) -> tuple[bytes, int]:
|
|
|
207
207
|
# `get<T>` the whitespace character in front of `get` / `set` becomes `;`. That ends the declaration and keeps every
|
|
208
208
|
# byte offset.
|
|
209
209
|
_ROUTE_ACCESSOR = re.compile(rb"([ \t]*)[ \t]((?:get|set)\s*(?:\(\s*(?:\"|\"\"\")|\{|<))")
|
|
210
|
+
# `var x by remember { mutableStateOf(..) }`, `by rememberSaveable { .. }`, `by mutableStateOf(..)`,
|
|
211
|
+
# `by vm.state.collectAsState()` / `collectAsStateWithLifecycle()`, `by produceState(..)`, `by derivedStateOf { }`
|
|
212
|
+
LOCAL_STATE = re.compile(r"\b(var|val)\s+(\w+)(?:\s*:\s*[^=\n]+?)?\s+by\s+(?:remember(?:Saveable)?\b[^\n{]*\{\s*"
|
|
213
|
+
r"(mutable\w*StateOf|derivedStateOf|mutableStateListOf|mutableStateMapOf)"
|
|
214
|
+
r"|(mutable\w*StateOf|derivedStateOf)\s*[({]|[\w.]*?\b(collectAs\w*State\w*)\s*\("
|
|
215
|
+
r"|(produceState|observeAsState|subscribeAsState)\b|[\w.]*?\.(observeAsState|subscribeAsState)\s*\()")
|
|
210
216
|
_DECL_LINE = re.compile(rb"^\s*(?:(?:private|internal|public|protected|const|lateinit|override|open)\s+)*(?:val|var)\s")
|
|
211
217
|
|
|
212
218
|
|
|
@@ -321,6 +327,7 @@ class KotlinPlugin(LanguagePlugin):
|
|
|
321
327
|
# stored properties of a class / enum are `field:<Type>.<name>` nodes with READS_PROP / WRITES_PROP (#88)
|
|
322
328
|
self.fields: dict[str, dict[str, str]] = defaultdict(dict) # class fqn -> name -> field id
|
|
323
329
|
self.field_names: set[str] = set()
|
|
330
|
+
self.local_state: dict[str, dict[str, str]] = defaultdict(dict) # function id -> local state name -> field id
|
|
324
331
|
self.copies: list[tuple] = [] # (owner, receiver (type, text), [(arg name, line)], kf, decl): `x.copy(a = 1)`
|
|
325
332
|
self.frefs: list[tuple] = [] # (owner_id, name, receiver (type, text) | None, line, file, decl, write)
|
|
326
333
|
self.reads: list[tuple] = [] # (owner_id, name, receiver node, line, file obj, decl, read | write)
|
|
@@ -617,6 +624,7 @@ class KotlinPlugin(LanguagePlugin):
|
|
|
617
624
|
if any(dflt for _n, dflt, _f in fparams):
|
|
618
625
|
self.fn_params[dc.id] = fparams
|
|
619
626
|
self._add_decl(dc, kind)
|
|
627
|
+
self._local_state(dc, kf, c)
|
|
620
628
|
self._local_fns(c, kf, dc)
|
|
621
629
|
elif ty == "enum_entry" and cls is not None:
|
|
622
630
|
nm = self._name(c)
|
|
@@ -655,6 +663,30 @@ class KotlinPlugin(LanguagePlugin):
|
|
|
655
663
|
self.field_names.add(nm)
|
|
656
664
|
self.st["stored_property_nodes"] += 1
|
|
657
665
|
|
|
666
|
+
def _local_state(self, dc: Decl, kf: KFile, c):
|
|
667
|
+
"""Compose state held in a local delegate (`var count by remember { mutableIntStateOf(0) }`, `val ui by
|
|
668
|
+
vm.state.collectAsStateWithLifecycle()`): a `field:<function>.<name>` node (`property: state`, `hook`) whose
|
|
669
|
+
reads and writes inside the function are READS_PROP / WRITES_PROP, like React `useState` (#105, #88)."""
|
|
670
|
+
txt = self.t(c)
|
|
671
|
+
if " by " not in txt:
|
|
672
|
+
return
|
|
673
|
+
for m in LOCAL_STATE.finditer(txt):
|
|
674
|
+
nm = m.group(2)
|
|
675
|
+
if nm in self.local_state[dc.id]:
|
|
676
|
+
continue
|
|
677
|
+
hook = next(g for g in m.groups()[2:] if g).split(".")[-1]
|
|
678
|
+
line = c.start_point[0] + 1 + txt.count("\n", 0, m.start(2))
|
|
679
|
+
a = {"property": "state", "hook": hook, "binding": m.group(1), "local": True}
|
|
680
|
+
if kf.test:
|
|
681
|
+
a["test"] = True
|
|
682
|
+
fid = self.b.add_node("field", f"{dc.fqn}.{nm}", name=nm, fqn=f"{dc.fqn}.{nm}", file=kf.rel, line=line,
|
|
683
|
+
end_line=line, module=getattr(self.b.nodes.get(dc.id), "module", None), lang="kotlin",
|
|
684
|
+
attrs=a)
|
|
685
|
+
self.b.add_edge(dc.id, fid, "CONTAINS", kf.rel, line, EXACT)
|
|
686
|
+
self.local_state[dc.id][nm] = fid
|
|
687
|
+
self.field_names.add(nm)
|
|
688
|
+
self.st["local_state_nodes"] += 1
|
|
689
|
+
|
|
658
690
|
def _prop_kind(self, c) -> tuple | None:
|
|
659
691
|
"""(property kind, accessors) of a property that runs code when read or written (#89): a custom `get()` /
|
|
660
692
|
`set(value)` (custom), `by lazy { }` (lazy) or another delegate (delegated); None for a stored property."""
|
|
@@ -1954,6 +1986,13 @@ class KotlinPlugin(LanguagePlugin):
|
|
|
1954
1986
|
decl if decl is not None and decl.kind == "class" else None)
|
|
1955
1987
|
fid = None
|
|
1956
1988
|
rt = recv[1] if recv is not None else None
|
|
1989
|
+
loc = self.local_state.get(decl.id, {}).get(name) if recv is None and decl is not None else None
|
|
1990
|
+
if loc:
|
|
1991
|
+
if loc != owner:
|
|
1992
|
+
self.b.add_edge(owner, loc, "WRITES_PROP" if write else "READS_PROP", kf.rel, line, RESOLVED,
|
|
1993
|
+
receiver="local", **({"via": write} if isinstance(write, str) else {}))
|
|
1994
|
+
self.st["local_state_writes" if write else "local_state_reads"] += 1
|
|
1995
|
+
continue
|
|
1957
1996
|
if recv is None or rt == "this":
|
|
1958
1997
|
if recv is None and self._shadowed_local(decl, name, kf):
|
|
1959
1998
|
continue
|
{cg_code_graph-0.23.10 → cg_code_graph-0.23.11}/cg_code_graph/plugins/ts/extractor/extract.mjs
RENAMED
|
@@ -983,6 +983,7 @@ const STATE_HOOKS = new Set(['useState', 'useReducer', 'ref', 'shallowRef', 'rea
|
|
|
983
983
|
const optFields = new Map() // options ObjectLiteralExpression -> Map(name -> field id)
|
|
984
984
|
const storeFields = new Map() // store VariableDeclaration -> Map(name -> field id)
|
|
985
985
|
const optNames = new Set()
|
|
986
|
+
const fileOptData = new Map() // rel .vue path -> Map(data() key -> field id): bare names in its template
|
|
986
987
|
function returnedObject(f) {
|
|
987
988
|
if (!f) return null
|
|
988
989
|
f = unwrap(f)
|
|
@@ -1013,6 +1014,7 @@ function optionsFields(sf, r, fid) {
|
|
|
1013
1014
|
}
|
|
1014
1015
|
optFields.set(obj, m)
|
|
1015
1016
|
if (storeDecl) storeFields.set(storeDecl, m)
|
|
1017
|
+
if (hook === 'data') { const f = fileOptData.get(r) || new Map(); for (const [k, v] of m) f.set(k, v); fileOptData.set(r, f) }
|
|
1016
1018
|
}
|
|
1017
1019
|
const scan = (n) => {
|
|
1018
1020
|
if (ts.isCallExpression(n) && ts.isIdentifier(n.expression) && n.expression.text === 'defineStore') {
|
|
@@ -1065,6 +1067,20 @@ function optionsRef(node, cur, sf, r) {
|
|
|
1065
1067
|
addEdge(cur, fid, write ? 'WRITES_PROP' : 'READS_PROP', r, lineOf(node, sf), m === null ? 'resolved' : (recv === 'this' ? 'exact' : 'resolved'), { receiver: recv, ...(via ? { via } : {}) })
|
|
1066
1068
|
stats[write ? 'state_field_writes' : 'state_field_reads'] = (stats[write ? 'state_field_writes' : 'state_field_reads'] || 0) + 1
|
|
1067
1069
|
}
|
|
1070
|
+
// `{{ count }}` / `@click="count++"` in the template of an Options API component: a bare data() key (#88)
|
|
1071
|
+
function optionsTplRef(node, cur, sf, r) {
|
|
1072
|
+
const m = fileOptData.get(r), fid = m && m.get(node.text)
|
|
1073
|
+
if (!fid || fid === cur || !isTemplateLine(node, sf)) return
|
|
1074
|
+
const p = node.parent
|
|
1075
|
+
if (p && ((ts.isPropertyAccessExpression(p) && p.name === node) || (ts.isPropertyAssignment(p) && p.name === node)
|
|
1076
|
+
|| ts.isParameter(p) || ts.isFunctionDeclaration(p))) return
|
|
1077
|
+
let s = null
|
|
1078
|
+
try { s = checker.getSymbolAtLocation(node) } catch { }
|
|
1079
|
+
if (s && (s.declarations || []).length) return // a v-for variable / slot prop / import of that name
|
|
1080
|
+
const [write, via] = writeOf(node)
|
|
1081
|
+
addEdge(cur, fid, write ? 'WRITES_PROP' : 'READS_PROP', r, lineOf(node, sf), 'resolved', { template: true, ...(via ? { via } : {}) })
|
|
1082
|
+
stats[write ? 'state_field_writes' : 'state_field_reads'] = (stats[write ? 'state_field_writes' : 'state_field_reads'] || 0) + 1
|
|
1083
|
+
}
|
|
1068
1084
|
function stateDecl(d, cur, sf, r) {
|
|
1069
1085
|
const init = unwrap(d.initializer)
|
|
1070
1086
|
if (!init || !ts.isCallExpression(init)) return
|
|
@@ -2865,6 +2881,7 @@ for (const sf of sourceFiles) {
|
|
|
2865
2881
|
if (ts.isVariableDeclaration(node) && node.initializer && cur) stateDecl(node, cur, sf, r)
|
|
2866
2882
|
if (ts.isIdentifier(node) && stateNames.has(node.text) && cur) stateRef(node, cur, sf, r)
|
|
2867
2883
|
if (ts.isPropertyAccessExpression(node) && optNames.has(node.name.text) && cur) optionsRef(node, cur, sf, r)
|
|
2884
|
+
if (isVue && ts.isIdentifier(node) && optNames.has(node.text) && cur && fileOptData.has(r)) optionsTplRef(node, cur, sf, r)
|
|
2868
2885
|
// .astro: `<a href>` inside a template expression (`{posts.map(p => <a href={`/blog/${p.slug}`}>)}`) is navigation,
|
|
2869
2886
|
// like a top-level one (the scanner handles those)
|
|
2870
2887
|
if (isAstro && ts.isJsxAttribute(node) && node.initializer && ts.isIdentifier(node.name) && node.name.text === 'href'
|
|
@@ -119,6 +119,13 @@ def _bounds(text: str) -> tuple[float, float] | None:
|
|
|
119
119
|
|
|
120
120
|
def _fn_bounds(st: GraphStore, src: _Src, name: str) -> tuple[float, float] | None:
|
|
121
121
|
"""Bounds inside a project function `name` (`func clamp(_ v: Double) -> Double { min(max(v, 0), 10) }`)."""
|
|
122
|
+
memo = src.__dict__.setdefault("bounds", {})
|
|
123
|
+
if name not in memo:
|
|
124
|
+
memo[name] = _fn_bounds1(st, src, name)
|
|
125
|
+
return memo[name]
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _fn_bounds1(st: GraphStore, src: _Src, name: str) -> tuple[float, float] | None:
|
|
122
129
|
for r in st.q("SELECT file, line, end_line FROM nodes WHERE kind IN ('function','method') AND name=? LIMIT 3", (name,)):
|
|
123
130
|
ls = src.lines(r["file"])
|
|
124
131
|
body = "\n".join(ls[(r["line"] or 1) - 1:(r["end_line"] or r["line"] or 1)])
|
|
@@ -273,8 +280,19 @@ def roundtrip(st: GraphStore, spec: str, include_tests: bool = False) -> dict:
|
|
|
273
280
|
for r in Q.prop_access(st, spec, "READS_PROP"):
|
|
274
281
|
if include_tests or not r.get("test"):
|
|
275
282
|
res["reads"].append(_read_site(st, src, r))
|
|
276
|
-
|
|
277
|
-
|
|
283
|
+
res["findings"] = _pair(src, res["writes"], res["reads"], prop)
|
|
284
|
+
for x in res["writes"]:
|
|
285
|
+
x.pop("_span", None)
|
|
286
|
+
for x in res["reads"]:
|
|
287
|
+
x.pop("_src", None)
|
|
288
|
+
return res
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def _pair(src, writes, reads, prop) -> list[dict]:
|
|
292
|
+
"""Findings: a lossy write and a read of the same property that seeds UI state."""
|
|
293
|
+
out = []
|
|
294
|
+
lossy = [w for w in writes if w["lossy"]]
|
|
295
|
+
seeds = [x for x in reads if x["seeds"]]
|
|
278
296
|
for w in lossy:
|
|
279
297
|
b = w["lossy"].get("bounds")
|
|
280
298
|
for x in seeds:
|
|
@@ -287,14 +305,60 @@ def roundtrip(st: GraphStore, spec: str, include_tests: bool = False) -> dict:
|
|
|
287
305
|
"read": x["at"], "seeds": x["seeds"], "wider_ranges": []}
|
|
288
306
|
if b:
|
|
289
307
|
f["wider_ranges"] = _ranges(src, x["at"].rsplit(":", 1)[0], tuple(b))[:5]
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
308
|
+
out.append(f)
|
|
309
|
+
return out
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def roundtrip_all(st: GraphStore, include_tests: bool = False) -> dict:
|
|
313
|
+
"""Every stored property in one pass (`cg roundtrip --all`): write sites are read once, file lines and callee
|
|
314
|
+
bounds are shared, and reads are looked at only for properties with a lossy write."""
|
|
315
|
+
root = st.meta().get("root")
|
|
316
|
+
globs, lsrc = lossy_names(st, root)
|
|
317
|
+
src = _Src(root)
|
|
318
|
+
stored = {r["id"]: r["fqn"] or r["name"] or r["id"] for r in st.q(
|
|
319
|
+
"""SELECT id, fqn, name FROM nodes WHERE kind IN ('field', 'property') AND attrs LIKE '%"property": "stored"%'""")}
|
|
320
|
+
|
|
321
|
+
def rows(kind):
|
|
322
|
+
by: dict = {}
|
|
323
|
+
for r in st.q("""SELECT e.src, e.dst, e.kind, e.file, e.line, n.fqn FROM edges e JOIN nodes n ON n.id = e.src
|
|
324
|
+
WHERE e.kind = ? OR (e.kind = 'TEST_USES' AND e.attrs LIKE ?) ORDER BY e.dst, e.file, e.line""",
|
|
325
|
+
(kind, f'%"orig": "{kind}"%')):
|
|
326
|
+
if r["dst"] in stored and r["file"] and (include_tests or r["kind"] != "TEST_USES"):
|
|
327
|
+
d = dict(r)
|
|
328
|
+
d["test"] = r["kind"] == "TEST_USES"
|
|
329
|
+
by.setdefault(r["dst"], []).append(d)
|
|
330
|
+
return by
|
|
331
|
+
|
|
332
|
+
res = {"confidence": "heuristic", "lossy_sources": lsrc, "fields_with_writes": 0, "lossy_writes": 0, "findings": []}
|
|
333
|
+
writes = rows("WRITES_PROP")
|
|
334
|
+
res["fields_with_writes"] = len(writes)
|
|
335
|
+
lossy: dict = {}
|
|
336
|
+
for fid, ws in writes.items():
|
|
337
|
+
prop = re.split(r"[.$:#]", stored[fid])[-1]
|
|
338
|
+
sites = [_write_site(st, src, r, prop, globs) for r in ws]
|
|
339
|
+
if any(w["lossy"] for w in sites):
|
|
340
|
+
lossy[fid] = (prop, sites)
|
|
341
|
+
res["lossy_writes"] += sum(1 for w in sites if w["lossy"])
|
|
342
|
+
if lossy:
|
|
343
|
+
reads = rows("READS_PROP")
|
|
344
|
+
for fid, (prop, sites) in lossy.items():
|
|
345
|
+
for f in _pair(src, sites, [_read_site(st, src, r) for r in reads.get(fid, [])], prop):
|
|
346
|
+
res["findings"].append(dict(f, state=fid))
|
|
295
347
|
return res
|
|
296
348
|
|
|
297
349
|
|
|
350
|
+
def render_all(res: dict) -> str:
|
|
351
|
+
out = [f"roundtrip --all — heuristic; lossy names: {', '.join(res['lossy_sources'])}",
|
|
352
|
+
f"{res['fields_with_writes']} stored properties with writes, {res['lossy_writes']} lossy writes, "
|
|
353
|
+
f"{len(res['findings'])} round trips"]
|
|
354
|
+
for f in res["findings"]:
|
|
355
|
+
out.append(f" {f['state']}: write @{f['write']} -> {'/'.join(f['lossy']['calls'])} @{f['lossy']['at']} "
|
|
356
|
+
f"-> read @{f['read']} -> seeds {f['seeds']}")
|
|
357
|
+
for g in f["wider_ranges"]:
|
|
358
|
+
out.append(f" un-narrowed range {_fmt(g['range'])} @{g['at']}: {g['code']}")
|
|
359
|
+
return "\n".join(out)
|
|
360
|
+
|
|
361
|
+
|
|
298
362
|
def _read_back(src, w, x, prop) -> bool:
|
|
299
363
|
"""Is this read a read-back of the stored value rather than the same setup using what it just built? Not when
|
|
300
364
|
the writer reads it a few lines later (`scrollBar = ScrollBarView(...)` then `addView(scrollBar)` in one init),
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Compose state held in a local delegate (#105, #88): `var count by remember { mutableIntStateOf(0) }`,
|
|
2
|
+
`by rememberSaveable { mutableStateOf("") }`, `by vm.state.collectAsStateWithLifecycle()` and `by mutableStateOf()`
|
|
3
|
+
are `field:<function>.<name>` nodes (`property: state`, `hook`, `local`); bare reads and writes inside the function
|
|
4
|
+
(including lambdas such as `onClick = { count++ }`) are READS_PROP / WRITES_PROP. A plain local of the same name in
|
|
5
|
+
another function binds nothing."""
|
|
6
|
+
import json
|
|
7
|
+
import sqlite3
|
|
8
|
+
import sys
|
|
9
|
+
import tempfile
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
15
|
+
sys.path.insert(0, str(ROOT))
|
|
16
|
+
from cg_code_graph.indexer import index_project # noqa: E402
|
|
17
|
+
|
|
18
|
+
pytest.importorskip("tree_sitter_kotlin")
|
|
19
|
+
|
|
20
|
+
SRC = """\
|
|
21
|
+
package app
|
|
22
|
+
|
|
23
|
+
import androidx.compose.runtime.*
|
|
24
|
+
|
|
25
|
+
class CounterViewModel {
|
|
26
|
+
val state = MutableStateFlow(0)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@Composable
|
|
30
|
+
fun CounterScreen(vm: CounterViewModel) {
|
|
31
|
+
var count by remember { mutableIntStateOf(0) }
|
|
32
|
+
var name by rememberSaveable { mutableStateOf("") }
|
|
33
|
+
val total by vm.state.collectAsStateWithLifecycle()
|
|
34
|
+
var shown by mutableStateOf(false)
|
|
35
|
+
Button(onClick = { count++ }) {
|
|
36
|
+
Text(label(count, total))
|
|
37
|
+
}
|
|
38
|
+
TextField(value = name, onValueChange = { name = it })
|
|
39
|
+
if (shown) Dialog(onDismiss = { shown = false })
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@Composable
|
|
43
|
+
fun Other() {
|
|
44
|
+
val count = 3
|
|
45
|
+
Text(label(count, 0))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fun label(a: Int, b: Int): String = ""
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@pytest.fixture(scope="module")
|
|
53
|
+
def g():
|
|
54
|
+
d = Path(tempfile.mkdtemp(prefix="cg-kt-local-state-"))
|
|
55
|
+
(d / "p/src/main/kotlin/app").mkdir(parents=True)
|
|
56
|
+
(d / "p/src/main/kotlin/app/Counter.kt").write_text(SRC)
|
|
57
|
+
index_project(d / "p", d / "g.db", "kls")
|
|
58
|
+
return sqlite3.connect(d / "g.db")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_local_state_nodes(g):
|
|
62
|
+
n = {i: json.loads(a or "{}") for i, a in g.execute("select id, attrs from nodes where kind='field'")}
|
|
63
|
+
f = "field:app.CounterScreen."
|
|
64
|
+
assert n[f + "count"] == {"property": "state", "hook": "mutableIntStateOf", "binding": "var", "local": True}
|
|
65
|
+
assert n[f + "name"]["hook"] == "mutableStateOf" and n[f + "total"]["hook"] == "collectAsStateWithLifecycle"
|
|
66
|
+
assert n[f + "shown"]["binding"] == "var"
|
|
67
|
+
assert not [i for i in n if i.startswith("field:app.Other.")]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_local_state_reads_and_writes(g):
|
|
71
|
+
e = {(d.rsplit(".", 1)[-1], k, ln) for s, d, k, ln in g.execute(
|
|
72
|
+
"select src, dst, kind, line from edges where kind in ('READS_PROP','WRITES_PROP') and dst like 'field:app.CounterScreen.%'")}
|
|
73
|
+
assert {("count", "READS_PROP", 15), ("count", "WRITES_PROP", 15), ("count", "READS_PROP", 16),
|
|
74
|
+
("total", "READS_PROP", 16), ("name", "READS_PROP", 18), ("name", "WRITES_PROP", 18),
|
|
75
|
+
("shown", "READS_PROP", 19), ("shown", "WRITES_PROP", 19)} <= e, e
|
|
76
|
+
srcs = {s for (s,) in g.execute("select src from edges where dst like 'field:app.CounterScreen.%' and kind like '%PROP'")}
|
|
77
|
+
assert srcs == {"function:app.CounterScreen"}
|
|
@@ -45,7 +45,10 @@ def test_swift():
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
def test_kotlin():
|
|
48
|
-
|
|
48
|
+
# not :19 (requestId); SuspendSearch.kt:9 awaits a plain `suspend` call (no marker), :16 is a fixed request and
|
|
49
|
+
# :23 calls a non-suspend function
|
|
50
|
+
assert found("kotlin") == [("src/main/kotlin/app/Search.kt:10", "launch", "heuristic"),
|
|
51
|
+
("src/main/kotlin/app/SuspendSearch.kt:9", "launch", "heuristic")]
|
|
49
52
|
|
|
50
53
|
|
|
51
54
|
def test_react():
|
|
@@ -87,8 +90,8 @@ def test_mcp_tool(monkeypatch):
|
|
|
87
90
|
|
|
88
91
|
|
|
89
92
|
@pytest.mark.parametrize("lang,at,missing", [
|
|
90
|
-
("swift", "Sources/App/Cache.swift:9", ["size"]),
|
|
91
|
-
("kotlin", "src/main/kotlin/app/Cache.kt:
|
|
93
|
+
("swift", "Sources/App/Cache.swift:9", ["self.scale", "size"]), # `scale` is a field used without `self.`
|
|
94
|
+
("kotlin", "src/main/kotlin/app/Cache.kt:9", ["size"]),
|
|
92
95
|
("react", "src/Cache.tsx:5", ["size"]),
|
|
93
96
|
("python", "app/cache.py:8", ["self.theme"]),
|
|
94
97
|
])
|
|
@@ -102,7 +105,7 @@ def test_incomplete_cache_key(lang, at, missing):
|
|
|
102
105
|
pytest.skip("node not installed")
|
|
103
106
|
got = [(f["at"], f["missing"], f["confidence"]) for f in LA.lint(GraphStore(db(lang)))["findings"]
|
|
104
107
|
if f["rule"] == "incomplete-cache-key"]
|
|
105
|
-
assert got ==
|
|
108
|
+
assert got[0] == (at, missing, "heuristic") and len(got) == (2 if lang == "kotlin" else 1) # + Kotlin `icon`
|
|
106
109
|
|
|
107
110
|
|
|
108
111
|
def test_cache_key_idents():
|
|
@@ -142,3 +145,17 @@ def test_rules_subset():
|
|
|
142
145
|
out = subprocess.run([sys.executable, "-m", "cg_code_graph.cli", "lint", "async-state", "--db", str(db("python")),
|
|
143
146
|
"--rules", "incomplete-cache-key"], capture_output=True, text=True, check=True, cwd=ROOT).stdout
|
|
144
147
|
assert "[incomplete-cache-key]" in out and "[echo-suppression]" not in out
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def test_incomplete_cache_key_bare_kotlin_field():
|
|
151
|
+
"""`render(url, size * density)` keyed by url and size: `density` is a field used without `this.`."""
|
|
152
|
+
got = [(f["at"], f["missing"]) for f in LA.lint(GraphStore(db("kotlin")))["findings"] if f["rule"] == "incomplete-cache-key"]
|
|
153
|
+
assert ("src/main/kotlin/app/Cache.kt:21", ["self.density"]) in got, got
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_sentinel_reset_is_a_default():
|
|
157
|
+
"""`searchResults = AsyncData.Loading()` / `= UiState.Idle` reset state to a sentinel: not a competing value."""
|
|
158
|
+
assert LA.LITERAL_RHS_RE.search("searchResults = AsyncData.Loading()")
|
|
159
|
+
assert LA.LITERAL_RHS_RE.search("state = UiState.Idle")
|
|
160
|
+
assert not LA.LITERAL_RHS_RE.search("results = Search.run(query)")
|
|
161
|
+
assert not LA.LITERAL_RHS_RE.search("now = clock.now()")
|
|
@@ -126,3 +126,15 @@ def test_call_args_scopes_caller_hop():
|
|
|
126
126
|
stmt = "rooms.insert(Room(spaceRoom: spaceRoom), at: Int(index))"
|
|
127
127
|
assert _call_args(St(), stmt, "method:Room.init", "spaceRoom").strip() == "spaceRoom"
|
|
128
128
|
assert _call_args(St(), "x = Room(spaceRoom: Int(v), other: 1)", "method:Room.init", "spaceRoom") == "Int(v)"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@pytest.mark.parametrize("lang", ["swift", "kotlin", "python"])
|
|
132
|
+
def test_all_properties_one_pass(lang):
|
|
133
|
+
"""`cg roundtrip --all` finds the same round trips as asking for the property, in one pass over every field."""
|
|
134
|
+
pytest.importorskip("tree_sitter_swift" if lang == "swift" else "tree_sitter_kotlin" if lang == "kotlin" else "json")
|
|
135
|
+
one = rt(lang)["findings"]
|
|
136
|
+
allr = RT.roundtrip_all(GraphStore(db(lang)))
|
|
137
|
+
got = [(f["write"], f["read"]) for f in allr["findings"] if f["state"] in rt(lang)["fields"]]
|
|
138
|
+
assert one and got == [(f["write"], f["read"]) for f in one]
|
|
139
|
+
assert allr["fields_with_writes"] >= 1 and allr["lossy_writes"] >= 1
|
|
140
|
+
assert "round trips" in RT.render_all(allr)
|
|
@@ -72,7 +72,18 @@ def test_pinia_options_store_and_vue_data():
|
|
|
72
72
|
add, comp = "function:src/stores/cart.ts#useCartStore.add", "component:src/components/Counter.vue"
|
|
73
73
|
assert e[(add, s + "items", "WRITES_PROP", 7)]["via"] == "mutating"
|
|
74
74
|
assert (add, s + "total", "WRITES_PROP", 8) in e and (add, s + "total", "READS_PROP", 9) in e
|
|
75
|
-
assert e[(comp, v + "count", "WRITES_PROP",
|
|
76
|
-
assert e[(comp, s + "total", "WRITES_PROP",
|
|
77
|
-
assert (comp, s + "items", "READS_PROP",
|
|
78
|
-
assert e[(comp, s + "total", "READS_PROP",
|
|
75
|
+
assert e[(comp, v + "count", "WRITES_PROP", 17)] == {"receiver": "this"}
|
|
76
|
+
assert e[(comp, s + "total", "WRITES_PROP", 19)] == {"receiver": "cart"}
|
|
77
|
+
assert (comp, s + "items", "READS_PROP", 20) in e
|
|
78
|
+
assert e[(comp, s + "total", "READS_PROP", 20)] == {"receiver": "useCartStore()"}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_vue_options_template_reads_and_writes():
|
|
82
|
+
"""`{{ count }}`, `:title="label"` and `@click="count++"` in an Options API template read / write the data() key;
|
|
83
|
+
a v-for variable of the same name (`label in labels`) does not."""
|
|
84
|
+
e = edges("vue_options_fixture", ("READS_PROP", "WRITES_PROP"))
|
|
85
|
+
comp, v = "component:src/components/Counter.vue", "field:src/components/Counter.vue#"
|
|
86
|
+
assert e[(comp, v + "count", "READS_PROP", 2)] == {"template": True}
|
|
87
|
+
assert (comp, v + "labels", "READS_PROP", 3) in e and (comp, v + "label", "READS_PROP", 3) not in e
|
|
88
|
+
assert (comp, v + "label", "WRITES_PROP", 4) in e and (comp, v + "label", "READS_PROP", 4) in e
|
|
89
|
+
assert (comp, v + "count", "WRITES_PROP", 5) in e
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|