Development Guides Local Development - hiraishikentaro/rails-factorybot-jump GitHub Wiki
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
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
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
Launch Development Environment:
- Open the project in VSCode
- Press
F5
or go to Run → Start Debugging - This launches a new "Extension Development Host" window
- The extension is automatically loaded in this window
- 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
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) orCmd+R
(Mac) - This reloads the extension with your latest changes
- No need to restart the entire development host
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
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
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);
});
});
Test Factory Detection:
- 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
- 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
- Open test.rb in Extension Development Host
- Hover over
:user
and:admin
to verify links appear - Click links to verify navigation works
Test Configuration Changes:
- Open settings in Extension Development Host
- Modify
rails-factorybot-jump.factoryPaths
- Verify extension updates factory search paths
- Test with custom factory directory structure
Test File Watching:
- Modify a factory file while Extension Development Host is open
- Verify cache updates automatically
- Check that links update in test files
Debugger Setup:
// .vscode/launch.json (already configured)
{
"type": "extensionHost",
"request": "launch",
"name": "Extension",
"runtimeExecutable": "${execPath}",
"args": ["--extensionDevelopmentPath=${workspaceRoot}"]
}
Debug Workflow:
- Set breakpoints in TypeScript source files
- Press
F5
to start debugging - Use the Extension Development Host to trigger breakpoints
- Inspect variables, call stack, and execution flow
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:
- In Extension Development Host: Help → Toggle Developer Tools
- Go to Console tab to see your debug output
- Use Network tab to monitor file operations
- Use Sources tab for debugging with source maps
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
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;
}
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
}
}
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);
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);
});
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
});
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);
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
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
});
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.