@adminide-stack/form-builder-core 5.1.4-alpha.81 → 6.0.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,380 +0,0 @@
1
- # JavaScript Autocomplete Integration for Inngest Steps
2
-
3
- Complete integration of intelligent JavaScript autocompletion in step function editors.
4
-
5
- ## Overview
6
-
7
- This integration connects Monaco Editor with the `js-autocomplete-extension` to provide:
8
-
9
- - Context-aware JavaScript completions using Tern.js
10
- - Type information on hover
11
- - Step-specific completions for Inngest workflows
12
- - Library support (lodash, moment, etc.)
13
- - Dynamic completions based on execution context
14
-
15
- ## Architecture
16
-
17
- ```
18
- ┌─────────────────────────────────────────────────┐
19
- │ CodeEditor Component │
20
- │ (Monaco Editor Instance) │
21
- └──────────────────┬──────────────────────────────┘
22
-
23
- │ User types code
24
-
25
- ┌──────────────────▼──────────────────────────────┐
26
- │ monacoAutocompleteIntegration.ts │
27
- │ - setupMonacoAutocomplete() │
28
- │ - setupStepAutocomplete() │
29
- └──────────────────┬──────────────────────────────┘
30
-
31
- │ services.commands.executeCommand()
32
-
33
- ┌──────────────────▼──────────────────────────────┐
34
- │ js-autocomplete-extension │
35
- │ - jsAutocomplete.getCompletions │
36
- │ - jsAutocomplete.getTypeInfo │
37
- │ - jsAutocomplete.installLibrary │
38
- └──────────────────┬──────────────────────────────┘
39
-
40
- │ code.javascript.* API
41
-
42
- ┌──────────────────▼──────────────────────────────┐
43
- │ JavaScript Worker (Tern.js) │
44
- │ - Type inference │
45
- │ - Library definitions │
46
- │ - Scope analysis │
47
- └──────────────────────────────────────────────────┘
48
- ```
49
-
50
- ## Files Created
51
-
52
- ### 1. `stepGenerator.ts` (Updated)
53
-
54
- Added completion support functions:
55
-
56
- - `getStepCompletionScope()` - Returns available scope variables
57
- - `getStepTypeDefinitions()` - Returns TypeScript definitions for Inngest API
58
- - `getStepTypeCompletions()` - Returns step-type-specific completions
59
- - `extractVariablesFromCode()` - Extracts variables from code for context
60
- - `getStepCompletionContext()` - Gets complete completion context for a step
61
-
62
- ### 2. `monacoAutocompleteIntegration.ts` (New)
63
-
64
- Monaco Editor integration layer:
65
-
66
- - `setupMonacoAutocomplete()` - Setup general JS/TS autocomplete
67
- - `setupStepAutocomplete()` - Setup step-specific autocomplete
68
- - `installLibraryForAutocomplete()` - Install library definitions
69
- - `updateAutocompleteConfig()` - Update autocomplete settings
70
- - `getAvailableDefinitions()` - Get loaded type definitions
71
-
72
- Uses your command execution pattern:
73
-
74
- ```typescript
75
- await services.commands.executeCommand({
76
- command: 'jsAutocomplete.getCompletions',
77
- arguments: [text, position, scope],
78
- });
79
- ```
80
-
81
- ## Usage in CodeEditor
82
-
83
- ### Basic Integration
84
-
85
- ```tsx
86
- import { setupMonacoAutocomplete } from '@form-builder/core/inngest/monacoAutocompleteIntegration';
87
-
88
- const CodeEditor: React.FC<CodeEditorProps> = ({ value, onChange, services }) => {
89
- const handleEditorWillMount = async (monaco: any) => {
90
- // Setup autocomplete
91
- if (services?.commands) {
92
- await setupMonacoAutocomplete(
93
- monaco,
94
- {
95
- enableInngestContext: true,
96
- customScope: ['step', 'event'],
97
- enableHoverInfo: true,
98
- commandService: services.commands,
99
- },
100
- services.commands,
101
- );
102
- }
103
-
104
- // Rest of your setup...
105
- };
106
-
107
- return <Editor beforeMount={handleEditorWillMount} />;
108
- };
109
- ```
110
-
111
- ### Step-Specific Integration
112
-
113
- ```tsx
114
- import { setupStepAutocomplete } from '@form-builder/core/inngest/monacoAutocompleteIntegration';
115
-
116
- const handleEditorWillMount = async (monaco: any) => {
117
- if (services?.commands && currentStep) {
118
- // Provides step-type-specific completions
119
- await setupStepAutocomplete(monaco, currentStep, code, services.commands);
120
- }
121
- };
122
- ```
123
-
124
- ## Extension Commands
125
-
126
- All extension commands follow your command execution pattern:
127
-
128
- ### Get Completions
129
-
130
- ```typescript
131
- const result = await services.commands.executeCommand({
132
- command: 'jsAutocomplete.getCompletions',
133
- arguments: [
134
- text, // Full source code
135
- position, // Cursor offset
136
- ['step', 'event', 'myVar'], // Optional scope
137
- ],
138
- });
139
-
140
- // Returns:
141
- // {
142
- // completions: [
143
- // { name: 'run', type: 'fn(id: string, fn: function): Promise', doc: '...' },
144
- // { name: 'sleep', type: 'fn(id: string, duration: string): Promise', doc: '...' }
145
- // ],
146
- // isIncomplete: false
147
- // }
148
- ```
149
-
150
- ### Get Type Info
151
-
152
- ```typescript
153
- const typeInfo = await services.commands.executeCommand({
154
- command: 'jsAutocomplete.getTypeInfo',
155
- arguments: ['step', ['event', 'step']],
156
- });
157
-
158
- // Returns:
159
- // {
160
- // type: 'object with methods run, sleep, sendEvent, waitForEvent',
161
- // doc: 'Inngest step API for workflow orchestration',
162
- // url: 'https://docs.inngest.com'
163
- // }
164
- ```
165
-
166
- ### Install Library
167
-
168
- ```typescript
169
- await services.commands.executeCommand({
170
- command: 'jsAutocomplete.installLibrary',
171
- arguments: ['https://cdn.jsdelivr.net/npm/@types/lodash/index.d.ts', ['_', 'lodash']],
172
- });
173
- ```
174
-
175
- ### Update Configuration
176
-
177
- ```typescript
178
- await services.commands.executeCommand({
179
- command: 'jsAutocomplete.updateConfig',
180
- arguments: [
181
- {
182
- includeDefaults: true,
183
- includeLibraries: true,
184
- enableDynamicLibraries: true,
185
- customDefinitions: ['lodash', 'moment'],
186
- },
187
- ],
188
- });
189
- ```
190
-
191
- ## Step-Specific Completions
192
-
193
- The integration provides context-aware completions based on step type:
194
-
195
- ### Sleep Step
196
-
197
- ```javascript
198
- step.sleep('step-id', '5s'); // Completions show duration formats: "5s", "1m", "1h"
199
- ```
200
-
201
- ### Send Event Step
202
-
203
- ```javascript
204
- step.sendEvent('step-id', {
205
- name: 'my.event', // Completions suggest event patterns
206
- data: {}, // Type-aware data completions
207
- });
208
- ```
209
-
210
- ### Wait For Event Step
211
-
212
- ```javascript
213
- step.waitForEvent('step-id', {
214
- event: '', // Event name completions
215
- timeout: '', // Duration completions
216
- });
217
- ```
218
-
219
- ### Run Step
220
-
221
- ```javascript
222
- step.run('step-id', async (event, step) => {
223
- event. // Completions for event properties
224
- step. // Completions for step methods
225
- })
226
- ```
227
-
228
- ## Type Definitions
229
-
230
- The integration includes comprehensive type definitions:
231
-
232
- ```typescript
233
- declare const step: {
234
- run<T>(id: string, fn: (event: any, step: any) => Promise<T> | T): Promise<T>;
235
- sendEvent(id: string, input: { name: string; data?: any }): Promise<void>;
236
- waitForEvent<T = any>(id: string, opts: { event: string; timeout?: string | number }): Promise<T>;
237
- sleep(id: string, ms: string | number): Promise<void>;
238
- };
239
-
240
- declare const event: {
241
- data: any;
242
- id: string;
243
- name: string;
244
- ts: number;
245
- };
246
- ```
247
-
248
- ## Features
249
-
250
- ### 1. Context-Aware Completions
251
-
252
- - Knows about `step`, `event`, and local variables
253
- - Provides method completions based on type inference
254
- - Suggests relevant APIs for current step type
255
-
256
- ### 2. Hover Type Information
257
-
258
- - Hover over any symbol to see its type
259
- - View documentation inline
260
- - Links to external documentation
261
-
262
- ### 3. Library Support
263
-
264
- - Automatically includes installed libraries
265
- - Dynamic library detection from execution context
266
- - Custom library definitions
267
-
268
- ### 4. Scope Analysis
269
-
270
- - Extracts variables from code
271
- - Maintains scope context across edits
272
- - Provides completions for local variables
273
-
274
- ### 5. Snippets Integration
275
-
276
- - Works alongside your existing Monaco snippets
277
- - Doesn't conflict with manual completions
278
- - Combines template snippets with intelligent completions
279
-
280
- ## Configuration
281
-
282
- Users can configure autocomplete behavior:
283
-
284
- ```typescript
285
- {
286
- "jsAutocomplete.includeDefaults": true, // ECMAScript definitions
287
- "jsAutocomplete.includeLibraries": true, // Installed libraries
288
- "jsAutocomplete.enableDynamicLibraries": true, // Runtime detection
289
- "jsAutocomplete.customDefinitions": [] // Custom type defs
290
- }
291
- ```
292
-
293
- ## Testing
294
-
295
- ### Test Extension Availability
296
-
297
- ```typescript
298
- React.useEffect(() => {
299
- if (services?.commands) {
300
- services.commands
301
- .executeCommand({
302
- command: 'jsAutocomplete.getAvailableDefinitions',
303
- arguments: [],
304
- })
305
- .then((defs) => {
306
- console.log('Extension loaded, definitions:', defs);
307
- })
308
- .catch((err) => {
309
- console.error('Extension not available:', err);
310
- });
311
- }
312
- }, [services]);
313
- ```
314
-
315
- ### Test Completions
316
-
317
- ```typescript
318
- const testCompletions = async () => {
319
- const result = await services.commands.executeCommand({
320
- command: 'jsAutocomplete.getCompletions',
321
- arguments: ['step.', 5, ['step', 'event']],
322
- });
323
-
324
- console.log('Completions:', result.completions);
325
- // Should show: run, sleep, sendEvent, waitForEvent
326
- };
327
- ```
328
-
329
- ## Troubleshooting
330
-
331
- ### No Completions Showing
332
-
333
- 1. ✅ Check extension is activated in console
334
- 2. ✅ Verify `services.commands` is available
335
- 3. ✅ Test command execution manually
336
- 4. ✅ Check Monaco provider was registered
337
-
338
- ### Wrong Completions
339
-
340
- 1. ✅ Verify scope context is correct
341
- 2. ✅ Check step type is properly set
342
- 3. ✅ Try resetting context: `jsAutocomplete.resetContext`
343
-
344
- ### Type Info Not Showing
345
-
346
- 1. ✅ Ensure `enableHoverInfo: true`
347
- 2. ✅ Check hover provider is registered
348
- 3. ✅ Test `getTypeInfo` command manually
349
-
350
- ## Performance
351
-
352
- - **Lazy Loading**: Type definitions loaded on-demand
353
- - **Caching**: Tern.js caches type information
354
- - **Incremental**: Updates as code changes
355
- - **Worker-Based**: Runs in separate thread
356
-
357
- ## Future Enhancements
358
-
359
- - [ ] Signature help for function parameters
360
- - [ ] Definition provider (Go to Definition)
361
- - [ ] References provider (Find All References)
362
- - [ ] Rename provider
363
- - [ ] Code actions (quick fixes)
364
- - [ ] Import statement generation
365
- - [ ] JSDoc parsing and display
366
- - [ ] Multi-step context awareness
367
-
368
- ## Benefits
369
-
370
- ✅ **Intelligent Completions** - Context-aware suggestions using Tern.js
371
- ✅ **Type Information** - Hover to see types and documentation
372
- ✅ **Library Support** - Completions for installed libraries
373
- ✅ **Step-Specific** - Tailored completions for each step type
374
- ✅ **Works with Existing Code** - Integrates with your snippets
375
- ✅ **Command Pattern** - Uses your existing command execution
376
- ✅ **Performance** - Worker-based, doesn't block UI
377
-
378
- ## License
379
-
380
- MIT
@@ -1,151 +0,0 @@
1
- /* eslint-disable no-use-before-define */
2
- import type {
3
- InngestFunctionDef,
4
- InngestStep,
5
- ExtractedFunction,
6
- StepFunction,
7
- GeneratedFunctionResult,
8
- } from './interfaces/types';
9
- import {
10
- cleanStepCode,
11
- extractStepVarName,
12
- generateFromExtractedFunctions,
13
- extractFunctionBody,
14
- } from './stepGenerator';
15
-
16
- // Re-export utilities for backward compatibility
17
- export { cleanStepCode, extractStepVarName } from './stepGenerator';
18
-
19
- // Check if code contains direct step operations (sleep, sendEvent, etc)
20
- function hasDirectStepOperations(code: string): boolean {
21
- return /step\.(sleep|sendEvent|waitForEvent|run)\s*\(/.test(code);
22
- }
23
-
24
- function getDefaultDirectBody(type: string, id: string, label?: string): string {
25
- switch (type) {
26
- case 'sleep':
27
- return `const ${id}_result = await step.sleep('${id}', '5s');`;
28
- case 'sendEvent':
29
- return `const ${id}_result = await step.sendEvent('${id}', { name: 'my.custom.event', data: { source: '${
30
- label || id
31
- }', ts: new Date().toISOString() } });`;
32
- case 'waitForEvent':
33
- return `const ${id}_result = await step.waitForEvent('${id}', { event: 'my.waited.event', timeout: '60s' });`;
34
- default:
35
- return `// not supported`;
36
- }
37
- }
38
-
39
- function indent(s: string, spaces: number): string {
40
- const pad = ' '.repeat(spaces);
41
- return s
42
- .split('\n')
43
- .map((l) => (l ? pad + l : l))
44
- .join('\n');
45
- }
46
-
47
- // Simple code formatter
48
- function formatCode(code: string): string {
49
- // Basic formatting - in production, you'd use a proper formatter
50
- return code
51
- .split('\n')
52
- .map((line) => line.trimEnd())
53
- .join('\n')
54
- .replace(/\n{3,}/g, '\n\n'); // Remove excessive blank lines
55
- }
56
-
57
- function generateStepBlock(step: InngestStep, position: number): string {
58
- const stepVar = (step.code || '').match(/const\s+(\w+)\s*=/)?.[1] || `step_${position}`;
59
-
60
- // If caller supplied code, embed it inside step.run wrapper by default for consistency
61
- if (step.type === 'sleep' || step.type === 'sendEvent' || step.type === 'waitForEvent') {
62
- // Execute directly (these typically call step.* helpers)
63
- const body = extractFunctionBody(step.code || '') || getDefaultDirectBody(step.type, stepVar, step.name);
64
- return `// ${step.description || step.name || `Step ${position}`}
65
- ${body}`;
66
- }
67
-
68
- const inner = extractFunctionBody(step.code || '') || 'return { success: true };';
69
- return `// ${step.description || step.name || `Step ${position}`}
70
- const ${stepVar}_result = await step.run('${stepVar}', async (event, step) => {
71
- ${indent(inner, 2)}
72
- });`;
73
- }
74
-
75
- // Minimal shared generator. Replace internals by moving editor logic here incrementally.
76
- export function generateFunctionCode(def: InngestFunctionDef): string {
77
- const eventsString = def.events.length > 0 ? def.events.map((e) => `'${e}'`).join(', ') : `'app.event'`;
78
- const safeId = def.id.replace(/[^a-zA-Z0-9]/g, '') || 'function';
79
- const body = generateHandlerBody(def);
80
- return `const ${safeId}Function = inngest.createFunction(
81
- { id: '${def.id}' },
82
- { event: [${eventsString}] },
83
- async ({ event, step }) => {
84
- ${indent(body, 4)}
85
- }
86
- );`;
87
- }
88
-
89
- // New: return only the handler body that backend executes and editor displays
90
- export function generateHandlerBody(def: InngestFunctionDef): string {
91
- const stepBlocks = def.steps.map((step, index) => generateStepBlock(step, index + 1)).join('\n');
92
- // Footer removed: callers should append their own consolidated return as needed
93
- return `${stepBlocks}`;
94
- }
95
-
96
- // Generate Inngest function from database-extracted functions
97
- export function generateStepFunctionsFromDB(
98
- functionId: string,
99
- events: string[],
100
- extractedFunctions: ExtractedFunction[],
101
- ): GeneratedFunctionResult {
102
- if (!extractedFunctions || extractedFunctions.length === 0) {
103
- throw new Error('No functions provided to generate');
104
- }
105
-
106
- // Use the new unified generator
107
- const code = generateFromExtractedFunctions(extractedFunctions);
108
-
109
- return {
110
- code: formatCode(code),
111
- functionId,
112
- stepCount: extractedFunctions.length,
113
- };
114
- }
115
-
116
- // Wrap multiple step functions in a single Inngest function
117
- export function wrapStepsInInngestFunction(functionDef: InngestFunctionDef, stepFunctions: StepFunction[]): string {
118
- const extractedFunctions: ExtractedFunction[] = stepFunctions.map((sf) => ({
119
- id: sf.id,
120
- name: sf.name,
121
- code: sf.code,
122
- description: sf.description,
123
- }));
124
-
125
- const result = generateStepFunctionsFromDB(functionDef.id, functionDef.events, extractedFunctions);
126
-
127
- return result.code;
128
- }
129
-
130
- // Generate a single step from an extracted function
131
- export function generateStepFromFunction(stepFunction: StepFunction, index: number): string {
132
- const stepVar = extractStepVarName(stepFunction.code) || `step_${index}`;
133
- const functionBody = extractFunctionBody(stepFunction.code);
134
-
135
- if (!functionBody) {
136
- return `// ${
137
- stepFunction.name || `Step ${index}`
138
- }\nconst ${stepVar}_result = { success: false, error: 'Invalid function format' };`;
139
- }
140
-
141
- const hasDirectOps = hasDirectStepOperations(stepFunction.code);
142
- const cleanedBody = cleanStepCode(functionBody);
143
-
144
- if (hasDirectOps) {
145
- return `// ${stepFunction.name || `Step ${index}`}\n${cleanedBody}`;
146
- }
147
-
148
- return `// ${
149
- stepFunction.name || `Step ${index}`
150
- }\nconst ${stepVar}_result = await step.run('${stepVar}', async (event, step) => {\n${indent(cleanedBody, 2)}\n});`;
151
- }
@@ -1 +0,0 @@
1
- export * from './types';
@@ -1,63 +0,0 @@
1
- export type InngestStepType =
2
- | 'run'
3
- | 'sleep'
4
- | 'sendEvent'
5
- | 'waitForEvent'
6
- | 'retrieveData'
7
- | 'parallel'
8
- | 'validateForm';
9
-
10
- export interface InngestStep {
11
- id: string;
12
- name: string;
13
- type: InngestStepType;
14
- code?: string;
15
- description?: string;
16
- // Loose optional fields to avoid coupling; extend in callers as needed
17
- [key: string]: unknown;
18
- }
19
-
20
- export interface InngestFunctionDef {
21
- id: string;
22
- name: string;
23
- description?: string;
24
- events: string[];
25
- steps: InngestStep[];
26
- concurrency?: number;
27
- retries?: number;
28
- timeout?: string | number;
29
- // Extra passthrough metadata
30
- [key: string]: unknown;
31
- }
32
-
33
- // New interfaces for database-extracted functions
34
- export interface ExtractedFunction {
35
- id: string;
36
- name: string;
37
- code?: string; // The complete async function code
38
- extensionId?: string;
39
- extensionName?: string;
40
- generatedCode?: string;
41
- steps?: StepDefinition[];
42
- originalStepName?: string;
43
- }
44
-
45
- export interface StepFunction {
46
- id: string;
47
- name: string;
48
- code: string;
49
- type?: InngestStepType;
50
- description?: string;
51
- }
52
-
53
- export interface StepDefinition {
54
- id: string;
55
- name: string;
56
- code: string;
57
- }
58
-
59
- export interface GeneratedFunctionResult {
60
- code: string;
61
- functionId: string;
62
- stepCount: number;
63
- }