hynt
v1.5.1
Published
TypeScript/TSX Hydration Checker - Catches Next.js hydration errors before production
Downloads
9
Maintainers
Readme
Hynt
A TypeScript/TSX Hydration Checker with pattern detection. Catches Next.js hydration errors before production using pattern detection and AST analysis.
Features
- Comprehensive Detection: 9 specialized pattern detectors covering all hydration error types
- Performance: Clustering and parallel processing for efficient throughput
- Zero False Positives: Context-aware AST analysis with pattern matching
- Next.js Optimized: Built specifically for Next.js SSR/SSG hydration issues
- Extensible: Modular architecture with pattern registry system
- CI/CD Ready: JSON output, exit codes, and automated setup
- Auto-Setup: Automatic configuration on install via postinstall script
Installation
# Install as dev dependency (recommended)
npm install --save-dev hynt
# Or run once with npx
npx hyntRequirements: Node.js >= 16
Quick Start
# Analyze your project
npx hynt
# Strict mode (fail on errors)
npx hynt --strict
# CI/CD mode
npx hynt --ci
# Analyze specific directory
npx hynt --path ./srcDetection Capabilities
Hynt uses 9 specialized pattern detectors plus 3 React-specific analyzers to catch all hydration errors:
Pattern-Based Detectors (Unified Hydration Analyzer)
Universal Hydration Detector - Modular pattern registry detecting:
- Non-deterministic values (Math.random, Date, crypto.randomUUID)
- Conditional expressions with browser APIs
- Logical expressions with client-only code
- Hook dependencies with non-deterministic values
- Return statements with dynamic content
- Template literals with random values
- Object/array patterns with non-deterministic properties
- Function calls to browser-only APIs
Non-Deterministic Value Detector - Detection for:
- Math.random() usage
- Date.now(), new Date() in render
- crypto.randomUUID(), crypto.getRandomValues()
- window.location, document properties
- localStorage, sessionStorage access
- Any value that differs between server and client
Text Content Mismatch Detector - Detects:
- Server/client text differences
- Dynamic text content in JSX
- Template literals with non-deterministic values
- Whitespace-only text nodes in sensitive contexts
Attribute Mismatch Detector - Finds:
- className/class differences
- Style attribute mismatches
- Boolean attributes (checked, disabled, selected)
- data-* and aria-* attribute issues
- Browser-dependent attribute values
Nesting Violation Detector - Identifies:
- Invalid HTML nesting (e.g.,
<p>inside<p>) - Interactive elements nested incorrectly
- Table structure violations
- List item placement issues
- Invalid HTML nesting (e.g.,
Whitespace Issue Detector - Catches:
- Inconsistent whitespace in inline elements
- Mixed whitespace types (spaces/tabs/newlines)
- Leading/trailing whitespace in blocks
- Whitespace between inline elements
Conditional Rendering Detector - Detects:
- Browser API-dependent conditionals
- Client-only state in rendering logic
- Inconsistent ternary/logical operators
- SSR/client conditional mismatches
DangerouslySetInnerHTML Detector - Flags:
dangerouslySetInnerHTMLmismatches- Dynamic HTML content differences
Suspense Boundary Detector - Identifies:
- Suspense boundary issues
- Missing or dynamic fallback content
- Third-party component hydration problems
React-Specific Analyzers
Consistent UseId Analyzer - Validates:
- Proper useId() hook usage
- Static ID attributes in form elements
- Math.random() used for IDs
No Missing Keys Analyzer - Checks:
- Missing key props in .map() calls
- Keys in JSX elements within arrays
No Unsafe Hooks Analyzer - Detects:
- useLayoutEffect during SSR
- useImperativeHandle, useInsertionEffect issues
- DOM manipulation in hooks
- Conditional hook usage
CLI Options
Basic Options
-s, --strict- Exit with non-zero code on any hydration issue-j, --json- Output report in JSON format-c, --ci- CI/CD friendly mode (JSON output + non-zero exit on issues)-p, --path <dir>- Target directory to analyze (default: current working directory)-r, --runtime- Enable SSR → DOM hydration diff analysis
Advanced Options
--parallel- Enable parallel processing (default: true)--no-parallel- Disable parallel processing--max-issues <number>- Maximum number of issues to report (0 = unlimited, default: 0)--patterns-only- Use only pattern-based detection (disable React-specific analyzers)--legacy-only- Use only React-specific analyzers (disable pattern-based detection)
Setup Command
hynt setup- Generate hynt.config.ts for your projecthynt setup --force- Overwrite existing configuration file
Configuration
Generate a configuration file:
npx hynt setuphynt.config.ts
import { HyntConfig } from 'hynt';
const config: HyntConfig = {
rules: {
// === Pattern-Based Detection ===
// The unified-hydration rule uses pattern detection
// to catch hydration errors automatically
'unified-hydration': 'issue',
// === React-Specific Analyzers ===
// These cover React-specific patterns not handled by pattern detection
'consistent-useId': 'issue', // Validates proper useId() usage
'no-missing-keys': 'issue', // Checks for keys in .map()
'no-unsafe-hooks': 'issue' // React hooks best practices
},
// Files and directories to exclude from analysis
exclude: [
'node_modules/**',
'.next/**',
'dist/**',
'build/**',
'coverage/**',
'out/**',
'.cache/**',
'**/*.test.ts',
'**/*.test.tsx',
'**/*.spec.ts',
'**/*.spec.tsx',
'**/__tests__/**',
'**/*.d.ts'
],
// Enable runtime hydration analysis (SSR → DOM comparison)
runtimeChecks: false,
// Maximum number of issues to report (0 = unlimited)
maxIssues: 0,
// Enable parallel processing
parallel: true
};
export default config;Rule Severity Levels:
'issue'- Enable the rule and report issues'off'- Disable the rule
Architecture
Hynt uses a modular architecture with separation of concerns:
┌─────────────────────────────────────────────┐
│ CLI Interface │
│ (Commander.js + Console Reporter) │
├─────────────────────────────────────────────┤
│ Analysis Engine │
│ (Orchestrates file discovery & analysis) │
├─────────────────────────────────────────────┤
│ Unified Detection Engine │
│ ├─ Pattern Registry │
│ ├─ Unified Hydration Analyzer │
│ └─ Pattern Context & Caching │
├─────────────────────────────────────────────┤
│ Pattern Detectors (9) │
│ ├─ Universal Hydration Detector │
│ ├─ Non-Deterministic Value Detector │
│ ├─ Text Content Mismatch Detector │
│ ├─ Attribute Mismatch Detector │
│ ├─ Nesting Violation Detector │
│ ├─ Whitespace Issue Detector │
│ ├─ Conditional Rendering Detector │
│ ├─ DangerouslySetInnerHTML Detector │
│ └─ Suspense Boundary Detector │
├─────────────────────────────────────────────┤
│ React-Specific Analyzers (3) │
│ ├─ Consistent UseId Analyzer │
│ ├─ No Missing Keys Analyzer │
│ └─ No Unsafe Hooks Analyzer │
├─────────────────────────────────────────────┤
│ File Cluster Processor │
│ ├─ Adaptive Batch Sizing │
│ ├─ Resource-Aware Concurrency │
│ └─ CPU/Memory Detection │
└─────────────────────────────────────────────┘Examples
Basic Usage
# Analyze Next.js project
cd my-nextjs-app
npx hynt
# Expected output:
# Discovered 42 files to analyze
#
# 0 issues — 42 files analyzed
# Analysis completed in 2.3s
#
# Hynt - Hydration AnalysisWhen issues are found, they're displayed with file paths, line numbers, rule names, and suggestions:
src/pages/index.tsx
15:23 issue Non-deterministic value detected [Non-deterministic value detected]
Use a deterministic value or move to client-side only
Code: Math.random()
0 issues — 3 files analyzed
Analysis completed in 60.9msCI/CD Integration
# .github/workflows/check-hydration.yml
name: Hydration Check
on: [push, pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
- run: npx hynt --ciProgrammatic Usage
import { AnalysisEngine, HyntConfiguration } from 'hynt';
import { UnifiedHydrationAnalyzer } from 'hynt/domain/rules/UnifiedHydrationAnalyzer';
import { ConsistentUseIdAnalyzer } from 'hynt/domain/rules/ConsistentUseIdAnalyzer';
import { NoMissingKeysAnalyzer } from 'hynt/domain/rules/NoMissingKeysAnalyzer';
import { NoUnsafeHooksAnalyzer } from 'hynt/domain/rules/NoUnsafeHooksAnalyzer';
const config: HyntConfiguration = {
rules: {
'unified-hydration': 'issue',
'consistent-useId': 'issue',
'no-missing-keys': 'issue',
'no-unsafe-hooks': 'issue'
},
exclude: ['node_modules/**'],
include: ['**/*.ts', '**/*.tsx'],
runtimeChecks: false,
maxIssues: 0,
parallel: true
};
const engine = new AnalysisEngine([
new UnifiedHydrationAnalyzer(),
new ConsistentUseIdAnalyzer(),
new NoMissingKeysAnalyzer(),
new NoUnsafeHooksAnalyzer()
]);
const report = await engine.analyzeProject('./src', config);
console.log(`Found ${report.summary.issues} issues in ${report.summary.filesAnalyzed} files`);Performance
Hynt is designed for speed and resource efficiency:
- Parallel Processing: Analyzes files concurrently using up to 80% of available CPU cores
- Clustering: Adaptive batch sizing (default: 15 files per batch)
- Resource-Aware: Automatically adjusts concurrency based on CPU count and available memory
- Pattern Caching: Detection results cached per file to avoid redundant analysis
- Automatic Thresholds: Clustering enabled automatically for 20+ files
Performance Characteristics:
- Uses adaptive batching to balance throughput and memory usage
- Automatically detects concurrency based on system resources
- Processes files in parallel batches
- Memory-aware to prevent system overload on large projects
Development
# Clone repository
git clone https://github.com/abd-ul-ahad/hynt.git
cd hynt
# Install dependencies
npm install
# Build
npm run build
# Run tests
npm test
# Run on example project
cd examples/nextjs-app
npx hyntAdvanced Topics
Automatic Setup
Hynt automatically sets up configuration when installed via npm. The postinstall script:
- Detects React/Next.js projects
- Creates
hynt.config.tsif it doesn't exist - Adds npm scripts to
package.json(optional) - Provides setup messages
Custom Pattern Detectors
Create your own pattern detector by extending BaseHydrationPattern:
import { BaseHydrationPattern, PatternContext, PatternCategory } from 'hynt/domain/patterns';
export class MyCustomDetector extends BaseHydrationPattern {
readonly id = 'my-custom-check';
readonly name = 'My Custom Check';
readonly description = 'Detects my specific hydration issue';
readonly category = PatternCategory.CUSTOM;
readonly enabled = true;
protected async executeDetection(context: PatternContext) {
const issues = [];
// Your detection logic here
// Access context.ast, context.sourceCode, context.filePath
// Use this.createIssue() helper to create issues
return this.createResult(issues);
}
}Pattern Registry
Register custom patterns with the Unified Detection Engine:
import { PatternRegistry, UnifiedDetectionEngine } from 'hynt/domain/patterns';
const registry = new PatternRegistry();
registry.register(new MyCustomDetector());
const engine = new UnifiedDetectionEngine(registry);Contributing
Contributions welcome! Please read CONTRIBUTING.md first.
License
BSD-2-Clause - see LICENSE for details.
Acknowledgments
Built with:
- @babel/parser - AST parsing and traversal
- @babel/traverse - AST traversal
- TypeScript - Type safety
- Commander - CLI framework
- Chalk - Terminal colors
- fs-extra - File system utilities
Made by the Hynt Contributors
