@opencode/codemode 0.0.0-dev-19427 → 0.0.0-dev-19432

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.
@@ -5,3 +5,4 @@ export declare const containsOpaqueReference: (value: unknown) => boolean;
5
5
  export declare const rejectCircularInsertion: (container: object, value: unknown, label: string, node: AstNode, seen?: Set<object>) => void;
6
6
  export declare const describeValue: (value: unknown) => string;
7
7
  export declare const typeofValue: (value: unknown) => string;
8
+ export declare const parseArrayIndex: (key: string | number) => number | undefined;
@@ -93,3 +93,11 @@ export const typeofValue = (value) => {
93
93
  return value.path.length > 0 ? "function" : "object";
94
94
  return typeof value;
95
95
  };
96
+ const MAX_ARRAY_LENGTH = 4_294_967_295;
97
+ export const parseArrayIndex = (key) => {
98
+ const property = String(key);
99
+ if (!/^(0|[1-9]\d*)$/.test(property))
100
+ return undefined;
101
+ const index = Number(property);
102
+ return index < MAX_ARRAY_LENGTH ? index : undefined;
103
+ };
@@ -8,7 +8,7 @@ import { HostFunction, HostNamespace } from "./host.js";
8
8
  import { invokeIntrinsic } from "./methods.js";
9
9
  import { preserveConsumerError } from "./runner.js";
10
10
  import { invokePromiseInstanceMethod, PromiseRuntime, resolvePromise, resolvePromiseValue } from "./promises.js";
11
- import { containsOpaqueReference, describeValue, isRuntimeReference, rejectCircularInsertion, typeofValue, } from "./references.js";
11
+ import { containsOpaqueReference, describeValue, isRuntimeReference, parseArrayIndex, rejectCircularInsertion, typeofValue, } from "./references.js";
12
12
  import { ScopeStack } from "./scope.js";
13
13
  import { arrayMethods, mapMethods, setMethods } from "../stdlib/collections.js";
14
14
  import { dateMethods } from "../stdlib/date.js";
@@ -16,16 +16,9 @@ import { numberMethods } from "../stdlib/number.js";
16
16
  import { constructRegExp, regexpMethods, regexpProperties } from "../stdlib/regexp.js";
17
17
  import { stringMethods } from "../stdlib/string.js";
18
18
  import { uriArgument, urlMethods, urlProperties, urlSearchParamsMethods, urlWritableProperties } from "../stdlib/url.js";
19
+ import { enumerableSource } from "../stdlib/object.js";
19
20
  import { coerceToNumber, coerceToString, compoundOperators, errorBrandName } from "../stdlib/value.js";
20
21
  import { Values } from "../values.js";
