npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@angular-modernizer/core

v1.2.0

Published

Core kernel for the Angular Modernization Platform

Readme

@angular-modernizer/core

The Kernel - Infrastructure and plugin lifecycle management

Overview

The @angular-modernizer/core package provides the foundational infrastructure for the Angular Modernization Platform. It contains the Kernel, file system abstractions, plugin management system, transformation pipeline, and advanced orchestration capabilities that power the entire platform.

Architecture

The core package follows the "Infrastructure Only" principle - it provides domain-agnostic building blocks without any Angular-specific logic.

Kernel (Domain Agnostic)
  - Plugin System (Contracts)
  - File System (Abstraction)
  - TypeScript Project (ts-morph)
  - Transformation Pipeline (Coordinator + Execution Engine)
  - Orchestration System (Parallel + Incremental + Workers)
  - Cache Manager (AST Caching + Invalidation)

Core Components

Kernel

The Kernel is the central orchestrator that manages the entire platform lifecycle:

interface KernelConfig {
  tsConfigPath?: string;
  fileSystem?: FileSystemAdapter;
  projectOptions?: Partial<ProjectOptions>;
  plugins?: Plugin[];
  transformationCoordinator?: TransformationCoordinator;
  api?: unknown; // defaults to createPublicApi(project) when plugins are set
  cacheConfig?: Partial<CacheConfig>;
  resourceLimits?: ResourceLimits;
  enableParallelExecution?: boolean; // default: true
}

class Kernel {
  constructor(config?: KernelConfig); // All parameters optional

  async initialize(): Promise<void>;
  getProject(): Project;
  getFileSystem(): FileSystemAdapter;
  getCacheManager(): CacheManager | undefined;
  getBuildValidator(): BuildValidator;
  getPlugin(name: string): Plugin | undefined;
  getAllPlugins(): Plugin[];
  hasPlugin(name: string): boolean;
  isInitialized(): boolean;
  getConfig(): Readonly<KernelConfig>;
  getProjectRoot(): string; // safe before initialize()

  // Transformation API
  transformFile(
    sourceFile: SourceFile,
    config?: TransformationConfig,
  ): Promise<TransformationResult>;

  // Orchestration API
  getParallelExecutor(): ParallelExecutor | undefined;
  getIncrementalAnalyzer(): IncrementalAnalyzer | undefined;
  getProgressReporter(): ProgressReporter | undefined;
  getResourceManager(): ResourceManager | undefined;
  getOrchestrationStats(): OrchestrationStats | undefined;

  analyzeParallel(options?: ParallelAnalysisOptions): Promise<unknown[]>;
  analyzeIncremental(options?: IncrementalAnalysisOptions): Promise<unknown>;
}

Key features:

  • All constructor parameters are optional with sensible defaults
  • Async lifecycle management with async plugin loading
  • Full TypeScript support with strict typing
  • Configuration is read-only after initialization

Usage examples:

// Minimal setup
const kernel1 = new Kernel();
await kernel1.initialize();

// Explicit empty config
const kernel2 = new Kernel({});
await kernel2.initialize();

// Full configuration
const kernel3 = new Kernel({
  tsConfigPath: './tsconfig.json',
  fileSystem: new RealFileSystemAdapter(),
  plugins: [new StandalonePlugin()],
});
await kernel3.initialize();

File System Abstraction

The platform uses a custom FileSystemAdapter interface to enable both production file system access and in-memory testing:

interface FileSystemAdapter {
  readFile(path: string): Promise<string>;
  writeFile(path: string, content: string): Promise<void>;
  exists(path: string): Promise<boolean>;
  readDirectory(path: string): Promise<string[]>;
  deleteFile(path: string): Promise<void>;
  createDirectory(path: string): Promise<void>;
  fileExists(path: string): Promise<boolean>;
  directoryExists(path: string): Promise<boolean>;
  getFileStats(path: string): Promise<{ /* size, mtime, ... */ }>;
}

RealFileSystemAdapter

Production file system access with full ts-morph compatibility:

