Skip to content

nikuscs/ts-code-scan

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🔍 code-scan

CI Release License

Fast, single-binary Rust CLI that indexes TypeScript/JavaScript codebases for AI and automation. It walks your project, parses files in parallel, and returns a deterministic JSON index so tools can understand a repo’s structure instantly.

The index includes functions, bindings with reference counts, exports, and optional rule violations. Output is available as compact tuple arrays (token-friendly for LLMs) or verbose objects (human-readable) — ideal for AI assistants, code review automation, repo analytics, and refactoring planning.

Quick start

Scan a folder and get every function in every file:

code-scan index --root src/
{
  "ver": 1,
  "stats": { "files": 3, "parsed": 3, "skipped": 0, "errors": 0 },
  "f": [
    ["src/auth.ts", 5, 0, "login", 1, "fn"],
    ["src/auth.ts", 18, 0, "logout", 1, "fn"],
    ["src/auth.ts", 30, 0, "refreshToken", 1, "arr"],
    ["src/hooks.ts", 3, 0, "useUser", 1, "arr"],
    ["src/hooks.ts", 15, 0, "useAuth", 1, "arr"],
    ["src/utils.ts", 1, 0, "formatDate", 1, "fn"]
  ]
}

Each entry is [file, line, col, name, exported, kind]. You get all functions grouped by file — feed it to an LLM and it instantly knows what every file in the project does.

Why?

  • Fast — indexes 5,000+ files in under 0.5s. Native Rust with oxc parser + rayon parallelism.
  • Token-efficient — compact mode uses tuple arrays and short keys (f, b, x) to minimize tokens when feeding to LLMs.
  • Complete — functions (declarations, arrows, class methods, getters/setters, constructors), bindings with reference counts, exports, and lint violations.
  • Zero config — respects .gitignore, auto-skips node_modules/dist/build/.next, detects TS/JS/JSX/TSX by extension.
  • Single binary — ~3MB stripped. No runtime dependencies.

Install

Binary

# From source (requires Rust 1.91+)
cargo install --git https://github.com/nikuscs/ts-code-scan

# Or clone and build
git clone https://github.com/nikuscs/ts-code-scan
cd ts-code-scan
cargo build --release
# Binary at target/release/code-scan

Pre-built binaries available in Releases.

Claude Code Skill

This repo ships as a Claude Code plugin with a ready-to-use /code-scan:scan skill.

# Add the marketplace
/plugin marketplace add nikuscs/ts-code-scan

# Install the plugin
/plugin install code-scan@ts-code-scan

Then use it:

/code-scan:scan                  # index the whole project
/code-scan:scan src/utils.ts     # index a single file
/code-scan:scan rules            # run lint rules
/code-scan:scan verbose          # verbose output

Requires the code-scan binary in your $PATH. Install it first with cargo install or download from Releases.

Usage

Index a project

# Compact JSON (default, token-efficient for LLMs)
code-scan index --root ./my-project

# Verbose JSON (pretty-printed, human-readable)
code-scan index --root ./my-project --mode verbose

# Single file
code-scan index --file src/utils.ts

# Filter function kinds
code-scan index --root . --function-kinds top+arrow

# Only TypeScript files
code-scan index --root . --include ts,tsx

Built-in groupings (LLM-friendly)

# Per-file function names
code-scan index --root ./my-project --mode files

# Per-folder summary (function count + names)
code-scan index --root ./my-project --mode folders

The files and folders modes emit pre-grouped JSON to avoid extra tooling.

  • Dot notation: nested functions are prefixed with their nearest enclosing named function, e.g. createBlogRegistry.get.

Example (files mode):

{
  "ver": 1,
  "stats": { "files": 6, "parsed": 6, "skipped": 0, "errors": 0 },
  "files": {
    "services/blog.service.ts": [
      "calculateReadingTime",
      "createBlogRegistry",
      "createBlogRegistry.get",
      "createBlogRegistry.getAllPosts"
    ],
    "services/rss.service.ts": ["createRssResponse", "createRssXml"]
  }
}

Group by file (with jq)

Get a per-file list of function names (compact mode):

code-scan index --root ./my-project --mode compact \
  | jq 'reduce .f[] as $t ({}; (.[$t[0]] |= ((. // []) + [$t[3]])))
        | with_entries(.value |= (map(select(. != "")) | unique | sort))'

Group by folder (with jq)

Per-folder function names:

