Skip to content

ahmadawais/grepts

Repository files navigation

grepts

grepts

A fast TypeScript grep — ripgrep reimagined for the Node.js ecosystem.

  ██████  ██████  ███████ ██████  ████████ ███████
 ██       ██   ██ ██      ██   ██    ██    ██
 ██   ███ ██████  █████   ██████     ██    ███████
 ██    ██ ██   ██ ██      ██         ██         ██
  ██████  ██   ██ ███████ ██         ██    ███████

grepts is a TypeScript-native grep tool with full ripgrep feature parity. Use it as a CLI or as an in-process Node.js module — no subprocess spawn overhead.

Install

pnpm add grepts

CLI Usage

# Basic search
grepts "TODO" ./src

# Case insensitive
grepts -i "fixme" ./src

# Regex pattern
grepts "(import|export).*from" ./src

# Word boundary matching
grepts -w "error" ./src

# Only show file names with matches
grepts -l "TODO" .

# Count matches per file
grepts -c "function" ./src

# Glob filter — only search .ts files
grepts -g "*.ts" "interface" ./src

# Max matches per file
grepts -m 5 "TODO" ./src

# Invert match — show lines NOT matching
grepts --invert-match "test" ./src

# Context lines (like grep -C)
grepts -C 3 "error" ./src
grepts -B 2 -A 5 "error" ./src

# Fixed strings (no regex)
grepts -F "array[0]" ./src

# Multiline mode
grepts -U "function.*\n.*return" ./src

# Search hidden files
grepts --hidden "secret" .

# Limit directory depth
grepts --max-depth 2 "TODO" .

# Quiet mode — exit 0 if match found, 1 otherwise
grepts -q "TODO" ./src

# Show version
grepts -v

All CLI Flags

Flag Description
-i, --ignore-case Case insensitive search
-n, --line-number Show line numbers (default: on)
-c, --count Show count of matches per file
-l, --files-with-matches Show only file names with matches
--files-without-match Show only file names without matches
-w, --word-regexp Match whole words only
-F, --fixed-strings Treat pattern as literal string
-g, --glob <pattern> Filter files by glob (e.g., *.ts)
--hidden Search hidden files and directories
--max-depth <n> Max directory recursion depth
-m, --max-count <n> Max matches per file
--invert-match Select non-matching lines
-U, --multiline Multiline matching
-C, --context <n> Lines of context around matches
-B, --before-context <n> Lines before match
-A, --after-context <n> Lines after match
--no-ignore Don't respect .gitignore
--no-color Disable color output
-q, --quiet Suppress output, exit code only
-v, --version Show version

Module Usage

Use grepts as an in-process Node.js library — zero subprocess overhead.

import { search, searchAsync, searchOptionsSchema } from 'grepts';

// Validate and search
const options = searchOptionsSchema.parse({
  pattern: 'TODO',
  paths: ['./src'],
  ignoreCase: true,
});

// Synchronous search
const results = search(options);

for (const result of results) {
  console.log(`${result.filePath}: ${result.matchCount} matches`);
  for (const match of result.matches) {
    console.log(`  L${match.lineNumber}: ${match.line}`);
  }
}

// Async search (concurrent file I/O)
const asyncResults = await searchAsync(options);

API

search(options: SearchOptions): readonly SearchResult[]

Synchronous recursive grep. Reads files with readFileSync.

searchAsync(options: SearchOptions): Promise<readonly SearchResult[]>

Async recursive grep. Reads files concurrently with 32-way parallelism.

searchOptionsSchema

Zod schema for validating search options. Use .parse() or .safeParse().

SearchOptions

interface SearchOptions {
  pattern: string;          // Regex pattern or literal string
  paths: string[];          // Files or directories to search
  ignoreCase?: boolean;     // Default: false
  lineNumber?: boolean;     // Default: true
  count?: boolean;          // Default: false
  filesWithMatches?: boolean;
  filesWithoutMatch?: boolean;
  wordRegexp?: boolean;     // Default: false
  fixedStrings?: boolean;   // Default: false
  glob?: string;            // e.g., "*.ts"
  hidden?: boolean;         // Default: false
  maxDepth?: number;
  maxCount?: number;
  context?: number;         // Default: 0
  beforeContext?: number;
  afterContext?: number;
  invertMatch?: boolean;    // Default: false
  multiline?: boolean;      // Default: false
  respectGitignore?: boolean; // Default: true
  color?: boolean;          // Default: true
  quiet?: boolean;          // Default: false
}

SearchResult

interface SearchResult {
  filePath: string;
  matches: MatchInfo[];
  matchCount: number;
}

interface MatchInfo {
  line: string;
  lineNumber: number;
  columnStart: number;
  columnEnd: number;
}

Feature Parity with ripgrep

Feature grepts ripgrep
Regex search
Recursive directory walk
.gitignore support
Case insensitive (-i)
Line numbers (-n)
Match count (-c)
Files with matches (-l)
Files without match
Word boundary (-w)
Fixed strings (-F)
Glob filtering (-g)
Hidden files (--hidden)
Max depth (--max-depth)
Max count (-m)
Invert match
Multiline (-U)
Color output
Quiet mode (-q)
Context lines (-C/-A/-B)
Binary file detection
In-process Node.js API
Async concurrent I/O
Zero-overhead integration

Benchmarks

grepts is 323x faster than ripgrep per invocation when used in-process (no subprocess spawn overhead). Run benchmarks yourself:

pnpm build && pnpm bench

See BENCHMARKS.md for full results.

Why grepts is faster

When integrating search into Node.js tools (IDEs, build systems, linters, watch mode), you have two options:

  1. Spawn ripgrep → ~5ms per invocation (fork + exec + pipe overhead)
  2. Call grepts → ~16μs per invocation (in-process function call)

For a single search, 5ms is fine. But IDEs and build tools search hundreds of times per second. That 323x advantage compounds:

Scenario ripgrep (subprocess) grepts (in-process)
1 search 5ms 16μs
100 searches 500ms 1.6ms
1000 searches 5s 16ms

Project Structure

src/
  core/           # Node module (importable library)
    index.ts      # Public API exports
    search.ts     # Search engine (regex, matching)
    search-async.ts # Async parallel search
    walker.ts     # Directory traversal, gitignore, glob
    output.ts     # Color formatting
    schemas.ts    # Zod validation schemas
    types.ts      # TypeScript types
  cli/            # CLI application
    cli.ts        # Commander.js CLI entry point
  bench/          # Benchmark suite
    bench.ts      # grepts vs ripgrep vs grep benchmarks
  __tests__/      # Vitest tests

Development

# Install dependencies
pnpm install

# Type check
pnpm typecheck

# Run tests
pnpm test

# Build
pnpm build

# Run benchmarks
pnpm bench

# Lint
pnpm lint

License

Apache-2.0 by Ahmad Awais built with Command Code.

About

grepts is a a fast TypeScript grep, ripgrep reimagined for the Node.js ecosystem.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors