@opencode/codemode 0.0.0-dev-20148 → 0.0.0-dev-20150
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/dist/interpreter/callback.d.ts +3 -3
- package/dist/interpreter/callback.js +6 -3
- package/dist/interpreter/interpreter.js +26 -16
- package/dist/stdlib/array.js +9 -4
- package/dist/stdlib/collections.js +2 -2
- package/dist/stdlib/headers.js +1 -1
- package/dist/stdlib/number.js +19 -24
- package/dist/stdlib/string.js +98 -72
- package/dist/stdlib/url.js +1 -1
- package/package.json +1 -1
|
@@ -16,9 +16,9 @@ export declare const invoke: <R>(ctx: Interpreter<R>, value: Value, name: string
|
|
|
16
16
|
export declare const toPrimitiveString: <R>(ctx: Interpreter<R>, value: Value) => Effect.Effect<string, unknown, R>;
|
|
17
17
|
export declare const toPrimitiveNumber: <R>(ctx: Interpreter<R>, value: Value) => Effect.Effect<number, unknown, R>;
|
|
18
18
|
/**
|
|
19
|
-
* Runs a
|
|
20
|
-
*
|
|
19
|
+
* Runs a native body on its arguments after ToPrimitive, in order, with one hint for all positions or one per
|
|
20
|
+
* position. Primitive arguments skip the Effect entirely.
|
|
21
21
|
*/
|
|
22
|
-
export declare const withPrimitives: <R>(ctx: Interpreter<R>, hints: Hint | ReadonlyArray<Hint>, values: Array<Value>, body: (primitives: Array<Value>) => Value) => Value | Effect.Effect<Value, unknown, R>;
|
|
22
|
+
export declare const withPrimitives: <R>(ctx: Interpreter<R>, hints: Hint | ReadonlyArray<Hint>, values: Array<Value>, body: (primitives: Array<Value>) => Value | Effect.Effect<Value, unknown, R>) => Value | Effect.Effect<Value, unknown, R>;
|
|
23
23
|
export declare const isSupportedCallback: (value: Value) => value is Callable;
|
|
24
24
|
export declare const applyCollectionCallback: <R>(ctx: Interpreter<R>, callback: Value, name: string) => ((args: Array<Value>, thisValue?: Value) => Effect.Effect<Value, unknown, R>);
|
|
@@ -47,13 +47,16 @@ export const invoke = (ctx, value, name, label) => {
|
|
|
47
47
|
export const toPrimitiveString = (ctx, value) => Effect.map(toPrimitive(ctx, value, "string"), coerceToString);
|
|
48
48
|
export const toPrimitiveNumber = (ctx, value) => Effect.map(toPrimitive(ctx, value, "number"), coerceToNumber);
|
|
49
49
|
/**
|
|
50
|
-
* Runs a
|
|
51
|
-
*
|
|
50
|
+
* Runs a native body on its arguments after ToPrimitive, in order, with one hint for all positions or one per
|
|
51
|
+
* position. Primitive arguments skip the Effect entirely.
|
|
52
52
|
*/
|
|
53
53
|
export const withPrimitives = (ctx, hints, values, body) => {
|
|
54
54
|
if (!values.some((value) => value instanceof Obj))
|
|
55
55
|
return body(values);
|
|
56
|
-
return Effect.
|
|
56
|
+
return Effect.flatMap(Effect.forEach(values, (value, index) => toPrimitive(ctx, value, typeof hints === "string" ? hints : hints[index])), (primitives) => {
|
|
57
|
+
const result = body(primitives);
|
|
58
|
+
return Effect.isEffect(result) ? result : Effect.succeed(result);
|
|
59
|
+
});
|
|
57
60
|
};
|
|
58
61
|
// The single acceptance list for callbacks: collections, sort, string replacers,
|
|
59
62
|
// Array.from mappers, and promise reactions all admit exactly these callables.
|
|
@@ -33,6 +33,8 @@ const primitiveOperators = new Set([
|
|
|
33
33
|
">>",
|
|
34
34
|
">>>",
|
|
35
35
|
]);
|
|
36
|
+
/** ToPropertyKey on a primitive (or an opaque value, which keeps its built-in string form). */
|
|
37
|
+
const propertyKey = (value) => typeof value === "string" || typeof value === "number" || typeof value === "symbol" ? value : coerceToString(value);
|
|
36
38
|
// What a loop does with its body's result: exit with a StatementResult, or undefined to keep iterating.
|
|
37
39
|
// Unlabelled break ends this loop; a label the loop does not carry propagates outward.
|
|
38
40
|
const loopExit = (result, labels) => {
|
|
@@ -999,7 +1001,7 @@ class Frame {
|
|
|
999
1001
|
}
|
|
1000
1002
|
const keyNode = property.key;
|
|
1001
1003
|
if (property.computed) {
|
|
1002
|
-
return Effect.
|
|
1004
|
+
return Effect.flatMap(this.evaluateExpression(keyNode), (value) => this.toPropertyKey(value, keyNode));
|
|
1003
1005
|
}
|
|
1004
1006
|
if (keyNode.type === "Identifier")
|
|
1005
1007
|
return Effect.succeed(keyNode.name);
|
|
@@ -1120,6 +1122,10 @@ class Frame {
|
|
|
1120
1122
|
// IsLooselyEqual converts only an object facing a non-nullish primitive; two objects (including tool
|
|
1121
1123
|
// references, which are not Obj) compare by identity.
|
|
1122
1124
|
const equality = operator === "==" || operator === "!=";
|
|
1125
|
+
// `in` checks the right operand before ToPropertyKey on the left, so a bad right side wins over a bad key.
|
|
1126
|
+
if (operator === "in" && lhs instanceof Obj && !isOpaque(lhs) && rhs instanceof Obj) {
|
|
1127
|
+
return Effect.map(this.toPropertyKey(lhs, node), (key) => has(rhs, key));
|
|
1128
|
+
}
|
|
1123
1129
|
const other = lhs instanceof Obj ? rhs : lhs;
|
|
1124
1130
|
const converts = primitiveOperators.has(operator) ||
|
|
1125
1131
|
(equality && other !== null && other !== undefined && typeof other !== "object");
|
|
@@ -1142,9 +1148,8 @@ class Frame {
|
|
|
1142
1148
|
return this.looselyEqual(lhs, rhs, node);
|
|
1143
1149
|
if (operator === "!=")
|
|
1144
1150
|
return !this.looselyEqual(lhs, rhs, node);
|
|
1145
|
-
if (operator === "in" && rhs instanceof Obj && !isOpaque(lhs))
|
|
1146
|
-
return has(rhs,
|
|
1147
|
-
}
|
|
1151
|
+
if (operator === "in" && rhs instanceof Obj && !isOpaque(lhs))
|
|
1152
|
+
return has(rhs, propertyKey(lhs));
|
|
1148
1153
|
if (isOpaque(lhs) || isOpaque(rhs)) {
|
|
1149
1154
|
throw invalidData("Binary operators require data values.", node);
|
|
1150
1155
|
}
|
|
@@ -1709,13 +1714,13 @@ class Frame {
|
|
|
1709
1714
|
const keyNode = property.key;
|
|
1710
1715
|
let key;
|
|
1711
1716
|
if (property.computed) {
|
|
1712
|
-
key = self.toPropertyKey(yield* self.evaluateExpression(keyNode));
|
|
1717
|
+
key = yield* self.toPropertyKey(yield* self.evaluateExpression(keyNode), keyNode);
|
|
1713
1718
|
}
|
|
1714
1719
|
else if (keyNode.type === "Identifier") {
|
|
1715
1720
|
key = keyNode.name;
|
|
1716
1721
|
}
|
|
1717
1722
|
else if (keyNode.type === "Literal") {
|
|
1718
|
-
key =
|
|
1723
|
+
key = propertyKey(literal(keyNode));
|
|
1719
1724
|
}
|
|
1720
1725
|
else {
|
|
1721
1726
|
throw typeError("Unsupported object property key shape.", keyNode);
|
|
@@ -1820,11 +1825,15 @@ class Frame {
|
|
|
1820
1825
|
return OptionalShortCircuit;
|
|
1821
1826
|
if ((objectValue === null || objectValue === undefined) && node.optional)
|
|
1822
1827
|
return OptionalShortCircuit;
|
|
1823
|
-
const
|
|
1824
|
-
?
|
|
1825
|
-
: propertyNode
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
+
const keyValue = !node.computed && propertyNode.type === "Identifier"
|
|
1829
|
+
? propertyNode.name
|
|
1830
|
+
: yield* self.evaluateExpression(propertyNode);
|
|
1831
|
+
// GetValue applies ToObject to the base before ToPropertyKey, so a nullish base throws before the key's own
|
|
1832
|
+
// toString runs.
|
|
1833
|
+
if (objectValue === null || objectValue === undefined) {
|
|
1834
|
+
throw typeError(`Cannot read properties of ${objectValue} (reading '${coerceToString(keyValue)}').`, objectNode);
|
|
1835
|
+
}
|
|
1836
|
+
const key = yield* self.toPropertyKey(keyValue, propertyNode);
|
|
1828
1837
|
return self.resolveProperty(objectValue, key, objectNode, propertyNode);
|
|
1829
1838
|
});
|
|
1830
1839
|
}
|
|
@@ -1942,10 +1951,11 @@ class Frame {
|
|
|
1942
1951
|
return;
|
|
1943
1952
|
throw typeError(`Cannot assign to read only property '${String(key)}'.`, node);
|
|
1944
1953
|
}
|
|
1945
|
-
// ToPropertyKey:
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1954
|
+
// ToPropertyKey: a data object converts through its own `toString`/`valueOf` first; anything else becomes its
|
|
1955
|
+
// string form synchronously, so `counts[row.category]` works when the field is null.
|
|
1956
|
+
toPropertyKey(value, node) {
|
|
1957
|
+
if (!(value instanceof Obj))
|
|
1958
|
+
return Effect.succeed(propertyKey(value));
|
|
1959
|
+
return Effect.map(this.toPrimitive(value, "string", node), propertyKey);
|
|
1950
1960
|
}
|
|
1951
1961
|
}
|
package/dist/stdlib/array.js
CHANGED
|
@@ -29,7 +29,7 @@ const arrayFrom = (ctx, args) => {
|
|
|
29
29
|
const values = [];
|
|
30
30
|
for (let index = 0; index < arrayLike.length; index += 1) {
|
|
31
31
|
const item = get(arrayLike.source, index);
|
|
32
|
-
values.push(apply === undefined ? item : yield* apply([item, index]));
|
|
32
|
+
values.push(apply === undefined ? item : yield* apply([item, index], args[2]));
|
|
33
33
|
}
|
|
34
34
|
return new Arr(proto, values);
|
|
35
35
|
}
|
|
@@ -39,7 +39,9 @@ const arrayFrom = (ctx, args) => {
|
|
|
39
39
|
const step = yield* cursor.next;
|
|
40
40
|
if (step.done)
|
|
41
41
|
return new Arr(proto, values);
|
|
42
|
-
values.push(apply === undefined
|
|
42
|
+
values.push(apply === undefined
|
|
43
|
+
? step.value
|
|
44
|
+
: yield* preserveConsumerError(cursor.close, apply([step.value, index], args[2])));
|
|
43
45
|
index += 1;
|
|
44
46
|
}
|
|
45
47
|
});
|
|
@@ -332,7 +334,7 @@ export const arrayGlobal = (ctx) => {
|
|
|
332
334
|
for (let index = 0; index < length; index += 1) {
|
|
333
335
|
if (!(index in target.items))
|
|
334
336
|
continue;
|
|
335
|
-
const mapped = yield* apply([target.items[index], index, target]);
|
|
337
|
+
const mapped = yield* apply([target.items[index], index, target], args[1]);
|
|
336
338
|
if (mapped instanceof Arr)
|
|
337
339
|
values.push(...mapped.items);
|
|
338
340
|
else
|
|
@@ -357,7 +359,10 @@ export const callbackMethods = (ctx, label, self, elements, wrap) => {
|
|
|
357
359
|
length,
|
|
358
360
|
(thisValue, args) => {
|
|
359
361
|
const target = self(thisValue, name);
|
|
360
|
-
|
|
362
|
+
const call = applyCollectionCallback(ctx, args[0], `${label}.${name}`);
|
|
363
|
+
// reduce and reduceRight take an initial value where the others take a thisArg.
|
|
364
|
+
const thisArg = name.startsWith("reduce") ? undefined : args[1];
|
|
365
|
+
return body(elements(target), target, (callbackArgs) => call(callbackArgs, thisArg), args);
|
|
361
366
|
},
|
|
362
367
|
];
|
|
363
368
|
return [
|
|
@@ -167,7 +167,7 @@ export const mapGlobal = (ctx) => {
|
|
|
167
167
|
const apply = applyCollectionCallback(ctx, args[0], "Map.forEach");
|
|
168
168
|
return Effect.gen(function* () {
|
|
169
169
|
for (const [key, item] of target.map.entries())
|
|
170
|
-
yield* apply([item, key, target]);
|
|
170
|
+
yield* apply([item, key, target], args[1]);
|
|
171
171
|
return undefined;
|
|
172
172
|
});
|
|
173
173
|
},
|
|
@@ -357,7 +357,7 @@ export const setGlobal = (ctx) => {
|
|
|
357
357
|
const apply = applyCollectionCallback(ctx, args[0], "Set.forEach");
|
|
358
358
|
return Effect.gen(function* () {
|
|
359
359
|
for (const item of target.set.values())
|
|
360
|
-
yield* apply([item, item, target]);
|
|
360
|
+
yield* apply([item, item, target], args[1]);
|
|
361
361
|
return undefined;
|
|
362
362
|
});
|
|
363
363
|
},
|
package/dist/stdlib/headers.js
CHANGED
|
@@ -104,7 +104,7 @@ export const headersGlobal = (ctx) => {
|
|
|
104
104
|
const apply = applyCollectionCallback(ctx, args[0], "Headers.forEach");
|
|
105
105
|
return Effect.gen(function* () {
|
|
106
106
|
for (const [key, value] of Array.from(target.headers.entries()))
|
|
107
|
-
yield* apply([value, key, target]);
|
|
107
|
+
yield* apply([value, key, target], args[1]);
|
|
108
108
|
return undefined;
|
|
109
109
|
});
|
|
110
110
|
},
|
package/dist/stdlib/number.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { constructor, constants, methods } from "../interpreter/native.js";
|
|
2
2
|
import { coerceToNumber } from "../interpreter/objects.js";
|
|
3
3
|
import { rangeError, typeError } from "../interpreter/model.js";
|
|
4
|
+
import { withPrimitives } from "../interpreter/callback.js";
|
|
4
5
|
import { coerce, coercion } from "./value.js";
|
|
5
6
|
export const numberGlobal = (ctx) => {
|
|
6
7
|
const builtins = ctx.builtins;
|
|
@@ -32,32 +33,26 @@ export const numberGlobal = (ctx) => {
|
|
|
32
33
|
return thisValue;
|
|
33
34
|
throw typeError(`Number.prototype.${name} requires that 'this' be a Number.`);
|
|
34
35
|
};
|
|
35
|
-
|
|
36
|
+
// The receiver is checked first, then the one argument converts through ToPrimitive with the number hint.
|
|
37
|
+
const formatting = (name, op) => [
|
|
38
|
+
name,
|
|
39
|
+
1,
|
|
40
|
+
(thisValue, args) => {
|
|
41
|
+
const value = self(thisValue, name);
|
|
42
|
+
return withPrimitives(ctx, "number", [args[0]], ([digits]) => op(value, digits === undefined ? undefined : coerceToNumber(digits)));
|
|
43
|
+
},
|
|
44
|
+
];
|
|
36
45
|
methods(builtins, builtins.Number, [
|
|
37
|
-
|
|
46
|
+
formatting("toFixed", (value, digits) => value.toFixed(digits)),
|
|
38
47
|
["toLocaleString", 0, (thisValue) => self(thisValue, "toLocaleString").toLocaleString("en-US")],
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
[
|
|
50
|
-
"toString",
|
|
51
|
-
1,
|
|
52
|
-
(thisValue, args) => {
|
|
53
|
-
const value = self(thisValue, "toString");
|
|
54
|
-
const radix = optNum(args[0]);
|
|
55
|
-
if (radix !== undefined && (radix < 2 || radix > 36)) {
|
|
56
|
-
throw rangeError("Number.toString radix must be between 2 and 36.");
|
|
57
|
-
}
|
|
58
|
-
return value.toString(radix);
|
|
59
|
-
},
|
|
60
|
-
],
|
|
48
|
+
formatting("toExponential", (value, digits) => value.toExponential(digits)),
|
|
49
|
+
formatting("toPrecision", (value, digits) => (digits === undefined ? value.toString() : value.toPrecision(digits))),
|
|
50
|
+
formatting("toString", (value, radix) => {
|
|
51
|
+
if (radix !== undefined && (radix < 2 || radix > 36)) {
|
|
52
|
+
throw rangeError("Number.toString radix must be between 2 and 36.");
|
|
53
|
+
}
|
|
54
|
+
return value.toString(radix);
|
|
55
|
+
}),
|
|
61
56
|
["valueOf", 0, (thisValue) => self(thisValue, "valueOf")],
|
|
62
57
|
]);
|
|
63
58
|
return number;
|
package/dist/stdlib/string.js
CHANGED
|
@@ -4,7 +4,7 @@ import { checkArrayLength, checkStringLength } from "../interpreter/limits.js";
|
|
|
4
4
|
import { invalidData, IteratorSymbol, rangeError, typeError } from "../interpreter/model.js";
|
|
5
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, toPrimitiveString } from "../interpreter/callback.js";
|
|
7
|
+
import { applyCollectionCallback, isSupportedCallback, toPrimitiveString, withPrimitives, } 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.
|
|
@@ -111,28 +111,50 @@ export const stringGlobal = (ctx) => {
|
|
|
111
111
|
const num = (name, args, index) => coerceToNumber(requireDataArgument(name, index, args[index]));
|
|
112
112
|
const optNum = (name, args, index) => args[index] === undefined ? undefined : num(name, args, index);
|
|
113
113
|
const optStr = (name, args, index) => args[index] === undefined ? undefined : str(name, args, index);
|
|
114
|
-
|
|
114
|
+
// ToPrimitive in spec order: the receiver, then the arguments the method consumes, one hint per position; the
|
|
115
|
+
// rest pass through as they are.
|
|
116
|
+
const simple = (name, length, op, hints = []) => [
|
|
117
|
+
name,
|
|
118
|
+
length,
|
|
119
|
+
(thisValue, args) => {
|
|
120
|
+
if (thisValue === null || thisValue === undefined) {
|
|
121
|
+
throw typeError(`String.prototype.${name} called on null or undefined.`);
|
|
122
|
+
}
|
|
123
|
+
return withPrimitives(ctx, ["string", ...hints], [thisValue, ...args.slice(0, hints.length)], ([value, ...primitives]) => op(coerceToString(value), [...primitives, ...args.slice(hints.length)]));
|
|
124
|
+
},
|
|
125
|
+
];
|
|
126
|
+
// includes, startsWith, and endsWith reject a RegExp before converting their search string and position.
|
|
127
|
+
const searching = (name, op) => simple(name, 1, (value, args) => {
|
|
115
128
|
if (args[0] instanceof RegExpObj) {
|
|
116
129
|
throw typeError(`String.${name} cannot take a regular expression; use regex.test(string) or String.search instead.`);
|
|
117
130
|
}
|
|
118
|
-
|
|
119
|
-
|
|
131
|
+
return withPrimitives(ctx, ["string", "number"], args.slice(0, 2), (primitives) => op(value, str(name, primitives, 0), optNum(name, primitives, 1)));
|
|
132
|
+
});
|
|
133
|
+
// match, matchAll, and search read a RegExp as is and convert anything else to its pattern text.
|
|
134
|
+
const withPattern = (args, op) => args[0] instanceof RegExpObj ? op(args[0]) : withPrimitives(ctx, "string", [args[0]], ([text]) => op(text));
|
|
120
135
|
const replace = (name) => simple(name, 2, (value, args) => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
+
const pattern = args[0];
|
|
137
|
+
const replacer = args[1];
|
|
138
|
+
// A RegExp pattern is used as is; a plain one converts to its search string, then a non-callable replacement.
|
|
139
|
+
return withPrimitives(ctx, "string", [pattern instanceof RegExpObj ? undefined : pattern, isSupportedCallback(replacer) ? undefined : replacer], ([search, replacement]) => {
|
|
140
|
+
if (isSupportedCallback(replacer)) {
|
|
141
|
+
return replaceWithCallback(ctx, value, name, [pattern instanceof RegExpObj ? pattern : search, replacer]);
|
|
142
|
+
}
|
|
143
|
+
if (typeofValue(replacer) === "function") {
|
|
144
|
+
throw typeError(`String.${name} cannot use this callable as a replacer; wrap it in an arrow function, e.g. (match) => tools.ns.tool(match).`);
|
|
145
|
+
}
|
|
146
|
+
const primitives = [search, replacement];
|
|
147
|
+
if (pattern instanceof RegExpObj) {
|
|
148
|
+
const regex = pattern.regex;
|
|
149
|
+
const text = str(name, primitives, 1);
|
|
150
|
+
if (name === "replaceAll")
|
|
151
|
+
replaceAllNeedsGlobal(regex);
|
|
152
|
+
return name === "replace" ? value.replace(regex, text) : value.replaceAll(regex, text);
|
|
153
|
+
}
|
|
154
|
+
if (name === "replace")
|
|
155
|
+
return value.replace(str(name, primitives, 0), str(name, primitives, 1));
|
|
156
|
+
return value.replaceAll(str(name, primitives, 0), str(name, primitives, 1));
|
|
157
|
+
});
|
|
136
158
|
});
|
|
137
159
|
methods(builtins, builtins.String, [
|
|
138
160
|
simple("toString", 0, (value) => value),
|
|
@@ -147,7 +169,7 @@ export const stringGlobal = (ctx) => {
|
|
|
147
169
|
simple("trimEnd", 0, (value) => value.trimEnd()),
|
|
148
170
|
simple("trimRight", 0, (value) => value.trimEnd()),
|
|
149
171
|
// Locale/options are deliberately unsupported; comparison uses the host default locale.
|
|
150
|
-
simple("localeCompare", 1, (value, args) => value.localeCompare(str("localeCompare", args, 0))),
|
|
172
|
+
simple("localeCompare", 1, (value, args) => value.localeCompare(str("localeCompare", args, 0)), ["string"]),
|
|
151
173
|
simple("normalize", 0, (value, args) => {
|
|
152
174
|
const form = optStr("normalize", args, 0);
|
|
153
175
|
try {
|
|
@@ -156,61 +178,62 @@ export const stringGlobal = (ctx) => {
|
|
|
156
178
|
catch {
|
|
157
179
|
throw rangeError(`String.normalize expects the form "NFC", "NFD", "NFKC", or "NFKD" (got ${JSON.stringify(form)}).`);
|
|
158
180
|
}
|
|
159
|
-
}),
|
|
181
|
+
}, ["string"]),
|
|
160
182
|
simple("split", 2, (value, args) => {
|
|
161
|
-
const
|
|
162
|
-
//
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
return value.includes(str("includes", args, 0), optNum("includes", args, 1));
|
|
183
|
+
const separator = args[0];
|
|
184
|
+
// A RegExp separator is used as is; the limit converts before a plain separator does, as in the spec.
|
|
185
|
+
return withPrimitives(ctx, ["number", "string"], [args[1], separator instanceof RegExpObj ? undefined : separator], ([limit, pattern]) => {
|
|
186
|
+
const wrap = (parts) => new Arr(builtins.Array, parts);
|
|
187
|
+
// Native: an undefined separator returns the whole string, not a split on "undefined",
|
|
188
|
+
// unless the limit truncates to zero.
|
|
189
|
+
const requestedLimit = args[1] === undefined ? undefined : num("split", [pattern, limit], 1);
|
|
190
|
+
if (separator === undefined) {
|
|
191
|
+
return wrap(requestedLimit !== undefined && requestedLimit >>> 0 === 0 ? [] : [value]);
|
|
192
|
+
}
|
|
193
|
+
const parts = separator instanceof RegExpObj
|
|
194
|
+
? value.split(separator.regex, requestedLimit)
|
|
195
|
+
: value.split(str("split", [pattern], 0), requestedLimit === undefined ? undefined : requestedLimit >>> 0);
|
|
196
|
+
checkArrayLength(parts.length);
|
|
197
|
+
return wrap(parts);
|
|
198
|
+
});
|
|
178
199
|
}),
|
|
179
|
-
simple("
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
200
|
+
simple("slice", 2, (value, args) => value.slice(optNum("slice", args, 0), optNum("slice", args, 1)), [
|
|
201
|
+
"number",
|
|
202
|
+
"number",
|
|
203
|
+
]),
|
|
204
|
+
searching("includes", (value, search, position) => value.includes(search, position)),
|
|
205
|
+
searching("startsWith", (value, search, position) => value.startsWith(search, position)),
|
|
206
|
+
searching("endsWith", (value, search, position) => value.endsWith(search, position)),
|
|
207
|
+
simple("indexOf", 1, (value, args) => value.indexOf(str("indexOf", args, 0), optNum("indexOf", args, 1)), [
|
|
208
|
+
"string",
|
|
209
|
+
"number",
|
|
210
|
+
]),
|
|
211
|
+
simple("lastIndexOf", 1, (value, args) => value.lastIndexOf(str("lastIndexOf", args, 0), optNum("lastIndexOf", args, 1)), ["string", "number"]),
|
|
189
212
|
replace("replace"),
|
|
190
213
|
replace("replaceAll"),
|
|
191
|
-
simple("match", 1, (value, args) => {
|
|
192
|
-
const
|
|
193
|
-
const matched = value.match(
|
|
214
|
+
simple("match", 1, (value, args) => withPattern(args, (arg) => {
|
|
215
|
+
const regex = toHostRegex(arg, "match");
|
|
216
|
+
const matched = value.match(regex);
|
|
194
217
|
if (matched === null)
|
|
195
218
|
return null;
|
|
196
219
|
// Preserve the own `index` and `groups` properties on non-global matches.
|
|
197
|
-
if (
|
|
220
|
+
if (regex.global)
|
|
198
221
|
return new Arr(builtins.Array, [...matched]);
|
|
199
222
|
return matchToValue(builtins, matched);
|
|
200
|
-
}),
|
|
201
|
-
simple("matchAll", 1, (value, args) => {
|
|
202
|
-
const
|
|
203
|
-
if (!
|
|
204
|
-
throw typeError(`String.matchAll requires a regular expression with the global (g) flag: write /${
|
|
223
|
+
})),
|
|
224
|
+
simple("matchAll", 1, (value, args) => withPattern(args, (arg) => {
|
|
225
|
+
const regex = toHostRegex(arg, "matchAll", "g");
|
|
226
|
+
if (!regex.global) {
|
|
227
|
+
throw typeError(`String.matchAll requires a regular expression with the global (g) flag: write /${regex.source}/${regex.flags}g, or use String.match for a single match.`);
|
|
205
228
|
}
|
|
206
229
|
const matches = [];
|
|
207
|
-
for (const match of value.matchAll(
|
|
230
|
+
for (const match of value.matchAll(regex)) {
|
|
208
231
|
checkArrayLength(matches.length + 1);
|
|
209
232
|
matches.push(matchToValue(builtins, match));
|
|
210
233
|
}
|
|
211
234
|
return new Arr(builtins.Array, matches);
|
|
212
|
-
}),
|
|
213
|
-
simple("search", 1, (value, args) => value.search(toHostRegex(
|
|
235
|
+
})),
|
|
236
|
+
simple("search", 1, (value, args) => withPattern(args, (arg) => value.search(toHostRegex(arg, "search")))),
|
|
214
237
|
simple("repeat", 1, (value, args) => {
|
|
215
238
|
const count = num("repeat", args, 0);
|
|
216
239
|
if (!Number.isFinite(count) || count < 0) {
|
|
@@ -218,30 +241,33 @@ export const stringGlobal = (ctx) => {
|
|
|
218
241
|
}
|
|
219
242
|
checkStringLength(value.length * count);
|
|
220
243
|
return value.repeat(count);
|
|
221
|
-
}),
|
|
244
|
+
}, ["number"]),
|
|
222
245
|
simple("padStart", 1, (value, args) => {
|
|
223
246
|
const length = num("padStart", args, 0);
|
|
224
247
|
checkStringLength(length);
|
|
225
248
|
return value.padStart(length, optStr("padStart", args, 1));
|
|
226
|
-
}),
|
|
249
|
+
}, ["number", "string"]),
|
|
227
250
|
simple("padEnd", 1, (value, args) => {
|
|
228
251
|
const length = num("padEnd", args, 0);
|
|
229
252
|
checkStringLength(length);
|
|
230
253
|
return value.padEnd(length, optStr("padEnd", args, 1));
|
|
231
|
-
}),
|
|
232
|
-
simple("charAt", 1, (value, args) => value.charAt(optNum("charAt", args, 0) ?? 0)),
|
|
233
|
-
simple("at", 1, (value, args) => value.at(optNum("at", args, 0) ?? 0)),
|
|
234
|
-
simple("substring", 2, (value, args) => value.substring(optNum("substring", args, 0) ?? 0, optNum("substring", args, 1))),
|
|
235
|
-
simple("substr", 2, (value, args) => value.substr(optNum("substr", args, 0) ?? 0, optNum("substr", args, 1))
|
|
254
|
+
}, ["number", "string"]),
|
|
255
|
+
simple("charAt", 1, (value, args) => value.charAt(optNum("charAt", args, 0) ?? 0), ["number"]),
|
|
256
|
+
simple("at", 1, (value, args) => value.at(optNum("at", args, 0) ?? 0), ["number"]),
|
|
257
|
+
simple("substring", 2, (value, args) => value.substring(optNum("substring", args, 0) ?? 0, optNum("substring", args, 1)), ["number", "number"]),
|
|
258
|
+
simple("substr", 2, (value, args) => value.substr(optNum("substr", args, 0) ?? 0, optNum("substr", args, 1)), [
|
|
259
|
+
"number",
|
|
260
|
+
"number",
|
|
261
|
+
]),
|
|
236
262
|
simple("isWellFormed", 0, (value) => value.isWellFormed()),
|
|
237
263
|
simple("toWellFormed", 0, (value) => value.toWellFormed()),
|
|
238
|
-
simple("charCodeAt", 1, (value, args) => value.charCodeAt(optNum("charCodeAt", args, 0) ?? 0)),
|
|
239
|
-
simple("codePointAt", 1, (value, args) => value.codePointAt(optNum("codePointAt", args, 0) ?? 0)),
|
|
240
|
-
simple("concat", 1, (value, args) => {
|
|
241
|
-
const joined = value.concat(...
|
|
264
|
+
simple("charCodeAt", 1, (value, args) => value.charCodeAt(optNum("charCodeAt", args, 0) ?? 0), ["number"]),
|
|
265
|
+
simple("codePointAt", 1, (value, args) => value.codePointAt(optNum("codePointAt", args, 0) ?? 0), ["number"]),
|
|
266
|
+
simple("concat", 1, (value, args) => withPrimitives(ctx, "string", args, (parts) => {
|
|
267
|
+
const joined = value.concat(...parts.map((_, index) => str("concat", parts, index)));
|
|
242
268
|
checkStringLength(joined.length);
|
|
243
269
|
return joined;
|
|
244
|
-
}),
|
|
270
|
+
})),
|
|
245
271
|
]);
|
|
246
272
|
define(builtins.String, IteratorSymbol, fn(builtins, "[Symbol.iterator]", 0, (thisValue) => hostIterator(builtins, self(thisValue, "[Symbol.iterator]")[Symbol.iterator]())), hidden);
|
|
247
273
|
return string;
|
package/dist/stdlib/url.js
CHANGED
|
@@ -246,7 +246,7 @@ export const urlSearchParamsGlobal = (ctx) => {
|
|
|
246
246
|
const apply = applyCollectionCallback(ctx, args[0], "URLSearchParams.forEach");
|
|
247
247
|
return Effect.gen(function* () {
|
|
248
248
|
for (const [key, value] of Array.from(target.params.entries()))
|
|
249
|
-
yield* apply([value, key, target]);
|
|
249
|
+
yield* apply([value, key, target], args[1]);
|
|
250
250
|
return undefined;
|
|
251
251
|
});
|
|
252
252
|
},
|
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-20150",
|
|
5
5
|
"description": "Effect-native confined code execution over schema-described tools",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|