1- import type { Variable , VariableDefinition } from "@observablehq/runtime" ;
1+ import { Runtime , type Module , type Variable , type VariableDefinition } from "@observablehq/runtime" ;
22import type { DisplayState } from "./display.js" ;
33import { clear , display , observe } from "./display.js" ;
4- import { main } from "./index.js" ;
4+ import { library } from "./stdlib /index.js" ;
55import { input } from "./stdlib/generators/index.js" ;
66import { Mutator } from "./stdlib/mutable.js" ;
7+ import { fileAttachments } from "./stdlib/fileAttachment.js" ;
78
89export type DefineState = DisplayState & {
910 /** the runtime variables associated with this cell */
@@ -31,61 +32,87 @@ export type Definition = {
3132 assets ?: Map < string , string > ;
3233} ;
3334
34- export function define ( state : DefineState , definition : Definition , observer = observe ) : void {
35- const { id, body, inputs = [ ] , outputs = [ ] , output, autodisplay, autoview, automutable} = definition ;
36- const variables = state . variables ;
37- const v = main . variable ( observer ( state , definition ) , { shadow : { } } ) ;
38- const vid = output ?? ( outputs . length ? `cell ${ id } ` : null ) ;
39- if ( inputs . includes ( "display" ) || inputs . includes ( "view" ) ) {
40- let displayVersion = - 1 ; // the variable._version of currently-displayed values
41- const vd = new ( v . constructor as typeof Variable ) ( 2 , v . _module ) ;
42- vd . define (
43- inputs . filter ( ( i ) => i !== "display" && i !== "view" ) ,
44- ( ) => {
45- const version = v . _version ; // capture version on input change
46- return ( value : unknown ) => {
47- if ( version < displayVersion ) throw new Error ( "stale display" ) ;
48- else if ( state . variables [ 0 ] !== v ) throw new Error ( "stale display" ) ;
49- else if ( version > displayVersion ) clear ( state ) ;
50- displayVersion = version ;
51- display ( state , value ) ;
52- return value ;
53- } ;
54- }
55- ) ;
56- v . _shadow . set ( "display" , vd ) ;
57- if ( inputs . includes ( "view" ) ) {
58- const vv = new ( v . constructor as typeof Variable ) ( 2 , v . _module , null , { shadow : { } } ) ;
59- vv . _shadow . set ( "display" , vd ) ;
60- vv . define ( [ "display" ] , ( display ) => ( value : unknown ) => input ( display ( value ) ) ) ;
61- v . _shadow . set ( "view" , vv ) ;
62- }
63- } else if ( ! autodisplay ) {
64- clear ( state ) ;
35+ export class NotebookInstance {
36+
37+ readonly runtime = Object . assign ( new Runtime ( { ...library , __ojs_runtime : ( ) => this . runtime } ) , { fileAttachments } ) ;
38+ readonly main = ( this . runtime as typeof this . runtime & { main : Module } ) . main = this . runtime . module ( ) ;
39+
40+ constructor ( ) {
6541 }
66- variables . push ( v . define ( vid , inputs , body ) ) ;
67- if ( output != null ) {
68- if ( autoview ) {
69- const o = unprefix ( output , "viewof$" ) ;
70- variables . push ( main . define ( o , [ output ] , input ) ) ;
71- } else if ( automutable ) {
72- const o = unprefix ( output , "mutable " ) ;
73- const x = `cell ${ id } ` ;
74- v . define ( o , [ x ] , ( [ mutable ] ) => mutable ) ; // observe live value
75- variables . push (
76- main . define ( output , inputs , body ) , // initial value
77- main . define ( x , [ output ] , Mutator ) ,
78- main . define ( `mutable$${ o } ` , [ x ] , ( [ , mutator ] ) => mutator )
42+
43+ define ( state : DefineState , definition : Definition , observer = observe ) : void {
44+ const { id, body, inputs = [ ] , outputs = [ ] , output, autodisplay, autoview, automutable } = definition ;
45+ const variables = state . variables ;
46+ const v = this . main . variable ( observer ( state , definition ) , { shadow : { } } ) ;
47+ const vid = output ?? ( outputs . length ? `cell ${ id } ` : null ) ;
48+ if ( inputs . includes ( "display" ) || inputs . includes ( "view" ) ) {
49+ let displayVersion = - 1 ; // the variable._version of currently-displayed values
50+ const vd = new ( v . constructor as typeof Variable ) ( 2 , v . _module ) ;
51+ vd . define (
52+ inputs . filter ( ( i ) => i !== "display" && i !== "view" ) ,
53+ ( ) => {
54+ const version = v . _version ; // capture version on input change
55+ return ( value : unknown ) => {
56+ if ( version < displayVersion ) throw new Error ( "stale display" ) ;
57+ else if ( state . variables [ 0 ] !== v ) throw new Error ( "stale display" ) ;
58+ else if ( version > displayVersion ) clear ( state ) ;
59+ displayVersion = version ;
60+ display ( state , value ) ;
61+ return value ;
62+ } ;
63+ }
7964 ) ;
65+ v . _shadow . set ( "display" , vd ) ;
66+ if ( inputs . includes ( "view" ) ) {
67+ const vv = new ( v . constructor as typeof Variable ) ( 2 , v . _module , null , { shadow : { } } ) ;
68+ vv . _shadow . set ( "display" , vd ) ;
69+ vv . define ( [ "display" ] , ( display ) => ( value : unknown ) => input ( display ( value ) ) ) ;
70+ v . _shadow . set ( "view" , vv ) ;
71+ }
72+ } else if ( ! autodisplay ) {
73+ clear ( state ) ;
8074 }
81- } else {
82- for ( const o of outputs ) {
83- variables . push ( main . variable ( true ) . define ( o , [ vid ! ] , ( exports ) => exports [ o ] ) ) ;
75+ variables . push ( v . define ( vid , inputs , body ) ) ;
76+ if ( output != null ) {
77+ if ( autoview ) {
78+ const o = this . unprefix ( output , "viewof$" ) ;
79+ variables . push ( this . main . define ( o , [ output ] , input ) ) ;
80+ } else if ( automutable ) {
81+ const o = this . unprefix ( output , "mutable " ) ;
82+ const x = `cell ${ id } ` ;
83+ v . define ( o , [ x ] , ( [ mutable ] ) => mutable ) ; // observe live value
84+ variables . push (
85+ this . main . define ( output , inputs , body ) , // initial value
86+ this . main . define ( x , [ output ] , Mutator ) ,
87+ this . main . define ( `mutable$${ o } ` , [ x ] , ( [ , mutator ] ) => mutator )
88+ ) ;
89+ }
90+ } else {
91+ for ( const o of outputs ) {
92+ variables . push ( this . main . variable ( true ) . define ( o , [ vid ! ] , ( exports ) => exports [ o ] ) ) ;
93+ }
8494 }
8595 }
86- }
8796
88- function unprefix ( name : string , prefix : string ) : string {
89- if ( ! name . startsWith ( prefix ) ) throw new Error ( `expected ${ prefix } : ${ name } ` ) ;
90- return name . slice ( prefix . length ) ;
97+ protected unprefix ( name : string , prefix : string ) : string {
98+ if ( ! name . startsWith ( prefix ) ) throw new Error ( `expected ${ prefix } : ${ name } ` ) ;
99+ return name . slice ( prefix . length ) ;
100+ }
91101}
102+
103+ const defaultInstance = new NotebookInstance ( ) ;
104+
105+ export const runtime = defaultInstance . runtime ;
106+ export const main = defaultInstance . main ;
107+
108+ main . constructor . prototype . defines = function ( this : Module , name : string ) : boolean {
109+ return (
110+ this . _scope . has ( name ) ||
111+ this . _builtins . has ( name ) ||
112+ this . _runtime . _builtin . _scope . has ( name )
113+ ) ;
114+ } ;
115+
116+ export function define ( state : DefineState , definition : Definition , observer = observe ) : void {
117+ defaultInstance . define ( state , definition , observer ) ;
118+ }
0 commit comments