- 
                Notifications
    
You must be signed in to change notification settings  - Fork 21
 
Description
So when I first made this library, I had one use-case in mind: atom-observable. That extension was pretty minimal: given Observable javascript code, render it into an HTML page. No on-the-fly redefining, only import external notebooks from observablehq.com, it didnt even support viewof and mutable that well: just straight up refresh the page when the source code changes.
But now, given that this project is the only one of its kind, and I'm starting to see a few more projects built on top of this project, I think it's time to re-think how this library is structured. @bryangingechen put it a lot of smart work to make this compiler better, but it was built on top of my ill-defined idea of how the project should be structured. I've spent some time using this library in another project, dataflow, and I've found many issues/confusing things in this library that I think we can improve on.
1) This library is an interpreter and compiler
My original take of this library was an interpreter, NOT a compiler. I named it "compiler" because that's what Observable called their closed-source library, but the original take of this library was like so:
const compile = new Compiler();
const main = await compile.module(`a =1; b = 2; c = a + b;`);
console.log(main.value('c')); // 3The above doesn't compile observable javascript into "real" javascript, it interprets it and executes it on the fly. This library didnt have "compiler" features until @bryangingechen added it like so:
const compile = new Compiler();
const src = compile.moduleToESModule(`a = 1; b = 2; c = a + b`);
console.log(src); // "export default function define(runtime, observer) { ..."I think we can do a better job at distinguishing this in the API. Maybe separate Interpreter and Compiler classes that you interact with. In dataflow, I found myself using the "Interpreter" functions (.cell, .module, createCellDefinition)  when building the "live editor" features, and the "Compiler" functions (.moduleToESModule) when building "export" features. I would assume other users of this library would want something similar, and an easier-to-understand API would be very helpful.
2) define/redefine doesn't help, but raw Runtime variables do
Many of the current "interpreter" functions return explicit define/redefine functions like so:
{define, redefine} = await compile.cell(`a = 20`);
redefine(main);
await main.value("a"); // 20But I didn't find this useful at all in dataflow. I found only define useful, and instead of redefine, I would just delete the original variable and define a new one right away, and I would see no problems. What's key here we need to return runtime variable references in interpreter commands, which #23 made me realize (thanks @a10k !). With those variables, people can delete/redefine the variable directly as they please, instead of dealing with these cryptic define/redefine methods.
3) I found pre-parsing input important
Sometimes, I would pre-parse source code with @observablehq/parser to check for specific references, like FileAttachment and Secret, or to keep track of source code -> runtime variable references to rearrange when code was re-arranged. I would also do this to find import statements and import remote notebooks when interpreting (our current interpreter assumes remote modules are pre-fetched, which is also NOT good).
I think we should either a) only allow people to pass in pre-parsed source code instead of source code directly (meaning we could make @observablehq/parser an optional peer-dependency and make user handle that on their own), b) offer some sort of utility functions that make this easier, or c) return more than just runtime variables / offer better hooks to customize behavior (e.g. return whether a cell is referencing FileAttachment/secrets, adding a "resolveNotebookPath" function in function calls, etc.).
I haven't thought too much about what this would look like, but I think this can be done last when most of the other changes are made.
Let me know what you think!
I plan to "release" dataflow in the very near future, and I want to eventually make a stable v1 release of this library sometime in the future. Not too urgent, I made a new branch of this compiler for my own needs for dataflow, but I would eventually like to use this library officially in that project.