npm package: @redocly/recheck
Description: Content linting (configurable + built-in rules)
Author: Redocly
Latest version: 0.1.0

# Recheck - Content Linting Tool

A modern, production-ready content linter for markdown files with configurable rules and built-in content quality checks.

## Features

✅ **Modern Scope-Based Architecture**
- File-first processing with semantic scope parsing
- Support for `sentence`, `paragraph`, `heading`, `code`, `default`, `raw`, and `all` scopes
- Vale-compatible scope notation (e.g., `heading.h1`, `heading.h2`)
- Efficient rule indexing for fast processing at scale

✅ **Flexible Configuration Format**
- Modern `assertions`-based rule definitions
- `severity` levels: `off`, `info`, `warn`, `error`
- Array-based scope targeting for precise control
- Comprehensive JSON Schema validation

✅ **Production-Ready Engine**
- High-performance JavaScript engine optimized for large repositories
- Successfully processes 300+ files with 1,000+ issues efficiently
- Built-in rules for common content quality checks
- Safe auto-fix capabilities for appropriate rules

✅ **Developer-Friendly CLI**
- Table, JSON, SARIF, and GitHub Actions output formats for CI/CD integration
- Universal output-path option for file export
- Inline PR annotations with GitHub Actions format
- Severity filtering and detailed statistics
- Auto-fix with granular control
- Comprehensive error reporting

## Installation

```bash
# Navigate to the recheck package
cd packages/recheck

# Install dependencies
pnpm install

# Build the project
pnpm build
```

## Usage

### Validate Configuration

```bash
# Validate with explicit config file
node dist/cli.js validate --config recheck.example.yaml

# Auto-discover config file in current directory
node dist/cli.js validate
```

### Run content linting

```bash
# Run on current directory
node dist/cli.js run . --config recheck.example.yaml

# Run on specific file
node dist/cli.js run README.md --config recheck.example.yaml

# Filter by severity (only show errors)
node dist/cli.js run . --severity error

# Show all enabled rules (info and above)
node dist/cli.js run . --severity info

# Output formats (table is default)
node dist/cli.js run . --output table           # Human-readable table (default)
node dist/cli.js run . --output json            # Structured JSON for CI
node dist/cli.js run . --output sarif           # SARIF format for security tools
node dist/cli.js run . --output github-actions  # GitHub Actions annotations (inline PR comments)

# Show detailed statistics
node dist/cli.js run . --stats

# Auto-fix safe issues (trailing spaces, bullet style, hard tabs)
node dist/cli.js run . --fix

# Combine auto-fix with statistics
node dist/cli.js run . --fix --stats

# Limit annotations for CI (applies to file output, default: 20)
node dist/cli.js run . --annotations-limit 50

# Output to file (works with all formats)
node dist/cli.js run . --output json --output-path report.json
node dist/cli.js run . --output sarif --output-path recheck.sarif
node dist/cli.js run . --output json --output-path limited.json --annotations-limit 50

# Emit run summary to a file (json or text)
node dist/cli.js run . --summary json --summary-path recheck-summary.json

# Scan only changed files (via file list or stdin)
# From file:
node dist/cli.js run . --changed-only --changed-list changed.txt
# Or with stdin:
git diff --name-only origin/main... | node dist/cli.js run . --changed-only
```

## Configuration Format

Configuration uses a modern `assertions`-based format with `severity` levels and flexible scope targeting:

```yaml
recheck/us-spelling:
  scope: all # default
  severity: error
  message: 'Use the US spelling "%s" instead of British "%s".'
  link: https://docs.microsoft.com/en-us/style-guide/word-choice/use-us-spelling-avoid-non-english-words
  appliesTo:
    - "docs/**"              # Only apply to documentation
  assertions:
    swap:
      ignoreCase: true
      wordBoundary: true
      pairs:
        color: colour
        behavior: behaviour
        organize: organise
  exceptions:
    files: [docs/style-guide.md]
    lines:
      - "British spellings such as 'color'"

recheck/no-gerund-headings:
  severity: error
  scope: 
    - heading.h1
    - heading.h2
    - heading.h3
  message: 'Do not start headings with a gerund.'
  excludes:
    - "**/drafts/**"         # Exclude draft documents
  assertions:
    pattern:
      ignoreCase: true
      tokens:
        - '^\\w*ing.*'

recheck/config-line-length:
  severity: error
  message: 'Config docs: keep lines under %s characters.'
  appliesTo:
    - "docs/config/**"       # Only apply to config documentation
  assertions:
    max-line-length:
      max: 100
      ignoreCodeBlocks: true

recheck/bullet-style-dash:
  severity: error
  message: "Use '-' for unordered list bullets."
  autoFixable: true  # Safe for auto-fix
  excludes:
    - "**/examples/**"       # Allow mixed styles in examples
  assertions:
    bullet-style:
      style: '-'
      normalizeNested: true
```

