@opencode/codemode 0.0.0-beta-19422 → 0.0.0-beta-19500

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.
@@ -1,26 +1,24 @@
1
1
  import { Effect } from "effect";
2
2
  import { HostFunction, sync, syncCall } from "../interpreter/host.js";
3
3
  import { CodeModeGenerator, InterpreterRuntimeError } from "../interpreter/model.js";
4
+ import { get, ProgramArray, ProgramObject } from "../interpreter/objects.js";
4
5
  import { describeValue } from "../interpreter/references.js";
5
6
  import { applyCollectionCallback, preserveConsumerError } from "../interpreter/runner.js";
6
7
  const constructArray = (args, node) => {
7
8
  if (args.length !== 1)
8
- return [...args];
9
+ return new ProgramArray([...args]);
9
10
  const first = args[0];
10
11
  if (typeof first !== "number")
11
- return [first];
12
+ return new ProgramArray([first]);
12
13
  if (!Number.isInteger(first) || first < 0 || first > 4294967295) {
13
14
  throw new InterpreterRuntimeError("Invalid array length.", node).as("RangeError");
14
15
  }
15
16
  // Sparse like JS: Array(3) has holes, and combinator loops already skip them.
16
- return new Array(first);
17
+ return new ProgramArray(new Array(first));
17
18
  };
