@opencode/codemode 0.0.0-beta-19289 → 0.0.0-beta-19365
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/codemode.d.ts +8 -11
- package/dist/codemode.js +4 -8
- package/dist/data.d.ts +28 -0
- package/dist/data.js +130 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interpreter/errors.d.ts +1 -1
- package/dist/interpreter/errors.js +2 -2
- package/dist/interpreter/execute.d.ts +3 -3
- package/dist/interpreter/execute.js +9 -15
- package/dist/interpreter/methods.d.ts +9 -2
- package/dist/interpreter/methods.js +54 -76
- package/dist/interpreter/model.d.ts +12 -32
- package/dist/interpreter/model.js +0 -31
- package/dist/interpreter/promises.d.ts +8 -8
- package/dist/interpreter/promises.js +4 -4
- package/dist/interpreter/references.js +12 -42
- package/dist/interpreter/runtime.d.ts +2 -3
- package/dist/interpreter/runtime.js +255 -311
- package/dist/openapi/spec.js +1 -1
- package/dist/stdlib/console.js +14 -14
- package/dist/stdlib/date.d.ts +2 -2
- package/dist/stdlib/date.js +1 -1
- package/dist/stdlib/json.js +17 -26
- package/dist/stdlib/number.d.ts +1 -1
- package/dist/stdlib/number.js +4 -3
- package/dist/stdlib/object.js +11 -10
- package/dist/stdlib/regexp.d.ts +2 -2
- package/dist/stdlib/regexp.js +3 -3
- package/dist/stdlib/string.d.ts +1 -1
- package/dist/stdlib/string.js +1 -1
- package/dist/stdlib/url.d.ts +3 -3
- package/dist/stdlib/url.js +7 -6
- package/dist/stdlib/value.d.ts +2 -3
- package/dist/stdlib/value.js +14 -15
- package/dist/tool-runtime.d.ts +16 -15
- package/dist/tool-runtime.js +13 -150
- package/dist/values.d.ts +22 -16
- package/dist/values.js +23 -17
- package/package.json +1 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { CodeModeFunction, CodeModeGenerator, CoercionFunction, ErrorConstructorReference, GlobalMethodReference, GlobalNamespace, IntrinsicReference, InterpreterRuntimeError, JsonMethodReference, PromiseCapabilityFunction, PromiseNamespace, UriFunction, } from "./model.js";
|
|
3
3
|
import { containsOpaqueReference, isRuntimeReference, rejectCircularInsertion, typeofValue } from "./references.js";
|
|
4
|
-
import { isBlockedMember } from "../
|
|
5
|
-
import {
|
|
4
|
+
import { isBlockedMember, toProgram } from "../data.js";
|
|
5
|
+
import { compareText } from "../tool-runtime.js";
|
|
6
|
+
import { Values } from "../values.js";
|
|
6
7
|
import { dateSetterArgumentCount, invokeDateMethod, invokeDateStatic } from "../stdlib/date.js";
|
|
7
8
|
import { invokeMathMethod } from "../stdlib/math.js";
|
|
8
9
|
import { invokeNumberMethod, invokeNumberStatic } from "../stdlib/number.js";
|
|
@@ -10,7 +11,7 @@ import { invokeObjectMethod } from "../stdlib/object.js";
|
|
|
10
11
|
import { invokeRegExpMethod, invokeRegExpStatic, matchToValue, toHostRegex } from "../stdlib/regexp.js";
|
|
11
12
|
import { invokeStringStatic } from "../stdlib/string.js";
|
|
12
13
|
import { invokeURLMethod, invokeURLStatic, uriArgument } from "../stdlib/url.js";
|
|
13
|
-
import {
|
|
14
|
+
import { coerceToNumber, coerceToString, errorBrandName } from "../stdlib/value.js";
|
|
14
15
|
import { preserveConsumerError } from "./iterator.js";
|
|
15
16
|
export const isSupportedCallback = (value) => value instanceof CodeModeFunction ||
|
|
16
17
|
value instanceof CoercionFunction ||
|
|
@@ -41,7 +42,7 @@ export const invokeIntrinsic = (runner, ref, args, node) => {
|
|
|
41
42
|
if (Array.isArray(ref.receiver)) {
|
|
42
43
|
return invokeArrayMethod(runner, ref.receiver, ref.name, args, node);
|
|
43
44
|
}
|
|
44
|
-
if (ref.receiver instanceof
|
|
45
|
+
if (ref.receiver instanceof Values.Date) {
|
|
45
46
|
const target = ref.receiver;
|
|
46
47
|
const argumentCount = dateSetterArgumentCount(ref.name);
|
|
47
48
|
if (argumentCount === undefined)
|
|
@@ -52,49 +53,53 @@ export const invokeIntrinsic = (runner, ref, args, node) => {
|
|
|
52
53
|
concurrency: 1,
|
|
53
54
|
}), (values) => invokeDateMethod(target, ref.name, values, node, initialTime));
|
|
54
55
|
}
|
|
55
|
-
if (ref.receiver instanceof
|
|
56
|
+
if (ref.receiver instanceof Values.RegExp) {
|
|
56
57
|
return Effect.succeed(invokeRegExpMethod(ref.receiver, ref.name, args, node));
|
|
57
58
|
}
|
|
58
|
-
if (ref.receiver instanceof
|
|
59
|
+
if (ref.receiver instanceof Values.Map) {
|
|
59
60
|
return invokeMapMethod(runner, ref.receiver, ref.name, args, node);
|
|
60
61
|
}
|
|
61
|
-
if (ref.receiver instanceof
|
|
62
|
+
if (ref.receiver instanceof Values.Set) {
|
|
62
63
|
return invokeSetMethod(runner, ref.receiver, ref.name, args, node);
|
|
63
64
|
}
|
|
64
|
-
if (ref.receiver instanceof
|
|
65
|
+
if (ref.receiver instanceof Values.URL) {
|
|
65
66
|
return Effect.succeed(invokeURLMethod(ref.receiver, ref.name, node));
|
|
66
67
|
}
|
|
67
|
-
if (ref.receiver instanceof
|
|
68
|
+
if (ref.receiver instanceof Values.URLSearchParams) {
|
|
68
69
|
return invokeURLSearchParamsMethod(runner, ref.receiver, ref.name, args, node);
|
|
69
70
|
}
|
|
70
71
|
throw new InterpreterRuntimeError(`Method '${ref.name}' is not available.`, node);
|
|
71
72
|
};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
/**
|
|
74
|
+
* ToPrimitive: tries an object's own `valueOf`/`toString` in hint order and returns the first
|
|
75
|
+
* primitive result. Runtime values behave like their JS counterparts (Date yields its time under a
|
|
76
|
+
* number hint; the rest yield their string form). An inherited `toString` yields the default
|
|
77
|
+
* string form, so plain objects become "[object Object]" and arrays join.
|
|
78
|
+
*/
|
|
79
|
+
export const toPrimitive = (runner, value, hint, node) => {
|
|
80
|
+
if (value === null || typeof value !== "object")
|
|
81
|
+
return Effect.succeed(value);
|
|
82
|
+
if (Values.isValue(value)) {
|
|
83
|
+
return Effect.succeed(value instanceof Values.Date && hint === "number" ? value.time : coerceToString(value));
|
|
75
84
|
}
|
|
76
85
|
const object = value;
|
|
86
|
+
const order = hint === "number" ? ["valueOf", "toString"] : ["toString", "valueOf"];
|
|
77
87
|
return Effect.gen(function* () {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (typeofValue(object.toString) === "function") {
|
|
87
|
-
const result = yield* runner.invokeCallable(object.toString, [], node);
|
|
88
|
-
if (result === null || (typeof result !== "object" && typeof result !== "function")) {
|
|
89
|
-
return coerceToNumber(result);
|
|
90
|
-
}
|
|
88
|
+
for (const method of order) {
|
|
89
|
+
if (method === "toString" && !Object.hasOwn(object, "toString"))
|
|
90
|
+
return coerceToString(value);
|
|
91
|
+
if (!Object.hasOwn(object, method) || typeofValue(object[method]) !== "function")
|
|
92
|
+
continue;
|
|
93
|
+
const result = yield* runner.invokeCallable(object[method], [], node);
|
|
94
|
+
if (result === null || (typeof result !== "object" && typeof result !== "function"))
|
|
95
|
+
return result;
|
|
91
96
|
}
|
|
92
97
|
throw new InterpreterRuntimeError("Cannot convert object to primitive value.", node).as("TypeError");
|
|
93
98
|
});
|
|
94
99
|
};
|
|
100
|
+
const coerceNumericArgument = (runner, value, node) => Effect.map(toPrimitive(runner, value, "number", node), coerceToNumber);
|
|
101
|
+
// console is intercepted by the interpreter before reaching here.
|
|
95
102
|
export const invokeGlobalMethod = (ref, args, node) => {
|
|
96
|
-
if (ref.namespace === "console")
|
|
97
|
-
throw new InterpreterRuntimeError(`console.${ref.name} is not available.`, node);
|
|
98
103
|
if (ref.namespace === "Object")
|
|
99
104
|
return invokeObjectMethod(ref.name, args, node);
|
|
100
105
|
if (ref.namespace === "Math")
|
|
@@ -111,9 +116,6 @@ export const invokeGlobalMethod = (ref, args, node) => {
|
|
|
111
116
|
return invokeDateStatic(ref.name, args, node);
|
|
112
117
|
if (ref.namespace === "RegExp")
|
|
113
118
|
return invokeRegExpStatic(ref.name, args, node);
|
|
114
|
-
if (ref.namespace === "Map" || ref.namespace === "Set" || ref.namespace === "URLSearchParams") {
|
|
115
|
-
throw new InterpreterRuntimeError(`${ref.namespace}.${ref.name} is not available.`, node);
|
|
116
|
-
}
|
|
117
119
|
throw new InterpreterRuntimeError(`${ref.namespace}.${ref.name} is not available.`, node);
|
|
118
120
|
};
|
|
119
121
|
const requireDataArgument = (name, index, arg, node) => {
|
|
@@ -129,7 +131,7 @@ const invokeStringMethod = (value, name, args, node) => {
|
|
|
129
131
|
const optNum = (index) => (args[index] === undefined ? undefined : num(index));
|
|
130
132
|
const optStr = (index) => (args[index] === undefined ? undefined : str(index));
|
|
131
133
|
const rejectRegex = () => {
|
|
132
|
-
if (args[0] instanceof
|
|
134
|
+
if (args[0] instanceof Values.RegExp) {
|
|
133
135
|
throw new InterpreterRuntimeError(`String.${name} cannot take a regular expression; use regex.test(string) or String.search instead.`, node).as("TypeError");
|
|
134
136
|
}
|
|
135
137
|
};
|
|
@@ -172,7 +174,7 @@ const invokeStringMethod = (value, name, args, node) => {
|
|
|
172
174
|
result = requestedLimit !== undefined && requestedLimit >>> 0 === 0 ? [] : [value];
|
|
173
175
|
break;
|
|
174
176
|
}
|
|
175
|
-
if (args[0] instanceof
|
|
177
|
+
if (args[0] instanceof Values.RegExp) {
|
|
176
178
|
result = value.split(args[0].regex, optNum(1));
|
|
177
179
|
break;
|
|
178
180
|
}
|
|
@@ -203,7 +205,7 @@ const invokeStringMethod = (value, name, args, node) => {
|
|
|
203
205
|
break;
|
|
204
206
|
case "replace":
|
|
205
207
|
case "replaceAll": {
|
|
206
|
-
if (args[0] instanceof
|
|
208
|
+
if (args[0] instanceof Values.RegExp) {
|
|
207
209
|
const pattern = args[0].regex;
|
|
208
210
|
const replacement = str(1);
|
|
209
211
|
if (name === "replaceAll" && !pattern.global) {
|
|
@@ -226,7 +228,7 @@ const invokeStringMethod = (value, name, args, node) => {
|
|
|
226
228
|
return null;
|
|
227
229
|
// Preserve the own `index` and `groups` properties on non-global matches.
|
|
228
230
|
if (pattern.global)
|
|
229
|
-
return
|
|
231
|
+
return toProgram(matched, "String.match result");
|
|
230
232
|
return matchToValue(matched);
|
|
231
233
|
}
|
|
232
234
|
case "matchAll": {
|
|
@@ -278,7 +280,7 @@ const invokeStringMethod = (value, name, args, node) => {
|
|
|
278
280
|
default:
|
|
279
281
|
throw new InterpreterRuntimeError(`String method '${name}' is not available.`, node);
|
|
280
282
|
}
|
|
281
|
-
return
|
|
283
|
+
return toProgram(result, `String.${name} result`);
|
|
282
284
|
};
|
|
283
285
|
export const arrayStatics = new Set(["isArray", "of", "from"]);
|
|
284
286
|
const invokeArrayStatic = (name, args, node) => {
|
|
@@ -292,7 +294,7 @@ const invokeArrayStatic = (name, args, node) => {
|
|
|
292
294
|
}
|
|
293
295
|
};
|
|
294
296
|
const arrayLikeSource = (source, node) => {
|
|
295
|
-
if (source instanceof
|
|
297
|
+
if (source instanceof Values.Promise) {
|
|
296
298
|
throw new InterpreterRuntimeError("Array.from received an un-awaited Promise; await it before creating the array.", node, "InvalidDataValue");
|
|
297
299
|
}
|
|
298
300
|
if (source !== null &&
|
|
@@ -347,7 +349,7 @@ export const invokeGroupBy = (runner, namespace, args, node) => {
|
|
|
347
349
|
throw new InterpreterRuntimeError(`${namespace}.groupBy expects an iterable collection.`, node).as("TypeError");
|
|
348
350
|
}
|
|
349
351
|
if (namespace === "Map") {
|
|
350
|
-
const result = new
|
|
352
|
+
const result = new Values.Map();
|
|
351
353
|
let index = 0;
|
|
352
354
|
while (true) {
|
|
353
355
|
const step = yield* cursor.next;
|
|
@@ -384,32 +386,12 @@ export const invokeGroupBy = (runner, namespace, args, node) => {
|
|
|
384
386
|
});
|
|
385
387
|
};
|
|
386
388
|
const coerceGroupByPropertyKey = (runner, value, node) => {
|
|
387
|
-
if (value
|
|
388
|
-
return Effect.succeed(coerceToString(value));
|
|
389
|
-
}
|
|
390
|
-
if (value instanceof CodeModePromise)
|
|
389
|
+
if (value instanceof Values.Promise)
|
|
391
390
|
return Effect.succeed("[object Promise]");
|
|
392
|
-
if (isRuntimeReference(value)) {
|
|
391
|
+
if (!Values.isValue(value) && isRuntimeReference(value)) {
|
|
393
392
|
throw new InterpreterRuntimeError("Object.groupBy callback must return a data value.", node, "InvalidDataValue");
|
|
394
393
|
}
|
|
395
|
-
|
|
396
|
-
if (!Object.hasOwn(object, "toString"))
|
|
397
|
-
return Effect.succeed(coerceToString(value));
|
|
398
|
-
return Effect.gen(function* () {
|
|
399
|
-
if (typeofValue(object.toString) === "function") {
|
|
400
|
-
const result = yield* runner.invokeCallable(object.toString, [], node);
|
|
401
|
-
if (result === null || (typeof result !== "object" && typeof result !== "function")) {
|
|
402
|
-
return coerceToString(result);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
if (Object.hasOwn(object, "valueOf") && typeofValue(object.valueOf) === "function") {
|
|
406
|
-
const result = yield* runner.invokeCallable(object.valueOf, [], node);
|
|
407
|
-
if (result === null || (typeof result !== "object" && typeof result !== "function")) {
|
|
408
|
-
return coerceToString(result);
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
throw new InterpreterRuntimeError("Cannot convert object to primitive value.", node).as("TypeError");
|
|
412
|
-
});
|
|
394
|
+
return Effect.map(toPrimitive(runner, value, "string", node), coerceToString);
|
|
413
395
|
};
|
|
414
396
|
const invokeStringReplacer = (runner, value, name, args, node) => {
|
|
415
397
|
const apply = applyCollectionCallback(runner, args[1], `String.${name}`, node);
|
|
@@ -434,7 +416,7 @@ const invokeStringReplacer = (runner, value, name, args, node) => {
|
|
|
434
416
|
return match;
|
|
435
417
|
};
|
|
436
418
|
const pattern = args[0];
|
|
437
|
-
if (pattern instanceof
|
|
419
|
+
if (pattern instanceof Values.RegExp) {
|
|
438
420
|
if (name === "replaceAll" && !pattern.regex.global) {
|
|
439
421
|
throw new InterpreterRuntimeError(`String.replaceAll requires a regular expression with the global (g) flag: write /${pattern.regex.source}/${pattern.regex.flags}g, or use String.replace to replace only the first match.`, node);
|
|
440
422
|
}
|
|
@@ -455,16 +437,16 @@ const invokeStringReplacer = (runner, value, name, args, node) => {
|
|
|
455
437
|
let end = 0;
|
|
456
438
|
for (const match of matches) {
|
|
457
439
|
const replacement = yield* apply(match.args);
|
|
458
|
-
// Error values are branded plain objects;
|
|
459
|
-
output.push(value.slice(end, match.offset), replacement instanceof
|
|
440
|
+
// Error values are branded plain objects; toProgram would strip the brand before coercion.
|
|
441
|
+
output.push(value.slice(end, match.offset), replacement instanceof Values.Promise
|
|
460
442
|
? "[object Promise]"
|
|
461
443
|
: errorBrandName(replacement)
|
|
462
444
|
? coerceToString(replacement)
|
|
463
|
-
: coerceToString(
|
|
445
|
+
: coerceToString(toProgram(replacement, `String.${name} replacer result`)));
|
|
464
446
|
end = match.offset + match.match.length;
|
|
465
447
|
}
|
|
466
448
|
output.push(value.slice(end));
|
|
467
|
-
return
|
|
449
|
+
return toProgram(output.join(""), `String.${name} result`);
|
|
468
450
|
});
|
|
469
451
|
};
|
|
470
452
|
export const applyCollectionCallback = (runner, callback, name, node) => {
|
|
@@ -562,7 +544,7 @@ const invokeSetOperation = (runner, target, name, source, node) => Effect.gen(fu
|
|
|
562
544
|
return result;
|
|
563
545
|
}
|
|
564
546
|
if (name === "intersection") {
|
|
565
|
-
const result = new
|
|
547
|
+
const result = new Values.Set();
|
|
566
548
|
if (target.set.size <= other.size) {
|
|
567
549
|
for (const item of target.set.values()) {
|
|
568
550
|
if (yield* other.has(item))
|
|
@@ -631,27 +613,27 @@ const invokeSetOperation = (runner, target, name, source, node) => Effect.gen(fu
|
|
|
631
613
|
return true;
|
|
632
614
|
});
|
|
633
615
|
const copySet = (source) => {
|
|
634
|
-
const result = new
|
|
616
|
+
const result = new Values.Set();
|
|
635
617
|
for (const item of source.set.values())
|
|
636
618
|
result.set.add(item);
|
|
637
619
|
return result;
|
|
638
620
|
};
|
|
639
621
|
const loadSetRecord = (runner, source, name, node) => {
|
|
640
|
-
if (source instanceof
|
|
622
|
+
if (source instanceof Values.Set) {
|
|
641
623
|
return Effect.succeed({
|
|
642
624
|
size: source.set.size,
|
|
643
625
|
has: (item) => Effect.succeed(source.set.has(item)),
|
|
644
626
|
keys: () => Effect.succeed(source.set.values()),
|
|
645
627
|
});
|
|
646
628
|
}
|
|
647
|
-
if (source instanceof
|
|
629
|
+
if (source instanceof Values.Map) {
|
|
648
630
|
return Effect.succeed({
|
|
649
631
|
size: source.map.size,
|
|
650
632
|
has: (item) => Effect.succeed(source.map.has(item)),
|
|
651
633
|
keys: () => Effect.succeed(source.map.keys()),
|
|
652
634
|
});
|
|
653
635
|
}
|
|
654
|
-
if (source === null || typeof source !== "object" ||
|
|
636
|
+
if (source === null || typeof source !== "object" || Values.isValue(source)) {
|
|
655
637
|
throw new InterpreterRuntimeError(`Set.${name} expects a Set-like object.`, node).as("TypeError");
|
|
656
638
|
}
|
|
657
639
|
const object = source;
|
|
@@ -756,7 +738,7 @@ const invokeArrayMethod = (runner, target, name, args, node) => {
|
|
|
756
738
|
if (args.length > 1 || (args.length === 1 && typeof args[0] !== "string")) {
|
|
757
739
|
throw new InterpreterRuntimeError("Array.join expects zero arguments or one string separator.", node);
|
|
758
740
|
}
|
|
759
|
-
const input =
|
|
741
|
+
const input = toProgram(target, "Array.join input");
|
|
760
742
|
return Effect.succeed(input.map((item) => coerceToString(item ?? "")).join(args.length === 0 ? "," : args[0]));
|
|
761
743
|
}
|
|
762
744
|
case "includes":
|
|
@@ -992,11 +974,7 @@ const invokeArrayMethod = (runner, target, name, args, node) => {
|
|
|
992
974
|
};
|
|
993
975
|
const sortArray = (runner, target, comparator, name, node) => {
|
|
994
976
|
if (comparator === undefined) {
|
|
995
|
-
return Effect.sync(() => [...target].sort((a, b) =>
|
|
996
|
-
const left = coerceToString(a);
|
|
997
|
-
const right = coerceToString(b);
|
|
998
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
999
|
-
}));
|
|
977
|
+
return Effect.sync(() => [...target].sort((a, b) => compareText(coerceToString(a), coerceToString(b))));
|
|
1000
978
|
}
|
|
1001
979
|
const apply = applyCollectionCallback(runner, comparator, name, node);
|
|
1002
980
|
const mergeSort = (items) => {
|
|
@@ -1,23 +1,10 @@
|
|
|
1
|
+
import type { BlockStatement, Expression, Node, Pattern } from "acorn";
|
|
1
2
|
import type { Effect } from "effect";
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
};
|
|
8
|
-
export type SourceLocation = {
|
|
9
|
-
start: SourcePosition;
|
|
10
|
-
end: SourcePosition;
|
|
11
|
-
};
|
|
12
|
-
export type AstNode = {
|
|
13
|
-
type: string;
|
|
14
|
-
loc?: SourceLocation;
|
|
15
|
-
[key: string]: unknown;
|
|
16
|
-
};
|
|
17
|
-
export type ProgramNode = AstNode & {
|
|
18
|
-
type: "Program";
|
|
19
|
-
body: Array<AstNode>;
|
|
20
|
-
};
|
|
3
|
+
import type { DiagnosticKind } from "../codemode.js";
|
|
4
|
+
import type { SafeObject } from "../data.js";
|
|
5
|
+
import type { Values } from "../values.js";
|
|
6
|
+
/** Any parsed node; the interpreter narrows on `type` and reads `loc` for diagnostics. */
|
|
7
|
+
export type AstNode = Node;
|
|
21
8
|
export type Binding = {
|
|
22
9
|
mutable: boolean;
|
|
23
10
|
value: unknown;
|
|
@@ -36,16 +23,16 @@ export type StatementResult = {
|
|
|
36
23
|
label?: string;
|
|
37
24
|
};
|
|
38
25
|
export type MemberReference = {
|
|
39
|
-
target: SafeObject | Array<unknown> |
|
|
26
|
+
target: SafeObject | Array<unknown> | Values.RegExp | Values.URL;
|
|
40
27
|
key: PropertyKey;
|
|
41
28
|
};
|
|
42
29
|
export declare class CodeModeFunction {
|
|
43
|
-
readonly parameters: ReadonlyArray<
|
|
44
|
-
readonly body:
|
|
30
|
+
readonly parameters: ReadonlyArray<Pattern>;
|
|
31
|
+
readonly body: BlockStatement | Expression;
|
|
45
32
|
readonly capturedScopes: ReadonlyArray<Map<string, Binding>>;
|
|
46
33
|
readonly async: boolean;
|
|
47
34
|
readonly generator: boolean;
|
|
48
|
-
constructor(parameters: ReadonlyArray<
|
|
35
|
+
constructor(parameters: ReadonlyArray<Pattern>, body: BlockStatement | Expression, capturedScopes: ReadonlyArray<Map<string, Binding>>, async: boolean, generator: boolean);
|
|
49
36
|
}
|
|
50
37
|
export type GeneratorRequestKind = "next" | "return" | "throw";
|
|
51
38
|
export declare class CodeModeGenerator {
|
|
@@ -81,9 +68,9 @@ export declare class PromiseMethodReference {
|
|
|
81
68
|
}
|
|
82
69
|
export type PromiseInstanceMethodName = "then" | "catch" | "finally";
|
|
83
70
|
export declare class PromiseInstanceMethodReference {
|
|
84
|
-
readonly promise:
|
|
71
|
+
readonly promise: Values.Promise;
|
|
85
72
|
readonly name: PromiseInstanceMethodName;
|
|
86
|
-
constructor(promise:
|
|
73
|
+
constructor(promise: Values.Promise, name: PromiseInstanceMethodName);
|
|
87
74
|
}
|
|
88
75
|
export declare class PromiseCapabilityFunction {
|
|
89
76
|
readonly settle: (value: unknown) => void;
|
|
@@ -125,7 +112,6 @@ export declare class ErrorConstructorReference {
|
|
|
125
112
|
readonly name: string;
|
|
126
113
|
constructor(name: string);
|
|
127
114
|
}
|
|
128
|
-
export type DiagnosticKind = "ParseError" | "UnsupportedSyntax" | "UnknownTool" | "InvalidToolInput" | "InvalidToolOutput" | "InvalidDataValue" | "ToolCallLimitExceeded" | "TimeoutExceeded" | "ToolFailure" | "ExecutionFailure";
|
|
129
115
|
export declare const OptionalShortCircuit: unique symbol;
|
|
130
116
|
export declare const supportedSyntaxMessage = "Supported orchestration syntax: tools.* calls (they return promises - resolve them with await), data literals, destructuring, optional chaining, template literals, conditionals, switch, loops (incl. for...of and for...in over object/array/tools keys), arrow functions, spread, try/catch, array methods (map/filter/find/findIndex/some/every/reduce/flatMap/forEach/sort/slice/concat/indexOf/lastIndexOf/at/flat/reverse/includes/join), string methods (incl. match/matchAll/replace/split with regular expressions), Date/RegExp/Map/Set/URL/URLSearchParams, URI encoding helpers, Object/Math/JSON helpers, captured console.log/warn/error/dir/table, Promise.all/allSettled/race/any/resolve/reject over arrays mixing promises and plain values for parallel tool calls, promise chaining with .then/.catch/.finally, and new Promise((resolve, reject) => ...) construction.";
|
|
131
117
|
export declare class InterpreterRuntimeError extends Error {
|
|
@@ -138,12 +124,6 @@ export declare class InterpreterRuntimeError extends Error {
|
|
|
138
124
|
}
|
|
139
125
|
export declare const unsupportedSyntax: (kind: string, node: AstNode) => InterpreterRuntimeError;
|
|
140
126
|
export declare const isRecord: (value: unknown) => value is Record<string, unknown>;
|
|
141
|
-
export declare const asNode: (value: unknown, context: string) => AstNode;
|
|
142
|
-
export declare const getArray: (node: AstNode, key: string) => Array<unknown>;
|
|
143
|
-
export declare const getString: (node: AstNode, key: string) => string;
|
|
144
|
-
export declare const getBoolean: (node: AstNode, key: string) => boolean;
|
|
145
|
-
export declare const getOptionalNode: (node: AstNode, key: string) => AstNode | undefined;
|
|
146
|
-
export declare const getNode: (node: AstNode, key: string) => AstNode;
|
|
147
127
|
export declare const sourceLocation: (node: AstNode) => {
|
|
148
128
|
readonly line: number;
|
|
149
129
|
readonly column: number;
|
|
@@ -143,37 +143,6 @@ export class InterpreterRuntimeError extends Error {
|
|
|
143
143
|
}
|
|
144
144
|
export const unsupportedSyntax = (kind, node) => new InterpreterRuntimeError(`Syntax '${kind}' is not supported. ${supportedSyntaxMessage}`, node, "UnsupportedSyntax", [supportedSyntaxMessage]);
|
|
145
145
|
export const isRecord = (value) => typeof value === "object" && value !== null;
|
|
146
|
-
export const asNode = (value, context) => {
|
|
147
|
-
if (!isRecord(value) || typeof value.type !== "string") {
|
|
148
|
-
throw new InterpreterRuntimeError(`Invalid AST node while reading ${context}.`);
|
|
149
|
-
}
|
|
150
|
-
return value;
|
|
151
|
-
};
|
|
152
|
-
export const getArray = (node, key) => {
|
|
153
|
-
const value = node[key];
|
|
154
|
-
if (!Array.isArray(value))
|
|
155
|
-
throw new InterpreterRuntimeError(`Expected '${key}' to be an array.`, node);
|
|
156
|
-
return value;
|
|
157
|
-
};
|
|
158
|
-
export const getString = (node, key) => {
|
|
159
|
-
const value = node[key];
|
|
160
|
-
if (typeof value !== "string")
|
|
161
|
-
throw new InterpreterRuntimeError(`Expected '${key}' to be a string.`, node);
|
|
162
|
-
return value;
|
|
163
|
-
};
|
|
164
|
-
export const getBoolean = (node, key) => {
|
|
165
|
-
const value = node[key];
|
|
166
|
-
if (typeof value !== "boolean")
|
|
167
|
-
throw new InterpreterRuntimeError(`Expected '${key}' to be a boolean.`, node);
|
|
168
|
-
return value;
|
|
169
|
-
};
|
|
170
|
-
export const getOptionalNode = (node, key) => {
|
|
171
|
-
const value = node[key];
|
|
172
|
-
if (value === undefined || value === null)
|
|
173
|
-
return undefined;
|
|
174
|
-
return asNode(value, key);
|
|
175
|
-
};
|
|
176
|
-
export const getNode = (node, key) => asNode(node[key], key);
|
|
177
146
|
export const sourceLocation = (node) => ({
|
|
178
147
|
line: Math.max(1, (node.loc?.start.line ?? 2) - 1),
|
|
179
148
|
column: Math.max(1, (node.loc?.start.column ?? 4) - 3),
|
|
@@ -2,7 +2,7 @@ import { Effect, Exit, Scope } from "effect";
|
|
|
2
2
|
import type { Diagnostic } from "../codemode.js";
|
|
3
3
|
import { type AstNode, InterpreterRuntimeError, PromiseInstanceMethodReference, PromiseMethodReference } from "./model.js";
|
|
4
4
|
import { type CallbackRunner } from "./methods.js";
|
|
5
|
-
import {
|
|
5
|
+
import { Values } from "../values.js";
|
|
6
6
|
import type { SyncIteratorRunner } from "./iterator.js";
|
|
7
7
|
export declare class PromiseRuntime<R> {
|
|
8
8
|
private readonly scope;
|
|
@@ -12,18 +12,18 @@ export declare class PromiseRuntime<R> {
|
|
|
12
12
|
private readonly failures;
|
|
13
13
|
private nextID;
|
|
14
14
|
constructor(scope: Scope.Scope);
|
|
15
|
-
create(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<
|
|
16
|
-
markObserved(promise:
|
|
17
|
-
await(promise:
|
|
15
|
+
create(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<Values.Promise, never, R>;
|
|
16
|
+
markObserved(promise: Values.Promise): void;
|
|
17
|
+
await(promise: Values.Promise): Effect.Effect<Exit.Exit<unknown, unknown>>;
|
|
18
18
|
fork(effect: Effect.Effect<unknown, unknown, R>): Effect.Effect<void, never, R>;
|
|
19
19
|
diagnostics(): Array<Diagnostic>;
|
|
20
20
|
interrupt(): Effect.Effect<Array<Diagnostic>>;
|
|
21
21
|
}
|
|
22
22
|
export declare const selfResolutionError: (node?: AstNode) => InterpreterRuntimeError;
|
|
23
23
|
export declare const resolvePromiseValue: <R>(runner: CallbackRunner<R>, value: unknown, node: AstNode, own?: {
|
|
24
|
-
promise?:
|
|
24
|
+
promise?: Values.Promise;
|
|
25
25
|
}) => Effect.Effect<unknown, unknown, R>;
|
|
26
|
-
export declare const resolvePromise: <R>(runner: CallbackRunner<R>, promises: PromiseRuntime<R>, value: unknown, node: AstNode) => Effect.Effect<
|
|
26
|
+
export declare const resolvePromise: <R>(runner: CallbackRunner<R>, promises: PromiseRuntime<R>, value: unknown, node: AstNode) => Effect.Effect<Values.Promise, never, R>;
|
|
27
27
|
export declare const invokePromiseMethod: <R>(runner: CallbackRunner<R> & SyncIteratorRunner<R>, promises: PromiseRuntime<R>, ref: PromiseMethodReference, args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
|
|
28
|
-
export declare const invokePromiseInstanceMethod: <R>(runner: CallbackRunner<R>, promises: PromiseRuntime<R>, ref: PromiseInstanceMethodReference, args: Array<unknown>, node: AstNode) => Effect.Effect<
|
|
29
|
-
export declare const constructPromise: <R>(runner: CallbackRunner<R>, promises: PromiseRuntime<R>, executor: unknown, node: AstNode) => Effect.Effect<
|
|
28
|
+
export declare const invokePromiseInstanceMethod: <R>(runner: CallbackRunner<R>, promises: PromiseRuntime<R>, ref: PromiseInstanceMethodReference, args: Array<unknown>, node: AstNode) => Effect.Effect<Values.Promise, never, R>;
|
|
29
|
+
export declare const constructPromise: <R>(runner: CallbackRunner<R>, promises: PromiseRuntime<R>, executor: unknown, node: AstNode) => Effect.Effect<Values.Promise, unknown, R>;
|
|
@@ -4,7 +4,7 @@ import { caughtErrorValue, normalizeError } from "./errors.js";
|
|
|
4
4
|
import { applyCollectionCallback, isSupportedCallback } from "./methods.js";
|
|
5
5
|
import { typeofValue } from "./references.js";
|
|
6
6
|
import { createAggregateErrorValue } from "../stdlib/value.js";
|
|
7
|
-
import {
|
|
7
|
+
import { Values } from "../values.js";
|
|
8
8
|
// Observation only controls rejection reporting; program completion interrupts all promise work.
|
|
9
9
|
export class PromiseRuntime {
|
|
10
10
|
scope;
|
|
@@ -21,7 +21,7 @@ export class PromiseRuntime {
|
|
|
21
21
|
// Allocate before forking so reruns get distinct IDs and diagnostics retain creation order.
|
|
22
22
|
const id = this.nextID++;
|
|
23
23
|
return Effect.map(Effect.forkIn(effect, this.scope, { startImmediately: true }), (fiber) => {
|
|
24
|
-
const promise = new
|
|
24
|
+
const promise = new Values.Promise(fiber);
|
|
25
25
|
this.active.add(promise);
|
|
26
26
|
this.ids.set(promise, id);
|
|
27
27
|
fiber.addObserver((exit) => {
|
|
@@ -72,7 +72,7 @@ export const selfResolutionError = (node) => new InterpreterRuntimeError("Chaini
|
|
|
72
72
|
export const resolvePromiseValue = (runner, value, node, own) => {
|
|
73
73
|
if (own?.promise !== undefined && value === own.promise)
|
|
74
74
|
return Effect.fail(selfResolutionError(node));
|
|
75
|
-
if (value instanceof
|
|
75
|
+
if (value instanceof Values.Promise)
|
|
76
76
|
return runner.settlePromise(value);
|
|
77
77
|
if (value === null || typeof value !== "object" || !Object.hasOwn(value, "then"))
|
|
78
78
|
return Effect.succeed(value);
|
|
@@ -99,7 +99,7 @@ export const resolvePromiseValue = (runner, value, node, own) => {
|
|
|
99
99
|
});
|
|
100
100
|
};
|
|
101
101
|
export const resolvePromise = (runner, promises, value, node) => {
|
|
102
|
-
if (value instanceof
|
|
102
|
+
if (value instanceof Values.Promise)
|
|
103
103
|
return Effect.succeed(value);
|
|
104
104
|
const box = {};
|
|
105
105
|
return Effect.map(promises.create(resolvePromiseValue(runner, value, node, box)), (promise) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AsyncIteratorSymbol, CodeModeFunction, CodeModeGenerator, CoercionFunction, ErrorConstructorReference, GlobalMethodReference, GlobalNamespace, GeneratorMethodReference, InterpreterRuntimeError, IntrinsicReference, IteratorSymbol, JsonMethodReference, PromiseCapabilityFunction, PromiseInstanceMethodReference, PromiseMethodReference, PromiseNamespace, SearchFunction, SymbolNamespace, UriFunction, } from "./model.js";
|
|
2
2
|
import { ToolReference } from "../tool-runtime.js";
|
|
3
|
-
import {
|
|
3
|
+
import { Values } from "../values.js";
|
|
4
4
|
export const isRuntimeReference = (value) => value instanceof CodeModeFunction ||
|
|
5
5
|
value instanceof CodeModeGenerator ||
|
|
6
6
|
value instanceof GeneratorMethodReference ||
|
|
@@ -12,14 +12,14 @@ export const isRuntimeReference = (value) => value instanceof CodeModeFunction |
|
|
|
12
12
|
value instanceof PromiseNamespace ||
|
|
13
13
|
value instanceof PromiseMethodReference ||
|
|
14
14
|
value instanceof PromiseInstanceMethodReference ||
|
|
15
|
-
value instanceof
|
|
15
|
+
value instanceof Values.Promise ||
|
|
16
16
|
value instanceof CoercionFunction ||
|
|
17
17
|
value instanceof UriFunction ||
|
|
18
18
|
value instanceof SearchFunction ||
|
|
19
19
|
value instanceof PromiseCapabilityFunction ||
|
|
20
20
|
value instanceof ErrorConstructorReference ||
|
|
21
21
|
value instanceof SymbolNamespace ||
|
|
22
|
-
|
|
22
|
+
Values.isValue(value);
|
|
23
23
|
function* childValues(value) {
|
|
24
24
|
for (const key of Reflect.ownKeys(value)) {
|
|
25
25
|
if (!Object.prototype.propertyIsEnumerable.call(value, key))
|
|
@@ -29,9 +29,9 @@ function* childValues(value) {
|
|
|
29
29
|
yield Reflect.get(value, key);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
// Depth-first search over a value tree. `match` stops the walk; `skip` prunes a subtree without matching it.
|
|
33
|
+
const find = (value, match, skip, seen) => {
|
|
33
34
|
const pending = [[value].values()];
|
|
34
|
-
const seen = new Set();
|
|
35
35
|
while (pending.length > 0) {
|
|
36
36
|
const next = pending.at(-1).next();
|
|
37
37
|
if (next.done) {
|
|
@@ -39,53 +39,23 @@ export const containsRuntimeReference = (value) => {
|
|
|
39
39
|
continue;
|
|
40
40
|
}
|
|
41
41
|
const current = next.value;
|
|
42
|
-
if (
|
|
42
|
+
if (match(current))
|
|
43
43
|
return true;
|
|
44
|
-
if (current === null || typeof current !== "object" || seen.has(current))
|
|
44
|
+
if (current === null || typeof current !== "object" || skip(current) || seen.has(current))
|
|
45
45
|
continue;
|
|
46
46
|
seen.add(current);
|
|
47
47
|
pending.push(childValues(current));
|
|
48
48
|
}
|
|
49
49
|
return false;
|
|
50
50
|
};
|
|
51
|
+
const never = () => false;
|
|
52
|
+
export const containsRuntimeReference = (value) => find(value, isRuntimeReference, never, new Set());
|
|
51
53
|
// CodeMode values are data here, not opaque interpreter references.
|
|
52
|
-
export const containsOpaqueReference = (value) =>
|
|
53
|
-
const pending = [[value].values()];
|
|
54
|
-
const seen = new Set();
|
|
55
|
-
while (pending.length > 0) {
|
|
56
|
-
const next = pending.at(-1).next();
|
|
57
|
-
if (next.done) {
|
|
58
|
-
pending.pop();
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
const current = next.value;
|
|
62
|
-
if (isCodeModeValue(current))
|
|
63
|
-
continue;
|
|
64
|
-
if (isRuntimeReference(current))
|
|
65
|
-
return true;
|
|
66
|
-
if (current === null || typeof current !== "object" || seen.has(current))
|
|
67
|
-
continue;
|
|
68
|
-
seen.add(current);
|
|
69
|
-
pending.push(childValues(current));
|
|
70
|
-
}
|
|
71
|
-
return false;
|
|
72
|
-
};
|
|
54
|
+
export const containsOpaqueReference = (value) => find(value, (current) => !Values.isValue(current) && isRuntimeReference(current), Values.isValue, new Set());
|
|
73
55
|
// Reject cycles before mutation so later boundary walks remain safe.
|
|
74
56
|
export const rejectCircularInsertion = (container, value, label, node, seen = new Set()) => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const next = pending.at(-1).next();
|
|
78
|
-
if (next.done) {
|
|
79
|
-
pending.pop();
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
const current = next.value;
|
|
83
|
-
if (current === container)
|
|
84
|
-
throw new InterpreterRuntimeError(`${label} contains a circular value.`, node, "InvalidDataValue");
|
|
85
|
-
if (current === null || typeof current !== "object" || isRuntimeReference(current) || seen.has(current))
|
|
86
|
-
continue;
|
|
87
|
-
seen.add(current);
|
|
88
|
-
pending.push(childValues(current));
|
|
57
|
+
if (find(value, (current) => current === container, isRuntimeReference, seen)) {
|
|
58
|
+
throw new InterpreterRuntimeError(`${label} contains a circular value.`, node, "InvalidDataValue");
|
|
89
59
|
}
|
|
90
60
|
};
|
|
91
61
|
export const typeofValue = (value) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { Program } from "acorn";
|
|
1
2
|
import { Effect } from "effect";
|
|
2
|
-
import { type ProgramNode } from "./model.js";
|
|
3
3
|
import { PromiseRuntime } from "./promises.js";
|
|
4
4
|
export declare class Interpreter<R> {
|
|
5
5
|
private scopes;
|
|
@@ -12,7 +12,7 @@ export declare class Interpreter<R> {
|
|
|
12
12
|
private generatorAsync;
|
|
13
13
|
private readonly runner;
|
|
14
14
|
constructor(executeTool: (path: ReadonlyArray<string>, args: Array<unknown>) => Effect.Effect<unknown, unknown, R>, invokeSearch: (args: Array<unknown>) => Effect.Effect<unknown, unknown, R>, toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>, promises: PromiseRuntime<R>, logs?: Array<string>);
|
|
15
|
-
run(program:
|
|
15
|
+
run(program: Program): Effect.Effect<unknown, unknown, R>;
|
|
16
16
|
private createToolCallPromise;
|
|
17
17
|
private createPromise;
|
|
18
18
|
private settlePromise;
|
|
@@ -55,7 +55,6 @@ export declare class Interpreter<R> {
|
|
|
55
55
|
private constructArray;
|
|
56
56
|
private constructObject;
|
|
57
57
|
private constructDate;
|
|
58
|
-
private toDatePrimitive;
|
|
59
58
|
private constructRegExp;
|
|
60
59
|
private constructMap;
|
|
61
60
|
private constructSet;
|