Development Guides Local Development - hiraishikentaro/rails-factorybot-jump GitHub Wiki

Development Guides: Local Development

Local Development Setup

Prerequisites Verification

Before starting local development, ensure your environment meets the requirements:

# Check Node.js version (18.x required)
node --version

# Check npm version
npm --version

# Check VSCode version (1.85.0+ required)
code --version

# Check TypeScript installation
npx tsc --version

Project Setup

1. Clone and Install:

git clone https://github.com/hiraishikentaro/rails-factorybot-jump.git
cd rails-factorybot-jump
npm install

2. Verify Installation:

# Compile TypeScript
npm run compile

# Run linting
npm run lint

# Run tests
npm test

Source: package.json#L68-L76

Development Workflow

1. Development Environment

VSCode Development Setup:

# Open project in VSCode
code .

# Install recommended extensions
# - TypeScript and JavaScript Language Features (built-in)
# - ESLint
# - Mocha Test Explorer

Development Mode:

# Watch mode for automatic compilation
npm run watch

# This will:
# - Watch for TypeScript file changes
# - Automatically recompile to out/ directory
# - Preserve source maps for debugging

2. Extension Development Host

Launch Development Environment:

  1. Open the project in VSCode
  2. Press F5 or go to Run → Start Debugging
  3. This launches a new "Extension Development Host" window
  4. The extension is automatically loaded in this window
  5. Test your changes in the development host

Development Host Features:

  • Full VSCode environment with your extension loaded
  • Real-time updates when you recompile
  • Access to Developer Tools for debugging
  • Isolated from your main VSCode installation

3. Hot Reload Development

Automatic Recompilation:

# Terminal 1: Watch mode for TypeScript compilation
npm run watch

# Terminal 2: Run tests in watch mode (if needed)
npm run test:watch

Reload Extension:

  • In Extension Development Host, press Ctrl+R (Windows/Linux) or Cmd+R (Mac)
  • This reloads the extension with your latest changes
  • No need to restart the entire development host

File Structure and Development

Source Code Organization

src/
├── extension.ts              # Main entry point - start here
├── providers/
│   └── factoryLinkProvider.ts # Core business logic
├── test/
│   ├── runTest.ts           # Test configuration
│   └── suite/
│       └── extension.test.ts # Test cases
└── utils/                   # Future utility modules

Key Development Files

Main Extension Entry (src/extension.ts):

  • Extension activation and deactivation
  • Provider registration with VSCode
  • Command registration
  • File system watcher setup

Core Provider (src/providers/factoryLinkProvider.ts):

  • Factory detection logic
  • Cache management
  • Document link generation
  • Configuration handling

Source: src/extension.ts, src/providers/factoryLinkProvider.ts

Testing During Development

1. Unit Test Development

Running Tests:

# Run all tests
npm test

# Run specific test suite
npm test -- --grep "Factory Detection"

# Run tests with detailed output
npm test -- --reporter spec

Writing New Tests:

// Add tests to src/test/suite/extension.test.ts
suite("New Feature", () => {
  test("should handle new functionality", () => {
    // Test implementation
    assert.strictEqual(actual, expected);
  });
});

2. Manual Testing

Test Factory Detection:

  1. Create a test Ruby file:
# test.rb
RSpec.describe User do
  it "creates user" do
    user = create(:user, :admin)
    expect(user).to be_valid
  end
end
  1. Create a test factory file:
# spec/factories/users.rb
FactoryBot.define do
  factory :user do
    name { "Test User" }

    trait :admin do
      admin { true }
    end
  end
end
  1. Open test.rb in Extension Development Host
  2. Hover over :user and :admin to verify links appear
  3. Click links to verify navigation works

3. Integration Testing

Test Configuration Changes:

  1. Open settings in Extension Development Host
  2. Modify rails-factorybot-jump.factoryPaths
  3. Verify extension updates factory search paths
  4. Test with custom factory directory structure

Test File Watching:

  1. Modify a factory file while Extension Development Host is open
  2. Verify cache updates automatically
  3. Check that links update in test files

Debugging Techniques

1. VSCode Debugging

Debugger Setup:

// .vscode/launch.json (already configured)
{
  "type": "extensionHost",
  "request": "launch",
  "name": "Extension",
  "runtimeExecutable": "${execPath}",
  "args": ["--extensionDevelopmentPath=${workspaceRoot}"]
}

Debug Workflow:

  1. Set breakpoints in TypeScript source files
  2. Press F5 to start debugging
  3. Use the Extension Development Host to trigger breakpoints
  4. Inspect variables, call stack, and execution flow

2. Console Logging

Strategic Logging:

// Debug factory detection
console.log("Factory detection regex result:", matches);

// Debug cache operations
console.log("Factory cache size:", factoryCache.size);
console.log("Factory cache contents:", Array.from(factoryCache.entries()));

