@opencode/codemode 0.0.0-beta-19296 → 0.0.0-beta-19378
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.
- package/README.md +6 -0
- package/dist/codemode.d.ts +8 -11
- package/dist/codemode.js +4 -8
- package/dist/data.d.ts +28 -0
- package/dist/data.js +130 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interpreter/errors.d.ts +4 -6
- package/dist/interpreter/errors.js +22 -6
- package/dist/interpreter/execute.d.ts +3 -3
- package/dist/interpreter/execute.js +11 -18
- package/dist/interpreter/globals.d.ts +13 -0
- package/dist/interpreter/globals.js +59 -0
- package/dist/interpreter/host.d.ts +41 -0
- package/dist/interpreter/host.js +44 -0
- package/dist/interpreter/methods.d.ts +3 -16
- package/dist/interpreter/methods.js +42 -239
- package/dist/interpreter/model.d.ts +12 -73
- package/dist/interpreter/model.js +0 -87
- package/dist/interpreter/promises.d.ts +12 -13
- package/dist/interpreter/promises.js +49 -26
- package/dist/interpreter/references.js +23 -70
- package/dist/interpreter/runner.d.ts +23 -0
- package/dist/interpreter/runner.js +42 -0
- package/dist/interpreter/runtime.d.ts +13 -95
- package/dist/interpreter/runtime.js +290 -723
- package/dist/openapi/spec.js +1 -1
- package/dist/stdlib/array.d.ts +3 -0
- package/dist/stdlib/array.js +73 -0
- package/dist/stdlib/collections.d.ts +6 -1
- package/dist/stdlib/collections.js +120 -1
- package/dist/stdlib/console.d.ts +3 -2
- package/dist/stdlib/console.js +25 -16
- package/dist/stdlib/date.d.ts +5 -4
- package/dist/stdlib/date.js +28 -12
- package/dist/stdlib/json.d.ts +4 -4
- package/dist/stdlib/json.js +23 -28
- package/dist/stdlib/math.d.ts +3 -7
- package/dist/stdlib/math.js +85 -153
- package/dist/stdlib/number.d.ts +2 -4
- package/dist/stdlib/number.js +30 -37
- package/dist/stdlib/object.d.ts +4 -6
- package/dist/stdlib/object.js +106 -75
- package/dist/stdlib/regexp.d.ts +4 -6
- package/dist/stdlib/regexp.js +35 -12
- package/dist/stdlib/string.d.ts +1 -3
- package/dist/stdlib/string.js +15 -17
- package/dist/stdlib/url.d.ts +10 -6
- package/dist/stdlib/url.js +102 -25
- package/dist/stdlib/value.d.ts +6 -5
- package/dist/stdlib/value.js +33 -32
- package/dist/tool-runtime.d.ts +16 -15
- package/dist/tool-runtime.js +13 -150
- package/dist/values.d.ts +22 -16
- package/dist/values.js +23 -17
- package/package.json +1 -1
- package/dist/interpreter/iterator.d.ts +0 -13
- package/dist/interpreter/iterator.js +0 -4
- package/dist/stdlib/promise.d.ts +0 -2
- package/dist/stdlib/promise.js +0 -1
package/dist/openapi/spec.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { fromSchemaOpenApi3_0, fromSchemaOpenApi3_1 } from "effect/JsonSchema";
|
|
2
|
-
import { isBlockedMember } from "../
|
|
2
|
+
import { isBlockedMember } from "../data.js";
|
|
3
3
|
export const methods = new Set(["get", "put", "post", "delete", "options", "head", "patch", "trace"]);
|
|
4
4
|
const parameterLocations = ["path", "query", "header"];
|
|
5
5
|
const ignoredHeaderParameters = new Set(["accept", "content-type", "authorization"]);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { HostFunction, sync, syncCall } from "../interpreter/host.js";
|
|
3
|
+
import { CodeModeGenerator, InterpreterRuntimeError } from "../interpreter/model.js";
|
|
4
|
+
import { applyCollectionCallback, preserveConsumerError } from "../interpreter/runner.js";
|
|
5
|
+
import { Values } from "../values.js";
|
|
6
|
+
const constructArray = (args, node) => {
|
|
7
|
+
if (args.length !== 1)
|
|
8
|
+
return [...args];
|
|
9
|
+
const first = args[0];
|
|
10
|
+
if (typeof first !== "number")
|
|
11
|
+
return [first];
|
|
12
|
+
if (!Number.isInteger(first) || first < 0 || first > 4294967295) {
|
|
13
|
+
throw new InterpreterRuntimeError("Invalid array length.", node).as("RangeError");
|
|
14
|
+
}
|
|
15
|
+
// Sparse like JS: Array(3) has holes, and combinator loops already skip them.
|
|
16
|
+
return new Array(first);
|
|
17
|
+
};
|
|
18
|
+
const arrayLikeSource = (source, node) => {
|
|
19
|
+
if (source instanceof Values.Promise) {
|
|
20
|
+
throw new InterpreterRuntimeError("Array.from received an un-awaited Promise; await it before creating the array.", node, "InvalidDataValue");
|
|
21
|
+
}
|
|
22
|
+
if (source !== null &&
|
|
23
|
+
typeof source === "object" &&
|
|
24
|
+
(Object.getPrototypeOf(source) === Object.prototype || Object.getPrototypeOf(source) === null) &&
|
|
25
|
+
typeof source.length === "number") {
|
|
26
|
+
const length = source.length;
|
|
27
|
+
const normalized = Number.isNaN(length) || length <= 0 ? 0 : Math.trunc(length);
|
|
28
|
+
if (normalized > 4_294_967_295)
|
|
29
|
+
throw new RangeError("Invalid array length");
|
|
30
|
+
return { length: normalized, source };
|
|
31
|
+
}
|
|
32
|
+
throw new InterpreterRuntimeError("Array.from expects an array, string, Map, Set, or array-like value.", node, "InvalidDataValue");
|
|
33
|
+
};
|
|
34
|
+
const arrayFrom = (runner, args, node) => {
|
|
35
|
+
const source = args[0];
|
|
36
|
+
const apply = args.length < 2 || args[1] === undefined ? undefined : applyCollectionCallback(runner, args[1], "Array.from", node);
|
|
37
|
+
return Effect.gen(function* () {
|
|
38
|
+
const cursor = yield* runner.syncIterator(source, node);
|
|
39
|
+
if (cursor === undefined) {
|
|
40
|
+
if (source instanceof CodeModeGenerator) {
|
|
41
|
+
throw new InterpreterRuntimeError("Array.from expects a synchronous iterable or array-like value.", node).as("TypeError");
|
|
42
|
+
}
|
|
43
|
+
const arrayLike = arrayLikeSource(source, node);
|
|
44
|
+
const values = [];
|
|
45
|
+
for (let index = 0; index < arrayLike.length; index += 1) {
|
|
46
|
+
const item = Reflect.get(arrayLike.source, index);
|
|
47
|
+
values.push(apply === undefined ? item : yield* apply([item, index]));
|
|
48
|
+
}
|
|
49
|
+
return values;
|
|
50
|
+
}
|
|
51
|
+
const values = [];
|
|
52
|
+
let index = 0;
|
|
53
|
+
while (true) {
|
|
54
|
+
const step = yield* cursor.next;
|
|
55
|
+
if (step.done)
|
|
56
|
+
return values;
|
|
57
|
+
values.push(apply === undefined ? step.value : yield* preserveConsumerError(cursor, apply([step.value, index])));
|
|
58
|
+
index += 1;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
// Array constructs identically with or without new, like JS.
|
|
63
|
+
export const arrayGlobal = (runner) => new HostFunction({
|
|
64
|
+
name: "Array",
|
|
65
|
+
call: syncCall(constructArray),
|
|
66
|
+
construct: syncCall(constructArray),
|
|
67
|
+
instanceOf: (value) => Array.isArray(value),
|
|
68
|
+
members: {
|
|
69
|
+
isArray: sync("Array.isArray", (args) => Array.isArray(args[0])),
|
|
70
|
+
of: sync("Array.of", (args) => [...args]),
|
|
71
|
+
from: new HostFunction({ name: "Array.from", call: (args, node) => arrayFrom(runner, args, node) }),
|
|
72
|
+
},
|
|
73
|
+
});
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
import { HostFunction } from "../interpreter/host.js";
|
|
2
|
+
import { type Runner } from "../interpreter/runner.js";
|
|
1
3
|
export declare const arrayMethods: Set<string>;
|
|
2
4
|
export declare const mapMethods: Set<string>;
|
|
3
|
-
export declare const mapStatics: Set<string>;
|
|
4
5
|
export declare const setMethods: Set<string>;
|
|
6
|
+
/** `Map.groupBy` and `Object.groupBy`: the same iteration, keyed into a Map or a data object. */
|
|
7
|
+
export declare const groupBy: <R>(runner: Runner<R>, namespace: "Map" | "Object") => HostFunction<R>;
|
|
8
|
+
export declare const mapGlobal: <R>(runner: Runner<R>) => HostFunction<R>;
|
|
9
|
+
export declare const setGlobal: <R>(runner: Runner<R>) => HostFunction<R>;
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { isBlockedMember } from "../data.js";
|
|
3
|
+
import { HostFunction, requiresNew } from "../interpreter/host.js";
|
|
4
|
+
import { InterpreterRuntimeError, isRecord } from "../interpreter/model.js";
|
|
5
|
+
import { isRuntimeReference } from "../interpreter/references.js";
|
|
6
|
+
import { applyCollectionCallback, preserveConsumerError, toPrimitive } from "../interpreter/runner.js";
|
|
7
|
+
import { Values } from "../values.js";
|
|
8
|
+
import { coerceToString } from "./value.js";
|
|
1
9
|
export const arrayMethods = new Set([
|
|
2
10
|
"map",
|
|
3
11
|
"filter",
|
|
@@ -37,7 +45,6 @@ export const arrayMethods = new Set([
|
|
|
37
45
|
"entries",
|
|
38
46
|
]);
|
|
39
47
|
export const mapMethods = new Set(["get", "set", "has", "delete", "clear", "forEach", "keys", "values", "entries"]);
|
|
40
|
-
export const mapStatics = new Set(["groupBy"]);
|
|
41
48
|
export const setMethods = new Set([
|
|
42
49
|
"add",
|
|
43
50
|
"has",
|
|
@@ -55,3 +62,115 @@ export const setMethods = new Set([
|
|
|
55
62
|
"isSupersetOf",
|
|
56
63
|
"isDisjointFrom",
|
|
57
64
|
]);
|
|
65
|
+
const coerceGroupByPropertyKey = (runner, value, node) => {
|
|
66
|
+
if (value instanceof Values.Promise)
|
|
67
|
+
return Effect.succeed("[object Promise]");
|
|
68
|
+
if (!Values.isValue(value) && isRuntimeReference(value)) {
|
|
69
|
+
throw new InterpreterRuntimeError("Object.groupBy callback must return a data value.", node, "InvalidDataValue");
|
|
70
|
+
}
|
|
71
|
+
return Effect.map(toPrimitive(runner, value, "string", node), coerceToString);
|
|
72
|
+
};
|
|
73
|
+
/** `Map.groupBy` and `Object.groupBy`: the same iteration, keyed into a Map or a data object. */
|
|
74
|
+
export const groupBy = (runner, namespace) => new HostFunction({
|
|
75
|
+
name: `${namespace}.groupBy`,
|
|
76
|
+
call: (args, node) => {
|
|
77
|
+
const source = args[0];
|
|
78
|
+
if (source === null || source === undefined) {
|
|
79
|
+
throw new InterpreterRuntimeError(`${namespace}.groupBy expects an iterable collection.`, node).as("TypeError");
|
|
80
|
+
}
|
|
81
|
+
const apply = applyCollectionCallback(runner, args[1], `${namespace}.groupBy`, node);
|
|
82
|
+
return Effect.gen(function* () {
|
|
83
|
+
const cursor = yield* runner.syncIterator(source, node);
|
|
84
|
+
if (cursor === undefined) {
|
|
85
|
+
throw new InterpreterRuntimeError(`${namespace}.groupBy expects an iterable collection.`, node).as("TypeError");
|
|
86
|
+
}
|
|
87
|
+
if (namespace === "Map") {
|
|
88
|
+
const result = new Values.Map();
|
|
89
|
+
let index = 0;
|
|
90
|
+
while (true) {
|
|
91
|
+
const step = yield* cursor.next;
|
|
92
|
+
if (step.done)
|
|
93
|
+
return result;
|
|
94
|
+
const item = step.value;
|
|
95
|
+
const key = yield* preserveConsumerError(cursor, apply([item, index]));
|
|
96
|
+
const group = result.map.get(key);
|
|
97
|
+
if (group === undefined)
|
|
98
|
+
result.map.set(key, [item]);
|
|
99
|
+
else
|
|
100
|
+
group.push(item);
|
|
101
|
+
index += 1;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const result = Object.create(null);
|
|
105
|
+
let index = 0;
|
|
106
|
+
while (true) {
|
|
107
|
+
const step = yield* cursor.next;
|
|
108
|
+
if (step.done)
|
|
109
|
+
return result;
|
|
110
|
+
const item = step.value;
|
|
111
|
+
const key = yield* preserveConsumerError(cursor, Effect.flatMap(apply([item, index]), (value) => coerceGroupByPropertyKey(runner, value, node)));
|
|
112
|
+
if (isBlockedMember(key)) {
|
|
113
|
+
return yield* preserveConsumerError(cursor, Effect.fail(new InterpreterRuntimeError(`Property '${key}' is not available.`, node)));
|
|
114
|
+
}
|
|
115
|
+
const group = result[key];
|
|
116
|
+
if (group === undefined)
|
|
117
|
+
result[key] = [item];
|
|
118
|
+
else
|
|
119
|
+
group.push(item);
|
|
120
|
+
index += 1;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
const constructMap = (runner, init, node) => {
|
|
126
|
+
const target = new Values.Map();
|
|
127
|
+
if (init === undefined || init === null)
|
|
128
|
+
return Effect.succeed(target);
|
|
129
|
+
return Effect.gen(function* () {
|
|
130
|
+
const cursor = yield* runner.syncIterator(init, node);
|
|
131
|
+
if (cursor === undefined) {
|
|
132
|
+
throw new InterpreterRuntimeError("new Map(...) expects an iterable of [key, value] pairs or no argument.", node).as("TypeError");
|
|
133
|
+
}
|
|
134
|
+
while (true) {
|
|
135
|
+
const step = yield* cursor.next;
|
|
136
|
+
if (step.done)
|
|
137
|
+
return target;
|
|
138
|
+
yield* preserveConsumerError(cursor, Effect.sync(() => {
|
|
139
|
+
if (!isRecord(step.value) || isRuntimeReference(step.value)) {
|
|
140
|
+
throw new InterpreterRuntimeError("new Map(...) expects [key, value] pairs as entry objects.", node).as("TypeError");
|
|
141
|
+
}
|
|
142
|
+
target.map.set(step.value[0], step.value[1]);
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
const constructSet = (runner, init, node) => {
|
|
148
|
+
const target = new Values.Set();
|
|
149
|
+
if (init === undefined || init === null)
|
|
150
|
+
return Effect.succeed(target);
|
|
151
|
+
return Effect.gen(function* () {
|
|
152
|
+
const cursor = yield* runner.syncIterator(init, node);
|
|
153
|
+
if (cursor === undefined) {
|
|
154
|
+
throw new InterpreterRuntimeError("new Set(...) expects a synchronous iterable or no argument.", node).as("TypeError");
|
|
155
|
+
}
|
|
156
|
+
while (true) {
|
|
157
|
+
const step = yield* cursor.next;
|
|
158
|
+
if (step.done)
|
|
159
|
+
return target;
|
|
160
|
+
target.set.add(step.value);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
export const mapGlobal = (runner) => new HostFunction({
|
|
165
|
+
name: "Map",
|
|
166
|
+
call: requiresNew("Map"),
|
|
167
|
+
construct: (args, node) => constructMap(runner, args[0], node),
|
|
168
|
+
instanceOf: (value) => value instanceof Values.Map,
|
|
169
|
+
members: { groupBy: groupBy(runner, "Map") },
|
|
170
|
+
});
|
|
171
|
+
export const setGlobal = (runner) => new HostFunction({
|
|
172
|
+
name: "Set",
|
|
173
|
+
call: requiresNew("Set"),
|
|
174
|
+
construct: (args, node) => constructSet(runner, args[0], node),
|
|
175
|
+
instanceOf: (value) => value instanceof Values.Set,
|
|
176
|
+
});
|
package/dist/stdlib/console.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { HostNamespace } from "../interpreter/host.js";
|
|
2
|
+
/** Captured console: every method appends one formatted line to `logs`. */
|
|
3
|
+
export declare const consoleGlobal: (logs: Array<string>) => HostNamespace;
|
package/dist/stdlib/console.js
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
|
+
import { toData, toProgram } from "../data.js";
|
|
2
|
+
import { HostNamespace, sync } from "../interpreter/host.js";
|
|
1
3
|
import { containsOpaqueReference, containsRuntimeReference, isRuntimeReference } from "../interpreter/references.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import { Values } from "../values.js";
|
|
5
|
+
import { coerceToString } from "./value.js";
|
|
6
|
+
const consoleMethods = ["log", "info", "debug", "warn", "error", "dir", "table"];
|
|
7
|
+
/** Captured console: every method appends one formatted line to `logs`. */
|
|
8
|
+
export const consoleGlobal = (logs) => new HostNamespace("console", Object.fromEntries(consoleMethods.map((name) => [
|
|
9
|
+
name,
|
|
10
|
+
sync(`console.${name}`, (args) => {
|
|
11
|
+
logs.push(formatConsoleMessage(name, args));
|
|
12
|
+
return undefined;
|
|
13
|
+
}),
|
|
14
|
+
])));
|
|
6
15
|
const MAX_CONSOLE_DEPTH = 32;
|
|
7
|
-
|
|
16
|
+
const formatConsoleMessage = (name, args) => {
|
|
8
17
|
if (name === "dir")
|
|
9
18
|
return args.length === 0 ? "undefined" : formatConsoleArgument(args[0]);
|
|
10
19
|
if (name === "table")
|
|
@@ -28,21 +37,21 @@ const formatConsoleValue = (value, seen, depth) => {
|
|
|
28
37
|
return String(value);
|
|
29
38
|
if (typeof value !== "object")
|
|
30
39
|
return String(value);
|
|
31
|
-
if (value instanceof
|
|
40
|
+
if (value instanceof Values.Promise)
|
|
32
41
|
return "[Promise (await it to get its value)]";
|
|
33
|
-
if (value instanceof
|
|
42
|
+
if (value instanceof Values.Date)
|
|
34
43
|
return coerceToString(value);
|
|
35
|
-
if (value instanceof
|
|
44
|
+
if (value instanceof Values.RegExp)
|
|
36
45
|
return coerceToString(value);
|
|
37
|
-
if (value instanceof
|
|
46
|
+
if (value instanceof Values.URL)
|
|
38
47
|
return coerceToString(value);
|
|
39
|
-
if (value instanceof
|
|
48
|
+
if (value instanceof Values.URLSearchParams)
|
|
40
49
|
return coerceToString(value);
|
|
41
50
|
if (depth > MAX_CONSOLE_DEPTH)
|
|
42
51
|
return "...";
|
|
43
52
|
if (seen.has(value))
|
|
44
53
|
return "[Circular]";
|
|
45
|
-
if (value instanceof
|
|
54
|
+
if (value instanceof Values.Map) {
|
|
46
55
|
seen.add(value);
|
|
47
56
|
try {
|
|
48
57
|
const entries = Array.from(value.map.entries(), ([key, item]) => [key, item]);
|
|
@@ -52,7 +61,7 @@ const formatConsoleValue = (value, seen, depth) => {
|
|
|
52
61
|
seen.delete(value);
|
|
53
62
|
}
|
|
54
63
|
}
|
|
55
|
-
if (value instanceof
|
|
64
|
+
if (value instanceof Values.Set) {
|
|
56
65
|
seen.add(value);
|
|
57
66
|
try {
|
|
58
67
|
return `Set(${value.set.size}) ${formatConsoleValue(Array.from(value.set.values()), seen, depth + 1)}`;
|
|
@@ -81,7 +90,7 @@ const formatConsoleTable = (value, columnsArgument) => {
|
|
|
81
90
|
return "undefined";
|
|
82
91
|
if (containsOpaqueReference(value))
|
|
83
92
|
return "[opaque reference]";
|
|
84
|
-
const data =
|
|
93
|
+
const data = toProgram(value, "console.table argument");
|
|
85
94
|
const columns = consoleTableColumns(columnsArgument);
|
|
86
95
|
const rows = consoleTableRows(data, columns);
|
|
87
96
|
const keys = columns ?? Array.from(new Set(rows.flatMap((row) => Object.keys(row.values))));
|
|
@@ -96,20 +105,20 @@ const consoleTableColumns = (value) => {
|
|
|
96
105
|
return undefined;
|
|
97
106
|
if (containsRuntimeReference(value))
|
|
98
107
|
return undefined;
|
|
99
|
-
const columns =
|
|
108
|
+
const columns = toData(value, "console.table columns", "result");
|
|
100
109
|
return Array.isArray(columns) ? columns.map((column) => String(column)) : undefined;
|
|
101
110
|
};
|
|
102
111
|
const consoleTableRows = (data, columns) => {
|
|
103
112
|
if (Array.isArray(data)) {
|
|
104
113
|
return data.map((item, index) => ({ index: String(index), values: consoleTableValues(item, columns) }));
|
|
105
114
|
}
|
|
106
|
-
if (data !== null && typeof data === "object" && !
|
|
115
|
+
if (data !== null && typeof data === "object" && !Values.isValue(data)) {
|
|
107
116
|
return Object.entries(data).map(([index, item]) => ({ index, values: consoleTableValues(item, columns) }));
|
|
108
117
|
}
|
|
109
118
|
return [{ index: "0", values: { Value: data } }];
|
|
110
119
|
};
|
|
111
120
|
const consoleTableValues = (value, columns) => {
|
|
112
|
-
if (value !== null && typeof value === "object" && !Array.isArray(value) && !
|
|
121
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value) && !Values.isValue(value)) {
|
|
113
122
|
const source = value;
|
|
114
123
|
if (columns !== undefined)
|
|
115
124
|
return Object.fromEntries(columns.map((column) => [column, source[column]]));
|
package/dist/stdlib/date.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { HostFunction } from "../interpreter/host.js";
|
|
1
2
|
import { type AstNode } from "../interpreter/model.js";
|
|
2
|
-
import {
|
|
3
|
+
import { type Runner } from "../interpreter/runner.js";
|
|
4
|
+
import { Values } from "../values.js";
|
|
3
5
|
export declare const dateMethods: Set<string>;
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const invokeDateStatic: (name: string, args: Array<unknown>, node: AstNode) => number;
|
|
6
|
+
export declare const dateGlobal: <R>(runner: Runner<R>) => HostFunction<R>;
|
|
6
7
|
export declare const dateSetterArgumentCount: (name: string) => number | undefined;
|
|
7
|
-
export declare const invokeDateMethod: (value:
|
|
8
|
+
export declare const invokeDateMethod: (value: Values.Date, name: string, args: Array<number>, node: AstNode, initialTime?: number) => unknown;
|
package/dist/stdlib/date.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { HostFunction, sync } from "../interpreter/host.js";
|
|
1
3
|
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
2
|
-
import {
|
|
4
|
+
import { toPrimitive } from "../interpreter/runner.js";
|
|
5
|
+
import { Values } from "../values.js";
|
|
3
6
|
import { coerceToNumber, coerceToString } from "./value.js";
|
|
4
7
|
const dateSetterArguments = new Map([
|
|
5
8
|
["setTime", 1],
|
|
@@ -45,19 +48,32 @@ export const dateMethods = new Set([
|
|
|
45
48
|
"getTimezoneOffset",
|
|
46
49
|
...dateSetterArguments.keys(),
|
|
47
50
|
]);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
throw new InterpreterRuntimeError(`Date.${name} is not available.`, node);
|
|
51
|
+
const constructDate = (runner, args, node) => {
|
|
52
|
+
if (args.length === 0)
|
|
53
|
+
return Effect.succeed(new Values.Date(Date.now()));
|
|
54
|
+
if (args.length === 1) {
|
|
55
|
+
const arg = args[0];
|
|
56
|
+
if (arg instanceof Values.Date)
|
|
57
|
+
return Effect.succeed(new Values.Date(arg.time));
|
|
58
|
+
return Effect.map(toPrimitive(runner, arg, "number", node), (value) => typeof value === "string"
|
|
59
|
+
? new Values.Date(Date.parse(value))
|
|
60
|
+
: new Values.Date(new Date(coerceToNumber(value)).getTime()));
|
|
59
61
|
}
|
|
62
|
+
const parts = args.map((arg) => coerceToNumber(arg));
|
|
63
|
+
return Effect.succeed(new Values.Date(new Date(...parts).getTime()));
|
|
60
64
|
};
|
|
65
|
+
export const dateGlobal = (runner) => new HostFunction({
|
|
66
|
+
name: "Date",
|
|
67
|
+
// ISO instead of the host's locale string: date strings are deterministic and must not leak the host timezone.
|
|
68
|
+
call: () => Effect.sync(() => new Date().toISOString()),
|
|
69
|
+
construct: (args, node) => constructDate(runner, args, node),
|
|
70
|
+
instanceOf: (value) => value instanceof Values.Date,
|
|
71
|
+
members: {
|
|
72
|
+
now: sync("Date.now", () => Date.now()),
|
|
73
|
+
parse: sync("Date.parse", (args) => Date.parse(coerceToString(args[0]))),
|
|
74
|
+
UTC: sync("Date.UTC", (args) => Date.UTC(...args.map((arg) => coerceToNumber(arg)))),
|
|
75
|
+
},
|
|
76
|
+
});
|
|
61
77
|
export const dateSetterArgumentCount = (name) => dateSetterArguments.get(name);
|
|
62
78
|
export const invokeDateMethod = (value, name, args, node, initialTime = value.time) => {
|
|
63
79
|
const hosted = new Date(initialTime);
|
package/dist/stdlib/json.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import
|
|
2
|
+
import { HostNamespace } from "../interpreter/host.js";
|
|
3
|
+
import { type Runner } from "../interpreter/runner.js";
|
|
3
4
|
import { type AstNode } from "../interpreter/model.js";
|
|
4
|
-
export declare const
|
|
5
|
-
export
|
|
6
|
-
export declare const invokeJsonMethod: <R>(runner: CallbackRunner<R>, name: JsonMethodName, args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
|
|
5
|
+
export declare const invokeJsonMethod: <R>(runner: Runner<R>, name: "parse" | "stringify", args: Array<unknown>, node: AstNode) => Effect.Effect<unknown, unknown, R>;
|
|
6
|
+
export declare const jsonGlobal: <R>(runner: Runner<R>) => HostNamespace;
|
package/dist/stdlib/json.js
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import {
|
|
2
|
+
import { HostFunction, HostNamespace } from "../interpreter/host.js";
|
|
3
|
+
import { applyCollectionCallback } from "../interpreter/runner.js";
|
|
3
4
|
import { InterpreterRuntimeError } from "../interpreter/model.js";
|
|
4
5
|
import { typeofValue } from "../interpreter/references.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
export const jsonStatics = new Set(["parse", "stringify"]);
|
|
6
|
+
import { fromData, toData, toProgram } from "../data.js";
|
|
7
|
+
import { Values } from "../values.js";
|
|
8
8
|
export const invokeJsonMethod = (runner, name, args, node) => {
|
|
9
9
|
return name === "parse" ? parse(runner, args, node) : stringify(runner, args, node);
|
|
10
10
|
};
|
|
11
|
+
export const jsonGlobal = (runner) => new HostNamespace("JSON", {
|
|
12
|
+
parse: new HostFunction({ name: "JSON.parse", call: (args, node) => parse(runner, args, node) }),
|
|
13
|
+
stringify: new HostFunction({ name: "JSON.stringify", call: (args, node) => stringify(runner, args, node) }),
|
|
14
|
+
});
|
|
11
15
|
const parse = (runner, args, node) => {
|
|
12
16
|
const text = args[0];
|
|
13
17
|
if (typeof text !== "string")
|
|
14
18
|
throw new InterpreterRuntimeError("JSON.parse expects a string.", node);
|
|
15
19
|
const parsed = (() => {
|
|
16
20
|
try {
|
|
17
|
-
return
|
|
21
|
+
return fromData(JSON.parse(text), "JSON.parse result");
|
|
18
22
|
}
|
|
19
23
|
catch (error) {
|
|
20
24
|
throw new InterpreterRuntimeError(`JSON.parse received invalid JSON: ${error instanceof Error ? error.message : String(error)}`, node).as("SyntaxError");
|
|
@@ -54,27 +58,25 @@ const stringify = (runner, args, node) => {
|
|
|
54
58
|
const space = args[2];
|
|
55
59
|
const indent = typeof space === "number" || typeof space === "string" ? space : undefined;
|
|
56
60
|
const replacer = args[1];
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return Effect.succeed(JSON.stringify(copyOut(input, "json"), properties, indent));
|
|
65
|
-
}
|
|
66
|
-
if (!callable) {
|
|
67
|
-
return Effect.succeed(JSON.stringify(copyOut(input, "json"), null, indent));
|
|
61
|
+
if (typeofValue(replacer) !== "function") {
|
|
62
|
+
const properties = Array.isArray(replacer)
|
|
63
|
+
? replacer
|
|
64
|
+
.filter((item) => typeof item === "string" || typeof item === "number")
|
|
65
|
+
.map(String)
|
|
66
|
+
: null;
|
|
67
|
+
return Effect.succeed(JSON.stringify(toData(args[0], "JSON.stringify value"), properties, indent));
|
|
68
68
|
}
|
|
69
|
+
// Validate up front; the replacer walk below reads the original value.
|
|
70
|
+
toProgram(args[0], "JSON.stringify value");
|
|
69
71
|
const apply = applyCollectionCallback(runner, replacer, "JSON.stringify", node);
|
|
70
72
|
const root = Object.create(null);
|
|
71
|
-
root[""] =
|
|
73
|
+
root[""] = args[0];
|
|
72
74
|
const stack = new Set();
|
|
73
75
|
const visit = (holder, key) => Effect.gen(function* () {
|
|
74
76
|
const value = yield* apply([key, toJSONValue(holder[key])]);
|
|
75
77
|
if (value === undefined || typeofValue(value) === "function")
|
|
76
78
|
return undefined;
|
|
77
|
-
|
|
79
|
+
toProgram(value, "JSON.stringify replacer result");
|
|
78
80
|
if (typeof value === "number")
|
|
79
81
|
return Number.isFinite(value) ? value : null;
|
|
80
82
|
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
@@ -107,18 +109,11 @@ const stringify = (runner, args, node) => {
|
|
|
107
109
|
return Effect.map(visit(root, ""), (value) => JSON.stringify(value, null, indent));
|
|
108
110
|
};
|
|
109
111
|
const toJSONValue = (value) => {
|
|
110
|
-
if (value instanceof
|
|
112
|
+
if (value instanceof Values.Date) {
|
|
111
113
|
return Number.isFinite(value.time) ? new Date(value.time).toISOString() : null;
|
|
112
114
|
}
|
|
113
|
-
if (value instanceof
|
|
115
|
+
if (value instanceof Values.URL)
|
|
114
116
|
return value.url.href;
|
|
115
117
|
return value;
|
|
116
118
|
};
|
|
117
|
-
const isPlainObject = (value) => value !== null &&
|
|
118
|
-
typeof value === "object" &&
|
|
119
|
-
!(value instanceof CodeModeDate) &&
|
|
120
|
-
!(value instanceof CodeModeRegExp) &&
|
|
121
|
-
!(value instanceof CodeModeMap) &&
|
|
122
|
-
!(value instanceof CodeModeSet) &&
|
|
123
|
-
!(value instanceof CodeModeURL) &&
|
|
124
|
-
!(value instanceof CodeModeURLSearchParams);
|
|
119
|
+
const isPlainObject = (value) => value !== null && typeof value === "object" && !Values.isValue(value);
|
package/dist/stdlib/math.d.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { type
|
|
3
|
-
import { type AstNode } from "../interpreter/model.js";
|
|
1
|
+
import { HostNamespace } from "../interpreter/host.js";
|
|
2
|
+
import { type Runner } from "../interpreter/runner.js";
|
|
4
3
|
declare global {
|
|
5
4
|
interface Math {
|
|
6
5
|
sumPrecise(values: Iterable<number>): number;
|
|
7
6
|
}
|
|
8
7
|
}
|
|
9
|
-
export declare const
|
|
10
|
-
export declare const mathMethods: Set<string>;
|
|
11
|
-
export declare const invokeMathMethod: (name: string, args: Array<unknown>, node: AstNode) => number;
|
|
12
|
-
export declare const invokeMathSumPrecise: <R>(runner: SyncIteratorRunner<R>, source: unknown, node: AstNode) => Effect.Effect<number, unknown, R>;
|
|
8
|
+
export declare const mathGlobal: <R>(runner: Runner<R>) => HostNamespace;
|