## Exceptions

Rules can be configured with exceptions to skip specific files or lines:

### File Exceptions

Skip entire files using glob patterns or exact matches:

```yaml
recheck/us-spelling:
  # ... other config
  exceptions:
    files:
      - "docs/style-guide.md"      # Exact filename
      - "docs/api/*.md"            # Glob pattern
      - "**/CHANGELOG.md"          # Recursive glob
```

**File matching supports:**
- **Basename matching**: `style-guide.md` matches any file with that name
- **Relative path matching**: `docs/style-guide.md` matches the specific path
- **Glob patterns**: `docs/*.md` matches all markdown files in docs directory

### Line Exceptions

Skip specific lines using fragment matching:

```yaml
recheck/no-trailing-spaces:
  # ... other config
  exceptions:
    lines:
      - "British spellings such as"    # Fragment match
      - "Code example:"                # Beginning of line
      - "// ignore-lint"               # Comment-based exception
```

**Line matching behavior:**
- **Fragment matching**: If the line contains the exception text anywhere, it's skipped
- **Case-sensitive**: `"Code Example"` does not match `"code example"`
- **Multiple patterns**: Any matching pattern will skip the line

### Exception Examples

```yaml
# Skip documentation style guides for spelling rules
recheck/us-spelling:
  exceptions:
    files: ["docs/style-guide.md", "**/*style*"]
    lines: ["British spellings such as 'colour'"]

# Skip auto-generated files and code blocks
recheck/no-trailing-spaces:
  exceptions:
    files: ["**/generated/**", "CHANGELOG.md"]
    lines: ["```", "Code example:", "// prettier-ignore"]
```

## Rule Types and Assertions

### Assertion Types

Rules are defined using `assertions` that specify their behavior:

#### Swap Assertions (`swap`)
Text replacement with configurable options:
```yaml
assertions:
  swap:
    ignoreCase: true
    wordBoundary: true
    pairs:
      color: colour
      behavior: behaviour
```

#### Pattern Assertions (`pattern`)
Regex-based pattern matching:
```yaml
assertions:
  pattern:
    ignoreCase: true
    tokens:
      - '^\\w*ing.*'
```

#### Built-in Assertions
Predefined content checks with typed options:
- `max-line-length` - Line length enforcement
- `no-trailing-spaces` - Trailing whitespace detection ✅ **Auto-fixable**
- `bullet-style` - Unordered list bullet consistency ✅ **Auto-fixable**
- `semantic-line-breaks` - Semantic line break validation
- `no-hard-tabs` - Hard tab detection ✅ **Auto-fixable**
- `no-duplicate-headings` - Duplicate heading detection
- `no-broken-fragment-links` - Broken link fragment detection

### Enhanced Scope Support

The `scope` field supports arrays and specific targeting:
```yaml
scope: all              # Apply to all content
scope: heading          # Apply to all headings
scope: sentence         # Apply to sentences only
scope: paragraph        # Apply to paragraphs only
scope: code             # Apply to code blocks only
scope: default          # Apply to default content (excludes code/comments)
scope: raw              # Apply to raw file content
scope:                  # Apply to specific heading levels
  - heading.h1
  - heading.h2
  - heading.h3
