Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions docs/src/content/docs/api/dependency-analyzer.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,125 @@ docs = terraform_analyzer.generate_resource_documentation(

* String containing the markdown documentation of resources

### GoDependencyAnalyzer

**Class: `GoDependencyAnalyzer`**
*(defined in `kit/dependency_analyzer/go_dependency_analyzer.py`)*

The `GoDependencyAnalyzer` extends the base `DependencyAnalyzer` to analyze Go codebases, focusing on package import relationships.

#### Additional Methods

##### `get_package_dependencies`

**Method: `GoDependencyAnalyzer.get_package_dependencies`**
*(defined in `kit/dependency_analyzer/go_dependency_analyzer.py`)*

Gets dependencies for a specific Go package.

```python
# Get direct dependencies
deps = go_analyzer.get_package_dependencies("github.com/myorg/myapp/pkg/server")

# Get all dependencies (including indirect)
all_deps = go_analyzer.get_package_dependencies(
"github.com/myorg/myapp/pkg/server",
include_indirect=True
)
```

**Parameters:**

* **`package_path`** (`str`, required):
Full import path of the package to check.
* **`include_indirect`** (`bool`, optional):
Whether to include indirect dependencies. Defaults to `False`.

**Returns:**

* List of package import paths this package depends on

### JavaScriptDependencyAnalyzer

**Class: `JavaScriptDependencyAnalyzer`**
*(defined in `kit/dependency_analyzer/javascript_dependency_analyzer.py`)*

The `JavaScriptDependencyAnalyzer` extends the base `DependencyAnalyzer` to analyze JavaScript and TypeScript codebases, supporting both ESM (`import`) and CommonJS (`require`) module systems.

#### Additional Methods

##### `get_module_dependencies`

**Method: `JavaScriptDependencyAnalyzer.get_module_dependencies`**
*(defined in `kit/dependency_analyzer/javascript_dependency_analyzer.py`)*

Gets dependencies for a specific JavaScript/TypeScript module.

```python
# Get direct dependencies
deps = js_analyzer.get_module_dependencies("src/index.js")

# Get all dependencies (including indirect)
all_deps = js_analyzer.get_module_dependencies(
"src/index.js",
include_indirect=True
)
```

**Parameters:**

* **`module_path`** (`str`, required):
Path to the module file.
* **`include_indirect`** (`bool`, optional):
Whether to include indirect dependencies. Defaults to `False`.

**Returns:**

* List of module paths/package names this module depends on

##### `generate_dependency_report`

**Method: `JavaScriptDependencyAnalyzer.generate_dependency_report`**
*(defined in `kit/dependency_analyzer/javascript_dependency_analyzer.py`)*

Generates a comprehensive dependency report for the repository.

```python
report = js_analyzer.generate_dependency_report(
output_path="dependency_report.json"
)
```

**Parameters:**

* **`output_path`** (`str`, optional):
Path to save the report JSON. If `None`, returns the report data without saving.

**Returns:**

* Dictionary with the complete dependency report including:
* Package name (from package.json)
* Internal module count
* External package count
* Node.js built-in usage
* Detected cycles
* High-dependency modules

#### Supported Import Styles

The JavaScript analyzer detects:
- ESM imports: `import x from 'pkg'`, `import { x } from 'pkg'`
- ESM re-exports: `export { x } from 'pkg'`, `export * from 'pkg'`
- CommonJS: `require('pkg')`
- Dynamic imports: `import('pkg')`

#### Dependency Classification

Dependencies are classified as:
- **internal**: Relative imports (`./`, `../`)
- **external**: npm packages (including scoped `@org/pkg`)
- **node_builtin**: Node.js built-in modules (`fs`, `path`, `http`, etc.)

## Key Features and Notes

- All dependency analyzers store absolute file paths for resources, making it easy to locate components in complex codebases with files that might have the same name in different directories.
Expand All @@ -363,3 +482,5 @@ docs = terraform_analyzer.generate_resource_documentation(
- Visualizations require the Graphviz software to be installed on your system.

- The dependency graph is built on first use and cached. If the codebase changes, you may need to call `build_dependency_graph()` again to refresh the analysis.

- **Supported languages**: Python, Terraform, Go, JavaScript/TypeScript
4 changes: 2 additions & 2 deletions docs/src/content/docs/development/roadmap.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This roadmap reflects our current priorities. Updated quarterly.
## Now / Next

**Dependency Analysis Expansion**
- JavaScript/TypeScript (package.json, ESM/CJS imports)
- ~~JavaScript/TypeScript (package.json, ESM/CJS imports)~~ ✓ Shipped
- Rust (Cargo.toml, mod system)
- Java (Maven pom.xml, Gradle)

Expand All @@ -42,4 +42,4 @@ These are ideas we're considering. No commitments.

## Feedback

Have ideas or priorities? [Open an issue](https://github.com/cased/kit/issues) or [start a discussion](https://github.com/cased/kit/discussions).
Have ideas or priorities? [Open an issue](https://github.com/cased/kit/issues).
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "cased-kit"
version = "3.0.0"
version = "3.1.0"
description = "A modular toolkit for LLM-powered codebase understanding."
authors = [
{ name = "Cased", email = "ted@cased.com" }
Expand Down
28 changes: 7 additions & 21 deletions src/kit/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ def analyze_dependencies(
):
"""Analyze and visualize code dependencies within a repository.

Supports Python, Terraform, and Go dependency analysis with features including:
Supports Python, Terraform, Go, and JavaScript/TypeScript dependency analysis with features including:
• Dependency graph generation and export
• Circular dependency detection
• Module-specific analysis
Expand All @@ -348,7 +348,7 @@ def analyze_dependencies(
Examples:
kit dependencies . --language python --format dot --output deps.dot
kit dependencies . --language terraform --cycles --visualize
kit dependencies . --language python --module kit.repository --include-indirect
kit dependencies . --language javascript --module src/index.js --include-indirect
kit dependencies . --language python --llm-context --output context.md
"""
from kit import Repository
Expand All @@ -357,10 +357,10 @@ def analyze_dependencies(
repo = Repository(path, ref=ref)

# Validate language
supported_languages = ["python", "terraform", "go", "golang"]
supported_languages = ["python", "terraform", "go", "golang", "javascript", "typescript", "js", "ts"]
if language.lower() not in supported_languages:
typer.secho(
f"❌ Unsupported language: {language}. Supported: {', '.join(supported_languages)}",
f"❌ Unsupported language: {language}. Supported: python, terraform, go, javascript, typescript",
fg=typer.colors.RED,
)
raise typer.Exit(code=1)
Expand Down Expand Up @@ -407,23 +407,9 @@ def analyze_dependencies(
typer.secho(f"❌ Module/resource '{module}' not found in dependency graph", fg=typer.colors.RED)
raise typer.Exit(code=1)

# Get dependencies and dependents using the correct methods for each analyzer type
if language.lower() == "python":
# Use the Python-specific methods
if hasattr(analyzer, "get_module_dependencies") and hasattr(analyzer, "get_dependents"):
dependencies = analyzer.get_module_dependencies(module, include_indirect=include_indirect) # type: ignore
dependents = analyzer.get_dependents(module, include_indirect=include_indirect) # type: ignore
else:
typer.secho("❌ Python dependency analyzer methods not available", fg=typer.colors.RED)
raise typer.Exit(code=1)
else: # terraform
# Use the Terraform-specific methods
if hasattr(analyzer, "get_resource_dependencies") and hasattr(analyzer, "get_dependents"):
dependencies = analyzer.get_resource_dependencies(module, include_indirect=include_indirect) # type: ignore
dependents = analyzer.get_dependents(module, include_indirect=include_indirect) # type: ignore
else:
typer.secho("❌ Terraform dependency analyzer methods not available", fg=typer.colors.RED)
raise typer.Exit(code=1)
# Get dependencies and dependents using the generic interface
dependencies = analyzer.get_dependencies(module, include_indirect=include_indirect) # type: ignore
dependents = analyzer.get_dependents(module, include_indirect=include_indirect) # type: ignore

dep_type = "All" if include_indirect else "Direct"
typer.echo(f"📥 {dep_type} dependencies ({len(dependencies)}):")
Expand Down
35 changes: 33 additions & 2 deletions src/kit/dependency_analyzer/dependency_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,34 @@ def find_cycles(self) -> List[List[str]]:
"""
pass

@abstractmethod
def get_dependencies(self, item: str, include_indirect: bool = False) -> List[str]:
"""
Get dependencies for a specific component.

Args:
item: Identifier for the component (file path, module name, resource ID, etc.)
include_indirect: Whether to include indirect/transitive dependencies

Returns:
List of component identifiers this item depends on
"""
pass

@abstractmethod
def get_dependents(self, item: str, include_indirect: bool = False) -> List[str]:
"""
Get components that depend on the specified item.

Args:
item: Identifier for the component (file path, module name, resource ID, etc.)
include_indirect: Whether to include indirect/transitive dependents

Returns:
List of component identifiers that depend on this item
"""
pass

@abstractmethod
def visualize_dependencies(self, output_path: str, format: str = "png") -> str:
"""
Expand Down Expand Up @@ -208,7 +236,7 @@ def get_for_language(cls, repository: "Repository", language: str) -> "Dependenc

Args:
repository: A kit.Repository instance
language: Language identifier (e.g., 'python', 'terraform', 'go')
language: Language identifier (e.g., 'python', 'terraform', 'go', 'javascript', 'typescript')

Returns:
An appropriate DependencyAnalyzer instance for the language
Expand All @@ -217,6 +245,7 @@ def get_for_language(cls, repository: "Repository", language: str) -> "Dependenc
ValueError: If the specified language is not supported
"""
from .go_dependency_analyzer import GoDependencyAnalyzer
from .javascript_dependency_analyzer import JavaScriptDependencyAnalyzer
from .python_dependency_analyzer import PythonDependencyAnalyzer
from .terraform_dependency_analyzer import TerraformDependencyAnalyzer

Expand All @@ -228,10 +257,12 @@ def get_for_language(cls, repository: "Repository", language: str) -> "Dependenc
return TerraformDependencyAnalyzer(repository)
elif language == "go" or language == "golang":
return GoDependencyAnalyzer(repository)
elif language in ("javascript", "typescript", "js", "ts"):
return JavaScriptDependencyAnalyzer(repository)
else:
raise ValueError(
f"Unsupported language for dependency analysis: {language}. "
f"Currently supported languages: python, terraform, go"
f"Currently supported languages: python, terraform, go, javascript, typescript"
)

# ------------------------------------------------------------------
Expand Down
13 changes: 13 additions & 0 deletions src/kit/dependency_analyzer/go_dependency_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,19 @@ def dfs(pkg):

return cycles

def get_dependencies(self, item: str, include_indirect: bool = False) -> List[str]:
"""
Get dependencies for a specific component.

Args:
item: Import path of the package
include_indirect: Whether to include indirect dependencies

Returns:
List of package import paths this package depends on
"""
return self.get_package_dependencies(item, include_indirect)

def get_package_dependencies(self, package_path: str, include_indirect: bool = False) -> List[str]:
"""
Get dependencies for a specific package.
Expand Down
Loading