Skip to content

Commit 0c9b29d

Browse files
committed
Interpreting JSON to rxjs graph
1 parent e7ec60f commit 0c9b29d

File tree

2 files changed

+231
-0
lines changed

2 files changed

+231
-0
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<title>rxjs</title>
5+
</head>
6+
<style type="text/css">
7+
.columns {
8+
display: flex;
9+
gap: 16px;
10+
}
11+
12+
.columns > * {
13+
flex: 1;
14+
}
15+
</style>
16+
<body>
17+
<div id="app">
18+
</div>
19+
20+
<pre id="tree"></pre>
21+
22+
<script type="module">
23+
import "./index.js";
24+
</script>
25+
</body>
26+
</html>
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import { BehaviorSubject, combineLatest } from 'https://cdn.jsdelivr.net/npm/rxjs@7.8.1/+esm';
2+
3+
// Example usage with a simplified system.get function
4+
const system = {
5+
get: (key) => {
6+
if (key === 'todos') {
7+
return [
8+
{ label: 'Buy groceries', checked: false },
9+
{ label: 'Vacuum house', checked: true },
10+
{ label: 'Learn RxJS', checked: false }
11+
];
12+
}
13+
return [];
14+
}
15+
};
16+
17+
// Function to create the RxJS network from the new JSON graph format
18+
function createRxJSNetworkFromJson(graph) {
19+
const context = {};
20+
21+
// Create subjects for each node
22+
graph.nodes.forEach(node => {
23+
const nodeName = node.definition.name;
24+
context[nodeName] = {};
25+
context[nodeName]['out'] = new BehaviorSubject(null);
26+
27+
// foreach input in the signature, create a subject
28+
if (node.definition.signature) {
29+
const { inputs } = node.definition.signature;
30+
for (const inputName in inputs) {
31+
context[nodeName][inputName] = new BehaviorSubject(null);
32+
}
33+
}
34+
});
35+
36+
// Set up reactive bindings based on edges
37+
graph.edges.forEach(edge => {
38+
const [source, target] = Object.entries(edge)[0];
39+
const sourceSubject = context[source]['out'];
40+
const targetSubject = context[target[0]][target[1]];
41+
42+
sourceSubject.subscribe(value => {
43+
targetSubject.next(value);
44+
});
45+
});
46+
47+
// Process node definitions and set up reactive logic
48+
graph.nodes.forEach(node => {
49+
const nodeName = node.definition.name;
50+
const { contentType, body, signature } = node.definition;
51+
52+
if (contentType === 'text/javascript') {
53+
// Evaluate the JavaScript content and bind it to the subject
54+
const func = new Function('system', body);
55+
const result = func(system, {
56+
get: (key) => context[key]['out'].getValue(),
57+
set: (key, value) => context[key]['out'].next(value)
58+
});
59+
context[nodeName]['out'].next(result);
60+
} else if (contentType === 'application/json+vnd.common.ui') {
61+
// Set up template rendering
62+
const { inputs } = signature;
63+
const inputObservables = [];
64+
65+
for (const inputName in inputs) {
66+
if (context[inputName]) {
67+
inputObservables.push(context[inputName].out);
68+
}
69+
}
70+
71+
combineLatest(inputObservables).subscribe(values => {
72+
const inputValues = values.reduce((acc, value, index) => {
73+
const key = Object.keys(inputs)[index];
74+
acc[key] = value;
75+
return acc;
76+
}, {});
77+
78+
const renderedTemplate = renderTemplate(node.definition.body, inputValues);
79+
context[nodeName]['out'].next(renderedTemplate);
80+
});
81+
}
82+
});
83+
84+
return context;
85+
}
86+
87+
// Function to render the template based on the node body and input values
88+
function renderTemplate(body, inputValues) {
89+
// Simplified rendering logic for demonstration
90+
if (body.type === 'repeat' && body.binding in inputValues) {
91+
return inputValues[body.binding].map(item => {
92+
return body.template.map(templateNode => {
93+
return `<${templateNode.tag} class="${body.props?.className}">${item.label}</${templateNode.tag}>`;
94+
}).join('');
95+
}).join('');
96+
} else {
97+
let children = body.children;
98+
if (!Array.isArray(body.children)) {
99+
children = [body.children];
100+
}
101+
102+
return `<${body.tag} class="${body.props.className}">${children.map(c => renderTemplate(c, inputValues)).join('\n')}</${body.tag}>`;
103+
}
104+
}
105+
106+
// Example JSON graph document
107+
const jsonDocument = {
108+
"nodes": [
109+
{
110+
"id": "a",
111+
"messages": [
112+
{
113+
"role": "user",
114+
"content": "get my todos"
115+
},
116+
{
117+
"role": "assistant",
118+
"content": "..."
119+
}
120+
],
121+
"definition": {
122+
"name": "todos",
123+
"contentType": "text/javascript",
124+
"signature": {
125+
"inputs": {},
126+
"output": {
127+
"$id": "https://common.tools/stream.schema.json",
128+
"type": {
129+
"$id": "https://common.tools/todos.json"
130+
}
131+
}
132+
},
133+
"body": "return system.get('todos')"
134+
}
135+
},
136+
{
137+
"id": "b",
138+
"messages": [
139+
{
140+
"role": "user",
141+
"content": "render todo"
142+
},
143+
{
144+
"role": "assistant",
145+
"content": "..."
146+
}
147+
],
148+
"definition": {
149+
"name": "ui",
150+
"contentType": "application/json+vnd.common.ui",
151+
"signature": {
152+
"inputs": {
153+
"todos": {
154+
"$id": "https://common.tools/stream.schema.json",
155+
"type": {
156+
"$id": "https://common.tools/todos.json"
157+
}
158+
}
159+
},
160+
"output": {
161+
"$id": "https://common.tools/ui.schema.json"
162+
}
163+
},
164+
"body": {
165+
"tag": "todos",
166+
"props": {
167+
"className": "todo"
168+
},
169+
"children": {
170+
"type": "repeat",
171+
"binding": "todos",
172+
"template": [
173+
{
174+
"tag": "li",
175+
"props": {
176+
"todo": {
177+
"$id": "https://common.tools/cell.json",
178+
"type": "todo"
179+
}
180+
},
181+
"children": []
182+
}
183+
]
184+
}
185+
}
186+
}
187+
}
188+
],
189+
"edges": [
190+
{ "todos": ["ui", "todos"] }
191+
],
192+
"order": [
193+
"a",
194+
"b"
195+
]
196+
};
197+
198+
// Create the RxJS network
199+
const context = createRxJSNetworkFromJson(jsonDocument);
200+
201+
// Example output for the UI component
202+
context['ui'].out.subscribe(renderedTemplate => {
203+
console.log(renderedTemplate);
204+
document.getElementById('app').innerHTML = renderedTemplate;
205+
});

0 commit comments

Comments
 (0)