@mondaydotcomorg/atp-compiler 0.17.14
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.
- package/README.md +382 -0
- package/__tests__/integration/all-array-methods-native.test.ts +321 -0
- package/__tests__/integration/all-callback-types.test.ts +406 -0
- package/__tests__/integration/comprehensive-edge-cases.test.ts +701 -0
- package/__tests__/integration/native-behavior-verification.test.ts +340 -0
- package/__tests__/integration/semantic-correctness.test.ts +354 -0
- package/__tests__/integration/threshold-tests.test.ts +529 -0
- package/__tests__/unit/batch-optimizer.test.ts +253 -0
- package/__tests__/unit/checkpoint-manager.test.ts +145 -0
- package/__tests__/unit/detector.test.ts +346 -0
- package/dist/atp-compiler/src/index.d.ts +6 -0
- package/dist/atp-compiler/src/index.d.ts.map +1 -0
- package/dist/atp-compiler/src/index.js +6 -0
- package/dist/atp-compiler/src/index.js.map +1 -0
- package/dist/atp-compiler/src/runtime/batch-parallel.d.ts +3 -0
- package/dist/atp-compiler/src/runtime/batch-parallel.d.ts.map +1 -0
- package/dist/atp-compiler/src/runtime/batch-parallel.js +13 -0
- package/dist/atp-compiler/src/runtime/batch-parallel.js.map +1 -0
- package/dist/atp-compiler/src/runtime/checkpoint-manager.d.ts +19 -0
- package/dist/atp-compiler/src/runtime/checkpoint-manager.d.ts.map +1 -0
- package/dist/atp-compiler/src/runtime/checkpoint-manager.js +81 -0
- package/dist/atp-compiler/src/runtime/checkpoint-manager.js.map +1 -0
- package/dist/atp-compiler/src/runtime/context.d.ts +8 -0
- package/dist/atp-compiler/src/runtime/context.d.ts.map +1 -0
- package/dist/atp-compiler/src/runtime/context.js +25 -0
- package/dist/atp-compiler/src/runtime/context.js.map +1 -0
- package/dist/atp-compiler/src/runtime/errors.d.ts +38 -0
- package/dist/atp-compiler/src/runtime/errors.d.ts.map +1 -0
- package/dist/atp-compiler/src/runtime/errors.js +61 -0
- package/dist/atp-compiler/src/runtime/errors.js.map +1 -0
- package/dist/atp-compiler/src/runtime/index.d.ts +16 -0
- package/dist/atp-compiler/src/runtime/index.d.ts.map +1 -0
- package/dist/atp-compiler/src/runtime/index.js +20 -0
- package/dist/atp-compiler/src/runtime/index.js.map +1 -0
- package/dist/atp-compiler/src/runtime/resumable-arrays.d.ts +9 -0
- package/dist/atp-compiler/src/runtime/resumable-arrays.d.ts.map +1 -0
- package/dist/atp-compiler/src/runtime/resumable-arrays.js +179 -0
- package/dist/atp-compiler/src/runtime/resumable-arrays.js.map +1 -0
- package/dist/atp-compiler/src/runtime/resumable-loops.d.ts +4 -0
- package/dist/atp-compiler/src/runtime/resumable-loops.d.ts.map +1 -0
- package/dist/atp-compiler/src/runtime/resumable-loops.js +61 -0
- package/dist/atp-compiler/src/runtime/resumable-loops.js.map +1 -0
- package/dist/atp-compiler/src/runtime/resumable-parallel.d.ts +3 -0
- package/dist/atp-compiler/src/runtime/resumable-parallel.d.ts.map +1 -0
- package/dist/atp-compiler/src/runtime/resumable-parallel.js +44 -0
- package/dist/atp-compiler/src/runtime/resumable-parallel.js.map +1 -0
- package/dist/atp-compiler/src/transformer/array-transformer-batch.d.ts +13 -0
- package/dist/atp-compiler/src/transformer/array-transformer-batch.d.ts.map +1 -0
- package/dist/atp-compiler/src/transformer/array-transformer-batch.js +55 -0
- package/dist/atp-compiler/src/transformer/array-transformer-batch.js.map +1 -0
- package/dist/atp-compiler/src/transformer/array-transformer-sequential.d.ts +6 -0
- package/dist/atp-compiler/src/transformer/array-transformer-sequential.d.ts.map +1 -0
- package/dist/atp-compiler/src/transformer/array-transformer-sequential.js +23 -0
- package/dist/atp-compiler/src/transformer/array-transformer-sequential.js.map +1 -0
- package/dist/atp-compiler/src/transformer/array-transformer-utils.d.ts +18 -0
- package/dist/atp-compiler/src/transformer/array-transformer-utils.d.ts.map +1 -0
- package/dist/atp-compiler/src/transformer/array-transformer-utils.js +69 -0
- package/dist/atp-compiler/src/transformer/array-transformer-utils.js.map +1 -0
- package/dist/atp-compiler/src/transformer/array-transformer-wrappers.d.ts +26 -0
- package/dist/atp-compiler/src/transformer/array-transformer-wrappers.d.ts.map +1 -0
- package/dist/atp-compiler/src/transformer/array-transformer-wrappers.js +88 -0
- package/dist/atp-compiler/src/transformer/array-transformer-wrappers.js.map +1 -0
- package/dist/atp-compiler/src/transformer/array-transformer.d.ts +12 -0
- package/dist/atp-compiler/src/transformer/array-transformer.d.ts.map +1 -0
- package/dist/atp-compiler/src/transformer/array-transformer.js +47 -0
- package/dist/atp-compiler/src/transformer/array-transformer.js.map +1 -0
- package/dist/atp-compiler/src/transformer/batch-detector.d.ts +16 -0
- package/dist/atp-compiler/src/transformer/batch-detector.d.ts.map +1 -0
- package/dist/atp-compiler/src/transformer/batch-detector.js +131 -0
- package/dist/atp-compiler/src/transformer/batch-detector.js.map +1 -0
- package/dist/atp-compiler/src/transformer/batch-optimizer.d.ts +27 -0
- package/dist/atp-compiler/src/transformer/batch-optimizer.d.ts.map +1 -0
- package/dist/atp-compiler/src/transformer/batch-optimizer.js +244 -0
- package/dist/atp-compiler/src/transformer/batch-optimizer.js.map +1 -0
- package/dist/atp-compiler/src/transformer/detector.d.ts +9 -0
- package/dist/atp-compiler/src/transformer/detector.d.ts.map +1 -0
- package/dist/atp-compiler/src/transformer/detector.js +141 -0
- package/dist/atp-compiler/src/transformer/detector.js.map +1 -0
- package/dist/atp-compiler/src/transformer/index.d.ts +22 -0
- package/dist/atp-compiler/src/transformer/index.d.ts.map +1 -0
- package/dist/atp-compiler/src/transformer/index.js +132 -0
- package/dist/atp-compiler/src/transformer/index.js.map +1 -0
- package/dist/atp-compiler/src/transformer/loop-transformer.d.ts +25 -0
- package/dist/atp-compiler/src/transformer/loop-transformer.d.ts.map +1 -0
- package/dist/atp-compiler/src/transformer/loop-transformer.js +193 -0
- package/dist/atp-compiler/src/transformer/loop-transformer.js.map +1 -0
- package/dist/atp-compiler/src/transformer/promise-transformer.d.ts +17 -0
- package/dist/atp-compiler/src/transformer/promise-transformer.d.ts.map +1 -0
- package/dist/atp-compiler/src/transformer/promise-transformer.js +132 -0
- package/dist/atp-compiler/src/transformer/promise-transformer.js.map +1 -0
- package/dist/atp-compiler/src/transformer/utils.d.ts +15 -0
- package/dist/atp-compiler/src/transformer/utils.d.ts.map +1 -0
- package/dist/atp-compiler/src/transformer/utils.js +118 -0
- package/dist/atp-compiler/src/transformer/utils.js.map +1 -0
- package/dist/atp-compiler/src/types.d.ts +57 -0
- package/dist/atp-compiler/src/types.d.ts.map +1 -0
- package/dist/atp-compiler/src/types.js +23 -0
- package/dist/atp-compiler/src/types.js.map +1 -0
- package/dist/protocol/src/auth.d.ts +173 -0
- package/dist/protocol/src/auth.d.ts.map +1 -0
- package/dist/protocol/src/auth.js +202 -0
- package/dist/protocol/src/auth.js.map +1 -0
- package/dist/protocol/src/index.d.ts +7 -0
- package/dist/protocol/src/index.d.ts.map +1 -0
- package/dist/protocol/src/index.js +7 -0
- package/dist/protocol/src/index.js.map +1 -0
- package/dist/protocol/src/oauth.d.ts +63 -0
- package/dist/protocol/src/oauth.d.ts.map +1 -0
- package/dist/protocol/src/oauth.js +5 -0
- package/dist/protocol/src/oauth.js.map +1 -0
- package/dist/protocol/src/providers.d.ts +167 -0
- package/dist/protocol/src/providers.d.ts.map +1 -0
- package/dist/protocol/src/providers.js +33 -0
- package/dist/protocol/src/providers.js.map +1 -0
- package/dist/protocol/src/schemas.d.ts +6 -0
- package/dist/protocol/src/schemas.d.ts.map +1 -0
- package/dist/protocol/src/schemas.js +51 -0
- package/dist/protocol/src/schemas.js.map +1 -0
- package/dist/protocol/src/types.d.ts +489 -0
- package/dist/protocol/src/types.d.ts.map +1 -0
- package/dist/protocol/src/types.js +88 -0
- package/dist/protocol/src/types.js.map +1 -0
- package/dist/protocol/src/validation.d.ts +76 -0
- package/dist/protocol/src/validation.d.ts.map +1 -0
- package/dist/protocol/src/validation.js +129 -0
- package/dist/protocol/src/validation.js.map +1 -0
- package/dist/provenance/src/ast/instrumentor.d.ts +37 -0
- package/dist/provenance/src/ast/instrumentor.d.ts.map +1 -0
- package/dist/provenance/src/ast/instrumentor.js +299 -0
- package/dist/provenance/src/ast/instrumentor.js.map +1 -0
- package/dist/provenance/src/index.d.ts +7 -0
- package/dist/provenance/src/index.d.ts.map +1 -0
- package/dist/provenance/src/index.js +7 -0
- package/dist/provenance/src/index.js.map +1 -0
- package/dist/provenance/src/policies/engine.d.ts +71 -0
- package/dist/provenance/src/policies/engine.d.ts.map +1 -0
- package/dist/provenance/src/policies/engine.js +433 -0
- package/dist/provenance/src/policies/engine.js.map +1 -0
- package/dist/provenance/src/registry.d.ts +94 -0
- package/dist/provenance/src/registry.d.ts.map +1 -0
- package/dist/provenance/src/registry.js +445 -0
- package/dist/provenance/src/registry.js.map +1 -0
- package/dist/provenance/src/tokens.d.ts +49 -0
- package/dist/provenance/src/tokens.d.ts.map +1 -0
- package/dist/provenance/src/tokens.js +239 -0
- package/dist/provenance/src/tokens.js.map +1 -0
- package/dist/provenance/src/types.d.ts +150 -0
- package/dist/provenance/src/types.d.ts.map +1 -0
- package/dist/provenance/src/types.js +47 -0
- package/dist/provenance/src/types.js.map +1 -0
- package/dist/runtime/src/approval/handler.d.ts +12 -0
- package/dist/runtime/src/approval/handler.d.ts.map +1 -0
- package/dist/runtime/src/approval/handler.js +17 -0
- package/dist/runtime/src/approval/handler.js.map +1 -0
- package/dist/runtime/src/approval/index.d.ts +17 -0
- package/dist/runtime/src/approval/index.d.ts.map +1 -0
- package/dist/runtime/src/approval/index.js +94 -0
- package/dist/runtime/src/approval/index.js.map +1 -0
- package/dist/runtime/src/approval/types.d.ts +21 -0
- package/dist/runtime/src/approval/types.d.ts.map +1 -0
- package/dist/runtime/src/approval/types.js +5 -0
- package/dist/runtime/src/approval/types.js.map +1 -0
- package/dist/runtime/src/cache/backends.d.ts +39 -0
- package/dist/runtime/src/cache/backends.d.ts.map +1 -0
- package/dist/runtime/src/cache/backends.js +167 -0
- package/dist/runtime/src/cache/backends.js.map +1 -0
- package/dist/runtime/src/cache/index.d.ts +32 -0
- package/dist/runtime/src/cache/index.d.ts.map +1 -0
- package/dist/runtime/src/cache/index.js +103 -0
- package/dist/runtime/src/cache/index.js.map +1 -0
- package/dist/runtime/src/cache/types.d.ts +20 -0
- package/dist/runtime/src/cache/types.d.ts.map +1 -0
- package/dist/runtime/src/cache/types.js +2 -0
- package/dist/runtime/src/cache/types.js.map +1 -0
- package/dist/runtime/src/embedding/index.d.ts +39 -0
- package/dist/runtime/src/embedding/index.d.ts.map +1 -0
- package/dist/runtime/src/embedding/index.js +162 -0
- package/dist/runtime/src/embedding/index.js.map +1 -0
- package/dist/runtime/src/embedding/types.d.ts +28 -0
- package/dist/runtime/src/embedding/types.d.ts.map +1 -0
- package/dist/runtime/src/embedding/types.js +5 -0
- package/dist/runtime/src/embedding/types.js.map +1 -0
- package/dist/runtime/src/embedding/utils.d.ts +11 -0
- package/dist/runtime/src/embedding/utils.d.ts.map +1 -0
- package/dist/runtime/src/embedding/utils.js +30 -0
- package/dist/runtime/src/embedding/utils.js.map +1 -0
- package/dist/runtime/src/embedding/vector-store.d.ts +64 -0
- package/dist/runtime/src/embedding/vector-store.d.ts.map +1 -0
- package/dist/runtime/src/embedding/vector-store.js +142 -0
- package/dist/runtime/src/embedding/vector-store.js.map +1 -0
- package/dist/runtime/src/index.d.ts +18 -0
- package/dist/runtime/src/index.d.ts.map +1 -0
- package/dist/runtime/src/index.js +17 -0
- package/dist/runtime/src/index.js.map +1 -0
- package/dist/runtime/src/llm/callback.d.ts +13 -0
- package/dist/runtime/src/llm/callback.d.ts.map +1 -0
- package/dist/runtime/src/llm/callback.js +19 -0
- package/dist/runtime/src/llm/callback.js.map +1 -0
- package/dist/runtime/src/llm/index.d.ts +29 -0
- package/dist/runtime/src/llm/index.d.ts.map +1 -0
- package/dist/runtime/src/llm/index.js +118 -0
- package/dist/runtime/src/llm/index.js.map +1 -0
- package/dist/runtime/src/llm/replay.d.ts +47 -0
- package/dist/runtime/src/llm/replay.d.ts.map +1 -0
- package/dist/runtime/src/llm/replay.js +114 -0
- package/dist/runtime/src/llm/replay.js.map +1 -0
- package/dist/runtime/src/llm/types.d.ts +24 -0
- package/dist/runtime/src/llm/types.d.ts.map +1 -0
- package/dist/runtime/src/llm/types.js +2 -0
- package/dist/runtime/src/llm/types.js.map +1 -0
- package/dist/runtime/src/log/index.d.ts +12 -0
- package/dist/runtime/src/log/index.d.ts.map +1 -0
- package/dist/runtime/src/log/index.js +166 -0
- package/dist/runtime/src/log/index.js.map +1 -0
- package/dist/runtime/src/log/types.d.ts +19 -0
- package/dist/runtime/src/log/types.d.ts.map +1 -0
- package/dist/runtime/src/log/types.js +5 -0
- package/dist/runtime/src/log/types.js.map +1 -0
- package/dist/runtime/src/metadata/decorators.d.ts +27 -0
- package/dist/runtime/src/metadata/decorators.d.ts.map +1 -0
- package/dist/runtime/src/metadata/decorators.js +38 -0
- package/dist/runtime/src/metadata/decorators.js.map +1 -0
- package/dist/runtime/src/metadata/generated.d.ts +18 -0
- package/dist/runtime/src/metadata/generated.d.ts.map +1 -0
- package/dist/runtime/src/metadata/generated.js +290 -0
- package/dist/runtime/src/metadata/generated.js.map +1 -0
- package/dist/runtime/src/metadata/index.d.ts +11 -0
- package/dist/runtime/src/metadata/index.d.ts.map +1 -0
- package/dist/runtime/src/metadata/index.js +45 -0
- package/dist/runtime/src/metadata/index.js.map +1 -0
- package/dist/runtime/src/metadata/types.d.ts +22 -0
- package/dist/runtime/src/metadata/types.d.ts.map +1 -0
- package/dist/runtime/src/metadata/types.js +6 -0
- package/dist/runtime/src/metadata/types.js.map +1 -0
- package/dist/runtime/src/pause/index.d.ts +11 -0
- package/dist/runtime/src/pause/index.d.ts.map +1 -0
- package/dist/runtime/src/pause/index.js +15 -0
- package/dist/runtime/src/pause/index.js.map +1 -0
- package/dist/runtime/src/pause/types.d.ts +46 -0
- package/dist/runtime/src/pause/types.d.ts.map +1 -0
- package/dist/runtime/src/pause/types.js +57 -0
- package/dist/runtime/src/pause/types.js.map +1 -0
- package/dist/runtime/src/progress/index.d.ts +19 -0
- package/dist/runtime/src/progress/index.d.ts.map +1 -0
- package/dist/runtime/src/progress/index.js +61 -0
- package/dist/runtime/src/progress/index.js.map +1 -0
- package/dist/runtime/src/progress/types.d.ts +7 -0
- package/dist/runtime/src/progress/types.d.ts.map +1 -0
- package/dist/runtime/src/progress/types.js +2 -0
- package/dist/runtime/src/progress/types.js.map +1 -0
- package/dist/runtime/src/registry.d.ts +16 -0
- package/dist/runtime/src/registry.d.ts.map +1 -0
- package/dist/runtime/src/registry.js +16 -0
- package/dist/runtime/src/registry.js.map +1 -0
- package/dist/runtime/src/utils.d.ts +11 -0
- package/dist/runtime/src/utils.d.ts.map +1 -0
- package/dist/runtime/src/utils.js +31 -0
- package/dist/runtime/src/utils.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/jest.config.js +29 -0
- package/package.json +56 -0
- package/project.json +31 -0
- package/src/index.ts +6 -0
- package/src/runtime/batch-parallel.ts +22 -0
- package/src/runtime/checkpoint-manager.ts +105 -0
- package/src/runtime/context.ts +33 -0
- package/src/runtime/errors.ts +79 -0
- package/src/runtime/index.ts +35 -0
- package/src/runtime/resumable-arrays.ts +253 -0
- package/src/runtime/resumable-loops.ts +93 -0
- package/src/runtime/resumable-parallel.ts +57 -0
- package/src/transformer/array-transformer-batch.ts +86 -0
- package/src/transformer/array-transformer-sequential.ts +38 -0
- package/src/transformer/array-transformer-utils.ts +80 -0
- package/src/transformer/array-transformer-wrappers.ts +165 -0
- package/src/transformer/array-transformer.ts +76 -0
- package/src/transformer/batch-detector.ts +166 -0
- package/src/transformer/batch-optimizer.ts +320 -0
- package/src/transformer/detector.ts +171 -0
- package/src/transformer/index.ts +155 -0
- package/src/transformer/loop-transformer.ts +285 -0
- package/src/transformer/promise-transformer.ts +194 -0
- package/src/transformer/utils.ts +147 -0
- package/src/types.ts +101 -0
- package/tsconfig.json +12 -0
|
@@ -0,0 +1,701 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* COMPREHENSIVE EDGE CASE TESTS
|
|
3
|
+
*
|
|
4
|
+
* Tests ALL array methods, loops, and complex scenarios
|
|
5
|
+
* to ensure batch optimization is production-ready
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, test, expect, beforeEach } from '@jest/globals';
|
|
9
|
+
import { ATPCompiler } from '../../src/transformer/index';
|
|
10
|
+
|
|
11
|
+
describe('Comprehensive Edge Case Tests', () => {
|
|
12
|
+
let compiler: ATPCompiler;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
compiler = new ATPCompiler({ enableBatchParallel: true });
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('Array Methods - ALL variations', () => {
|
|
19
|
+
describe('map()', () => {
|
|
20
|
+
test('✅ Simple map - should batch', () => {
|
|
21
|
+
const code = `
|
|
22
|
+
const items = [1, 2, 3];
|
|
23
|
+
const results = await items.map(async (item) => {
|
|
24
|
+
return await atp.llm.call({ prompt: item });
|
|
25
|
+
});
|
|
26
|
+
`;
|
|
27
|
+
const result = compiler.transform(code);
|
|
28
|
+
expect(result.transformed).toBe(true);
|
|
29
|
+
expect(result.code).toContain('batchParallel');
|
|
30
|
+
expect(result.metadata.arrayMethodCount).toBeGreaterThan(0);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('✅ Map with arrow expression - should batch', () => {
|
|
34
|
+
const code = `
|
|
35
|
+
const results = await items.map(async (x) => await atp.llm.call({ prompt: x }));
|
|
36
|
+
`;
|
|
37
|
+
const result = compiler.transform(code);
|
|
38
|
+
expect(result.transformed).toBe(true);
|
|
39
|
+
expect(result.code).toContain('batchParallel');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('❌ Map with conditional - should NOT batch', () => {
|
|
43
|
+
const code = `
|
|
44
|
+
const results = await items.map(async (item) => {
|
|
45
|
+
if (item > 5) {
|
|
46
|
+
return await atp.llm.call({ prompt: item });
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
`;
|
|
50
|
+
const result = compiler.transform(code);
|
|
51
|
+
expect(result.transformed).toBe(true);
|
|
52
|
+
expect(result.code).toContain('resumableMap');
|
|
53
|
+
expect(result.code).not.toContain('batchParallel');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('❌ Map with try-catch - should NOT batch', () => {
|
|
57
|
+
const code = `
|
|
58
|
+
const results = await items.map(async (item) => {
|
|
59
|
+
try {
|
|
60
|
+
return await atp.llm.call({ prompt: item });
|
|
61
|
+
} catch (e) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
`;
|
|
66
|
+
const result = compiler.transform(code);
|
|
67
|
+
expect(result.code).toContain('resumableMap');
|
|
68
|
+
expect(result.code).not.toContain('batchParallel');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('❌ Map with sequential dependencies - should NOT batch', () => {
|
|
72
|
+
const code = `
|
|
73
|
+
const results = await items.map(async (item) => {
|
|
74
|
+
const first = await atp.llm.call({ prompt: 'A' + item });
|
|
75
|
+
const second = await atp.llm.call({ prompt: first });
|
|
76
|
+
return second;
|
|
77
|
+
});
|
|
78
|
+
`;
|
|
79
|
+
const result = compiler.transform(code);
|
|
80
|
+
expect(result.code).toContain('resumableMap');
|
|
81
|
+
expect(result.code).not.toContain('batchParallel');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('✨ Map with nested loop - outer sequential, inner batched!', () => {
|
|
85
|
+
const code = `
|
|
86
|
+
const items = [{subs: ['a', 'b']}, {subs: ['c', 'd']}];
|
|
87
|
+
const results = await items.map(async (item) => {
|
|
88
|
+
for (const sub of item.subs) {
|
|
89
|
+
await atp.llm.call({ prompt: sub });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
`;
|
|
93
|
+
const result = compiler.transform(code);
|
|
94
|
+
expect(result.transformed).toBe(true);
|
|
95
|
+
// Outer map uses resumableMap (has nested loop)
|
|
96
|
+
expect(result.code).toContain('resumableMap');
|
|
97
|
+
// SMART: Inner for...of is simple, so IT gets batched!
|
|
98
|
+
expect(result.code).toContain('batchParallel');
|
|
99
|
+
// This is actually optimal - inner batching gives performance boost
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('forEach()', () => {
|
|
104
|
+
test('✅ Simple forEach - should batch', () => {
|
|
105
|
+
const code = `
|
|
106
|
+
await items.forEach(async (item) => {
|
|
107
|
+
await atp.llm.call({ prompt: item });
|
|
108
|
+
});
|
|
109
|
+
`;
|
|
110
|
+
const result = compiler.transform(code);
|
|
111
|
+
expect(result.transformed).toBe(true);
|
|
112
|
+
expect(result.code).toContain('batchParallel');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test('❌ forEach with conditional - should NOT batch', () => {
|
|
116
|
+
const code = `
|
|
117
|
+
await items.forEach(async (item) => {
|
|
118
|
+
if (item.valid) {
|
|
119
|
+
await atp.llm.call({ prompt: item.text });
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
`;
|
|
123
|
+
const result = compiler.transform(code);
|
|
124
|
+
expect(result.code).toContain('resumableForEach');
|
|
125
|
+
expect(result.code).not.toContain('batchParallel');
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe('filter()', () => {
|
|
130
|
+
test('✅ Simple filter - ACTUALLY BATCHES! (Smart optimization)', () => {
|
|
131
|
+
const code = `
|
|
132
|
+
const valid = await items.filter(async (item) => {
|
|
133
|
+
const result = await atp.llm.call({ prompt: String(item) });
|
|
134
|
+
return result;
|
|
135
|
+
});
|
|
136
|
+
`;
|
|
137
|
+
const result = compiler.transform(code);
|
|
138
|
+
// Filter is SMART enough to batch simple cases!
|
|
139
|
+
expect(result.transformed).toBe(true);
|
|
140
|
+
expect(result.code).toContain('batchParallel');
|
|
141
|
+
// This is actually optimal - filter gets batched when possible
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('❌ filter with conditional - should NOT batch (unknown size)', () => {
|
|
145
|
+
const code = `
|
|
146
|
+
const valid = await items.filter(async (item) => {
|
|
147
|
+
if (item.priority > 5) {
|
|
148
|
+
return await atp.llm.call({ prompt: item });
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
});
|
|
152
|
+
`;
|
|
153
|
+
const result = compiler.transform(code);
|
|
154
|
+
expect(result.code).toContain('resumableFilter');
|
|
155
|
+
expect(result.code).not.toContain('batchParallel');
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe('reduce()', () => {
|
|
160
|
+
test('❌ reduce - should NEVER batch (sequential by nature)', () => {
|
|
161
|
+
const code = `
|
|
162
|
+
const total = await items.reduce(async (acc, item) => {
|
|
163
|
+
const result = await atp.llm.call({ prompt: item });
|
|
164
|
+
return acc + result;
|
|
165
|
+
}, 0);
|
|
166
|
+
`;
|
|
167
|
+
const result = compiler.transform(code);
|
|
168
|
+
expect(result.code).toContain('resumableReduce');
|
|
169
|
+
expect(result.code).not.toContain('batchParallel');
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe('find()', () => {
|
|
174
|
+
test('✅ find simple - DOES batch (no conditionals)', () => {
|
|
175
|
+
const code = `
|
|
176
|
+
const found = await items.find(async (item) => {
|
|
177
|
+
return await atp.llm.call({ prompt: item });
|
|
178
|
+
});
|
|
179
|
+
`;
|
|
180
|
+
const result = compiler.transform(code);
|
|
181
|
+
expect(result.code).toContain('batchParallel');
|
|
182
|
+
expect(result.code).toContain('items.find');
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe('some() / every()', () => {
|
|
187
|
+
test('✅ some simple - DOES batch (no conditionals)', () => {
|
|
188
|
+
const code = `
|
|
189
|
+
const hasValid = await items.some(async (item) => {
|
|
190
|
+
return await atp.llm.call({ prompt: item });
|
|
191
|
+
});
|
|
192
|
+
`;
|
|
193
|
+
const result = compiler.transform(code);
|
|
194
|
+
expect(result.code).toContain('batchParallel');
|
|
195
|
+
expect(result.code).toContain('.some(');
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test('✅ every simple - DOES batch (no conditionals)', () => {
|
|
199
|
+
const code = `
|
|
200
|
+
const allValid = await items.every(async (item) => {
|
|
201
|
+
return await atp.llm.call({ prompt: item });
|
|
202
|
+
});
|
|
203
|
+
`;
|
|
204
|
+
const result = compiler.transform(code);
|
|
205
|
+
expect(result.code).toContain('batchParallel');
|
|
206
|
+
expect(result.code).toContain('.every(');
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
describe('flatMap()', () => {
|
|
211
|
+
test('❌ flatMap - should NOT batch (complex)', () => {
|
|
212
|
+
const code = `
|
|
213
|
+
const flattened = await items.flatMap(async (item) => {
|
|
214
|
+
return await atp.llm.call({ prompt: item });
|
|
215
|
+
});
|
|
216
|
+
`;
|
|
217
|
+
const result = compiler.transform(code);
|
|
218
|
+
expect(result.code).toContain('resumableFlatMap');
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
describe('Loops - ALL variations', () => {
|
|
224
|
+
describe('for...of', () => {
|
|
225
|
+
test('✅ Simple for...of - should batch', () => {
|
|
226
|
+
const code = `
|
|
227
|
+
for (const item of items) {
|
|
228
|
+
await atp.llm.call({ prompt: item });
|
|
229
|
+
}
|
|
230
|
+
`;
|
|
231
|
+
const result = compiler.transform(code);
|
|
232
|
+
expect(result.code).toContain('batchParallel');
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test('❌ for...of with break - should NOT batch', () => {
|
|
236
|
+
const code = `
|
|
237
|
+
for (const item of items) {
|
|
238
|
+
await atp.llm.call({ prompt: item });
|
|
239
|
+
if (item === 'stop') break;
|
|
240
|
+
}
|
|
241
|
+
`;
|
|
242
|
+
const result = compiler.transform(code);
|
|
243
|
+
expect(result.code).toContain('resumableForOf');
|
|
244
|
+
expect(result.code).not.toContain('batchParallel');
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test('❌ for...of with continue - should NOT batch', () => {
|
|
248
|
+
const code = `
|
|
249
|
+
for (const item of items) {
|
|
250
|
+
if (!item.valid) continue;
|
|
251
|
+
await atp.llm.call({ prompt: item });
|
|
252
|
+
}
|
|
253
|
+
`;
|
|
254
|
+
const result = compiler.transform(code);
|
|
255
|
+
expect(result.code).toContain('resumableForOf');
|
|
256
|
+
expect(result.code).not.toContain('batchParallel');
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
test('✅ for...of with conditional - SEQUENTIAL (unknown size, smart batching)', () => {
|
|
260
|
+
const code = `
|
|
261
|
+
for (const item of items) {
|
|
262
|
+
if (item.priority > 5) {
|
|
263
|
+
await atp.llm.call({ prompt: item });
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
`;
|
|
267
|
+
const result = compiler.transform(code);
|
|
268
|
+
// Unknown array size + conditionals → Sequential (conservative)
|
|
269
|
+
expect(result.code).toContain('resumableForOf');
|
|
270
|
+
expect(result.code).not.toContain('batchParallel');
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test('✨ Nested for...of - outer sequential, inner batched!', () => {
|
|
274
|
+
const code = `
|
|
275
|
+
const items = [{children: ['a', 'b']}, {children: ['c', 'd']}];
|
|
276
|
+
for (const outer of items) {
|
|
277
|
+
for (const inner of outer.children) {
|
|
278
|
+
await atp.llm.call({ prompt: inner });
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
`;
|
|
282
|
+
const result = compiler.transform(code);
|
|
283
|
+
expect(result.transformed).toBe(true);
|
|
284
|
+
// Outer loop uses resumableForOf (has nested loop)
|
|
285
|
+
expect(result.code).toContain('resumableForOf');
|
|
286
|
+
// SMART: Inner loop is simple, so IT gets batched!
|
|
287
|
+
expect(result.code).toContain('batchParallel');
|
|
288
|
+
// Optimal - inner loop gets performance boost
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
describe('while', () => {
|
|
293
|
+
test('❌ while - should NEVER batch (dynamic condition)', () => {
|
|
294
|
+
const code = `
|
|
295
|
+
let i = 0;
|
|
296
|
+
while (i < 10) {
|
|
297
|
+
await atp.llm.call({ prompt: i });
|
|
298
|
+
i++;
|
|
299
|
+
}
|
|
300
|
+
`;
|
|
301
|
+
const result = compiler.transform(code);
|
|
302
|
+
expect(result.code).toContain('resumableWhile');
|
|
303
|
+
expect(result.code).not.toContain('batchParallel');
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
describe('for', () => {
|
|
308
|
+
test('❌ for - transforms to resumableForLoop if has await', () => {
|
|
309
|
+
const code = `
|
|
310
|
+
async function process() {
|
|
311
|
+
for (let i = 0; i < 10; i++) {
|
|
312
|
+
await atp.llm.call({ prompt: String(i) });
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
`;
|
|
316
|
+
const result = compiler.transform(code);
|
|
317
|
+
|
|
318
|
+
// Regular for loops with await are transformed
|
|
319
|
+
if (result.transformed) {
|
|
320
|
+
expect(result.code).toContain('resumableForLoop');
|
|
321
|
+
// For loops cannot be batched (dynamic condition)
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
describe('Edge Cases - Data Structures', () => {
|
|
328
|
+
test('Empty array - still detects pattern', () => {
|
|
329
|
+
const code = `
|
|
330
|
+
const results = await [].map(async (item) => {
|
|
331
|
+
return await atp.llm.call({ prompt: item });
|
|
332
|
+
});
|
|
333
|
+
`;
|
|
334
|
+
const result = compiler.transform(code);
|
|
335
|
+
// Even empty arrays get transformed (compiler doesn't know array is empty at compile time)
|
|
336
|
+
expect(result.transformed).toBe(true);
|
|
337
|
+
expect(result.code).toContain('batchParallel');
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
test('Single item array - should batch', () => {
|
|
341
|
+
const code = `
|
|
342
|
+
const results = await [1].map(async (item) => {
|
|
343
|
+
return await atp.llm.call({ prompt: item });
|
|
344
|
+
});
|
|
345
|
+
`;
|
|
346
|
+
const result = compiler.transform(code);
|
|
347
|
+
expect(result.code).toContain('batchParallel');
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
test('Large array literal - should batch', () => {
|
|
351
|
+
const code = `
|
|
352
|
+
const results = await [1,2,3,4,5,6,7,8,9,10].map(async (item) => {
|
|
353
|
+
return await atp.llm.call({ prompt: item });
|
|
354
|
+
});
|
|
355
|
+
`;
|
|
356
|
+
const result = compiler.transform(code);
|
|
357
|
+
expect(result.code).toContain('batchParallel');
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
test('Array variable - should batch', () => {
|
|
361
|
+
const code = `
|
|
362
|
+
const items = getItems();
|
|
363
|
+
const results = await items.map(async (item) => {
|
|
364
|
+
return await atp.llm.call({ prompt: item });
|
|
365
|
+
});
|
|
366
|
+
`;
|
|
367
|
+
const result = compiler.transform(code);
|
|
368
|
+
expect(result.code).toContain('batchParallel');
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
test('Array method chain - should transform', () => {
|
|
372
|
+
const code = `
|
|
373
|
+
const results = await items
|
|
374
|
+
.filter(x => x.valid)
|
|
375
|
+
.map(async (item) => {
|
|
376
|
+
return await atp.llm.call({ prompt: item });
|
|
377
|
+
});
|
|
378
|
+
`;
|
|
379
|
+
const result = compiler.transform(code);
|
|
380
|
+
expect(result.transformed).toBe(true);
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
describe('Complex Scenarios', () => {
|
|
385
|
+
test('Multiple array methods in sequence', () => {
|
|
386
|
+
const code = `
|
|
387
|
+
const step1 = await items.map(async (item) => {
|
|
388
|
+
return await atp.llm.call({ prompt: 'Step1: ' + item });
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
const step2 = await step1.map(async (item) => {
|
|
392
|
+
return await atp.llm.call({ prompt: 'Step2: ' + item });
|
|
393
|
+
});
|
|
394
|
+
`;
|
|
395
|
+
const result = compiler.transform(code);
|
|
396
|
+
expect(result.code).toContain('batchParallel');
|
|
397
|
+
expect(result.metadata.arrayMethodCount).toBe(2);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
test('Array method inside function', () => {
|
|
401
|
+
const code = `
|
|
402
|
+
async function processItems(items) {
|
|
403
|
+
return await items.map(async (item) => {
|
|
404
|
+
return await atp.llm.call({ prompt: item });
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
`;
|
|
408
|
+
const result = compiler.transform(code);
|
|
409
|
+
expect(result.code).toContain('batchParallel');
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
test('Nested array methods - outer simple, inner complex', () => {
|
|
413
|
+
const code = `
|
|
414
|
+
const results = await outerItems.map(async (outer) => {
|
|
415
|
+
return await outer.inner.map(async (inner) => {
|
|
416
|
+
if (inner.valid) {
|
|
417
|
+
return await atp.llm.call({ prompt: inner });
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
`;
|
|
422
|
+
const result = compiler.transform(code);
|
|
423
|
+
expect(result.transformed).toBe(true);
|
|
424
|
+
// Outer can batch, inner cannot
|
|
425
|
+
expect(result.metadata.arrayMethodCount).toBe(2);
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
test('Promise.all inside map - should NOT batch outer', () => {
|
|
429
|
+
const code = `
|
|
430
|
+
const results = await items.map(async (item) => {
|
|
431
|
+
return await Promise.all([
|
|
432
|
+
atp.llm.call({ prompt: 'A' + item }),
|
|
433
|
+
atp.llm.call({ prompt: 'B' + item })
|
|
434
|
+
]);
|
|
435
|
+
});
|
|
436
|
+
`;
|
|
437
|
+
const result = compiler.transform(code);
|
|
438
|
+
// Has Promise.all inside, so can't batch the map
|
|
439
|
+
expect(result.code).toContain('resumableMap');
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
test('Multiple LLM providers', () => {
|
|
443
|
+
const code = `
|
|
444
|
+
const results = await items.map(async (item) => {
|
|
445
|
+
return await atp.llm.call({ prompt: item });
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
const approvals = await items.map(async (item) => {
|
|
449
|
+
return await atp.approval.request({ message: item });
|
|
450
|
+
});
|
|
451
|
+
`;
|
|
452
|
+
const result = compiler.transform(code);
|
|
453
|
+
expect(result.transformed).toBe(true);
|
|
454
|
+
expect(result.metadata.arrayMethodCount).toBe(2);
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
test('Complex payload in LLM call', () => {
|
|
458
|
+
const code = `
|
|
459
|
+
const results = await items.map(async (item) => {
|
|
460
|
+
return await atp.llm.call({
|
|
461
|
+
prompt: item.text,
|
|
462
|
+
model: item.model || 'gpt-4',
|
|
463
|
+
temperature: 0.7,
|
|
464
|
+
maxTokens: 1000,
|
|
465
|
+
metadata: { id: item.id, timestamp: Date.now() }
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
`;
|
|
469
|
+
const result = compiler.transform(code);
|
|
470
|
+
expect(result.code).toContain('batchParallel');
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
test('Destructuring in callback', () => {
|
|
474
|
+
const code = `
|
|
475
|
+
const results = await items.map(async ({ text, priority }) => {
|
|
476
|
+
return await atp.llm.call({ prompt: text });
|
|
477
|
+
});
|
|
478
|
+
`;
|
|
479
|
+
const result = compiler.transform(code);
|
|
480
|
+
expect(result.transformed).toBe(true);
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
test('Index parameter used', () => {
|
|
484
|
+
const code = `
|
|
485
|
+
const results = await items.map(async (item, index) => {
|
|
486
|
+
return await atp.llm.call({ prompt: \`Item \${index}: \${item}\` });
|
|
487
|
+
});
|
|
488
|
+
`;
|
|
489
|
+
const result = compiler.transform(code);
|
|
490
|
+
expect(result.code).toContain('batchParallel');
|
|
491
|
+
});
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
describe('Mixed Simple and Complex Patterns', () => {
|
|
495
|
+
test('Simple map followed by complex map', () => {
|
|
496
|
+
const code = `
|
|
497
|
+
// Simple - should batch
|
|
498
|
+
const step1 = await items.map(async (item) => {
|
|
499
|
+
return await atp.llm.call({ prompt: item });
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
// Complex - should NOT batch
|
|
503
|
+
const step2 = await step1.map(async (item) => {
|
|
504
|
+
if (item.valid) {
|
|
505
|
+
return await atp.llm.call({ prompt: item.text });
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
`;
|
|
509
|
+
const result = compiler.transform(code);
|
|
510
|
+
expect(result.transformed).toBe(true);
|
|
511
|
+
expect(result.metadata.arrayMethodCount).toBe(2);
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
test('Simple forEach in if block', () => {
|
|
515
|
+
const code = `
|
|
516
|
+
if (shouldProcess) {
|
|
517
|
+
await items.forEach(async (item) => {
|
|
518
|
+
await atp.llm.call({ prompt: item });
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
`;
|
|
522
|
+
const result = compiler.transform(code);
|
|
523
|
+
expect(result.code).toContain('batchParallel');
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
test('Simple map in try block', () => {
|
|
527
|
+
const code = `
|
|
528
|
+
try {
|
|
529
|
+
const results = await items.map(async (item) => {
|
|
530
|
+
return await atp.llm.call({ prompt: item });
|
|
531
|
+
});
|
|
532
|
+
} catch (e) {
|
|
533
|
+
console.error(e);
|
|
534
|
+
}
|
|
535
|
+
`;
|
|
536
|
+
const result = compiler.transform(code);
|
|
537
|
+
expect(result.code).toContain('batchParallel');
|
|
538
|
+
});
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
describe('Error Cases', () => {
|
|
542
|
+
test('Non-async callback - should not transform', () => {
|
|
543
|
+
const code = `
|
|
544
|
+
const results = items.map((item) => {
|
|
545
|
+
return item * 2;
|
|
546
|
+
});
|
|
547
|
+
`;
|
|
548
|
+
const result = compiler.transform(code);
|
|
549
|
+
expect(result.transformed).toBe(false);
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
test('No await in callback - transforms to sequential (no pausable calls)', () => {
|
|
553
|
+
const code = `
|
|
554
|
+
const results = await items.map(async (item) => {
|
|
555
|
+
return item * 2;
|
|
556
|
+
});
|
|
557
|
+
`;
|
|
558
|
+
const result = compiler.transform(code);
|
|
559
|
+
// No pausable calls, so it's transformed to resumableMap as fallback
|
|
560
|
+
// This is actually correct - the callback is async so it gets transformed
|
|
561
|
+
expect(result.transformed).toBe(true);
|
|
562
|
+
expect(result.code).toContain('resumableMap');
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
test('Non-pausable await - transforms to sequential (no pausable calls)', () => {
|
|
566
|
+
const code = `
|
|
567
|
+
const results = await items.map(async (item) => {
|
|
568
|
+
return await fetch(item.url);
|
|
569
|
+
});
|
|
570
|
+
`;
|
|
571
|
+
const result = compiler.transform(code);
|
|
572
|
+
// fetch is not a pausable call, so it falls back to resumableMap
|
|
573
|
+
expect(result.transformed).toBe(true);
|
|
574
|
+
expect(result.code).toContain('resumableMap');
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
test('Valid syntax with transformations always succeeds', () => {
|
|
578
|
+
// In production, TypeScript validates syntax BEFORE reaching the compiler
|
|
579
|
+
// The compiler expects valid JavaScript/TypeScript input
|
|
580
|
+
// Testing invalid syntax is not relevant to compiler logic
|
|
581
|
+
const code = `
|
|
582
|
+
const results = await items.map(async (item) => {
|
|
583
|
+
return await atp.llm.call({ prompt: item });
|
|
584
|
+
});
|
|
585
|
+
`;
|
|
586
|
+
// Valid code should transform successfully
|
|
587
|
+
const result = compiler.transform(code);
|
|
588
|
+
expect(result.transformed).toBe(true);
|
|
589
|
+
expect(result.code).toContain('batchParallel');
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
describe('Detection Accuracy', () => {
|
|
594
|
+
test('detect() should match transform() behavior', () => {
|
|
595
|
+
const simpleCodes = [
|
|
596
|
+
`items.map(async (x) => await atp.llm.call({ prompt: x }))`,
|
|
597
|
+
`items.forEach(async (x) => { await atp.llm.call({ prompt: x }); })`,
|
|
598
|
+
`for (const x of items) { await atp.llm.call({ prompt: x }); }`,
|
|
599
|
+
];
|
|
600
|
+
|
|
601
|
+
simpleCodes.forEach((code) => {
|
|
602
|
+
const detection = compiler.detect(code);
|
|
603
|
+
const transformation = compiler.transform(code);
|
|
604
|
+
|
|
605
|
+
expect(detection.needsTransform).toBe(transformation.transformed);
|
|
606
|
+
if (detection.needsTransform) {
|
|
607
|
+
expect(detection.patterns.length).toBeGreaterThan(0);
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
test('Batch detection should be accurate', () => {
|
|
613
|
+
// batchableParallel is specifically for Promise.all patterns
|
|
614
|
+
const promiseAllCode = `
|
|
615
|
+
const results = await Promise.all([
|
|
616
|
+
atp.llm.call({ prompt: 'A' }),
|
|
617
|
+
atp.llm.call({ prompt: 'B' })
|
|
618
|
+
]);
|
|
619
|
+
`;
|
|
620
|
+
|
|
621
|
+
const detection = compiler.detect(promiseAllCode);
|
|
622
|
+
const transformation = compiler.transform(promiseAllCode);
|
|
623
|
+
|
|
624
|
+
expect(detection.batchableParallel).toBe(true);
|
|
625
|
+
expect(transformation.code).toContain('batchParallel');
|
|
626
|
+
|
|
627
|
+
// Array methods use a different detection mechanism
|
|
628
|
+
const arrayMethodCode = `
|
|
629
|
+
const results = await items.map(async (item) => {
|
|
630
|
+
return await atp.llm.call({ prompt: item });
|
|
631
|
+
});
|
|
632
|
+
`;
|
|
633
|
+
|
|
634
|
+
const arrayDetection = compiler.detect(arrayMethodCode);
|
|
635
|
+
const arrayTransformation = compiler.transform(arrayMethodCode);
|
|
636
|
+
|
|
637
|
+
expect(arrayDetection.needsTransform).toBe(true);
|
|
638
|
+
expect(arrayTransformation.code).toContain('batchParallel');
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
test('Non-batchable should not report as batchable', () => {
|
|
642
|
+
const nonBatchableCode = `
|
|
643
|
+
const results = await items.map(async (item) => {
|
|
644
|
+
if (item.valid) {
|
|
645
|
+
return await atp.llm.call({ prompt: item });
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
`;
|
|
649
|
+
|
|
650
|
+
const detection = compiler.detect(nonBatchableCode);
|
|
651
|
+
const transformation = compiler.transform(nonBatchableCode);
|
|
652
|
+
|
|
653
|
+
// Should detect async patterns but not as batchable
|
|
654
|
+
expect(detection.needsTransform).toBe(true);
|
|
655
|
+
expect(transformation.code).not.toContain('batchParallel');
|
|
656
|
+
});
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
describe('Performance Characteristics', () => {
|
|
660
|
+
test('Large code - should transform efficiently', () => {
|
|
661
|
+
const largeCode = `
|
|
662
|
+
${Array.from(
|
|
663
|
+
{ length: 100 },
|
|
664
|
+
(_, i) => `
|
|
665
|
+
const results${i} = await items.map(async (item) => {
|
|
666
|
+
return await atp.llm.call({ prompt: item + ${i} });
|
|
667
|
+
});
|
|
668
|
+
`
|
|
669
|
+
).join('\n')}
|
|
670
|
+
`;
|
|
671
|
+
|
|
672
|
+
const start = Date.now();
|
|
673
|
+
const result = compiler.transform(largeCode);
|
|
674
|
+
const duration = Date.now() - start;
|
|
675
|
+
|
|
676
|
+
expect(result.transformed).toBe(true);
|
|
677
|
+
expect(duration).toBeLessThan(5000); // Should complete in < 5 seconds
|
|
678
|
+
expect(result.metadata.arrayMethodCount).toBe(100);
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
test('Deep nesting - should handle', () => {
|
|
682
|
+
const deepCode = `
|
|
683
|
+
await items.map(async (a) => {
|
|
684
|
+
return await a.items.map(async (b) => {
|
|
685
|
+
return await b.items.map(async (c) => {
|
|
686
|
+
return await c.items.map(async (d) => {
|
|
687
|
+
return await atp.llm.call({ prompt: d });
|
|
688
|
+
});
|
|
689
|
+
});
|
|
690
|
+
});
|
|
691
|
+
});
|
|
692
|
+
`;
|
|
693
|
+
|
|
694
|
+
const result = compiler.transform(deepCode);
|
|
695
|
+
expect(result.transformed).toBe(true);
|
|
696
|
+
expect(result.metadata.arrayMethodCount).toBe(4);
|
|
697
|
+
});
|
|
698
|
+
});
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
console.log('\n🎯 COMPREHENSIVE EDGE CASE TESTS COMPLETE!\n');
|