Skip to content

Commit 5de34c7

Browse files
committed
Use Proxy to allow for arbitrary property/array access
1 parent 4a6cf04 commit 5de34c7

File tree

16 files changed

+1096
-70
lines changed

16 files changed

+1096
-70
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env -S npx ts-node --transpileOnly
2+
3+
import { Substrate, Box, sb } from "substrate";
4+
5+
async function main() {
6+
const SUBSTRATE_API_KEY = process.env["SUBSTRATE_API_KEY"];
7+
8+
const substrate = new Substrate({
9+
apiKey: SUBSTRATE_API_KEY,
10+
});
11+
12+
const numbers = new Box(
13+
{
14+
value: [0, 1],
15+
},
16+
);
17+
18+
const latin = new Box(
19+
{
20+
value: ["a", "b"],
21+
},
22+
);
23+
24+
const greek = new Box(
25+
{
26+
value: {
27+
a: "α",
28+
b: "β",
29+
}
30+
},
31+
);
32+
33+
const result = new Box(
34+
{
35+
value: {
36+
a: latin.future.value[numbers.future.value[0]],
37+
b: greek.future.value[latin.future.value[1]],
38+
ab: sb.concat(greek.future.value.a, greek.future.value.b),
39+
},
40+
}
41+
);
42+
43+
const res = await substrate.run(result);
44+
console.log(res.get(result));
45+
}
46+
main();

examples/box.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,13 @@ async function main() {
3131
}, {}),
3232
});
3333

34-
const res = await substrate.run(box);
34+
const box2 = new Box({
35+
value: box.future.value.swedish,
36+
});
37+
38+
const res = await substrate.run(box, box2);
3539

3640
console.log({ box: res.get(box) });
41+
console.log({ box2: res.get(box2) });
3742
}
3843
main();

examples/bug.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env -S npx ts-node --transpileOnly
2+
3+
import { Substrate, Box, sb } from "substrate";
4+
5+
async function main() {
6+
const SUBSTRATE_API_KEY = process.env["SUBSTRATE_API_KEY"];
7+
8+
const substrate = new Substrate({ apiKey: SUBSTRATE_API_KEY });
9+
10+
const data = new Box(
11+
{
12+
value: {
13+
letters: ["a", "b"],
14+
index: 0,
15+
},
16+
}
17+
);
18+
19+
const selected = new Box(
20+
{
21+
value: ob4: sb.get<string>(
22+
data.future.value.object,
23+
data.future.value.letters[1],
24+
),
25+
},
26+
},
27+
{ id: "selected" },
28+
);
29+
30+
// console.log(JSON.stringify(Substrate.serialize(selected), null, 2));
31+
// return;
32+
33+
const res = await substrate.run(selected);
34+
console.log(JSON.stringify(res.json, null, 2));
35+
}
36+
main();

examples/if.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ async function main() {
3030
});
3131

3232
const [jupiter, mars] = sizes as [ComputeJSON, ComputeJSON];
33-
const radius = (p: ComputeJSON) =>
34-
p.future.json_object.get("radius") as unknown as number;
33+
const radius = (p: ComputeJSON) => p.future.json_object.radius;
3534

3635
const comparison = new ComputeJSON({
3736
prompt: sb.interpolate`Is ${radius(jupiter)} > ${radius(mars)}?`,
@@ -45,16 +44,14 @@ async function main() {
4544
},
4645
});
4746

