lynx_eye

Crates.iolynx_eye
lib.rslynx_eye
version0.0.3
created_at2025-12-21 23:22:26.746593+00
updated_at2025-12-23 14:32:26.764214+00
descriptionA code complexity analyzer for JavaScript, TypeScript, and Rust using tree-sitter. Calculates NLOC, CCN, token count, and complexity scores.
homepagehttps://github.com/yzzting/LynxEye
repositoryhttps://github.com/yzzting/LynxEye
max_upload_size
id1998739
size101,855
ZenYang (yzzting)

documentation

README

Lynx Eye

License: MIT Rust

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 --trace mode
    • LiveRate (percentage of code actually executed)
    • Dead code detection
  • 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

git clone https://github.com/yzzting/LynxEye.git
cd LynxEye
cargo build --release

The release binary will be available at target/release/lynx_eye.

Install from crates.io

cargo install lynx_eye

Usage

Command Line Options

# Show help
lynx_eye --help

# Show version
lynx_eye --version

Static Analysis (Default)

Input Options

# Analyze a single file
lynx_eye demo/test.js

# Analyze multiple files
lynx_eye demo/test.js demo/test.ts src/lib.rs

# Analyze an entire directory (non-recursive)
lynx_eye demo/

# Analyze directory recursively (includes subdirectories)
lynx_eye --recursive demo/
lynx_eye -r src/

Output Formats

Table Format (Default)

lynx_eye demo/test.js

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

lynx_eye --format json demo/test.js

CSV Format

lynx_eye --format csv demo/test.js

Filtering Functions

# Show only functions with complexity score >= 40
lynx_eye --min-score 40 demo/

# Show only highly complex functions (CCN >= 10)
lynx_eye --min-ccn 10 demo/

# Show only large functions (NLOC >= 20)
lynx_eye --min-nloc 20 demo/

# Show functions with many parameters (>= 5)
lynx_eye --min-params 5 demo/

# Combine multiple filters
lynx_eye --min-score 50 --min-ccn 5 --min-nloc 20 demo/

Output to File

# Save JSON output
lynx_eye --format json --output analysis.json demo/

# Save CSV output
lynx_eye --format csv --output analysis.csv demo/

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
lynx_eye --trace src/ --entry main.js

# Analyze with test command
lynx_eye --trace src/ --test-cmd "npm test"

# Analyze single file
lynx_eye --trace demo/trace_test.js --entry trace_test.js

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
lynx_eye --trace src/ --entry main.js

This will:

  1. Instrument all JS files in src/
  2. Execute from main.js
  3. 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.

function example(param) {    // Not counted (comment)
    let result = param;      // NLOC: 1 ✅
    // This is a comment     // Not counted
    return result;           // NLOC: 1 ✅
}                            // 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
function example(value) {        // Base: 1
    if (value > 10) {            // +1 = 2
        return value * 2;
    } else if (value < 5) {      // +1 = 3
        return value / 2;
    }
    return value + 1;            // Total CCN: 3
}

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
cargo build

# Run in debug mode
cargo run

# Build optimized release version
cargo build --release

Testing

# Run all tests
cargo test

# Run a specific test
cargo test test_function_name

Development Tools

# Quick check without building
cargo check

# Run linter
cargo clippy

# Format code
cargo fmt

# Clean build artifacts
cargo clean

Architecture

Lynx Eye uses tree-sitter to parse source code into a Concrete Syntax Tree (CST), then:

  1. Static Analysis:

    • Tree traversal to identify function nodes
    • Metadata extraction (name, lines, parameters)
    • NLOC, CCN, token count calculation
    • Complexity score computation
  2. Dynamic Analysis (JS only):

    • Source code instrumentation with __lynx.hit() calls
    • Runtime execution via Node.js
    • Trace data collection
    • LiveRate calculation per function

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
Commit count: 0

cargo fmt