@opencode/codemode 0.0.0-dev-19438 → 0.0.0-dev-19440

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.
@@ -11,6 +11,7 @@ import { regexpGlobal } from "../stdlib/regexp.js";
11
11
  import { stringGlobal } from "../stdlib/string.js";
12
12
  import { uriGlobal, urlGlobal, urlSearchParamsGlobal } from "../stdlib/url.js";
13
13
  import { coercion, errorConstructors } from "../stdlib/value.js";
14
+ import { atobGlobal, btoaGlobal, cryptoGlobal } from "../stdlib/web.js";
14
15
  import { ToolReference } from "../tool-runtime.js";
15
16
  import { errorGlobal } from "./errors.js";
16
17
  import { HostFunction } from "./host.js";
@@ -55,5 +56,8 @@ export const globals = (host) => [
55
56
  ["encodeURIComponent", uriGlobal("encodeURIComponent")],
56
57
  ["decodeURI", uriGlobal("decodeURI")],
57
58
  ["decodeURIComponent", uriGlobal("decodeURIComponent")],
59
+ ["atob", atobGlobal],
60
+ ["btoa", btoaGlobal],
61
+ ["crypto", cryptoGlobal],
58
62
  ...[...errorConstructors].map((name) => [name, errorGlobal(name, host.runner)]),
59
63
  ];
@@ -108,6 +108,8 @@ const collectPatternNames = (pattern, out = []) => {
108
108
  return out;
109
109
  };
110
110
  // `var` names declared anywhere in a function body except inside nested functions, which own theirs.
111
+ // Memoized per body: a function's var names never change, and hoisting runs on every call.
112
+ const varNames = new WeakMap();
111
113
  const collectVarNames = (node, out = []) => {
112
114
  if (!node)
113
115
  return out;
@@ -341,13 +343,14 @@ class Frame {
341
343
  // Hoisted `var` bindings start undefined, or copy a same-named parameter. Function bodies hoist
342
344
  // into their own scope above the parameters so closures in parameter defaults keep seeing outer names.
343
345
  hoistVars(statements, parameters) {
346
+ const names = varNames.get(statements) ??
347
+ statements.reduce((out, statement) => collectVarNames(statement, out), []);
348
+ varNames.set(statements, names);
344
349
  const scope = this.scopes.current();
345
- for (const statement of statements) {
346
- for (const name of collectVarNames(statement)) {
347
- if (scope.has(name))
348
- continue;
349
- scope.set(name, { mutable: true, value: parameters?.get(name)?.value, initialized: true });
350
- }
350
+ for (const name of names) {
351
+ if (scope.has(name))
352
+ continue;
353
+ scope.set(name, { mutable: true, value: parameters?.get(name)?.value, initialized: true });
351
354
  }
352
355
  }
353
356
  predeclareLexical(statements) {
@@ -385,7 +388,9 @@ class Frame {
385
388
  self.scopes.push();
386
389
  return yield* Effect.gen(function* () {
387
390
  const cases = node.cases;
388
- self.predeclareLexical(cases.flatMap((branch) => branch.consequent));
391
+ const statements = cases.flatMap((branch) => branch.consequent);
392
+ self.predeclareLexical(statements);
393
+ self.hoistFunctions(statements);
389
394
  let defaultIndex;
390
395
  let selected;
391
396
  for (const [index, branch] of cases.entries()) {
@@ -1399,12 +1404,7 @@ class Frame {
1399
1404
  return Effect.succeed(this.createGenerator(invocation, run, fn.async));
1400
1405
  if (!fn.async)
1401
1406
  return run;
1402
- // The initial yield assigns the promise before the body can self-resolve.
1403
- const box = {};
1404
- return Effect.map(this.createPromise(Effect.flatMap(run, (value) => resolvePromiseValue(invocation.runtime.runner, value, fn.body, box))), (promise) => {
1405
- box.promise = promise;
1406
- return promise;
1407
- });
1407
+ return this.runtime.promises.createWithSelf((self) => Effect.flatMap(run, (value) => resolvePromiseValue(invocation.runtime.runner, value, fn.body, self)));
1408
1408
  }
1409
1409
  createGenerator(invocation, run, asynchronous) {
1410
1410
  const state = { started: false, completed: false, draining: false, pending: [], pendingIndex: 0 };
@@ -0,0 +1,4 @@
1
+ import { HostNamespace } from "../interpreter/host.js";
2
+ export declare const atobGlobal: import("../interpreter/host.js").HostFunction<never>;
3
+ export declare const btoaGlobal: import("../interpreter/host.js").HostFunction<never>;
4
+ export declare const cryptoGlobal: HostNamespace;
@@ -0,0 +1,21 @@
1
+ import { HostNamespace, sync } from "../interpreter/host.js";
2
+ import { InterpreterRuntimeError } from "../interpreter/model.js";
3
+ import { coerceToString } from "./value.js";
4
+ // WebIDL DOMString conversion: a missing argument is a TypeError, anything else stringifies.
5
+ const base64 = (name) => sync(name, (args, node) => {
6
+ if (args.length === 0) {
7
+ throw new InterpreterRuntimeError(`${name} requires 1 argument, but only 0 were provided.`, node).as("TypeError");
8
+ }
9
+ const input = coerceToString(args[0]);
10
+ try {
11
+ return name === "atob" ? atob(input) : btoa(input);
12
+ }
13
+ catch {
14
+ throw new InterpreterRuntimeError("The string contains invalid characters.", node).as("InvalidCharacterError");
15
+ }
16
+ });
17
+ export const atobGlobal = base64("atob");
18
+ export const btoaGlobal = base64("btoa");
19
+ export const cryptoGlobal = new HostNamespace("crypto", {
20
+ randomUUID: sync("crypto.randomUUID", () => crypto.randomUUID()),
21
+ });
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-19438",
4
+ "version": "0.0.0-dev-19440",
5
5
  "description": "Effect-native confined code execution over schema-described tools",
6
6
  "type": "module",
7
7
  "license": "MIT",