Architecture Module Structure - hiraishikentaro/rails-factorybot-jump GitHub Wiki

Architecture: Module Structure

Code Organization Overview

The Rails FactoryBot Jump extension follows a modular architecture with clear separation of concerns and well-defined module boundaries.

src/
├── extension.ts              # Extension entry point and lifecycle
├── providers/
│   └── factoryLinkProvider.ts # Document link provider implementation
├── models/                   # Data models
│   ├── factory.ts           # Factory definition model
│   ├── location.ts          # Location tracking model
│   └── trait.ts             # Trait definition model
├── services/                 # Business services
│   ├── cacheManager.ts      # Multi-level cache management
│   ├── configurationManager.ts # Configuration handling
│   ├── errorNotificationService.ts # Error handling and notifications
│   ├── factoryParser.ts     # Factory file parsing logic
│   └── fileSearcher.ts      # File discovery and watching
├── utils/                    # Utility functions
│   ├── pathUtils.ts         # Path manipulation utilities
│   └── regexPatterns.ts     # Regex pattern definitions
├── constants/
│   └── defaults.ts          # Default configuration values
└── test/
    ├── runTest.ts           # Integration test runner
    ├── runUnitTests.ts      # Unit test runner
    ├── suite/
    │   ├── index.ts         # Integration test setup
    │   └── extension.test.ts # Integration test cases
    └── unit/
        ├── index.ts         # Unit test setup
        ├── models/          # Model unit tests
        ├── services/        # Service unit tests
        └── utils/           # Utility unit tests

Core Modules

1. Extension Entry Point (extension.ts)

Purpose: Main extension lifecycle management and VSCode integration.

Key Responsibilities:

  • Extension activation and deactivation
  • Provider and command registration
  • File system watcher setup
  • Resource management

Public Interface:

export function activate(context: vscode.ExtensionContext): void;
export function deactivate(): void;

Dependencies:

  • vscode - VSCode Extension API
  • ./providers/factoryLinkProvider - Core business logic

Internal Structure:

function activate(context: vscode.ExtensionContext) {
  // Provider registration
  const provider = new FactoryLinkProvider();
  context.subscriptions.push(
    vscode.languages.registerDocumentLinkProvider(
      { scheme: "file", language: "ruby" },
      provider
    )
  );

  // Command registration
  context.subscriptions.push(
    vscode.commands.registerCommand(
      "rails-factorybot-jump.gotoLine",
      gotoLineHandler
    )
  );

  // File system watcher
  const watcher = vscode.workspace.createFileSystemWatcher(
    "**/factories/**/*.rb"
  );
  // ... watcher event handlers
}

Source: src/extension.ts#L4-L42

2. Factory Link Provider (providers/factoryLinkProvider.ts)

Purpose: Core business logic for factory detection and link generation.

Key Responsibilities:

  • Factory and trait detection
  • Cache management
  • Document link generation
  • Configuration handling

Public Interface:

export class FactoryLinkProvider implements vscode.DocumentLinkProvider {
  provideDocumentLinks(document: vscode.TextDocument): vscode.DocumentLink[];
  initializeFactoryFiles(): Promise<void>;
}

Internal Architecture:

class FactoryLinkProvider {
  // Cache structures
  private factoryCache: Map<string, { uri: vscode.Uri; lineNumber: number }>;
  private traitCache: Map<
    string,
    { uri: vscode.Uri; lineNumber: number; factory: string }
  >;
  private factoryFiles: vscode.Uri[];

  // Core methods
  private async initializeFactoryFiles();
  private async cacheFactoryDefinitions();
  private async cacheTraitDefinitions();
  private createDocumentLink();
}

Dependencies:

  • vscode - VSCode APIs for file operations and link generation
  • path - Path manipulation utilities

Source: src/providers/factoryLinkProvider.ts

Module Dependencies

Dependency Graph

graph TD
    A[extension.ts] --> B[providers/factoryLinkProvider.ts]
    A --> C[vscode API]
    B --> D[services/cacheManager.ts]
    B --> E[services/factoryParser.ts]
    B --> F[services/fileSearcher.ts]
    B --> G[services/configurationManager.ts]
    B --> H[services/errorNotificationService.ts]
    D --> I[models/factory.ts]
    D --> J[models/trait.ts]
    D --> K[models/location.ts]
    E --> I
    E --> J
    E --> L[utils/regexPatterns.ts]
    F --> M[utils/pathUtils.ts]
    G --> N[constants/defaults.ts]
    O[test/runTest.ts] --> P[test/suite/extension.test.ts]
    Q[test/runUnitTests.ts] --> R[test/unit/**/*.test.ts]
    P --> A
    P --> S[vscode/test-electron]
    P --> T[mocha]
    R --> U[sinon]
Loading

External Dependencies

VSCode Extension API:

  • vscode.languages.registerDocumentLinkProvider
  • vscode.commands.registerCommand
  • vscode.workspace.createFileSystemWatcher
  • vscode.workspace.findFiles
  • vscode.workspace.openTextDocument

Node.js Core Modules:

  • path - Cross-platform path operations

Development Dependencies:

  • @vscode/test-electron - Extension testing framework
  • mocha - Test runner
  • sinon - Mocking framework

Source: package.json#L77-L90

Data Flow Between Modules

1. Initialization Flow

sequenceDiagram
    participant Main as extension.ts
    participant Provider as factoryLinkProvider.ts
    participant VSCode as VSCode APIs
    participant FS as File System

    Main->>Provider: new FactoryLinkProvider()
    Main->>VSCode: registerDocumentLinkProvider(provider)
    Main->>VSCode: createFileSystemWatcher()
    Note over Provider: Lazy initialization on first use
    VSCode->>Provider: provideDocumentLinks()
    Provider->>VSCode: workspace.findFiles()
    VSCode->>FS: Find factory files
    FS-->>VSCode: File URIs
    VSCode-->>Provider: Factory file list
    Provider->>Provider: Build caches