```

### Rule Severity Levels

Rules can be configured with different severity levels:

- **`off`**: Disable the rule completely
- **`info`**: Informational messages (exit code 0)
- **`warn`**: Warning messages (exit code 0)
- **`error`**: Error messages (exit code 1)

### Auto-Fix Safety

Only rules marked with `autoFixable: true` can be automatically corrected:

- ✅ **Safe Rules**: `no-trailing-spaces`, `bullet-style`, `no-hard-tabs`
- ❌ **Unsafe Rules**: `max-line-length`, `semantic-line-breaks`, `no-duplicate-headings`

## GitHub Actions Integration

Recheck provides seamless GitHub Actions integration for automated content quality checking on pull requests.

### Output Format: `github-actions`

Use the `--output github-actions` format to generate inline file annotations that appear directly on pull request files:

```bash
# Basic GitHub Actions output
node dist/cli.js run docs --output github-actions

# With annotation limits (recommended for PR workflows)
node dist/cli.js run docs --output github-actions --annotations-limit 20
```

### Annotation Output

The GitHub Actions format produces annotations that GitHub automatically displays as inline comments:

```
::error title=recheck/no-trailing-spaces,file=docs/guide.md,line=42,col=15,endColumn=18::Remove trailing spaces.
::warning title=recheck/bullet-style-dash,file=docs/api.md,line=23,col=1,endColumn=2::Use '-' for unordered list bullets.
```

### GitHub Actions Limits

GitHub Actions has strict limits on annotations:
- **10 error** and **10 warning** annotations per step
- **50 total** annotations per job

**Recommendation**: Use `--annotations-limit 20` (the default) to stay well within these limits while prioritizing the most critical issues.

### Workflow Example

```yaml
- name: Run recheck with inline annotations
  run: |
    node packages/recheck/dist/cli.js run docs \
      --config recheck.yaml \
      --output github-actions \
      --changed-only < changed-files.txt
```

This creates both inline file annotations AND summary comments when combined with the PR comment workflow.

## Performance

The new architecture delivers excellent performance:

- ✅ **Small Projects**: ~15ms for single files
- ✅ **Medium Projects**: ~50-100ms for 10-50 files
- ✅ **Large Projects**: Successfully processes 300+ files with 1,000+ issues
- ✅ **Scalable**: File-first architecture with rule indexing optimizes for large repositories

## Dependencies

### Runtime Dependencies
- `ajv` + `ajv-formats` - JSON Schema validation
- `js-yaml` - YAML configuration parsing
- `yargs` - CLI interface
- `colorette` - Terminal colors
- `picomatch` - File pattern matching

### Development Dependencies
- `vitest` - Modern testing framework
- `typescript` - Type checking and compilation
- `@types/*` - TypeScript definitions

## Example Output

### Standard Run
```
🏃 Running recheck on: docs/
✅ Configuration loaded successfully!
   Config file: recheck.yaml
   Loaded 8 rule(s)
   Disabled 1 rule(s) (severity: off)

🔧 Running 8 rule(s)...
   Found 311 markdown file(s)
   Checking rule: us-spelling...
   Checking rule: no-gerund-headings...
   Checking rule: oxford-comma...
   Checking rule: no-trailing-spaces...
   Checking rule: bullet-style-dash...
   Checking rule: semantic-line-breaks...
   Checking rule: no-hard-tabs...
   Checking rule: no-duplicate-headings...

📋 Found 1086 issue(s):

us-spelling               README.md:68:5      Use the US spelling "color" instead of British "colour".
no-trailing-spaces        README.md:15:42     Remove trailing spaces.
bullet-style-dash         docs/guide.md:22:1  Use '-' for unordered list bullets.

   65 error(s)
   1021 warning(s)

❌ Found 65 error(s). Exiting with code 1.
   Completed in 156ms
```

### JSON Output
```json
{
  "summary": {
    "filesScanned": 311,
    "totalIssues": 1086,
    "breakdown": {
      "recheck/no-trailing-spaces": {
        "errors": 65,
        "warnings": 0,
        "info": 0,
        "total": 65
      },
      "recheck/bullet-style-dash": {
        "errors": 1021,
        "warnings": 0,
        "info": 0,
        "total": 1021
      }
    }
  },
  "issues": [
    {
      "file": "../../docs/public/branding/index.md",
      "line": 13,
      "column": 22,
      "text": "Use the brand guidelines when applying Redocly brand",
      "match": "  ",
      "ruleName": "recheck/no-trailing-spaces",
      "severity": "error",
      "message": "Remove trailing spaces."
    }
  ]
}
```

## What's Working Now

- ✅ **Modern Architecture**: File-first processing with scope-based rule application
- ✅ **Vale Compatibility**: Scope notation compatible with Vale linter
- ✅ **Swap Rules**: Find and replace text patterns with word boundaries and case sensitivity
- ✅ **Pattern Rules**: Regex matching with precise scope filtering
- ✅ **Built-in Rules**: All 6 built-in rules fully implemented with comprehensive tests
- ✅ **File Discovery**: Recursive markdown file finding with common directory exclusions
- ✅ **Multiple Output Formats**: Human-readable table, structured JSON, SARIF, and GitHub Actions
- ✅ **Severity Filtering**: Show only errors, warnings, or all issues
- ✅ **Exit Codes**: Non-zero exit when errors found (perfect for CI)
- ✅ **Exception Handling**: Skip lines and files that match exception patterns
- ✅ **Auto-Fix**: Safe automatic correction for appropriate rules
- ✅ **Production Scale**: Successfully handles large documentation repositories
- ✅ **Comprehensive Testing**: Full test suite with 161 passing tests


### Key Design Principles

- **File-First Processing**: Iterate by files, then by semantic scopes within files
- **Scope-Based Rules**: Apply rules only to relevant content scopes
- **Type Safety**: Full TypeScript coverage with strict typing
- **Scope parsing**: Efficient per-file segmentation for applying rules by scope
- **Modular Rules**: Each built-in rule in its own file with dedicated tests
- **Safe Auto-Fix**: Granular control over which rules can auto-fix
- **Vale Compatibility**: Scope notation compatible with existing Vale configurations

## File Targeting

Rules can target specific files using path patterns with `appliesTo` and `excludes`:

### Apply Rules to Specific Files

```yaml
recheck/config-docs-only:
  severity: error
  message: "Config docs must follow specific patterns"
  appliesTo:
    - "docs/config/**"        # All files in docs/config directory
    - "**/api/*.md"           # All .md files in any api directory  
    - "*.config.md"           # Files ending with .config.md
  assertions:
    pattern:
      tokens: ["TODO"]

recheck/api-standards:
  severity: warn
  message: "API docs need review"
  appliesTo:
    - "docs/api/**"           # Target API documentation
    - "**/endpoints/*.md"     # Target endpoint documentation
  assertions:
    pattern:
      tokens: ["DRAFT", "TBD"]
```

### Exclude Files from Rules

```yaml
recheck/no-todos:
  severity: error
  message: "No TODOs allowed"
  excludes:
    - "docs/drafts/**"        # Exclude all draft documents
    - "**/temp*.md"           # Exclude temporary files
    - "README.md"             # Exclude specific file
  assertions:
    pattern:
      tokens: ["TODO"]
