Skip to content

Conversation

@DaxServer
Copy link
Owner

This commit introduces a comprehensive type dependency traversal implementation
that combines AST traversal, dependency collection, and analysis. The key
changes are:

  • Implement DependencyTraversal class that manages the dependency graph using
    Graphology library
  • Add methods to extract interface and type alias references from type
    declarations
  • Introduce TypeReferenceExtractor interface to allow customization of type
    reference extraction
  • Implement ProcessingOrderResult to analyze the optimal processing order for
    interfaces and type aliases

These changes enable efficient management of type dependencies, which is
crucial for generating code that respects the correct order of type
declarations.

…raversal

This commit introduces a comprehensive type dependency traversal implementation
that combines AST traversal, dependency collection, and analysis. The key
changes are:

- Implement `DependencyTraversal` class that manages the dependency graph using
  Graphology library
- Add methods to extract interface and type alias references from type
  declarations
- Introduce `TypeReferenceExtractor` interface to allow customization of type
  reference extraction
- Implement `ProcessingOrderResult` to analyze the optimal processing order for
  interfaces and type aliases

These changes enable efficient management of type dependencies, which is
crucial for generating code that respects the correct order of type
declarations.
@coderabbitai
Copy link

coderabbitai bot commented Aug 27, 2025

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Introduced graph-based dependency traversal with export-aware ordering.
    • Added getTopologicallySortedTypesWithPreference() for prioritized sorting.
    • Added reset/clearCache methods to improve cache hygiene.
  • Performance
    • Improved caching strategy, O(1) lookups, and parser reuse for faster generation.
  • Refactor
    • Consolidated multiple analyzers into a single, unified traversal API.
  • Documentation
    • Updated architecture to describe the new graph-centric, phase-based design.
  • Chores
    • Added Graphology-related dependencies.
  • Tests
    • Adjusted expectations for export order in specific cases; reorganized suites.

Walkthrough

Replaces the Map-based DependencyCollector/Analyzer/ASTTraversal with a Graphology-backed DependencyTraversal. Updates codegen to use the new traversal phases and methods, adjusts package dependencies, removes old traversal utilities, and updates tests (removals, new traversal unit tests, revised expectations, commented scaffolds).

Changes

Cohort / File(s) Summary
Architecture Docs
ARCHITECTURE.md
Documents shift to Graphology-based DependencyTraversal, phase-separated lifecycle, export-aware ordering, caching strategy, API renames/additions.
Dependency Traversal Refactor
src/traverse/dependency-collector.ts, src/traverse/dependency-analyzer.ts, src/traverse/ast-traversal.ts, src/traverse/dependency-type.ts, src/traverse/dependency-traversal.ts
Removes legacy collector/analyzer/AST helpers and old type extractor. Adds dependency-traversal.ts with graph-based traversal, interfaces, and APIs: import collection, local type addition, processing-order analysis, filtering, topological sort, cache reset.
Codegen Integration
src/ts-morph-codegen.ts
Rewires to DependencyTraversal: replaces analyzer/collector usage, adds filtering step, uses traversal’s topological ordering and reference extraction, adjusts processing phases and control flow.
Package Dependencies
package.json
Adds dependencies: graphology, graphology-dag, graphology-traversal; devDependency graphology-types. No script changes.
Tests — Removed Old Collector Suites
tests/dependency-collector.integration.test.ts, tests/dependency-collector.performance.test.ts, tests/dependency-ordering.test.ts
Deletes integration, performance, and ordering tests tied to DependencyCollector.
Tests — Updated/Adjusted
tests/traverse/dependency-collector.unit.test.ts, tests/import-resolution.test.ts, tests/export-everything.test.ts
Converts unit tests to DependencyTraversal and updates imports/constructors; removes DependencyCollector cache reset; updates expectation order in export-everything test.
Tests — New Commented Scaffolds
tests/traverse/dependency-collector.integration.test.ts, tests/traverse/dependency-collector.performance.test.ts, tests/traverse/dependency-ordering.test.ts
Adds commented-out scaffolds mirroring previous integration/performance/ordering scenarios; no executable tests added.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Codegen as ts-morph-codegen
  participant Traversal as DependencyTraversal
  participant Resolver as FileResolver
  participant Graph as Graphology DirectedGraph

  User->>Codegen: generate(project, sourceFile, options)
  Codegen->>Traversal: new DependencyTraversal(...)
  Codegen->>Traversal: addLocalTypes(localTypeAliases, sourceFile)
  Codegen->>Traversal: collectFromImports(importDeclarations)
  Traversal->>Resolver: resolve(moduleSpecifier)
  Resolver-->>Traversal: SourceFile | undefined
  Traversal->>Graph: add nodes/edges (types, refs)
  Codegen->>Traversal: analyzeProcessingOrder(typeAliases, interfaces)
  Codegen->>Traversal: filterUnusedImports() [if !exportEverything]
  Codegen->>Traversal: getTopologicallySortedTypes(exportEverything)
  Traversal->>Graph: topological sort (graphology-dag)
  Traversal-->>Codegen: ordered TypeDependency[]
  Codegen-->>User: emit types in sorted order
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–90 minutes