Loading

2. Runtime Data Flow

graph LR
    A[User Action] --> B[VSCode Core]
    B --> C[extension.ts]
    C --> D[factoryLinkProvider.ts]
    D --> E[Factory Cache]
    D --> F[Trait Cache]
    E --> G[Document Links]
    F --> G
    G --> B
    B --> H[UI Display]
Loading

Modular Design Patterns

1. Provider Pattern

Implementation:

  • FactoryLinkProvider implements vscode.DocumentLinkProvider
  • Clean separation between VSCode integration and business logic
  • Single responsibility for link generation

Benefits:

  • Testable business logic
  • VSCode API abstraction
  • Swappable implementations

2. Facade Pattern

Implementation:

  • extension.ts acts as facade to VSCode APIs
  • Simplifies interaction with complex VSCode subsystems
  • Provides unified interface for extension functionality

Benefits:

  • Simplified client interface
  • Centralized configuration
  • Easier testing and mocking

3. Repository Pattern (Cache Layer)

Implementation:

  • Cache maps act as repositories for factory definitions
  • Abstract data access from business logic
  • Consistent data access interface

Benefits:

  • Centralized data management
  • Performance optimization
  • Testable data layer

Module Configuration

Configuration Flow

graph TB
    A[VSCode Settings] --> B[extension.ts]
    B --> C[Configuration Change Event]
    C --> D[factoryLinkProvider.ts]
    D --> E[Cache Invalidation]
    E --> F[Factory File Re-scan]
    F --> G[Cache Rebuild]
Loading

Configuration Schema

Extension Manifest (package.json):

{
  "contributes": {
    "configuration": {
      "properties": {
        "rails-factorybot-jump.factoryPaths": {
          "type": "array",
          "default": ["spec/factories/**/*.rb"]
        }
      }
    }
  }
}

Runtime Access:

const config = vscode.workspace.getConfiguration("rails-factorybot-jump");
const factoryPaths = config.get<string[]>("factoryPaths", [
  "spec/factories/**/*.rb",
]);

Source: package.json#L52-L66

Testing Module Structure

Test Organization

test/
├── runTest.ts           # Test runner entry point
└── suite/
    ├── index.ts         # Mocha configuration
    └── extension.test.ts # Test cases

Test Module Dependencies

Test Runner (runTest.ts):

  • Configures VSCode test environment
  • Sets up extension development host
  • Manages test execution lifecycle

Test Suite (extension.test.ts):

  • Unit tests for core functionality
  • Integration tests with VSCode APIs
  • Mock factory files and configurations

Test Infrastructure:

// Test module imports
import * as vscode from "vscode";
import * as assert from "assert";
import * as sinon from "sinon";
import { FactoryLinkProvider } from "../../providers/factoryLinkProvider";

Source: src/test/suite/extension.test.ts

Module Interfaces

Public APIs

Extension Interface:

// Main extension exports
export function activate(context: vscode.ExtensionContext): void;
export function deactivate(): void;

Provider Interface:

// VSCode DocumentLinkProvider contract
interface DocumentLinkProvider {
  provideDocumentLinks(document: TextDocument): DocumentLink[];
}

Internal Interfaces

Cache Interfaces:

interface FactoryDefinition {
  uri: vscode.Uri;
  lineNumber: number;
}

interface TraitDefinition extends FactoryDefinition {
  factory: string;
}

Configuration Interface:

interface ExtensionConfig {
  factoryPaths: string[];
}

Error Handling Across Modules

Error Propagation Strategy

graph TB
    A[File System Error] --> B[factoryLinkProvider.ts]
    B --> C[Error Logging]
    B --> D[Graceful Degradation]
    D --> E[Partial Functionality]

    F[VSCode API Error] --> G[extension.ts]
    G --> H[Error Logging]
    G --> I[Resource Cleanup]
Loading

Error Boundaries

Module-Level Error Handling:

  • Each module handles its own errors
  • Errors don't propagate to break other modules
  • Graceful degradation strategies

Cross-Module Error Communication:

  • Logging for debugging
  • Status indicators for user feedback
  • Fallback behaviors

Module Extension Points

Implemented Module Structure

Current Architecture:

The extension has evolved from a simple two-file structure to a comprehensive service-oriented architecture:

  • Models Layer: Data models with proper encapsulation and type safety
  • Services Layer: Business logic separation with dedicated services for caching, parsing, configuration, and error handling
  • Utils Layer: Shared utilities for common operations
  • Constants Layer: Centralized configuration defaults

Future Expansion Possibilities:

src/
└── language-support/ # Multi-language support modules (planned)

Extension Strategies

Plugin Architecture:

  • Provider interface for different language support
  • Configurable parsing strategies
  • Pluggable cache implementations

Configuration Extension:

  • Module-specific configuration sections
  • Dynamic module loading
  • Feature flags for experimental modules

Performance Considerations

Module Loading

Lazy Loading Strategy:

  • Core modules loaded on activation
  • Feature modules loaded on first use
  • Test modules only in test environment

Memory Management:

  • Module-specific resource cleanup
  • Shared resource pooling
  • Cache size limitations

Inter-Module Communication

Efficient Data Passing:

  • Minimal data copying between modules
  • Shared data structures where appropriate
  • Event-driven updates to minimize polling

This modular structure provides a solid foundation for maintainability, testability, and future extensibility while keeping the codebase organized and easy to understand.

⚠️ **GitHub.com Fallback** ⚠️