48-
const result = new If({
49-
condition: comparison.future.json_object.get("isGreaterThan") as any,
50-
value_if_true: jupiter.future.json_object,
51-
value_if_false: mars.future.json_object,
47+
const planetName = new If({
48+
condition: comparison.future.json_object.isGreaterThan,
49+
value_if_true: jupiter.future.json_object.planetName,
50+
value_if_false: mars.future.json_object.planetName,
5251
});
5352

5453
const output = new Box({
55-
value: sb.interpolate`The bigger planet is ${result.future.result.get(
56-
"planetName",
57-
)}!`,
54+
value: sb.interpolate`The bigger planet is ${planetName.future.result}!`,
5855
});
5956

6057
const res = await substrate.run(output);

examples/image-generation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env -S npx ts-node --transpileOnly
22

3-
import { Substrate, ComputeText, GenerateImage } from "substrate";
3+
import { Substrate, ComputeText, GenerateImage, sb } from "substrate";
44

55
async function main() {
66
const SUBSTRATE_API_KEY = process.env["SUBSTRATE_API_KEY"];
@@ -22,7 +22,7 @@ async function main() {
2222

2323
const images = styles.map((style) => {
2424
return new GenerateImage({
25-
prompt: scene.future.text.concat(` render in a ((${style})) style`),
25+
prompt: sb.concat(scene.future.text, ` render in a "${style}" style`),
2626
store: "hosted",
2727
});
2828
});

examples/json.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ async function main() {
2626
max_tokens: 800,
2727
});
2828

29-
const name = author.future.json_object.get("name");
30-
const bio = author.future.json_object.get("bio");
29+
const name = author.future.json_object.name;
30+
const bio = author.future.json_object.bio;
3131

3232
const report = new ComputeText({
3333
prompt: sb.interpolate`Write a short summary about ${name} and make sure to use the following bio: ${bio}`,

examples/large-run.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env -S npx ts-node --transpileOnly
22

3-
import { Substrate, ComputeText } from "substrate";
3+
import { Substrate, ComputeText, sb } from "substrate";
44

55
async function main() {
66
const SUBSTRATE_API_KEY = process.env["SUBSTRATE_API_KEY"];
@@ -9,10 +9,10 @@ async function main() {
99

1010
let nodes = [];
1111
let prompt: any = "once upon a time...";
12-
for (let i = 0; i < 50; i++) {
12+
for (let i = 0; i < 25; i++) {
1313
const node = new ComputeText({ prompt });
1414
nodes.push(node);
15-
prompt = node.future.text.concat(" and then");
15+
prompt = sb.concat(node.future.text, " and then");
1616
}
1717

1818
const res = await substrate.run(...nodes);

examples/qa.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.

out.json

Whitespace-only changes.

src/Future.ts

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { idGenerator } from "substrate/idGenerator";
22
import { Node } from "substrate/Node";
3+
import { unproxy } from "./ProxiedFuture";
34

45
type Accessor = "item" | "attr";
56
type TraceOperation = {
@@ -8,7 +9,7 @@ type TraceOperation = {
89
accessor: Accessor;
910
};
1011

11-
type TraceProp = string | Future<string> | number | Future<number>;
12+
export type TraceProp = string | Future<string> | number | Future<number>;
1213
type Concatable = string | Future<string>;
1314
type JQCompatible = Record<string, unknown> | any[] | string | number;
1415
type JQDirectiveTarget = Future<any> | JQCompatible;
@@ -33,7 +34,11 @@ abstract class Directive {
3334
// @ts-ignore
3435
return this.items
3536
.filter((p) => p instanceof Future)
36-
.flatMap((p) => [p, ...p.referencedFutures()]);
37+
.map((p) => unproxy(p) as Future<any>)
38+
.flatMap((p) =>
39+
// @ts-ignore
40+
[p, ...p.referencedFutures()]
41+
);
3742
}
3843
}
3944

@@ -92,6 +97,11 @@ export class Trace extends Directive {
9297
// @ts-expect-error (accessing protected prop: _id)
9398
return Trace.Operation.future("attr", item._id);
9499
} else if (typeof item === "string") {
100+
if (/^\d+$/.test(item)) {
101+
// When item is a number (as a string) we're going to assume it's an array index
102+
let index = parseInt(item);
103+
return Trace.Operation.key("item", index);
104+
}
95105
return Trace.Operation.key("attr", item);
96106
}
97107
return Trace.Operation.key("item", item);
@@ -117,7 +127,7 @@ export class JQ extends Directive {
117127
rawValue: (val: JQCompatible) => ({ future_id: null, val }),
118128
};
119129

120-
override next(...items: TraceProp[]) {
130+
override next(..._items: TraceProp[]) {
121131
return new JQ(this.query, this.target);
122132
}
123133

@@ -184,7 +194,7 @@ export class StringConcat extends Directive {
184194
}
185195
}
186196

187-
export class Future<T> {
197+
export class Future<T = unknown> {
188198
protected _directive: Directive;
189199
protected _id: string = "";
190200
protected _runtimeHint:
@@ -228,7 +238,8 @@ export class Future<T> {
228238
* let newFuture = concat("string", node.future.someString, "!")
229239
*/
230240
export const concat = (...items: (string | Future<string>)[]) => {
231-
return new Future<string>(new StringConcat(items));
241+
const uitems = items.map((item) => item instanceof Future ? unproxy(item) : item);
242+
return new Future<string>(new StringConcat(uitems));
232243
};
233244

234245
/**
@@ -245,7 +256,13 @@ export const interpolate = (
245256
return concat(
246257
...strings.flatMap((s: string, i: number) => {
247258
const expr = exprs[i];
248-
return expr ? [s, expr instanceof Future ? expr : expr.toString()] : [s];
259+
if (expr instanceof Future) {
260+
return [s, unproxy(expr)];
261+
} else if (!expr) {
262+
return [s];
263+
} else {
264+
return [s, expr.toString()];
265+
}
249266
}),
250267
);
251268
};
@@ -279,15 +296,17 @@ export const get = <T = any>(
279296
future: Future<Object>,
280297
path: string | Future<string>,
281298
) => {
299+
const ufuture = unproxy(future);
300+
const upath = path instanceof Future ? unproxy(path) : path;
282301
// @ts-ignore (protected _runtimeHint)
283-
if (path instanceof Future) index._runtimeHint = "string";
302+
if (upath instanceof Future) upath._runtimeHint = "string";
284303

285304
const d =
286-
typeof path === "string"
305+
typeof upath === "string"
287306
? // @ts-ignore (protected _directive)
288-
future._directive.next(...parsePath(path))
307+
ufuture._directive.next(...parsePath(upath))
289308
: // @ts-ignore (protected _directive)
290-
future._directive.next(path);
309+
ufuture._directive.next(upath);
291310
return new Future<T>(d);
292311
};
293312

@@ -299,7 +318,10 @@ export const get = <T = any>(
299318
* let newFuture = at<string>(node.future.strings, 0);
300319
*
301320
*/
302-
export const at = <T = any>(future: Future<T[]>, index: number | Future<number>) => {
321+
export const at = <T = any>(
322+
future: Future<T[]>,
323+
index: number | Future<number>,
324+
) => {
303325
// @ts-ignore (protected _runtimeHint)
304326
if (index instanceof Future) index._runtimeHint = "number";
305327
// @ts-ignore (protected _directive)

0 commit comments

Comments
 (0)