21
- const MAX_ARRAY_LENGTH = 4_294_967_295;
22
- const parseArrayIndex = (key) => {
23
- const property = String(key);
24
- if (!/^(0|[1-9]\d*)$/.test(property))
25
- return undefined;
26
- const index = Number(property);
27
- return index < MAX_ARRAY_LENGTH ? index : undefined;
28
- };
29
22
  const calleeDescription = (callee) => {
30
23
  if (callee?.type === "Identifier")
31
24
  return callee.name;
@@ -673,17 +666,13 @@ class Frame {
673
666
  return value;
674
667
  throw new InterpreterRuntimeError(`${context} must be a function.`, node).as("TypeError");
675
668
  }
676
- enumerableKeys(value) {
677
- if (value instanceof ToolReference) {
669
+ // for...in over null/undefined iterates nothing, like JS.
670
+ enumerableKeys(value, node) {
671
+ if (value instanceof ToolReference)
678
672
  return [...this.runtime.toolKeys(value.path)];
679
- }
680
- if (Array.isArray(value)) {
681
- return Object.keys(value);
682
- }
683
- if (value !== null && typeof value === "object" && !isRuntimeReference(value)) {
684
- return Object.keys(value);
685
- }
686
- return undefined;
673
+ if (value === null || value === undefined)
674
+ return [];
675
+ return Object.keys(enumerableSource("for...in", value, node));
687
676
  }
688
677
  evaluateForInStatement(node, labels) {
689
678
  const left = node.left;
@@ -695,10 +684,7 @@ class Frame {
695
684
  if (declared?.lexical)
696
685
  self.predeclarePattern(declared.pattern, declared.mutable, left);
697
686
  const right = yield* self.evaluateExpression(node.right);
698
- const keys = self.enumerableKeys(right);
699
- if (keys === undefined) {
700
- throw new InterpreterRuntimeError("for...in requires a plain object, array, or tools reference. Use for...of for arrays/strings/Maps/Sets, or Object.keys(value) for a key list.", node);
701
- }
687
+ const keys = self.enumerableKeys(right, node.right);
702
688
  if (left.type !== "Identifier" && left.type !== "VariableDeclaration") {
703
689
  throw new InterpreterRuntimeError("Unsupported for...in binding.", left);
704
690
  }
@@ -1597,14 +1583,13 @@ class Frame {
1597
1583
  for (const property of node.properties) {
1598
1584
  if (property.type === "SpreadElement") {
1599
1585
  const spread = yield* self.evaluateExpression(property.argument);
1600
- if (spread === null || spread === undefined || Values.isValue(spread))
1586
+ if (spread === null || spread === undefined)
1601
1587
  continue;
1602
- if (typeof spread !== "object" || Array.isArray(spread) || isRuntimeReference(spread)) {
1603
- throw new InterpreterRuntimeError(`Object spread requires a data object, received ${describeValue(spread)}.`, property, "InvalidDataValue");
1604
- }
1605
- for (const [key, value] of Object.entries(spread))
1588
+ const from = enumerableSource("Object spread", spread, property);
1589
+ for (const [key, value] of Object.entries(from))
1606
1590
  objectValue[key] = value;
1607
- copyIteratorSymbols(spread, objectValue);
1591
+ if (typeof from === "object")
1592
+ copyIteratorSymbols(from, objectValue);
1608
1593
  continue;
1609
1594
  }
1610
1595
  if (property.kind !== "init") {
@@ -1,5 +1,6 @@
1
1
  import { HostFunction } from "../interpreter/host.js";
2
2
  import { type AstNode } from "../interpreter/model.js";
3
3
  import { type Runner } from "../interpreter/runner.js";
4
+ export declare const enumerableSource: (label: string, value: unknown, node: AstNode) => Record<string, unknown>;
4
5
  export declare const objectAssign: (args: Array<unknown>, node: AstNode) => unknown;
5
6
  export declare const objectGlobal: <R>(runner: Runner<R>, toolKeys: (path: ReadonlyArray<string>) => ReadonlyArray<string>) => HostFunction<R>;
@@ -2,52 +2,62 @@ 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 { containsOpaqueReference, describeValue, rejectCircularInsertion, typeofValue, } from "../interpreter/references.js";
5
+ import { containsOpaqueReference, describeValue, isRuntimeReference, parseArrayIndex, rejectCircularInsertion, typeofValue, } from "../interpreter/references.js";
6
6
  import { preserveConsumerError } from "../interpreter/runner.js";
7
7
  import { ToolReference } from "../tool-runtime.js";
8
8
  import { Values } from "../values.js";
9
9
  import { groupBy } from "./collections.js";
10
10
  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");
11
+ // ToObject for enumeration. Strings return themselves: the host's Object.keys/entries/hasOwn index a
12
+ // primitive string directly. Numbers, booleans, wrappers, and functions have no own enumerable keys.
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");
19
22
  }
20
- return input;
23
+ if (typeof value === "string")
24
+ return value;
25
+ if (typeof value !== "object" || Values.isValue(value) || isRuntimeReference(value))
26
+ return {};
27
+ return value;
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 === null || typeof target !== "object" || Values.isValue(target) || isRuntimeReference(target)) {
33
+ throw new InterpreterRuntimeError(`Object.assign expects a data object or array target, received ${describeValue(target)}.`, node).as("TypeError");
26
34
  }
27
35
  const out = target;
28
36
  const seen = new Set();
29
37
  const guardedSet = (key, item) => {
38
+ // Arrays hold only indexed elements, as with direct assignment; Reflect.set would otherwise
39
+ // reach Array's length and Object.prototype's __proto__ setter.
40
+ if (Array.isArray(out) && (typeof key === "symbol" || parseArrayIndex(key) === undefined)) {
41
+ throw new InterpreterRuntimeError(`Object.assign cannot assign '${String(key)}' to an array: only array indexes may be assigned.`, node).as("TypeError");
42
+ }
30
43
  rejectCircularInsertion(out, item, "Object.assign result", node, seen);
31
44
  if (!Reflect.set(out, key, item))
32
45
  throw new InterpreterRuntimeError(`Object.assign could not assign property '${String(key)}'.`, node).as("TypeError");
33
46
  };
34
47
  for (const source of args.slice(1)) {
35
- if (source === null || source === undefined || Values.isValue(source))
48
+ if (source === null || source === undefined)
49
+ continue;
50
+ const from = enumerableSource("Object.assign(...)", source, node);
51
+ if (typeof from !== "object") {
52
+ for (const [key, item] of Object.entries(from))
53
+ guardedSet(key, item);
36
54
  continue;
37
- if (typeof source !== "object" || Array.isArray(source)) {
38
- throw new InterpreterRuntimeError("Object.assign expects data objects.", node);
39
55
  }
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));
44
- continue;
45
- }
46
- if (key !== AsyncIteratorSymbol && key !== IteratorSymbol)
56
+ for (const key of Reflect.ownKeys(from)) {
57
+ if (typeof key === "symbol" && key !== AsyncIteratorSymbol && key !== IteratorSymbol)
47
58
  continue;
48
- if (!Object.prototype.propertyIsEnumerable.call(source, key))
49
- continue;
50
- guardedSet(key, Reflect.get(source, key));
59
+ if (Object.prototype.propertyIsEnumerable.call(from, key))
60
+ guardedSet(key, Reflect.get(from, key));
51
61
  }
52
62
  }
53
63
  return out;
@@ -93,10 +103,7 @@ const rejectTools = (name, args, node) => {
93
103
  return;
94
104
  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
105
  };
96
- const objectStatic = (name, impl) => sync(`Object.${name}`, (args, node) => {
97
- rejectTools(name, args, node);
98
- return impl(args, node);
99
- });
106
+ const objectStatic = (name, impl) => sync(`Object.${name}`, impl);
100
107
  // Object constructs identically with or without new, like JS. Only `keys` copies its result into the
101
108
  // program; `values`, `entries`, `assign`, and `fromEntries` hand back the program's own values.
102
109
  export const objectGlobal = (runner, toolKeys) => new HostFunction({
@@ -107,10 +114,10 @@ export const objectGlobal = (runner, toolKeys) => new HostFunction({
107
114
  members: {
108
115
  keys: sync("Object.keys", (args, node) => toProgram(args[0] instanceof ToolReference
109
116
  ? [...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]))),
117
+ : Object.keys(enumerableSource("Object.keys(...)", args[0], node)), "Object.keys result")),
118
+ values: objectStatic("values", (args, node) => Object.values(enumerableSource("Object.values(...)", args[0], node))),
119
+ entries: objectStatic("entries", (args, node) => Object.entries(enumerableSource("Object.entries(...)", args[0], node)).map(([key, item]) => [key, item])),
120
+ hasOwn: objectStatic("hasOwn", (args, node) => Object.hasOwn(enumerableSource("Object.hasOwn(...)", args[0], node), args[1] === AsyncIteratorSymbol || args[1] === IteratorSymbol ? args[1] : String(args[1]))),
114
121
  is: objectStatic("is", (args, node) => {
115
122
  if (containsOpaqueReference(args[0]) || containsOpaqueReference(args[1])) {
116
123
  throw new InterpreterRuntimeError("Object.is requires data values.", node, "InvalidDataValue");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@opencode/codemode",
4
- "version": "0.0.0-dev-19427",
4
+ "version": "0.0.0-dev-19432",
5
5
  "description": "Effect-native confined code execution over schema-described tools",
6
6
  "type": "module",
7
7
  "license": "MIT",