code-scan index --root ./my-project --mode compact \
  | jq 'reduce .f[] as $t ({}; (
          ($t[0] | split("/") | .[:-1] | join("/")) as $dir |
          (.[$dir] |= ((. // []) + [$t[3]]))
        ))
        | with_entries(.value |= (map(select(. != "")) | unique | sort))'

Per-folder summary with counts and names:

code-scan index --root ./my-project --mode compact \
  | jq 'reduce .f[] as $t ({ };
        (
          ($t[0] | split("/") | .[:-1] | join("/")) as $dir |
          .[$dir] |= ((. // {functions: 0, names: []})
            | .functions += 1
            | .names += [$t[3]])
        ))
        | with_entries(.value.names |= (map(select(. != "")) | unique | sort))'

Or, include metadata (name, line, kind, exported):

# Compact
code-scan index --root ./my-project --mode compact \
  | jq 'reduce .f[] as $t ({}; (.[$t[0]] |= ((. // []) + [{name:$t[3], line:$t[1], kind:$t[5], exported:($t[4]==1)}])))'

# Verbose
code-scan index --root ./my-project --mode verbose \
  | jq 'reduce .functions[] as $f ({}; (.[$f.file] |= ((. // []) + [{name:$f.name, line:$f.span.start.line, kind:$f.kind, exported:$f.exported}])))'

Run rules

# Run all rules
code-scan rules --root ./my-project

# Specific rules
code-scan rules --root . --rules no_unused_bindings,max_functions_per_file

# Single file check
code-scan rules --file src/large-file.ts --rules max_functions_per_file

Output

Compact mode (default)

Tuple arrays for minimal token usage:

{
  "ver": 1,
  "stats": { "files": 842, "parsed": 830, "skipped": 12, "errors": 0 },
  "f": [["src/utils.ts", 10, 3, "sum", 1, "fn"]],
  "b": [["src/utils.ts", 5, 7, "tmp", "const", 0]],
  "x": [["src/utils.ts", "sum", 1]]
}
Key Contents Tuple format
f Functions [file, line, col, name, exported(0/1), kind]
b Bindings [file, line, col, name, kind, refs]
x Exports [file, name, kind_code]
viol Violations [file, rule, count, details]

Verbose mode

Full objects with spans:

{
  "ver": 1,
  "functions": [{
    "file": "src/utils.ts",
    "name": "sum",
    "kind": "FunctionDeclaration",
    "exported": true,
    "isAsync": false,
    "isGenerator": false,
    "span": { "start": { "line": 10, "col": 3 }, "end": { "line": 25, "col": 0 } }
  }]
}

Options

Index

Flag Default Description
--root . Project root directory
--mode compact Output mode: compact, verbose, files, or folders
--include all File extensions to include (comma-separated)
--exclude Patterns to exclude (comma-separated)
--max-bytes-per-file 1048576 Skip files larger than N bytes
--function-kinds all Filter: top, top+arrow, top+arrow+class, all
--file Scan a single file instead of a directory
--with-exports false Include export info in output

Rules

Flag Default Description
--root . Project root directory
--mode compact Output mode: compact or verbose
--rules all Rules to run (comma-separated)
--file Check a single file instead of a directory

Available rules

Rule Description
no_unused_bindings Flags bindings with zero references (skips _-prefixed and imports)
one_exported_function_per_file Flags files with more than one exported function
max_functions_per_file Flags files with more than 20 functions

Function kinds

Code Kind
fn Function declaration
arr Arrow function
fex Function expression
cls Class method
obj Object method
get Getter
set Setter
ctor Constructor

How It Works

  1. File discovery — walks the project tree with ignore, respects .gitignore, filters by extension
  2. Parallel parsing — each file gets its own arena allocator, parsed by oxc into AST + semantic model
  3. AST extraction — visitor walks the AST collecting functions (declarations, arrows, methods, getters/setters, constructors) and exports
  4. Binding analysis — scoping API iterates all symbols, counts references, maps to binding kinds
  5. Rule checking — optional lint rules run against each file's extracted index
  6. JSON output — compact tuples or verbose objects, sorted by file path for deterministic output

Related Projects

Disclaimer

This project is for educational purposes and AI automation research only. The authors are not responsible for any misuse or for any damages resulting from the use of this tool. Users are solely responsible for ensuring compliance with applicable laws and the terms of service of any websites accessed. This software is provided "as-is" without warranty of any kind.

If you are a rights holder and wish to have this project removed, please contact me.

Note: This project was partially developed with AI assistance and may contain bugs or unexpected behavior. Use at your own risk.

License

MIT — see LICENSE.

About

Single-binary Rust CLI that indexes TS/JS codebases into deterministic JSON for AI tooling. Fast, zero runtime deps.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors