@opencode/codemode 0.0.0-dev-20027 → 0.0.0-dev-20030
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,9 +1,9 @@
|
|
|
1
|
-
import type { Program } from "acorn";
|
|
1
|
+
import type { Program, TaggedTemplateExpression } from "acorn";
|
|
2
2
|
import { Effect } from "effect";
|
|
3
3
|
import { type Json } from "../data.js";
|
|
4
4
|
import { type ToolRuntime } from "../tool-runtime.js";
|
|
5
5
|
import { type Builtins } from "./intrinsics.js";
|
|
6
|
-
import { type Cursor, PromiseObj, type Value } from "./objects.js";
|
|
6
|
+
import { type Cursor, Arr, PromiseObj, type Value } from "./objects.js";
|
|
7
7
|
import { Pending } from "./promises.js";
|
|
8
8
|
/** One program execution: the tool bridge, promise scheduler, captured logs, and the global scope built once. */
|
|
9
9
|
export declare class Interpreter<R> {
|
|
@@ -11,6 +11,8 @@ export declare class Interpreter<R> {
|
|
|
11
11
|
readonly pending: Pending<R>;
|
|
12
12
|
readonly builtins: Builtins;
|
|
13
13
|
readonly logs: Array<string>;
|
|
14
|
+
/** Template objects by site: a tag sees the same `strings` array every time its literal is evaluated, as in JS. */
|
|
15
|
+
readonly templates: WeakMap<TaggedTemplateExpression, Arr>;
|
|
14
16
|
private readonly root;
|
|
15
17
|
constructor(options: {
|
|
16
18
|
readonly tools: ToolRuntime<R>;
|
|
@@ -6,7 +6,7 @@ import { checkStringLength } from "./limits.js";
|
|
|
6
6
|
import { locate, materialize } from "./errors.js";
|
|
7
7
|
import { primitivePrototype } from "./intrinsics.js";
|
|
8
8
|
import { globals } from "./globals.js";
|
|
9
|
-
import { assign, Callable, define, get, hostCursor, IteratorObj, has, hidden, hasPrototype, keys, Native, parseArrayIndex, Arr, Fn, GeneratorObj, Obj, PromiseObj, record, remove, set, coerceToNumber, coerceToString, } from "./objects.js";
|
|
9
|
+
import { assign, Callable, define, frozen, get, hostCursor, IteratorObj, has, hidden, hasPrototype, keys, Native, parseArrayIndex, Arr, Fn, GeneratorObj, Obj, PromiseObj, record, remove, set, coerceToNumber, coerceToString, } from "./objects.js";
|
|
10
10
|
import { preserveConsumerError } from "./callback.js";
|
|
11
11
|
import { Pending, resolvePromise, resolvePromiseValue } from "./promises.js";
|
|
12
12
|
import { containsOpaqueReference, describeValue, rejectCircularInsertion, typeofValue } from "./references.js";
|
|
@@ -163,6 +163,8 @@ export class Interpreter {
|
|
|
163
163
|
pending;
|
|
164
164
|
builtins;
|
|
165
165
|
logs;
|
|
166
|
+
/** Template objects by site: a tag sees the same `strings` array every time its literal is evaluated, as in JS. */
|
|
167
|
+
templates = new WeakMap();
|
|
166
168
|
root;
|
|
167
169
|
constructor(options) {
|
|
168
170
|
this.tools = options.tools;
|
|
@@ -1016,6 +1018,8 @@ class Frame {
|
|
|
1016
1018
|
return this.evaluateArrayExpression(node);
|
|
1017
1019
|
case "TemplateLiteral":
|
|
1018
1020
|
return this.evaluateTemplateLiteral(node);
|
|
1021
|
+
case "TaggedTemplateExpression":
|
|
1022
|
+
return this.evaluateTaggedTemplate(node);
|
|
1019
1023
|
case "ConditionalExpression":
|
|
1020
1024
|
return this.evaluateConditionalExpression(node);
|
|
1021
1025
|
case "UpdateExpression":
|
|
@@ -1666,7 +1670,7 @@ class Frame {
|
|
|
1666
1670
|
return Effect.gen(function* () {
|
|
1667
1671
|
for (let index = 0; index < quasis.length; index += 1) {
|
|
1668
1672
|
const quasi = quasis[index];
|
|
1669
|
-
// acorn only omits `cooked` for invalid escapes
|
|
1673
|
+
// acorn only omits `cooked` for invalid escapes, which are a parse error outside a tagged template.
|
|
1670
1674
|
if (typeof quasi.value.cooked !== "string") {
|
|
1671
1675
|
throw typeError("Invalid template literal quasi.", quasi);
|
|
1672
1676
|
}
|
|
@@ -1681,6 +1685,27 @@ class Frame {
|
|
|
1681
1685
|
return output;
|
|
1682
1686
|
});
|
|
1683
1687
|
}
|
|
1688
|
+
// `tag\`a${x}b\`` is `tag(strings, x)`: the tag is read like a callee (a member keeps its receiver), the
|
|
1689
|
+
// substitutions are evaluated in order, and `strings` carries the escaped source as `strings.raw`.
|
|
1690
|
+
evaluateTaggedTemplate(node) {
|
|
1691
|
+
const self = this;
|
|
1692
|
+
return Effect.gen(function* () {
|
|
1693
|
+
const { callable, thisValue } = node.tag.type === "MemberExpression"
|
|
1694
|
+
? yield* self.readMethod(node.tag)
|
|
1695
|
+
: { callable: yield* self.evaluateExpression(node.tag), thisValue: undefined };
|
|
1696
|
+
const strings = self.ctx.templates.get(node) ?? self.createTemplateObject(node);
|
|
1697
|
+
const values = yield* Effect.forEach(node.quasi.expressions, (expression) => self.evaluateExpression(expression));
|
|
1698
|
+
return yield* self.call(callable, thisValue, [strings, ...values], node, node.tag);
|
|
1699
|
+
});
|
|
1700
|
+
}
|
|
1701
|
+
createTemplateObject(node) {
|
|
1702
|
+
const array = this.ctx.builtins.Array;
|
|
1703
|
+
// An invalid escape such as `\unicode` cooks to `undefined` and survives only in `raw`.
|
|
1704
|
+
const strings = new Arr(array, node.quasi.quasis.map((quasi) => quasi.value.cooked ?? undefined));
|
|
1705
|
+
define(strings, "raw", new Arr(array, node.quasi.quasis.map((quasi) => quasi.value.raw)), frozen);
|
|
1706
|
+
this.ctx.templates.set(node, strings);
|
|
1707
|
+
return strings;
|
|
1708
|
+
}
|
|
1684
1709
|
evaluateConditionalExpression(node) {
|
|
1685
1710
|
return Effect.flatMap(this.evaluateExpression(node.test), (test) => this.evaluateExpression(test ? node.consequent : node.alternate));
|
|
1686
1711
|
}
|
|
@@ -62,7 +62,7 @@ export declare const rangeError: (message: string, node?: AstNode) => PendingThr
|
|
|
62
62
|
export declare const referenceError: (message: string, node?: AstNode) => PendingThrow;
|
|
63
63
|
export declare const syntaxError: (message: string, node?: AstNode) => PendingThrow;
|
|
64
64
|
export declare const uriError: (message: string, node?: AstNode) => PendingThrow;
|
|
65
|
-
export declare const supportedSyntaxMessage = "This is a restricted JavaScript-like language. Supported: plain and async functions, data literals, destructuring, standard control flow, await and Promise, and built-ins such as Array, Object, Math, JSON, Date, RegExp, Map, Set, and URL. Unsupported: classes, this, getters/setters,
|
|
65
|
+
export declare const supportedSyntaxMessage = "This is a restricted JavaScript-like language. Supported: plain and async functions, data literals, destructuring, standard control flow, await and Promise, and built-ins such as Array, Object, Math, JSON, Date, RegExp, Map, Set, and URL. Unsupported: classes, this, getters/setters, BigInt, and custom Symbols. Use plain functions and data objects instead.";
|
|
66
66
|
export declare const unsupportedSyntax: (kind: string, node: AstNode) => PendingThrow;
|
|
67
67
|
export declare const sourceLocation: (node: AstNode) => {
|
|
68
68
|
readonly line: number;
|
|
@@ -49,7 +49,7 @@ export const referenceError = failure("ReferenceError");
|
|
|
49
49
|
export const syntaxError = failure("SyntaxError");
|
|
50
50
|
export const uriError = failure("URIError");
|
|
51
51
|
// Orient the agent rather than enumerate JavaScript; interpreter-support.md is the full matrix.
|
|
52
|
-
export const supportedSyntaxMessage = "This is a restricted JavaScript-like language. Supported: plain and async functions, data literals, destructuring, standard control flow, await and Promise, and built-ins such as Array, Object, Math, JSON, Date, RegExp, Map, Set, and URL. Unsupported: classes, this, getters/setters,
|
|
52
|
+
export const supportedSyntaxMessage = "This is a restricted JavaScript-like language. Supported: plain and async functions, data literals, destructuring, standard control flow, await and Promise, and built-ins such as Array, Object, Math, JSON, Date, RegExp, Map, Set, and URL. Unsupported: classes, this, getters/setters, BigInt, and custom Symbols. Use plain functions and data objects instead.";
|
|
53
53
|
export const unsupportedSyntax = (kind, node) => new PendingThrow("SyntaxError", `Syntax '${kind}' is not supported. ${supportedSyntaxMessage}`, node, "UnsupportedSyntax", [supportedSyntaxMessage]);
|
|
54
54
|
// Acorn lines are 1-based and its columns are 0-based. Diagnostics use 1-based columns of the submitted source.
|
|
55
55
|
export const sourceLocation = (node) => ({
|
package/dist/stdlib/string.js
CHANGED
|
@@ -2,9 +2,9 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { constructor, fn, methods } from "../interpreter/native.js";
|
|
3
3
|
import { checkArrayLength, checkStringLength } from "../interpreter/limits.js";
|
|
4
4
|
import { invalidData, IteratorSymbol, rangeError, typeError } from "../interpreter/model.js";
|
|
5
|
-
import { define, hidden, Arr, hostIterator, RegExpObj, record, coerceToNumber, coerceToString, } from "../interpreter/objects.js";
|
|
5
|
+
import { define, get, hidden, Arr, hostIterator, Obj, RegExpObj, record, coerceToInteger, coerceToNumber, coerceToString, } from "../interpreter/objects.js";
|
|
6
6
|
import { containsOpaqueReference, typeofValue } from "../interpreter/references.js";
|
|
7
|
-
import { applyCollectionCallback, isSupportedCallback } from "../interpreter/callback.js";
|
|
7
|
+
import { applyCollectionCallback, isSupportedCallback, toPrimitiveString } from "../interpreter/callback.js";
|
|
8
8
|
import { matchToValue, toHostRegex } from "./regexp.js";
|
|
9
9
|
import { coercion } from "./value.js";
|
|
10
10
|
// console is intercepted by the interpreter before reaching here.
|
|
@@ -78,6 +78,25 @@ export const stringGlobal = (ctx) => {
|
|
|
78
78
|
methods(builtins, string, [
|
|
79
79
|
codeUnits("fromCharCode", String.fromCharCode),
|
|
80
80
|
codeUnits("fromCodePoint", String.fromCodePoint),
|
|
81
|
+
[
|
|
82
|
+
"raw",
|
|
83
|
+
1,
|
|
84
|
+
(_, args) => {
|
|
85
|
+
const template = args[0];
|
|
86
|
+
const raw = template instanceof Obj ? get(template, "raw") : undefined;
|
|
87
|
+
if (!(raw instanceof Obj))
|
|
88
|
+
throw typeError("String.raw expects a template object with a raw array.");
|
|
89
|
+
const count = Math.max(0, coerceToInteger(get(raw, "length")));
|
|
90
|
+
checkArrayLength(count);
|
|
91
|
+
// Each literal is followed by its substitution, except the last literal, or when substitutions run out.
|
|
92
|
+
const parts = Array.from({ length: count }, (_, index) => index + 1 < count && index + 1 < args.length ? [get(raw, index), args[index + 1]] : [get(raw, index)]).flat();
|
|
93
|
+
return Effect.map(Effect.forEach(parts, (part) => toPrimitiveString(ctx, part)), (strings) => {
|
|
94
|
+
const output = strings.join("");
|
|
95
|
+
checkStringLength(output.length);
|
|
96
|
+
return output;
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
],
|
|
81
100
|
]);
|
|
82
101
|
const self = (thisValue, name) => {
|
|
83
102
|
if (typeof thisValue === "string")
|
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-
|
|
4
|
+
"version": "0.0.0-dev-20030",
|
|
5
5
|
"description": "Effect-native confined code execution over schema-described tools",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|