-
Notifications
You must be signed in to change notification settings - Fork 130
/
main.js
75 lines (67 loc) · 2.5 KB
/
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import {makeDatabaseClient} from "./database.js";
import {inspect, inspectError} from "./inspect.js";
import {makeLibrary} from "./library.js";
import {Runtime} from "./runtime.js";
const library = makeLibrary();
const {Generators} = library;
library.DatabaseClient = () => makeDatabaseClient(resolveDatabaseToken);
const runtime = new Runtime(library);
export const main = runtime.module();
const attachedFiles = new Map();
function resolveFile(name) {
return attachedFiles.get(name);
}
const databaseTokens = new Map();
async function resolveDatabaseToken(name) {
const token = databaseTokens.get(name);
if (!token) throw new Error(`Database configuration for ${name} not found`);
return token;
}
// https://github.com/observablehq/cli/issues/190
const FileAttachment = runtime.fileAttachments(resolveFile);
FileAttachment.prototype.url = async function() { return String(new URL(await this._url, location)); }; // prettier-ignore
main.builtin("FileAttachment", FileAttachment);
export const cellsById = new Map(); // TODO hide
export function define(cell) {
const {id, inline, inputs = [], outputs = [], files = [], databases = [], body} = cell;
const variables = [];
cellsById.get(id)?.variables.forEach((v) => v.delete());
cellsById.set(id, {cell, variables});
const root = document.querySelector(`#cell-${id}`);
let reset = null;
const clear = () => ((root.innerHTML = ""), (reset = null));
const display = inline
? (v) => {
reset?.();
if (isNode(v) || typeof v === "string" || !v?.[Symbol.iterator]) root.append(v);
else root.append(...v);
return v;
}
: (v) => {
reset?.();
root.append(isNode(v) ? v : inspect(v));
return v;
};
const v = main.variable(
{
pending: () => (reset = clear),
fulfilled: () => reset?.(),
rejected: (error) => (reset?.(), root.append(inspectError(error)))
},
{
shadow: {
display: () => display,
view: () => (v) => Generators.input(display(v))
}
}
);
v.define(outputs.length ? `cell ${id}` : null, inputs, body);
variables.push(v);
for (const o of outputs) variables.push(main.define(o, [`cell ${id}`], (exports) => exports[o]));
for (const f of files) attachedFiles.set(f.name, {url: f.path, mimeType: f.mimeType});
for (const d of databases) databaseTokens.set(d.name, d);
}
// Note: Element.prototype is instanceof Node, but cannot be inserted!
function isNode(value) {
return value instanceof Node && value instanceof value.constructor;
}