// Debug file operations
console.log(
  "Found factory files:",
  factoryFiles.map((f) => f.path)
);

VSCode Developer Tools:

  1. In Extension Development Host: Help → Toggle Developer Tools
  2. Go to Console tab to see your debug output
  3. Use Network tab to monitor file operations
  4. Use Sources tab for debugging with source maps

3. Error Tracking

Error Handling Development:

try {
  await provider.initializeFactoryFiles();
} catch (error) {
  console.error("Factory initialization failed:", error);
  // Log stack trace
  console.error(error.stack);
}

Common Debug Scenarios:

  • Factory files not found → Check path configuration
  • Regex not matching → Test regex patterns in isolation
  • Cache not updating → Verify file watcher events
  • Links not appearing → Check document link provider registration

Development Best Practices

1. Code Organization

Single Responsibility:

// Good: Each method has one clear purpose
class FactoryLinkProvider {
  private async initializeFactoryFiles() {
    /* ... */
  }
  private async cacheFactoryDefinitions() {
    /* ... */
  }
  private createDocumentLink() {
    /* ... */
  }
}

Clear Interfaces:

// Good: Clear data structures
interface FactoryDefinition {
  uri: vscode.Uri;
  lineNumber: number;
}

interface TraitDefinition extends FactoryDefinition {
  factory: string;
}

2. Error Handling

Graceful Degradation:

// Good: Continue with partial functionality
try {
  const factoryFiles = await vscode.workspace.findFiles(pattern);
  await this.processFactoryFiles(factoryFiles);
} catch (error) {
  console.warn("Failed to load some factory files:", error);
  // Continue with available files
}

User-Friendly Behavior:

// Good: Fail silently for user, log for developers
provideDocumentLinks(document: vscode.TextDocument): vscode.DocumentLink[] {
  try {
    return this.generateLinks(document)
  } catch (error) {
    console.error('Link generation failed:', error)
    return [] // Return empty array instead of throwing
  }
}

3. Performance During Development

Development Optimizations:

// Use smaller test datasets during development
const maxFactoryFiles = process.env.NODE_ENV === "development" ? 10 : Infinity;

// Add timing measurements
const start = Date.now();
await this.initializeFactoryFiles();
console.log(`Factory initialization took ${Date.now() - start}ms`);

Memory Monitoring:

// Monitor cache size during development
setInterval(() => {
  console.log("Cache stats:", {
    factories: this.factoryCache.size,
    traits: this.traitCache.size,
    memory: process.memoryUsage(),
  });
}, 10000);

Common Development Tasks

1. Adding New Factory Methods

Update Detection Regex:

// Add new method to existing regex
const factoryCallPattern =
  /(?:create|build|attributes_for|NEW_METHOD)\s*(?:\(\s*)?:([a-zA-Z0-9_]+)/g;

Test New Method:

test("detects new factory method", () => {
  const text = "attrs = attributes_for(:user)";
  const matches = Array.from(text.matchAll(factoryCallPattern));
  assert.strictEqual(matches.length, 1);
});

2. Improving Pattern Detection

Test New Patterns:

// Test complex factory calls
const complexPatterns = [
  'create(:user, name: "John")',
  "build_list(:user, 5, :admin)",
  'create :user, :admin, name: "Admin"',
];

complexPatterns.forEach((pattern) => {
  // Test regex against each pattern
});

3. Configuration Enhancements

Add New Configuration Options:

// package.json - contributes.configuration.properties
"rails-factorybot-jump.newOption": {
  "type": "boolean",
  "default": true,
  "description": "Enable new feature"
}

Access Configuration:

const config = vscode.workspace.getConfiguration("rails-factorybot-jump");
const newOption = config.get<boolean>("newOption", true);

Troubleshooting Development Issues

1. Extension Not Loading

Check Activation Events:

// package.json - ensure proper activation
"activationEvents": [
  "onLanguage:ruby"
]

Verify Extension Host:

  • Check Extension Development Host console for activation errors
  • Ensure no syntax errors in TypeScript compilation
  • Verify all required dependencies are installed

2. Tests Failing

Common Test Issues:

# Clean and rebuild
rm -rf out/
npm run compile
npm test

# Check test environment
node --version  # Should be 18.x

Mock Issues:

// Ensure proper cleanup
afterEach(() => {
  sinon.restore(); // Restore all stubs
});

3. Performance Issues

Profile Development:

// Add timing to identify bottlenecks
console.time("factoryDiscovery");
await this.initializeFactoryFiles();
console.timeEnd("factoryDiscovery");

Check Resource Usage:

  • Monitor memory usage in Extension Development Host
  • Use VSCode's built-in performance tools
  • Profile regex performance with large files

This comprehensive local development guide provides everything needed to contribute effectively to the Rails FactoryBot Jump extension.

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