Skip to content

Commit c518e57

Browse files
committed
minimize diff
1 parent ae6e4b8 commit c518e57

File tree

2 files changed

+89
-95
lines changed

2 files changed

+89
-95
lines changed

src/runtime/define.ts

Lines changed: 50 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import type {Module, Variable, VariableDefinition} from "@observablehq/runtime";
2-
import {Runtime} from "@observablehq/runtime";
32
import type {DisplayState} from "./display.js";
43
import {clear, display, observe} from "./display.js";
5-
import {fileAttachments} from "./stdlib/fileAttachment.js";
64
import {input} from "./stdlib/generators/index.js";
7-
import {library} from "./stdlib/index.js";
85
import {Mutator} from "./stdlib/mutable.js";
96

107
export type DefineState = DisplayState & {
@@ -33,100 +30,61 @@ export type Definition = {
3330
assets?: Map<string, string>;
3431
};
3532

36-
export class NotebookRuntime {
37-
readonly runtime: Runtime & {fileAttachments: typeof fileAttachments};
38-
readonly main: Module;
39-
40-
constructor(builtins = library) {
41-
const runtime = new Runtime({...builtins, __ojs_runtime: () => runtime});
42-
this.runtime = Object.assign(runtime, {fileAttachments});
43-
this.main = runtime.module();
33+
export function define(main: Module, state: DefineState, definition: Definition, observer = observe): void {
34+
const {id, body, inputs = [], outputs = [], output, autodisplay, autoview, automutable} = definition;
35+
const variables = state.variables;
36+
const v = main.variable(observer(state, definition), {shadow: {}});
37+
const vid = output ?? (outputs.length ? `cell ${id}` : null);
38+
if (inputs.includes("display") || inputs.includes("view")) {
39+
let displayVersion = -1; // the variable._version of currently-displayed values
40+
const vd = new (v.constructor as typeof Variable)(2, v._module);
41+
vd.define(
42+
inputs.filter((i) => i !== "display" && i !== "view"),
43+
() => {
44+
const version = v._version; // capture version on input change
45+
return (value: unknown) => {
46+
if (version < displayVersion) throw new Error("stale display");
47+
else if (state.variables[0] !== v) throw new Error("stale display");
48+
else if (version > displayVersion) clear(state);
49+
displayVersion = version;
50+
display(state, value);
51+
return value;
52+
};
53+
}
54+
);
55+
v._shadow.set("display", vd);
56+
if (inputs.includes("view")) {
57+
const vv = new (v.constructor as typeof Variable)(2, v._module, null, {shadow: {}});
58+
vv._shadow.set("display", vd);
59+
vv.define(["display"], (display) => (value: unknown) => input(display(value)));
60+
v._shadow.set("view", vv);
61+
}
62+
} else if (!autodisplay) {
63+
clear(state);
4464
}
45-
46-
define(state: DefineState, definition: Definition, observer = observe): void {
47-
const {
48-
id,
49-
body,
50-
inputs = [],
51-
outputs = [],
52-
output,
53-
autodisplay,
54-
autoview,
55-
automutable
56-
} = definition;
57-
const variables = state.variables;
58-
const v = this.main.variable(observer(state, definition), {shadow: {}});
59-
const vid = output ?? (outputs.length ? `cell ${id}` : null);
60-
if (inputs.includes("display") || inputs.includes("view")) {
61-
let displayVersion = -1; // the variable._version of currently-displayed values
62-
const vd = new (v.constructor as typeof Variable)(2, v._module);
63-
vd.define(
64-
inputs.filter((i) => i !== "display" && i !== "view"),
65-
() => {
66-
const version = v._version; // capture version on input change
67-
return (value: unknown) => {
68-
if (version < displayVersion) throw new Error("stale display");
69-
else if (state.variables[0] !== v) throw new Error("stale display");
70-
else if (version > displayVersion) clear(state);
71-
displayVersion = version;
72-
display(state, value);
73-
return value;
74-
};
75-
}
65+
variables.push(v.define(vid, inputs, body));
66+
if (output != null) {
67+
if (autoview) {
68+
const o = unprefix(output, "viewof$");
69+
variables.push(main.define(o, [output], input));
70+
} else if (automutable) {
71+
const o = unprefix(output, "mutable ");
72+
const x = `cell ${id}`;
73+
v.define(o, [x], ([mutable]) => mutable); // observe live value
74+
variables.push(
75+
main.define(output, inputs, body), // initial value
76+
main.define(x, [output], Mutator),
77+
main.define(`mutable$${o}`, [x], ([, mutator]) => mutator)
7678
);
77-
v._shadow.set("display", vd);
78-
if (inputs.includes("view")) {
79-
const vv = new (v.constructor as typeof Variable)(2, v._module, null, {shadow: {}});
80-
vv._shadow.set("display", vd);
81-
vv.define(["display"], (display) => (value: unknown) => input(display(value)));
82-
v._shadow.set("view", vv);
83-
}
84-
} else if (!autodisplay) {
85-
clear(state);
8679
}
87-
variables.push(v.define(vid, inputs, body));
88-
if (output != null) {
89-
if (autoview) {
90-
const o = this.unprefix(output, "viewof$");
91-
variables.push(this.main.define(o, [output], input));
92-
} else if (automutable) {
93-
const o = this.unprefix(output, "mutable ");
94-
const x = `cell ${id}`;
95-
v.define(o, [x], ([mutable]) => mutable); // observe live value
96-
variables.push(
97-
this.main.define(output, inputs, body), // initial value
98-
this.main.define(x, [output], Mutator),
99-
this.main.define(`mutable$${o}`, [x], ([, mutator]) => mutator)
100-
);
101-
}
102-
} else {
103-
for (const o of outputs) {
104-
variables.push(this.main.variable(true).define(o, [vid!], (exports) => exports[o]));
105-
}
80+
} else {
81+
for (const o of outputs) {
82+
variables.push(main.variable(true).define(o, [vid!], (exports) => exports[o]));
10683
}
10784
}
108-
109-
protected unprefix(name: string, prefix: string): string {
110-
if (!name.startsWith(prefix)) throw new Error(`expected ${prefix}: ${name}`);
111-
return name.slice(prefix.length);
112-
}
11385
}
11486

115-
const defaultNotebook = new NotebookRuntime();
116-
117-
export const runtime = defaultNotebook.runtime;
118-
export const main = defaultNotebook.main;
119-
120-
main.constructor.prototype.defines = function (this: Module, name: string): boolean {
121-
return (
122-
this._scope.has(name) || this._builtins.has(name) || this._runtime._builtin._scope.has(name)
123-
);
124-
};
125-
126-
export function define(
127-
state: DefineState,
128-
definition: Definition,
129-
observer?: typeof observe
130-
): void {
131-
defaultNotebook.define(state, definition, observer);
87+
function unprefix(name: string, prefix: string): string {
88+
if (!name.startsWith(prefix)) throw new Error(`expected ${prefix}: ${name}`);
89+
return name.slice(prefix.length);
13290
}

src/runtime/index.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,45 @@
1-
export * from "./define.js";
1+
import type {Module} from "@observablehq/runtime";
2+
import {Runtime} from "@observablehq/runtime";
3+
import type {DefineState, Definition} from "./define.js";
4+
import {define as _define} from "./define.js";
5+
import type {observe} from "./display.js";
6+
import {fileAttachments} from "./stdlib/fileAttachment.js";
7+
import {library} from "./stdlib/index.js";
8+
9+
export type {DefineState, Definition} from "./define.js";
210
export * from "./display.js";
311
export * from "./inspect.js";
412
export * from "./stdlib/index.js";
5-
613
export type * from "./stdlib/databaseClient.js";
7-
export type * from "./stdlib/fileAttachment.js";
814
export {DatabaseClient} from "./stdlib/databaseClient.js";
15+
export type * from "./stdlib/fileAttachment.js";
916
export {FileAttachment, registerFile} from "./stdlib/fileAttachment.js";
17+
18+
export class NotebookRuntime {
19+
readonly runtime: Runtime & {fileAttachments: typeof fileAttachments};
20+
readonly main: Module;
21+
22+
constructor(builtins = library) {
23+
const runtime = new Runtime({...builtins, __ojs_runtime: () => runtime});
24+
this.runtime = Object.assign(runtime, {fileAttachments});
25+
this.main = runtime.module();
26+
}
27+
28+
define(state: DefineState, definition: Definition, observer?: typeof observe): void {
29+
_define(this.main, state, definition, observer);
30+
}
31+
}
32+
33+
const defaultNotebook = new NotebookRuntime();
34+
35+
export const runtime = defaultNotebook.runtime;
36+
export const main = defaultNotebook.main;
37+
export const define = defaultNotebook.define.bind(defaultNotebook);
38+
39+
main.constructor.prototype.defines = function (this: Module, name: string): boolean {
40+
return (
41+
this._scope.has(name) ||
42+
this._builtins.has(name) ||
43+
this._runtime._builtin._scope.has(name)
44+
);
45+
};

0 commit comments

Comments
 (0)