import { RealFileSystemAdapter } from '@angular-modernizer/core';

const fileSystem = new RealFileSystemAdapter();

const kernel = new Kernel({
  fileSystem,
  projectOptions: {
    fileSystem: fileSystem,
  },
});

Features:

  • Full FileSystemHost implementation for ts-morph compatibility
  • All sync methods implemented: readFileSync(), writeFileSync(), mkdirSync(), etc.
  • Proper error handling and encoding support

InMemoryFileSystemAdapter

Testing and development with in-memory file system:

import { InMemoryFileSystemAdapter } from '@angular-modernizer/core';

const fileSystem = new InMemoryFileSystemAdapter();

const kernel = new Kernel({
  fileSystem,
  projectOptions: {
    useInMemoryFileSystem: true,
    compilerOptions: {
      target: 99,   // ES2022
      module: 199,  // NodeNext
    },
  },
});

Features:

  • No file system side effects
  • Fast and deterministic
  • Full ts-morph compatibility

Plugin Management

The Kernel provides comprehensive plugin lifecycle management:

class Kernel {
  getPlugin(name: string): Plugin | undefined;
  getAllPlugins(): Plugin[];
  hasPlugin(name: string): boolean;
  async initialize(): Promise<void>;
}

Plugin interface:

interface Plugin {
  readonly name: string;
  readonly version: string;

  initialize(kernel: IKernel): Promise<void>;
  getAnalysisRules(): AnalysisRule[];
  getTransformRules(): TransformRule[];
  getValidationRules(): ValidationRule[];
}

Transformation Infrastructure

The core package provides a robust transformation pipeline for automated code modifications.

TransformationCoordinator

Orchestrates transformation operations across multiple plugins:

class TransformationCoordinator {
  constructor(plugins: Plugin[], api: unknown);

  async transformFile(
    sourceFile: SourceFile,
    project: Project,
    config?: TransformationConfig,
  ): Promise<TransformationResult>;
}