Possibly related PRs

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch graphology

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
ARCHITECTURE.md (1)

369-397: Outdated references to “DependencyCollector” and related tests.

This section documents “DependencyCollector Optimizations” and mentions tests/dependency-collector.performance.test.ts, which conflict with the Graphology-only architecture and removed modules.

Proposed clean-up:

  • Replace “DependencyCollector Optimizations” with “DependencyTraversal Optimizations” or remove if redundant.
  • Update/remove performance test references to match current files, or add an equivalent dependency-traversal.performance.test.ts.

I can draft the updated performance section once you confirm the current test filenames.

tests/traverse/dependency-collector.integration.test.ts (1)

1-430: Port or remove lingering DependencyCollector references

The rg sweep shows that remnants of the deleted DependencyCollector API still exist in the codebase:

  • tests/traverse/dependency-collector.integration.test.ts
  • tests/traverse/dependency-collector.performance.test.ts
  • ARCHITECTURE.md (sections “DependencyCollector” and “DependencyCollector Optimizations”)

These files currently target an API that no longer exists, which adds noise and will break CI. You should either fully migrate these to the new DependencyTraversal API or delete them until you’re ready to reintroduce traversal tests.

Action items:

  • In each test file:
    • Replace imports of DependencyCollector with DependencyTraversal.
    • Update instantiation: const traversal = new DependencyTraversal().
    • Swap out calls to collector.collectFromImports(...) and cache-clearing methods for the equivalent traversal methods (e.g. traversal.collectFromImports(...) + traversal.getTopologicallySortedTypes() and any traversal reset calls).
    • Remove or adapt any now-obsolete cache-clear calls (DependencyCollector.clearGlobalCache()).
  • In ARCHITECTURE.md:
    • Update the “DependencyCollector” headings and links to refer to DependencyTraversal, or remove those sections if documentation isn’t yet available.
  • After refactoring, re-run:
    rg -n -e '\bDependencyCollector\b' -e 'dependency-collector'
    to confirm no stray references remain.
🧹 Nitpick comments (21)
tests/traverse/dependency-collector.performance.test.ts (7)

1-341: Replace dead, legacy scaffold with a skipped, minimal DependencyTraversal perf suite (or delete the file).

All code is commented out and targets the removed DependencyCollector, yielding zero coverage and future drift. Convert to a small, skipped scaffold referencing DependencyTraversal so the intent is preserved without flakiness, or remove the file entirely.

Apply this diff to replace the commented content with a gated, skipped scaffold aligned to the new API:

-// import { DependencyCollector } from '@daxserver/validation-schema-codegen/traverse/dependency-collector'
-// import { createSourceFile } from '@test-fixtures/utils'
-// import { beforeEach, describe, expect, test } from 'bun:test'
-// import { Project } from 'ts-morph'
-//
-// describe('DependencyCollector Performance Tests', () => {
-//   let project: Project
-//   let collector: DependencyCollector
-//
-//   beforeEach(() => {
-//     project = new Project()
-//     collector = new DependencyCollector()
-//   })
-//
-//   ... (all commented tests)
-// })
+import { beforeEach, describe, test } from 'bun:test'
+import { Project } from 'ts-morph'
+// Note: wire this when DependencyTraversal API is finalized in this PR
+// import { DependencyTraversal } from '@daxserver/validation-schema-codegen/traverse/dependency-traversal'
+// import { createSourceFile } from '@test-fixtures/utils'
+
+// Gate perf on env and keep it skipped by default to avoid CI flakiness.
+const PERF_ENABLED = process.env.RUN_PERF_TESTS === '1'
+const maybeDescribe = PERF_ENABLED ? describe : describe.skip
+
+maybeDescribe('DependencyTraversal performance (ported from legacy collector) [PERF]', () => {
+  let project: Project
+  // let traversal: DependencyTraversal
+
+  beforeEach(() => {
+    project = new Project()
+    // traversal = new DependencyTraversal(/* extractor/config */)
+  })
+
+  test.todo('deep import chains (50 files)')
+  test.todo('wide import trees (100 imports)')
+  test.todo('cache key overhead (20 complex types x5 passes)')
+  test.todo('memory with large cache (200 files)')
+  test.todo('diamond pattern revisits (base/left/right + 30 leaves)')
+  test.todo('complex topological sort (web of 50 types)')
+  test.todo('large type definitions (50 x 100 fields)')
+  test.todo('graph operations stress (100 nodes)')
+})