18
19
  const arrayLikeSource = (source, node) => {
19
- if (source !== null &&
20
- typeof source === "object" &&
21
- (Object.getPrototypeOf(source) === Object.prototype || Object.getPrototypeOf(source) === null) &&
22
- typeof source.length === "number") {
23
- const length = source.length;
20
+ if (source instanceof ProgramObject && typeof get(source, "length") === "number") {
21
+ const length = get(source, "length");
24
22
  const normalized = Number.isNaN(length) || length <= 0 ? 0 : Math.trunc(length);
25
23
  if (normalized > 4_294_967_295)
26
24
  throw new RangeError("Invalid array length");
@@ -40,17 +38,17 @@ const arrayFrom = (runner, args, node) => {
40
38
  const arrayLike = arrayLikeSource(source, node);
41
39
  const values = [];
42
40
  for (let index = 0; index < arrayLike.length; index += 1) {
43
- const item = Reflect.get(arrayLike.source, index);
41
+ const item = get(arrayLike.source, index);
44
42
  values.push(apply === undefined ? item : yield* apply([item, index]));
45
43
  }
46
- return values;
44
+ return new ProgramArray(values);
47
45
  }
48
46
  const values = [];
49
47
  let index = 0;
50
48
  while (true) {
51
49
  const step = yield* cursor.next;
52
50
  if (step.done)
53
- return values;
51
+ return new ProgramArray(values);
54
52
  values.push(apply === undefined ? step.value : yield* preserveConsumerError(cursor, apply([step.value, index])));
55
53
  index += 1;
56
54
  }
@@ -61,10 +59,10 @@ export const arrayGlobal = (runner) => new HostFunction({
61
59
  name: "Array",
62
60
  call: syncCall(constructArray),
63
61
  construct: syncCall(constructArray),
64
- instanceOf: (value) => Array.isArray(value),
62
+ instanceOf: (value) => value instanceof ProgramArray,
65
63
  members: {
66
- isArray: sync("Array.isArray", (args) => Array.isArray(args[0])),
67
- of: sync("Array.of", (args) => [...args]),
64
+ isArray: sync("Array.isArray", (args) => args[0] instanceof ProgramArray),
65
+ of: sync("Array.of", (args) => new ProgramArray([...args])),
68
66
  from: new HostFunction({ name: "Array.from", call: (args, node) => arrayFrom(runner, args, node) }),
69
67
  },
70
68
  });
@@ -1,6 +1,7 @@
1
1
  import { Effect } from "effect";
2
2
  import { HostFunction, requiresNew } from "../interpreter/host.js";
3
- import { InterpreterRuntimeError, isRecord } from "../interpreter/model.js";
3
+ import { InterpreterRuntimeError } from "../interpreter/model.js";
4
+ import { getOwn, ProgramArray, ProgramObject, set } from "../interpreter/objects.js";
4
5
  import { describeValue, isRuntimeReference } from "../interpreter/references.js";
5
6
  import { applyCollectionCallback, preserveConsumerError, toPrimitive } from "../interpreter/runner.js";
6
7
  import { Values } from "../values.js";
@@ -94,13 +95,13 @@ export const groupBy = (runner, namespace) => new HostFunction({
94
95
  const key = yield* preserveConsumerError(cursor, apply([item, index]));
95
96
  const group = result.map.get(key);
96
97
  if (group === undefined)
97
- result.map.set(key, [item]);
98
+ result.map.set(key, new ProgramArray([item]));
98
99
  else
99
- group.push(item);
100
+ group.items.push(item);
100
101
  index += 1;
101
102
  }
102
103
  }
103
- const result = Object.create(null);
104
+ const result = new ProgramObject();
104
105
  let index = 0;
105
106
  while (true) {
106
107
  const step = yield* cursor.next;
@@ -108,11 +109,11 @@ export const groupBy = (runner, namespace) => new HostFunction({
108
109
  return result;
109
110
  const item = step.value;
110
111
  const key = yield* preserveConsumerError(cursor, Effect.flatMap(apply([item, index]), (value) => coerceGroupByPropertyKey(runner, value, node)));
111
- const group = result[key];
112
+ const group = getOwn(result, key);
112
113
  if (group === undefined)
113
- result[key] = [item];
114
+ set(result, key, new ProgramArray([item]));
114
115
  else
115
- group.push(item);
116
+ group.items.push(item);
116
117
  index += 1;
117
118
  }
118
119
  });
@@ -132,10 +133,10 @@ const constructMap = (runner, init, node) => {
132
133
  if (step.done)
133
134
  return target;
134
135
  yield* preserveConsumerError(cursor, Effect.sync(() => {
135
- if (!isRecord(step.value) || isRuntimeReference(step.value)) {
136
+ if (!(step.value instanceof ProgramObject)) {
136
137
  throw new InterpreterRuntimeError("new Map(...) expects [key, value] pairs as entry objects.", node).as("TypeError");
137
138
  }
138
- target.map.set(step.value[0], step.value[1]);
139
+ target.map.set(getOwn(step.value, 0), getOwn(step.value, 1));
139
140
  }));
140
141
  }
141
142
  });
@@ -1,5 +1,6 @@
1
1
  import { toData, toProgram } from "../data.js";
2
2
  import { HostNamespace, sync } from "../interpreter/host.js";
3
+ import { get, ownEntries, ProgramArray, ProgramObject } from "../interpreter/objects.js";
3
4
  import { containsOpaqueReference, containsRuntimeReference, isRuntimeReference } from "../interpreter/references.js";
4
5
  import { Values } from "../values.js";
5
6
  import { coerceToString } from "./value.js";
@@ -54,8 +55,8 @@ const formatConsoleValue = (value, seen, depth) => {
54
55
  if (value instanceof Values.Map) {
55
56
  seen.add(value);
56
57
  try {
57
- const entries = Array.from(value.map.entries(), ([key, item]) => [key, item]);
58
- return `Map(${value.map.size}) ${formatConsoleValue(entries, seen, depth + 1)}`;
58
+ const entries = Array.from(value.map.entries(), ([key, item]) => new ProgramArray([key, item]));
59
+ return `Map(${value.map.size}) ${formatConsoleValue(new ProgramArray(entries), seen, depth + 1)}`;
59
60
  }
60
61
  finally {
61
62
  seen.delete(value);
@@ -64,7 +65,7 @@ const formatConsoleValue = (value, seen, depth) => {
64
65
  if (value instanceof Values.Set) {
65
66
  seen.add(value);
66
67
  try {
67
- return `Set(${value.set.size}) ${formatConsoleValue(Array.from(value.set.values()), seen, depth + 1)}`;
68
+ return `Set(${value.set.size}) ${formatConsoleValue(new ProgramArray([...value.set.values()]), seen, depth + 1)}`;
68
69
  }
69
70
  finally {
70
71
  seen.delete(value);
@@ -74,10 +75,12 @@ const formatConsoleValue = (value, seen, depth) => {
74
75
  return "[opaque reference]";
75
76
  seen.add(value);
76
77
  try {
77
- if (Array.isArray(value)) {
78
- return `[${value.map((item) => formatConsoleValue(item, seen, depth + 1)).join(",")}]`;
78
+ if (value instanceof ProgramArray) {
79
+ return `[${value.items.map((item) => formatConsoleValue(item, seen, depth + 1)).join(",")}]`;
79
80
  }
80
- return `{${Object.entries(value)
81
+ if (!(value instanceof ProgramObject))
82
+ return "[object Object]";
83
+ return `{${ownEntries(value)
81
84
  .map(([key, item]) => `${JSON.stringify(key)}:${formatConsoleValue(item, seen, depth + 1)}`)
82
85
  .join(",")}}`;
83
86
  }
@@ -109,20 +112,19 @@ const consoleTableColumns = (value) => {
109
112
  return Array.isArray(columns) ? columns.map((column) => String(column)) : undefined;
110
113
  };
111
114
  const consoleTableRows = (data, columns) => {
112
- if (Array.isArray(data)) {
113
- return data.map((item, index) => ({ index: String(index), values: consoleTableValues(item, columns) }));
115
+ if (data instanceof ProgramArray) {
116
+ return data.items.map((item, index) => ({ index: String(index), values: consoleTableValues(item, columns) }));
114
117
  }
115
- if (data !== null && typeof data === "object" && !Values.isValue(data)) {
116
- return Object.entries(data).map(([index, item]) => ({ index, values: consoleTableValues(item, columns) }));
118
+ if (data instanceof ProgramObject) {
119
+ return ownEntries(data).map(([index, item]) => ({ index, values: consoleTableValues(item, columns) }));
117
120
  }
118
121
  return [{ index: "0", values: { Value: data } }];
119
122
  };
120
123
  const consoleTableValues = (value, columns) => {
121
- if (value !== null && typeof value === "object" && !Array.isArray(value) && !Values.isValue(value)) {
122
- const source = value;
124
+ if (value instanceof ProgramObject && !(value instanceof ProgramArray)) {
123
125
  if (columns !== undefined)
124
- return Object.fromEntries(columns.map((column) => [column, source[column]]));
125
- return Object.fromEntries(Object.entries(source));
126
+ return Object.fromEntries(columns.map((column) => [column, get(value, column)]));
127
+ return Object.fromEntries(ownEntries(value));
126
128
  }
127
129
  return { Value: value };
128
130
  };
@@ -27,6 +27,8 @@ export const dateMethods = new Set([
27
27
  "toISOString",
28
28
  "toJSON",
29
29
  "toString",
30
+ "toDateString",
31
+ "toTimeString",
30
32
  "toUTCString",
31
33
  "toGMTString",
32
34
  "getFullYear",
@@ -89,6 +91,10 @@ export const invokeDateMethod = (value, name, args, node, initialTime = value.ti
89
91
  return Number.isFinite(value.time) ? hosted.toISOString() : null;
90
92
  case "toString":
91
93
  return coerceToString(value);
94
+ case "toDateString":
95
+ return hosted.toDateString();
96
+ case "toTimeString":
97
+ return hosted.toTimeString();
92
98
  case "toUTCString":
93
99
  case "toGMTString":
94
100
  return hosted.toUTCString();
@@ -4,6 +4,7 @@ import { applyCollectionCallback } from "../interpreter/runner.js";
4
4
  import { InterpreterRuntimeError } from "../interpreter/model.js";
5
5
  import { typeofValue } from "../interpreter/references.js";
6
6
  import { fromData, toData, toProgram } from "../data.js";
7
+ import { get, ownKeys, ProgramArray, ProgramObject, record, remove, set } from "../interpreter/objects.js";
7
8
  import { Values } from "../values.js";
8
9
  export const jsonGlobal = (runner) => new HostNamespace("JSON", {
9
10
  parse: new HostFunction({ name: "JSON.parse", call: (args, node) => parse(runner, args, node) }),
@@ -24,40 +25,28 @@ const parse = (runner, args, node) => {
24
25
  if (typeofValue(args[1]) !== "function")
25
26
  return Effect.succeed(parsed);
26
27
  const apply = applyCollectionCallback(runner, args[1], "JSON.parse", node);
27
- const root = Object.create(null);
28
- root[""] = parsed;
29
28
  const visit = (holder, key) => Effect.gen(function* () {
30
- const value = holder[key];
31
- if (Array.isArray(value)) {
32
- const length = value.length;
33
- for (let index = 0; index < length; index += 1) {
34
- const revived = yield* visit(value, String(index));
35
- if (revived === undefined)
36
- Reflect.deleteProperty(value, index);
37
- else
38
- value[index] = revived;
39
- }
40
- }
41
- else if (isPlainObject(value)) {
42
- for (const name of Object.keys(value)) {
29
+ const value = get(holder, key);
30
+ if (value instanceof ProgramObject) {
31
+ for (const name of ownKeys(value)) {
43
32
  const revived = yield* visit(value, name);
44
33
  if (revived === undefined)
45
- Reflect.deleteProperty(value, name);
34
+ remove(value, name);
46
35
  else
47
- value[name] = revived;
36
+ set(value, name, revived);
48
37
  }
49
38
  }
50
39
  return yield* apply([key, value]);
51
40
  });
52
- return visit(root, "");
41
+ return visit(record({ "": parsed }), "");
53
42
  };
54
43
  const stringify = (runner, args, node) => {
55
44
  const space = args[2];
56
45
  const indent = typeof space === "number" || typeof space === "string" ? space : undefined;
57
46
  const replacer = args[1];
58
47
  if (typeofValue(replacer) !== "function") {
59
- const properties = Array.isArray(replacer)
60
- ? replacer
48
+ const properties = replacer instanceof ProgramArray
49
+ ? replacer.items
61
50
  .filter((item) => typeof item === "string" || typeof item === "number")
62
51
  .map(String)
63
52
  : null;
@@ -66,11 +55,9 @@ const stringify = (runner, args, node) => {
66
55
  // Validate up front; the replacer walk below reads the original value.
67
56
  toProgram(args[0], "JSON.stringify value");
68
57
  const apply = applyCollectionCallback(runner, replacer, "JSON.stringify", node);
69
- const root = Object.create(null);
70
- root[""] = args[0];
71
58
  const stack = new Set();
72
59
  const visit = (holder, key) => Effect.gen(function* () {
73
- const value = yield* apply([key, toJSONValue(holder[key])]);
60
+ const value = yield* apply([key, toJSONValue(get(holder, key))]);
74
61
  if (value === undefined || typeofValue(value) === "function")
75
62
  return undefined;
76
63
  toProgram(value, "JSON.stringify replacer result");
@@ -78,24 +65,23 @@ const stringify = (runner, args, node) => {
78
65
  return Number.isFinite(value) ? value : null;
79
66
  if (value === null || typeof value === "string" || typeof value === "boolean")
80
67
  return value;
81
- if (Array.isArray(value)) {
82
- if (stack.has(value))
83
- throw new InterpreterRuntimeError("Converting circular structure to JSON.", node).as("TypeError");
84
- stack.add(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) {
85
74
  const result = [];
86
- for (let index = 0; index < value.length; index += 1) {
75
+ for (let index = 0; index < value.items.length; index += 1) {
87
76
  result.push((yield* visit(value, String(index))) ?? null);
88
77
  }
89
78
  stack.delete(value);
90
79
  return result;
91
80
  }
92
- if (!isPlainObject(value))
93
- return {};
94
- if (stack.has(value))
95
- throw new InterpreterRuntimeError("Converting circular structure to JSON.", node).as("TypeError");
96
- stack.add(value);
97
81
  const result = Object.create(null);
98
- for (const name of Object.keys(value)) {
82
+ for (const name of ownKeys(value)) {
83
+ if (typeof name !== "string")
84
+ continue;
99
85
  const item = yield* visit(value, name);
100
86
  if (item !== undefined)
101
87
  result[name] = item;
@@ -103,7 +89,7 @@ const stringify = (runner, args, node) => {
103
89
  stack.delete(value);
104
90
  return result;
105
91
  });
106
- return Effect.map(visit(root, ""), (value) => JSON.stringify(value, null, indent));
92
+ return Effect.map(visit(record({ "": args[0] }), ""), (value) => JSON.stringify(value, null, indent));
107
93
  };
108
94
  const toJSONValue = (value) => {
109
95
  if (value instanceof Values.Date) {
@@ -113,4 +99,3 @@ const toJSONValue = (value) => {
113
99
  return value.url.href;
114
100
  return value;
115
101
  };
116
- const isPlainObject = (value) => value !== null && typeof value === "object" && !Values.isValue(value);
@@ -1,5 +1,7 @@
1
1
  import { HostFunction } from "../interpreter/host.js";
2
2
  import { type AstNode } from "../interpreter/model.js";
3
+ import { ProgramObject } from "../interpreter/objects.js";
3
4
  import { type Runner } from "../interpreter/runner.js";
5
+ export declare const enumerableSource: (label: string, value: unknown, node: AstNode) => ProgramObject;
4
6
  export declare const objectAssign: (args: Array<unknown>, node: AstNode) => unknown;
5
7
  export declare const objectGlobal: <R>(runner: Runner<R>, toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>) => HostFunction<R>;
@@ -2,58 +2,54 @@ import { Effect } from "effect";
2
2
  import { toProgram } from "../data.js";
3
3
  import { HostFunction, sync, syncCall } from "../interpreter/host.js";
4
4
  import { AsyncIteratorSymbol, InterpreterRuntimeError, IteratorSymbol } from "../interpreter/model.js";
5
+ import { getOwn, hasOwn, ownEntries, ownKeys, ProgramArray, ProgramObject, set } from "../interpreter/objects.js";
5
6
  import { containsOpaqueReference, describeValue, rejectCircularInsertion, typeofValue, } from "../interpreter/references.js";
6
7
  import { preserveConsumerError } from "../interpreter/runner.js";
7
8
  import { ToolReference } from "../tool-runtime.js";
8
9
  import { Values } from "../values.js";
9
10
  import { groupBy } from "./collections.js";
10
11
  import { coerceToString } from "./value.js";
11
- const requireObject = (name, input, node) => {
12
- if (Array.isArray(input))
13
- return input;
14
- if (Values.isValue(input))
15
- return {};
16
- const prototype = input === null || typeof input !== "object" ? undefined : Object.getPrototypeOf(input);
17
- if (prototype !== null && prototype !== Object.prototype) {
18
- throw new InterpreterRuntimeError(`Object.${name} expects a data object or array, received ${describeValue(input)}.`, node, "InvalidDataValue");
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");
19
16
  }
20
- return input;
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();
21
28
  };
22
29
  export const objectAssign = (args, node) => {
23
30
  const target = args[0];
24
- if (target === null || typeof target !== "object" || Array.isArray(target) || Values.isValue(target)) {
25
- throw new InterpreterRuntimeError("Object.assign expects a data object target.", node);
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");
26
34
  }
27
- const out = target;
28
35
  const seen = new Set();
29
- const guardedSet = (key, item) => {
30
- rejectCircularInsertion(out, item, "Object.assign result", node, seen);
31
- if (!Reflect.set(out, key, item))
32
- throw new InterpreterRuntimeError(`Object.assign could not assign property '${String(key)}'.`, node).as("TypeError");
33
- };
34
36
  for (const source of args.slice(1)) {
35
- if (source === null || source === undefined || Values.isValue(source))
37
+ if (source === null || source === undefined)
36
38
  continue;
37
- if (typeof source !== "object" || Array.isArray(source)) {
38
- throw new InterpreterRuntimeError("Object.assign expects data objects.", node);
39
- }
40
- for (const key of Reflect.ownKeys(source)) {
41
- if (typeof key === "string") {
42
- if (Object.prototype.propertyIsEnumerable.call(source, key))
43
- guardedSet(key, Reflect.get(source, key));
39
+ const from = enumerableSource("Object.assign(...)", source, node);
40
+ for (const key of ownKeys(from)) {
41
+ if (typeof key === "symbol" && key !== AsyncIteratorSymbol && key !== IteratorSymbol)
44
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");
45
46
  }
46
- if (key !== AsyncIteratorSymbol && key !== IteratorSymbol)
47
- continue;
48
- if (!Object.prototype.propertyIsEnumerable.call(source, key))
49
- continue;
50
- guardedSet(key, Reflect.get(source, key));
51
47
  }
52
48
  }
53
- return out;
49
+ return target;
54
50
  };
55
51
  const objectFromEntries = (runner, source, node) => {
56
- const out = Object.create(null);
52
+ const out = new ProgramObject();
57
53
  return Effect.gen(function* () {
58
54
  const cursor = yield* runner.syncIterator(source, node);
59
55
  if (cursor === undefined) {
@@ -64,17 +60,10 @@ const objectFromEntries = (runner, source, node) => {
64
60
  if (step.done)
65
61
  return out;
66
62
  yield* preserveConsumerError(cursor, Effect.sync(() => {
67
- if (step.value === null ||
68
- typeof step.value !== "object" ||
69
- Values.isValue(step.value) ||
70
- containsOpaqueReference(step.value)) {
63
+ if (!(step.value instanceof ProgramObject) || containsOpaqueReference(step.value)) {
71
64
  throw new InterpreterRuntimeError("Object.fromEntries expects [key, value] entry objects.", node).as("TypeError");
72
65
  }
73
- const entry = step.value;
74
- toProgram(entry[0], "Object.fromEntries key");
75
- toProgram(entry[1], "Object.fromEntries value");
76
- const key = coerceToString(entry[0]);
77
- out[key] = entry[1];
66
+ set(out, coerceToString(getOwn(step.value, 0)), getOwn(step.value, 1));
78
67
  }));
79
68
  }
80
69
  });
@@ -82,21 +71,11 @@ const objectFromEntries = (runner, source, node) => {
82
71
  const constructObject = (args, node) => {
83
72
  const first = args[0];
84
73
  if (first === null || first === undefined)
85
- return Object.create(null);
74
+ return new ProgramObject();
86
75
  if (typeof first === "object")
87
76
  return first;
88
77
  throw new InterpreterRuntimeError(`Object(${typeof first}) wrapper objects are not supported; use the primitive value directly.`, node);
89
78
  };
90
- // Tool references are not data; only Object.keys(tools) reads them, for tool names.
91
- const rejectTools = (name, args, node) => {
92
- if (!(args[0] instanceof ToolReference))
93
- return;
94
- throw new InterpreterRuntimeError(`Object.${name}(...) cannot read tool references: they are not plain data. Use Object.keys(tools) for names, or search({ query }) for signatures.`, node, "InvalidDataValue");
95
- };
96
- const objectStatic = (name, impl) => sync(`Object.${name}`, (args, node) => {
97
- rejectTools(name, args, node);
98
- return impl(args, node);
99
- });
100
79
  // Object constructs identically with or without new, like JS. Only `keys` copies its result into the
101
80
  // program; `values`, `entries`, `assign`, and `fromEntries` hand back the program's own values.
102
81
  export const objectGlobal = (runner, toolKeys) => new HostFunction({
@@ -107,23 +86,20 @@ export const objectGlobal = (runner, toolKeys) => new HostFunction({
107
86
  members: {
108
87
  keys: sync("Object.keys", (args, node) => toProgram(args[0] instanceof ToolReference
109
88
  ? [...toolKeys(args[0].path)]
110
- : Object.keys(requireObject("keys", args[0], node)), "Object.keys result")),
111
- values: objectStatic("values", (args, node) => Object.values(requireObject("values", args[0], node))),
112
- entries: objectStatic("entries", (args, node) => Object.entries(requireObject("entries", args[0], node)).map(([key, item]) => [key, item])),
113
- hasOwn: objectStatic("hasOwn", (args, node) => Object.hasOwn(requireObject("hasOwn", args[0], node), args[1] === AsyncIteratorSymbol || args[1] === IteratorSymbol ? args[1] : String(args[1]))),
114
- is: objectStatic("is", (args, node) => {
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) => {
115
94
  if (containsOpaqueReference(args[0]) || containsOpaqueReference(args[1])) {
116
95
  throw new InterpreterRuntimeError("Object.is requires data values.", node, "InvalidDataValue");
117
96
  }
118
97
  return Object.is(args[0], args[1]);
119
98
  }),
120
- assign: objectStatic("assign", objectAssign),
99
+ assign: sync("Object.assign", objectAssign),
121
100
  fromEntries: new HostFunction({
122
101
  name: "Object.fromEntries",
123
- call: (args, node) => Effect.suspend(() => {
124
- rejectTools("fromEntries", args, node);
125
- return objectFromEntries(runner, args[0], node);
126
- }),
102
+ call: (args, node) => Effect.suspend(() => objectFromEntries(runner, args[0], node)),
127
103
  }),
128
104
  groupBy: groupBy(runner, "Object"),
129
105
  },
@@ -1,9 +1,10 @@
1
1
  import { type AstNode } from "../interpreter/model.js";
2
+ import { ProgramArray } from "../interpreter/objects.js";
2
3
  import { Values } from "../values.js";
3
4
  export declare const regexpMethods: Set<string>;
4
5
  export declare const regexpProperties: Set<string>;
5
6
  export declare const toHostRegex: (arg: unknown, method: string, node: AstNode, extraFlags?: string) => RegExp;
6
- export declare const matchToValue: (match: RegExpMatchArray) => Array<unknown>;
7
+ export declare const matchToValue: (match: RegExpMatchArray) => ProgramArray;
7
8
  export declare const constructRegExp: (args: Array<unknown>, node: AstNode) => Values.RegExp;
8
9
  export declare const regexpGlobal: import("../interpreter/host.js").HostFunction<never>;
9
10
  export declare const invokeRegExpMethod: (value: Values.RegExp, name: string, args: Array<unknown>, node: AstNode) => unknown;
@@ -1,5 +1,6 @@
1
1
  import { sync, syncCall } from "../interpreter/host.js";
2
2
  import { InterpreterRuntimeError } from "../interpreter/model.js";
3
+ import { ProgramArray, record, set } from "../interpreter/objects.js";
3
4
  import { Values } from "../values.js";
4
5
  import { coerceToNumber, coerceToString } from "./value.js";
5
6
  export const regexpMethods = new Set(["test", "exec", "toString"]);
@@ -35,18 +36,15 @@ export const toHostRegex = (arg, method, node, extraFlags = "") => {
35
36
  throw new InterpreterRuntimeError(`String.${method} expects a regular expression (a /pattern/flags literal or new RegExp(...)) or a string pattern, not ${arg === null ? "null" : typeof arg}.`, node);
36
37
  };
37
38
  export const matchToValue = (match) => {
38
- const result = Array.from(match, (group) => group);
39
+ const result = new ProgramArray(Array.from(match, (group) => group));
39
40
  if (match.index !== undefined)
40
- result.index = match.index;
41
- if (match.groups) {
42
- const groups = Object.create(null);
43
- for (const [key, group] of Object.entries(match.groups)) {
44
- groups[key] = group;
45
- }
46
- result.groups = groups;
47
- }
41
+ set(result, "index", match.index);
42
+ if (match.input !== undefined)
43
+ set(result, "input", match.input);
44
+ if (match.groups)
45
+ set(result, "groups", record(match.groups));
48
46
  if (match.indices)
49
- result.indices = indicesToValue(match.indices);
47
+ set(result, "indices", indicesToValue(match.indices));
50
48
  return result;
51
49
  };
52
50
  export const constructRegExp = (args, node) => {
@@ -112,15 +110,11 @@ const toLength = (value) => {
112
110
  return Math.min(Math.floor(number), Number.MAX_SAFE_INTEGER);
113
111
  };
114
112
  const indicesToValue = (indices) => {
115
- const result = Array.from(indices, (range) => (range === undefined ? undefined : [...range]));
116
- if (indices.groups) {
117
- const groups = Object.create(null);
118
- for (const [key, range] of Object.entries(indices.groups)) {
119
- groups[key] = range === undefined ? undefined : [...range];
120
- }
121
- result.groups = groups;
122
- return result;
123
- }
124
- result.groups = undefined;
113
+ const range = (pair) => (pair === undefined ? undefined : new ProgramArray([...pair]));
114
+ const result = new ProgramArray(Array.from(indices, range));
115
+ const groups = indices.groups;
116
+ set(result, "groups", groups === undefined
117
+ ? undefined
118
+ : record(Object.fromEntries(Object.entries(groups).map(([key, pair]) => [key, range(pair)]))));
125
119
  return result;
126
120
  };
@@ -7,9 +7,12 @@ export const stringMethods = new Set([
7
7
  "trim",
8
8
  "trimStart",
9
9
  "trimEnd",
10
+ "trimLeft",
11
+ "trimRight",
10
12
  "split",
11
13
  "slice",
12
14
  "substring",
15
+ "substr",
13
16
  "includes",
14
17
  "startsWith",
15
18
  "endsWith",
@@ -31,6 +34,8 @@ export const stringMethods = new Set([
31
34
  "search",
32
35
  "localeCompare",
33
36
  "normalize",
37
+ "isWellFormed",
38
+ "toWellFormed",
34
39
  ]);
35
40
  const codeUnits = (name, op) => sync(`String.${name}`, (args, node) => op(...args.map((arg) => {
36
41
  if (typeof arg !== "number")
@@ -2,6 +2,7 @@ import { Effect } from "effect";
2
2
  import { toProgram } from "../data.js";
3
3
  import { HostFunction, requiresNew, sync, syncCall } from "../interpreter/host.js";
4
4
  import { InterpreterRuntimeError } from "../interpreter/model.js";
5
+ import { ownEntries, ProgramObject } from "../interpreter/objects.js";
5
6
  import { isRuntimeReference } from "../interpreter/references.js";
6
7
  import { preserveConsumerError } from "../interpreter/runner.js";
7
8
  import { Values } from "../values.js";
@@ -141,11 +142,10 @@ const constructURLSearchParams = (runner, init, node) => {
141
142
  }
142
143
  if (Values.isValue(init))
143
144
  return new Values.URLSearchParams(new URLSearchParams());
144
- const data = toProgram(init, "new URLSearchParams input");
145
- if (data === null || typeof data !== "object") {
145
+ if (!(init instanceof ProgramObject)) {
146
146
  throw new InterpreterRuntimeError("new URLSearchParams(...) expects a query string, data object, iterable pairs, or URLSearchParams.", node).as("TypeError");
147
147
  }
148
- return new Values.URLSearchParams(new URLSearchParams(Object.fromEntries(Object.entries(data).map(([key, value]) => [key, coerceToString(value)]))));
148
+ return new Values.URLSearchParams(new URLSearchParams(Object.fromEntries(ownEntries(init).map(([key, value]) => [key, coerceToString(value)]))));
149
149
  });
150
150
  };
151
151
  export const urlSearchParamsGlobal = (runner) => new HostFunction({
@@ -1,9 +1,9 @@
1
1
  import { type HostFunction, type SyncOptions } from "../interpreter/host.js";
2
- import { type SafeObject } from "../data.js";
2
+ import { ProgramError } from "../interpreter/objects.js";
3
3
  export declare const errorConstructors: Set<string>;
4
4
  export declare const compoundOperators: Set<string>;
5
- export declare const createErrorValue: (name: string, message: string) => SafeObject;
6
- export declare const createAggregateErrorValue: (errors: Array<unknown>, message: string) => SafeObject;
5
+ export declare const createErrorValue: (name: string, message: string) => ProgramError;
6
+ export declare const createAggregateErrorValue: (errors: Array<unknown>, message: string) => ProgramError;
7
7
  export declare const errorBrandName: (value: unknown) => string | undefined;
8
8
  export declare const coerceToString: (value: unknown) => string;
9
9
  export declare const coerceToNumber: (value: unknown) => number;