Skip to content

feat(neo4j): import/export bindings, parameters_json and unresolved config reads (#182) - #183

Merged
rahlk merged 4 commits into
mainfrom
feat/issue-182-neo4j-bindings
Sep 7, 2026
Merged

feat(neo4j): import/export bindings, parameters_json and unresolved config reads (#182)#183
rahlk merged 4 commits into
mainfrom
feat/issue-182-neo4j-bindings

Conversation

@rahlk

@rahlk rahlk commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Closes #182. Spec: docs/design/specs/neo4j-bindings-parameters-config.md (decisions D1–D6, mirrored in .claude/SCHEMA_DECISIONS.md). Additive on Neo4j contract 2.0.0; ships in 1.4.0.

What changes

analysis.json Neo4j
imports TSImport.resolved_module — the compiler's answer (ts.resolveModuleName, tsconfig paths, directory index, .js.ts), absent for externals/builtins/unresolvable; a per-run stamp over cached modules too (syntactic_analysis/moduleResolution.ts), since tsconfig and target existence are state the content-hash cache cannot see TS_IMPORTS :TSModule → :TSModule | :TSExternal, ONE per (module, target): spellings[], imported_names[], aliases[], type_only_names[]; externals on the @external/<package root> ghost TS_PROVIDES/TS_UNRESOLVED_IMPORT already address; unresolved relative spellings dropped (python's rule)
exports TSExport.resolved_module on re-exports; export { type X } per-specifier flag now honoured TS_RE_EXPORTS aggregated like imports (exported_names[], "*" for star); exports_json on :TSModule (verbatim list, absent when empty)
parameters parameters_json on :TSCallable, python's encoding (verbatim list, absent when empty). Measured 430 KB = 1.4 % of graph.cypher on cants self
config reads TS_READS_CONFIG_UNRESOLVED :TSApplication → :TSExternal | :TSCallable, key/reason/prov, _k = key|reason, no site (python's documented per-site collapse)

Corrects the issue as filed: TS_USES_CONFIG was already projected; only the unresolved counterpart was missing.

Why ts.resolveModuleName and not ts-morph's getModuleSpecifierSourceFile()

The ts-morph route goes through the module symbol, which a side-effect-imported script with no import/export of its own never has — import "./polyfill" came back unresolved. The compiler resolver answers every specifier the way tsc does. One ModuleResolutionCache per project.

Incremental Bolt ceiling (recorded in the spec)

A binding edge's presence depends on the target existing, so an edge that flips absent → present while the importer is byte-identical (target file added, shard widened) is computed but filtered by the changed-owner rule and not written until the importer changes or the push is --eager. Same class as TS_CALLS; the removal direction is covered by the container test.

Tests

  • test/neo4j-bindings.test.ts (new): a cache-persistence case (target added later, paths edited, target removed — importer cached throughout); a temp project with paths alias, directory index, .js.ts, side-effect, import type/{ type X }, external, builtin, missing relative, star/named/aliased/type-only re-exports, local export { x as y }; parameters incl. optional/rest; unresolved reads on artifacts-app with the _k rule.
  • test/schema-v2.test.ts: the exhaustive edge-accounting gate learns the three aggregated families (distinct-pair / distinct-triple counts restated from JSON).
  • test/neo4j-bolt.test.ts (container, ran locally, 6 pass): edges land live; a stale TS_IMPORTS edge to a vanished target survives a default push and goes with the target under --eager.
  • schema.neo4j.json regenerated; conformance green. bun test: 325 pass.

Propagation

  • python-sdk leg 2.5b: get_imports/get_exports/get_method_parameters/get_config_readers can answer; pin moves to the release carrying this. reconstruct.callable_ already decodes parameters_json.
  • codeanalyzer-java #231: spell the config edge JAVA_READS_CONFIG_UNRESOLVED with _k = key|reason (comment posted). Java already has J_IMPORTS and parameters_json.

…onfig reads reach the graph (#182)

resolved_module on TSImport/TSExport (ts.resolveModuleName at build time, per-project
resolution cache); TS_IMPORTS / TS_RE_EXPORTS aggregated per (module, target) with
spellings/names/aliases/type_only_names; exports_json on :TSModule; parameters_json on
:TSCallable; TS_READS_CONFIG_UNRESOLVED app -> ghost/callee keyed key|reason. Contract stays
2.0.0 (additive). export { type X } per-specifier flags now honoured.
… review follow-ups (#182)

Moves resolution out of the builder into syntactic_analysis/moduleResolution.ts, re-stamped
every run (tsconfig paths and target existence are state the content-hash cache cannot see).
Folds prov across collapsed unresolved-read sites; the accounting test enumerates the new
ghost sources; the bolt-writer absent->present ceiling is recorded in the spec.
@rahlk
rahlk merged commit 45f3d39 into main Sep 7, 2026
1 check passed
@rahlk
rahlk deleted the feat/issue-182-neo4j-bindings branch September 7, 2026 21:19
@rahlk rahlk mentioned this pull request Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Neo4j projection omits import/export bindings, callable parameters, and config-read edges

1 participant