@opencode/codemode 0.0.0-reserved → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +184 -2
  2. package/dist/codemode.d.ts +145 -0
  3. package/dist/codemode.js +66 -0
  4. package/dist/data.d.ts +25 -0
  5. package/dist/data.js +153 -0
  6. package/dist/index.d.ts +7 -0
  7. package/dist/index.js +7 -0
  8. package/dist/interpreter/errors.d.ts +7 -0
  9. package/dist/interpreter/errors.js +106 -0
  10. package/dist/interpreter/execute.d.ts +5 -0
  11. package/dist/interpreter/execute.js +171 -0
  12. package/dist/interpreter/globals.d.ts +13 -0
  13. package/dist/interpreter/globals.js +63 -0
  14. package/dist/interpreter/host.d.ts +41 -0
  15. package/dist/interpreter/host.js +44 -0
  16. package/dist/interpreter/methods.d.ts +4 -0
  17. package/dist/interpreter/methods.js +837 -0
  18. package/dist/interpreter/model.d.ts +82 -0
  19. package/dist/interpreter/model.js +86 -0
  20. package/dist/interpreter/objects.d.ts +37 -0
  21. package/dist/interpreter/objects.js +151 -0
  22. package/dist/interpreter/promises.d.ts +31 -0
  23. package/dist/interpreter/promises.js +271 -0
  24. package/dist/interpreter/references.d.ts +7 -0
  25. package/dist/interpreter/references.js +93 -0
  26. package/dist/interpreter/runner.d.ts +24 -0
  27. package/dist/interpreter/runner.js +45 -0
  28. package/dist/interpreter/runtime.d.ts +19 -0
  29. package/dist/interpreter/runtime.js +1940 -0
  30. package/dist/interpreter/scope.d.ts +15 -0
  31. package/dist/interpreter/scope.js +79 -0
  32. package/dist/interpreter/transpile.node.d.ts +5 -0
  33. package/dist/interpreter/transpile.node.js +19 -0
  34. package/dist/interpreter/transpile.workerd.d.ts +5 -0
  35. package/dist/interpreter/transpile.workerd.js +6 -0
  36. package/dist/namespace.d.ts +15 -0
  37. package/dist/namespace.js +7 -0
  38. package/dist/openapi/index.d.ts +7 -0
  39. package/dist/openapi/index.js +101 -0
  40. package/dist/openapi/runtime.d.ts +4 -0
  41. package/dist/openapi/runtime.js +283 -0
  42. package/dist/openapi/spec.d.ts +20 -0
  43. package/dist/openapi/spec.js +583 -0
  44. package/dist/openapi/types.d.ts +122 -0
  45. package/dist/openapi/types.js +2 -0
  46. package/dist/stdlib/array.d.ts +3 -0
  47. package/dist/stdlib/array.js +68 -0
  48. package/dist/stdlib/collections.d.ts +9 -0
  49. package/dist/stdlib/collections.js +173 -0
  50. package/dist/stdlib/console.d.ts +3 -0
  51. package/dist/stdlib/console.js +137 -0
  52. package/dist/stdlib/date.d.ts +8 -0
  53. package/dist/stdlib/date.js +208 -0
  54. package/dist/stdlib/json.d.ts +3 -0
  55. package/dist/stdlib/json.js +101 -0
  56. package/dist/stdlib/math.d.ts +8 -0
  57. package/dist/stdlib/math.js +89 -0
  58. package/dist/stdlib/number.d.ts +4 -0
  59. package/dist/stdlib/number.js +69 -0
  60. package/dist/stdlib/object.d.ts +7 -0
  61. package/dist/stdlib/object.js +106 -0
  62. package/dist/stdlib/regexp.d.ts +10 -0
  63. package/dist/stdlib/regexp.js +120 -0
  64. package/dist/stdlib/string.d.ts +2 -0
  65. package/dist/stdlib/string.js +51 -0
  66. package/dist/stdlib/url.d.ts +16 -0
  67. package/dist/stdlib/url.js +161 -0
  68. package/dist/stdlib/value.d.ts +13 -0
  69. package/dist/stdlib/value.js +120 -0
  70. package/dist/stdlib/web.d.ts +4 -0
  71. package/dist/stdlib/web.js +20 -0
  72. package/dist/tool-error.d.ts +11 -0
  73. package/dist/tool-error.js +9 -0
  74. package/dist/tool-runtime.d.ts +69 -0
  75. package/dist/tool-runtime.js +254 -0
  76. package/dist/tool-schema.d.ts +16 -0
  77. package/dist/tool-schema.js +263 -0
  78. package/dist/tool.d.ts +66 -0
  79. package/dist/tool.js +16 -0
  80. package/dist/tools.d.ts +5 -0
  81. package/dist/tools.js +1 -0
  82. package/dist/values.d.ts +37 -0
  83. package/dist/values.js +56 -0
  84. package/package.json +37 -6