Key responsibilities:

  • Plugin discovery (finds all TransformRules across loaded plugins)
  • Context creation (builds TransformContext with dependency injection)
  • Rule execution (coordinates execution through TransformExecutionEngine)
  • Result aggregation (combines results from multiple rules)
  • Error isolation (failed rules don't stop the entire transformation)

TransformExecutionEngine

Safely executes individual transformation rules:

class TransformExecutionEngine {
  async executeRule(
    rule: TransformRule,
    context: TransformContext,
  ): Promise<TransformResult>;
}

Key features:

  • Pre-execution validation of rules and contexts
  • 30-second execution timeout prevents hanging
  • Structured error results instead of exceptions
  • Consistent result format across all rules

TransformContext and TransformResult

interface TransformContext {
  sourceFile: SourceFile;
  project: Project;
  api?: unknown;
  config?: Record<string, unknown>;
  filePath?: string;
  type?: string;
  options?: {
    dryRun?: boolean;
    autoSave?: boolean;
    format?: boolean;
  };
}

interface TransformResult {
  ruleId: string;
  modified: boolean;
  message: string;
  filePath?: string;
  changeCount?: number;
  metadata?: Record<string, unknown>;
}

Cache Manager

Intelligent caching system for AST and analysis results with automatic invalidation.

The CacheManager provides significant performance improvements by caching expensive operations. It automatically invalidates cache entries when files change, using SHA-256 content hashing for accuracy.

interface CacheConfig {
  enabled: boolean;
  cacheDir: string;
  maxSize: number;
  maxAge: number;
  version: string;
  compression: boolean;
}

class CacheManager {
  constructor(fileSystem: FileSystemAdapter, config?: Partial<CacheConfig>);

  async initialize(): Promise<void>;

  async getAst(filePath: string): Promise<CachedAst | null>;
  async setAst(filePath: string, ast: string): Promise<void>;

  async getAnalysisResult(filePath: string): Promise<CachedAnalysisResult | null>;
  async setAnalysisResult(
    filePath: string,
    results: unknown[],
    dependencies?: string[],
  ): Promise<void>;

  async invalidate(filePath: string, type?: 'ast' | 'analysis'): Promise<void>;
  async clear(): Promise<void>;
  getStats(): CacheStats;
}

Key features:

  • Content-based invalidation using SHA-256 hashes
  • LRU eviction when cache size limits are reached; eviction, clear() and size statistics touch only the manager's own entries, never other caches or files in the same directory
  • Entries at <cacheDir>/(ast|analysis)/<name>.<hash>.(ast|analysis).json, independent of the date, so maxAge (24 hours) applies across midnight
  • Dependency tracking (invalidates analysis results when dependencies change)
  • Optional gzip compression to reduce disk usage
  • Real-time hit rate and performance metrics

Performance characteristics:

| Operation | Performance | Notes | |-|-|-| | Cache Hit | 50,657 ops/sec | 1.58x faster than writes | | Cache Miss | 208,606 ops/sec | Ultra-fast null return | | File Change Detection | 52,052 ops/sec | Unchanged files | | Write with Compression | 60,157 ops/sec | 10KB with gzip | | Statistics | 2.8M ops/sec | Nearly instant |

Usage example:

const kernel = new Kernel({
  tsConfigPath: './tsconfig.json',
  fileSystem: new RealFileSystemAdapter(),
  cacheConfig: {
    enabled: true,
    cacheDir: '.angular-modernizer-cache',
    maxSize: 100 * 1024 * 1024, // 100MB
    maxAge: 24 * 60 * 60 * 1000, // 24 hours
    compression: true,
    version: '1.0.0',
  },
});

await kernel.initialize();

const cache = kernel.getCacheManager();
if (cache) {
  const stats = cache.getStats();
  console.log(`Hit rate: ${stats.hitRate.toFixed(1)}%`);
  console.log(`Total entries: ${stats.totalEntries}`);
}

For detailed caching documentation, see CACHE.md.

Orchestration System

Advanced parallel processing, incremental analysis, and resource management for large-scale Angular projects.

interface KernelConfig {
  resourceLimits?: {
    maxMemory?: number;     // bytes, default: 80% of available
    maxWorkers?: number;    // default: CPU cores - 1
    maxQueueSize?: number;  // default: 1000
    autoThrottle?: boolean; // default: true
  };
  enableParallelExecution?: boolean; // default: true
}

Key components:

ParallelExecutor - File-level parallelism with configurable worker pools. Supports both Promise-based execution and worker threads for true multi-threaded execution.

IncrementalAnalyzer - Git-based change detection for efficient re-analysis. Uses content hashing for file modification tracking and dependency graph analysis for transitive invalidation.

ProgressReporter - Real-time progress tracking with ETA calculation. Event-driven architecture for flexible integration.

ResourceManager - Memory monitoring with configurable heap limits and CPU usage tracking. Automatic resource management for large codebases.

WorkerPool - Node.js worker threads for true parallelism. Isolated V8 instances preventing memory interference. Health monitoring with automatic recycling.

Performance characteristics:

| Feature | Performance | Use Case | |-|-|-| | Parallel Execution | 1.5-4x speedup | Large codebases (100+ files) | | Incremental Analysis | >90% cache hit rate | Repeated analysis runs | | Worker Threads | 5-10x potential speedup | CPU-intensive tasks | | Progress Reporting | Real-time with ETA | Long-running operations | | Resource Management | Automatic throttling | Memory-constrained environments |

Usage examples:

// Parallel analysis over all project files and the rules of all plugins
const kernel = new Kernel({
  tsConfigPath: './tsconfig.json',
  plugins: [new SolidPlugin()],
  resourceLimits: { maxWorkers: 4 },
});
await kernel.initialize();

const results = await kernel.analyzeParallel({
  plugins: ['@angular-modernizer/plugin-solid'],
  onProgress: (progress) => {
    console.log(`${progress.percentage}% complete, ETA: ${progress.eta}ms`);
  },
});

// Incremental analysis against a git base
const incrementalResult = await kernel.analyzeIncremental({
  baseBranch: 'main',
  includeDependents: true,
});

// Worker thread execution
const workerResults = await kernel.analyzeParallel({
  useWorkerThreads: true,
  tsConfigPath: './tsconfig.json',
  workerScriptPath: getWorkerScriptPath(), // from @angular-modernizer/worker
  maxWorkers: 4,
});

For detailed orchestration documentation, see the orchestration source files in src/orchestration/.

Feedback Collection

Privacy-first AI transformation feedback system for continuous learning and improvement.

The feedback collection system captures transformation outcomes, AI decision-making, and validation results in a privacy-preserving format that enables pattern learning without exposing sensitive code or business logic.

Key features:

  • No code snippets stored, hashed file paths, bucketed metrics
  • Dual storage (project .claude-feedback/ and platform root)
  • Automated validation with 6 checks ensuring feedback quality
  • Outlier detection (4 detection types) for anomaly handling
  • Pattern detection with confidence scoring

FeedbackCollector

import { FeedbackCollector } from '@angular-modernizer/core';

const collector = new FeedbackCollector({
  projectRoot: '/path/to/project',
  platformRoot: '/path/to/tsanalyzer',
  storageLocation: 'both', // 'project', 'platform', or 'both' (default)
  salt: 'unique-installation-salt',
});

const project = new Project({ tsConfigFilePath: 'tsconfig.json' });
const sessionId = await collector.startSession({ projectRoot: '/path/to/project', project });

const feedback: TransformationFeedback = {
  transformationId: 'transform-1',
  timestamp: new Date().toISOString(),
  rule: {
    ruleId: 'standalone-migration-v1',
    ruleName: 'Migrate to Standalone Components',
    ruleType: 'transform',
    category: 'standalone-migration',
  },
  target: {
    filePathHash: 'src/app/user.component.ts', // Will be hashed
    fileType: 'component',
    linesOfCode: 147,
    complexity: 8.5,
  },
  decision: {
    approach: 'Convert to standalone component',
    alternatives: ['Keep NgModule', 'Partial migration'],
    reasoning: 'File is isolated, no complex dependencies',
    confidence: 0.95,
    contextUsed: ['file-structure', 'dependencies'],
    timeToDecision: 250,
  },
  execution: {
    succeeded: true,
    duration: 1200,
  },
  validation: {
    build: { success: true, duration: 8500, errors: [], warnings: [] },
    tests: { success: true, duration: 4200, coverage: 92.5 },
  },
  outcome: {
    status: 'success',
    quality: 'improved',
    metrics: {
      codeComplexity: { before: 10, after: 8, delta: -2 },
    },
  },
  metadata: {
    source: 'automatic',
    collectorVersion: '1.0.0',
    reliability: 1.0,
    completenessScore: 95,
  },
};

try {
  await collector.recordTransformation(sessionId, feedback);
} catch (error) {
  console.error('Validation failed:', error.message);
}

const outcome = await collector.endSession(sessionId);
console.log(`Success: ${outcome.successful}/${outcome.totalTransformations}`);

API reference:

class FeedbackCollector {
  constructor(
    config: FeedbackCollectorConfig,
    privacyFilter?: PrivacyFilter,
    feedbackStorage?: FeedbackStorage,
    feedbackValidator?: FeedbackValidator,
  );

  async startSession(context: TransformContext): Promise<string>;
  async recordTransformation(sessionId: string, feedback: TransformationFeedback): Promise<void>;
  async endSession(sessionId: string): Promise<SessionOutcome>;
  extractLearnings(feedback: TransformationFeedback): Learning[];
}

PrivacyFilter

Anonymizes sensitive data before storage:

import { PrivacyFilter } from '@angular-modernizer/core';

const filter = new PrivacyFilter({
  salt: 'unique-installation-salt',
  strictMode: true,
});

const anonymized = filter.anonymize(feedback);

// File path hashing (preserves structure)
const hashedPath = filter.anonymizeFilePath('src/app/user/user.component.ts', 'salt');
// Result: "abc123/def456/ghi789/jkl012.component.ts"

// Bucket numeric values (hide exact numbers)
const complexityBucket = filter.bucketValue(8.5, [0, 5, 10, 20, 50]);
// Result: "small" (labels: tiny, small, medium, large, huge)

// Audit privacy before storage (returns a PrivacyAudit, does not throw)
const audit = filter.auditPrivacy(anonymized);
if (!audit.passed) {
  console.error('Privacy audit failed:', {
    hasCodeSnippets: audit.hasCodeSnippets,
    hasRealFilePaths: audit.hasRealFilePaths,
    hasProjectNames: audit.hasProjectNames,
    hasBusinessLogic: audit.hasBusinessLogic,
  });
}

FeedbackValidator

Validates feedback quality with 6 checks:

import { FeedbackValidator } from '@angular-modernizer/core';

const validator = new FeedbackValidator({
  minCompletenessScore: 70,
  strictMode: false,
  maxDuration: 600000,
});

const result = validator.validate(feedback);

if (!result.valid) {
  console.error(`Validation failed (score: ${result.score}/100):`);
  result.issues.forEach((issue) => {
    console.error(`  [${issue.severity}] ${issue.field}: ${issue.message}`);
  });
}

Validation checks:

  1. Schema completeness (required fields present)
  2. Consistency checks (outcome matches execution)
  3. Confidence sanity (high confidence failures flagged)
  4. Quality metrics validity (reasonable deltas)
  5. Duration sanity (positive, reasonable durations)
  6. Learning quality (patterns, evidence present)

OutlierDetector

Detects anomalous feedback for quarantine:

import { OutlierDetector } from '@angular-modernizer/core';

const detector = new OutlierDetector();
const report = detector.detectOutliers(feedbackArray);

console.log(`Outlier rate: ${report.outlierRate * 100}%`);

report.outliers.forEach((outlier) => {
  console.log(`${outlier.feedbackId}: ${outlier.reasons.join(', ')}`);
  console.log(`Action: ${outlier.action}`); // 'quarantine' | 'flag' | 'purge'
});

Four outlier detection types:

  1. Duration outliers: >10x median duration (unusually slow)
  2. Overconfident failures: AI confidence >0.95 but transformation failed
  3. Quality degradation: code complexity increased >50%
  4. Impossibly fast: transformations <10ms (likely corrupted)

Target: <3% outlier rate

FeedbackStorage

Dual-location JSON Lines storage:

import { FeedbackStorage } from '@angular-modernizer/core';

const storage = new FeedbackStorage({
  projectRoot: '/path/to/project',
  platformRoot: '/path/to/tsanalyzer',
  storageLocation: 'both',
});

await storage.initSession(sessionId, session);
await storage.appendTransformation(sessionId, feedback);
const loadedSession = await storage.loadSession(sessionId);

Storage paths:

  • Project: {projectRoot}/.claude-feedback/sessions/{sessionId}.jsonl
  • Platform: {platformRoot}/.claude-feedback/sessions/{sessionId}.jsonl

The MCP feedback tools (collect-feedback, review-feedback, suggest-improvements, analyze-parser-performance) always use the project and add a platform root only when ANGULAR_MODERNIZER_PLATFORM_ROOT is set.

Format: JSON Lines (one JSON object per line, append-only)

Usage Patterns

Basic Kernel Setup

import { Kernel, RealFileSystemAdapter } from '@angular-modernizer/core';
import { StandalonePlugin } from '@angular-modernizer/plugin-standalone';

const kernel = new Kernel({
  tsConfigPath: './tsconfig.json',
  fileSystem: new RealFileSystemAdapter(),
  plugins: [new StandalonePlugin()],
});

await kernel.initialize();

const project = kernel.getProject();
const plugin = kernel.getPlugin('@angular-modernizer/plugin-standalone');

Testing with In-Memory File System

import { Kernel, InMemoryFileSystemAdapter } from '@angular-modernizer/core';

describe('MyPlugin', () => {
  let kernel: Kernel;

  beforeEach(async () => {
    kernel = new Kernel({
      fileSystem: new InMemoryFileSystemAdapter(),
      projectOptions: {
        useInMemoryFileSystem: true,
        compilerOptions: {
          target: 99,   // ES2022
          module: 199,  // NodeNext
        },
      },
      plugins: [new MyPlugin()],
    });

    await kernel.initialize();
  });

  it('should work with in-memory files', () => {
    const project = kernel.getProject();

    const sourceFile = project.createSourceFile(
      'test.component.ts',
      '@Component({}) export class TestComponent {}',
    );

    expect(sourceFile).toBeDefined();
  });
});

Plugin Development

import { Plugin, Kernel } from '@angular-modernizer/core';

class MyCustomPlugin implements Plugin {
  readonly name = '@my-org/plugin-custom';
  readonly version = '1.0.0';
  readonly description = 'Custom analysis and transformation rules';

  async initialize(kernel: Kernel): Promise<void> {
    console.log('Custom plugin initialized');
  }

  getAnalysisRules(): AnalysisRule[] {
    return [new MyAnalysisRule()];
  }

  getTransformRules(): TransformRule[] {
    return [new MyTransformRule()];
  }

  getValidationRules(): ValidationRule[] {
    return [];
  }
}

const kernel = new Kernel({
  plugins: [new MyCustomPlugin()],
});

Intelligent Mode Selection

The orchestration system automatically chooses between Promise-based and worker thread parallelism based on project complexity:

import { ParallelExecutor } from '@angular-modernizer/core';

const executor = new ParallelExecutor({ maxWorkers: 4 });

const results = await executor.executeParallel(sourceFiles, rules, {
  autoSelectMode: true,
});

// Mode selection analyzes:
// - File count (30% weight)
// - Total LOC/size (35% weight)
// - Large file outliers (20% weight)
// - Current memory pressure (15% weight)
//
// Decision thresholds:
// - Score < 35:  Promise mode (safe, fast startup)
// - Score 35-50: Promise mode with monitoring and fallback to workers
// - Score 50-75: Worker threads preferred
// - Score >= 75: Worker threads required

Promise mode monitoring and fallback:

const results = await executor.executeParallel(sourceFiles, rules, {
  autoSelectMode: true,
  enableMonitoring: true,
  fallbackToWorkers: true,
  workerScriptPath: getWorkerScriptPath(),
  tsConfigPath: './tsconfig.json',
});

// If Promise mode hits 85% heap limit:
// -> Aborts execution
// -> Automatically switches to worker threads
// -> Completes analysis safely

Force override (always respected):

const results = await executor.executeParallel(sourceFiles, rules, {
  useWorkerThreads: false, // Force Promise mode
});

The thresholds option exists in ParallelOptions but the mode selector currently always uses its default thresholds.

Advanced Orchestration

import { Kernel, RealFileSystemAdapter } from '@angular-modernizer/core';
import { SolidPlugin } from '@angular-modernizer/plugin-solid';
import { getWorkerScriptPath } from '@angular-modernizer/worker';

const kernel = new Kernel({
  tsConfigPath: './tsconfig.json',
  fileSystem: new RealFileSystemAdapter(),
  plugins: [new SolidPlugin()],
  resourceLimits: { maxWorkers: 4, maxMemory: 512 * 1024 * 1024 },
});

await kernel.initialize();

// Promise mode with progress
const results = await kernel.analyzeParallel({
  useWorkerThreads: false,
  onProgress: (progress) => {
    console.log(`Progress: ${progress.percentage}% (${progress.message})`);
  },
});

// Worker threads
const workerResults = await kernel.analyzeParallel({
  useWorkerThreads: true,
  tsConfigPath: './tsconfig.json',
  workerScriptPath: getWorkerScriptPath(),
});

// Incremental
const incrementalResult = await kernel.analyzeIncremental({
  baseBranch: 'main',
  includeDependents: true,
});

Code Transformations

import { Kernel, RealFileSystemAdapter } from '@angular-modernizer/core';
import { StandalonePlugin } from '@angular-modernizer/plugin-standalone';

const kernel = new Kernel({
  tsConfigPath: './tsconfig.json',
  fileSystem: new RealFileSystemAdapter(),
  plugins: [new StandalonePlugin()],
});

await kernel.initialize();

const sourceFile = kernel.getProject().getSourceFile('component.ts');
const result = await kernel.transformFile(sourceFile, {
  dryRun: false,
  autoSave: true,
  pluginConfig: {
    '@angular-modernizer/plugin-standalone': {
      migrationType: 'to-standalone',
    },
  },
});

console.log(`Success: ${result.success}`);
console.log(`Rules executed: ${result.ruleResults.length}`);
console.log(`Errors: ${result.errors.length}`);

Design Principles

Domain Agnostic

The core package contains no Angular-specific logic:

// Correct: generic infrastructure
class Kernel {
  // Manages any TypeScript project
  // Works with any plugins
  // Uses any file system
}

Optional Configuration

All configuration is optional with sensible defaults:

new Kernel();
new Kernel({});
new Kernel({ tsConfigPath: './tsconfig.json' });
new Kernel({ plugins: [plugin] });

Async by Default

All I/O operations are async for scalability:

await fileSystem.readFile('file.ts');
await fileSystem.writeFile('file.ts', content);
await kernel.initialize();
await plugin.initialize(kernel);

Testability First

In-memory file system enables fast, isolated testing:

const kernel = new Kernel({
  fileSystem: new InMemoryFileSystemAdapter(),
});

Package Structure

packages/core/
├── src/
│   ├── kernel.ts
│   ├── kernel-factory.ts        # createKernel, findTsConfigPath
│   ├── file-system.ts           # FileSystemAdapter, Real/InMemory adapters
│   ├── index.ts
│   ├── analysis/                # dependency graph, path aliases, false positives
│   ├── cache/                   # CacheManager, MultiCacheFallbackManager
│   ├── config/                  # ConfigLoader, config types
│   ├── feedback/                # FeedbackCollector, PrivacyFilter, storage
│   ├── fluent/                  # FluentKernel pipeline
│   ├── orchestration/
│   │   ├── parallel-executor.ts
│   │   ├── mode-selector.ts
│   │   ├── incremental-analyzer.ts
│   │   ├── progress-reporter.ts
│   │   ├── promise-monitor.ts
│   │   ├── resource-manager.ts
│   │   ├── worker-pool.ts
│   │   ├── types.ts
│   │   └── index.ts
│   ├── parsers/                 # parser strategies, external decorators
│   ├── pattern-analysis/
│   ├── rollback/                # BackupManager, GitIntegration, RollbackManager
│   ├── streaming/               # StreamingKernelWrapper, diffs
│   ├── testing/                 # RealFsTestHelper
│   ├── transformation/
│   │   ├── transformation-coordinator.ts
│   │   ├── transform-execution-engine.ts
│   │   ├── transform-rule-executor.ts
│   │   ├── transformation-result-validator.ts
│   │   └── index.ts
│   ├── utils/
│   └── validation/              # build, TypeScript and pre/post-transform validation
├── __tests__/
├── schemas/                     # angular-modernizer.schema.json
├── CACHE.md
├── package.json
├── tsconfig.json
├── jest.config.js
└── README.md

Dependencies

  • ts-morph: TypeScript AST manipulation and project management
  • @angular-modernizer/api, @angular-modernizer/plugin-system: public API and plugin contracts
  • ajv: JSON Schema validation of .angular-modernizer.json
  • diff: unified diffs for streaming results
  • rxjs: optional peer dependency for the RxJS integration of the fluent API

Testing

pnpm --filter @angular-modernizer/core test
pnpm --filter @angular-modernizer/core test --coverage
pnpm --filter @angular-modernizer/core bench

Test categories:

  • Kernel: initialization, configuration, plugin management
  • File System: both real and in-memory implementations
  • Cache: invalidation, LRU eviction, file change detection
  • Transformation: coordinator, execution engine, context management
  • Orchestration: parallel execution, incremental analysis, progress reporting, resource management, worker threads
  • Performance benchmarks: cache performance, orchestration scaling, memory usage
  • Integration: end-to-end kernel usage scenarios with real plugins
  • Error handling: edge cases and failure scenarios

Worker thread tests run only with ENABLE_WORKER_TESTS=true.

Testing patterns:

describe('Kernel', () => {
  describe('initialization', () => {
    it('should initialize with minimal config', async () => {
      const kernel = new Kernel();
      await expect(kernel.initialize()).resolves.not.toThrow();
      expect(kernel.isInitialized()).toBe(true);
    });

    it('should initialize with full config', async () => {
      const kernel = new Kernel({
        tsConfigPath: './tsconfig.json',
        fileSystem: new RealFileSystemAdapter(),
        plugins: [new TestPlugin()],
      });

      await kernel.initialize();
      expect(kernel.getAllPlugins()).toHaveLength(1);
    });
  });
});

Performance Considerations

Memory Management

  • ts-morph projects can be memory-intensive for large codebases
  • Use InMemoryFileSystemAdapter for testing to reduce memory footprint
  • Consider incremental analysis for very large projects

File System Operations

  • RealFileSystemAdapter uses async operations for scalability
  • Batch file operations when possible

Plugin Initialization

  • Plugins are initialized sequentially to avoid race conditions
  • Plugin initialization is async to support I/O operations
  • A failing plugin initialize() aborts kernel.initialize() with Failed to initialize plugin "<name>"; plugin names must be unique

Troubleshooting

Common Issues

Kernel initialization fails:

const kernel = new Kernel({
  tsConfigPath: './tsconfig.json', // Ensure this file exists
});

Plugin not found:

const kernel = new Kernel({
  plugins: [new MyPlugin()],
});

await kernel.initialize();

console.log(kernel.getAllPlugins());
console.log(kernel.hasPlugin('my-plugin-name'));

File system errors:

const fileSystem = new RealFileSystemAdapter();
try {
  await fileSystem.exists('./src');
} catch (error) {
  console.error('File system error:', error);
}

ESLint / TypeScript IDE Errors

If VSCode shows @typescript-eslint/no-unsafe-assignment errors but the build passes:

  1. Verify the code compiles: pnpm --filter @angular-modernizer/core build
  2. Verify ESLint passes: npx eslint packages/core/src/orchestration/promise-monitor.ts
  3. If both pass, reload the TypeScript server in VSCode (Cmd+Shift+P > "TypeScript: Restart TS Server")

This is a known issue with TypeScript language server type inference in certain contexts involving complex type narrowing. The satisfies operator can help:

private collectMetrics(): RuntimeMetrics {
  return {
    // ... properties
  } satisfies RuntimeMetrics;
}

Memory Issues with Promise-Based Parallelism

If you see FATAL ERROR: Reached heap limit Allocation failed with 500+ files:

const results = await kernel.analyzeParallel({
  useWorkerThreads: true,
  tsConfigPath: './tsconfig.json',
  workerScriptPath: getWorkerScriptPath(),
  maxWorkers: 4,
  minFilesForWorkers: 200,
});

Worker threads use isolated heaps and avoid the V8 heap fragmentation that causes crashes in Promise-based parallelism.

Worker Thread Build Errors

If worker threads fail with "Cannot find module" errors, build all packages:

pnpm run build
# Or build worker specifically
pnpm --filter @angular-modernizer/worker build

Promise-based parallelism does not require building and works immediately.

Streaming and Structured Diffs

The streaming path (deprecated on the MCP side, where tools use native progress and cancellation) is exported from the package root:

import {
  StreamingKernelWrapper,
  generateUnifiedDiff,
  generateDiffSummary,
  detectSyntaxErrors,
  type FileDiff,
  type DiffHunk,
  type LineChange,
  type SemanticAnnotation,
  type AngularContext,
  type SyntaxType,
  type StreamingOptions,
  type StreamingProgressEvent,
  type StreamingTransformResult,
} from '@angular-modernizer/core';

See Also

License

MIT License - See LICENSE file for details