```

### Path Pattern Support

File targeting supports multiple pattern types:

- **Full path patterns**: `docs/config/**`, `src/components/*.md`
- **Recursive patterns**: `**/api/*.md`, `**/README.md`
- **Basename patterns**: `*.config.md`, `temp*.md` (backward compatible)
- **Exact matches**: `README.md`, `docs/guide.md`

### Pattern Matching Strategy

The enhanced pattern matching checks patterns against:

1. **Filename** (`config.md`) - for simple patterns
2. **Relative path** (`docs/config/settings.md`) - for full path patterns  
3. **Path segments** (`config/settings.md`) - for partial path patterns

This allows flexible targeting while maintaining backward compatibility.

## Contributing

Want to add new assertions or improve existing ones? Check out our **[Contributing Guide](src/assertions/CONTRIBUTING.md)** for:

- 🏗️ **Architecture overview** - How the centralized scoping system works
- 📝 **Step-by-step guide** - Create new assertions following best practices  
- 🧪 **Testing guidelines** - Comprehensive test coverage examples
- ✅ **Code standards** - Follow our established conventions
- 🚀 **Quick examples** - Get started with working code templates

The guide covers our modern architecture where the **runner handles scoping automatically**, so your assertions can focus on their core logic without worrying about segment filtering or line number adjustments.

## Future Enhancements

1. **Plugin System**: Custom rule loading from external files/packages
2. **Configuration Inheritance**: Config file discovery and inheritance
3. **Watch Mode**: Real-time linting as files change
4. **IDE Integration**: Language server protocol support
5. **Additional Scopes**: Support for more Vale-compatible scopes