@mondaydotcomorg/atp-compiler 0.17.16 → 0.18.4-rc.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.
Files changed (115) hide show
  1. package/__tests__/unit/default-compiler.test.ts +259 -0
  2. package/__tests__/unit/plugin-system.test.ts +401 -0
  3. package/dist/atp-compiler/src/index.d.ts +8 -0
  4. package/dist/atp-compiler/src/index.d.ts.map +1 -1
  5. package/dist/atp-compiler/src/index.js +9 -0
  6. package/dist/atp-compiler/src/index.js.map +1 -1
  7. package/dist/atp-compiler/src/plugin-system/create-default-compiler.d.ts +40 -0
  8. package/dist/atp-compiler/src/plugin-system/create-default-compiler.d.ts.map +1 -0
  9. package/dist/atp-compiler/src/plugin-system/create-default-compiler.js +40 -0
  10. package/dist/atp-compiler/src/plugin-system/create-default-compiler.js.map +1 -0
  11. package/dist/atp-compiler/src/plugin-system/default-plugins/array-transformer-plugin.d.ts +18 -0
  12. package/dist/atp-compiler/src/plugin-system/default-plugins/array-transformer-plugin.d.ts.map +1 -0
  13. package/dist/atp-compiler/src/plugin-system/default-plugins/array-transformer-plugin.js +45 -0
  14. package/dist/atp-compiler/src/plugin-system/default-plugins/array-transformer-plugin.js.map +1 -0
  15. package/dist/atp-compiler/src/plugin-system/default-plugins/detection-plugin.d.ts +17 -0
  16. package/dist/atp-compiler/src/plugin-system/default-plugins/detection-plugin.d.ts.map +1 -0
  17. package/dist/atp-compiler/src/plugin-system/default-plugins/detection-plugin.js +33 -0
  18. package/dist/atp-compiler/src/plugin-system/default-plugins/detection-plugin.js.map +1 -0
  19. package/dist/atp-compiler/src/plugin-system/default-plugins/index.d.ts +11 -0
  20. package/dist/atp-compiler/src/plugin-system/default-plugins/index.d.ts.map +1 -0
  21. package/dist/atp-compiler/src/plugin-system/default-plugins/index.js +11 -0
  22. package/dist/atp-compiler/src/plugin-system/default-plugins/index.js.map +1 -0
  23. package/dist/atp-compiler/src/plugin-system/default-plugins/loop-transformer-plugin.d.ts +17 -0
  24. package/dist/atp-compiler/src/plugin-system/default-plugins/loop-transformer-plugin.d.ts.map +1 -0
  25. package/dist/atp-compiler/src/plugin-system/default-plugins/loop-transformer-plugin.js +36 -0
  26. package/dist/atp-compiler/src/plugin-system/default-plugins/loop-transformer-plugin.js.map +1 -0
  27. package/dist/atp-compiler/src/plugin-system/default-plugins/promise-transformer-plugin.d.ts +19 -0
  28. package/dist/atp-compiler/src/plugin-system/default-plugins/promise-transformer-plugin.d.ts.map +1 -0
  29. package/dist/atp-compiler/src/plugin-system/default-plugins/promise-transformer-plugin.js +49 -0
  30. package/dist/atp-compiler/src/plugin-system/default-plugins/promise-transformer-plugin.js.map +1 -0
  31. package/dist/atp-compiler/src/plugin-system/examples/loop-transformer-plugin.d.ts +31 -0
  32. package/dist/atp-compiler/src/plugin-system/examples/loop-transformer-plugin.d.ts.map +1 -0
  33. package/dist/atp-compiler/src/plugin-system/examples/loop-transformer-plugin.js +60 -0
  34. package/dist/atp-compiler/src/plugin-system/examples/loop-transformer-plugin.js.map +1 -0
  35. package/dist/atp-compiler/src/plugin-system/examples/security-validator-plugin.d.ts +48 -0
  36. package/dist/atp-compiler/src/plugin-system/examples/security-validator-plugin.d.ts.map +1 -0
  37. package/dist/atp-compiler/src/plugin-system/examples/security-validator-plugin.js +108 -0
  38. package/dist/atp-compiler/src/plugin-system/examples/security-validator-plugin.js.map +1 -0
  39. package/dist/atp-compiler/src/plugin-system/examples/timeout-plugin.d.ts +53 -0
  40. package/dist/atp-compiler/src/plugin-system/examples/timeout-plugin.d.ts.map +1 -0
  41. package/dist/atp-compiler/src/plugin-system/examples/timeout-plugin.js +106 -0
  42. package/dist/atp-compiler/src/plugin-system/examples/timeout-plugin.js.map +1 -0
  43. package/dist/atp-compiler/src/plugin-system/index.d.ts +14 -0
  44. package/dist/atp-compiler/src/plugin-system/index.d.ts.map +1 -0
  45. package/dist/atp-compiler/src/plugin-system/index.js +16 -0
  46. package/dist/atp-compiler/src/plugin-system/index.js.map +1 -0
  47. package/dist/atp-compiler/src/plugin-system/pluggable-compiler.d.ts +102 -0
  48. package/dist/atp-compiler/src/plugin-system/pluggable-compiler.d.ts.map +1 -0
  49. package/dist/atp-compiler/src/plugin-system/pluggable-compiler.js +280 -0
  50. package/dist/atp-compiler/src/plugin-system/pluggable-compiler.js.map +1 -0
  51. package/dist/atp-compiler/src/plugin-system/plugin-api.d.ts +165 -0
  52. package/dist/atp-compiler/src/plugin-system/plugin-api.d.ts.map +1 -0
  53. package/dist/atp-compiler/src/plugin-system/plugin-api.js +180 -0
  54. package/dist/atp-compiler/src/plugin-system/plugin-api.js.map +1 -0
  55. package/dist/atp-compiler/src/transformer/array-transformer-utils.d.ts +2 -2
  56. package/dist/atp-compiler/src/transformer/array-transformer-utils.d.ts.map +1 -1
  57. package/dist/atp-compiler/src/transformer/array-transformer-utils.js +2 -2
  58. package/dist/atp-compiler/src/transformer/array-transformer-utils.js.map +1 -1
  59. package/dist/atp-compiler/src/transformer/index.d.ts +15 -1
  60. package/dist/atp-compiler/src/transformer/index.d.ts.map +1 -1
  61. package/dist/atp-compiler/src/transformer/index.js +17 -0
  62. package/dist/atp-compiler/src/transformer/index.js.map +1 -1
  63. package/dist/atp-compiler/src/transformer/loop-transformer.d.ts +0 -4
  64. package/dist/atp-compiler/src/transformer/loop-transformer.d.ts.map +1 -1
  65. package/dist/atp-compiler/src/transformer/loop-transformer.js +5 -60
  66. package/dist/atp-compiler/src/transformer/loop-transformer.js.map +1 -1
  67. package/dist/atp-compiler/src/transformer/utils.d.ts +4 -0
  68. package/dist/atp-compiler/src/transformer/utils.d.ts.map +1 -1
  69. package/dist/atp-compiler/src/transformer/utils.js +15 -0
  70. package/dist/atp-compiler/src/transformer/utils.js.map +1 -1
  71. package/dist/atp-compiler/src/types/compiler-interface.d.ts +61 -0
  72. package/dist/atp-compiler/src/types/compiler-interface.d.ts.map +1 -0
  73. package/dist/atp-compiler/src/types/compiler-interface.js +18 -0
  74. package/dist/atp-compiler/src/types/compiler-interface.js.map +1 -0
  75. package/dist/runtime/src/approval/index.js +2 -1
  76. package/dist/runtime/src/approval/index.js.map +1 -1
  77. package/dist/runtime/src/index.d.ts +1 -1
  78. package/dist/runtime/src/index.d.ts.map +1 -1
  79. package/dist/runtime/src/index.js +1 -1
  80. package/dist/runtime/src/index.js.map +1 -1
  81. package/dist/runtime/src/llm/index.d.ts +1 -1
  82. package/dist/runtime/src/llm/index.d.ts.map +1 -1
  83. package/dist/runtime/src/llm/index.js +1 -1
  84. package/dist/runtime/src/llm/index.js.map +1 -1
  85. package/dist/runtime/src/llm/replay.d.ts +75 -0
  86. package/dist/runtime/src/llm/replay.d.ts.map +1 -1
  87. package/dist/runtime/src/llm/replay.js +187 -5
  88. package/dist/runtime/src/llm/replay.js.map +1 -1
  89. package/dist/runtime/src/metadata/generated.d.ts.map +1 -1
  90. package/dist/runtime/src/metadata/generated.js +189 -189
  91. package/dist/runtime/src/metadata/generated.js.map +1 -1
  92. package/dist/runtime/src/metadata/index.js +2 -2
  93. package/dist/runtime/src/metadata/index.js.map +1 -1
  94. package/dist/runtime/src/metadata/types.d.ts +1 -1
  95. package/dist/tsconfig.tsbuildinfo +1 -0
  96. package/package.json +14 -5
  97. package/project.json +1 -3
  98. package/src/index.ts +26 -0
  99. package/src/plugin-system/create-default-compiler.ts +57 -0
  100. package/src/plugin-system/default-plugins/array-transformer-plugin.ts +57 -0
  101. package/src/plugin-system/default-plugins/detection-plugin.ts +41 -0
  102. package/src/plugin-system/default-plugins/index.ts +12 -0
  103. package/src/plugin-system/default-plugins/loop-transformer-plugin.ts +47 -0
  104. package/src/plugin-system/default-plugins/promise-transformer-plugin.ts +63 -0
  105. package/src/plugin-system/examples/loop-transformer-plugin.ts +76 -0
  106. package/src/plugin-system/examples/security-validator-plugin.ts +168 -0
  107. package/src/plugin-system/examples/timeout-plugin.ts +158 -0
  108. package/src/plugin-system/index.ts +19 -0
  109. package/src/plugin-system/pluggable-compiler.ts +318 -0
  110. package/src/plugin-system/plugin-api.ts +330 -0
  111. package/src/transformer/array-transformer-utils.ts +3 -7
  112. package/src/transformer/index.ts +21 -1
  113. package/src/transformer/loop-transformer.ts +5 -66
  114. package/src/transformer/utils.ts +14 -0
  115. package/src/types/compiler-interface.ts +79 -0