6-14: Don’t keep commented describe/beforeEach; either skip or gate.

Use describe.skip or an env gate to prevent accidental activation and CI flakiness while keeping tests visible to maintainers.


15-70: Prefer benchmarks over timing assertions in unit tests.

Hard time thresholds are brittle across CI. If you need performance tracking, move these to Bun benchmarks.

Example benchmark (new file suggestion, not a direct diff here):

import { bench, run } from 'mitata' // or Bun's built-in bench when available
bench('deep import chain (50)', () => {
  // setup synthetic files, run traversal, assert counts outside timing
})
await run()

72-168: Cache-oriented tests need new measurement points.

The graphology-backed design won’t mirror “collector cache” behavior. Measure graph node/edge counts and traversal order size instead of Map/cache timings.


170-221: Diamond dependency: validate single-visit semantics via traversal order, not import scans.

With the graph, assert that base is not redundantly processed by checking the processing order or visit counts exposed by ProcessingOrderResult.


222-263: Complex topo sort: assert on ProcessingOrderResult invariants.

Replace dependencies.length checks with:

  • All edges go from earlier to later in the order.
  • Order contains expected subset/superset of nodes.

265-341: Memory-heavy scenarios: keep opt-in and small by default.

Generating 50x100-field types and 200-file graphs can destabilize CI. Keep behind RUN_PERF_TESTS=1 and consider smaller defaults with a larger locally-run variant.

Optional gating pattern (additive to the main diff if you keep individual tests active later):

if (process.env.RUN_PERF_TESTS !== '1') test.skip('large type definitions (50 x 100 fields)', () => {})
package.json (1)

36-41: Consider pinning Graphology versions for determinism.

Caret ranges are fine; if traversal order determinism matters across CI nodes, pinning exact versions reduces flakiness from transitive updates.

ARCHITECTURE.md (3)

118-151: Remove or clearly scope legacy “Collector”/multi-mechanism references.

This section claims a single, unified Graphology mechanism, but later the doc still references multiple trackers and caches outside the graph model. Clarify that any caches (e.g., on nodes) are graph-backed, or drop references that imply parallel systems.


160-166: Confirm Interface inheritance uses Type.Composite in code.

Doc states InterfaceTypeHandler emits Type.Composite([Base, Type.Object(...)]). Verify implementation and update examples if it still uses Type.Intersect.

If using Composite, add a short example snippet to this section to cement expected output.


322-341: Minor: tighten repetition in Graphology optimization bullets.

These bullets repeat earlier claims. Consider consolidating to reduce length and improve scanability.

tests/traverse/dependency-ordering.test.ts (1)

1-93: Avoid committed fully-commented test files; either enable or drop.

As-is, this adds no coverage. Prefer enabling at least the first test, or delete until ready to run.

Apply this minimal diff to enable the first test and keep the second as a TODO:

-// import { formatWithPrettier, generateFormattedCode } from '@test-fixtures/utils'
-// import { beforeEach, describe, expect, test } from 'bun:test'
-// import { Project } from 'ts-morph'
+import { formatWithPrettier, generateFormattedCode } from '@test-fixtures/utils'
+import { beforeEach, describe, expect, test } from 'bun:test'
+import { Project } from 'ts-morph'

