JavaScript Autocomplete Integration for Inngest Steps
Complete integration of intelligent JavaScript autocompletion in step function editors.
Overview
This integration connects Monaco Editor with the js-autocomplete-extension to provide:
- Context-aware JavaScript completions using Tern.js
- Type information on hover
- Step-specific completions for Inngest workflows
- Library support (lodash, moment, etc.)
- Dynamic completions based on execution context
Architecture
┌─────────────────────────────────────────────────┐
│ CodeEditor Component │
│ (Monaco Editor Instance) │
└──────────────────┬──────────────────────────────┘
│
│ User types code
│
┌──────────────────▼──────────────────────────────┐
│ monacoAutocompleteIntegration.ts │
│ - setupMonacoAutocomplete() │
│ - setupStepAutocomplete() │
└──────────────────┬──────────────────────────────┘
│
│ services.commands.executeCommand()
│
┌──────────────────▼──────────────────────────────┐
│ js-autocomplete-extension │
│ - jsAutocomplete.getCompletions │
│ - jsAutocomplete.getTypeInfo │
│ - jsAutocomplete.installLibrary │
└──────────────────┬──────────────────────────────┘
│
│ code.javascript.* API
│
┌──────────────────▼──────────────────────────────┐
│ JavaScript Worker (Tern.js) │
│ - Type inference │
│ - Library definitions │
│ - Scope analysis │
└──────────────────────────────────────────────────┘
Files Created
1. stepGenerator.ts (Updated)
Added completion support functions:
getStepCompletionScope() - Returns available scope variables
getStepTypeDefinitions() - Returns TypeScript definitions for Inngest API
getStepTypeCompletions() - Returns step-type-specific completions
extractVariablesFromCode() - Extracts variables from code for context
getStepCompletionContext() - Gets complete completion context for a step
2. monacoAutocompleteIntegration.ts (New)
Monaco Editor integration layer:
setupMonacoAutocomplete() - Setup general JS/TS autocomplete
setupStepAutocomplete() - Setup step-specific autocomplete
installLibraryForAutocomplete() - Install library definitions
updateAutocompleteConfig() - Update autocomplete settings
getAvailableDefinitions() - Get loaded type definitions
Uses your command execution pattern:
await services.commands.executeCommand({
command: 'jsAutocomplete.getCompletions',
arguments: [text, position, scope],
});
Usage in CodeEditor
Basic Integration
import { setupMonacoAutocomplete } from '@form-builder/core/inngest/monacoAutocompleteIntegration';
const CodeEditor: React.FC<CodeEditorProps> = ({ value, onChange, services }) => {
const handleEditorWillMount = async (monaco: any) => {
if (services?.commands) {
await setupMonacoAutocomplete(
monaco,
{
enableInngestContext: true,
customScope: ['step', 'event'],
enableHoverInfo: true,
commandService: services.commands,
},
services.commands,
);
}
};
return <Editor beforeMount={handleEditorWillMount} />;
};
Step-Specific Integration
import { setupStepAutocomplete } from '@form-builder/core/inngest/monacoAutocompleteIntegration';
const handleEditorWillMount = async (monaco: any) => {
if (services?.commands && currentStep) {
await setupStepAutocomplete(monaco, currentStep, code, services.commands);
}
};
Extension Commands
All extension commands follow your command execution pattern:
Get Completions
const result = await services.commands.executeCommand({
command: 'jsAutocomplete.getCompletions',
arguments: [
text,
position,
['step', 'event', 'myVar'],
],
});
Get Type Info
const typeInfo = await services.commands.executeCommand({
command: 'jsAutocomplete.getTypeInfo',
arguments: ['step', ['event', 'step']],
});
Install Library
await services.commands.executeCommand({
command: 'jsAutocomplete.installLibrary',
arguments: ['https://cdn.jsdelivr.net/npm/@types/lodash/index.d.ts', ['_', 'lodash']],
});
Update Configuration
await services.commands.executeCommand({
command: 'jsAutocomplete.updateConfig',
arguments: [
{
includeDefaults: true,
includeLibraries: true,
enableDynamicLibraries: true,
customDefinitions: ['lodash', 'moment'],
},
],
});
Step-Specific Completions
The integration provides context-aware completions based on step type:
Sleep Step
step.sleep('step-id', '5s');
Send Event Step
step.sendEvent('step-id', {
name: 'my.event',
data: {},
});
Wait For Event Step
step.waitForEvent('step-id', {
event: '',
timeout: '',
});
Run Step
step.run('step-id', async (event, step) => {
event.
step.
})
Type Definitions
The integration includes comprehensive type definitions:
declare const step: {
run<T>(id: string, fn: (event: any, step: any) => Promise<T> | T): Promise<T>;
sendEvent(id: string, input: { name: string; data?: any }): Promise<void>;
waitForEvent<T = any>(id: string, opts: { event: string; timeout?: string | number }): Promise<T>;
sleep(id: string, ms: string | number): Promise<void>;
};
declare const event: {
data: any;
id: string;
name: string;
ts: number;
};
Features
1. Context-Aware Completions
- Knows about
step, event, and local variables
- Provides method completions based on type inference
- Suggests relevant APIs for current step type
2. Hover Type Information
- Hover over any symbol to see its type
- View documentation inline
- Links to external documentation
3. Library Support
- Automatically includes installed libraries
- Dynamic library detection from execution context
- Custom library definitions
4. Scope Analysis
- Extracts variables from code
- Maintains scope context across edits
- Provides completions for local variables
5. Snippets Integration
- Works alongside your existing Monaco snippets
- Doesn't conflict with manual completions
- Combines template snippets with intelligent completions
Configuration
Users can configure autocomplete behavior:
{
"jsAutocomplete.includeDefaults": true,
"jsAutocomplete.includeLibraries": true,
"jsAutocomplete.enableDynamicLibraries": true,
"jsAutocomplete.customDefinitions": []
}
Testing
Test Extension Availability
React.useEffect(() => {
if (services?.commands) {
services.commands
.executeCommand({
command: 'jsAutocomplete.getAvailableDefinitions',
arguments: [],
})
.then((defs) => {
console.log('Extension loaded, definitions:', defs);
})
.catch((err) => {
console.error('Extension not available:', err);
});
}
}, [services]);
Test Completions
const testCompletions = async () => {
const result = await services.commands.executeCommand({
command: 'jsAutocomplete.getCompletions',
arguments: ['step.', 5, ['step', 'event']],
});
console.log('Completions:', result.completions);
};
Troubleshooting
No Completions Showing
- ✅ Check extension is activated in console
- ✅ Verify
services.commands is available
- ✅ Test command execution manually
- ✅ Check Monaco provider was registered
Wrong Completions
- ✅ Verify scope context is correct
- ✅ Check step type is properly set
- ✅ Try resetting context:
jsAutocomplete.resetContext
Type Info Not Showing
- ✅ Ensure
enableHoverInfo: true
- ✅ Check hover provider is registered
- ✅ Test
getTypeInfo command manually
Performance
- Lazy Loading: Type definitions loaded on-demand
- Caching: Tern.js caches type information
- Incremental: Updates as code changes
- Worker-Based: Runs in separate thread
Future Enhancements
Benefits
✅ Intelligent Completions - Context-aware suggestions using Tern.js
✅ Type Information - Hover to see types and documentation
✅ Library Support - Completions for installed libraries
✅ Step-Specific - Tailored completions for each step type
✅ Works with Existing Code - Integrates with your snippets
✅ Command Pattern - Uses your existing command execution
✅ Performance - Worker-based, doesn't block UI
License
MIT