@opencode/codemode 0.0.0-beta-19296 → 0.0.0-beta-19378
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 +4 -6
- package/dist/interpreter/errors.js +22 -6
- package/dist/interpreter/execute.d.ts +3 -3
- package/dist/interpreter/execute.js +11 -18
- package/dist/interpreter/globals.d.ts +13 -0
- package/dist/interpreter/globals.js +59 -0
- package/dist/interpreter/host.d.ts +41 -0
- package/dist/interpreter/host.js +44 -0
- package/dist/interpreter/methods.d.ts +3 -16
- package/dist/interpreter/methods.js +42 -239
- package/dist/interpreter/model.d.ts +12 -73
- package/dist/interpreter/model.js +0 -87
- package/dist/interpreter/promises.d.ts +12 -13
- package/dist/interpreter/promises.js +49 -26
- package/dist/interpreter/references.js +23 -70
- package/dist/interpreter/runner.d.ts +23 -0
- package/dist/interpreter/runner.js +42 -0
- package/dist/interpreter/runtime.d.ts +13 -95
- package/dist/interpreter/runtime.js +290 -723
- package/dist/openapi/spec.js +1 -1
- package/dist/stdlib/array.d.ts +3 -0
- package/dist/stdlib/array.js +73 -0
- package/dist/stdlib/collections.d.ts +6 -1
- package/dist/stdlib/collections.js +120 -1
- package/dist/stdlib/console.d.ts +3 -2
- package/dist/stdlib/console.js +25 -16
- package/dist/stdlib/date.d.ts +5 -4
- package/dist/stdlib/date.js +28 -12
- package/dist/stdlib/json.d.ts +4 -4
- package/dist/stdlib/json.js +23 -28
- package/dist/stdlib/math.d.ts +3 -7
- package/dist/stdlib/math.js +85 -153
- package/dist/stdlib/number.d.ts +2 -4
- package/dist/stdlib/number.js +30 -37
- package/dist/stdlib/object.d.ts +4 -6
- package/dist/stdlib/object.js +106 -75
- package/dist/stdlib/regexp.d.ts +4 -6
- package/dist/stdlib/regexp.js +35 -12
- package/dist/stdlib/string.d.ts +1 -3
- package/dist/stdlib/string.js +15 -17
- package/dist/stdlib/url.d.ts +10 -6
- package/dist/stdlib/url.js +102 -25
- package/dist/stdlib/value.d.ts +6 -5
- package/dist/stdlib/value.js +33 -32
- 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
- package/dist/interpreter/iterator.d.ts +0 -13
- package/dist/interpreter/iterator.js +0 -4
- package/dist/stdlib/promise.d.ts +0 -2
- package/dist/stdlib/promise.js +0 -1
|
@@ -1,29 +1,15 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { boundedData, coerceToNumber, coerceToString, errorBrandName } from "../stdlib/value.js";
|
|
14
|
-
import { preserveConsumerError } from "./iterator.js";
|
|
15
|
-
export const isSupportedCallback = (value) => value instanceof CodeModeFunction ||
|
|
16
|
-
value instanceof CoercionFunction ||
|
|
17
|
-
value instanceof UriFunction ||
|
|
18
|
-
value instanceof PromiseCapabilityFunction ||
|
|
19
|
-
value instanceof GlobalMethodReference ||
|
|
20
|
-
value instanceof JsonMethodReference ||
|
|
21
|
-
value instanceof IntrinsicReference ||
|
|
22
|
-
value instanceof ErrorConstructorReference ||
|
|
23
|
-
// Callable namespaces dispatch like JS: Array/Object/Date/RegExp construct,
|
|
24
|
-
// new-requiring constructors throw a TypeError. Math/JSON/console stay non-callable.
|
|
25
|
-
(value instanceof GlobalNamespace && typeofValue(value) === "function") ||
|
|
26
|
-
value instanceof PromiseNamespace;
|
|
2
|
+
import { isBlockedMember, toProgram } from "../data.js";
|
|
3
|
+
import { dateSetterArgumentCount, invokeDateMethod } from "../stdlib/date.js";
|
|
4
|
+
import { invokeNumberMethod } from "../stdlib/number.js";
|
|
5
|
+
import { invokeRegExpMethod, matchToValue, toHostRegex } from "../stdlib/regexp.js";
|
|
6
|
+
import { invokeURLMethod, uriArgument } from "../stdlib/url.js";
|
|
7
|
+
import { coerceToNumber, coerceToString, errorBrandName } from "../stdlib/value.js";
|
|
8
|
+
import { compareText } from "../tool-runtime.js";
|
|
9
|
+
import { Values } from "../values.js";
|
|
10
|
+
import { IntrinsicReference, InterpreterRuntimeError } from "./model.js";
|
|
11
|
+
import { containsOpaqueReference, rejectCircularInsertion, typeofValue } from "./references.js";
|
|
12
|
+
import { applyCollectionCallback, isSupportedCallback, toPrimitive } from "./runner.js";
|
|
27
13
|
export const invokeIntrinsic = (runner, ref, args, node) => {
|
|
28
14
|
if (typeof ref.receiver === "string") {
|
|
29
15
|
if (ref.name === "replace" || ref.name === "replaceAll") {
|
|
@@ -41,7 +27,7 @@ export const invokeIntrinsic = (runner, ref, args, node) => {
|
|
|
41
27
|
if (Array.isArray(ref.receiver)) {
|
|
42
28
|
return invokeArrayMethod(runner, ref.receiver, ref.name, args, node);
|
|
43
29
|
}
|
|
44
|
-
if (ref.receiver instanceof
|
|
30
|
+
if (ref.receiver instanceof Values.Date) {
|
|
45
31
|
const target = ref.receiver;
|
|
46
32
|
const argumentCount = dateSetterArgumentCount(ref.name);
|
|
47
33
|
if (argumentCount === undefined)
|
|
@@ -52,70 +38,31 @@ export const invokeIntrinsic = (runner, ref, args, node) => {
|
|
|
52
38
|
concurrency: 1,
|
|
53
39
|
}), (values) => invokeDateMethod(target, ref.name, values, node, initialTime));
|
|
54
40
|
}
|
|
55
|
-
if (ref.receiver instanceof
|
|
41
|
+
if (ref.receiver instanceof Values.RegExp) {
|
|
56
42
|
return Effect.succeed(invokeRegExpMethod(ref.receiver, ref.name, args, node));
|
|
57
43
|
}
|
|
58
|
-
if (ref.receiver instanceof
|
|
44
|
+
if (ref.receiver instanceof Values.Map) {
|
|
59
45
|
return invokeMapMethod(runner, ref.receiver, ref.name, args, node);
|
|
60
46
|
}
|
|
61
|
-
if (ref.receiver instanceof
|
|
47
|
+
if (ref.receiver instanceof Values.Set) {
|
|
62
48
|
return invokeSetMethod(runner, ref.receiver, ref.name, args, node);
|
|
63
49
|
}
|
|
64
|
-
if (ref.receiver instanceof
|
|
50
|
+
if (ref.receiver instanceof Values.URL) {
|
|
65
51
|
return Effect.succeed(invokeURLMethod(ref.receiver, ref.name, node));
|
|
66
52
|
}
|
|
67
|
-
if (ref.receiver instanceof
|
|
53
|
+
if (ref.receiver instanceof Values.URLSearchParams) {
|
|
68
54
|
return invokeURLSearchParamsMethod(runner, ref.receiver, ref.name, args, node);
|
|
69
55
|
}
|
|
70
56
|
throw new InterpreterRuntimeError(`Method '${ref.name}' is not available.`, node);
|
|
71
57
|
};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (result === null || (typeof result !== "object" && typeof result !== "function")) {
|
|
81
|
-
return coerceToNumber(result);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
if (!Object.hasOwn(object, "toString"))
|
|
85
|
-
return coerceToNumber(value);
|
|
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
|
-
}
|
|
91
|
-
}
|
|
92
|
-
throw new InterpreterRuntimeError("Cannot convert object to primitive value.", node).as("TypeError");
|
|
93
|
-
});
|
|
94
|
-
};
|
|
95
|
-
export const invokeGlobalMethod = (ref, args, node) => {
|
|
96
|
-
if (ref.namespace === "console")
|
|
97
|
-
throw new InterpreterRuntimeError(`console.${ref.name} is not available.`, node);
|
|
98
|
-
if (ref.namespace === "Object")
|
|
99
|
-
return invokeObjectMethod(ref.name, args, node);
|
|
100
|
-
if (ref.namespace === "Math")
|
|
101
|
-
return invokeMathMethod(ref.name, args, node);
|
|
102
|
-
if (ref.namespace === "Array")
|
|
103
|
-
return invokeArrayStatic(ref.name, args, node);
|
|
104
|
-
if (ref.namespace === "Number")
|
|
105
|
-
return invokeNumberStatic(ref.name, args, node);
|
|
106
|
-
if (ref.namespace === "String")
|
|
107
|
-
return invokeStringStatic(ref.name, args, node);
|
|
108
|
-
if (ref.namespace === "URL")
|
|
109
|
-
return invokeURLStatic(ref.name, args, node);
|
|
110
|
-
if (ref.namespace === "Date")
|
|
111
|
-
return invokeDateStatic(ref.name, args, node);
|
|
112
|
-
if (ref.namespace === "RegExp")
|
|
113
|
-
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
|
-
throw new InterpreterRuntimeError(`${ref.namespace}.${ref.name} is not available.`, node);
|
|
118
|
-
};
|
|
58
|
+
/**
|
|
59
|
+
* ToPrimitive: tries an object's own `valueOf`/`toString` in hint order and returns the first
|
|
60
|
+
* primitive result. Runtime values behave like their JS counterparts (Date yields its time under a
|
|
61
|
+
* number hint; the rest yield their string form). An inherited `toString` yields the default
|
|
62
|
+
* string form, so plain objects become "[object Object]" and arrays join.
|
|
63
|
+
*/
|
|
64
|
+
const coerceNumericArgument = (runner, value, node) => Effect.map(toPrimitive(runner, value, "number", node), coerceToNumber);
|
|
65
|
+
// console is intercepted by the interpreter before reaching here.
|
|
119
66
|
const requireDataArgument = (name, index, arg, node) => {
|
|
120
67
|
if (containsOpaqueReference(arg)) {
|
|
121
68
|
throw new InterpreterRuntimeError(`String.${name} expects argument ${index + 1} to be a data value.`, node, "InvalidDataValue");
|
|
@@ -129,7 +76,7 @@ const invokeStringMethod = (value, name, args, node) => {
|
|
|
129
76
|
const optNum = (index) => (args[index] === undefined ? undefined : num(index));
|
|
130
77
|
const optStr = (index) => (args[index] === undefined ? undefined : str(index));
|
|
131
78
|
const rejectRegex = () => {
|
|
132
|
-
if (args[0] instanceof
|
|
79
|
+
if (args[0] instanceof Values.RegExp) {
|
|
133
80
|
throw new InterpreterRuntimeError(`String.${name} cannot take a regular expression; use regex.test(string) or String.search instead.`, node).as("TypeError");
|
|
134
81
|
}
|
|
135
82
|
};
|
|
@@ -172,7 +119,7 @@ const invokeStringMethod = (value, name, args, node) => {
|
|
|
172
119
|
result = requestedLimit !== undefined && requestedLimit >>> 0 === 0 ? [] : [value];
|
|
173
120
|
break;
|
|
174
121
|
}
|
|
175
|
-
if (args[0] instanceof
|
|
122
|
+
if (args[0] instanceof Values.RegExp) {
|
|
176
123
|
result = value.split(args[0].regex, optNum(1));
|
|
177
124
|
break;
|
|
178
125
|
}
|
|
@@ -203,7 +150,7 @@ const invokeStringMethod = (value, name, args, node) => {
|
|
|
203
150
|
break;
|
|
204
151
|
case "replace":
|
|
205
152
|
case "replaceAll": {
|
|
206
|
-
if (args[0] instanceof
|
|
153
|
+
if (args[0] instanceof Values.RegExp) {
|
|
207
154
|
const pattern = args[0].regex;
|
|
208
155
|
const replacement = str(1);
|
|
209
156
|
if (name === "replaceAll" && !pattern.global) {
|
|
@@ -226,7 +173,7 @@ const invokeStringMethod = (value, name, args, node) => {
|
|
|
226
173
|
return null;
|
|
227
174
|
// Preserve the own `index` and `groups` properties on non-global matches.
|
|
228
175
|
if (pattern.global)
|
|
229
|
-
return
|
|
176
|
+
return toProgram(matched, "String.match result");
|
|
230
177
|
return matchToValue(matched);
|
|
231
178
|
}
|
|
232
179
|
case "matchAll": {
|
|
@@ -278,138 +225,7 @@ const invokeStringMethod = (value, name, args, node) => {
|
|
|
278
225
|
default:
|
|
279
226
|
throw new InterpreterRuntimeError(`String method '${name}' is not available.`, node);
|
|
280
227
|
}
|
|
281
|
-
return
|
|
282
|
-
};
|
|
283
|
-
export const arrayStatics = new Set(["isArray", "of", "from"]);
|
|
284
|
-
const invokeArrayStatic = (name, args, node) => {
|
|
285
|
-
switch (name) {
|
|
286
|
-
case "isArray":
|
|
287
|
-
return Array.isArray(args[0]);
|
|
288
|
-
case "of":
|
|
289
|
-
return [...args];
|
|
290
|
-
default:
|
|
291
|
-
throw new InterpreterRuntimeError(`Array.${name} is not available.`, node);
|
|
292
|
-
}
|
|
293
|
-
};
|
|
294
|
-
const arrayLikeSource = (source, node) => {
|
|
295
|
-
if (source instanceof CodeModePromise) {
|
|
296
|
-
throw new InterpreterRuntimeError("Array.from received an un-awaited Promise; await it before creating the array.", node, "InvalidDataValue");
|
|
297
|
-
}
|
|
298
|
-
if (source !== null &&
|
|
299
|
-
typeof source === "object" &&
|
|
300
|
-
(Object.getPrototypeOf(source) === Object.prototype || Object.getPrototypeOf(source) === null) &&
|
|
301
|
-
typeof source.length === "number") {
|
|
302
|
-
const length = source.length;
|
|
303
|
-
const normalized = Number.isNaN(length) || length <= 0 ? 0 : Math.trunc(length);
|
|
304
|
-
if (normalized > 4_294_967_295)
|
|
305
|
-
throw new RangeError("Invalid array length");
|
|
306
|
-
return { length: normalized, source };
|
|
307
|
-
}
|
|
308
|
-
throw new InterpreterRuntimeError("Array.from expects an array, string, Map, Set, or array-like value.", node, "InvalidDataValue");
|
|
309
|
-
};
|
|
310
|
-
export const invokeArrayFrom = (runner, args, node) => {
|
|
311
|
-
const source = args[0];
|
|
312
|
-
const apply = args.length < 2 || args[1] === undefined ? undefined : applyCollectionCallback(runner, args[1], "Array.from", node);
|
|
313
|
-
return Effect.gen(function* () {
|
|
314
|
-
const cursor = yield* runner.syncIterator(source, node);
|
|
315
|
-
if (cursor === undefined) {
|
|
316
|
-
if (source instanceof CodeModeGenerator) {
|
|
317
|
-
throw new InterpreterRuntimeError("Array.from expects a synchronous iterable or array-like value.", node).as("TypeError");
|
|
318
|
-
}
|
|
319
|
-
const arrayLike = arrayLikeSource(source, node);
|
|
320
|
-
const values = [];
|
|
321
|
-
for (let index = 0; index < arrayLike.length; index += 1) {
|
|
322
|
-
const item = Reflect.get(arrayLike.source, index);
|
|
323
|
-
values.push(apply === undefined ? item : yield* apply([item, index]));
|
|
324
|
-
}
|
|
325
|
-
return values;
|
|
326
|
-
}
|
|
327
|
-
const values = [];
|
|
328
|
-
let index = 0;
|
|
329
|
-
while (true) {
|
|
330
|
-
const step = yield* cursor.next;
|
|
331
|
-
if (step.done)
|
|
332
|
-
return values;
|
|
333
|
-
values.push(apply === undefined ? step.value : yield* preserveConsumerError(cursor, apply([step.value, index])));
|
|
334
|
-
index += 1;
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
};
|
|
338
|
-
export const invokeGroupBy = (runner, namespace, args, node) => {
|
|
339
|
-
const source = args[0];
|
|
340
|
-
if (source === null || source === undefined) {
|
|
341
|
-
throw new InterpreterRuntimeError(`${namespace}.groupBy expects an iterable collection.`, node).as("TypeError");
|
|
342
|
-
}
|
|
343
|
-
const apply = applyCollectionCallback(runner, args[1], `${namespace}.groupBy`, node);
|
|
344
|
-
return Effect.gen(function* () {
|
|
345
|
-
const cursor = yield* runner.syncIterator(source, node);
|
|
346
|
-
if (cursor === undefined) {
|
|
347
|
-
throw new InterpreterRuntimeError(`${namespace}.groupBy expects an iterable collection.`, node).as("TypeError");
|
|
348
|
-
}
|
|
349
|
-
if (namespace === "Map") {
|
|
350
|
-
const result = new CodeModeMap();
|
|
351
|
-
let index = 0;
|
|
352
|
-
while (true) {
|
|
353
|
-
const step = yield* cursor.next;
|
|
354
|
-
if (step.done)
|
|
355
|
-
return result;
|
|
356
|
-
const item = step.value;
|
|
357
|
-
const key = yield* preserveConsumerError(cursor, apply([item, index]));
|
|
358
|
-
const group = result.map.get(key);
|
|
359
|
-
if (group === undefined)
|
|
360
|
-
result.map.set(key, [item]);
|
|
361
|
-
else
|
|
362
|
-
group.push(item);
|
|
363
|
-
index += 1;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
const result = Object.create(null);
|
|
367
|
-
let index = 0;
|
|
368
|
-
while (true) {
|
|
369
|
-
const step = yield* cursor.next;
|
|
370
|
-
if (step.done)
|
|
371
|
-
return result;
|
|
372
|
-
const item = step.value;
|
|
373
|
-
const key = yield* preserveConsumerError(cursor, Effect.flatMap(apply([item, index]), (value) => coerceGroupByPropertyKey(runner, value, node)));
|
|
374
|
-
if (isBlockedMember(key)) {
|
|
375
|
-
return yield* preserveConsumerError(cursor, Effect.fail(new InterpreterRuntimeError(`Property '${key}' is not available.`, node)));
|
|
376
|
-
}
|
|
377
|
-
const group = result[key];
|
|
378
|
-
if (group === undefined)
|
|
379
|
-
result[key] = [item];
|
|
380
|
-
else
|
|
381
|
-
group.push(item);
|
|
382
|
-
index += 1;
|
|
383
|
-
}
|
|
384
|
-
});
|
|
385
|
-
};
|
|
386
|
-
const coerceGroupByPropertyKey = (runner, value, node) => {
|
|
387
|
-
if (value === null || typeof value !== "object" || Array.isArray(value) || isCodeModeValue(value)) {
|
|
388
|
-
return Effect.succeed(coerceToString(value));
|
|
389
|
-
}
|
|
390
|
-
if (value instanceof CodeModePromise)
|
|
391
|
-
return Effect.succeed("[object Promise]");
|
|
392
|
-
if (isRuntimeReference(value)) {
|
|
393
|
-
throw new InterpreterRuntimeError("Object.groupBy callback must return a data value.", node, "InvalidDataValue");
|
|
394
|
-
}
|
|
395
|
-
const object = value;
|
|
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
|
-
});
|
|
228
|
+
return toProgram(result, `String.${name} result`);
|
|
413
229
|
};
|
|
414
230
|
const invokeStringReplacer = (runner, value, name, args, node) => {
|
|
415
231
|
const apply = applyCollectionCallback(runner, args[1], `String.${name}`, node);
|
|
@@ -434,7 +250,7 @@ const invokeStringReplacer = (runner, value, name, args, node) => {
|
|
|
434
250
|
return match;
|
|
435
251
|
};
|
|
436
252
|
const pattern = args[0];
|
|
437
|
-
if (pattern instanceof
|
|
253
|
+
if (pattern instanceof Values.RegExp) {
|
|
438
254
|
if (name === "replaceAll" && !pattern.regex.global) {
|
|
439
255
|
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
256
|
}
|
|
@@ -455,27 +271,18 @@ const invokeStringReplacer = (runner, value, name, args, node) => {
|
|
|
455
271
|
let end = 0;
|
|
456
272
|
for (const match of matches) {
|
|
457
273
|
const replacement = yield* apply(match.args);
|
|
458
|
-
// Error values are branded plain objects;
|
|
459
|
-
output.push(value.slice(end, match.offset), replacement instanceof
|
|
274
|
+
// Error values are branded plain objects; toProgram would strip the brand before coercion.
|
|
275
|
+
output.push(value.slice(end, match.offset), replacement instanceof Values.Promise
|
|
460
276
|
? "[object Promise]"
|
|
461
277
|
: errorBrandName(replacement)
|
|
462
278
|
? coerceToString(replacement)
|
|
463
|
-
: coerceToString(
|
|
279
|
+
: coerceToString(toProgram(replacement, `String.${name} replacer result`)));
|
|
464
280
|
end = match.offset + match.match.length;
|
|
465
281
|
}
|
|
466
282
|
output.push(value.slice(end));
|
|
467
|
-
return
|
|
283
|
+
return toProgram(output.join(""), `String.${name} result`);
|
|
468
284
|
});
|
|
469
285
|
};
|
|
470
|
-
export const applyCollectionCallback = (runner, callback, name, node) => {
|
|
471
|
-
if (!isSupportedCallback(callback)) {
|
|
472
|
-
if (typeofValue(callback) === "function") {
|
|
473
|
-
throw new InterpreterRuntimeError(`${name} cannot use this callable as a callback; wrap it in an arrow function, e.g. (value) => tools.ns.tool(value).`, node);
|
|
474
|
-
}
|
|
475
|
-
throw new InterpreterRuntimeError(`${name} expects a function callback.`, node).as("TypeError");
|
|
476
|
-
}
|
|
477
|
-
return (callbackArgs) => runner.invokeCallable(callback, callbackArgs, node);
|
|
478
|
-
};
|
|
479
286
|
const invokeMapMethod = (runner, target, name, args, node) => {
|
|
480
287
|
switch (name) {
|
|
481
288
|
case "get":
|
|
@@ -562,7 +369,7 @@ const invokeSetOperation = (runner, target, name, source, node) => Effect.gen(fu
|
|
|
562
369
|
return result;
|
|
563
370
|
}
|
|
564
371
|
if (name === "intersection") {
|
|
565
|
-
const result = new
|
|
372
|
+
const result = new Values.Set();
|
|
566
373
|
if (target.set.size <= other.size) {
|
|
567
374
|
for (const item of target.set.values()) {
|
|
568
375
|
if (yield* other.has(item))
|
|
@@ -631,27 +438,27 @@ const invokeSetOperation = (runner, target, name, source, node) => Effect.gen(fu
|
|
|
631
438
|
return true;
|
|
632
439
|
});
|
|
633
440
|
const copySet = (source) => {
|
|
634
|
-
const result = new
|
|
441
|
+
const result = new Values.Set();
|
|
635
442
|
for (const item of source.set.values())
|
|
636
443
|
result.set.add(item);
|
|
637
444
|
return result;
|
|
638
445
|
};
|
|
639
446
|
const loadSetRecord = (runner, source, name, node) => {
|
|
640
|
-
if (source instanceof
|
|
447
|
+
if (source instanceof Values.Set) {
|
|
641
448
|
return Effect.succeed({
|
|
642
449
|
size: source.set.size,
|
|
643
450
|
has: (item) => Effect.succeed(source.set.has(item)),
|
|
644
451
|
keys: () => Effect.succeed(source.set.values()),
|
|
645
452
|
});
|
|
646
453
|
}
|
|
647
|
-
if (source instanceof
|
|
454
|
+
if (source instanceof Values.Map) {
|
|
648
455
|
return Effect.succeed({
|
|
649
456
|
size: source.map.size,
|
|
650
457
|
has: (item) => Effect.succeed(source.map.has(item)),
|
|
651
458
|
keys: () => Effect.succeed(source.map.keys()),
|
|
652
459
|
});
|
|
653
460
|
}
|
|
654
|
-
if (source === null || typeof source !== "object" ||
|
|
461
|
+
if (source === null || typeof source !== "object" || Values.isValue(source)) {
|
|
655
462
|
throw new InterpreterRuntimeError(`Set.${name} expects a Set-like object.`, node).as("TypeError");
|
|
656
463
|
}
|
|
657
464
|
const object = source;
|
|
@@ -756,7 +563,7 @@ const invokeArrayMethod = (runner, target, name, args, node) => {
|
|
|
756
563
|
if (args.length > 1 || (args.length === 1 && typeof args[0] !== "string")) {
|
|
757
564
|
throw new InterpreterRuntimeError("Array.join expects zero arguments or one string separator.", node);
|
|
758
565
|
}
|
|
759
|
-
const input =
|
|
566
|
+
const input = toProgram(target, "Array.join input");
|
|
760
567
|
return Effect.succeed(input.map((item) => coerceToString(item ?? "")).join(args.length === 0 ? "," : args[0]));
|
|
761
568
|
}
|
|
762
569
|
case "includes":
|
|
@@ -992,11 +799,7 @@ const invokeArrayMethod = (runner, target, name, args, node) => {
|
|
|
992
799
|
};
|
|
993
800
|
const sortArray = (runner, target, comparator, name, node) => {
|
|
994
801
|
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
|
-
}));
|
|
802
|
+
return Effect.sync(() => [...target].sort((a, b) => compareText(coerceToString(a), coerceToString(b))));
|
|
1000
803
|
}
|
|
1001
804
|
const apply = applyCollectionCallback(runner, comparator, name, node);
|
|
1002
805
|
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 {
|
|
@@ -67,51 +54,14 @@ export declare class ComputedValue {
|
|
|
67
54
|
readonly value: unknown;
|
|
68
55
|
constructor(value: unknown);
|
|
69
56
|
}
|
|
70
|
-
export declare class PromiseNamespace {
|
|
71
|
-
}
|
|
72
|
-
export declare class SymbolNamespace {
|
|
73
|
-
}
|
|
74
57
|
export declare const AsyncIteratorSymbol: unique symbol;
|
|
75
58
|
export declare const IteratorSymbol: unique symbol;
|
|
76
59
|
export declare const IteratorSymbols: readonly [typeof AsyncIteratorSymbol, typeof IteratorSymbol];
|
|
77
|
-
export type PromiseMethodName = "all" | "allSettled" | "race" | "any" | "resolve" | "reject";
|
|
78
|
-
export declare class PromiseMethodReference {
|
|
79
|
-
readonly name: PromiseMethodName;
|
|
80
|
-
constructor(name: PromiseMethodName);
|
|
81
|
-
}
|
|
82
60
|
export type PromiseInstanceMethodName = "then" | "catch" | "finally";
|
|
83
61
|
export declare class PromiseInstanceMethodReference {
|
|
84
|
-
readonly promise:
|
|
62
|
+
readonly promise: Values.Promise;
|
|
85
63
|
readonly name: PromiseInstanceMethodName;
|
|
86
|
-
constructor(promise:
|
|
87
|
-
}
|
|
88
|
-
export declare class PromiseCapabilityFunction {
|
|
89
|
-
readonly settle: (value: unknown) => void;
|
|
90
|
-
constructor(settle: (value: unknown) => void);
|
|
91
|
-
}
|
|
92
|
-
export type GlobalNamespaceName = "Object" | "Math" | "JSON" | "Array" | "console" | "Date" | "RegExp" | "Map" | "Set" | "URL" | "URLSearchParams";
|
|
93
|
-
export declare class GlobalNamespace {
|
|
94
|
-
readonly name: GlobalNamespaceName;
|
|
95
|
-
constructor(name: GlobalNamespaceName);
|
|
96
|
-
}
|
|
97
|
-
export declare class GlobalMethodReference {
|
|
98
|
-
readonly namespace: Exclude<GlobalNamespaceName, "JSON"> | "Number" | "String";
|
|
99
|
-
readonly name: string;
|
|
100
|
-
constructor(namespace: Exclude<GlobalNamespaceName, "JSON"> | "Number" | "String", name: string);
|
|
101
|
-
}
|
|
102
|
-
export declare class JsonMethodReference {
|
|
103
|
-
readonly name: "parse" | "stringify";
|
|
104
|
-
constructor(name: "parse" | "stringify");
|
|
105
|
-
}
|
|
106
|
-
export declare class CoercionFunction {
|
|
107
|
-
readonly name: "Number" | "String" | "Boolean" | "parseInt" | "parseFloat" | "isFinite" | "isNaN";
|
|
108
|
-
constructor(name: "Number" | "String" | "Boolean" | "parseInt" | "parseFloat" | "isFinite" | "isNaN");
|
|
109
|
-
}
|
|
110
|
-
export declare class UriFunction {
|
|
111
|
-
readonly name: "encodeURI" | "encodeURIComponent" | "decodeURI" | "decodeURIComponent";
|
|
112
|
-
constructor(name: "encodeURI" | "encodeURIComponent" | "decodeURI" | "decodeURIComponent");
|
|
113
|
-
}
|
|
114
|
-
export declare class SearchFunction {
|
|
64
|
+
constructor(promise: Values.Promise, name: PromiseInstanceMethodName);
|
|
115
65
|
}
|
|
116
66
|
export declare class ProgramThrow {
|
|
117
67
|
readonly value: unknown;
|
|
@@ -121,11 +71,6 @@ export declare class GeneratorReturn {
|
|
|
121
71
|
readonly value: unknown;
|
|
122
72
|
constructor(value: unknown);
|
|
123
73
|
}
|
|
124
|
-
export declare class ErrorConstructorReference {
|
|
125
|
-
readonly name: string;
|
|
126
|
-
constructor(name: string);
|
|
127
|
-
}
|
|
128
|
-
export type DiagnosticKind = "ParseError" | "UnsupportedSyntax" | "UnknownTool" | "InvalidToolInput" | "InvalidToolOutput" | "InvalidDataValue" | "ToolCallLimitExceeded" | "TimeoutExceeded" | "ToolFailure" | "ExecutionFailure";
|
|
129
74
|
export declare const OptionalShortCircuit: unique symbol;
|
|
130
75
|
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
76
|
export declare class InterpreterRuntimeError extends Error {
|
|
@@ -138,12 +83,6 @@ export declare class InterpreterRuntimeError extends Error {
|
|
|
138
83
|
}
|
|
139
84
|
export declare const unsupportedSyntax: (kind: string, node: AstNode) => InterpreterRuntimeError;
|
|
140
85
|
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
86
|
export declare const sourceLocation: (node: AstNode) => {
|
|
148
87
|
readonly line: number;
|
|
149
88
|
readonly column: number;
|
|
@@ -42,19 +42,9 @@ export class ComputedValue {
|
|
|
42
42
|
this.value = value;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
export class PromiseNamespace {
|
|
46
|
-
}
|
|
47
|
-
export class SymbolNamespace {
|
|
48
|
-
}
|
|
49
45
|
export const AsyncIteratorSymbol = Symbol("codemode.async-iterator");
|
|
50
46
|
export const IteratorSymbol = Symbol("codemode.iterator");
|
|
51
47
|
export const IteratorSymbols = [AsyncIteratorSymbol, IteratorSymbol];
|
|
52
|
-
export class PromiseMethodReference {
|
|
53
|
-
name;
|
|
54
|
-
constructor(name) {
|
|
55
|
-
this.name = name;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
48
|
export class PromiseInstanceMethodReference {
|
|
59
49
|
promise;
|
|
60
50
|
name;
|
|
@@ -63,46 +53,6 @@ export class PromiseInstanceMethodReference {
|
|
|
63
53
|
this.name = name;
|
|
64
54
|
}
|
|
65
55
|
}
|
|
66
|
-
export class PromiseCapabilityFunction {
|
|
67
|
-
settle;
|
|
68
|
-
constructor(settle) {
|
|
69
|
-
this.settle = settle;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
export class GlobalNamespace {
|
|
73
|
-
name;
|
|
74
|
-
constructor(name) {
|
|
75
|
-
this.name = name;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
export class GlobalMethodReference {
|
|
79
|
-
namespace;
|
|
80
|
-
name;
|
|
81
|
-
constructor(namespace, name) {
|
|
82
|
-
this.namespace = namespace;
|
|
83
|
-
this.name = name;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
export class JsonMethodReference {
|
|
87
|
-
name;
|
|
88
|
-
constructor(name) {
|
|
89
|
-
this.name = name;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
export class CoercionFunction {
|
|
93
|
-
name;
|
|
94
|
-
constructor(name) {
|
|
95
|
-
this.name = name;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
export class UriFunction {
|
|
99
|
-
name;
|
|
100
|
-
constructor(name) {
|
|
101
|
-
this.name = name;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
export class SearchFunction {
|
|
105
|
-
}
|
|
106
56
|
export class ProgramThrow {
|
|
107
57
|
value;
|
|
108
58
|
constructor(value) {
|
|
@@ -115,12 +65,6 @@ export class GeneratorReturn {
|
|
|
115
65
|
this.value = value;
|
|
116
66
|
}
|
|
117
67
|
}
|
|
118
|
-
export class ErrorConstructorReference {
|
|
119
|
-
name;
|
|
120
|
-
constructor(name) {
|
|
121
|
-
this.name = name;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
68
|
export const OptionalShortCircuit = Symbol("codemode.optional-short-circuit");
|
|
125
69
|
export 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.";
|
|
126
70
|
export class InterpreterRuntimeError extends Error {
|
|
@@ -143,37 +87,6 @@ export class InterpreterRuntimeError extends Error {
|
|
|
143
87
|
}
|
|
144
88
|
export const unsupportedSyntax = (kind, node) => new InterpreterRuntimeError(`Syntax '${kind}' is not supported. ${supportedSyntaxMessage}`, node, "UnsupportedSyntax", [supportedSyntaxMessage]);
|
|
145
89
|
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
90
|
export const sourceLocation = (node) => ({
|
|
178
91
|
line: Math.max(1, (node.loc?.start.line ?? 2) - 1),
|
|
179
92
|
column: Math.max(1, (node.loc?.start.column ?? 4) - 3),
|