Lynx Eye
Lynx Eye is a code analysis tool similar to Lizard, built with Rust and tree-sitter. It analyzes code metrics for JavaScript, TypeScript, and Rust, focusing on function-level static analysis to help identify complex or oversized functions that may need refactoring.
Features
- Multi-language Support: Analyzes JavaScript, TypeScript, and Rust code
- Function-level Analysis: Extracts detailed metrics for each function
- Static Analysis Metrics:
- NLOC (Non-commenting Lines of Code)
- CCN (Cyclomatic Complexity Number)
- Token count
- Parameter count
- Complexity Score (0-100)
- Dynamic Analysis (JavaScript only):
- Runtime tracing with
--tracemode - LiveRate (percentage of code actually executed)
- Dead code detection
- Runtime tracing with
- Configurable Thresholds: Set custom limits for complexity warnings
- Fast Performance: Built with Rust for efficient processing
Installation
Prerequisites
- Rust (edition 2024 or later)
- Cargo
- Node.js v14+ (required for dynamic analysis)
Build from Source
The release binary will be available at target/release/lynx_eye.
Install from crates.io
Usage
Command Line Options
# Show help
# Show version
Static Analysis (Default)
Input Options
# Analyze a single file
# Analyze multiple files
# Analyze an entire directory (non-recursive)
# Analyze directory recursively (includes subdirectories)
Output Formats
Table Format (Default)
Output:
+------+-----+-------+-------+-------+----------------+------+---------+
| NLOC | CCN | Token | Param | Score | Function | Line | File |
+======================================================================+
| 7 | 2 | 30 | 1 | 24.4 | calculateTotal | 1 | test.js |
|------+-----+-------+-------+-------+----------------+------+---------|
| 3 | 1 | 13 | 2 | 17.2 | add | 14 | test.js |
+------+-----+-------+-------+-------+----------------+------+---------+
JSON Format
CSV Format
Filtering Functions
# Show only functions with complexity score >= 40
# Show only highly complex functions (CCN >= 10)
# Show only large functions (NLOC >= 20)
# Show functions with many parameters (>= 5)
# Combine multiple filters
Output to File
# Save JSON output
# Save CSV output
Dynamic Analysis (JavaScript)
Dynamic analysis traces code execution at runtime to measure which lines are actually executed.
Prerequisites
- Node.js v14+ must be installed
Basic Usage
# Analyze with entry point
# Analyze with test command
# Analyze single file
Output with LiveRate
+------+-----+-------+-------+-------+----------+----------------+------+---------------+
| NLOC | CCN | Token | Param | Score | LiveRate | Function | Line | File |
+=======================================================================================+
| 3 | 1 | 14 | 2 | 18.0 | 100% | add | 3 | trace_test.js |
|------+-----+-------+-------+-------+----------+----------------+------+---------------|
| 10 | 3 | 64 | 3 | 36.0 | 60% | calculate | 11 | trace_test.js |
|------+-----+-------+-------+-------+----------+----------------+------+---------------|
| 4 | 1 | 19 | 0 | 19.2 | 0% | unusedFunction | 23 | trace_test.js |
+------+-----+-------+-------+-------+----------+----------------+------+---------------+
Dead Code Report:
=================
calculate (trace_test.js:11-21)
LiveRate: 60.0% (3/5 lines executed)
- Lines 18-19: Never executed
unusedFunction (trace_test.js:23-27)
LiveRate: 0.0% (0/2 lines executed)
- Lines 25-26: Never executed
Multi-file Analysis
Dynamic analysis supports cross-file tracing:
# Analyze entire directory with entry point
This will:
- Instrument all JS files in
src/ - Execute from
main.js - Track which functions in imported files are actually called
LiveRate Interpretation
| LiveRate | Meaning |
|---|---|
| 100% | All code in the function was executed |
| 70-99% | Most code executed, some branches not taken |
| 50-69% | Significant unused branches |
| 1-49% | Most code never executed |
| 0% | Function was never called |
File Type Support
| Language | Extensions | Static Analysis | Dynamic Analysis |
|---|---|---|---|
| JavaScript | .js, .mjs, .cjs |
✅ | ✅ |
| TypeScript | .ts, .tsx, .mts |
✅ | 🔜 Planned |
| Rust | .rs |
✅ | 🔜 Planned |
Metrics Explained
NLOC (Non-commenting Lines of Code)
The number of lines containing actual code, excluding empty lines and comments.
// NLOC: 1 ✅
// Total NLOC: 3
Threshold: Functions with NLOC > 30 are considered large.
CCN (Cyclomatic Complexity Number)
The number of independent paths through the code.
- Base complexity: 1
- +1 for each:
if,for,while,do,switch case,? :,&&,||,catch
Threshold: CCN > 15 indicates highly complex code.
Complexity Score (0-100)
A composite score combining multiple metrics:
Score = 0.5 × CCN_norm + 0.3 × NLOC_norm + 0.2 × Density_norm
| Score | Interpretation |
|---|---|
| 0-30 | Simple function ✅ |
| 30-60 | Moderate complexity ⚠️ |
| 60-100 | High complexity ❌ |
LiveRate (Dynamic Analysis)
Percentage of code lines actually executed during runtime.
LiveRate = (Executed Lines / Instrumented Lines) × 100%
| LiveRate | Interpretation |
|---|---|
| 90-100% | Most code is actively used ✅ |
| 70-90% | Some unused branches (normal) |
| 50-70% | Significant dead code ⚠️ |
| < 50% | Major dead code problem ❌ |
Development
Build and Run
# Build the project
# Run in debug mode
# Build optimized release version
Testing
# Run all tests
# Run a specific test
Development Tools
# Quick check without building
# Run linter
# Format code
# Clean build artifacts
Architecture
Lynx Eye uses tree-sitter to parse source code into a Concrete Syntax Tree (CST), then:
-
Static Analysis:
- Tree traversal to identify function nodes
- Metadata extraction (name, lines, parameters)
- NLOC, CCN, token count calculation
- Complexity score computation
-
Dynamic Analysis (JS only):
- Source code instrumentation with
__lynx.hit()calls - Runtime execution via Node.js
- Trace data collection
- LiveRate calculation per function
- Source code instrumentation with
Project Structure
src/
├── analysis.rs # Static analysis logic
├── parser.rs # Tree-sitter parsing
├── languages/ # Language-specific configs
│ ├── mod.rs
│ ├── javascript.rs
│ └── rust.rs
├── trace/ # Dynamic analysis
│ ├── mod.rs
│ ├── instrumenter.rs
│ ├── executor.rs
│ ├── reporter.rs
│ └── runtime/
│ └── js_runtime.js
├── lib.rs
└── main.rs
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Acknowledgments
- tree-sitter - Parser generator tool
- Lizard - Inspiration for this project
- The Rust community for excellent tooling and libraries