@opencode/codemode 2.0.13 → 2.0.15
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;
|
|
@@ -715,10 +717,10 @@ class Frame {
|
|
|
715
717
|
self.predeclarePattern(declared.pattern, declared.mutable, left);
|
|
716
718
|
const right = yield* self.evaluateExpression(node.right);
|
|
717
719
|
const keys = self.enumerableKeys(right, node.right);
|
|
718
|
-
if (left.type
|
|
720
|
+
if (left.type === "RestElement" || left.type === "AssignmentPattern") {
|
|
719
721
|
throw typeError("Unsupported for...in binding.", left);
|
|
720
722
|
}
|
|
721
|
-
const
|
|
723
|
+
const assignment = left.type === "VariableDeclaration" ? undefined : left;
|
|
722
724
|
for (const key of keys) {
|
|
723
725
|
const result = yield* Effect.gen(function* () {
|
|
724
726
|
if (declared?.lexical) {
|
|
@@ -729,8 +731,8 @@ class Frame {
|
|
|
729
731
|
else if (declared) {
|
|
730
732
|
yield* self.assignPattern(declared.pattern, key, left);
|
|
731
733
|
}
|
|
732
|
-
else if (
|
|
733
|
-
self.
|
|
734
|
+
else if (assignment) {
|
|
735
|
+
yield* self.assignPattern(assignment, key, left);
|
|
734
736
|
}
|
|
735
737
|
return yield* self.evaluateStatement(node.body);
|
|
736
738
|
}).pipe(Effect.ensuring(Effect.sync(() => {
|
|
@@ -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":
|
|
@@ -1366,12 +1370,16 @@ class Frame {
|
|
|
1366
1370
|
paramScope.set(name, { mutable: true, value: undefined, initialized: false });
|
|
1367
1371
|
}
|
|
1368
1372
|
}
|
|
1373
|
+
const parameters = fn.parameters.map((parameter) => parameter.type === "Identifier" ? parameter.name : undefined);
|
|
1369
1374
|
const bind = Effect.gen(function* () {
|
|
1370
1375
|
for (const [index, parameter] of fn.parameters.entries()) {
|
|
1371
1376
|
if (parameter.type === "RestElement") {
|
|
1372
1377
|
yield* invocation.declarePattern(parameter.argument, new Arr(self.ctx.builtins.Array, args.slice(index)), true, parameter, true);
|
|
1373
1378
|
break;
|
|
1374
1379
|
}
|
|
1380
|
+
// A sloppy simple parameter list may repeat a name; the last occurrence wins, as in JS.
|
|
1381
|
+
if (parameter.type === "Identifier" && parameters.lastIndexOf(parameter.name) !== index)
|
|
1382
|
+
continue;
|
|
1375
1383
|
yield* invocation.declarePattern(parameter, args[index], true, parameter, true);
|
|
1376
1384
|
}
|
|
1377
1385
|
});
|
|
@@ -1666,7 +1674,7 @@ class Frame {
|
|
|
1666
1674
|
return Effect.gen(function* () {
|
|
1667
1675
|
for (let index = 0; index < quasis.length; index += 1) {
|
|
1668
1676
|
const quasi = quasis[index];
|
|
1669
|
-
// acorn only omits `cooked` for invalid escapes
|
|
1677
|
+
// acorn only omits `cooked` for invalid escapes, which are a parse error outside a tagged template.
|
|
1670
1678
|
if (typeof quasi.value.cooked !== "string") {
|
|
1671
1679
|
throw typeError("Invalid template literal quasi.", quasi);
|
|
1672
1680
|
}
|
|
@@ -1681,6 +1689,27 @@ class Frame {
|
|
|
1681
1689
|
return output;
|
|
1682
1690
|
});
|
|
1683
1691
|
}
|
|
1692
|
+
// `tag\`a${x}b\`` is `tag(strings, x)`: the tag is read like a callee (a member keeps its receiver), the
|
|
1693
|
+
// substitutions are evaluated in order, and `strings` carries the escaped source as `strings.raw`.
|
|
1694
|
+
evaluateTaggedTemplate(node) {
|
|
1695
|
+
const self = this;
|
|
1696
|
+
return Effect.gen(function* () {
|
|
1697
|
+
const { callable, thisValue } = node.tag.type === "MemberExpression"
|
|
1698
|
+
? yield* self.readMethod(node.tag)
|
|
1699
|
+
: { callable: yield* self.evaluateExpression(node.tag), thisValue: undefined };
|
|
1700
|
+
const strings = self.ctx.templates.get(node) ?? self.createTemplateObject(node);
|
|
1701
|
+
const values = yield* Effect.forEach(node.quasi.expressions, (expression) => self.evaluateExpression(expression));
|
|
1702
|
+
return yield* self.call(callable, thisValue, [strings, ...values], node, node.tag);
|
|
1703
|
+
});
|
|
1704
|
+
}
|
|
1705
|
+
createTemplateObject(node) {
|
|
1706
|
+
const array = this.ctx.builtins.Array;
|
|
1707
|
+
// An invalid escape such as `\unicode` cooks to `undefined` and survives only in `raw`.
|
|
1708
|
+
const strings = new Arr(array, node.quasi.quasis.map((quasi) => quasi.value.cooked ?? undefined));
|
|
1709
|
+
define(strings, "raw", new Arr(array, node.quasi.quasis.map((quasi) => quasi.value.raw)), frozen);
|
|
1710
|
+
this.ctx.templates.set(node, strings);
|
|
1711
|
+
return strings;
|
|
1712
|
+
}
|
|
1684
1713
|
evaluateConditionalExpression(node) {
|
|
1685
1714
|
return Effect.flatMap(this.evaluateExpression(node.test), (test) => this.evaluateExpression(test ? node.consequent : node.alternate));
|
|
1686
1715
|
}
|
|
@@ -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/regexp.js
CHANGED
|
@@ -15,20 +15,16 @@ const flagProperties = [
|
|
|
15
15
|
const regexFailureReason = (error) => (error instanceof Error ? error.message : String(error)).replace(/^Invalid regular expression:\s*/i, "");
|
|
16
16
|
const escapeRegexHint = 'To match special characters like ( ) [ ] { } + * ? . literally, escape them with a backslash (e.g. "\\\\(") or test for them with String.includes instead.';
|
|
17
17
|
export const toHostRegex = (arg, method, extraFlags = "") => {
|
|
18
|
-
// Native parity: an undefined pattern behaves as an empty pattern.
|
|
19
|
-
if (arg === undefined)
|
|
20
|
-
return new RegExp("", extraFlags);
|
|
21
18
|
if (arg instanceof RegExpObj)
|
|
22
19
|
return arg.regex;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
20
|
+
// Anything else is a pattern string, as `new RegExp(arg)` would read it: undefined is the empty pattern.
|
|
21
|
+
const source = arg === undefined ? "" : coerceToString(arg);
|
|
22
|
+
try {
|
|
23
|
+
return new RegExp(source, extraFlags);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
throw syntaxError(`String.${method} received the string ${JSON.stringify(source)}, which is not a valid regular expression pattern (${regexFailureReason(error)}). ${escapeRegexHint}`);
|
|
30
27
|
}
|
|
31
|
-
throw typeError(`String.${method} expects a regular expression (a /pattern/flags literal or new RegExp(...)) or a string pattern, not ${arg === null ? "null" : typeof arg}.`);
|
|
32
28
|
};
|
|
33
29
|
export const matchToValue = (builtins, match) => {
|
|
34
30
|
const result = new Arr(builtins.Array, Array.from(match, (group) => group));
|
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