@@ -0,0 +1,208 @@
1
+ import { Effect } from "effect";
2
+ import { HostFunction, sync } from "../interpreter/host.js";
3
+ import { InterpreterRuntimeError } from "../interpreter/model.js";
4
+ import { toPrimitive } from "../interpreter/runner.js";
5
+ import { Values } from "../values.js";
6
+ import { coerceToNumber, coerceToString } from "./value.js";
7
+ const dateSetterArguments = new Map([
8
+ ["setTime", 1],
9
+ ["setMilliseconds", 1],
10
+ ["setUTCMilliseconds", 1],
11
+ ["setSeconds", 2],
12
+ ["setUTCSeconds", 2],
13
+ ["setMinutes", 3],
14
+ ["setUTCMinutes", 3],
15
+ ["setHours", 4],
16
+ ["setUTCHours", 4],
17
+ ["setDate", 1],
18
+ ["setUTCDate", 1],
19
+ ["setMonth", 2],
20
+ ["setUTCMonth", 2],
21
+ ["setFullYear", 3],
22
+ ["setUTCFullYear", 3],
23
+ ]);
24
+ export const dateMethods = new Set([
25
+ "getTime",
26
+ "valueOf",
27
+ "toISOString",
28
+ "toJSON",
29
+ "toString",
30
+ "toDateString",
31
+ "toTimeString",
32
+ "toUTCString",
33
+ "toGMTString",
34
+ "getFullYear",
35
+ "getMonth",
36
+ "getDate",
37
+ "getDay",
38
+ "getHours",
39
+ "getMinutes",
40
+ "getSeconds",
41
+ "getMilliseconds",
42
+ "getUTCFullYear",
43
+ "getUTCMonth",
44
+ "getUTCDate",
45
+ "getUTCDay",
46
+ "getUTCHours",
47
+ "getUTCMinutes",
48
+ "getUTCSeconds",
49
+ "getUTCMilliseconds",
50
+ "getTimezoneOffset",
51
+ ...dateSetterArguments.keys(),
52
+ ]);
53
+ const constructDate = (runner, args, node) => {
54
+ if (args.length === 0)
55
+ return Effect.succeed(new Values.Date(Date.now()));
56
+ if (args.length === 1) {
57
+ const arg = args[0];
58
+ if (arg instanceof Values.Date)
59
+ return Effect.succeed(new Values.Date(arg.time));
60
+ return Effect.map(toPrimitive(runner, arg, "number", node), (value) => typeof value === "string"
61
+ ? new Values.Date(Date.parse(value))
62
+ : new Values.Date(new Date(coerceToNumber(value)).getTime()));
63
+ }
64
+ const parts = args.map((arg) => coerceToNumber(arg));
65
+ return Effect.succeed(new Values.Date(new Date(...parts).getTime()));
66
+ };
67
+ export const dateGlobal = (runner) => new HostFunction({
68
+ name: "Date",
69
+ // ISO instead of the host's locale string: date strings are deterministic and must not leak the host timezone.
70
+ call: () => Effect.sync(() => new Date().toISOString()),
71
+ construct: (args, node) => constructDate(runner, args, node),
72
+ instanceOf: (value) => value instanceof Values.Date,
73
+ members: {
74
+ now: sync("Date.now", () => Date.now()),
75
+ parse: sync("Date.parse", (args) => Date.parse(coerceToString(args[0]))),
76
+ UTC: sync("Date.UTC", (args) => Date.UTC(...args.map((arg) => coerceToNumber(arg)))),
77
+ },
78
+ });
79
+ export const dateSetterArgumentCount = (name) => dateSetterArguments.get(name);
80
+ export const invokeDateMethod = (value, name, args, node, initialTime = value.time) => {
81
+ const hosted = new Date(initialTime);
82
+ switch (name) {
83
+ case "getTime":
84
+ case "valueOf":
85
+ return value.time;
86
+ case "toISOString":
87
+ if (!Number.isFinite(value.time))
88
+ throw new InterpreterRuntimeError("Invalid time value.", node).as("RangeError");
89
+ return hosted.toISOString();
90
+ case "toJSON":
91
+ return Number.isFinite(value.time) ? hosted.toISOString() : null;
92
+ case "toString":
93
+ return coerceToString(value);
94
+ case "toDateString":
95
+ return hosted.toDateString();
96
+ case "toTimeString":
97
+ return hosted.toTimeString();
98
+ case "toUTCString":
99
+ case "toGMTString":
100
+ return hosted.toUTCString();
101
+ case "getFullYear":
102
+ return hosted.getFullYear();
103
+ case "getMonth":
104
+ return hosted.getMonth();
105
+ case "getDate":
106
+ return hosted.getDate();
107
+ case "getDay":
108
+ return hosted.getDay();
109
+ case "getHours":
110
+ return hosted.getHours();
111
+ case "getMinutes":
112
+ return hosted.getMinutes();
113
+ case "getSeconds":
114
+ return hosted.getSeconds();
115
+ case "getMilliseconds":
116
+ return hosted.getMilliseconds();
117
+ case "getUTCFullYear":
118
+ return hosted.getUTCFullYear();
119
+ case "getUTCMonth":
120
+ return hosted.getUTCMonth();
121
+ case "getUTCDate":
122
+ return hosted.getUTCDate();
123
+ case "getUTCDay":
124
+ return hosted.getUTCDay();
125
+ case "getUTCHours":
126
+ return hosted.getUTCHours();
127
+ case "getUTCMinutes":
128
+ return hosted.getUTCMinutes();
129
+ case "getUTCSeconds":
130
+ return hosted.getUTCSeconds();
131
+ case "getUTCMilliseconds":
132
+ return hosted.getUTCMilliseconds();
133
+ case "getTimezoneOffset":
134
+ return hosted.getTimezoneOffset();
135
+ case "setTime":
136
+ return updateDate(value, hosted.setTime(args[0]));
137
+ case "setMilliseconds":
138
+ return updateDate(value, hosted.setMilliseconds(args[0]));
139
+ case "setUTCMilliseconds":
140
+ return updateDate(value, hosted.setUTCMilliseconds(args[0]));
141
+ case "setSeconds":
142
+ if (args.length < 2)
143
+ return updateDate(value, hosted.setSeconds(args[0]));
144
+ return updateDate(value, hosted.setSeconds(args[0], args[1]));
145
+ case "setUTCSeconds":
146
+ if (args.length < 2)
147
+ return updateDate(value, hosted.setUTCSeconds(args[0]));
148
+ return updateDate(value, hosted.setUTCSeconds(args[0], args[1]));
149
+ case "setMinutes":
150
+ if (args.length < 2)
151
+ return updateDate(value, hosted.setMinutes(args[0]));
152
+ if (args.length < 3)
153
+ return updateDate(value, hosted.setMinutes(args[0], args[1]));
154
+ return updateDate(value, hosted.setMinutes(args[0], args[1], args[2]));
155
+ case "setUTCMinutes":
156
+ if (args.length < 2)
157
+ return updateDate(value, hosted.setUTCMinutes(args[0]));
158
+ if (args.length < 3)
159
+ return updateDate(value, hosted.setUTCMinutes(args[0], args[1]));
160
+ return updateDate(value, hosted.setUTCMinutes(args[0], args[1], args[2]));
161
+ case "setHours":
162
+ if (args.length < 2)
163
+ return updateDate(value, hosted.setHours(args[0]));
164
+ if (args.length < 3)
165
+ return updateDate(value, hosted.setHours(args[0], args[1]));
166
+ if (args.length < 4)
167
+ return updateDate(value, hosted.setHours(args[0], args[1], args[2]));
168
+ return updateDate(value, hosted.setHours(args[0], args[1], args[2], args[3]));
169
+ case "setUTCHours":
170
+ if (args.length < 2)
171
+ return updateDate(value, hosted.setUTCHours(args[0]));
172
+ if (args.length < 3)
173
+ return updateDate(value, hosted.setUTCHours(args[0], args[1]));
174
+ if (args.length < 4)
175
+ return updateDate(value, hosted.setUTCHours(args[0], args[1], args[2]));
176
+ return updateDate(value, hosted.setUTCHours(args[0], args[1], args[2], args[3]));
177
+ case "setDate":
178
+ return updateDate(value, hosted.setDate(args[0]));
179
+ case "setUTCDate":
180
+ return updateDate(value, hosted.setUTCDate(args[0]));
181
+ case "setMonth":
182
+ if (args.length < 2)
183
+ return updateDate(value, hosted.setMonth(args[0]));
184
+ return updateDate(value, hosted.setMonth(args[0], args[1]));
185
+ case "setUTCMonth":
186
+ if (args.length < 2)
187
+ return updateDate(value, hosted.setUTCMonth(args[0]));
188
+ return updateDate(value, hosted.setUTCMonth(args[0], args[1]));
189
+ case "setFullYear":
190
+ if (args.length < 2)
191
+ return updateDate(value, hosted.setFullYear(args[0]));
192
+ if (args.length < 3)
193
+ return updateDate(value, hosted.setFullYear(args[0], args[1]));
194
+ return updateDate(value, hosted.setFullYear(args[0], args[1], args[2]));
195
+ case "setUTCFullYear":
196
+ if (args.length < 2)
197
+ return updateDate(value, hosted.setUTCFullYear(args[0]));
198
+ if (args.length < 3)
199
+ return updateDate(value, hosted.setUTCFullYear(args[0], args[1]));
200
+ return updateDate(value, hosted.setUTCFullYear(args[0], args[1], args[2]));
201
+ default:
202
+ throw new InterpreterRuntimeError(`Date method '${name}' is not available.`, node);
203
+ }
204
+ };
205
+ const updateDate = (value, time) => {
206
+ value.time = time;
207
+ return time;
208
+ };
@@ -0,0 +1,3 @@
1
+ import { HostNamespace } from "../interpreter/host.js";
2
+ import { type Runner } from "../interpreter/runner.js";
3
+ export declare const jsonGlobal: <R>(runner: Runner<R>) => HostNamespace;
@@ -0,0 +1,101 @@
1
+ import { Effect } from "effect";
2
+ import { HostFunction, HostNamespace } from "../interpreter/host.js";
3
+ import { applyCollectionCallback } from "../interpreter/runner.js";
4
+ import { InterpreterRuntimeError } from "../interpreter/model.js";
5
+ import { typeofValue } from "../interpreter/references.js";
6
+ import { fromData, toData, toProgram } from "../data.js";
7
+ import { get, ownKeys, ProgramArray, ProgramObject, record, remove, set } from "../interpreter/objects.js";
8
+ import { Values } from "../values.js";
9
+ export const jsonGlobal = (runner) => new HostNamespace("JSON", {
10
+ parse: new HostFunction({ name: "JSON.parse", call: (args, node) => parse(runner, args, node) }),
11
+ stringify: new HostFunction({ name: "JSON.stringify", call: (args, node) => stringify(runner, args, node) }),
12
+ });
13
+ const parse = (runner, args, node) => {
14
+ const text = args[0];
15
+ if (typeof text !== "string")
16
+ throw new InterpreterRuntimeError("JSON.parse expects a string.", node);
17
+ const parsed = (() => {
18
+ try {
19
+ return fromData(JSON.parse(text), "JSON.parse result");
20
+ }
21
+ catch (error) {
22
+ throw new InterpreterRuntimeError(`JSON.parse received invalid JSON: ${error instanceof Error ? error.message : String(error)}`, node).as("SyntaxError");
23
+ }
24
+ })();
25
+ if (typeofValue(args[1]) !== "function")
26
+ return Effect.succeed(parsed);
27
+ const apply = applyCollectionCallback(runner, args[1], "JSON.parse", node);
28
+ const visit = (holder, key) => Effect.gen(function* () {
29
+ const value = get(holder, key);
30
+ if (value instanceof ProgramObject) {
31
+ for (const name of ownKeys(value)) {
32
+ const revived = yield* visit(value, name);
33
+ if (revived === undefined)
34
+ remove(value, name);
35
+ else
36
+ set(value, name, revived);
37
+ }
38
+ }
39
+ return yield* apply([key, value]);
40
+ });
41
+ return visit(record({ "": parsed }), "");
42
+ };
43
+ const stringify = (runner, args, node) => {
44
+ const space = args[2];
45
+ const indent = typeof space === "number" || typeof space === "string" ? space : undefined;
46
+ const replacer = args[1];
47
+ if (typeofValue(replacer) !== "function") {
48
+ const properties = replacer instanceof ProgramArray
49
+ ? replacer.items
50
+ .filter((item) => typeof item === "string" || typeof item === "number")
51
+ .map(String)
52
+ : null;
53
+ return Effect.succeed(JSON.stringify(toData(args[0], "JSON.stringify value"), properties, indent));
54
+ }
55
+ // Validate up front; the replacer walk below reads the original value.
56
+ toProgram(args[0], "JSON.stringify value");
57
+ const apply = applyCollectionCallback(runner, replacer, "JSON.stringify", node);
58
+ const stack = new Set();
59
+ const visit = (holder, key) => Effect.gen(function* () {
60
+ const value = yield* apply([key, toJSONValue(get(holder, key))]);
61
+ if (value === undefined || typeofValue(value) === "function")
62
+ return undefined;
63
+ toProgram(value, "JSON.stringify replacer result");
64
+ if (typeof value === "number")
65
+ return Number.isFinite(value) ? value : null;
66
+ if (value === null || typeof value === "string" || typeof value === "boolean")
67
+ return value;
68
+ if (!(value instanceof ProgramObject))
69
+ return {};
70
+ if (stack.has(value))
71
+ throw new InterpreterRuntimeError("Converting circular structure to JSON.", node).as("TypeError");
72
+ stack.add(value);
73
+ if (value instanceof ProgramArray) {
74
+ const result = [];
75
+ for (let index = 0; index < value.items.length; index += 1) {
76
+ result.push((yield* visit(value, String(index))) ?? null);
77
+ }
78
+ stack.delete(value);
79
+ return result;
80
+ }
81
+ const result = Object.create(null);
82
+ for (const name of ownKeys(value)) {
83
+ if (typeof name !== "string")
84
+ continue;
85
+ const item = yield* visit(value, name);
86
+ if (item !== undefined)
87
+ result[name] = item;
88
+ }
89
+ stack.delete(value);
90
+ return result;
91
+ });
92
+ return Effect.map(visit(record({ "": args[0] }), ""), (value) => JSON.stringify(value, null, indent));
93
+ };
94
+ const toJSONValue = (value) => {
95
+ if (value instanceof Values.Date) {
96
+ return Number.isFinite(value.time) ? new Date(value.time).toISOString() : null;
97
+ }
98
+ if (value instanceof Values.URL)
99
+ return value.url.href;
100
+ return value;
101
+ };
@@ -0,0 +1,8 @@
1
+ import { HostNamespace } from "../interpreter/host.js";
2
+ import { type Runner } from "../interpreter/runner.js";
3
+ declare global {
4
+ interface Math {
5
+ sumPrecise(values: Iterable<number>): number;
6
+ }
7
+ }
8
+ export declare const mathGlobal: <R>(runner: Runner<R>) => HostNamespace;
@@ -0,0 +1,89 @@
1
+ import { Effect } from "effect";
2
+ import { HostFunction, HostNamespace, sync } from "../interpreter/host.js";
3
+ import { preserveConsumerError } from "../interpreter/runner.js";
4
+ import { InterpreterRuntimeError } from "../interpreter/model.js";
5
+ // Validate only the arguments a method consumes; like JS, extras are ignored
6
+ // (so built-ins work as callbacks receiving (element, index, array)).
7
+ const number = (name, args, index, node) => {
8
+ if (index >= args.length)
9
+ return Number.NaN;
10
+ const arg = args[index];
11
+ if (typeof arg !== "number")
12
+ throw new InterpreterRuntimeError(`Math.${name} expects number arguments.`, node);
13
+ return arg;
14
+ };
15
+ const unary = (name, op) => sync(`Math.${name}`, (args, node) => op(number(name, args, 0, node)));
16
+ const binary = (name, op) => sync(`Math.${name}`, (args, node) => op(number(name, args, 0, node), number(name, args, 1, node)));
17
+ const variadic = (name, op) => sync(`Math.${name}`, (args, node) => op(...args.map((arg) => {
18
+ if (typeof arg !== "number")
19
+ throw new InterpreterRuntimeError(`Math.${name} expects number arguments.`, node);
20
+ return arg;
21
+ })));
22
+ const sumPrecise = (runner) => new HostFunction({
23
+ name: "Math.sumPrecise",
24
+ call: (args, node) => Effect.gen(function* () {
25
+ const cursor = yield* runner.syncIterator(args[0], node);
26
+ if (cursor === undefined) {
27
+ throw new InterpreterRuntimeError("Math.sumPrecise expects a synchronous iterable.", node).as("TypeError");
28
+ }
29
+ const numbers = [];
30
+ while (true) {
31
+ const step = yield* cursor.next;
32
+ if (step.done)
33
+ return Math.sumPrecise(numbers);
34
+ yield* preserveConsumerError(cursor, Effect.sync(() => {
35
+ if (typeof step.value !== "number") {
36
+ throw new InterpreterRuntimeError("Math.sumPrecise expects an iterable of numbers.", node).as("TypeError");
37
+ }
38
+ numbers.push(step.value);
39
+ }));
40
+ }
41
+ }),
42
+ });
43
+ export const mathGlobal = (runner) => new HostNamespace("Math", {
44
+ PI: Math.PI,
45
+ E: Math.E,
46
+ LN2: Math.LN2,
47
+ LN10: Math.LN10,
48
+ LOG2E: Math.LOG2E,
49
+ LOG10E: Math.LOG10E,
50
+ SQRT2: Math.SQRT2,
51
+ SQRT1_2: Math.SQRT1_2,
52
+ random: sync("Math.random", () => Math.random()),
53
+ max: variadic("max", Math.max),
54
+ min: variadic("min", Math.min),
55
+ hypot: variadic("hypot", Math.hypot),
56
+ abs: unary("abs", Math.abs),
57
+ acos: unary("acos", Math.acos),
58
+ acosh: unary("acosh", Math.acosh),
59
+ asin: unary("asin", Math.asin),
60
+ asinh: unary("asinh", Math.asinh),
61
+ atan: unary("atan", Math.atan),
62
+ atan2: binary("atan2", Math.atan2),
63
+ atanh: unary("atanh", Math.atanh),
64
+ floor: unary("floor", Math.floor),
65
+ ceil: unary("ceil", Math.ceil),
66
+ round: unary("round", Math.round),
67
+ trunc: unary("trunc", Math.trunc),
68
+ sign: unary("sign", Math.sign),
69
+ sqrt: unary("sqrt", Math.sqrt),
70
+ cbrt: unary("cbrt", Math.cbrt),
71
+ pow: binary("pow", Math.pow),
72
+ cos: unary("cos", Math.cos),
73
+ cosh: unary("cosh", Math.cosh),
74
+ sin: unary("sin", Math.sin),
75
+ sinh: unary("sinh", Math.sinh),
76
+ tan: unary("tan", Math.tan),
77
+ tanh: unary("tanh", Math.tanh),
78
+ log: unary("log", Math.log),
79
+ log2: unary("log2", Math.log2),
80
+ log10: unary("log10", Math.log10),
81
+ log1p: unary("log1p", Math.log1p),
82
+ exp: unary("exp", Math.exp),
83
+ expm1: unary("expm1", Math.expm1),
84
+ f16round: unary("f16round", Math.f16round),
85
+ fround: unary("fround", Math.fround),
86
+ clz32: unary("clz32", Math.clz32),
87
+ imul: binary("imul", Math.imul),
88
+ sumPrecise: sumPrecise(runner),
89
+ });
@@ -0,0 +1,4 @@
1
+ import { type AstNode } from "../interpreter/model.js";
2
+ export declare const numberMethods: Set<string>;
3
+ export declare const invokeNumberMethod: (value: number, name: string, args: Array<unknown>, node: AstNode) => unknown;
4
+ export declare const numberGlobal: import("../interpreter/host.js").HostFunction<never>;
@@ -0,0 +1,69 @@
1
+ import { toProgram } from "../data.js";
2
+ import { sync } from "../interpreter/host.js";
3
+ import { InterpreterRuntimeError } from "../interpreter/model.js";
4
+ import { coercion, coerceToString } from "./value.js";
5
+ export const numberMethods = new Set(["toFixed", "toPrecision", "toExponential", "toString", "valueOf"]);
6
+ export const invokeNumberMethod = (value, name, args, node) => {
7
+ const optNum = (index) => {
8
+ const arg = args[index];
9
+ if (arg === undefined)
10
+ return undefined;
11
+ if (typeof arg !== "number")
12
+ throw new InterpreterRuntimeError(`Number.${name} expects a number argument.`, node);
13
+ return arg;
14
+ };
15
+ let result;
16
+ switch (name) {
17
+ case "toFixed":
18
+ result = value.toFixed(optNum(0));
19
+ break;
20
+ case "toExponential":
21
+ result = value.toExponential(optNum(0));
22
+ break;
23
+ case "toPrecision": {
24
+ const digits = optNum(0);
25
+ result = digits === undefined ? value.toString() : value.toPrecision(digits);
26
+ break;
27
+ }
28
+ case "toString": {
29
+ const radix = optNum(0);
30
+ if (radix !== undefined && (radix < 2 || radix > 36)) {
31
+ throw new InterpreterRuntimeError("Number.toString radix must be between 2 and 36.", node);
32
+ }
33
+ result = value.toString(radix);
34
+ break;
35
+ }
36
+ case "valueOf":
37
+ result = value;
38
+ break;
39
+ default:
40
+ throw new InterpreterRuntimeError(`Number method '${name}' is not available.`, node);
41
+ }
42
+ return toProgram(result, `Number.${name} result`);
43
+ };
44
+ const parseIntStatic = sync("Number.parseInt", (args, node) => {
45
+ const radix = args[1];
46
+ if (radix !== undefined && typeof radix !== "number") {
47
+ throw new InterpreterRuntimeError("Number.parseInt expects a numeric radix.", node);
48
+ }
49
+ return parseInt(coerceToString(args[0]), radix);
50
+ });
51
+ export const numberGlobal = coercion("Number", {
52
+ instanceOf: () => false,
53
+ members: {
54
+ MAX_SAFE_INTEGER: Number.MAX_SAFE_INTEGER,
55
+ MIN_SAFE_INTEGER: Number.MIN_SAFE_INTEGER,
56
+ MAX_VALUE: Number.MAX_VALUE,
57
+ MIN_VALUE: Number.MIN_VALUE,
58
+ EPSILON: Number.EPSILON,
59
+ NaN: Number.NaN,
60
+ POSITIVE_INFINITY: Number.POSITIVE_INFINITY,
61
+ NEGATIVE_INFINITY: Number.NEGATIVE_INFINITY,
62
+ isInteger: sync("Number.isInteger", (args) => Number.isInteger(args[0])),
63
+ isFinite: sync("Number.isFinite", (args) => Number.isFinite(args[0])),
64
+ isNaN: sync("Number.isNaN", (args) => Number.isNaN(args[0])),
65
+ isSafeInteger: sync("Number.isSafeInteger", (args) => Number.isSafeInteger(args[0])),
66
+ parseInt: parseIntStatic,
67
+ parseFloat: sync("Number.parseFloat", (args) => parseFloat(coerceToString(args[0]))),
68
+ },
69
+ });
@@ -0,0 +1,7 @@
1
+ import { HostFunction } from "../interpreter/host.js";
2
+ import { type AstNode } from "../interpreter/model.js";
3
+ import { ProgramObject } from "../interpreter/objects.js";
4
+ import { type Runner } from "../interpreter/runner.js";
5
+ export declare const enumerableSource: (label: string, value: unknown, node: AstNode) => ProgramObject;
6
+ export declare const objectAssign: (args: Array<unknown>, node: AstNode) => unknown;
7
+ export declare const objectGlobal: <R>(runner: Runner<R>, toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>) => HostFunction<R>;
@@ -0,0 +1,106 @@
1
+ import { Effect } from "effect";
2
+ import { toProgram } from "../data.js";
3
+ import { HostFunction, sync, syncCall } from "../interpreter/host.js";
4
+ import { AsyncIteratorSymbol, InterpreterRuntimeError, IteratorSymbol } from "../interpreter/model.js";
5
+ import { getOwn, hasOwn, ownEntries, ownKeys, ProgramArray, ProgramObject, set } from "../interpreter/objects.js";
6
+ import { containsOpaqueReference, describeValue, rejectCircularInsertion, typeofValue, } from "../interpreter/references.js";
7
+ import { preserveConsumerError } from "../interpreter/runner.js";
8
+ import { ToolReference } from "../tool-runtime.js";
9
+ import { Values } from "../values.js";
10
+ import { groupBy } from "./collections.js";
11
+ import { coerceToString } from "./value.js";
12
+ // ToObject for enumeration.
13
+ export const enumerableSource = (label, value, node) => {
14
+ if (value === null || value === undefined) {
15
+ throw new InterpreterRuntimeError(`${label} cannot convert ${describeValue(value)} to an object.`, node).as("TypeError");
16
+ }
17
+ if (value instanceof Values.Promise) {
18
+ throw new InterpreterRuntimeError(`${label} received an un-awaited Promise; await it before inspecting the result.`, node, "InvalidDataValue");
19
+ }
20
+ if (value instanceof ToolReference) {
21
+ throw new InterpreterRuntimeError(`${label} cannot read tool references: they are not plain data. Use Object.keys(tools) for names, or search({ query }) for signatures.`, node, "InvalidDataValue");
22
+ }
23
+ if (typeof value === "string")
24
+ return new ProgramArray([...value]);
25
+ if (value instanceof ProgramObject)
26
+ return value;
27
+ return new ProgramObject();
28
+ };
29
+ export const objectAssign = (args, node) => {
30
+ const target = args[0];
31
+ // JS would box a primitive target; wrappers and primitives cannot hold fields here.
32
+ if (!(target instanceof ProgramObject)) {
33
+ throw new InterpreterRuntimeError(`Object.assign expects a data object or array target, received ${describeValue(target)}.`, node).as("TypeError");
34
+ }
35
+ const seen = new Set();
36
+ for (const source of args.slice(1)) {
37
+ if (source === null || source === undefined)
38
+ continue;
39
+ const from = enumerableSource("Object.assign(...)", source, node);
40
+ for (const key of ownKeys(from)) {
41
+ if (typeof key === "symbol" && key !== AsyncIteratorSymbol && key !== IteratorSymbol)
42
+ continue;
43
+ rejectCircularInsertion(target, getOwn(from, key), "Object.assign result", node, seen);
44
+ if (!set(target, key, getOwn(from, key))) {
45
+ throw new InterpreterRuntimeError("Invalid array length", node).as("RangeError");
46
+ }
47
+ }
48
+ }
49
+ return target;
50
+ };
51
+ const objectFromEntries = (runner, source, node) => {
52
+ const out = new ProgramObject();
53
+ return Effect.gen(function* () {
54
+ const cursor = yield* runner.syncIterator(source, node);
55
+ if (cursor === undefined) {
56
+ throw new InterpreterRuntimeError("Object.fromEntries expects a synchronous iterable of entries.", node).as("TypeError");
57
+ }
58
+ while (true) {
59
+ const step = yield* cursor.next;
60
+ if (step.done)
61
+ return out;
62
+ yield* preserveConsumerError(cursor, Effect.sync(() => {
63
+ if (!(step.value instanceof ProgramObject) || containsOpaqueReference(step.value)) {
64
+ throw new InterpreterRuntimeError("Object.fromEntries expects [key, value] entry objects.", node).as("TypeError");
65
+ }
66
+ set(out, coerceToString(getOwn(step.value, 0)), getOwn(step.value, 1));
67
+ }));
68
+ }
69
+ });
70
+ };
71
+ const constructObject = (args, node) => {
72
+ const first = args[0];
73
+ if (first === null || first === undefined)
74
+ return new ProgramObject();
75
+ if (typeof first === "object")
76
+ return first;
77
+ throw new InterpreterRuntimeError(`Object(${typeof first}) wrapper objects are not supported; use the primitive value directly.`, node);
78
+ };
79
+ // Object constructs identically with or without new, like JS. Only `keys` copies its result into the
80
+ // program; `values`, `entries`, `assign`, and `fromEntries` hand back the program's own values.
81
+ export const objectGlobal = (runner, toolKeys) => new HostFunction({
82
+ name: "Object",
83
+ call: syncCall(constructObject),
84
+ construct: syncCall(constructObject),
85
+ instanceOf: (value) => value !== null && (typeof value === "object" || typeofValue(value) === "function"),
86
+ members: {
87
+ keys: sync("Object.keys", (args, node) => toProgram(args[0] instanceof ToolReference
88
+ ? [...toolKeys(args[0].path)]
89
+ : ownKeys(enumerableSource("Object.keys(...)", args[0], node)).filter((key) => typeof key === "string"), "Object.keys result")),
90
+ values: sync("Object.values", (args, node) => new ProgramArray(ownEntries(enumerableSource("Object.values(...)", args[0], node)).map((entry) => entry[1]))),
91
+ entries: sync("Object.entries", (args, node) => new ProgramArray(ownEntries(enumerableSource("Object.entries(...)", args[0], node)).map((entry) => new ProgramArray(entry)))),
92
+ hasOwn: sync("Object.hasOwn", (args, node) => hasOwn(enumerableSource("Object.hasOwn(...)", args[0], node), args[1] === AsyncIteratorSymbol || args[1] === IteratorSymbol ? args[1] : String(args[1]))),
93
+ is: sync("Object.is", (args, node) => {
94
+ if (containsOpaqueReference(args[0]) || containsOpaqueReference(args[1])) {
95
+ throw new InterpreterRuntimeError("Object.is requires data values.", node, "InvalidDataValue");
96
+ }
97
+ return Object.is(args[0], args[1]);
98
+ }),
99
+ assign: sync("Object.assign", objectAssign),
100
+ fromEntries: new HostFunction({
101
+ name: "Object.fromEntries",
102
+ call: (args, node) => Effect.suspend(() => objectFromEntries(runner, args[0], node)),
103
+ }),
104
+ groupBy: groupBy(runner, "Object"),
105
+ },
106
+ });
@@ -0,0 +1,10 @@
1
+ import { type AstNode } from "../interpreter/model.js";
2
+ import { ProgramArray } from "../interpreter/objects.js";
3
+ import { Values } from "../values.js";
4
+ export declare const regexpMethods: Set<string>;
5
+ export declare const regexpProperties: Set<string>;
6
+ export declare const toHostRegex: (arg: unknown, method: string, node: AstNode, extraFlags?: string) => RegExp;
7
+ export declare const matchToValue: (match: RegExpMatchArray) => ProgramArray;
8
+ export declare const constructRegExp: (args: Array<unknown>, node: AstNode) => Values.RegExp;
9
+ export declare const regexpGlobal: import("../interpreter/host.js").HostFunction<never>;
10
+ export declare const invokeRegExpMethod: (value: Values.RegExp, name: string, args: Array<unknown>, node: AstNode) => unknown;