-// describe('Dependency Ordering Bug', () => {
-//   let project: Project
+describe('Dependency Ordering', () => {
+  let project: Project

-//   beforeEach(() => {
-//     project = new Project()
-//   })
+  beforeEach(() => {
+    project = new Project()
+  })

-//   test('should define StringSnakDataValue before using it', () => {
+  test('should define StringSnakDataValue before using it', () => {
-//     const sourceFile = project.createSourceFile(
+    const sourceFile = project.createSourceFile(
-//       'test.ts',
-//       `
+      'test.ts',
+      `
-//         export type CommonsMediaSnakDataValue = StringSnakDataValue;
-//         export type StringSnakDataValue = {
+        export type CommonsMediaSnakDataValue = StringSnakDataValue;
+        export type StringSnakDataValue = {
-//           value: string;
-//           type: 'string';
-//         };
-//       `,
-//     )
+          value: string;
+          type: 'string';
+        };
+      `,
+    )

-//     expect(generateFormattedCode(sourceFile, true)).resolves.toBe(
+    expect(generateFormattedCode(sourceFile, true)).resolves.toBe(
-//       formatWithPrettier(`
+      formatWithPrettier(`
-//         export const StringSnakDataValue = Type.Object({
+        export const StringSnakDataValue = Type.Object({
-//           value: Type.String(),
-//           type: Type.Literal('string'),
-//         });
+          value: Type.String(),
+          type: Type.Literal('string'),
+        });
 
-//         export type StringSnakDataValue = Static<typeof StringSnakDataValue>;
+        export type StringSnakDataValue = Static<typeof StringSnakDataValue>;
 
-//         export const CommonsMediaSnakDataValue = StringSnakDataValue;
+        export const CommonsMediaSnakDataValue = StringSnakDataValue;
 
-//         export type CommonsMediaSnakDataValue = Static<typeof CommonsMediaSnakDataValue>;
-//       `),
-//     )
-//   })
+        export type CommonsMediaSnakDataValue = Static<typeof CommonsMediaSnakDataValue>;
+      `),
+    )
+  })
 
-//   test('should handle complex dependency chains correctly', () => {
+  // test('should handle complex dependency chains correctly', () => {
+  //   // TODO: enable after traversal ordering is finalized
+  // })
-// })
+})
tests/traverse/dependency-collector.unit.test.ts (3)

1-5: Tighten type-only imports

DefaultFileResolver is only used for a type-cast; prefer importing just FileResolver and cast to that.

-import type {
-  DefaultFileResolver,
-  FileResolver,
-} from '@daxserver/validation-schema-codegen/traverse/dependency-file-resolver'
+import type {
+  FileResolver,
+} from '@daxserver/validation-schema-codegen/traverse/dependency-file-resolver'

34-37: Cast to the interface, not the concrete class

Avoid coupling the test to the default implementation; cast to FileResolver.

-      const mockFileResolver = {} as DefaultFileResolver
+      const mockFileResolver = {} as FileResolver

162-177: Test name misleads (no topo assertions made)

This test doesn’t validate topological ordering—only collection. Either rename or add assertions using real ts-morph nodes in a future test.

-    test('should handle dependency resolution', () => {
+    test('should add local types without errors', () => {
src/ts-morph-codegen.ts (3)

113-116: Remove duplicate unused-import filtering

getTopologicallySortedTypes(false) already calls filterUnusedImports(). The extra call is redundant.

-  // Filter unused imports if exportEverything is false
-  if (!exportEverything) {
-    dependencyTraversal.filterUnusedImports()
-  }

117-118: Guard against cycles in type aliases

Topological sort will throw on cycles. Add a safe fallback with a clear error or degrade gracefully.

-  const orderedDependencies = dependencyTraversal.getTopologicallySortedTypes(exportEverything)
+  let orderedDependencies: ReturnType<typeof dependencyTraversal.getTopologicallySortedTypes>
+  try {
+    orderedDependencies = dependencyTraversal.getTopologicallySortedTypes(exportEverything)
+  } catch (err) {
+    // Fallback: emit in insertion order; consider surfacing a diagnostic to the caller.
+    orderedDependencies = [...dependencyTraversal.getDependencies().values()]
+  }

129-141: Avoid remapping type aliases inside the loop

Precompute the map once to reduce allocations.

-    orderedDependencies.forEach((dependency) => {
+    const localTypeAliasMap = new Map(localTypeAliases.map((ta) => [ta.getName(), ta]))
+    orderedDependencies.forEach((dependency) => {
       const interfaceDependsOnThis = dependencyAnalysis.interfacesDependingOnTypeAliases.some(
         (interfaceName) => {
           const interfaceDecl = interfaces.find((i) => i.getName() === interfaceName)
           if (!interfaceDecl) return false
-          const typeAliasRefs = dependencyTraversal.extractTypeAliasReferences(
-            interfaceDecl,
-            new Map(localTypeAliases.map((ta) => [ta.getName(), ta])),
-          )
+          const typeAliasRefs = dependencyTraversal.extractTypeAliasReferences(
+            interfaceDecl,
+            localTypeAliasMap,
+          )
           return typeAliasRefs.includes(dependency.typeAlias.getName())
         },
       )
src/traverse/dependency-traversal.ts (3)

399-414: Topological sort can throw on cycles; handle gracefully

Provide a safer sort to avoid crashing on cyclic type aliases.

-    const sortedNodes = topologicalSort(this.dependencyGraph)
+    let sortedNodes: string[]
+    try {
+      sortedNodes = topologicalSort(this.dependencyGraph)
+    } catch (err) {
+      // Fallback: maintain current node order; optionally expose diagnostics upstream.
+      sortedNodes = (this.dependencyGraph.nodes() as string[]) ?? []
+    }

155-182: Duplicate type-reference traversal logic

extractTypeReferences duplicates DefaultTypeReferenceExtractor.extractTypeReferences. Consider delegating to the injected extractor for consistency and single source of truth.


204-245: Potential node-id collisions between file paths and type names

Files use raw filePath as node ids; a type alias named like a path could collide. Consider namespacing ids (e.g., file:/... vs type:Name) to harden the graph.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between dea3c9c and de868d5.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (17)
  • ARCHITECTURE.md (4 hunks)
  • package.json (2 hunks)
  • src/traverse/ast-traversal.ts (0 hunks)
  • src/traverse/dependency-analyzer.ts (0 hunks)
  • src/traverse/dependency-collector.ts (0 hunks)
  • src/traverse/dependency-traversal.ts (1 hunks)
  • src/traverse/dependency-type.ts (0 hunks)
  • src/ts-morph-codegen.ts (5 hunks)
  • tests/dependency-collector.integration.test.ts (0 hunks)
  • tests/dependency-collector.performance.test.ts (0 hunks)
  • tests/dependency-ordering.test.ts (0 hunks)
  • tests/export-everything.test.ts (1 hunks)
  • tests/import-resolution.test.ts (0 hunks)
  • tests/traverse/dependency-collector.integration.test.ts (1 hunks)
  • tests/traverse/dependency-collector.performance.test.ts (1 hunks)
  • tests/traverse/dependency-collector.unit.test.ts (9 hunks)
  • tests/traverse/dependency-ordering.test.ts (1 hunks)
💤 Files with no reviewable changes (8)
  • tests/dependency-collector.performance.test.ts
  • src/traverse/dependency-analyzer.ts
  • tests/dependency-ordering.test.ts
  • tests/import-resolution.test.ts
  • src/traverse/ast-traversal.ts
  • tests/dependency-collector.integration.test.ts
  • src/traverse/dependency-type.ts
  • src/traverse/dependency-collector.ts
🧰 Additional context used
🧬 Code graph analysis (3)
src/traverse/dependency-traversal.ts (1)
src/traverse/dependency-file-resolver.ts (2)
  • FileResolver (3-8)
  • DefaultFileResolver (10-26)
tests/traverse/dependency-collector.unit.test.ts (2)
src/traverse/dependency-traversal.ts (1)
  • DependencyTraversal (37-605)
src/traverse/dependency-file-resolver.ts (1)
  • DefaultFileResolver (10-26)
src/ts-morph-codegen.ts (1)
src/traverse/dependency-traversal.ts (1)
  • DependencyTraversal (37-605)
🪛 LanguageTool
ARCHITECTURE.md

[grammar] ~107-~107: There might be a mistake here.
Context: ...y ordering with export-aware preferences - Uses graphology-dag for circular depende...

(QB_NEW_EN)


[grammar] ~108-~108: There might be a mistake here.
Context: ...ndency detection and topological sorting - Handles complex dependency scenarios inc...

(QB_NEW_EN)


[grammar] ~113-~113: There might be a mistake here.
Context: ...es code with appropriate export handling - Types are processed sequentially in the ...

(QB_NEW_EN)


[grammar] ~136-~136: There might be a mistake here.
Context: ...a structure for dependency relationships - Topological Sorting: Employs `topologi...

(QB_NEW_EN)


[grammar] ~137-~137: There might be a mistake here.
Context: ...ering with circular dependency detection - Preference-Based Ordering: Implements ...

(QB_NEW_EN)


[grammar] ~138-~138: There might be a mistake here.
Context: ...erence()` for export-aware type ordering - Memory Efficiency: Direct Graphology u...

(QB_NEW_EN)


[grammar] ~139-~139: There might be a mistake here.
Context: ...y management for large dependency graphs - Type Safety: Full TypeScript support t...

(QB_NEW_EN)


[grammar] ~328-~328: There might be a mistake here.
Context: ...ted graph data structures and algorithms - Optimized Performance: Benefits from G...

(QB_NEW_EN)


[grammar] ~329-~329: There might be a mistake here.
Context: ...nal implementations for graph operations - Advanced Graph Algorithms: Direct acce...

(QB_NEW_EN)


[grammar] ~330-~330: There might be a mistake here.
Context: ...m (graphology-dag, graphology-traversal) - Type Safety: Full TypeScript support t...

(QB_NEW_EN)


[grammar] ~331-~331: There might be a mistake here.
Context: ...support through graphology-types package - Memory Efficiency: Graphology's optimi...

(QB_NEW_EN)


[grammar] ~332-~332: There might be a mistake here.
Context: ...mized memory management for large graphs - Unified Architecture: Single module el...

(QB_NEW_EN)

🔇 Additional comments (6)
tests/traverse/dependency-collector.performance.test.ts (1)

1-5: Update imports to use DependencyTraversal and existing test utilities

The DependencyCollector import has been replaced by the new DependencyTraversal class (exported in src/traverse/dependency-traversal.ts), and the test fixtures under @test-fixtures/utils are already in use elsewhere. Please update the commented imports in tests/traverse/dependency-collector.performance.test.ts (and similarly in the integration test) to the following:

import { DependencyTraversal } from '@daxserver/validation-schema-codegen/traverse/dependency-traversal'
import { createSourceFile }           from '@test-fixtures/utils'
import { beforeEach, describe, expect, test } from 'bun:test'
import { Project }                    from 'ts-morph'
package.json (1)

18-18: Add: graphology-types devDependency — looks good.

Type definitions in devDependencies are appropriate. No issues.

tests/export-everything.test.ts (1)

80-82: Reordering expectation updated — OK.

This matches a topo order that prefers imported types first. Ensure the traversal keeps a stable tie-break to avoid nondeterministic reorders across runs.

If not already, sort adjacency lists (or node IDs) before topological sorting to guarantee stable output when multiple valid orders exist.

ARCHITECTURE.md (2)

78-89: Good: clear “DependencyTraversal” overview.

Section accurately explains the Graphology-centric approach and export-aware ordering.


99-117: Fix bullet/formatting glitches in the three-phase description.

Several bullets render on the same line (e.g., “ordering with export-aware preferences - Uses graphology-dag ...”). Insert proper newlines so each bullet is separate.

Apply consistent Markdown list formatting; example:

- - Topological sorting with export-aware preferences    - Uses graphology-dag ...
+ - Topological sorting with export-aware preferences
+ - Uses graphology-dag for circular dependency detection and topological sorting

Likely an incorrect or invalid review comment.

tests/traverse/dependency-collector.unit.test.ts (1)

140-158: Circular import guard looks solid

Nice use of the resolver/mocked recursion to assert visit-short-circuiting.

Comment on lines +36 to +41
"type": "module",
"dependencies": {
"graphology": "^0.26.0",
"graphology-dag": "^0.4.1",
"graphology-traversal": "^0.3.1"
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify Graphology ESM/CJS interop under "type": "module".

Graphology packages have had mixed ESM/CJS stories. With "type": "module", confirm imports like import Graph from 'graphology' work in Bun/Node for your test/runtime environments.

Run:


🏁 Script executed:

#!/bin/bash
# Check all import sites for graphology libs and ensure only ESM-style imports are used
rg -nC2 -e "from 'graphology" -e "from 'graphology-(dag|traversal)'" --type=ts

# If unsure about module format, consult upstream quickly:

Length of output: 546


🌐 Web query:

Do graphology@0.26.0, graphology-dag@0.4.1, and graphology-traversal@0.3.1 support ESM imports in Node when package.json has "type":"module"?

Error during web search


🏁 Script executed:

#!/bin/bash
set -e

echo "graphology@0.26.0 package.json relevant fields:"
curl -s https://unpkg.com/graphology@0.26.0/package.json | grep -E '"(main|module|exports)"' -B1 -A5

echo
echo "graphology-dag@0.4.1 package.json relevant fields:"
curl -s https://unpkg.com/graphology-dag@0.4.1/package.json | grep -E '"(main|module|exports)"' -B1 -A5

echo
echo "graphology-traversal@0.3.1 package.json relevant fields:"
curl -s https://unpkg.com/graphology-traversal@0.3.1/package.json | grep -E '"(main|module|exports)"' -B1 -A5

echo
echo "Import usage of graphology-traversal:"
rg -n "graphology-traversal" -C2 --type=ts || echo "No imports found"

Length of output: 1755


Graphology packages ESM/CJS support and required import adjustments

Based on the published package manifests:

  • graphology@0.26.0
    • Provides dual‐format builds:
    – “module”: dist/graphology.esm.js
    – “exports.import”: dist/graphology.mjs
    – “require”: dist/graphology.cjs.js
    → static import Graph from 'graphology' will load the ESM build under "type":"module".

  • graphology-dag@0.4.1 & graphology-traversal@0.3.1
    • Only declare "main": "index.js" with no "module" or "exports" entries
    → these are CJS‐only packages. Static ESM named imports (e.g. import { topologicalSort } from 'graphology-dag') may fail under Node’s ESM loader or in Bun.

Action items:

  • Confirm in your target runtimes (Node ≥14+, Bun) that all import sites still resolve as expected under "type":"module".
  • For CJS-only packages, switch to a default‐then‐destructure pattern if named imports error:
    import dag from 'graphology-dag';
    const { topologicalSort } = dag;
  • Alternatively, use dynamic import('graphology-dag') or adjust bundler settings to enable CJS–ESM interop where necessary.

Please update import statements or add compatibility shims so that the three packages load reliably in both Node and Bun under ESM.

🤖 Prompt for AI Agents
In package.json around lines 36 to 41, the review points out graphology is
dual-format ESM/CJS while graphology-dag and graphology-traversal are CJS-only,
which can break static ESM named imports under "type":"module"; update code so
imports are compatible: confirm behavior on target runtimes (Node ≥14+, Bun) and
replace any static named ESM imports from the CJS-only packages with a
default-then-destructure pattern or use dynamic import() where used, or add
bundler/CJS-interop shim; ensure any import sites that rely on named imports are
updated to first import the default and then destructure (or use await
import(...) in async contexts) so the packages load reliably under ESM.

Comment on lines +111 to +125
for (const typeParam of interfaceDecl.getTypeParameters()) {
const constraint = typeParam.getConstraint()
if (constraint) {
traverse(constraint)
}
}

for (const heritageClause of interfaceDecl.getHeritageClauses()) {
for (const typeNode of heritageClause.getTypeNodes()) {
traverse(typeNode)
}
}

return references
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Interface dependency extraction ignores member types

Currently only constraints/heritage are traversed; property/method/index signature types are missed, breaking dependency detection.

   for (const typeParam of interfaceDecl.getTypeParameters()) {
     const constraint = typeParam.getConstraint()
     if (constraint) {
       traverse(constraint)
     }
   }

   for (const heritageClause of interfaceDecl.getHeritageClauses()) {
     for (const typeNode of heritageClause.getTypeNodes()) {
       traverse(typeNode)
     }
   }
 
+  // Traverse interface members (properties, methods, index/call signatures, etc.)
+  for (const member of interfaceDecl.getMembers()) {
+    member.forEachChild(traverse)
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (const typeParam of interfaceDecl.getTypeParameters()) {
const constraint = typeParam.getConstraint()
if (constraint) {
traverse(constraint)
}
}
for (const heritageClause of interfaceDecl.getHeritageClauses()) {
for (const typeNode of heritageClause.getTypeNodes()) {
traverse(typeNode)
}
}
return references
}
for (const typeParam of interfaceDecl.getTypeParameters()) {
const constraint = typeParam.getConstraint()
if (constraint) {
traverse(constraint)
}
}
for (const heritageClause of interfaceDecl.getHeritageClauses()) {
for (const typeNode of heritageClause.getTypeNodes()) {
traverse(typeNode)
}
}
// Traverse interface members (properties, methods, index/call signatures, etc.)
for (const member of interfaceDecl.getMembers()) {
member.forEachChild(traverse)
}
return references
🤖 Prompt for AI Agents
In src/traverse/dependency-traversal.ts around lines 111 to 125, the interface
traversal only walks type parameter constraints and heritage clauses but skips
member signatures, so property types, method parameter/return types, index
signatures and call signatures are not traversed; update the function to iterate
over interfaceDecl.getMembers() and for each member handle PropertySignature
(traverse its typeNode), MethodSignature (traverse parameter types, return type,
and its type parameters' constraints), IndexSignature (traverse its parameter
types and return type) and CallSignature similarly, and for any member
recursively traverse any nested TypeNode(s) found (including
mapped/tuple/array/union/intersection nodes) so all referenced types are
captured before returning references.

Comment on lines +259 to +266
for (const typeAlias of typeAliases) {
typeAliasMap.set(typeAlias.getName(), typeAlias)
this.dependencyGraph.addNode(typeAlias.getName(), {
type: 'typeAlias',
declaration: typeAlias,
})
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Missing node attributes for type aliases during analysis lead to undefined flags later

Nodes added here lack sourceFile and isImported, causing downstream consumers to see undefined. Populate them.

-      this.dependencyGraph.addNode(typeAlias.getName(), {
-        type: 'typeAlias',
-        declaration: typeAlias,
-      })
+      this.dependencyGraph.addNode(typeAlias.getName(), {
+        type: 'typeAlias',
+        declaration: typeAlias,
+        sourceFile: typeAlias.getSourceFile(),
+        isImported: false,
+      })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (const typeAlias of typeAliases) {
typeAliasMap.set(typeAlias.getName(), typeAlias)
this.dependencyGraph.addNode(typeAlias.getName(), {
type: 'typeAlias',
declaration: typeAlias,
})
}
for (const typeAlias of typeAliases) {
typeAliasMap.set(typeAlias.getName(), typeAlias)
this.dependencyGraph.addNode(typeAlias.getName(), {
type: 'typeAlias',
declaration: typeAlias,
sourceFile: typeAlias.getSourceFile(),
isImported: false,
})
}
🤖 Prompt for AI Agents
In src/traverse/dependency-traversal.ts around lines 259-266, the nodes added
for type aliases lack the sourceFile and isImported attributes; update the
object passed to this.dependencyGraph.addNode(...) to include sourceFile: the
typeAlias.getSourceFile() (or its file path) and isImported: a boolean
indicating whether this alias comes from an external/imported file (compute by
comparing the alias's source file path to the current file being processed or by
using any existing helper like isImportedNode). Ensure both values are set for
every typeAlias so downstream consumers don't receive undefined.

Comment on lines +78 to +81
const dependencyAnalysis = dependencyTraversal.analyzeProcessingOrder(
localTypeAliases,
interfaces,
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Analysis mutates traversal graph; reset before collection to avoid stale/incomplete node attributes

analyzeProcessingOrder populates the graph with type aliases lacking sourceFile/isImported. Subsequent collection won’t update existing nodes, causing getTopologicallySortedTypes to yield undefined flags.

   const dependencyAnalysis = dependencyTraversal.analyzeProcessingOrder(
     localTypeAliases,
     interfaces,
   )
+
+  // Reset graph state before collection to ensure nodes carry complete attributes.
+  dependencyTraversal.clearCache()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const dependencyAnalysis = dependencyTraversal.analyzeProcessingOrder(
localTypeAliases,
interfaces,
)
const dependencyAnalysis = dependencyTraversal.analyzeProcessingOrder(
localTypeAliases,
interfaces,
)
// Reset graph state before collection to ensure nodes carry complete attributes.
dependencyTraversal.clearCache()
🤖 Prompt for AI Agents
In src/ts-morph-codegen.ts around lines 78-81, the call to
dependencyTraversal.analyzeProcessingOrder mutates the traversal graph and
leaves nodes with missing sourceFile/isImported, causing later collection to see
stale/undefined flags; fix by resetting or recreating the traversal graph before
performing the collection step (e.g., call a provided reset/clear method on
dependencyTraversal or instantiate a new traversal instance after
analyzeProcessingOrder) so that getTopologicallySortedTypes operates on a fresh
graph with correct node attributes.

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.

2 participants