IDE Plugin
Get real-time error detection in your editor.
Overview
The NeoSyringe LSP plugin integrates with TypeScript's language service to provide comprehensive real-time validation:
- 🔴 Missing dependency detection - Shows ALL missing dependencies at once, not just the first one
- 🔴 Circular dependency detection - Instant feedback when you create cycles
- 🔴 Duplicate registration detection - Warnings for conflicts in parent containers or partialConfigs
- 🎯 Precise error positioning - Errors point to the exact token, even for imported services
- 💡 Clean error messages - Readable names without internal hash IDs
What's Validated
The plugin validates dependencies across:
- defineBuilderConfig: Local injections + parent containers + extends
- definePartialConfig: Local injections only
- Cross-file imports: Services imported from other files work correctly
- Constructor dependencies: Automatically extracts required dependencies from class constructors
Setup
Step 1: Add to tsconfig.json
{
"compilerOptions": {
"plugins": [
{ "name": "@djodjonx/neosyringe-lsp" }
]
}
}Step 2: Use Workspace TypeScript
The plugin only works with the workspace TypeScript version.
VS Code
- Open Command Palette:
Ctrl+Shift+P(orCmd+Shift+Pon Mac) - Search for: "TypeScript: Select TypeScript Version"
- Select: "Use Workspace Version"
JetBrains IDEs (WebStorm, IntelliJ)
- Go to Settings → Languages & Frameworks → TypeScript
- Set TypeScript version to "Project" or point to
node_modules/typescript
Neovim (with nvim-lspconfig)
require('lspconfig').tsserver.setup {
init_options = {
plugins = {
{
name = "@djodjonx/neosyringe-lsp",
location = "./node_modules/@djodjonx/neosyringe/dist/lsp"
}
}
}
}Step 3: Restart TypeScript Server
After configuration, restart the TypeScript server:
- VS Code:
Ctrl+Shift+P→ "TypeScript: Restart TS Server" - WebStorm: File → Invalidate Caches / Restart
Comprehensive Validation
All Errors Shown at Once
Unlike build-time validation that stops at the first error, the LSP shows all validation errors simultaneously:
export const container = defineBuilderConfig({
injections: [
{ token: ServiceA }, // 🔴 Missing: ILogger
{ token: ServiceB }, // 🔴 Missing: ILogger
{ token: ServiceC }, // 🔴 Missing: IDatabase
]
});You'll see 3 errors in the Problems panel, allowing you to fix all issues at once instead of one-by-one.
Validation Context
The plugin validates dependencies based on context:
For definePartialConfig:
- Only checks local injections
- Reports missing dependencies within the partial config
For defineBuilderConfig:
- Checks local injections
- Validates against parent container (via
useContainer) - Validates against extended partials (via
extends) - Recursive validation through the entire dependency tree
Priority: Parent container → extends → local injections (with scoped: true overriding everything)
Detected Errors
Circular Dependency
class A {
constructor(private b: B) {}
}
class B {
constructor(private a: A) {} // 🔴 Cycle!
}
export const container = defineBuilderConfig({
injections: [
{ token: A },
{ token: B }
]
});
// Error: [NeoSyringe] Circular dependency detected: A -> B -> AMissing Binding
The LSP detects when a service requires dependencies that aren't registered. It checks:
- Constructor parameters in classes
- All services in the container (not just the first error)
- Dependencies in parent containers and extends
- Cross-file imports
interface ILogger {
log(msg: string): void;
}
interface IEventBus {
publish(event: any): void;
}
class InMemoryEventBus implements IEventBus {
constructor(private logger: ILogger) {} // Requires ILogger
publish(event: any) {}
}
class UserService {
constructor(
private logger: ILogger, // Requires ILogger
private eventBus: IEventBus
) {}
}
export const container = defineBuilderConfig({
injections: [
// ILogger is NOT registered
{ token: useInterface<IEventBus>(), provider: InMemoryEventBus }, // 🔴 Error!
{ token: UserService } // 🔴 Error!
]
});
// Error on line with IEventBus:
// [NeoSyringe] Missing binding: Service 'IEventBus' depends on 'ILogger',
// but no provider was registered.
//
// Error on line with UserService:
// [NeoSyringe] Missing binding: Service 'UserService' depends on 'ILogger',
// but no provider was registered.All missing dependencies are shown at once, helping you see the full picture.
Error positioning: The error appears on the exact line where the problematic service is registered, making it easy to locate and fix.
Duplicate Registration
const parent = defineBuilderConfig({
injections: [
{ token: useInterface<ILogger>(), provider: ConsoleLogger }
]
});
export const child = defineBuilderConfig({
useContainer: parent,
injections: [
{ token: useInterface<ILogger>(), provider: FileLogger } // 🔴 Duplicate!
]
});
// Error: [NeoSyringe] Duplicate registration: 'ILogger' is already registered
// in the parent container. Use 'scoped: true' to override intentionally.Error Display
Precise Error Positioning
Errors appear on the exact token that has the problem, not on the entire object:
┌─────────────────────────────────────────────────────────────────┐
│ container.ts │
├─────────────────────────────────────────────────────────────────┤
│ │
│ export const container = defineBuilderConfig({ │
│ injections: [ │
│ { token: UserService } │
│ ~~~~~~~~~~~ ← Error here, not on entire line │
│ ▲ │
│ ┌────────────┴───────────────────────────────────────────────┐ │
│ │ 🔴 [NeoSyringe] Missing binding: Service 'UserService' │ │
│ │ depends on 'ILogger', but no provider was registered. │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘Key features:
- Error positioned on the
token: ServiceNameproperty - Works correctly even when services are imported from other files
- Clean error messages with readable names (no internal hash IDs)
- All errors shown simultaneously in the Problems panel
Troubleshooting
Plugin Not Working
- Check TypeScript version: Must use workspace version
- Check tsconfig.json: Plugin must be in
compilerOptions.plugins - Restart TS Server: Changes require restart
- Check node_modules: Package must be installed
Errors Not Showing
- Save the file: Some editors need file save to trigger
- Check file extension: Only
.tsand.tsxfiles - Check if file has
defineBuilderConfig: Plugin only analyzes DI files
False Positives
If the plugin reports errors that shouldn't exist:
- Check that all imports are correct
- Ensure interface names match
- Try restarting the TypeScript server