@@ -0,0 +1,330 @@
1
+ /**
2
+ * ATP Compiler Plugin API
3
+ *
4
+ * Extensible plugin system for custom transformations and detections
5
+ */
6
+
7
+ import type { NodePath } from '@babel/traverse';
8
+ import type * as t from '@babel/types';
9
+ import type { CompilerConfig, DetectionResult, TransformMetadata, AsyncPattern } from '../types.js';
10
+
11
+ /**
12
+ * Base plugin interface
13
+ */
14
+ export interface CompilerPlugin {
15
+ /**
16
+ * Unique plugin name
17
+ */
18
+ name: string;
19
+
20
+ /**
21
+ * Plugin version (semver)
22
+ */
23
+ version: string;
24
+
25
+ /**
26
+ * Plugin priority (higher = runs first)
27
+ * Built-in plugins: 100
28
+ * User plugins: 50 (default)
29
+ * Low priority: 10
30
+ */
31
+ priority?: number;
32
+
33
+ /**
34
+ * Plugin initialization (optional)
35
+ * Called once when plugin is registered
36
+ */
37
+ initialize?(config: CompilerConfig): void | Promise<void>;
38
+
39
+ /**
40
+ * Plugin cleanup (optional)
41
+ * Called when compiler is disposed
42
+ */
43
+ dispose?(): void | Promise<void>;
44
+ }
45
+
46
+ /**
47
+ * Detection plugin - detects patterns that need transformation
48
+ */
49
+ export interface DetectionPlugin extends CompilerPlugin {
50
+ /**
51
+ * Detect patterns in code
52
+ */
53
+ detect(code: string, ast: t.File): DetectionResult | Promise<DetectionResult>;
54
+
55
+ /**
56
+ * Custom async patterns this plugin can detect
57
+ */
58
+ patterns: AsyncPattern[];
59
+ }
60
+
61
+ /**
62
+ * Transformation plugin - transforms AST nodes
63
+ */
64
+ export interface TransformationPlugin extends CompilerPlugin {
65
+ /**
66
+ * Visitor pattern for AST traversal
67
+ * Return visitor object compatible with @babel/traverse
68
+ */
69
+ getVisitor(config: CompilerConfig): BabelVisitor;
70
+
71
+ /**
72
+ * Get transformation metadata after transform
73
+ */
74
+ getMetadata(): Partial<TransformMetadata>;
75
+
76
+ /**
77
+ * Reset plugin state (called before each transform)
78
+ */
79
+ reset(): void;
80
+ }
81
+
82
+ /**
83
+ * Optimizer plugin - optimizes transformed code
84
+ */
85
+ export interface OptimizerPlugin extends CompilerPlugin {
86
+ /**
87
+ * Optimize AST after all transformations
88
+ */
89
+ optimize(ast: t.File, config: CompilerConfig): t.File | Promise<t.File>;
90
+ }
91
+
92
+ /**
93
+ * Validator plugin - validates code before/after transformation
94
+ */
95
+ export interface ValidatorPlugin extends CompilerPlugin {
96
+ /**
97
+ * Validate code (throw error if invalid)
98
+ */
99
+ validate(code: string, ast: t.File, phase: 'pre' | 'post'): void | Promise<void>;
100
+ }
101
+
102
+ /**
103
+ * Babel visitor type (simplified)
104
+ */
105
+ export interface BabelVisitor {
106
+ [key: string]: (path: NodePath<any>) => void;
107
+ }
108
+
109
+ /**
110
+ * Plugin context - shared state during transformation
111
+ */
112
+ export interface PluginContext {
113
+ config: CompilerConfig;
114
+ executionId?: string;
115
+ metadata: TransformMetadata;
116
+ patterns: Set<AsyncPattern>;
117
+ }
118
+
119
+ /**
120
+ * Plugin registry for managing plugins
121
+ */
122
+ export class PluginRegistry {
123
+ private detectors: DetectionPlugin[] = [];
124
+ private transformers: TransformationPlugin[] = [];
125
+ private optimizers: OptimizerPlugin[] = [];
126
+ private validators: ValidatorPlugin[] = [];
127
+
128
+ /**
129
+ * Register a plugin
130
+ */
131
+ register(plugin: CompilerPlugin): void {
132
+ // Check for name conflicts
133
+ if (this.findPlugin(plugin.name)) {
134
+ throw new Error(
135
+ `Plugin "${plugin.name}" is already registered. ` +
136
+ `Please use a unique name or unregister the existing plugin first.`
137
+ );
138
+ }
139
+
140
+ // Type guards to determine plugin type
141
+ if (this.isDetectionPlugin(plugin)) {
142
+ this.detectors.push(plugin);
143
+ this.detectors.sort((a, b) => (b.priority || 50) - (a.priority || 50));
144
+ }
145
+
146
+ if (this.isTransformationPlugin(plugin)) {
147
+ this.transformers.push(plugin);
148
+ this.transformers.sort((a, b) => (b.priority || 50) - (a.priority || 50));
149
+ }
150
+
151
+ if (this.isOptimizerPlugin(plugin)) {
152
+ this.optimizers.push(plugin);
153
+ this.optimizers.sort((a, b) => (b.priority || 50) - (a.priority || 50));
154
+ }
155
+
156
+ if (this.isValidatorPlugin(plugin)) {
157
+ this.validators.push(plugin);
158
+ this.validators.sort((a, b) => (b.priority || 50) - (a.priority || 50));
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Find a plugin by name
164
+ */
165
+ findPlugin(name: string): CompilerPlugin | undefined {
166
+ const allPlugins = [
167
+ ...this.detectors,
168
+ ...this.transformers,
169
+ ...this.optimizers,
170
+ ...this.validators,
171
+ ];
172
+ return allPlugins.find((p) => p.name === name);
173
+ }
174
+
175
+ /**
176
+ * Unregister a plugin by name
177
+ */
178
+ unregister(name: string): boolean {
179
+ let removed = false;
180
+
181
+ this.detectors = this.detectors.filter((p) => {
182
+ if (p.name === name) {
183
+ removed = true;
184
+ return false;
185
+ }
186
+ return true;
187
+ });
188
+
189
+ this.transformers = this.transformers.filter((p) => {
190
+ if (p.name === name) {
191
+ removed = true;
192
+ return false;
193
+ }
194
+ return true;
195
+ });
196
+
197
+ this.optimizers = this.optimizers.filter((p) => {
198
+ if (p.name === name) {
199
+ removed = true;
200
+ return false;
201
+ }
202
+ return true;
203
+ });
204
+
205
+ this.validators = this.validators.filter((p) => {
206
+ if (p.name === name) {
207
+ removed = true;
208
+ return false;
209
+ }
210
+ return true;
211
+ });
212
+
213
+ return removed;
214
+ }
215
+
216
+ /**
217
+ * Get all detection plugins
218
+ */
219
+ getDetectors(): DetectionPlugin[] {
220
+ return this.detectors;
221
+ }
222
+
223
+ /**
224
+ * Get all transformation plugins
225
+ */
226
+ getTransformers(): TransformationPlugin[] {
227
+ return this.transformers;
228
+ }
229
+
230
+ /**
231
+ * Get all optimizer plugins
232
+ */
233
+ getOptimizers(): OptimizerPlugin[] {
234
+ return this.optimizers;
235
+ }
236
+
237
+ /**
238
+ * Get all validator plugins
239
+ */
240
+ getValidators(): ValidatorPlugin[] {
241
+ return this.validators;
242
+ }
243
+
244
+ /**
245
+ * Initialize all plugins
246
+ */
247
+ async initializeAll(config: CompilerConfig): Promise<void> {
248
+ const allPlugins = [
249
+ ...this.detectors,
250
+ ...this.transformers,
251
+ ...this.optimizers,
252
+ ...this.validators,
253
+ ];
254
+
255
+ for (const plugin of allPlugins) {
256
+ if (plugin.initialize) {
257
+ await plugin.initialize(config);
258
+ }
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Dispose all plugins
264
+ */
265
+ async disposeAll(): Promise<void> {
266
+ const allPlugins = [
267
+ ...this.detectors,
268
+ ...this.transformers,
269
+ ...this.optimizers,
270
+ ...this.validators,
271
+ ];
272
+
273
+ for (const plugin of allPlugins) {
274
+ if (plugin.dispose) {
275
+ await plugin.dispose();
276
+ }
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Type guards
282
+ */
283
+ private isDetectionPlugin(plugin: CompilerPlugin): plugin is DetectionPlugin {
284
+ return 'detect' in plugin && 'patterns' in plugin;
285
+ }
286
+
287
+ private isTransformationPlugin(plugin: CompilerPlugin): plugin is TransformationPlugin {
288
+ return 'getVisitor' in plugin && 'getMetadata' in plugin && 'reset' in plugin;
289
+ }
290
+
291
+ private isOptimizerPlugin(plugin: CompilerPlugin): plugin is OptimizerPlugin {
292
+ return 'optimize' in plugin;
293
+ }
294
+
295
+ private isValidatorPlugin(plugin: CompilerPlugin): plugin is ValidatorPlugin {
296
+ return 'validate' in plugin;
297
+ }
298
+ }
299
+
300
+ /**
301
+ * Utility function to create a simple transformation plugin
302
+ */
303
+ export function createTransformPlugin(config: {
304
+ name: string;
305
+ version: string;
306
+ priority?: number;
307
+ visitor: BabelVisitor;
308
+ getMetadata?: () => Partial<TransformMetadata>;
309
+ }): TransformationPlugin {
310
+ let transformCount = 0;
311
+
312
+ return {
313
+ name: config.name,
314
+ version: config.version,
315
+ priority: config.priority || 50,
316
+
317
+ getVisitor() {
318
+ return config.visitor;
319
+ },
320
+
321
+ getMetadata() {
322
+ return config.getMetadata ? config.getMetadata() : { loopCount: transformCount };
323
+ },
324
+
325
+ reset() {
326
+ transformCount = 0;
327
+ },
328
+ };
329
+ }
330
+
@@ -1,11 +1,10 @@
1
1
  import * as t from '@babel/types';
2
+ import { isArrayMethod } from './utils.js';
2
3
 
3
4
  /**
4
- * Find LLM call expression in callback body
5
+ * Find LLM call expression in AST node
5
6
  */
6
- export function findLLMCallExpression(
7
- body: t.BlockStatement | t.Expression
8
- ): t.CallExpression | null {
7
+ export function findLLMCallExpression(body: t.Node): t.CallExpression | null {
9
8
  let found: t.CallExpression | null = null;
10
9
 
11
10
  const visit = (node: t.Node) => {
@@ -42,9 +41,6 @@ export function findLLMCallExpression(
42
41
  */
43
42
  export function getArrayMethodName(node: t.CallExpression): string | null {
44
43
  const arrayMethods = ['map', 'forEach', 'filter', 'reduce', 'find', 'some', 'every', 'flatMap'];
45
-
46
- const { isArrayMethod } = require('./utils.js');
47
-
48
44
  for (const method of arrayMethods) {
49
45
  if (isArrayMethod(node, method)) {
50
46
  return method;
@@ -12,8 +12,13 @@ import type { TransformResult, CompilerConfig, TransformMetadata } from '../type
12
12
  import { DEFAULT_COMPILER_CONFIG } from '../types.js';
13
13
  import { TransformationError } from '../runtime/errors.js';
14
14
  import { resetIdCounter } from '../runtime/context.js';
15
+ import type { ICompiler } from '../types/compiler-interface.js';
15
16
 
16
- export class ATPCompiler {
17
+ /**
18
+ * ATP Compiler - Standard compiler for transforming code to support resumability
19
+ * Implements ICompiler interface for consistency and dependency injection support
20
+ */
21
+ export class ATPCompiler implements ICompiler {
17
22
  private config: CompilerConfig;
18
23
  private detector: AsyncIterationDetector;
19
24
  private loopTransformer: LoopTransformer;
@@ -144,6 +149,21 @@ export class ATPCompiler {
144
149
  t.isIdentifier(callee.property, { name: 'allSettled' })
145
150
  );
146
151
  }
152
+
153
+ /**
154
+ * Get the compiler type identifier (ICompiler interface requirement)
155
+ */
156
+ getType(): string {
157
+ return 'ATPCompiler';
158
+ }
159
+
160
+ /**
161
+ * Get cache statistics (ICompiler interface requirement)
162
+ * ATPCompiler doesn't cache ASTs, so returns null
163
+ */
164
+ getCacheStats() {
165
+ return null;
166
+ }
147
167
  }
148
168
 
149
169
  export * from './detector.js';
@@ -1,8 +1,9 @@
1
1
  import * as t from '@babel/types';
2
2
  import { generateUniqueId } from '../runtime/context.js';
3
- import { containsAwait } from './utils.js';
3
+ import { containsAwait, extractForOfParamName } from './utils.js';
4
4
  import { BatchOptimizer } from './batch-optimizer.js';
5
5
  import { BatchParallelDetector } from './batch-detector.js';
6
+ import { findLLMCallExpression } from './array-transformer-utils.js';
6
7
 
7
8
  export class LoopTransformer {
8
9
  private transformCount = 0;
@@ -46,27 +47,10 @@ export class LoopTransformer {
46
47
  */
47
48
  private transformForOfToBatch(path: any, node: t.ForOfStatement): boolean {
48
49
  const loopId = generateUniqueId('for_of_batch');
49
- const left = node.left;
50
50
  const right = node.right;
51
+ const paramName = extractForOfParamName(node.left);
51
52
 
52
- let paramName: string;
53
- if (t.isVariableDeclaration(left)) {
54
- const id = left.declarations[0]?.id;
55
- paramName = t.isIdentifier(id) ? id.name : 'item';
56
- } else if (t.isIdentifier(left)) {
57
- paramName = left.name;
58
- } else {
59
- paramName = 'item';
60
- }
61
-
62
- const bodyStatements = t.isBlockStatement(node.body) ? node.body.body : [node.body];
63
- const callback = t.arrowFunctionExpression(
64
- [t.identifier(paramName)],
65
- t.blockStatement(bodyStatements),
66
- true
67
- );
68
-
69
- const llmCall = this.findLLMCallInBody(node.body);
53
+ const llmCall = findLLMCallExpression(node.body);
70
54
  if (!llmCall) {
71
55
  return this.transformForOfToSequential(path, node);
72
56
  }
@@ -109,18 +93,8 @@ export class LoopTransformer {
109
93
  */
110
94
  private transformForOfToSequential(path: any, node: t.ForOfStatement): boolean {
111
95
  const loopId = generateUniqueId('for_of');
112
- const left = node.left;
113
96
  const right = node.right;
114
-
115
- let paramName: string;
116
- if (t.isVariableDeclaration(left)) {
117
- const id = left.declarations[0]?.id;
118
- paramName = t.isIdentifier(id) ? id.name : 'item';
119
- } else if (t.isIdentifier(left)) {
120
- paramName = left.name;
121
- } else {
122
- paramName = 'item';
123
- }
97
+ const paramName = extractForOfParamName(node.left);
124
98
 
125
99
  const bodyStatements = t.isBlockStatement(node.body) ? node.body.body : [node.body];
126
100
 
@@ -142,41 +116,6 @@ export class LoopTransformer {
142
116
  return true;
143
117
  }
144
118
 
145
- /**
146
- * Find LLM call in loop body
147
- */
148
- private findLLMCallInBody(body: t.Statement | t.BlockStatement): t.CallExpression | null {
149
- let found: t.CallExpression | null = null;
150
-
151
- const visit = (node: t.Node) => {
152
- if (found) return;
153
-
154
- if (t.isAwaitExpression(node) && t.isCallExpression(node.argument)) {
155
- const call = node.argument;
156
- if (t.isMemberExpression(call.callee)) {
157
- found = call;
158
- return;
159
- }
160
- }
161
-
162
- Object.keys(node).forEach((key) => {
163
- const value = (node as any)[key];
164
- if (Array.isArray(value)) {
165
- value.forEach((item) => {
166
- if (item && typeof item === 'object' && item.type) {
167
- visit(item);
168
- }
169
- });
170
- } else if (value && typeof value === 'object' && value.type) {
171
- visit(value);
172
- }
173
- });
174
- };
175
-
176
- visit(body);
177
- return found;
178
- }
179
-
180
119
  transformWhileLoop(path: any): boolean {
181
120
  const node = path.node as t.WhileStatement;
182
121
 
@@ -145,3 +145,17 @@ export function isArrayMethod(node: t.Node, methodName: string): boolean {
145
145
 
146
146
  return t.isIdentifier(callee.property) && callee.property.name === methodName;
147
147
  }
148
+
149
+ /**
150
+ * Extract parameter name from ForOfStatement left side
151
+ */
152
+ export function extractForOfParamName(left: t.VariableDeclaration | t.LVal): string {
153
+ if (t.isVariableDeclaration(left)) {
154
+ const id = left.declarations[0]?.id;
155
+ return t.isIdentifier(id) ? id.name : 'item';
156
+ } else if (t.isIdentifier(left)) {
157
+ return left.name;
158
+ } else {
159
+ return 'item';
160
+ }
161
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Core compiler interface for ATP
3
+ * All ATP compilers must implement this interface to ensure consistency
4
+ */
5
+
6
+ import type { DetectionResult, TransformResult } from '../types.js';
7
+
8
+ /**
9
+ * ICompiler - The core interface that all ATP compilers must implement
10
+ *
11
+ * This interface defines the contract for any compiler in the ATP system,
12
+ * enabling dependency injection and easy extensibility.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * class MyCustomCompiler implements ICompiler {
17
+ * detect(code: string): DetectionResult {
18
+ * // Detection logic
19
+ * }
20
+ *
21
+ * transform(code: string): TransformResult {
22
+ * // Transformation logic
23
+ * }
24
+ *
25
+ * getType(): string {
26
+ * return 'MyCustomCompiler';
27
+ * }
28
+ * }
29
+ * ```
30
+ */
31
+ export interface ICompiler {
32
+ /**
33
+ * Detect if code needs transformation and what patterns it contains
34
+ * Can be synchronous or asynchronous
35
+ */
36
+ detect(code: string): DetectionResult | Promise<DetectionResult>;
37
+
38
+ /**
39
+ * Transform the code based on detected patterns
40
+ * Can be synchronous or asynchronous
41
+ */
42
+ transform(code: string): TransformResult | Promise<TransformResult>;
43
+
44
+ /**
45
+ * Get the compiler type identifier
46
+ */
47
+ getType(): string;
48
+
49
+ /**
50
+ * Get cache statistics (optional)
51
+ * Useful for performance monitoring and debugging
52
+ */
53
+ getCacheStats?(): CacheStats | null;
54
+ }
55
+
56
+ /**
57
+ * Cache statistics structure
58
+ */
59
+ export interface CacheStats {
60
+ size: number;
61
+ enabled: boolean;
62
+ }
63
+
64
+ /**
65
+ * Type guard to check if an object implements ICompiler
66
+ */
67
+ export function isCompiler(obj: unknown): obj is ICompiler {
68
+ return (
69
+ typeof obj === 'object' &&
70
+ obj !== null &&
71
+ 'detect' in obj &&
72
+ 'transform' in obj &&
73
+ 'getType' in obj &&
74
+ typeof (obj as any).detect === 'function' &&
75
+ typeof (obj as any).transform === 'function' &&
76
+ typeof (obj as any).getType === 'function'
77
+ );
78
+ }
79
+