feat(typescript): add tsc_only toggle and surface synthesized anonymous callables#179
Merged
Conversation
…us callables Drop reliance on the obsolete `--call-graph-provider both`. Add a configurable `tsc_only` knob on the TypeScript codeanalyzer config that passes `--tsc-only` (codeanalyzer-typescript >= 0.4.2) to pin the resolver-based call graph. Materialize Jelly-resolved anonymous callbacks as `TSSynthesizedCallable` so anonymous call-graph edges don't dangle. Wire `get_synthesized_callables` through the in-process, Neo4j, and facade backends, and add the nodes to the NetworkX call graph. Bump codeanalyzer-typescript 0.4.0 -> 0.4.3. Closes #174
…d) on the Neo4j backend The existence check is keyed off the path, not the backend: any non-None project_path is resolved and must be a directory on every backend, while None skips validation entirely (the Neo4j backends read their graph out of band over Bolt). Spell this out in `_normalize_project_path`, the java/python/typescript factory docstrings, and the README Neo4j example.
rahlk
added a commit
that referenced
this pull request
Jun 27, 2026
The lockfile still pinned codeanalyzer-typescript 0.4.0 while pyproject was bumped to 0.4.3 (#179); regenerate so the two agree. No runtime deps added (black stays in the test dependency group, not runtime).
9 tasks
rahlk
added a commit
that referenced
this pull request
Jun 27, 2026
…181) * feat(python): add bulk/projected accessors to avoid N+1 reconstruction Add set-at-a-time, field-projected reads to the Python facade so callers can enumerate the application in one round-trip instead of paying the per-entity reconstruction get_all_methods_in_application() does (tens of thousands of Bolt round-trips on large apps via the Neo4j backend). New `PyCallableOverview` projection model and three accessors on the PythonAnalysisBackend ABC, both backends, and the facade: - get_callables_overview() -> List[PyCallableOverview]: every callable (methods, module-level and nested functions) as a lightweight projection. - get_method_bodies(signatures) -> Dict[str, str]: batch source-body fetch. - get_decorated_callables(markers) -> List[PyCallableOverview]: overviews filtered by decorator (fills the get_methods_with_decorators gap). The in-process and Neo4j backends enumerate the same callable set (a "method" is one a class declares directly, mirroring PY_HAS_METHOD). Offline unit tests cover the in-process walk; the Neo4j test module asserts byte-for-byte parity against it when a server is reachable. Refs #180 * perf(python): reuse one Neo4j read session instead of one per query PyNeo4jBackend._run opened a fresh driver session on every call, so the N+1 reconstruction fan-out (get_symbol_table / get_all_methods_in_application) paid session-acquisition overhead on each of its tens of thousands of queries. Reuse a single lazily-opened session for the backend's lifetime, dropping it on error so the next call reopens cleanly. Closed in close(). Refs #180 * chore: sync uv.lock with codeanalyzer-typescript 0.4.3 The lockfile still pinned codeanalyzer-typescript 0.4.0 while pyproject was bumped to 0.4.3 (#179); regenerate so the two agree. No runtime deps added (black stays in the test dependency group, not runtime). * feat(python): add get_callsites_for batch accessor (#180 item 3) Batch call-site fetch keyed by owning signature, the last of the four bulk accessors from #180. One projected Cypher statement on the Neo4j backend (an OPTIONAL MATCH over PY_HAS_CALLSITE so an existing callable with no call sites still gets an empty-list entry, matching the in-process backend); one symbol-table walk in-process. Added to the ABC, both backends, and the facade, with offline and Neo4j-parity test coverage. Refs #180
rahlk
added a commit
that referenced
this pull request
Jun 27, 2026
Minor release: new backward-compatible API since v1.2.0. - Python facade bulk/projected accessors (get_callables_overview, get_method_bodies, get_decorated_callables, get_callsites_for) + the PyCallableOverview model (#181). - TypeScript tsc_only toggle (TSCodeAnalyzerConfig) and synthesized anonymous callables (TSSynthesizedCallable, get_synthesized_callables) (#179). - Neo4j Python backend reuses a single read session. - codeanalyzer-typescript 0.4.0 -> 0.4.3.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Make the TypeScript backend's call-graph intent explicit and stop riding the obsolete
--call-graph-provider bothdefault, and materialize the anonymous callbacks the Jelly resolver produces so call-graph edges to them don't dangle.Motivation and Context
Per #174, the
cants(codeanalyzer-typescript) binary's--call-graph-provider <tsc|jelly|both>machinery is obsolete — the resolver-basedtscpath is the only supported direction. The SDK never passed the flag, so it implicitly rode the binary default. This surfaces an explicittsc_onlyknob (--tsc-only) instead.Separately, the Jelly resolver emits call edges to first-party anonymous callbacks that the symbol table never names (the canonicalizer returns
nullfor them). Those edges previously pointed at nodes that didn't exist. This adds a slimTSSynthesizedCallable(mirroringTSExternalSymbol) keyed by the synthesized<enclosing-signature>:<line:col>so the edges resolve. Thetscresolver emits an empty map.Closes #174.
How Has This Been Tested?
tsc_only=True(passes--tsc-only) and default (Jelly) — call graph builds with no dangling anonymous/external nodes.:AnonymousCallablenodes scoped to the application's modules.Breaking Changes
None.
tsc_onlydefaults toFalse(binary chooses its default);synthesized_callablesdefaults to an empty map, so existing call-graph consumers are unaffected.TSBackendgainsTSCodeAnalyzerConfigas the first union member while remaining backward-compatible with a bareCodeAnalyzerConfig.Types of changes
Checklist
Additional context
TSCodeAnalyzerConfig(tsc_only: bool = False)incldk/analysis/commons/backend_config.py, added to theTSBackendunion and threaded throughTypeScriptAnalysisviagetattr(..., "tsc_only", False).TSSynthesizedCallable(+TSApplication.synthesized_callables), withget_synthesized_callables()added to theTSAnalysisBackendABC and implemented for the in-process and Neo4j backends (:AnonymousCallablenode +R.synthesizedreconstructor).codeanalyzer-typescriptpinned0.4.0 -> 0.4.3in bothdependenciesand[tool.backend-versions];--tsc-onlyrequires>= 0.4.2.