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
56 changes: 33 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Dead Code Hunter

A GitHub Action that finds unreachable functions in your codebase using [Supermodel](https://supermodeltools.com).
A GitHub Action that finds unused code in your codebase using [Supermodel](https://supermodeltools.com) static analysis.

## Installation

Expand Down Expand Up @@ -45,6 +45,7 @@ That's it! The action will now analyze your code on every PR and comment with an
| Input | Description | Required | Default |
|-------|-------------|----------|---------|
| `supermodel-api-key` | Your Supermodel API key | Yes | - |
| `github-token` | GitHub token for posting PR comments | No | `github.token` |
| `comment-on-pr` | Post findings as PR comment | No | `true` |
| `fail-on-dead-code` | Fail the action if dead code found | No | `false` |
| `ignore-patterns` | JSON array of glob patterns to ignore | No | `[]` |
Expand All @@ -61,36 +62,45 @@ That's it! The action will now analyze your code on every PR and comment with an

## What it does

1. Creates a zip of your repository
2. Sends it to Supermodel for analysis
3. Identifies functions with no callers
4. Filters out false positives (entry points, exports, tests)
5. Posts findings as a PR comment
1. Creates a zip of your repository via `git archive`
2. Sends it to the Supermodel dead code analysis API
3. The API performs symbol-level import analysis to identify unused exports
4. Results are returned with confidence levels and reasons
5. Posts findings as a PR comment with a sortable table

## What it detects

- **Functions** and **methods** with no callers
- **Classes** and **interfaces** that are never referenced
- **Types**, **variables**, and **constants** that are exported but never imported
- **Orphaned files** whose exports have no importers anywhere in the codebase
- **Transitively dead code** — code only called by other dead code

Each finding includes a **confidence level** (high, medium, low) and a **reason** explaining why it was flagged.

## Example output

> ## Dead Code Hunter
>
> Found **3** potentially unused functions:
> Found **3** potentially unused code elements:
>
> | Name | Type | File | Line | Confidence |
> |------|------|------|------|------------|
> | `unusedHelper` | function | src/utils.ts#L42 | L42 | :red_circle: high |
> | `OldValidator` | class | src/validation.ts#L15 | L15 | :red_circle: high |
> | `LegacyConfig` | interface | src/legacy.ts#L8 | L8 | :orange_circle: medium |
>
> <details><summary>Analysis summary</summary>
>
> | Function | File | Line |
> |----------|------|------|
> | `unusedHelper` | src/utils.ts#L42 | L42 |
> | `oldValidator` | src/validation.ts#L15 | L15 |
> | `deprecatedFn` | src/legacy.ts#L8 | L8 |
> - **Total declarations analyzed**: 150
> - **Dead code candidates**: 3
> - **Alive code**: 147
> - **Analysis method**: symbol_level_import_analysis
>
> </details>
>
> ---
> _Powered by [Supermodel](https://supermodeltools.com) graph analysis_

## False positive filtering

The action automatically skips:

- **Entry point files**: `index.ts`, `main.ts`, `app.ts`
- **Entry point functions**: `main`, `run`, `start`, `init`, `handler`
- **Exported functions**: May be called from outside the repo
- **Test files**: `*.test.ts`, `*.spec.ts`, `__tests__/**`
- **Build output**: `node_modules`, `dist`, `build`, `target`
> _Powered by [Supermodel](https://supermodeltools.com) dead code analysis_

## Supported languages

Expand Down
6 changes: 3 additions & 3 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: 'Dead Code Hunter'
description: 'Find unreachable functions in your codebase using Supermodel call graphs'
description: 'Find unused code in your codebase using Supermodel static analysis'
author: 'Supermodel Tools'

branding:
Expand Down Expand Up @@ -29,9 +29,9 @@ inputs:

outputs:
dead-code-count:
description: 'Number of dead code functions found'
description: 'Number of unused code elements found'
dead-code-json:
description: 'JSON array of dead code findings'
description: 'JSON array of dead code findings with type, confidence, and reason'

runs:
using: 'node20'
Expand Down
54 changes: 8 additions & 46 deletions dist/dead-code.d.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,12 @@
import { CodeGraphNode, CodeGraphRelationship } from '@supermodeltools/sdk';
import type { DeadCodeCandidate, DeadCodeAnalysisResponse, DeadCodeAnalysisMetadata } from '@supermodeltools/sdk';
export type { DeadCodeCandidate, DeadCodeAnalysisResponse, DeadCodeAnalysisMetadata };
/**
* Represents a potentially unused function found in the codebase.
* Filters dead code candidates by user-provided ignore patterns.
* The API handles all analysis server-side; this is purely for
* client-side post-filtering on file paths.
*/
export interface DeadCodeResult {
id: string;
name: string;
filePath: string;
startLine?: number;
endLine?: number;
}
/** Default glob patterns for files to exclude from dead code analysis. */
export declare const DEFAULT_EXCLUDE_PATTERNS: string[];
/** Glob patterns for files that are considered entry points. */
export declare const ENTRY_POINT_PATTERNS: string[];
/** Function names that are considered entry points. */
export declare const ENTRY_POINT_FUNCTION_NAMES: string[];
export declare function filterByIgnorePatterns(candidates: DeadCodeCandidate[], ignorePatterns: string[]): DeadCodeCandidate[];
/**
* Checks if a file path matches any entry point pattern.
* @param filePath - The file path to check
* @returns True if the file is an entry point
* Formats dead code analysis results as a GitHub PR comment.
*/
export declare function isEntryPointFile(filePath: string): boolean;
/**
* Checks if a function name is a common entry point name.
* @param name - The function name to check
* @returns True if the function name is an entry point
*/
export declare function isEntryPointFunction(name: string): boolean;
/**
* Checks if a file should be ignored based on exclude patterns.
* @param filePath - The file path to check
* @param ignorePatterns - Additional patterns to ignore
* @returns True if the file should be ignored
*/
export declare function shouldIgnoreFile(filePath: string, ignorePatterns?: string[]): boolean;
/**
* Analyzes a code graph to find functions that are never called.
* @param nodes - All nodes from the code graph
* @param relationships - All relationships from the code graph
* @param ignorePatterns - Additional glob patterns to ignore
* @returns Array of potentially unused functions
*/
export declare function findDeadCode(nodes: CodeGraphNode[], relationships: CodeGraphRelationship[], ignorePatterns?: string[]): DeadCodeResult[];
/**
* Formats dead code results as a GitHub PR comment.
* @param deadCode - Array of dead code results
* @returns Markdown-formatted comment string
*/
export declare function formatPrComment(deadCode: DeadCodeResult[]): string;
export declare function formatPrComment(candidates: DeadCodeCandidate[], metadata?: DeadCodeAnalysisMetadata): string;
2 changes: 1 addition & 1 deletion dist/dead-code.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/index.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading