@mondaydotcomorg/atp-compiler 0.19.7 → 0.19.9
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/dist/index.cjs +2947 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +2852 -14
- package/dist/index.js.map +1 -1
- package/package.json +12 -20
- package/project.json +1 -2
- package/src/runtime/runtime-functions.ts +0 -1
- package/tsconfig.json +1 -5
- package/tsconfig.tsbuildinfo +1 -1
- package/tsup.config.ts +16 -0
package/dist/index.js
CHANGED
|
@@ -1,15 +1,2853 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
import { parse } from '@babel/parser';
|
|
2
|
+
import _traverse from '@babel/traverse';
|
|
3
|
+
import _generate from '@babel/generator';
|
|
4
|
+
import * as t7 from '@babel/types';
|
|
5
|
+
import { getCallSequenceNumber, getCachedResult, nextSequenceNumber } from '@mondaydotcomorg/atp-runtime';
|
|
6
|
+
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
+
|
|
10
|
+
// src/types.ts
|
|
11
|
+
var PAUSABLE_CALL_PATTERNS = [
|
|
12
|
+
{
|
|
13
|
+
namespace: "atp.llm",
|
|
14
|
+
method: "call"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
namespace: "atp.llm",
|
|
18
|
+
method: "extract"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
namespace: "atp.llm",
|
|
22
|
+
method: "classify"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
namespace: "atp.llm",
|
|
26
|
+
method: "stream"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
namespace: "atp.llm",
|
|
30
|
+
method: "generate"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
namespace: "atp.approval",
|
|
34
|
+
method: "request"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
namespace: "atp.approval",
|
|
38
|
+
method: "confirm"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
namespace: "atp.approval",
|
|
42
|
+
method: "verify"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
namespace: "atp.embedding",
|
|
46
|
+
method: "embed"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
namespace: "atp.embedding",
|
|
50
|
+
method: "search"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
namespace: "atp.embedding",
|
|
54
|
+
method: "create"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
namespace: "atp.embedding",
|
|
58
|
+
method: "generate"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
namespace: "atp.embedding",
|
|
62
|
+
method: "encode"
|
|
63
|
+
}
|
|
64
|
+
];
|
|
65
|
+
var DEFAULT_COMPILER_CONFIG = {
|
|
66
|
+
enableBatchParallel: true,
|
|
67
|
+
maxLoopNesting: 10,
|
|
68
|
+
checkpointInterval: 1,
|
|
69
|
+
debugMode: false,
|
|
70
|
+
batchSizeThreshold: 10
|
|
71
|
+
};
|
|
72
|
+
function isPausableCall(node) {
|
|
73
|
+
if (!t7.isAwaitExpression(node)) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const argument = node.argument;
|
|
77
|
+
if (!t7.isCallExpression(argument)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
return isPausableCallExpression(argument);
|
|
81
|
+
}
|
|
82
|
+
__name(isPausableCall, "isPausableCall");
|
|
83
|
+
function isPausableCallExpression(node) {
|
|
84
|
+
const callee = node.callee;
|
|
85
|
+
if (!t7.isMemberExpression(callee)) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
const fullPath = getMemberExpressionPath(callee);
|
|
89
|
+
return PAUSABLE_CALL_PATTERNS.some((pattern) => fullPath === `${pattern.namespace}.${pattern.method}`);
|
|
90
|
+
}
|
|
91
|
+
__name(isPausableCallExpression, "isPausableCallExpression");
|
|
92
|
+
function getMemberExpressionPath(node) {
|
|
93
|
+
const parts = [];
|
|
94
|
+
let current = node;
|
|
95
|
+
while (t7.isMemberExpression(current)) {
|
|
96
|
+
if (t7.isIdentifier(current.property)) {
|
|
97
|
+
parts.unshift(current.property.name);
|
|
98
|
+
}
|
|
99
|
+
current = current.object;
|
|
100
|
+
}
|
|
101
|
+
if (t7.isIdentifier(current)) {
|
|
102
|
+
parts.unshift(current.name);
|
|
103
|
+
}
|
|
104
|
+
return parts.join(".");
|
|
105
|
+
}
|
|
106
|
+
__name(getMemberExpressionPath, "getMemberExpressionPath");
|
|
107
|
+
function containsAwait(node) {
|
|
108
|
+
let hasAwait = false;
|
|
109
|
+
const checkNode = /* @__PURE__ */ __name((n) => {
|
|
110
|
+
if (t7.isAwaitExpression(n)) {
|
|
111
|
+
hasAwait = true;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (hasAwait) return;
|
|
115
|
+
Object.keys(n).forEach((key) => {
|
|
116
|
+
const value = n[key];
|
|
117
|
+
if (Array.isArray(value)) {
|
|
118
|
+
value.forEach((item) => {
|
|
119
|
+
if (item && typeof item === "object" && item.type) {
|
|
120
|
+
checkNode(item);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
} else if (value && typeof value === "object" && value.type) {
|
|
124
|
+
checkNode(value);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}, "checkNode");
|
|
128
|
+
checkNode(node);
|
|
129
|
+
return hasAwait;
|
|
130
|
+
}
|
|
131
|
+
__name(containsAwait, "containsAwait");
|
|
132
|
+
function containsPausableCall(node) {
|
|
133
|
+
let hasPausable = false;
|
|
134
|
+
const checkNode = /* @__PURE__ */ __name((n) => {
|
|
135
|
+
if (t7.isAwaitExpression(n) && isPausableCall(n)) {
|
|
136
|
+
hasPausable = true;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (hasPausable) return;
|
|
140
|
+
Object.keys(n).forEach((key) => {
|
|
141
|
+
const value = n[key];
|
|
142
|
+
if (Array.isArray(value)) {
|
|
143
|
+
value.forEach((item) => {
|
|
144
|
+
if (item && typeof item === "object" && item.type) {
|
|
145
|
+
checkNode(item);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
} else if (value && typeof value === "object" && value.type) {
|
|
149
|
+
checkNode(value);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}, "checkNode");
|
|
153
|
+
checkNode(node);
|
|
154
|
+
return hasPausable;
|
|
155
|
+
}
|
|
156
|
+
__name(containsPausableCall, "containsPausableCall");
|
|
157
|
+
function isAsyncFunction(node) {
|
|
158
|
+
return (t7.isFunctionDeclaration(node) || t7.isFunctionExpression(node) || t7.isArrowFunctionExpression(node)) && node.async === true;
|
|
159
|
+
}
|
|
160
|
+
__name(isAsyncFunction, "isAsyncFunction");
|
|
161
|
+
function getNodeLocation(node) {
|
|
162
|
+
if (node.loc) {
|
|
163
|
+
return {
|
|
164
|
+
line: node.loc.start.line,
|
|
165
|
+
column: node.loc.start.column
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
return void 0;
|
|
169
|
+
}
|
|
170
|
+
__name(getNodeLocation, "getNodeLocation");
|
|
171
|
+
function createRuntimeCall(fnName, args) {
|
|
172
|
+
return t7.awaitExpression(t7.callExpression(t7.memberExpression(t7.identifier("__runtime"), t7.identifier(fnName)), args));
|
|
173
|
+
}
|
|
174
|
+
__name(createRuntimeCall, "createRuntimeCall");
|
|
175
|
+
function wrapInAsyncFunction(body) {
|
|
176
|
+
return t7.functionExpression(null, [], t7.blockStatement(body), false, true);
|
|
177
|
+
}
|
|
178
|
+
__name(wrapInAsyncFunction, "wrapInAsyncFunction");
|
|
179
|
+
function isArrayMethod(node, methodName) {
|
|
180
|
+
if (!t7.isCallExpression(node)) {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
const callee = node.callee;
|
|
184
|
+
if (!t7.isMemberExpression(callee)) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
return t7.isIdentifier(callee.property) && callee.property.name === methodName;
|
|
188
|
+
}
|
|
189
|
+
__name(isArrayMethod, "isArrayMethod");
|
|
190
|
+
function extractForOfParamName(left) {
|
|
191
|
+
if (t7.isVariableDeclaration(left)) {
|
|
192
|
+
const id = left.declarations[0]?.id;
|
|
193
|
+
return t7.isIdentifier(id) ? id.name : "item";
|
|
194
|
+
} else if (t7.isIdentifier(left)) {
|
|
195
|
+
return left.name;
|
|
196
|
+
} else {
|
|
197
|
+
return "item";
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
__name(extractForOfParamName, "extractForOfParamName");
|
|
201
|
+
|
|
202
|
+
// src/transformer/detector.ts
|
|
203
|
+
var traverse = typeof _traverse.default === "function" ? _traverse.default : _traverse;
|
|
204
|
+
var AsyncIterationDetector = class {
|
|
205
|
+
static {
|
|
206
|
+
__name(this, "AsyncIterationDetector");
|
|
207
|
+
}
|
|
208
|
+
detect(code) {
|
|
209
|
+
const patterns = [];
|
|
210
|
+
let batchableParallel = false;
|
|
211
|
+
try {
|
|
212
|
+
const ast = parse(code, {
|
|
213
|
+
sourceType: "module",
|
|
214
|
+
plugins: [
|
|
215
|
+
"typescript"
|
|
216
|
+
],
|
|
217
|
+
allowAwaitOutsideFunction: true,
|
|
218
|
+
allowReturnOutsideFunction: true
|
|
219
|
+
});
|
|
220
|
+
traverse(ast, {
|
|
221
|
+
ForOfStatement: /* @__PURE__ */ __name((path) => {
|
|
222
|
+
if (containsAwait(path.node.body)) {
|
|
223
|
+
patterns.push("for-of-await");
|
|
224
|
+
}
|
|
225
|
+
}, "ForOfStatement"),
|
|
226
|
+
WhileStatement: /* @__PURE__ */ __name((path) => {
|
|
227
|
+
if (containsAwait(path.node.body)) {
|
|
228
|
+
patterns.push("while-await");
|
|
229
|
+
}
|
|
230
|
+
}, "WhileStatement"),
|
|
231
|
+
CallExpression: /* @__PURE__ */ __name((path) => {
|
|
232
|
+
const node = path.node;
|
|
233
|
+
if (isArrayMethod(node, "map")) {
|
|
234
|
+
const callback = node.arguments[0];
|
|
235
|
+
if (callback && t7.isFunction(callback) && callback.async) {
|
|
236
|
+
patterns.push("map-async");
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (isArrayMethod(node, "forEach")) {
|
|
240
|
+
const callback = node.arguments[0];
|
|
241
|
+
if (callback && t7.isFunction(callback) && callback.async) {
|
|
242
|
+
patterns.push("forEach-async");
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (isArrayMethod(node, "filter")) {
|
|
246
|
+
const callback = node.arguments[0];
|
|
247
|
+
if (callback && t7.isFunction(callback) && callback.async) {
|
|
248
|
+
patterns.push("filter-async");
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (isArrayMethod(node, "reduce")) {
|
|
252
|
+
const callback = node.arguments[0];
|
|
253
|
+
if (callback && t7.isFunction(callback) && callback.async) {
|
|
254
|
+
patterns.push("reduce-async");
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (isArrayMethod(node, "find")) {
|
|
258
|
+
const callback = node.arguments[0];
|
|
259
|
+
if (callback && t7.isFunction(callback) && callback.async) {
|
|
260
|
+
patterns.push("find-async");
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (isArrayMethod(node, "some")) {
|
|
264
|
+
const callback = node.arguments[0];
|
|
265
|
+
if (callback && t7.isFunction(callback) && callback.async) {
|
|
266
|
+
patterns.push("some-async");
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (isArrayMethod(node, "every")) {
|
|
270
|
+
const callback = node.arguments[0];
|
|
271
|
+
if (callback && t7.isFunction(callback) && callback.async) {
|
|
272
|
+
patterns.push("every-async");
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
if (isArrayMethod(node, "flatMap")) {
|
|
276
|
+
const callback = node.arguments[0];
|
|
277
|
+
if (callback && t7.isFunction(callback) && callback.async) {
|
|
278
|
+
patterns.push("flatMap-async");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (this.isPromiseAll(node)) {
|
|
282
|
+
patterns.push("promise-all");
|
|
283
|
+
if (this.canBatchPromiseAll(node)) {
|
|
284
|
+
batchableParallel = true;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (this.isPromiseAllSettled(node)) {
|
|
288
|
+
patterns.push("promise-allSettled");
|
|
289
|
+
}
|
|
290
|
+
}, "CallExpression")
|
|
291
|
+
});
|
|
292
|
+
return {
|
|
293
|
+
needsTransform: patterns.length > 0,
|
|
294
|
+
patterns: [
|
|
295
|
+
...new Set(patterns)
|
|
296
|
+
],
|
|
297
|
+
batchableParallel
|
|
298
|
+
};
|
|
299
|
+
} catch (error) {
|
|
300
|
+
return {
|
|
301
|
+
needsTransform: false,
|
|
302
|
+
patterns: [],
|
|
303
|
+
batchableParallel: false
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
isPromiseAll(node) {
|
|
308
|
+
const callee = node.callee;
|
|
309
|
+
return t7.isMemberExpression(callee) && t7.isIdentifier(callee.object, {
|
|
310
|
+
name: "Promise"
|
|
311
|
+
}) && t7.isIdentifier(callee.property, {
|
|
312
|
+
name: "all"
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
isPromiseAllSettled(node) {
|
|
316
|
+
const callee = node.callee;
|
|
317
|
+
return t7.isMemberExpression(callee) && t7.isIdentifier(callee.object, {
|
|
318
|
+
name: "Promise"
|
|
319
|
+
}) && t7.isIdentifier(callee.property, {
|
|
320
|
+
name: "allSettled"
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
canBatchPromiseAll(node) {
|
|
324
|
+
const arrayArg = node.arguments[0];
|
|
325
|
+
if (!t7.isArrayExpression(arrayArg)) {
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
if (arrayArg.elements.length === 0) {
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
return arrayArg.elements.every((el) => {
|
|
332
|
+
if (!el || t7.isSpreadElement(el)) {
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
return this.isDirectPausableCall(el);
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
isDirectPausableCall(node) {
|
|
339
|
+
if (t7.isAwaitExpression(node)) {
|
|
340
|
+
node = node.argument;
|
|
341
|
+
}
|
|
342
|
+
if (!t7.isCallExpression(node)) {
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
return isPausableCallExpression(node);
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
// src/runtime/context.ts
|
|
350
|
+
var contextStack = [];
|
|
351
|
+
function setRuntimeContext(context) {
|
|
352
|
+
contextStack.push(context);
|
|
353
|
+
}
|
|
354
|
+
__name(setRuntimeContext, "setRuntimeContext");
|
|
355
|
+
function getRuntimeContext() {
|
|
356
|
+
const context = contextStack[contextStack.length - 1];
|
|
357
|
+
if (!context) {
|
|
358
|
+
throw new Error("No runtime context available. Compiler runtime not properly initialized.");
|
|
359
|
+
}
|
|
360
|
+
return context;
|
|
361
|
+
}
|
|
362
|
+
__name(getRuntimeContext, "getRuntimeContext");
|
|
363
|
+
function clearRuntimeContext() {
|
|
364
|
+
contextStack.pop();
|
|
365
|
+
}
|
|
366
|
+
__name(clearRuntimeContext, "clearRuntimeContext");
|
|
367
|
+
function hasRuntimeContext() {
|
|
368
|
+
return contextStack.length > 0;
|
|
369
|
+
}
|
|
370
|
+
__name(hasRuntimeContext, "hasRuntimeContext");
|
|
371
|
+
var idCounter = 0;
|
|
372
|
+
function generateUniqueId(prefix) {
|
|
373
|
+
return `${prefix}_${Date.now()}_${idCounter++}`;
|
|
374
|
+
}
|
|
375
|
+
__name(generateUniqueId, "generateUniqueId");
|
|
376
|
+
function resetIdCounter() {
|
|
377
|
+
idCounter = 0;
|
|
378
|
+
}
|
|
379
|
+
__name(resetIdCounter, "resetIdCounter");
|
|
380
|
+
var BatchOptimizer = class {
|
|
381
|
+
static {
|
|
382
|
+
__name(this, "BatchOptimizer");
|
|
383
|
+
}
|
|
384
|
+
arrayMethodsWithEarlyExit = [
|
|
385
|
+
"find",
|
|
386
|
+
"some",
|
|
387
|
+
"every"
|
|
388
|
+
];
|
|
389
|
+
canBatchArrayMethod(callback) {
|
|
390
|
+
if (!callback.async) {
|
|
391
|
+
return {
|
|
392
|
+
canBatch: false,
|
|
393
|
+
reason: "Not async"
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
const body = callback.body;
|
|
397
|
+
if (!t7.isBlockStatement(body)) {
|
|
398
|
+
if (t7.isAwaitExpression(body)) {
|
|
399
|
+
if (this.isDirectPausableCall(body.argument)) {
|
|
400
|
+
return {
|
|
401
|
+
canBatch: true,
|
|
402
|
+
llmCallPattern: "single",
|
|
403
|
+
hasConditionals: false
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return {
|
|
408
|
+
canBatch: false,
|
|
409
|
+
reason: "Non-block body without direct call"
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
const statements = body.body;
|
|
413
|
+
if (statements.length === 0) {
|
|
414
|
+
return {
|
|
415
|
+
canBatch: false,
|
|
416
|
+
reason: "Empty body"
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
let hasConditionals = false;
|
|
420
|
+
let hasLoops = false;
|
|
421
|
+
let hasTryCatch = false;
|
|
422
|
+
for (const stmt of statements) {
|
|
423
|
+
if (t7.isIfStatement(stmt) || t7.isSwitchStatement(stmt)) {
|
|
424
|
+
hasConditionals = true;
|
|
425
|
+
}
|
|
426
|
+
if (t7.isTryStatement(stmt)) {
|
|
427
|
+
hasTryCatch = true;
|
|
428
|
+
}
|
|
429
|
+
if (t7.isForStatement(stmt) || t7.isForOfStatement(stmt) || t7.isForInStatement(stmt) || t7.isWhileStatement(stmt) || t7.isDoWhileStatement(stmt)) {
|
|
430
|
+
hasLoops = true;
|
|
431
|
+
}
|
|
432
|
+
if (t7.isBreakStatement(stmt) || t7.isContinueStatement(stmt)) {
|
|
433
|
+
return {
|
|
434
|
+
canBatch: false,
|
|
435
|
+
reason: "Contains break/continue"
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
if (t7.isReturnStatement(stmt) && stmt !== statements[statements.length - 1]) {
|
|
439
|
+
return {
|
|
440
|
+
canBatch: false,
|
|
441
|
+
reason: "Early return"
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (hasLoops) {
|
|
446
|
+
return {
|
|
447
|
+
canBatch: false,
|
|
448
|
+
reason: "Contains loops",
|
|
449
|
+
hasLoops: true
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
if (hasTryCatch) {
|
|
453
|
+
return {
|
|
454
|
+
canBatch: false,
|
|
455
|
+
reason: "Contains try-catch"
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
const pausableCalls = this.countPausableCalls(body);
|
|
459
|
+
if (pausableCalls === 0) {
|
|
460
|
+
return {
|
|
461
|
+
canBatch: false,
|
|
462
|
+
reason: "No pausable calls"
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
if (pausableCalls > 1) {
|
|
466
|
+
return {
|
|
467
|
+
canBatch: false,
|
|
468
|
+
reason: "Multiple pausable calls",
|
|
469
|
+
llmCallPattern: "multiple"
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
if (hasConditionals) {
|
|
473
|
+
return {
|
|
474
|
+
canBatch: true,
|
|
475
|
+
llmCallPattern: "conditional",
|
|
476
|
+
hasConditionals: true,
|
|
477
|
+
reason: "Simple conditional - can batch but consider array size"
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
return {
|
|
481
|
+
canBatch: true,
|
|
482
|
+
llmCallPattern: "single",
|
|
483
|
+
hasConditionals: false
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Smart decision: Should we batch based on array size and method type?
|
|
488
|
+
*/
|
|
489
|
+
makeSmartBatchDecision(methodName, batchResult, arrayNode, threshold = 10) {
|
|
490
|
+
if (!batchResult.canBatch) {
|
|
491
|
+
return {
|
|
492
|
+
shouldBatch: false,
|
|
493
|
+
reason: "Complex callback - use sequential",
|
|
494
|
+
strategy: "never-batch"
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
if (!batchResult.hasConditionals) {
|
|
498
|
+
return {
|
|
499
|
+
shouldBatch: true,
|
|
500
|
+
reason: "Simple callback - batching is faster",
|
|
501
|
+
strategy: "always-batch"
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
const hasEarlyExitBenefit = this.arrayMethodsWithEarlyExit.includes(methodName);
|
|
505
|
+
if (!hasEarlyExitBenefit) {
|
|
506
|
+
const arraySize2 = this.estimateArraySize(arrayNode);
|
|
507
|
+
if (arraySize2 !== null && arraySize2 < threshold) {
|
|
508
|
+
return {
|
|
509
|
+
shouldBatch: true,
|
|
510
|
+
reason: `Small array (${arraySize2} < ${threshold}) - batch despite conditionals`,
|
|
511
|
+
strategy: "size-dependent"
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
return {
|
|
515
|
+
shouldBatch: false,
|
|
516
|
+
reason: "Conditionals + large/unknown array - sequential for safety",
|
|
517
|
+
strategy: "size-dependent"
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
const arraySize = this.estimateArraySize(arrayNode);
|
|
521
|
+
if (arraySize !== null && arraySize < threshold) {
|
|
522
|
+
return {
|
|
523
|
+
shouldBatch: true,
|
|
524
|
+
reason: `Small array (${arraySize} < ${threshold}) - batch for speed`,
|
|
525
|
+
strategy: "size-dependent"
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
if (arraySize !== null && arraySize >= threshold) {
|
|
529
|
+
return {
|
|
530
|
+
shouldBatch: false,
|
|
531
|
+
reason: `Large array (${arraySize} >= ${threshold}) + conditionals - sequential for early-exit savings`,
|
|
532
|
+
strategy: "size-dependent"
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
if (t7.isArrayExpression(arrayNode)) {
|
|
536
|
+
return {
|
|
537
|
+
shouldBatch: true,
|
|
538
|
+
reason: "Array literal (likely small) - batch",
|
|
539
|
+
strategy: "size-dependent"
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
return {
|
|
543
|
+
shouldBatch: false,
|
|
544
|
+
reason: "Unknown array size + conditionals - sequential for safety",
|
|
545
|
+
strategy: "size-dependent"
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
estimateArraySize(arrayNode) {
|
|
549
|
+
if (t7.isArrayExpression(arrayNode)) {
|
|
550
|
+
return arrayNode.elements.length;
|
|
551
|
+
}
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
canBatchForOfLoop(loopNode) {
|
|
555
|
+
const body = loopNode.body;
|
|
556
|
+
if (!t7.isBlockStatement(body)) {
|
|
557
|
+
return {
|
|
558
|
+
canBatch: false,
|
|
559
|
+
reason: "Loop body not a block"
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
const statements = body.body;
|
|
563
|
+
if (statements.length === 0) {
|
|
564
|
+
return {
|
|
565
|
+
canBatch: false,
|
|
566
|
+
reason: "Empty loop body"
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
const hasBreakOrContinue = this.containsBreakOrContinue(body);
|
|
570
|
+
if (hasBreakOrContinue) {
|
|
571
|
+
return {
|
|
572
|
+
canBatch: false,
|
|
573
|
+
reason: "Contains break/continue"
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
let hasConditionals = false;
|
|
577
|
+
for (const stmt of statements) {
|
|
578
|
+
if (t7.isIfStatement(stmt) || t7.isSwitchStatement(stmt)) {
|
|
579
|
+
hasConditionals = true;
|
|
580
|
+
}
|
|
581
|
+
if (t7.isForStatement(stmt) || t7.isForOfStatement(stmt) || t7.isForInStatement(stmt) || t7.isWhileStatement(stmt) || t7.isDoWhileStatement(stmt)) {
|
|
582
|
+
return {
|
|
583
|
+
canBatch: false,
|
|
584
|
+
reason: "Contains nested loops",
|
|
585
|
+
hasLoops: true
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
const pausableCalls = this.countPausableCalls(body);
|
|
590
|
+
if (pausableCalls === 0) {
|
|
591
|
+
return {
|
|
592
|
+
canBatch: false,
|
|
593
|
+
reason: "No pausable calls"
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
if (pausableCalls > 1) {
|
|
597
|
+
return {
|
|
598
|
+
canBatch: false,
|
|
599
|
+
reason: "Multiple pausable calls",
|
|
600
|
+
llmCallPattern: "multiple"
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
if (hasConditionals) {
|
|
604
|
+
return {
|
|
605
|
+
canBatch: true,
|
|
606
|
+
llmCallPattern: "conditional",
|
|
607
|
+
hasConditionals: true,
|
|
608
|
+
reason: "Simple conditional - can batch but consider array size"
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
return {
|
|
612
|
+
canBatch: true,
|
|
613
|
+
llmCallPattern: "single",
|
|
614
|
+
hasConditionals: false
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
containsBreakOrContinue(node) {
|
|
618
|
+
let found = false;
|
|
619
|
+
const visit = /* @__PURE__ */ __name((n) => {
|
|
620
|
+
if (found) return;
|
|
621
|
+
if (t7.isBreakStatement(n) || t7.isContinueStatement(n)) {
|
|
622
|
+
found = true;
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
if (t7.isForStatement(n) || t7.isForOfStatement(n) || t7.isForInStatement(n) || t7.isWhileStatement(n) || t7.isDoWhileStatement(n)) {
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
Object.keys(n).forEach((key) => {
|
|
629
|
+
const value = n[key];
|
|
630
|
+
if (Array.isArray(value)) {
|
|
631
|
+
value.forEach((item) => {
|
|
632
|
+
if (item && typeof item === "object" && item.type) {
|
|
633
|
+
visit(item);
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
} else if (value && typeof value === "object" && value.type) {
|
|
637
|
+
visit(value);
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
}, "visit");
|
|
641
|
+
visit(node);
|
|
642
|
+
return found;
|
|
643
|
+
}
|
|
644
|
+
isDirectPausableCall(node) {
|
|
645
|
+
if (!t7.isCallExpression(node)) {
|
|
646
|
+
return false;
|
|
647
|
+
}
|
|
648
|
+
return isPausableCallExpression(node);
|
|
649
|
+
}
|
|
650
|
+
countPausableCalls(body) {
|
|
651
|
+
let count = 0;
|
|
652
|
+
const visit = /* @__PURE__ */ __name((node) => {
|
|
653
|
+
if (t7.isAwaitExpression(node) && this.isDirectPausableCall(node.argument)) {
|
|
654
|
+
count++;
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
Object.keys(node).forEach((key) => {
|
|
658
|
+
const value = node[key];
|
|
659
|
+
if (Array.isArray(value)) {
|
|
660
|
+
value.forEach((item) => {
|
|
661
|
+
if (item && typeof item === "object" && item.type) {
|
|
662
|
+
visit(item);
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
} else if (value && typeof value === "object" && value.type) {
|
|
666
|
+
visit(value);
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
}, "visit");
|
|
670
|
+
visit(body);
|
|
671
|
+
return count;
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
var BatchParallelDetector = class {
|
|
675
|
+
static {
|
|
676
|
+
__name(this, "BatchParallelDetector");
|
|
677
|
+
}
|
|
678
|
+
canBatch(promiseAllNode) {
|
|
679
|
+
const arrayArg = promiseAllNode.arguments[0];
|
|
680
|
+
if (!t7.isArrayExpression(arrayArg)) {
|
|
681
|
+
return false;
|
|
682
|
+
}
|
|
683
|
+
if (arrayArg.elements.length === 0) {
|
|
684
|
+
return false;
|
|
685
|
+
}
|
|
686
|
+
return arrayArg.elements.every((el) => {
|
|
687
|
+
if (!el || t7.isSpreadElement(el)) {
|
|
688
|
+
return false;
|
|
689
|
+
}
|
|
690
|
+
return this.isDirectPausableCall(el);
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
isDirectPausableCall(node) {
|
|
694
|
+
if (t7.isAwaitExpression(node)) {
|
|
695
|
+
node = node.argument;
|
|
696
|
+
}
|
|
697
|
+
if (!t7.isCallExpression(node)) {
|
|
698
|
+
return false;
|
|
699
|
+
}
|
|
700
|
+
return isPausableCallExpression(node);
|
|
701
|
+
}
|
|
702
|
+
extractBatchCalls(arrayNode) {
|
|
703
|
+
const calls = [];
|
|
704
|
+
for (const el of arrayNode.elements) {
|
|
705
|
+
if (!el || t7.isSpreadElement(el)) {
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
let callNode = el;
|
|
709
|
+
if (t7.isAwaitExpression(callNode)) {
|
|
710
|
+
callNode = callNode.argument;
|
|
711
|
+
}
|
|
712
|
+
if (!t7.isCallExpression(callNode)) {
|
|
713
|
+
continue;
|
|
714
|
+
}
|
|
715
|
+
const callInfo = this.extractCallInfo(callNode);
|
|
716
|
+
if (callInfo) {
|
|
717
|
+
calls.push(callInfo);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
return calls;
|
|
721
|
+
}
|
|
722
|
+
extractCallInfo(callNode) {
|
|
723
|
+
if (!t7.isMemberExpression(callNode.callee)) {
|
|
724
|
+
return null;
|
|
725
|
+
}
|
|
726
|
+
const path = getMemberExpressionPath(callNode.callee);
|
|
727
|
+
const parts = path.split(".");
|
|
728
|
+
if (parts.length < 3) {
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
const [namespace, service, method] = parts;
|
|
732
|
+
if (namespace !== "atp" || !method) {
|
|
733
|
+
return null;
|
|
734
|
+
}
|
|
735
|
+
const type = service;
|
|
736
|
+
const payload = this.extractPayload(callNode.arguments);
|
|
737
|
+
return {
|
|
738
|
+
type,
|
|
739
|
+
operation: method,
|
|
740
|
+
payload
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Extract payload AST node directly
|
|
745
|
+
*/
|
|
746
|
+
extractPayloadNode(callNode) {
|
|
747
|
+
if (callNode.arguments.length === 0) {
|
|
748
|
+
return t7.objectExpression([]);
|
|
749
|
+
}
|
|
750
|
+
const firstArg = callNode.arguments[0];
|
|
751
|
+
if (!firstArg || t7.isSpreadElement(firstArg) || !t7.isExpression(firstArg)) {
|
|
752
|
+
return null;
|
|
753
|
+
}
|
|
754
|
+
return firstArg;
|
|
755
|
+
}
|
|
756
|
+
extractPayload(args) {
|
|
757
|
+
if (args.length === 0) {
|
|
758
|
+
return {};
|
|
759
|
+
}
|
|
760
|
+
const firstArg = args[0];
|
|
761
|
+
if (t7.isSpreadElement(firstArg)) {
|
|
762
|
+
return {};
|
|
763
|
+
}
|
|
764
|
+
if (t7.isObjectExpression(firstArg)) {
|
|
765
|
+
return this.objectExpressionToRecord(firstArg);
|
|
766
|
+
}
|
|
767
|
+
if (t7.isStringLiteral(firstArg)) {
|
|
768
|
+
return {
|
|
769
|
+
message: firstArg.value
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
return {};
|
|
773
|
+
}
|
|
774
|
+
objectExpressionToRecord(obj) {
|
|
775
|
+
const record = {};
|
|
776
|
+
for (const prop of obj.properties) {
|
|
777
|
+
if (t7.isObjectProperty(prop) && !prop.computed) {
|
|
778
|
+
const key = t7.isIdentifier(prop.key) ? prop.key.name : String(prop.key);
|
|
779
|
+
const value = this.extractValue(prop.value);
|
|
780
|
+
record[key] = value;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
return record;
|
|
784
|
+
}
|
|
785
|
+
extractValue(node) {
|
|
786
|
+
if (t7.isStringLiteral(node)) {
|
|
787
|
+
return node.value;
|
|
788
|
+
}
|
|
789
|
+
if (t7.isNumericLiteral(node)) {
|
|
790
|
+
return node.value;
|
|
791
|
+
}
|
|
792
|
+
if (t7.isBooleanLiteral(node)) {
|
|
793
|
+
return node.value;
|
|
794
|
+
}
|
|
795
|
+
if (t7.isNullLiteral(node)) {
|
|
796
|
+
return null;
|
|
797
|
+
}
|
|
798
|
+
if (t7.isArrayExpression(node)) {
|
|
799
|
+
return node.elements.map((el) => el && !t7.isSpreadElement(el) ? this.extractValue(el) : null);
|
|
800
|
+
}
|
|
801
|
+
if (t7.isObjectExpression(node)) {
|
|
802
|
+
return this.objectExpressionToRecord(node);
|
|
803
|
+
}
|
|
804
|
+
return void 0;
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
function findLLMCallExpression(body) {
|
|
808
|
+
let found = null;
|
|
809
|
+
const visit = /* @__PURE__ */ __name((node) => {
|
|
810
|
+
if (found) return;
|
|
811
|
+
if (t7.isAwaitExpression(node) && t7.isCallExpression(node.argument)) {
|
|
812
|
+
const call = node.argument;
|
|
813
|
+
if (t7.isMemberExpression(call.callee)) {
|
|
814
|
+
found = call;
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
Object.keys(node).forEach((key) => {
|
|
819
|
+
const value = node[key];
|
|
820
|
+
if (Array.isArray(value)) {
|
|
821
|
+
value.forEach((item) => {
|
|
822
|
+
if (item && typeof item === "object" && item.type) {
|
|
823
|
+
visit(item);
|
|
824
|
+
}
|
|
825
|
+
});
|
|
826
|
+
} else if (value && typeof value === "object" && value.type) {
|
|
827
|
+
visit(value);
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
}, "visit");
|
|
831
|
+
visit(body);
|
|
832
|
+
return found;
|
|
833
|
+
}
|
|
834
|
+
__name(findLLMCallExpression, "findLLMCallExpression");
|
|
835
|
+
function getArrayMethodName(node) {
|
|
836
|
+
const arrayMethods = [
|
|
837
|
+
"map",
|
|
838
|
+
"forEach",
|
|
839
|
+
"filter",
|
|
840
|
+
"reduce",
|
|
841
|
+
"find",
|
|
842
|
+
"some",
|
|
843
|
+
"every",
|
|
844
|
+
"flatMap"
|
|
845
|
+
];
|
|
846
|
+
for (const method of arrayMethods) {
|
|
847
|
+
if (isArrayMethod(node, method)) {
|
|
848
|
+
return method;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
return null;
|
|
852
|
+
}
|
|
853
|
+
__name(getArrayMethodName, "getArrayMethodName");
|
|
854
|
+
function getRuntimeMethodName(arrayMethod) {
|
|
855
|
+
const mapping = {
|
|
856
|
+
map: "resumableMap",
|
|
857
|
+
forEach: "resumableForEach",
|
|
858
|
+
filter: "resumableFilter",
|
|
859
|
+
reduce: "resumableReduce",
|
|
860
|
+
find: "resumableFind",
|
|
861
|
+
some: "resumableSome",
|
|
862
|
+
every: "resumableEvery",
|
|
863
|
+
flatMap: "resumableFlatMap"
|
|
864
|
+
};
|
|
865
|
+
return mapping[arrayMethod] || null;
|
|
866
|
+
}
|
|
867
|
+
__name(getRuntimeMethodName, "getRuntimeMethodName");
|
|
868
|
+
function canUseBatchParallel(methodName) {
|
|
869
|
+
return [
|
|
870
|
+
"map",
|
|
871
|
+
"forEach",
|
|
872
|
+
"filter",
|
|
873
|
+
"find",
|
|
874
|
+
"some",
|
|
875
|
+
"every"
|
|
876
|
+
].includes(methodName);
|
|
877
|
+
}
|
|
878
|
+
__name(canUseBatchParallel, "canUseBatchParallel");
|
|
879
|
+
|
|
880
|
+
// src/transformer/loop-transformer.ts
|
|
881
|
+
var LoopTransformer = class {
|
|
882
|
+
static {
|
|
883
|
+
__name(this, "LoopTransformer");
|
|
884
|
+
}
|
|
885
|
+
transformCount = 0;
|
|
886
|
+
batchOptimizer;
|
|
887
|
+
batchDetector;
|
|
888
|
+
batchSizeThreshold;
|
|
889
|
+
constructor(batchSizeThreshold = 10) {
|
|
890
|
+
this.batchOptimizer = new BatchOptimizer();
|
|
891
|
+
this.batchDetector = new BatchParallelDetector();
|
|
892
|
+
this.batchSizeThreshold = batchSizeThreshold;
|
|
893
|
+
}
|
|
894
|
+
transformForOfLoop(path) {
|
|
895
|
+
const node = path.node;
|
|
896
|
+
if (!containsAwait(node.body)) {
|
|
897
|
+
return false;
|
|
898
|
+
}
|
|
899
|
+
const batchResult = this.batchOptimizer.canBatchForOfLoop(node);
|
|
900
|
+
if (batchResult.canBatch) {
|
|
901
|
+
const decision = this.batchOptimizer.makeSmartBatchDecision("for...of", batchResult, node.right, this.batchSizeThreshold);
|
|
902
|
+
if (decision.shouldBatch) {
|
|
903
|
+
return this.transformForOfToBatch(path, node);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
return this.transformForOfToSequential(path, node);
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
909
|
+
* Transform simple for...of to batch parallel
|
|
910
|
+
*/
|
|
911
|
+
transformForOfToBatch(path, node) {
|
|
912
|
+
const loopId = generateUniqueId("for_of_batch");
|
|
913
|
+
const right = node.right;
|
|
914
|
+
const paramName = extractForOfParamName(node.left);
|
|
915
|
+
const llmCall = findLLMCallExpression(node.body);
|
|
916
|
+
if (!llmCall) {
|
|
917
|
+
return this.transformForOfToSequential(path, node);
|
|
918
|
+
}
|
|
919
|
+
const callInfo = this.batchDetector.extractCallInfo(llmCall);
|
|
920
|
+
if (!callInfo) {
|
|
921
|
+
return this.transformForOfToSequential(path, node);
|
|
922
|
+
}
|
|
923
|
+
const payloadNode = this.batchDetector.extractPayloadNode(llmCall);
|
|
924
|
+
if (!payloadNode) {
|
|
925
|
+
return this.transformForOfToSequential(path, node);
|
|
926
|
+
}
|
|
927
|
+
const batchCallsArray = t7.callExpression(t7.memberExpression(right, t7.identifier("map")), [
|
|
928
|
+
t7.arrowFunctionExpression([
|
|
929
|
+
t7.identifier(paramName)
|
|
930
|
+
], t7.objectExpression([
|
|
931
|
+
t7.objectProperty(t7.identifier("type"), t7.stringLiteral(callInfo.type)),
|
|
932
|
+
t7.objectProperty(t7.identifier("operation"), t7.stringLiteral(callInfo.operation)),
|
|
933
|
+
t7.objectProperty(t7.identifier("payload"), payloadNode)
|
|
934
|
+
]))
|
|
935
|
+
]);
|
|
936
|
+
const batchCall = t7.awaitExpression(t7.callExpression(t7.memberExpression(t7.identifier("__runtime"), t7.identifier("batchParallel")), [
|
|
937
|
+
batchCallsArray,
|
|
938
|
+
t7.stringLiteral(loopId)
|
|
939
|
+
]));
|
|
940
|
+
path.replaceWith(t7.expressionStatement(batchCall));
|
|
941
|
+
this.transformCount++;
|
|
942
|
+
return true;
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Transform for...of to sequential with checkpoints (fallback)
|
|
946
|
+
*/
|
|
947
|
+
transformForOfToSequential(path, node) {
|
|
948
|
+
const loopId = generateUniqueId("for_of");
|
|
949
|
+
const right = node.right;
|
|
950
|
+
const paramName = extractForOfParamName(node.left);
|
|
951
|
+
const bodyStatements = t7.isBlockStatement(node.body) ? node.body.body : [
|
|
952
|
+
node.body
|
|
953
|
+
];
|
|
954
|
+
const callbackFn = t7.arrowFunctionExpression([
|
|
955
|
+
t7.identifier(paramName),
|
|
956
|
+
t7.identifier("__index")
|
|
957
|
+
], t7.blockStatement(bodyStatements), true);
|
|
958
|
+
const runtimeCall = t7.awaitExpression(t7.callExpression(t7.memberExpression(t7.identifier("__runtime"), t7.identifier("resumableForOf")), [
|
|
959
|
+
right,
|
|
960
|
+
callbackFn,
|
|
961
|
+
t7.stringLiteral(loopId)
|
|
962
|
+
]));
|
|
963
|
+
path.replaceWith(t7.expressionStatement(runtimeCall));
|
|
964
|
+
this.transformCount++;
|
|
965
|
+
return true;
|
|
966
|
+
}
|
|
967
|
+
transformWhileLoop(path) {
|
|
968
|
+
const node = path.node;
|
|
969
|
+
if (!containsAwait(node.body)) {
|
|
970
|
+
return false;
|
|
971
|
+
}
|
|
972
|
+
const loopId = generateUniqueId("while");
|
|
973
|
+
const conditionFn = t7.arrowFunctionExpression([], node.test, false);
|
|
974
|
+
const bodyStatements = t7.isBlockStatement(node.body) ? node.body.body : [
|
|
975
|
+
node.body
|
|
976
|
+
];
|
|
977
|
+
const bodyFn = t7.arrowFunctionExpression([
|
|
978
|
+
t7.identifier("__iteration")
|
|
979
|
+
], t7.blockStatement(bodyStatements), true);
|
|
980
|
+
const runtimeCall = t7.awaitExpression(t7.callExpression(t7.memberExpression(t7.identifier("__runtime"), t7.identifier("resumableWhile")), [
|
|
981
|
+
conditionFn,
|
|
982
|
+
bodyFn,
|
|
983
|
+
t7.stringLiteral(loopId)
|
|
984
|
+
]));
|
|
985
|
+
path.replaceWith(t7.expressionStatement(runtimeCall));
|
|
986
|
+
this.transformCount++;
|
|
987
|
+
return true;
|
|
988
|
+
}
|
|
989
|
+
transformForLoop(path) {
|
|
990
|
+
const node = path.node;
|
|
991
|
+
if (!containsAwait(node.body)) {
|
|
992
|
+
return false;
|
|
993
|
+
}
|
|
994
|
+
if (!node.init || !node.test || !node.update) {
|
|
995
|
+
return false;
|
|
996
|
+
}
|
|
997
|
+
const loopId = generateUniqueId("for");
|
|
998
|
+
let initValue = t7.numericLiteral(0);
|
|
999
|
+
let loopVar = "__i";
|
|
1000
|
+
if (t7.isVariableDeclaration(node.init)) {
|
|
1001
|
+
const decl = node.init.declarations[0];
|
|
1002
|
+
if (decl && t7.isIdentifier(decl.id) && decl.init) {
|
|
1003
|
+
loopVar = decl.id.name;
|
|
1004
|
+
initValue = decl.init;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
const conditionFn = t7.arrowFunctionExpression([
|
|
1008
|
+
t7.identifier(loopVar)
|
|
1009
|
+
], node.test, false);
|
|
1010
|
+
const bodyStatements = t7.isBlockStatement(node.body) ? node.body.body : [
|
|
1011
|
+
node.body
|
|
1012
|
+
];
|
|
1013
|
+
const bodyFn = t7.arrowFunctionExpression([
|
|
1014
|
+
t7.identifier(loopVar)
|
|
1015
|
+
], t7.blockStatement(bodyStatements), true);
|
|
1016
|
+
let incrementFn;
|
|
1017
|
+
if (t7.isUpdateExpression(node.update)) {
|
|
1018
|
+
if (node.update.operator === "++") {
|
|
1019
|
+
incrementFn = t7.arrowFunctionExpression([
|
|
1020
|
+
t7.identifier(loopVar)
|
|
1021
|
+
], t7.binaryExpression("+", t7.identifier(loopVar), t7.numericLiteral(1)), false);
|
|
1022
|
+
} else if (node.update.operator === "--") {
|
|
1023
|
+
incrementFn = t7.arrowFunctionExpression([
|
|
1024
|
+
t7.identifier(loopVar)
|
|
1025
|
+
], t7.binaryExpression("-", t7.identifier(loopVar), t7.numericLiteral(1)), false);
|
|
1026
|
+
} else {
|
|
1027
|
+
return false;
|
|
1028
|
+
}
|
|
1029
|
+
} else {
|
|
1030
|
+
return false;
|
|
1031
|
+
}
|
|
1032
|
+
const runtimeCall = t7.awaitExpression(t7.callExpression(t7.memberExpression(t7.identifier("__runtime"), t7.identifier("resumableForLoop")), [
|
|
1033
|
+
initValue,
|
|
1034
|
+
conditionFn,
|
|
1035
|
+
incrementFn,
|
|
1036
|
+
bodyFn,
|
|
1037
|
+
t7.stringLiteral(loopId)
|
|
1038
|
+
]));
|
|
1039
|
+
path.replaceWith(t7.expressionStatement(runtimeCall));
|
|
1040
|
+
this.transformCount++;
|
|
1041
|
+
return true;
|
|
1042
|
+
}
|
|
1043
|
+
getTransformCount() {
|
|
1044
|
+
return this.transformCount;
|
|
1045
|
+
}
|
|
1046
|
+
resetTransformCount() {
|
|
1047
|
+
this.transformCount = 0;
|
|
1048
|
+
}
|
|
1049
|
+
};
|
|
1050
|
+
function wrapFilterResult(batchCall, array, methodId) {
|
|
1051
|
+
const resultsVar = `__filter_results_${methodId}`;
|
|
1052
|
+
const indexVar = `__i_${methodId}`;
|
|
1053
|
+
const arrayClone = t7.cloneNode(array, true);
|
|
1054
|
+
return t7.awaitExpression(t7.callExpression(t7.arrowFunctionExpression([], t7.blockStatement([
|
|
1055
|
+
t7.variableDeclaration("const", [
|
|
1056
|
+
t7.variableDeclarator(t7.identifier(resultsVar), batchCall.argument)
|
|
1057
|
+
]),
|
|
1058
|
+
t7.returnStatement(t7.callExpression(t7.memberExpression(arrayClone, t7.identifier("filter")), [
|
|
1059
|
+
t7.arrowFunctionExpression([
|
|
1060
|
+
t7.identifier("_"),
|
|
1061
|
+
t7.identifier(indexVar)
|
|
1062
|
+
], t7.callExpression(t7.identifier("Boolean"), [
|
|
1063
|
+
t7.memberExpression(t7.identifier(resultsVar), t7.identifier(indexVar), true)
|
|
1064
|
+
]))
|
|
1065
|
+
]))
|
|
1066
|
+
]), true), []));
|
|
1067
|
+
}
|
|
1068
|
+
__name(wrapFilterResult, "wrapFilterResult");
|
|
1069
|
+
function wrapFindResult(batchCall, array, methodId) {
|
|
1070
|
+
const resultsVar = `__find_results_${methodId}`;
|
|
1071
|
+
const arrayClone = t7.cloneNode(array, true);
|
|
1072
|
+
return t7.awaitExpression(t7.callExpression(t7.arrowFunctionExpression([], t7.blockStatement([
|
|
1073
|
+
t7.variableDeclaration("const", [
|
|
1074
|
+
t7.variableDeclarator(t7.identifier(resultsVar), batchCall.argument)
|
|
1075
|
+
]),
|
|
1076
|
+
t7.returnStatement(t7.callExpression(t7.memberExpression(arrayClone, t7.identifier("find")), [
|
|
1077
|
+
t7.arrowFunctionExpression([
|
|
1078
|
+
t7.identifier("_"),
|
|
1079
|
+
t7.identifier("__i")
|
|
1080
|
+
], t7.callExpression(t7.identifier("Boolean"), [
|
|
1081
|
+
t7.memberExpression(t7.identifier(resultsVar), t7.identifier("__i"), true)
|
|
1082
|
+
]))
|
|
1083
|
+
]))
|
|
1084
|
+
]), true), []));
|
|
1085
|
+
}
|
|
1086
|
+
__name(wrapFindResult, "wrapFindResult");
|
|
1087
|
+
function wrapSomeResult(batchCall, methodId) {
|
|
1088
|
+
const resultsVar = `__some_results_${methodId}`;
|
|
1089
|
+
return t7.awaitExpression(t7.callExpression(t7.arrowFunctionExpression([], t7.blockStatement([
|
|
1090
|
+
t7.variableDeclaration("const", [
|
|
1091
|
+
t7.variableDeclarator(t7.identifier(resultsVar), batchCall.argument)
|
|
1092
|
+
]),
|
|
1093
|
+
t7.returnStatement(t7.callExpression(t7.memberExpression(t7.identifier(resultsVar), t7.identifier("some")), [
|
|
1094
|
+
t7.arrowFunctionExpression([
|
|
1095
|
+
t7.identifier("r")
|
|
1096
|
+
], t7.callExpression(t7.identifier("Boolean"), [
|
|
1097
|
+
t7.identifier("r")
|
|
1098
|
+
]))
|
|
1099
|
+
]))
|
|
1100
|
+
]), true), []));
|
|
1101
|
+
}
|
|
1102
|
+
__name(wrapSomeResult, "wrapSomeResult");
|
|
1103
|
+
function wrapEveryResult(batchCall, methodId) {
|
|
1104
|
+
const resultsVar = `__every_results_${methodId}`;
|
|
1105
|
+
return t7.awaitExpression(t7.callExpression(t7.arrowFunctionExpression([], t7.blockStatement([
|
|
1106
|
+
t7.variableDeclaration("const", [
|
|
1107
|
+
t7.variableDeclarator(t7.identifier(resultsVar), batchCall.argument)
|
|
1108
|
+
]),
|
|
1109
|
+
t7.returnStatement(t7.callExpression(t7.memberExpression(t7.identifier(resultsVar), t7.identifier("every")), [
|
|
1110
|
+
t7.arrowFunctionExpression([
|
|
1111
|
+
t7.identifier("r")
|
|
1112
|
+
], t7.callExpression(t7.identifier("Boolean"), [
|
|
1113
|
+
t7.identifier("r")
|
|
1114
|
+
]))
|
|
1115
|
+
]))
|
|
1116
|
+
]), true), []));
|
|
1117
|
+
}
|
|
1118
|
+
__name(wrapEveryResult, "wrapEveryResult");
|
|
1119
|
+
function wrapBatchResultIfNeeded(batchCall, methodName, array, methodId) {
|
|
1120
|
+
switch (methodName) {
|
|
1121
|
+
case "filter":
|
|
1122
|
+
return wrapFilterResult(batchCall, array, methodId);
|
|
1123
|
+
case "find":
|
|
1124
|
+
return wrapFindResult(batchCall, array, methodId);
|
|
1125
|
+
case "some":
|
|
1126
|
+
return wrapSomeResult(batchCall, methodId);
|
|
1127
|
+
case "every":
|
|
1128
|
+
return wrapEveryResult(batchCall, methodId);
|
|
1129
|
+
case "forEach":
|
|
1130
|
+
return batchCall;
|
|
1131
|
+
default:
|
|
1132
|
+
return batchCall;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
__name(wrapBatchResultIfNeeded, "wrapBatchResultIfNeeded");
|
|
1136
|
+
|
|
1137
|
+
// src/transformer/array-transformer-batch.ts
|
|
1138
|
+
function extractBatchCallInfo(callback, batchDetector) {
|
|
1139
|
+
const paramName = callback.params[0];
|
|
1140
|
+
if (!t7.isIdentifier(paramName)) {
|
|
1141
|
+
return null;
|
|
1142
|
+
}
|
|
1143
|
+
const param = paramName.name;
|
|
1144
|
+
const llmCall = findLLMCallExpression(callback.body);
|
|
1145
|
+
if (!llmCall) {
|
|
1146
|
+
return null;
|
|
1147
|
+
}
|
|
1148
|
+
const callInfo = batchDetector.extractCallInfo(llmCall);
|
|
1149
|
+
if (!callInfo) {
|
|
1150
|
+
return null;
|
|
1151
|
+
}
|
|
1152
|
+
const payloadNode = batchDetector.extractPayloadNode(llmCall);
|
|
1153
|
+
if (!payloadNode) {
|
|
1154
|
+
return null;
|
|
1155
|
+
}
|
|
1156
|
+
const mapperFunction = t7.arrowFunctionExpression([
|
|
1157
|
+
t7.identifier(param)
|
|
1158
|
+
], t7.objectExpression([
|
|
1159
|
+
t7.objectProperty(t7.identifier("type"), t7.stringLiteral(callInfo.type)),
|
|
1160
|
+
t7.objectProperty(t7.identifier("operation"), t7.stringLiteral(callInfo.operation)),
|
|
1161
|
+
t7.objectProperty(t7.identifier("payload"), payloadNode)
|
|
1162
|
+
]));
|
|
1163
|
+
return {
|
|
1164
|
+
mapperFunction
|
|
1165
|
+
};
|
|
1166
|
+
}
|
|
1167
|
+
__name(extractBatchCallInfo, "extractBatchCallInfo");
|
|
1168
|
+
function transformToBatchParallel(path, node, methodName, callback, batchDetector, onTransform, fallbackTransform) {
|
|
1169
|
+
const methodId = generateUniqueId(`${methodName}_batch`);
|
|
1170
|
+
const array = node.callee.object;
|
|
1171
|
+
const callInfo = extractBatchCallInfo(callback, batchDetector);
|
|
1172
|
+
if (!callInfo) {
|
|
1173
|
+
return fallbackTransform();
|
|
1174
|
+
}
|
|
1175
|
+
const batchCallsArray = t7.callExpression(t7.memberExpression(array, t7.identifier("map")), [
|
|
1176
|
+
callInfo.mapperFunction
|
|
1177
|
+
]);
|
|
1178
|
+
const batchCall = t7.awaitExpression(t7.callExpression(t7.memberExpression(t7.identifier("__runtime"), t7.identifier("batchParallel")), [
|
|
1179
|
+
batchCallsArray,
|
|
1180
|
+
t7.stringLiteral(methodId)
|
|
1181
|
+
]));
|
|
1182
|
+
const finalCall = wrapBatchResultIfNeeded(batchCall, methodName, array, methodId);
|
|
1183
|
+
path.replaceWith(finalCall);
|
|
1184
|
+
onTransform();
|
|
1185
|
+
return true;
|
|
1186
|
+
}
|
|
1187
|
+
__name(transformToBatchParallel, "transformToBatchParallel");
|
|
1188
|
+
function transformToSequential(path, node, methodName, callback, onTransform) {
|
|
1189
|
+
const runtimeMethod = getRuntimeMethodName(methodName);
|
|
1190
|
+
if (!runtimeMethod) {
|
|
1191
|
+
return false;
|
|
1192
|
+
}
|
|
1193
|
+
const methodId = generateUniqueId(methodName);
|
|
1194
|
+
const array = node.callee.object;
|
|
1195
|
+
const args = [
|
|
1196
|
+
array,
|
|
1197
|
+
callback,
|
|
1198
|
+
t7.stringLiteral(methodId)
|
|
1199
|
+
];
|
|
1200
|
+
if (methodName === "reduce" && node.arguments[1]) {
|
|
1201
|
+
args.push(node.arguments[1]);
|
|
1202
|
+
}
|
|
1203
|
+
const runtimeCall = t7.awaitExpression(t7.callExpression(t7.memberExpression(t7.identifier("__runtime"), t7.identifier(runtimeMethod)), args));
|
|
1204
|
+
path.replaceWith(runtimeCall);
|
|
1205
|
+
onTransform();
|
|
1206
|
+
return true;
|
|
1207
|
+
}
|
|
1208
|
+
__name(transformToSequential, "transformToSequential");
|
|
1209
|
+
|
|
1210
|
+
// src/transformer/array-transformer.ts
|
|
1211
|
+
var ArrayTransformer = class {
|
|
1212
|
+
static {
|
|
1213
|
+
__name(this, "ArrayTransformer");
|
|
1214
|
+
}
|
|
1215
|
+
transformCount = 0;
|
|
1216
|
+
batchOptimizer;
|
|
1217
|
+
batchDetector;
|
|
1218
|
+
batchSizeThreshold;
|
|
1219
|
+
constructor(batchSizeThreshold = 10) {
|
|
1220
|
+
this.batchOptimizer = new BatchOptimizer();
|
|
1221
|
+
this.batchDetector = new BatchParallelDetector();
|
|
1222
|
+
this.batchSizeThreshold = batchSizeThreshold;
|
|
1223
|
+
}
|
|
1224
|
+
transformArrayMethod(path) {
|
|
1225
|
+
const node = path.node;
|
|
1226
|
+
const methodName = getArrayMethodName(node);
|
|
1227
|
+
if (!methodName) {
|
|
1228
|
+
return false;
|
|
1229
|
+
}
|
|
1230
|
+
const callback = node.arguments[0];
|
|
1231
|
+
if (!callback || !t7.isFunction(callback) || !callback.async) {
|
|
1232
|
+
return false;
|
|
1233
|
+
}
|
|
1234
|
+
const batchResult = this.batchOptimizer.canBatchArrayMethod(callback);
|
|
1235
|
+
if (batchResult.canBatch && canUseBatchParallel(methodName)) {
|
|
1236
|
+
const array = node.callee.object;
|
|
1237
|
+
const decision = this.batchOptimizer.makeSmartBatchDecision(methodName, batchResult, array, this.batchSizeThreshold);
|
|
1238
|
+
if (decision.shouldBatch) {
|
|
1239
|
+
return transformToBatchParallel(path, node, methodName, callback, this.batchDetector, () => this.transformCount++, () => this.doTransformToSequential(path, node, methodName, callback));
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
return this.doTransformToSequential(path, node, methodName, callback);
|
|
1243
|
+
}
|
|
1244
|
+
doTransformToSequential(path, node, methodName, callback) {
|
|
1245
|
+
return transformToSequential(path, node, methodName, callback, () => this.transformCount++);
|
|
1246
|
+
}
|
|
1247
|
+
getTransformCount() {
|
|
1248
|
+
return this.transformCount;
|
|
1249
|
+
}
|
|
1250
|
+
resetTransformCount() {
|
|
1251
|
+
this.transformCount = 0;
|
|
1252
|
+
}
|
|
1253
|
+
};
|
|
1254
|
+
|
|
1255
|
+
// src/runtime/runtime-functions.ts
|
|
1256
|
+
var RuntimeFunction = {
|
|
1257
|
+
// Promise operations
|
|
1258
|
+
RESUMABLE_PROMISE_ALL: "resumablePromiseAll",
|
|
1259
|
+
RESUMABLE_PROMISE_ALL_SETTLED: "resumablePromiseAllSettled",
|
|
1260
|
+
BATCH_PARALLEL: "batchParallel",
|
|
1261
|
+
// Loop operations
|
|
1262
|
+
RESUMABLE_FOR_OF: "resumableForOf",
|
|
1263
|
+
RESUMABLE_FOR_LOOP: "resumableForLoop",
|
|
1264
|
+
RESUMABLE_WHILE: "resumableWhile",
|
|
1265
|
+
// Array method operations
|
|
1266
|
+
RESUMABLE_MAP: "resumableMap",
|
|
1267
|
+
RESUMABLE_FOR_EACH: "resumableForEach",
|
|
1268
|
+
RESUMABLE_FILTER: "resumableFilter",
|
|
1269
|
+
RESUMABLE_REDUCE: "resumableReduce",
|
|
1270
|
+
RESUMABLE_FIND: "resumableFind",
|
|
1271
|
+
RESUMABLE_SOME: "resumableSome",
|
|
1272
|
+
RESUMABLE_EVERY: "resumableEvery",
|
|
1273
|
+
RESUMABLE_FLAT_MAP: "resumableFlatMap"
|
|
1274
|
+
};
|
|
1275
|
+
var IN_ISOLATE_RUNTIME_FUNCTIONS = [
|
|
1276
|
+
RuntimeFunction.RESUMABLE_PROMISE_ALL,
|
|
1277
|
+
RuntimeFunction.RESUMABLE_PROMISE_ALL_SETTLED,
|
|
1278
|
+
RuntimeFunction.RESUMABLE_FOR_OF,
|
|
1279
|
+
RuntimeFunction.RESUMABLE_FOR_LOOP,
|
|
1280
|
+
RuntimeFunction.RESUMABLE_WHILE,
|
|
1281
|
+
RuntimeFunction.RESUMABLE_MAP,
|
|
1282
|
+
RuntimeFunction.RESUMABLE_FOR_EACH,
|
|
1283
|
+
RuntimeFunction.RESUMABLE_FILTER,
|
|
1284
|
+
RuntimeFunction.RESUMABLE_REDUCE,
|
|
1285
|
+
RuntimeFunction.RESUMABLE_FIND,
|
|
1286
|
+
RuntimeFunction.RESUMABLE_SOME,
|
|
1287
|
+
RuntimeFunction.RESUMABLE_EVERY,
|
|
1288
|
+
RuntimeFunction.RESUMABLE_FLAT_MAP
|
|
1289
|
+
];
|
|
1290
|
+
function isInIsolateRuntimeFunction(name) {
|
|
1291
|
+
return IN_ISOLATE_RUNTIME_FUNCTIONS.includes(name);
|
|
1292
|
+
}
|
|
1293
|
+
__name(isInIsolateRuntimeFunction, "isInIsolateRuntimeFunction");
|
|
1294
|
+
|
|
1295
|
+
// src/transformer/promise-transformer.ts
|
|
1296
|
+
var PromiseTransformer = class {
|
|
1297
|
+
static {
|
|
1298
|
+
__name(this, "PromiseTransformer");
|
|
1299
|
+
}
|
|
1300
|
+
transformCount = 0;
|
|
1301
|
+
batchDetector;
|
|
1302
|
+
enableBatchParallel;
|
|
1303
|
+
constructor(enableBatchParallel = true) {
|
|
1304
|
+
this.batchDetector = new BatchParallelDetector();
|
|
1305
|
+
this.enableBatchParallel = enableBatchParallel;
|
|
1306
|
+
}
|
|
1307
|
+
transformPromiseAll(path) {
|
|
1308
|
+
const node = path.node;
|
|
1309
|
+
if (!this.isPromiseAll(node)) {
|
|
1310
|
+
return false;
|
|
1311
|
+
}
|
|
1312
|
+
const arrayArg = node.arguments[0];
|
|
1313
|
+
if (this.enableBatchParallel && this.batchDetector.canBatch(node)) {
|
|
1314
|
+
return this.transformToBatchParallel(path, node);
|
|
1315
|
+
}
|
|
1316
|
+
if (t7.isArrayExpression(arrayArg)) {
|
|
1317
|
+
return this.transformToSequential(path, node);
|
|
1318
|
+
}
|
|
1319
|
+
return false;
|
|
1320
|
+
}
|
|
1321
|
+
transformPromiseAllSettled(path) {
|
|
1322
|
+
const node = path.node;
|
|
1323
|
+
if (!this.isPromiseAllSettled(node)) {
|
|
1324
|
+
return false;
|
|
1325
|
+
}
|
|
1326
|
+
const arrayArg = node.arguments[0];
|
|
1327
|
+
if (t7.isArrayExpression(arrayArg)) {
|
|
1328
|
+
const parallelId = generateUniqueId("allSettled");
|
|
1329
|
+
const runtimeCall = t7.awaitExpression(t7.callExpression(t7.memberExpression(t7.identifier("__runtime"), t7.identifier(RuntimeFunction.RESUMABLE_PROMISE_ALL_SETTLED)), [
|
|
1330
|
+
arrayArg,
|
|
1331
|
+
t7.stringLiteral(parallelId)
|
|
1332
|
+
]));
|
|
1333
|
+
path.replaceWith(runtimeCall);
|
|
1334
|
+
this.transformCount++;
|
|
1335
|
+
return true;
|
|
1336
|
+
}
|
|
1337
|
+
return false;
|
|
1338
|
+
}
|
|
1339
|
+
transformToBatchParallel(path, node) {
|
|
1340
|
+
const arrayArg = node.arguments[0];
|
|
1341
|
+
if (!t7.isArrayExpression(arrayArg)) {
|
|
1342
|
+
return false;
|
|
1343
|
+
}
|
|
1344
|
+
const batchId = generateUniqueId("batch");
|
|
1345
|
+
const batchCallsArray = t7.arrayExpression(arrayArg.elements.map((el) => {
|
|
1346
|
+
if (!el || t7.isSpreadElement(el)) {
|
|
1347
|
+
return t7.nullLiteral();
|
|
1348
|
+
}
|
|
1349
|
+
let callNode = el;
|
|
1350
|
+
if (t7.isAwaitExpression(callNode)) {
|
|
1351
|
+
callNode = callNode.argument;
|
|
1352
|
+
}
|
|
1353
|
+
if (!t7.isCallExpression(callNode) || !t7.isMemberExpression(callNode.callee)) {
|
|
1354
|
+
return t7.nullLiteral();
|
|
1355
|
+
}
|
|
1356
|
+
const callInfo = this.batchDetector.extractCallInfo(callNode);
|
|
1357
|
+
if (!callInfo) {
|
|
1358
|
+
return t7.nullLiteral();
|
|
1359
|
+
}
|
|
1360
|
+
const payloadArg = callNode.arguments[0];
|
|
1361
|
+
return t7.objectExpression([
|
|
1362
|
+
t7.objectProperty(t7.identifier("type"), t7.stringLiteral(callInfo.type)),
|
|
1363
|
+
t7.objectProperty(t7.identifier("operation"), t7.stringLiteral(callInfo.operation)),
|
|
1364
|
+
t7.objectProperty(t7.identifier("payload"), payloadArg && t7.isExpression(payloadArg) ? payloadArg : t7.objectExpression([]))
|
|
1365
|
+
]);
|
|
1366
|
+
}));
|
|
1367
|
+
const runtimeCall = t7.awaitExpression(t7.callExpression(t7.memberExpression(t7.identifier("__runtime"), t7.identifier(RuntimeFunction.BATCH_PARALLEL)), [
|
|
1368
|
+
batchCallsArray,
|
|
1369
|
+
t7.stringLiteral(batchId)
|
|
1370
|
+
]));
|
|
1371
|
+
path.replaceWith(runtimeCall);
|
|
1372
|
+
this.transformCount++;
|
|
1373
|
+
return true;
|
|
1374
|
+
}
|
|
1375
|
+
transformToSequential(path, node) {
|
|
1376
|
+
const arrayArg = node.arguments[0];
|
|
1377
|
+
if (!t7.isArrayExpression(arrayArg)) {
|
|
1378
|
+
return false;
|
|
1379
|
+
}
|
|
1380
|
+
const parallelId = generateUniqueId("parallel");
|
|
1381
|
+
const runtimeCall = t7.awaitExpression(t7.callExpression(t7.memberExpression(t7.identifier("__runtime"), t7.identifier(RuntimeFunction.RESUMABLE_PROMISE_ALL)), [
|
|
1382
|
+
arrayArg,
|
|
1383
|
+
t7.stringLiteral(parallelId)
|
|
1384
|
+
]));
|
|
1385
|
+
path.replaceWith(runtimeCall);
|
|
1386
|
+
this.transformCount++;
|
|
1387
|
+
return true;
|
|
1388
|
+
}
|
|
1389
|
+
payloadToExpression(payload) {
|
|
1390
|
+
const properties = [];
|
|
1391
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
1392
|
+
properties.push(t7.objectProperty(t7.identifier(key), this.valueToExpression(value)));
|
|
1393
|
+
}
|
|
1394
|
+
return t7.objectExpression(properties);
|
|
1395
|
+
}
|
|
1396
|
+
valueToExpression(value) {
|
|
1397
|
+
if (typeof value === "string") {
|
|
1398
|
+
return t7.stringLiteral(value);
|
|
1399
|
+
}
|
|
1400
|
+
if (typeof value === "number") {
|
|
1401
|
+
return t7.numericLiteral(value);
|
|
1402
|
+
}
|
|
1403
|
+
if (typeof value === "boolean") {
|
|
1404
|
+
return t7.booleanLiteral(value);
|
|
1405
|
+
}
|
|
1406
|
+
if (value === null) {
|
|
1407
|
+
return t7.nullLiteral();
|
|
1408
|
+
}
|
|
1409
|
+
if (Array.isArray(value)) {
|
|
1410
|
+
return t7.arrayExpression(value.map((v) => this.valueToExpression(v)));
|
|
1411
|
+
}
|
|
1412
|
+
if (typeof value === "object") {
|
|
1413
|
+
return this.payloadToExpression(value);
|
|
1414
|
+
}
|
|
1415
|
+
return t7.identifier("undefined");
|
|
1416
|
+
}
|
|
1417
|
+
isPromiseAll(node) {
|
|
1418
|
+
const callee = node.callee;
|
|
1419
|
+
return t7.isMemberExpression(callee) && t7.isIdentifier(callee.object, {
|
|
1420
|
+
name: "Promise"
|
|
1421
|
+
}) && t7.isIdentifier(callee.property, {
|
|
1422
|
+
name: "all"
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
isPromiseAllSettled(node) {
|
|
1426
|
+
const callee = node.callee;
|
|
1427
|
+
return t7.isMemberExpression(callee) && t7.isIdentifier(callee.object, {
|
|
1428
|
+
name: "Promise"
|
|
1429
|
+
}) && t7.isIdentifier(callee.property, {
|
|
1430
|
+
name: "allSettled"
|
|
1431
|
+
});
|
|
1432
|
+
}
|
|
1433
|
+
getTransformCount() {
|
|
1434
|
+
return this.transformCount;
|
|
1435
|
+
}
|
|
1436
|
+
resetTransformCount() {
|
|
1437
|
+
this.transformCount = 0;
|
|
1438
|
+
}
|
|
1439
|
+
};
|
|
1440
|
+
|
|
1441
|
+
// src/runtime/errors.ts
|
|
1442
|
+
var CheckpointOperation;
|
|
1443
|
+
(function(CheckpointOperation2) {
|
|
1444
|
+
CheckpointOperation2["SAVE"] = "save";
|
|
1445
|
+
CheckpointOperation2["LOAD"] = "load";
|
|
1446
|
+
CheckpointOperation2["CLEAR"] = "clear";
|
|
1447
|
+
})(CheckpointOperation || (CheckpointOperation = {}));
|
|
1448
|
+
var BatchPauseExecutionError = class extends Error {
|
|
1449
|
+
static {
|
|
1450
|
+
__name(this, "BatchPauseExecutionError");
|
|
1451
|
+
}
|
|
1452
|
+
calls;
|
|
1453
|
+
batchId;
|
|
1454
|
+
sequenceNumber;
|
|
1455
|
+
constructor(calls, batchId, sequenceNumber) {
|
|
1456
|
+
super(`Batch pause for parallel execution (${calls.length} callbacks)`);
|
|
1457
|
+
this.name = "BatchPauseExecutionError";
|
|
1458
|
+
this.calls = calls;
|
|
1459
|
+
this.batchId = batchId;
|
|
1460
|
+
this.sequenceNumber = sequenceNumber;
|
|
1461
|
+
}
|
|
1462
|
+
};
|
|
1463
|
+
var CheckpointError = class extends Error {
|
|
1464
|
+
static {
|
|
1465
|
+
__name(this, "CheckpointError");
|
|
1466
|
+
}
|
|
1467
|
+
checkpointId;
|
|
1468
|
+
operation;
|
|
1469
|
+
constructor(message, checkpointId, operation) {
|
|
1470
|
+
super(`Checkpoint ${operation} failed for ${checkpointId}: ${message}`);
|
|
1471
|
+
this.name = "CheckpointError";
|
|
1472
|
+
this.checkpointId = checkpointId;
|
|
1473
|
+
this.operation = operation;
|
|
1474
|
+
}
|
|
1475
|
+
};
|
|
1476
|
+
var TransformationError = class extends Error {
|
|
1477
|
+
static {
|
|
1478
|
+
__name(this, "TransformationError");
|
|
1479
|
+
}
|
|
1480
|
+
code;
|
|
1481
|
+
pattern;
|
|
1482
|
+
location;
|
|
1483
|
+
constructor(message, code, pattern, location) {
|
|
1484
|
+
const loc = location ? ` at line ${location.line}:${location.column}` : "";
|
|
1485
|
+
super(`Transformation failed for ${pattern}${loc}: ${message}`);
|
|
1486
|
+
this.name = "TransformationError";
|
|
1487
|
+
this.code = code;
|
|
1488
|
+
this.pattern = pattern;
|
|
1489
|
+
this.location = location;
|
|
1490
|
+
}
|
|
1491
|
+
};
|
|
1492
|
+
var InfiniteLoopDetectionError = class extends Error {
|
|
1493
|
+
static {
|
|
1494
|
+
__name(this, "InfiniteLoopDetectionError");
|
|
1495
|
+
}
|
|
1496
|
+
loopId;
|
|
1497
|
+
iterationCount;
|
|
1498
|
+
constructor(loopId, iterationCount) {
|
|
1499
|
+
super(`Infinite loop detected: ${loopId} exceeded ${iterationCount} iterations without completing`);
|
|
1500
|
+
this.name = "InfiniteLoopDetectionError";
|
|
1501
|
+
this.loopId = loopId;
|
|
1502
|
+
this.iterationCount = iterationCount;
|
|
1503
|
+
}
|
|
1504
|
+
};
|
|
1505
|
+
function isBatchPauseError(error) {
|
|
1506
|
+
return error instanceof BatchPauseExecutionError;
|
|
1507
|
+
}
|
|
1508
|
+
__name(isBatchPauseError, "isBatchPauseError");
|
|
1509
|
+
function isCheckpointError(error) {
|
|
1510
|
+
return error instanceof CheckpointError;
|
|
1511
|
+
}
|
|
1512
|
+
__name(isCheckpointError, "isCheckpointError");
|
|
1513
|
+
function isTransformationError(error) {
|
|
1514
|
+
return error instanceof TransformationError;
|
|
1515
|
+
}
|
|
1516
|
+
__name(isTransformationError, "isTransformationError");
|
|
1517
|
+
|
|
1518
|
+
// src/transformer/index.ts
|
|
1519
|
+
var traverse2 = _traverse.default || _traverse;
|
|
1520
|
+
var generate = _generate.default || _generate;
|
|
1521
|
+
var ATPCompiler = class {
|
|
1522
|
+
static {
|
|
1523
|
+
__name(this, "ATPCompiler");
|
|
1524
|
+
}
|
|
1525
|
+
config;
|
|
1526
|
+
detector;
|
|
1527
|
+
loopTransformer;
|
|
1528
|
+
arrayTransformer;
|
|
1529
|
+
promiseTransformer;
|
|
1530
|
+
constructor(config = {}) {
|
|
1531
|
+
this.config = {
|
|
1532
|
+
...DEFAULT_COMPILER_CONFIG,
|
|
1533
|
+
...config
|
|
1534
|
+
};
|
|
1535
|
+
this.detector = new AsyncIterationDetector();
|
|
1536
|
+
this.loopTransformer = new LoopTransformer(this.config.batchSizeThreshold);
|
|
1537
|
+
this.arrayTransformer = new ArrayTransformer(this.config.batchSizeThreshold);
|
|
1538
|
+
this.promiseTransformer = new PromiseTransformer(this.config.enableBatchParallel);
|
|
1539
|
+
}
|
|
1540
|
+
detect(code) {
|
|
1541
|
+
return this.detector.detect(code);
|
|
1542
|
+
}
|
|
1543
|
+
transform(code) {
|
|
1544
|
+
resetIdCounter();
|
|
1545
|
+
const detection = this.detector.detect(code);
|
|
1546
|
+
if (!detection.needsTransform) {
|
|
1547
|
+
return {
|
|
1548
|
+
code,
|
|
1549
|
+
transformed: false,
|
|
1550
|
+
patterns: [],
|
|
1551
|
+
metadata: {
|
|
1552
|
+
loopCount: 0,
|
|
1553
|
+
arrayMethodCount: 0,
|
|
1554
|
+
parallelCallCount: 0,
|
|
1555
|
+
batchableCount: 0
|
|
1556
|
+
}
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1559
|
+
try {
|
|
1560
|
+
const ast = parse(code, {
|
|
1561
|
+
sourceType: "module",
|
|
1562
|
+
plugins: [
|
|
1563
|
+
"typescript"
|
|
1564
|
+
],
|
|
1565
|
+
allowAwaitOutsideFunction: true,
|
|
1566
|
+
allowReturnOutsideFunction: true
|
|
1567
|
+
});
|
|
1568
|
+
this.loopTransformer.resetTransformCount();
|
|
1569
|
+
this.arrayTransformer.resetTransformCount();
|
|
1570
|
+
this.promiseTransformer.resetTransformCount();
|
|
1571
|
+
traverse2(ast, {
|
|
1572
|
+
ForOfStatement: /* @__PURE__ */ __name((path) => {
|
|
1573
|
+
this.loopTransformer.transformForOfLoop(path);
|
|
1574
|
+
}, "ForOfStatement"),
|
|
1575
|
+
WhileStatement: /* @__PURE__ */ __name((path) => {
|
|
1576
|
+
this.loopTransformer.transformWhileLoop(path);
|
|
1577
|
+
}, "WhileStatement"),
|
|
1578
|
+
ForStatement: /* @__PURE__ */ __name((path) => {
|
|
1579
|
+
this.loopTransformer.transformForLoop(path);
|
|
1580
|
+
}, "ForStatement"),
|
|
1581
|
+
CallExpression: /* @__PURE__ */ __name((path) => {
|
|
1582
|
+
if (this.isArrayMethodCall(path.node)) {
|
|
1583
|
+
this.arrayTransformer.transformArrayMethod(path);
|
|
1584
|
+
} else if (this.isPromiseAllCall(path.node)) {
|
|
1585
|
+
this.promiseTransformer.transformPromiseAll(path);
|
|
1586
|
+
} else if (this.isPromiseAllSettledCall(path.node)) {
|
|
1587
|
+
this.promiseTransformer.transformPromiseAllSettled(path);
|
|
1588
|
+
}
|
|
1589
|
+
}, "CallExpression")
|
|
1590
|
+
});
|
|
1591
|
+
const output = generate(ast, {
|
|
1592
|
+
sourceMaps: false,
|
|
1593
|
+
retainLines: true,
|
|
1594
|
+
comments: true
|
|
1595
|
+
});
|
|
1596
|
+
const metadata = {
|
|
1597
|
+
loopCount: this.loopTransformer.getTransformCount(),
|
|
1598
|
+
arrayMethodCount: this.arrayTransformer.getTransformCount(),
|
|
1599
|
+
parallelCallCount: this.promiseTransformer.getTransformCount(),
|
|
1600
|
+
batchableCount: detection.batchableParallel ? 1 : 0
|
|
1601
|
+
};
|
|
1602
|
+
return {
|
|
1603
|
+
code: output.code,
|
|
1604
|
+
transformed: true,
|
|
1605
|
+
patterns: detection.patterns,
|
|
1606
|
+
metadata
|
|
1607
|
+
};
|
|
1608
|
+
} catch (error) {
|
|
1609
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1610
|
+
throw new TransformationError(message, code, "unknown");
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
isArrayMethodCall(node) {
|
|
1614
|
+
if (!t7.isMemberExpression(node.callee)) {
|
|
1615
|
+
return false;
|
|
1616
|
+
}
|
|
1617
|
+
const property = node.callee.property;
|
|
1618
|
+
if (!t7.isIdentifier(property)) {
|
|
1619
|
+
return false;
|
|
1620
|
+
}
|
|
1621
|
+
const arrayMethods = [
|
|
1622
|
+
"map",
|
|
1623
|
+
"forEach",
|
|
1624
|
+
"filter",
|
|
1625
|
+
"reduce",
|
|
1626
|
+
"find",
|
|
1627
|
+
"some",
|
|
1628
|
+
"every",
|
|
1629
|
+
"flatMap"
|
|
1630
|
+
];
|
|
1631
|
+
return arrayMethods.includes(property.name);
|
|
1632
|
+
}
|
|
1633
|
+
isPromiseAllCall(node) {
|
|
1634
|
+
const callee = node.callee;
|
|
1635
|
+
return t7.isMemberExpression(callee) && t7.isIdentifier(callee.object, {
|
|
1636
|
+
name: "Promise"
|
|
1637
|
+
}) && t7.isIdentifier(callee.property, {
|
|
1638
|
+
name: "all"
|
|
1639
|
+
});
|
|
1640
|
+
}
|
|
1641
|
+
isPromiseAllSettledCall(node) {
|
|
1642
|
+
const callee = node.callee;
|
|
1643
|
+
return t7.isMemberExpression(callee) && t7.isIdentifier(callee.object, {
|
|
1644
|
+
name: "Promise"
|
|
1645
|
+
}) && t7.isIdentifier(callee.property, {
|
|
1646
|
+
name: "allSettled"
|
|
1647
|
+
});
|
|
1648
|
+
}
|
|
1649
|
+
/**
|
|
1650
|
+
* Get the compiler type identifier (ICompiler interface requirement)
|
|
1651
|
+
*/
|
|
1652
|
+
getType() {
|
|
1653
|
+
return "ATPCompiler";
|
|
1654
|
+
}
|
|
1655
|
+
/**
|
|
1656
|
+
* Get cache statistics (ICompiler interface requirement)
|
|
1657
|
+
* ATPCompiler doesn't cache ASTs, so returns null
|
|
1658
|
+
*/
|
|
1659
|
+
getCacheStats() {
|
|
1660
|
+
return null;
|
|
1661
|
+
}
|
|
1662
|
+
};
|
|
1663
|
+
|
|
1664
|
+
// src/runtime/checkpoint-manager.ts
|
|
1665
|
+
var MAX_CHECKPOINT_SIZE = 10 * 1024 * 1024;
|
|
1666
|
+
var CHECKPOINT_TTL = 3600;
|
|
1667
|
+
var CheckpointManager = class {
|
|
1668
|
+
static {
|
|
1669
|
+
__name(this, "CheckpointManager");
|
|
1670
|
+
}
|
|
1671
|
+
cache;
|
|
1672
|
+
executionId;
|
|
1673
|
+
prefix;
|
|
1674
|
+
constructor(executionId, cache, prefix = "checkpoint") {
|
|
1675
|
+
this.executionId = executionId;
|
|
1676
|
+
this.cache = cache;
|
|
1677
|
+
this.prefix = prefix;
|
|
1678
|
+
}
|
|
1679
|
+
async save(checkpoint) {
|
|
1680
|
+
const key = this.getKey(checkpoint.loopId);
|
|
1681
|
+
try {
|
|
1682
|
+
const serialized = JSON.stringify(checkpoint);
|
|
1683
|
+
if (serialized.length > MAX_CHECKPOINT_SIZE) {
|
|
1684
|
+
throw new CheckpointError(`Checkpoint size ${serialized.length} exceeds maximum ${MAX_CHECKPOINT_SIZE}`, checkpoint.loopId, CheckpointOperation.SAVE);
|
|
1685
|
+
}
|
|
1686
|
+
await this.cache.set(key, checkpoint, CHECKPOINT_TTL);
|
|
1687
|
+
} catch (error) {
|
|
1688
|
+
if (error instanceof CheckpointError) {
|
|
1689
|
+
throw error;
|
|
1690
|
+
}
|
|
1691
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1692
|
+
throw new CheckpointError(message, checkpoint.loopId, CheckpointOperation.SAVE);
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
async load(loopId) {
|
|
1696
|
+
const key = this.getKey(loopId);
|
|
1697
|
+
try {
|
|
1698
|
+
const checkpoint = await this.cache.get(key);
|
|
1699
|
+
if (!checkpoint) {
|
|
1700
|
+
return null;
|
|
1701
|
+
}
|
|
1702
|
+
if (checkpoint.completed && checkpoint.completed instanceof Array) {
|
|
1703
|
+
checkpoint.completed = new Set(checkpoint.completed);
|
|
1704
|
+
}
|
|
1705
|
+
return checkpoint;
|
|
1706
|
+
} catch (error) {
|
|
1707
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1708
|
+
throw new CheckpointError(message, loopId, CheckpointOperation.LOAD);
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
async clear(loopId) {
|
|
1712
|
+
const key = this.getKey(loopId);
|
|
1713
|
+
try {
|
|
1714
|
+
await this.cache.delete(key);
|
|
1715
|
+
} catch (error) {
|
|
1716
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1717
|
+
throw new CheckpointError(message, loopId, CheckpointOperation.CLEAR);
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
async clearAll() {
|
|
1721
|
+
}
|
|
1722
|
+
getKey(loopId) {
|
|
1723
|
+
return `${this.prefix}:${this.executionId}:${loopId}`;
|
|
1724
|
+
}
|
|
1725
|
+
getExecutionId() {
|
|
1726
|
+
return this.executionId;
|
|
1727
|
+
}
|
|
1728
|
+
};
|
|
1729
|
+
var globalCheckpointManager = null;
|
|
1730
|
+
function setCheckpointManager(manager) {
|
|
1731
|
+
globalCheckpointManager = manager;
|
|
1732
|
+
}
|
|
1733
|
+
__name(setCheckpointManager, "setCheckpointManager");
|
|
1734
|
+
function getCheckpointManager() {
|
|
1735
|
+
if (!globalCheckpointManager) {
|
|
1736
|
+
throw new Error("CheckpointManager not initialized");
|
|
1737
|
+
}
|
|
1738
|
+
return globalCheckpointManager;
|
|
1739
|
+
}
|
|
1740
|
+
__name(getCheckpointManager, "getCheckpointManager");
|
|
1741
|
+
function clearCheckpointManager() {
|
|
1742
|
+
globalCheckpointManager = null;
|
|
1743
|
+
}
|
|
1744
|
+
__name(clearCheckpointManager, "clearCheckpointManager");
|
|
1745
|
+
function hasCheckpointManager() {
|
|
1746
|
+
return globalCheckpointManager !== null;
|
|
1747
|
+
}
|
|
1748
|
+
__name(hasCheckpointManager, "hasCheckpointManager");
|
|
1749
|
+
|
|
1750
|
+
// src/runtime/resumable-loops.ts
|
|
1751
|
+
var MAX_ITERATIONS = 1e6;
|
|
1752
|
+
async function resumableForOf(items, callback, loopId) {
|
|
1753
|
+
const checkpointManager = getCheckpointManager();
|
|
1754
|
+
const checkpoint = await checkpointManager.load(loopId);
|
|
1755
|
+
const startIndex = checkpoint?.currentIndex || 0;
|
|
1756
|
+
for (let i = startIndex; i < items.length; i++) {
|
|
1757
|
+
if (i > MAX_ITERATIONS) {
|
|
1758
|
+
throw new InfiniteLoopDetectionError(loopId, i);
|
|
1759
|
+
}
|
|
1760
|
+
await callback(items[i], i);
|
|
1761
|
+
const newCheckpoint = {
|
|
1762
|
+
loopId,
|
|
1763
|
+
currentIndex: i + 1,
|
|
1764
|
+
timestamp: Date.now()
|
|
1765
|
+
};
|
|
1766
|
+
await checkpointManager.save(newCheckpoint);
|
|
1767
|
+
}
|
|
1768
|
+
await checkpointManager.clear(loopId);
|
|
1769
|
+
}
|
|
1770
|
+
__name(resumableForOf, "resumableForOf");
|
|
1771
|
+
async function resumableWhile(conditionFn, bodyFn, loopId) {
|
|
1772
|
+
const checkpointManager = getCheckpointManager();
|
|
1773
|
+
const checkpoint = await checkpointManager.load(loopId);
|
|
1774
|
+
let iteration = checkpoint?.currentIndex || 0;
|
|
1775
|
+
while (await Promise.resolve(conditionFn())) {
|
|
1776
|
+
if (iteration > MAX_ITERATIONS) {
|
|
1777
|
+
throw new InfiniteLoopDetectionError(loopId, iteration);
|
|
1778
|
+
}
|
|
1779
|
+
await bodyFn(iteration);
|
|
1780
|
+
const newCheckpoint = {
|
|
1781
|
+
loopId,
|
|
1782
|
+
currentIndex: iteration + 1,
|
|
1783
|
+
timestamp: Date.now()
|
|
1784
|
+
};
|
|
1785
|
+
await checkpointManager.save(newCheckpoint);
|
|
1786
|
+
iteration++;
|
|
1787
|
+
}
|
|
1788
|
+
await checkpointManager.clear(loopId);
|
|
1789
|
+
}
|
|
1790
|
+
__name(resumableWhile, "resumableWhile");
|
|
1791
|
+
async function resumableForLoop(initValue, conditionFn, incrementFn, bodyFn, loopId) {
|
|
1792
|
+
const checkpointManager = getCheckpointManager();
|
|
1793
|
+
const checkpoint = await checkpointManager.load(loopId);
|
|
1794
|
+
let i = checkpoint?.currentIndex !== void 0 ? checkpoint.currentIndex : initValue;
|
|
1795
|
+
let iterations = 0;
|
|
1796
|
+
while (conditionFn(i)) {
|
|
1797
|
+
if (iterations++ > MAX_ITERATIONS) {
|
|
1798
|
+
throw new InfiniteLoopDetectionError(loopId, iterations);
|
|
1799
|
+
}
|
|
1800
|
+
await bodyFn(i);
|
|
1801
|
+
const newCheckpoint = {
|
|
1802
|
+
loopId,
|
|
1803
|
+
currentIndex: incrementFn(i),
|
|
1804
|
+
timestamp: Date.now()
|
|
1805
|
+
};
|
|
1806
|
+
await checkpointManager.save(newCheckpoint);
|
|
1807
|
+
i = incrementFn(i);
|
|
1808
|
+
}
|
|
1809
|
+
await checkpointManager.clear(loopId);
|
|
1810
|
+
}
|
|
1811
|
+
__name(resumableForLoop, "resumableForLoop");
|
|
1812
|
+
|
|
1813
|
+
// src/runtime/resumable-arrays.ts
|
|
1814
|
+
var MAX_ITERATIONS2 = 1e6;
|
|
1815
|
+
async function resumableMap(items, callback, mapId) {
|
|
1816
|
+
const checkpointManager = getCheckpointManager();
|
|
1817
|
+
const checkpoint = await checkpointManager.load(mapId);
|
|
1818
|
+
const startIndex = checkpoint?.currentIndex || 0;
|
|
1819
|
+
const results = checkpoint?.results || [];
|
|
1820
|
+
for (let i = startIndex; i < items.length; i++) {
|
|
1821
|
+
if (i > MAX_ITERATIONS2) {
|
|
1822
|
+
throw new InfiniteLoopDetectionError(mapId, i);
|
|
1823
|
+
}
|
|
1824
|
+
results[i] = await callback(items[i], i, items);
|
|
1825
|
+
const newCheckpoint = {
|
|
1826
|
+
loopId: mapId,
|
|
1827
|
+
currentIndex: i + 1,
|
|
1828
|
+
results,
|
|
1829
|
+
timestamp: Date.now()
|
|
1830
|
+
};
|
|
1831
|
+
await checkpointManager.save(newCheckpoint);
|
|
1832
|
+
}
|
|
1833
|
+
await checkpointManager.clear(mapId);
|
|
1834
|
+
return results;
|
|
1835
|
+
}
|
|
1836
|
+
__name(resumableMap, "resumableMap");
|
|
1837
|
+
async function resumableForEach(items, callback, forEachId) {
|
|
1838
|
+
const checkpointManager = getCheckpointManager();
|
|
1839
|
+
const checkpoint = await checkpointManager.load(forEachId);
|
|
1840
|
+
const startIndex = checkpoint?.currentIndex || 0;
|
|
1841
|
+
for (let i = startIndex; i < items.length; i++) {
|
|
1842
|
+
if (i > MAX_ITERATIONS2) {
|
|
1843
|
+
throw new InfiniteLoopDetectionError(forEachId, i);
|
|
1844
|
+
}
|
|
1845
|
+
await callback(items[i], i, items);
|
|
1846
|
+
const newCheckpoint = {
|
|
1847
|
+
loopId: forEachId,
|
|
1848
|
+
currentIndex: i + 1,
|
|
1849
|
+
timestamp: Date.now()
|
|
1850
|
+
};
|
|
1851
|
+
await checkpointManager.save(newCheckpoint);
|
|
1852
|
+
}
|
|
1853
|
+
await checkpointManager.clear(forEachId);
|
|
1854
|
+
}
|
|
1855
|
+
__name(resumableForEach, "resumableForEach");
|
|
1856
|
+
async function resumableFilter(items, callback, filterId) {
|
|
1857
|
+
const checkpointManager = getCheckpointManager();
|
|
1858
|
+
const checkpoint = await checkpointManager.load(filterId);
|
|
1859
|
+
const startIndex = checkpoint?.currentIndex || 0;
|
|
1860
|
+
const results = checkpoint?.results || [];
|
|
1861
|
+
for (let i = startIndex; i < items.length; i++) {
|
|
1862
|
+
if (i > MAX_ITERATIONS2) {
|
|
1863
|
+
throw new InfiniteLoopDetectionError(filterId, i);
|
|
1864
|
+
}
|
|
1865
|
+
const passed = await callback(items[i], i, items);
|
|
1866
|
+
if (passed) {
|
|
1867
|
+
results.push(items[i]);
|
|
1868
|
+
}
|
|
1869
|
+
const newCheckpoint = {
|
|
1870
|
+
loopId: filterId,
|
|
1871
|
+
currentIndex: i + 1,
|
|
1872
|
+
results,
|
|
1873
|
+
timestamp: Date.now()
|
|
1874
|
+
};
|
|
1875
|
+
await checkpointManager.save(newCheckpoint);
|
|
1876
|
+
}
|
|
1877
|
+
await checkpointManager.clear(filterId);
|
|
1878
|
+
return results;
|
|
1879
|
+
}
|
|
1880
|
+
__name(resumableFilter, "resumableFilter");
|
|
1881
|
+
async function resumableReduce(items, callback, initialValue, reduceId) {
|
|
1882
|
+
const checkpointManager = getCheckpointManager();
|
|
1883
|
+
const checkpoint = await checkpointManager.load(reduceId);
|
|
1884
|
+
const startIndex = checkpoint?.currentIndex || 0;
|
|
1885
|
+
let accumulator = checkpoint?.accumulator ?? initialValue;
|
|
1886
|
+
for (let i = startIndex; i < items.length; i++) {
|
|
1887
|
+
if (i > MAX_ITERATIONS2) {
|
|
1888
|
+
throw new InfiniteLoopDetectionError(reduceId, i);
|
|
1889
|
+
}
|
|
1890
|
+
accumulator = await callback(accumulator, items[i], i, items);
|
|
1891
|
+
const newCheckpoint = {
|
|
1892
|
+
loopId: reduceId,
|
|
1893
|
+
currentIndex: i + 1,
|
|
1894
|
+
accumulator,
|
|
1895
|
+
timestamp: Date.now()
|
|
1896
|
+
};
|
|
1897
|
+
await checkpointManager.save(newCheckpoint);
|
|
1898
|
+
}
|
|
1899
|
+
await checkpointManager.clear(reduceId);
|
|
1900
|
+
return accumulator;
|
|
1901
|
+
}
|
|
1902
|
+
__name(resumableReduce, "resumableReduce");
|
|
1903
|
+
async function resumableFind(items, callback, findId) {
|
|
1904
|
+
const checkpointManager = getCheckpointManager();
|
|
1905
|
+
const checkpoint = await checkpointManager.load(findId);
|
|
1906
|
+
const startIndex = checkpoint?.currentIndex || 0;
|
|
1907
|
+
for (let i = startIndex; i < items.length; i++) {
|
|
1908
|
+
if (i > MAX_ITERATIONS2) {
|
|
1909
|
+
throw new InfiniteLoopDetectionError(findId, i);
|
|
1910
|
+
}
|
|
1911
|
+
const found = await callback(items[i], i, items);
|
|
1912
|
+
if (found) {
|
|
1913
|
+
await checkpointManager.clear(findId);
|
|
1914
|
+
return items[i];
|
|
1915
|
+
}
|
|
1916
|
+
const newCheckpoint = {
|
|
1917
|
+
loopId: findId,
|
|
1918
|
+
currentIndex: i + 1,
|
|
1919
|
+
timestamp: Date.now()
|
|
1920
|
+
};
|
|
1921
|
+
await checkpointManager.save(newCheckpoint);
|
|
1922
|
+
}
|
|
1923
|
+
await checkpointManager.clear(findId);
|
|
1924
|
+
return void 0;
|
|
1925
|
+
}
|
|
1926
|
+
__name(resumableFind, "resumableFind");
|
|
1927
|
+
async function resumableSome(items, callback, someId) {
|
|
1928
|
+
const checkpointManager = getCheckpointManager();
|
|
1929
|
+
const checkpoint = await checkpointManager.load(someId);
|
|
1930
|
+
const startIndex = checkpoint?.currentIndex || 0;
|
|
1931
|
+
for (let i = startIndex; i < items.length; i++) {
|
|
1932
|
+
if (i > MAX_ITERATIONS2) {
|
|
1933
|
+
throw new InfiniteLoopDetectionError(someId, i);
|
|
1934
|
+
}
|
|
1935
|
+
const result = await callback(items[i], i, items);
|
|
1936
|
+
if (result) {
|
|
1937
|
+
await checkpointManager.clear(someId);
|
|
1938
|
+
return true;
|
|
1939
|
+
}
|
|
1940
|
+
const newCheckpoint = {
|
|
1941
|
+
loopId: someId,
|
|
1942
|
+
currentIndex: i + 1,
|
|
1943
|
+
timestamp: Date.now()
|
|
1944
|
+
};
|
|
1945
|
+
await checkpointManager.save(newCheckpoint);
|
|
1946
|
+
}
|
|
1947
|
+
await checkpointManager.clear(someId);
|
|
1948
|
+
return false;
|
|
1949
|
+
}
|
|
1950
|
+
__name(resumableSome, "resumableSome");
|
|
1951
|
+
async function resumableEvery(items, callback, everyId) {
|
|
1952
|
+
const checkpointManager = getCheckpointManager();
|
|
1953
|
+
const checkpoint = await checkpointManager.load(everyId);
|
|
1954
|
+
const startIndex = checkpoint?.currentIndex || 0;
|
|
1955
|
+
for (let i = startIndex; i < items.length; i++) {
|
|
1956
|
+
if (i > MAX_ITERATIONS2) {
|
|
1957
|
+
throw new InfiniteLoopDetectionError(everyId, i);
|
|
1958
|
+
}
|
|
1959
|
+
const result = await callback(items[i], i, items);
|
|
1960
|
+
if (!result) {
|
|
1961
|
+
await checkpointManager.clear(everyId);
|
|
1962
|
+
return false;
|
|
1963
|
+
}
|
|
1964
|
+
const newCheckpoint = {
|
|
1965
|
+
loopId: everyId,
|
|
1966
|
+
currentIndex: i + 1,
|
|
1967
|
+
timestamp: Date.now()
|
|
1968
|
+
};
|
|
1969
|
+
await checkpointManager.save(newCheckpoint);
|
|
1970
|
+
}
|
|
1971
|
+
await checkpointManager.clear(everyId);
|
|
1972
|
+
return true;
|
|
1973
|
+
}
|
|
1974
|
+
__name(resumableEvery, "resumableEvery");
|
|
1975
|
+
async function resumableFlatMap(items, callback, flatMapId) {
|
|
1976
|
+
const checkpointManager = getCheckpointManager();
|
|
1977
|
+
const checkpoint = await checkpointManager.load(flatMapId);
|
|
1978
|
+
const startIndex = checkpoint?.currentIndex || 0;
|
|
1979
|
+
const results = checkpoint?.results || [];
|
|
1980
|
+
for (let i = startIndex; i < items.length; i++) {
|
|
1981
|
+
if (i > MAX_ITERATIONS2) {
|
|
1982
|
+
throw new InfiniteLoopDetectionError(flatMapId, i);
|
|
1983
|
+
}
|
|
1984
|
+
const mapped = await callback(items[i], i, items);
|
|
1985
|
+
results.push(...mapped);
|
|
1986
|
+
const newCheckpoint = {
|
|
1987
|
+
loopId: flatMapId,
|
|
1988
|
+
currentIndex: i + 1,
|
|
1989
|
+
results,
|
|
1990
|
+
timestamp: Date.now()
|
|
1991
|
+
};
|
|
1992
|
+
await checkpointManager.save(newCheckpoint);
|
|
1993
|
+
}
|
|
1994
|
+
await checkpointManager.clear(flatMapId);
|
|
1995
|
+
return results;
|
|
1996
|
+
}
|
|
1997
|
+
__name(resumableFlatMap, "resumableFlatMap");
|
|
1998
|
+
|
|
1999
|
+
// src/runtime/resumable-parallel.ts
|
|
2000
|
+
async function resumablePromiseAll(promises, parallelId) {
|
|
2001
|
+
const checkpointManager = getCheckpointManager();
|
|
2002
|
+
const checkpoint = await checkpointManager.load(parallelId);
|
|
2003
|
+
const startIndex = checkpoint?.currentIndex || 0;
|
|
2004
|
+
const results = checkpoint?.results || [];
|
|
2005
|
+
for (let i = startIndex; i < promises.length; i++) {
|
|
2006
|
+
results[i] = await promises[i];
|
|
2007
|
+
const newCheckpoint = {
|
|
2008
|
+
loopId: parallelId,
|
|
2009
|
+
currentIndex: i + 1,
|
|
2010
|
+
results,
|
|
2011
|
+
timestamp: Date.now()
|
|
2012
|
+
};
|
|
2013
|
+
await checkpointManager.save(newCheckpoint);
|
|
2014
|
+
}
|
|
2015
|
+
await checkpointManager.clear(parallelId);
|
|
2016
|
+
return results;
|
|
2017
|
+
}
|
|
2018
|
+
__name(resumablePromiseAll, "resumablePromiseAll");
|
|
2019
|
+
async function resumablePromiseAllSettled(promises, parallelId) {
|
|
2020
|
+
const checkpointManager = getCheckpointManager();
|
|
2021
|
+
const checkpoint = await checkpointManager.load(parallelId);
|
|
2022
|
+
const startIndex = checkpoint?.currentIndex || 0;
|
|
2023
|
+
const results = checkpoint?.results || [];
|
|
2024
|
+
for (let i = startIndex; i < promises.length; i++) {
|
|
2025
|
+
try {
|
|
2026
|
+
const value = await promises[i];
|
|
2027
|
+
results[i] = {
|
|
2028
|
+
status: "fulfilled",
|
|
2029
|
+
value
|
|
2030
|
+
};
|
|
2031
|
+
} catch (reason) {
|
|
2032
|
+
results[i] = {
|
|
2033
|
+
status: "rejected",
|
|
2034
|
+
reason
|
|
2035
|
+
};
|
|
2036
|
+
}
|
|
2037
|
+
const newCheckpoint = {
|
|
2038
|
+
loopId: parallelId,
|
|
2039
|
+
currentIndex: i + 1,
|
|
2040
|
+
results,
|
|
2041
|
+
timestamp: Date.now()
|
|
2042
|
+
};
|
|
2043
|
+
await checkpointManager.save(newCheckpoint);
|
|
2044
|
+
}
|
|
2045
|
+
await checkpointManager.clear(parallelId);
|
|
2046
|
+
return results;
|
|
2047
|
+
}
|
|
2048
|
+
__name(resumablePromiseAllSettled, "resumablePromiseAllSettled");
|
|
2049
|
+
async function batchParallel(batchCalls, parallelId) {
|
|
2050
|
+
const currentSequence = getCallSequenceNumber();
|
|
2051
|
+
const cachedResult = getCachedResult(currentSequence);
|
|
2052
|
+
if (cachedResult !== void 0) {
|
|
2053
|
+
nextSequenceNumber();
|
|
2054
|
+
return cachedResult;
|
|
2055
|
+
}
|
|
2056
|
+
const sequenceForPause = nextSequenceNumber();
|
|
2057
|
+
throw new BatchPauseExecutionError(batchCalls, parallelId, sequenceForPause);
|
|
2058
|
+
}
|
|
2059
|
+
__name(batchParallel, "batchParallel");
|
|
2060
|
+
|
|
2061
|
+
// src/runtime/index.ts
|
|
2062
|
+
function initializeRuntime(options) {
|
|
2063
|
+
const checkpointManager = new CheckpointManager(options.executionId, options.cache, options.checkpointPrefix);
|
|
2064
|
+
setCheckpointManager(checkpointManager);
|
|
2065
|
+
setRuntimeContext({
|
|
2066
|
+
executionId: options.executionId,
|
|
2067
|
+
cache: options.cache,
|
|
2068
|
+
checkpointPrefix: options.checkpointPrefix
|
|
2069
|
+
});
|
|
2070
|
+
}
|
|
2071
|
+
__name(initializeRuntime, "initializeRuntime");
|
|
2072
|
+
function cleanupRuntime() {
|
|
2073
|
+
}
|
|
2074
|
+
__name(cleanupRuntime, "cleanupRuntime");
|
|
2075
|
+
|
|
2076
|
+
// src/types/compiler-interface.ts
|
|
2077
|
+
function isCompiler(obj) {
|
|
2078
|
+
return typeof obj === "object" && obj !== null && "detect" in obj && "transform" in obj && "getType" in obj && typeof obj.detect === "function" && typeof obj.transform === "function" && typeof obj.getType === "function";
|
|
2079
|
+
}
|
|
2080
|
+
__name(isCompiler, "isCompiler");
|
|
2081
|
+
|
|
2082
|
+
// src/plugin-system/plugin-api.ts
|
|
2083
|
+
var PluginRegistry = class {
|
|
2084
|
+
static {
|
|
2085
|
+
__name(this, "PluginRegistry");
|
|
2086
|
+
}
|
|
2087
|
+
detectors = [];
|
|
2088
|
+
transformers = [];
|
|
2089
|
+
optimizers = [];
|
|
2090
|
+
validators = [];
|
|
2091
|
+
/**
|
|
2092
|
+
* Register a plugin
|
|
2093
|
+
*/
|
|
2094
|
+
register(plugin) {
|
|
2095
|
+
if (this.findPlugin(plugin.name)) {
|
|
2096
|
+
throw new Error(`Plugin "${plugin.name}" is already registered. Please use a unique name or unregister the existing plugin first.`);
|
|
2097
|
+
}
|
|
2098
|
+
if (this.isDetectionPlugin(plugin)) {
|
|
2099
|
+
this.detectors.push(plugin);
|
|
2100
|
+
this.detectors.sort((a, b) => (b.priority || 50) - (a.priority || 50));
|
|
2101
|
+
}
|
|
2102
|
+
if (this.isTransformationPlugin(plugin)) {
|
|
2103
|
+
this.transformers.push(plugin);
|
|
2104
|
+
this.transformers.sort((a, b) => (b.priority || 50) - (a.priority || 50));
|
|
2105
|
+
}
|
|
2106
|
+
if (this.isOptimizerPlugin(plugin)) {
|
|
2107
|
+
this.optimizers.push(plugin);
|
|
2108
|
+
this.optimizers.sort((a, b) => (b.priority || 50) - (a.priority || 50));
|
|
2109
|
+
}
|
|
2110
|
+
if (this.isValidatorPlugin(plugin)) {
|
|
2111
|
+
this.validators.push(plugin);
|
|
2112
|
+
this.validators.sort((a, b) => (b.priority || 50) - (a.priority || 50));
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
/**
|
|
2116
|
+
* Find a plugin by name
|
|
2117
|
+
*/
|
|
2118
|
+
findPlugin(name) {
|
|
2119
|
+
const allPlugins = [
|
|
2120
|
+
...this.detectors,
|
|
2121
|
+
...this.transformers,
|
|
2122
|
+
...this.optimizers,
|
|
2123
|
+
...this.validators
|
|
2124
|
+
];
|
|
2125
|
+
return allPlugins.find((p) => p.name === name);
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Unregister a plugin by name
|
|
2129
|
+
*/
|
|
2130
|
+
unregister(name) {
|
|
2131
|
+
let removed = false;
|
|
2132
|
+
this.detectors = this.detectors.filter((p) => {
|
|
2133
|
+
if (p.name === name) {
|
|
2134
|
+
removed = true;
|
|
2135
|
+
return false;
|
|
2136
|
+
}
|
|
2137
|
+
return true;
|
|
2138
|
+
});
|
|
2139
|
+
this.transformers = this.transformers.filter((p) => {
|
|
2140
|
+
if (p.name === name) {
|
|
2141
|
+
removed = true;
|
|
2142
|
+
return false;
|
|
2143
|
+
}
|
|
2144
|
+
return true;
|
|
2145
|
+
});
|
|
2146
|
+
this.optimizers = this.optimizers.filter((p) => {
|
|
2147
|
+
if (p.name === name) {
|
|
2148
|
+
removed = true;
|
|
2149
|
+
return false;
|
|
2150
|
+
}
|
|
2151
|
+
return true;
|
|
2152
|
+
});
|
|
2153
|
+
this.validators = this.validators.filter((p) => {
|
|
2154
|
+
if (p.name === name) {
|
|
2155
|
+
removed = true;
|
|
2156
|
+
return false;
|
|
2157
|
+
}
|
|
2158
|
+
return true;
|
|
2159
|
+
});
|
|
2160
|
+
return removed;
|
|
2161
|
+
}
|
|
2162
|
+
/**
|
|
2163
|
+
* Get all detection plugins
|
|
2164
|
+
*/
|
|
2165
|
+
getDetectors() {
|
|
2166
|
+
return this.detectors;
|
|
2167
|
+
}
|
|
2168
|
+
/**
|
|
2169
|
+
* Get all transformation plugins
|
|
2170
|
+
*/
|
|
2171
|
+
getTransformers() {
|
|
2172
|
+
return this.transformers;
|
|
2173
|
+
}
|
|
2174
|
+
/**
|
|
2175
|
+
* Get all optimizer plugins
|
|
2176
|
+
*/
|
|
2177
|
+
getOptimizers() {
|
|
2178
|
+
return this.optimizers;
|
|
2179
|
+
}
|
|
2180
|
+
/**
|
|
2181
|
+
* Get all validator plugins
|
|
2182
|
+
*/
|
|
2183
|
+
getValidators() {
|
|
2184
|
+
return this.validators;
|
|
2185
|
+
}
|
|
2186
|
+
/**
|
|
2187
|
+
* Initialize all plugins
|
|
2188
|
+
*/
|
|
2189
|
+
async initializeAll(config) {
|
|
2190
|
+
const allPlugins = [
|
|
2191
|
+
...this.detectors,
|
|
2192
|
+
...this.transformers,
|
|
2193
|
+
...this.optimizers,
|
|
2194
|
+
...this.validators
|
|
2195
|
+
];
|
|
2196
|
+
for (const plugin of allPlugins) {
|
|
2197
|
+
if (plugin.initialize) {
|
|
2198
|
+
await plugin.initialize(config);
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
/**
|
|
2203
|
+
* Dispose all plugins
|
|
2204
|
+
*/
|
|
2205
|
+
async disposeAll() {
|
|
2206
|
+
const allPlugins = [
|
|
2207
|
+
...this.detectors,
|
|
2208
|
+
...this.transformers,
|
|
2209
|
+
...this.optimizers,
|
|
2210
|
+
...this.validators
|
|
2211
|
+
];
|
|
2212
|
+
for (const plugin of allPlugins) {
|
|
2213
|
+
if (plugin.dispose) {
|
|
2214
|
+
await plugin.dispose();
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
/**
|
|
2219
|
+
* Type guards
|
|
2220
|
+
*/
|
|
2221
|
+
isDetectionPlugin(plugin) {
|
|
2222
|
+
return "detect" in plugin && "patterns" in plugin;
|
|
2223
|
+
}
|
|
2224
|
+
isTransformationPlugin(plugin) {
|
|
2225
|
+
return "getVisitor" in plugin && "getMetadata" in plugin && "reset" in plugin;
|
|
2226
|
+
}
|
|
2227
|
+
isOptimizerPlugin(plugin) {
|
|
2228
|
+
return "optimize" in plugin;
|
|
2229
|
+
}
|
|
2230
|
+
isValidatorPlugin(plugin) {
|
|
2231
|
+
return "validate" in plugin;
|
|
2232
|
+
}
|
|
2233
|
+
};
|
|
2234
|
+
function createTransformPlugin(config) {
|
|
2235
|
+
let transformCount = 0;
|
|
2236
|
+
return {
|
|
2237
|
+
name: config.name,
|
|
2238
|
+
version: config.version,
|
|
2239
|
+
priority: config.priority || 50,
|
|
2240
|
+
getVisitor() {
|
|
2241
|
+
return config.visitor;
|
|
2242
|
+
},
|
|
2243
|
+
getMetadata() {
|
|
2244
|
+
return config.getMetadata ? config.getMetadata() : {
|
|
2245
|
+
loopCount: transformCount
|
|
2246
|
+
};
|
|
2247
|
+
},
|
|
2248
|
+
reset() {
|
|
2249
|
+
transformCount = 0;
|
|
2250
|
+
}
|
|
2251
|
+
};
|
|
2252
|
+
}
|
|
2253
|
+
__name(createTransformPlugin, "createTransformPlugin");
|
|
2254
|
+
var traverse3 = _traverse.default || _traverse;
|
|
2255
|
+
var generate2 = _generate.default || _generate;
|
|
2256
|
+
var PluggableCompiler = class {
|
|
2257
|
+
static {
|
|
2258
|
+
__name(this, "PluggableCompiler");
|
|
2259
|
+
}
|
|
2260
|
+
config;
|
|
2261
|
+
registry;
|
|
2262
|
+
initialized = false;
|
|
2263
|
+
/**
|
|
2264
|
+
* AST cache - maps code string to parsed AST
|
|
2265
|
+
* This avoids re-parsing the same code multiple times
|
|
2266
|
+
* (e.g., once in detect() and once in transform())
|
|
2267
|
+
*
|
|
2268
|
+
* Performance Impact: ~30% reduction in compile time
|
|
2269
|
+
*/
|
|
2270
|
+
astCache = /* @__PURE__ */ new Map();
|
|
2271
|
+
constructor(config = {}) {
|
|
2272
|
+
this.config = {
|
|
2273
|
+
...DEFAULT_COMPILER_CONFIG,
|
|
2274
|
+
...config
|
|
2275
|
+
};
|
|
2276
|
+
this.registry = new PluginRegistry();
|
|
2277
|
+
}
|
|
2278
|
+
/**
|
|
2279
|
+
* Register a plugin (chainable)
|
|
2280
|
+
*/
|
|
2281
|
+
use(plugin) {
|
|
2282
|
+
this.registry.register(plugin);
|
|
2283
|
+
return this;
|
|
2284
|
+
}
|
|
2285
|
+
/**
|
|
2286
|
+
* Unregister a plugin by name
|
|
2287
|
+
*/
|
|
2288
|
+
remove(pluginName) {
|
|
2289
|
+
return this.registry.unregister(pluginName);
|
|
2290
|
+
}
|
|
2291
|
+
/**
|
|
2292
|
+
* Initialize all plugins
|
|
2293
|
+
*/
|
|
2294
|
+
async initialize() {
|
|
2295
|
+
if (this.initialized) return;
|
|
2296
|
+
await this.registry.initializeAll(this.config);
|
|
2297
|
+
this.initialized = true;
|
|
2298
|
+
}
|
|
2299
|
+
/**
|
|
2300
|
+
* Detect patterns using all detection plugins
|
|
2301
|
+
*/
|
|
2302
|
+
async detect(code) {
|
|
2303
|
+
if (!this.initialized) {
|
|
2304
|
+
await this.initialize();
|
|
2305
|
+
}
|
|
2306
|
+
try {
|
|
2307
|
+
const ast = this.parseCode(code);
|
|
2308
|
+
const detectors = this.registry.getDetectors();
|
|
2309
|
+
const allPatterns = /* @__PURE__ */ new Set();
|
|
2310
|
+
let batchableParallel = false;
|
|
2311
|
+
for (const detector of detectors) {
|
|
2312
|
+
const result = await detector.detect(code, ast);
|
|
2313
|
+
result.patterns.forEach((p) => allPatterns.add(p));
|
|
2314
|
+
if (result.batchableParallel) {
|
|
2315
|
+
batchableParallel = true;
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
return {
|
|
2319
|
+
needsTransform: allPatterns.size > 0,
|
|
2320
|
+
patterns: Array.from(allPatterns),
|
|
2321
|
+
batchableParallel
|
|
2322
|
+
};
|
|
2323
|
+
} catch (error) {
|
|
2324
|
+
return {
|
|
2325
|
+
needsTransform: false,
|
|
2326
|
+
patterns: [],
|
|
2327
|
+
batchableParallel: false
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
/**
|
|
2332
|
+
* Transform code using all transformation plugins
|
|
2333
|
+
*/
|
|
2334
|
+
async transform(code) {
|
|
2335
|
+
if (!this.initialized) {
|
|
2336
|
+
await this.initialize();
|
|
2337
|
+
}
|
|
2338
|
+
resetIdCounter();
|
|
2339
|
+
await this.runValidation(code, "pre");
|
|
2340
|
+
const detection = await this.detect(code);
|
|
2341
|
+
if (!detection.needsTransform) {
|
|
2342
|
+
return {
|
|
2343
|
+
code,
|
|
2344
|
+
transformed: false,
|
|
2345
|
+
patterns: [],
|
|
2346
|
+
metadata: {
|
|
2347
|
+
loopCount: 0,
|
|
2348
|
+
arrayMethodCount: 0,
|
|
2349
|
+
parallelCallCount: 0,
|
|
2350
|
+
batchableCount: 0
|
|
2351
|
+
}
|
|
2352
|
+
};
|
|
2353
|
+
}
|
|
2354
|
+
try {
|
|
2355
|
+
const ast = this.parseCode(code);
|
|
2356
|
+
const transformers = this.registry.getTransformers();
|
|
2357
|
+
for (const transformer of transformers) {
|
|
2358
|
+
transformer.reset();
|
|
2359
|
+
}
|
|
2360
|
+
const visitors = {};
|
|
2361
|
+
for (const transformer of transformers) {
|
|
2362
|
+
const visitor = transformer.getVisitor(this.config);
|
|
2363
|
+
for (const [nodeType, handler] of Object.entries(visitor)) {
|
|
2364
|
+
if (!visitors[nodeType]) {
|
|
2365
|
+
visitors[nodeType] = handler;
|
|
2366
|
+
} else {
|
|
2367
|
+
const existing = visitors[nodeType];
|
|
2368
|
+
visitors[nodeType] = (path) => {
|
|
2369
|
+
existing(path);
|
|
2370
|
+
handler(path);
|
|
2371
|
+
};
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
traverse3(ast, visitors);
|
|
2376
|
+
let optimizedAst = ast;
|
|
2377
|
+
const optimizers = this.registry.getOptimizers();
|
|
2378
|
+
for (const optimizer of optimizers) {
|
|
2379
|
+
optimizedAst = await optimizer.optimize(optimizedAst, this.config);
|
|
2380
|
+
}
|
|
2381
|
+
const output = generate2(optimizedAst, {
|
|
2382
|
+
sourceMaps: false,
|
|
2383
|
+
retainLines: true,
|
|
2384
|
+
comments: true
|
|
2385
|
+
});
|
|
2386
|
+
const metadata = {
|
|
2387
|
+
loopCount: 0,
|
|
2388
|
+
arrayMethodCount: 0,
|
|
2389
|
+
parallelCallCount: 0,
|
|
2390
|
+
batchableCount: detection.batchableParallel ? 1 : 0
|
|
2391
|
+
};
|
|
2392
|
+
for (const transformer of transformers) {
|
|
2393
|
+
const pluginMetadata = transformer.getMetadata();
|
|
2394
|
+
metadata.loopCount += pluginMetadata.loopCount || 0;
|
|
2395
|
+
metadata.arrayMethodCount += pluginMetadata.arrayMethodCount || 0;
|
|
2396
|
+
metadata.parallelCallCount += pluginMetadata.parallelCallCount || 0;
|
|
2397
|
+
metadata.batchableCount += pluginMetadata.batchableCount || 0;
|
|
2398
|
+
}
|
|
2399
|
+
await this.runValidation(output.code, "post");
|
|
2400
|
+
return {
|
|
2401
|
+
code: output.code,
|
|
2402
|
+
transformed: true,
|
|
2403
|
+
patterns: detection.patterns,
|
|
2404
|
+
metadata
|
|
2405
|
+
};
|
|
2406
|
+
} catch (error) {
|
|
2407
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2408
|
+
const context = detection.patterns.length > 0 ? `[Plugin transformation] ${message}` : message;
|
|
2409
|
+
throw new TransformationError(context, code, "plugin-error");
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
/**
|
|
2413
|
+
* Dispose compiler and all plugins
|
|
2414
|
+
*/
|
|
2415
|
+
async dispose() {
|
|
2416
|
+
await this.registry.disposeAll();
|
|
2417
|
+
this.astCache.clear();
|
|
2418
|
+
this.initialized = false;
|
|
2419
|
+
}
|
|
2420
|
+
/**
|
|
2421
|
+
* Get current configuration
|
|
2422
|
+
*/
|
|
2423
|
+
getConfig() {
|
|
2424
|
+
return {
|
|
2425
|
+
...this.config
|
|
2426
|
+
};
|
|
2427
|
+
}
|
|
2428
|
+
/**
|
|
2429
|
+
* Update configuration
|
|
2430
|
+
*/
|
|
2431
|
+
setConfig(config) {
|
|
2432
|
+
this.config = {
|
|
2433
|
+
...this.config,
|
|
2434
|
+
...config
|
|
2435
|
+
};
|
|
2436
|
+
}
|
|
2437
|
+
/**
|
|
2438
|
+
* Parse code to AST with caching
|
|
2439
|
+
*
|
|
2440
|
+
* Caches parsed AST to avoid re-parsing the same code multiple times.
|
|
2441
|
+
* This provides ~30% performance improvement when detect() and transform()
|
|
2442
|
+
* are called on the same code.
|
|
2443
|
+
*/
|
|
2444
|
+
parseCode(code) {
|
|
2445
|
+
const cached = this.astCache.get(code);
|
|
2446
|
+
if (cached) {
|
|
2447
|
+
return cached;
|
|
2448
|
+
}
|
|
2449
|
+
const ast = parse(code, {
|
|
2450
|
+
sourceType: "module",
|
|
2451
|
+
plugins: [
|
|
2452
|
+
"typescript"
|
|
2453
|
+
],
|
|
2454
|
+
allowAwaitOutsideFunction: true,
|
|
2455
|
+
allowReturnOutsideFunction: true
|
|
2456
|
+
});
|
|
2457
|
+
this.astCache.set(code, ast);
|
|
2458
|
+
return ast;
|
|
2459
|
+
}
|
|
2460
|
+
/**
|
|
2461
|
+
* Clear AST cache
|
|
2462
|
+
*
|
|
2463
|
+
* Call this method to free memory if you've compiled many different code snippets.
|
|
2464
|
+
* The cache is automatically managed and uses Map, so old entries don't leak memory.
|
|
2465
|
+
*/
|
|
2466
|
+
clearCache() {
|
|
2467
|
+
this.astCache.clear();
|
|
2468
|
+
}
|
|
2469
|
+
/**
|
|
2470
|
+
* Get the compiler type identifier (ICompiler interface requirement)
|
|
2471
|
+
*/
|
|
2472
|
+
getType() {
|
|
2473
|
+
return "PluggableCompiler";
|
|
2474
|
+
}
|
|
2475
|
+
/**
|
|
2476
|
+
* Get cache statistics (for debugging/monitoring)
|
|
2477
|
+
*/
|
|
2478
|
+
getCacheStats() {
|
|
2479
|
+
return {
|
|
2480
|
+
size: this.astCache.size,
|
|
2481
|
+
enabled: true
|
|
2482
|
+
};
|
|
2483
|
+
}
|
|
2484
|
+
/**
|
|
2485
|
+
* Run validators
|
|
2486
|
+
*/
|
|
2487
|
+
async runValidation(code, phase) {
|
|
2488
|
+
const validators = this.registry.getValidators();
|
|
2489
|
+
const ast = this.parseCode(code);
|
|
2490
|
+
for (const validator of validators) {
|
|
2491
|
+
await validator.validate(code, ast, phase);
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
};
|
|
2495
|
+
|
|
2496
|
+
// src/plugin-system/default-plugins/detection-plugin.ts
|
|
2497
|
+
var DefaultDetectionPlugin = class {
|
|
2498
|
+
static {
|
|
2499
|
+
__name(this, "DefaultDetectionPlugin");
|
|
2500
|
+
}
|
|
2501
|
+
name = "atp-default-detector";
|
|
2502
|
+
version = "1.0.0";
|
|
2503
|
+
priority = 100;
|
|
2504
|
+
patterns = [
|
|
2505
|
+
"for-of-await",
|
|
2506
|
+
"while-await",
|
|
2507
|
+
"map-async",
|
|
2508
|
+
"forEach-async",
|
|
2509
|
+
"filter-async",
|
|
2510
|
+
"reduce-async",
|
|
2511
|
+
"find-async",
|
|
2512
|
+
"some-async",
|
|
2513
|
+
"every-async",
|
|
2514
|
+
"flatMap-async",
|
|
2515
|
+
"promise-all",
|
|
2516
|
+
"promise-allSettled"
|
|
2517
|
+
];
|
|
2518
|
+
detector;
|
|
2519
|
+
constructor() {
|
|
2520
|
+
this.detector = new AsyncIterationDetector();
|
|
2521
|
+
}
|
|
2522
|
+
async detect(code, ast) {
|
|
2523
|
+
return this.detector.detect(code);
|
|
2524
|
+
}
|
|
2525
|
+
};
|
|
2526
|
+
|
|
2527
|
+
// src/plugin-system/default-plugins/loop-transformer-plugin.ts
|
|
2528
|
+
var DefaultLoopTransformerPlugin = class {
|
|
2529
|
+
static {
|
|
2530
|
+
__name(this, "DefaultLoopTransformerPlugin");
|
|
2531
|
+
}
|
|
2532
|
+
name = "atp-loop-transformer";
|
|
2533
|
+
version = "1.0.0";
|
|
2534
|
+
priority = 100;
|
|
2535
|
+
transformer;
|
|
2536
|
+
constructor(batchSizeThreshold) {
|
|
2537
|
+
this.transformer = new LoopTransformer(batchSizeThreshold);
|
|
2538
|
+
}
|
|
2539
|
+
getVisitor(config) {
|
|
2540
|
+
return {
|
|
2541
|
+
ForOfStatement: /* @__PURE__ */ __name((path) => {
|
|
2542
|
+
this.transformer.transformForOfLoop(path);
|
|
2543
|
+
}, "ForOfStatement"),
|
|
2544
|
+
WhileStatement: /* @__PURE__ */ __name((path) => {
|
|
2545
|
+
this.transformer.transformWhileLoop(path);
|
|
2546
|
+
}, "WhileStatement"),
|
|
2547
|
+
ForStatement: /* @__PURE__ */ __name((path) => {
|
|
2548
|
+
this.transformer.transformForLoop(path);
|
|
2549
|
+
}, "ForStatement")
|
|
2550
|
+
};
|
|
2551
|
+
}
|
|
2552
|
+
getMetadata() {
|
|
2553
|
+
return {
|
|
2554
|
+
loopCount: this.transformer.getTransformCount()
|
|
2555
|
+
};
|
|
2556
|
+
}
|
|
2557
|
+
reset() {
|
|
2558
|
+
this.transformer.resetTransformCount();
|
|
2559
|
+
}
|
|
2560
|
+
};
|
|
2561
|
+
var DefaultArrayTransformerPlugin = class {
|
|
2562
|
+
static {
|
|
2563
|
+
__name(this, "DefaultArrayTransformerPlugin");
|
|
2564
|
+
}
|
|
2565
|
+
name = "atp-array-transformer";
|
|
2566
|
+
version = "1.0.0";
|
|
2567
|
+
priority = 100;
|
|
2568
|
+
transformer;
|
|
2569
|
+
constructor(batchSizeThreshold) {
|
|
2570
|
+
this.transformer = new ArrayTransformer(batchSizeThreshold);
|
|
2571
|
+
}
|
|
2572
|
+
getVisitor(config) {
|
|
2573
|
+
return {
|
|
2574
|
+
CallExpression: /* @__PURE__ */ __name((path) => {
|
|
2575
|
+
const node = path.node;
|
|
2576
|
+
if (this.isArrayMethodCall(node)) {
|
|
2577
|
+
this.transformer.transformArrayMethod(path);
|
|
2578
|
+
}
|
|
2579
|
+
}, "CallExpression")
|
|
2580
|
+
};
|
|
2581
|
+
}
|
|
2582
|
+
getMetadata() {
|
|
2583
|
+
return {
|
|
2584
|
+
arrayMethodCount: this.transformer.getTransformCount()
|
|
2585
|
+
};
|
|
2586
|
+
}
|
|
2587
|
+
reset() {
|
|
2588
|
+
this.transformer.resetTransformCount();
|
|
2589
|
+
}
|
|
2590
|
+
isArrayMethodCall(node) {
|
|
2591
|
+
if (!t7.isMemberExpression(node.callee)) {
|
|
2592
|
+
return false;
|
|
2593
|
+
}
|
|
2594
|
+
const property = node.callee.property;
|
|
2595
|
+
if (!t7.isIdentifier(property)) {
|
|
2596
|
+
return false;
|
|
2597
|
+
}
|
|
2598
|
+
const arrayMethods = [
|
|
2599
|
+
"map",
|
|
2600
|
+
"forEach",
|
|
2601
|
+
"filter",
|
|
2602
|
+
"reduce",
|
|
2603
|
+
"find",
|
|
2604
|
+
"some",
|
|
2605
|
+
"every",
|
|
2606
|
+
"flatMap"
|
|
2607
|
+
];
|
|
2608
|
+
return arrayMethods.includes(property.name);
|
|
2609
|
+
}
|
|
2610
|
+
};
|
|
2611
|
+
var DefaultPromiseTransformerPlugin = class {
|
|
2612
|
+
static {
|
|
2613
|
+
__name(this, "DefaultPromiseTransformerPlugin");
|
|
2614
|
+
}
|
|
2615
|
+
name = "atp-promise-transformer";
|
|
2616
|
+
version = "1.0.0";
|
|
2617
|
+
priority = 100;
|
|
2618
|
+
transformer;
|
|
2619
|
+
constructor(enableBatchParallel) {
|
|
2620
|
+
this.transformer = new PromiseTransformer(enableBatchParallel);
|
|
2621
|
+
}
|
|
2622
|
+
getVisitor(config) {
|
|
2623
|
+
return {
|
|
2624
|
+
CallExpression: /* @__PURE__ */ __name((path) => {
|
|
2625
|
+
const node = path.node;
|
|
2626
|
+
if (this.isPromiseAllCall(node)) {
|
|
2627
|
+
this.transformer.transformPromiseAll(path);
|
|
2628
|
+
} else if (this.isPromiseAllSettledCall(node)) {
|
|
2629
|
+
this.transformer.transformPromiseAllSettled(path);
|
|
2630
|
+
}
|
|
2631
|
+
}, "CallExpression")
|
|
2632
|
+
};
|
|
2633
|
+
}
|
|
2634
|
+
getMetadata() {
|
|
2635
|
+
return {
|
|
2636
|
+
parallelCallCount: this.transformer.getTransformCount()
|
|
2637
|
+
};
|
|
2638
|
+
}
|
|
2639
|
+
reset() {
|
|
2640
|
+
this.transformer.resetTransformCount();
|
|
2641
|
+
}
|
|
2642
|
+
isPromiseAllCall(node) {
|
|
2643
|
+
const callee = node.callee;
|
|
2644
|
+
return t7.isMemberExpression(callee) && t7.isIdentifier(callee.object, {
|
|
2645
|
+
name: "Promise"
|
|
2646
|
+
}) && t7.isIdentifier(callee.property, {
|
|
2647
|
+
name: "all"
|
|
2648
|
+
});
|
|
2649
|
+
}
|
|
2650
|
+
isPromiseAllSettledCall(node) {
|
|
2651
|
+
const callee = node.callee;
|
|
2652
|
+
return t7.isMemberExpression(callee) && t7.isIdentifier(callee.object, {
|
|
2653
|
+
name: "Promise"
|
|
2654
|
+
}) && t7.isIdentifier(callee.property, {
|
|
2655
|
+
name: "allSettled"
|
|
2656
|
+
});
|
|
2657
|
+
}
|
|
2658
|
+
};
|
|
2659
|
+
|
|
2660
|
+
// src/plugin-system/create-default-compiler.ts
|
|
2661
|
+
function createDefaultCompiler(config = {}) {
|
|
2662
|
+
const compiler = new PluggableCompiler(config);
|
|
2663
|
+
compiler.use(new DefaultDetectionPlugin());
|
|
2664
|
+
compiler.use(new DefaultLoopTransformerPlugin(config.batchSizeThreshold));
|
|
2665
|
+
compiler.use(new DefaultArrayTransformerPlugin(config.batchSizeThreshold));
|
|
2666
|
+
compiler.use(new DefaultPromiseTransformerPlugin(config.enableBatchParallel));
|
|
2667
|
+
return compiler;
|
|
2668
|
+
}
|
|
2669
|
+
__name(createDefaultCompiler, "createDefaultCompiler");
|
|
2670
|
+
var AsyncTimeoutPlugin = class {
|
|
2671
|
+
static {
|
|
2672
|
+
__name(this, "AsyncTimeoutPlugin");
|
|
2673
|
+
}
|
|
2674
|
+
name = "async-timeout";
|
|
2675
|
+
version = "1.0.0";
|
|
2676
|
+
priority = 40;
|
|
2677
|
+
options;
|
|
2678
|
+
transformCount = 0;
|
|
2679
|
+
constructor(options = {}) {
|
|
2680
|
+
this.options = {
|
|
2681
|
+
timeout: options.timeout || 5e3,
|
|
2682
|
+
patterns: options.patterns || [
|
|
2683
|
+
"fetch",
|
|
2684
|
+
"axios.*",
|
|
2685
|
+
"http.*"
|
|
2686
|
+
],
|
|
2687
|
+
wrapAll: options.wrapAll || false
|
|
2688
|
+
};
|
|
2689
|
+
}
|
|
2690
|
+
getVisitor(config) {
|
|
2691
|
+
return {
|
|
2692
|
+
AwaitExpression: /* @__PURE__ */ __name((path) => {
|
|
2693
|
+
if (!this.shouldWrap(path.node.argument)) {
|
|
2694
|
+
return;
|
|
2695
|
+
}
|
|
2696
|
+
const timeoutPromise = t7.newExpression(t7.identifier("Promise"), [
|
|
2697
|
+
t7.arrowFunctionExpression([
|
|
2698
|
+
t7.identifier("_"),
|
|
2699
|
+
t7.identifier("reject")
|
|
2700
|
+
], t7.blockStatement([
|
|
2701
|
+
t7.expressionStatement(t7.callExpression(t7.identifier("setTimeout"), [
|
|
2702
|
+
t7.arrowFunctionExpression([], t7.callExpression(t7.identifier("reject"), [
|
|
2703
|
+
t7.newExpression(t7.identifier("Error"), [
|
|
2704
|
+
t7.stringLiteral(`Timeout after ${this.options.timeout}ms`)
|
|
2705
|
+
])
|
|
2706
|
+
])),
|
|
2707
|
+
t7.numericLiteral(this.options.timeout)
|
|
2708
|
+
]))
|
|
2709
|
+
]))
|
|
2710
|
+
]);
|
|
2711
|
+
const raceCall = t7.callExpression(t7.memberExpression(t7.identifier("Promise"), t7.identifier("race")), [
|
|
2712
|
+
t7.arrayExpression([
|
|
2713
|
+
path.node.argument,
|
|
2714
|
+
timeoutPromise
|
|
2715
|
+
])
|
|
2716
|
+
]);
|
|
2717
|
+
path.node.argument = raceCall;
|
|
2718
|
+
this.transformCount++;
|
|
2719
|
+
}, "AwaitExpression")
|
|
2720
|
+
};
|
|
2721
|
+
}
|
|
2722
|
+
getMetadata() {
|
|
2723
|
+
return {
|
|
2724
|
+
// Custom metadata
|
|
2725
|
+
loopCount: 0,
|
|
2726
|
+
arrayMethodCount: 0,
|
|
2727
|
+
parallelCallCount: this.transformCount,
|
|
2728
|
+
batchableCount: 0
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2731
|
+
reset() {
|
|
2732
|
+
this.transformCount = 0;
|
|
2733
|
+
}
|
|
2734
|
+
/**
|
|
2735
|
+
* Check if this await should be wrapped with timeout
|
|
2736
|
+
*/
|
|
2737
|
+
shouldWrap(node) {
|
|
2738
|
+
if (this.options.wrapAll) {
|
|
2739
|
+
return true;
|
|
2740
|
+
}
|
|
2741
|
+
if (t7.isCallExpression(node)) {
|
|
2742
|
+
const funcName = this.getFunctionName(node);
|
|
2743
|
+
if (funcName) {
|
|
2744
|
+
return this.options.patterns.some((pattern) => {
|
|
2745
|
+
const regex = new RegExp(pattern.replace("*", ".*"));
|
|
2746
|
+
return regex.test(funcName);
|
|
2747
|
+
});
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
return false;
|
|
2751
|
+
}
|
|
2752
|
+
/**
|
|
2753
|
+
* Get function name from call expression
|
|
2754
|
+
*/
|
|
2755
|
+
getFunctionName(node) {
|
|
2756
|
+
if (t7.isIdentifier(node.callee)) {
|
|
2757
|
+
return node.callee.name;
|
|
2758
|
+
}
|
|
2759
|
+
if (t7.isMemberExpression(node.callee)) {
|
|
2760
|
+
const obj = t7.isIdentifier(node.callee.object) ? node.callee.object.name : "";
|
|
2761
|
+
const prop = t7.isIdentifier(node.callee.property) ? node.callee.property.name : "";
|
|
2762
|
+
return `${obj}.${prop}`;
|
|
2763
|
+
}
|
|
2764
|
+
return null;
|
|
2765
|
+
}
|
|
2766
|
+
};
|
|
2767
|
+
var traverse4 = _traverse.default || _traverse;
|
|
2768
|
+
var SecurityValidatorPlugin = class {
|
|
2769
|
+
static {
|
|
2770
|
+
__name(this, "SecurityValidatorPlugin");
|
|
2771
|
+
}
|
|
2772
|
+
name = "security-validator";
|
|
2773
|
+
version = "1.0.0";
|
|
2774
|
+
priority = 100;
|
|
2775
|
+
options;
|
|
2776
|
+
constructor(options = {}) {
|
|
2777
|
+
this.options = {
|
|
2778
|
+
forbiddenPatterns: options.forbiddenPatterns || [
|
|
2779
|
+
/\beval\s*\(/,
|
|
2780
|
+
/new\s+Function\s*\(/,
|
|
2781
|
+
/constructor\s*\[\s*['"`]constructor['"`]\s*\]/
|
|
2782
|
+
],
|
|
2783
|
+
maxComplexity: options.maxComplexity || 50,
|
|
2784
|
+
maxNesting: options.maxNesting || 10,
|
|
2785
|
+
forbiddenGlobals: options.forbiddenGlobals || [
|
|
2786
|
+
"process",
|
|
2787
|
+
"require",
|
|
2788
|
+
"__dirname",
|
|
2789
|
+
"__filename"
|
|
2790
|
+
]
|
|
2791
|
+
};
|
|
2792
|
+
}
|
|
2793
|
+
async validate(code, ast, phase) {
|
|
2794
|
+
if (phase === "post") {
|
|
2795
|
+
return;
|
|
2796
|
+
}
|
|
2797
|
+
for (const pattern of this.options.forbiddenPatterns) {
|
|
2798
|
+
if (pattern.test(code)) {
|
|
2799
|
+
throw new SecurityValidationError(`Forbidden pattern detected: ${pattern}`, "forbidden-pattern");
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
let maxNestingFound = 0;
|
|
2803
|
+
let complexityScore = 0;
|
|
2804
|
+
traverse4(ast, {
|
|
2805
|
+
enter(path) {
|
|
2806
|
+
const depth = path.scope.path.node ? getDepth(path) : 0;
|
|
2807
|
+
maxNestingFound = Math.max(maxNestingFound, depth);
|
|
2808
|
+
if (path.isIfStatement() || path.isWhileStatement() || path.isForStatement() || path.isForOfStatement() || path.isSwitchCase() || path.isCatchClause()) {
|
|
2809
|
+
complexityScore++;
|
|
2810
|
+
}
|
|
2811
|
+
},
|
|
2812
|
+
// 3. Check forbidden globals
|
|
2813
|
+
Identifier: /* @__PURE__ */ __name((path) => {
|
|
2814
|
+
if (this.options.forbiddenGlobals.includes(path.node.name) && !path.scope.hasBinding(path.node.name)) {
|
|
2815
|
+
throw new SecurityValidationError(`Access to forbidden global: ${path.node.name}`, "forbidden-global");
|
|
2816
|
+
}
|
|
2817
|
+
}, "Identifier")
|
|
2818
|
+
});
|
|
2819
|
+
if (maxNestingFound > this.options.maxNesting) {
|
|
2820
|
+
throw new SecurityValidationError(`Maximum nesting depth exceeded: ${maxNestingFound} > ${this.options.maxNesting}`, "max-nesting");
|
|
2821
|
+
}
|
|
2822
|
+
if (complexityScore > this.options.maxComplexity) {
|
|
2823
|
+
throw new SecurityValidationError(`Maximum complexity exceeded: ${complexityScore} > ${this.options.maxComplexity}`, "max-complexity");
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
};
|
|
2827
|
+
var SecurityValidationError = class extends Error {
|
|
2828
|
+
static {
|
|
2829
|
+
__name(this, "SecurityValidationError");
|
|
2830
|
+
}
|
|
2831
|
+
code;
|
|
2832
|
+
constructor(message, code) {
|
|
2833
|
+
super(message);
|
|
2834
|
+
this.code = code;
|
|
2835
|
+
this.name = "SecurityValidationError";
|
|
2836
|
+
}
|
|
2837
|
+
};
|
|
2838
|
+
function getDepth(path) {
|
|
2839
|
+
let depth = 0;
|
|
2840
|
+
let current = path;
|
|
2841
|
+
while (current.parentPath) {
|
|
2842
|
+
if (current.isBlockStatement() || current.isFunctionDeclaration() || current.isArrowFunctionExpression()) {
|
|
2843
|
+
depth++;
|
|
2844
|
+
}
|
|
2845
|
+
current = current.parentPath;
|
|
2846
|
+
}
|
|
2847
|
+
return depth;
|
|
2848
|
+
}
|
|
2849
|
+
__name(getDepth, "getDepth");
|
|
2850
|
+
|
|
2851
|
+
export { ATPCompiler, ArrayTransformer, AsyncIterationDetector, AsyncTimeoutPlugin, BatchOptimizer, BatchParallelDetector, BatchPauseExecutionError, CheckpointError, CheckpointManager, CheckpointOperation, DEFAULT_COMPILER_CONFIG, DefaultArrayTransformerPlugin, DefaultDetectionPlugin, DefaultLoopTransformerPlugin, DefaultPromiseTransformerPlugin, IN_ISOLATE_RUNTIME_FUNCTIONS, InfiniteLoopDetectionError, LoopTransformer, PAUSABLE_CALL_PATTERNS, PluggableCompiler, PluginRegistry, PromiseTransformer, RuntimeFunction, SecurityValidationError, SecurityValidatorPlugin, TransformationError, batchParallel, cleanupRuntime, clearCheckpointManager, clearRuntimeContext, containsAwait, containsPausableCall, createDefaultCompiler, createRuntimeCall, createTransformPlugin, extractForOfParamName, generateUniqueId, getCheckpointManager, getMemberExpressionPath, getNodeLocation, getRuntimeContext, hasCheckpointManager, hasRuntimeContext, initializeRuntime, isArrayMethod, isAsyncFunction, isBatchPauseError, isCheckpointError, isCompiler, isInIsolateRuntimeFunction, isPausableCall, isPausableCallExpression, isTransformationError, resetIdCounter, resumableEvery, resumableFilter, resumableFind, resumableFlatMap, resumableForEach, resumableForLoop, resumableForOf, resumableMap, resumablePromiseAll, resumablePromiseAllSettled, resumableReduce, resumableSome, resumableWhile, setCheckpointManager, setRuntimeContext, wrapInAsyncFunction };
|
|
2852
|
+
//# sourceMappingURL=index.js.map
|
|
15
2853
|
//# sourceMappingURL=index.js.map
|