Skip to main content

Node.js API

@revet/core exposes all of revet's analysis capabilities to JavaScript and TypeScript via NAPI-RS. Every function runs on a native thread pool — nothing blocks the Node.js event loop.

Installation​

npm install @revet/core
# or
yarn add @revet/core

Development build — if you're working on revet itself, run cargo build in the workspace root and load the binding from crates/node-binding. The index.js loader finds the cargo build output automatically.

Quick start​

import {
analyzeRepository,
analyzeFiles,
analyzeGraph,
suppress,
getVersion,
watchRepo,
} from '@revet/core';

// Full repository scan
const result = await analyzeRepository('/path/to/repo');
console.log(result.summary);
// → { total: 12, errors: 2, warnings: 9, info: 1, filesScanned: 84 }

result.findings.forEach(f =>
console.log(`${f.id} ${f.severity} ${f.file}:${f.line} ${f.message}`)
);

API reference​

analyzeRepository(repoPath, options?)​

Full repository scan. Loads .revet.toml from repoPath (falls back to defaults).

const result: AnalyzeResult = await analyzeRepository('/path/to/repo');
ParameterTypeDescription
repoPathstringAbsolute or relative path to the repository root
optionsAnalyzeOptions?Reserved for future use

analyzeFiles(files, repoRoot, options?)​

Targeted scan of a specific file list. Useful for editor integrations or incremental CI checks where only changed files need re-scanning.

const result = await analyzeFiles(
['/repo/src/auth.py', '/repo/src/db.py'],
'/repo',
);
ParameterTypeDescription
filesstring[]File paths to scan (absolute or relative)
repoRootstringRepository root — used for config loading and path relativisation
optionsAnalyzeOptions?Reserved for future use

analyzeGraph(repoPath)​

Parse the repository and return code-graph statistics. Uses the incremental on-disk cache (.revet-cache/) for speed.

const stats: GraphStats = await analyzeGraph('/path/to/repo');
console.log(stats.nodeCount, stats.edgeCount);

suppress(findingId, repoPath)​

Add a finding ID to [ignore].findings in .revet.toml. Creates the file if absent.

const added: boolean = await suppress('SEC-001', '/path/to/repo');
// false if the ID was already present (idempotent)

getVersion()​

Returns the revet-core library version string (synchronous).

console.log(getVersion()); // e.g. "0.2.0"

watchRepo(repoPath, options?)​

Watch a repository for file changes and stream findings in real time. Returns a standard Node.js EventEmitter with an additional .stop() method.

const watcher = watchRepo('/path/to/repo', { debounceMs: 500 });

watcher.on('progress', ({ progress }) => {
const total = progress.filesTotal || '?';
console.log(`scanning ${total} file(s)…`);
});

watcher.on('finding', ({ finding }) => {
console.log(`${finding.id} ${finding.severity} ${finding.file}:${finding.line}`);
console.log(` ${finding.message}`);
});

watcher.on('done', ({ summary }) => {
console.log(`scan complete — ${summary.total} findings in ${summary.filesScanned} files`);
});

watcher.on('error', (err) => {
console.error('watcher error:', err);
});

// Stop watching later
watcher.stop();
ParameterTypeDescription
repoPathstringRepository root to watch
options.debounceMsnumberDelay (ms) after last change before re-scanning. Default: 300

Behaviour​

  1. An initial full scan fires immediately when watchRepo is called.
  2. File changes are debounced — only the accumulated changed files are re-scanned after the quiet period, not the whole repo.
  3. The .revet-cache/ directory is excluded to avoid feedback loops.
  4. stop() signals the watcher thread to exit. Any in-progress scan finishes first.

Events​

EventPayloadWhen emitted
progress{ kind: 'progress', progress: WatchProgress }Before each scan pass starts
finding{ kind: 'finding', finding: JsFinding }Once per finding in each pass
done{ kind: 'done', summary: AnalyzeSummary }End of each scan pass
errorErrorWatcher or analysis failure

WatchProgress.filesTotal is 0 during the initial scan (file count is not known before discovery). For subsequent watch re-scans it equals the number of changed files being re-analysed.

WatchEmitter interface​

watcher.stop()      // → boolean: true if it was still running
watcher.isRunning // → boolean: read-only property

Type reference​

AnalyzeResult​

interface AnalyzeResult {
findings: JsFinding[];
summary: AnalyzeSummary;
}

JsFinding​

FieldTypeDescription
idstringe.g. "SEC-001"
severity"error" | "warning" | "info"
messagestringHuman-readable description
filestringPath relative to repo root
linenumber1-indexed line number
suggestionstring | undefinedOptional remediation hint

AnalyzeSummary​

FieldType
totalnumber
errorsnumber
warningsnumber
infonumber
filesScannednumber

GraphStats​

FieldTypeDescription
nodeCountnumberTotal graph nodes (files, functions, classes, …)
edgeCountnumberTotal graph edges (calls, imports, contains, …)
filesScannednumberFiles parsed or loaded from cache
parseErrorsnumberFiles that could not be parsed

TypeScript​

The package ships index.d.ts with full types. Import types directly:

import type {
AnalyzeResult,
JsFinding,
AnalyzeSummary,
WatchEmitter,
WatchEvent,
RevetWatchEvents,
} from '@revet/core';

WatchEmitter overloads on / once / off with the typed RevetWatchEvents map, so event payloads are fully typed in TypeScript.


Building from source​

# Install napi-rs CLI
npm install -g @napi-rs/cli

# Development build (current platform, debug)
cd crates/node-binding
napi build --platform

# Release build (current platform)
napi build --platform --release

# Cross-compile for a specific target
napi build --platform --target x86_64-unknown-linux-gnu --release

The built .node file is placed in crates/node-binding/ and picked up automatically by index.js.