> For AI agents: the complete documentation index is available at https://rslint.rs/llms.txt, the full documentation bundle is available at https://rslint.rs/llms-full.txt.

# JavaScript API

The JavaScript API lets you run rslint programmatically — lint files or in-memory source from a JavaScript runtime script, an editor integration, or a build tool. It is designed for JavaScript runtime hosts such as Node.js, Bun, or Deno when they can load npm packages and provide the Node-compatible filesystem and process APIs that `@rslint/core` uses. Its surface is aligned with [ESLint](https://eslint.org/docs/latest/integrate/nodejs-api)'s v10 programmatic API shape, so most ESLint API code ports over with minimal changes.

With automatic discovery, the native engine selects config candidates and file ownership while the JavaScript host evaluates and normalizes the selected JS or TS modules. Explicit config files and inline overrides use the same public API.

This guide focuses on common workflows. For complete method signatures and lifecycle details, see the [`Rslint` reference](https://rslint.rs/api/rslint.md).

## Getting started

```ts
import { Rslint } from '@rslint/core';

const rslint = new Rslint();
const results = await rslint.lintFiles(['src/**/*.ts']);

for (const result of results) {
  console.log(result.filePath, result.errorCount, result.warningCount);
}
```

`new Rslint(options)` creates a linter instance. Both `lintFiles` and `lintText` are async and return an ESLint-shaped `LintResult[]`.

## Linting files

[`lintFiles`](https://rslint.rs/api/rslint.md#lintfiles) takes one or more glob patterns resolved against `cwd`. It keeps supported source-file extensions that are not excluded by global config ignores or `.gitignore`. With automatic discovery, each selected file is routed to its nearest loadable config, so files in different monorepo packages can use different configs.

```ts
const results = await rslint.lintFiles(['src/**/*.ts', 'test/**/*.ts']);
```

Results are ordered by the linted file's path (deterministic), not by glob-walk order.

If no file matches the patterns, `lintFiles` returns an empty array rather than throwing — unlike ESLint v10, whose default `errorOnUnmatchedPattern` throws on an unmatched glob.

## Linting a string

[`lintText`](https://rslint.rs/api/rslint.md#linttext) lints an in-memory string as if it lived at `filePath`:

```ts
const [result] = await rslint.lintText('const x = 1', {
  filePath: 'example.ts',
});
```

`lintText` always returns exactly one result — for the linted buffer. If you omit `filePath`, the result's `filePath` is the `"<text>"` sentinel (matching ESLint).

## In-memory linting

See [In-memory projects](https://rslint.rs/api/rslint.md#in-memory-projects) for the complete constructor contract and path behavior.

By default `lintText` still reads the config and tsconfig from disk. To provide the source, config, tsconfig, and project files from memory, combine `overrideConfigFile: true` (use only the inline config), an inline `overrideConfig`, and a `virtualFiles` overlay:

```ts
const rslint = new Rslint({
  cwd: '/', // stable root for the virtual paths below
  overrideConfigFile: true, // use only overrideConfig — skip config discovery
  overrideConfig: [
    {
      files: ['**/*.ts'],
      // The tsconfig + parserOptions.project below are needed ONLY for
      // type-aware rules (like no-for-in-array). Other rules need neither.
      languageOptions: { parserOptions: { project: ['./tsconfig.json'] } },
      plugins: ['@typescript-eslint'],
      rules: { '@typescript-eslint/no-for-in-array': 'error' },
    },
  ],
  virtualFiles: {
    'tsconfig.json': JSON.stringify({
      compilerOptions: { strict: true },
      files: ['./a.ts'],
    }),
  },
});

const [result] = await rslint.lintText(
  'const a = [1];\nfor (const k in a) {}\n',
  { filePath: 'a.ts' },
);
```

`virtualFiles` is an in-memory file overlay (path → content) — an rslint extension; ESLint has no in-memory file map. Put the `tsconfig.json` that `parserOptions.project` names, plus any dependency files, in the overlay. The overlay does not disable filesystem fallback: rslint may still consult disk for `.gitignore` and TypeScript resolution, so this API is not a filesystem sandbox.

**Declaring plugins.** A rule from a plugin (`@typescript-eslint/*`, `unicorn/*`, and so on) runs only when that plugin is listed in `plugins` — rslint enforces this exactly like ESLint. Core rules (no `/` prefix) need no declaration.

**Type-aware vs non-type-aware rules.** The `tsconfig.json` and `parserOptions.project` matter only for **type-aware** rules, which need a real TypeScript program (see [Type Checking](https://rslint.rs/guide/type-checking.md)). If your config has only rules that do not require type information, you can drop both — no tsconfig, no `parserOptions.project`.

**Use relative paths** in `virtualFiles` keys and inside the tsconfig:

- **`virtualFiles` keys**: prefer relative paths (`'tsconfig.json'`). Keys are always resolved against `cwd`. An absolute key like `'/tsconfig.json'` happens to match only when `cwd` is `/`; with any other `cwd` it lands at the filesystem root.
- **`parserOptions.project`**: relative paths resolve from the config entry's effective base. In this override-only example that base is `cwd`; a `basePath` changes it. For a discovered config module it is normally the module directory.
- **Inside the tsconfig** (`files` and `include`): relative paths resolve from the tsconfig's own directory. A bare POSIX-absolute path (such as `/a.ts`) has no drive letter on Windows, so it won't match the overlay.

**Pin the tsconfig to explicit `files`** — a broad `include` glob is expanded against the real filesystem and scans from the tsconfig's directory (which is `cwd` in this example).

## Auto-fixing

Pass `fix: true`. A result whose file received at least one applied fix carries an `output` string — the full final source, even if later fixes restored the input; results with no applied fix have no `output`.

Rslint repeats linting and fixing until no fix is produced, a fix cycle restores the input, or ten writable rounds have run. `messages` and all diagnostic counts describe the final source in `output`, so successfully fixed findings are no longer reported. If the round limit leaves a fixable finding, its `message.fix` range also targets that final source.

**Write fixes to disk** with the static [`Rslint.outputFixes`](https://rslint.rs/api/rslint.md#outputfixes):

```ts
const rslint = new Rslint({ fix: true });
const results = await rslint.lintFiles(['src/**/*.ts']);
await Rslint.outputFixes(results); // writes fixed files back to disk
```

`Rslint.outputFixes` writes back only results whose `filePath` is absolute. A `lintText` result is absolute — and so will be written — when you pass a `filePath`; only a result with no `filePath` (the non-absolute `"<text>"` sentinel) is skipped.

**Apply fixes in memory** — to fix without touching disk, read `output` directly and don't call `outputFixes`:

```ts
const rslint = new Rslint({ fix: true /* + your in-memory config */ });
const [result] = await rslint.lintText('let x = foo!!.bar', {
  filePath: 'a.ts',
});
const fixed = result.output ?? 'let x = foo!!.bar'; // fixed source, or the original if nothing changed
```

`lintText` with `fix: true` never writes to disk — the fixed source comes back as `result.output`. For edit-level control, each `result.messages[].fix` is a `{ range: [start, end], text }` edit (UTF-16 offsets) you can splice into the source yourself; for more than one fix prefer `output`, which is already the safely merged whole-file result.

## Lifecycle

Each `Rslint` instance owns a long-lived rslint engine child process. You **don't** need to call `close()` — like ESLint, a one-off script exits cleanly on its own (the idle child is unref'd, so it never blocks the event loop).

Call [`close()`](https://rslint.rs/api/rslint.md#close) only in a long-running host (an editor server, a watch process) that creates many instances, to free each child promptly:

```ts
const rslint = new Rslint();
try {
  await rslint.lintFiles(['src/**/*.ts']);
} finally {
  await rslint.close();
}
```

Or use `await using` for automatic disposal at the end of scope:

```ts
await using rslint = new Rslint();
await rslint.lintFiles(['src/**/*.ts']);
```

Native `await using` needs a runtime with explicit resource management support, which Node.js 22 lacks (a bare `.mjs` throws a SyntaxError). Compile with a `using`-aware toolchain such as TypeScript 5.2+, or use the `try` / `finally` form above, which does not rely on native `using` syntax.

## Result shape

Both methods resolve to `LintResult[]`:

| Field                 | Type            | Description                                                         |
| --------------------- | --------------- | ------------------------------------------------------------------- |
| `filePath`            | `string`        | Absolute path, or `"<text>"` for `lintText` called with no filePath |
| `messages`            | `LintMessage[]` | Diagnostics for this file                                           |
| `errorCount`          | `number`        | Number of error-severity messages                                   |
| `warningCount`        | `number`        | Number of warning-severity messages                                 |
| `fixableErrorCount`   | `number`        | Errors that have an auto-fix                                        |
| `fixableWarningCount` | `number`        | Warnings that have an auto-fix                                      |
| `output`              | `string?`       | Final source — present when `fix: true` applied at least one fix    |

Each `LintMessage`:

| Field                   | Type                                         | Description                                                                  |
| ----------------------- | -------------------------------------------- | ---------------------------------------------------------------------------- |
| `ruleId`                | `string \| null`                             | The rule that produced the message (`null` if none)                          |
| `severity`              | `1 \| 2`                                     | `2` = error, `1` = warning                                                   |
| `message`               | `string`                                     | Human-readable message                                                       |
| `messageId`             | `string?`                                    | Stable message id, when the rule provides one                                |
| `line` / `column`       | `number`                                     | 1-based position (`column` counts UTF-16 code units)                         |
| `endLine` / `endColumn` | `number?`                                    | 1-based end position, when available                                         |
| `fix`                   | `{ range: [number, number]; text: string }?` | Flat UTF-16 offset range + replacement text                                  |
| `suggestions`           | `LintSuggestion[]?`                          | Suggested fixes (each with `desc`, `fix`, and optional `messageId` / `data`) |

## Options

[`new Rslint(options)`](https://rslint.rs/api/rslint.md#constructor) accepts:

| Option               | Type                                        | Default     | Description                                                                                                                                                                    |
| -------------------- | ------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `cwd`                | `string`                                    | current cwd | Working directory for targets and discovery; also the authored base of inline entries without `basePath`                                                                       |
| `overrideConfig`     | `RslintConfigEntry \| RslintConfig \| null` | —           | Extra config appended after the resolved/discovered config; `basePath` inherits the ConfigArray base, while entries without it keep Rslint's existing `cwd`-relative behavior  |
| `overrideConfigFile` | `string \| true \| null`                    | `null`      | `string`: use this module; `basePath` resolves from `cwd`, while entries without it retain the module-directory base. `true`: use only the inline override; otherwise discover |
| `fix`                | `boolean`                                   | `false`     | Apply rule auto-fixes; results carry `output`                                                                                                                                  |
| `virtualFiles`       | `Record<string, string>`                    | —           | In-memory file overlay (path → content); unresolved reads may fall back to disk                                                                                                |

See the [`basePath` configuration reference](https://rslint.rs/config/base-path.md) for the full source matrix.
