Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repl API #10

Open
wants to merge 35 commits into
base: lamdera-next
Choose a base branch
from
Open

Repl API #10

wants to merge 35 commits into from

Conversation

supermario
Copy link
Member

To boot:

stack ghci
:rr

Then to test with curl:

curl -s -d '{"imports":{},"types":{},"decls":{},"entry":"1+1"}' -X POST http://localhost:8000/repl

After any changes run :rr to recompile + reboot the lamdera live server.

The Javascript output uses postmessage to communicate with the current window: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage - not in particular the listener registration – this is how your JS code would receive the message from the evaluated JS.

As to how to evaluate the JS within the API result: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

If you want to do this all in Elm from elm-notebook, I would suggest:

  • Query the /repl command from Elm, constructing the equivalent request as above, expecting the body as a String
  • When the HTTP request resolves and you have your Ok string, send that out to Javascript with a port
  • In your port, run the string into eval(string)
  • This will execute the Elm code, firing the postMessage from our compiled code:
self.postMessage({
  name: null,
  value: _Debug_toAnsiString(true, $author$project$Elm_Repl$repl_input_value_),
  type: "number"
});
  • If you were correctly subscribed to postmessage events already, you should now have an object where the .value is the ANSI string of the execution result as above.
  • You can now send that string back into Elm with a port

I think this will be the core building block POC.

Errors

Here's an example request that returns an Elm compiler error object instead:

$ curl -s -d '{"imports":{},"types":{},"decls":{},"entry":"Blah"}' -X POST http://localhost:8000/repl
{"type":"compile-errors","errors":[{"path":"/repl","name":"Elm_Repl","problems":[{"title":"NAMING ERROR","region":{"start":{"line":3,"column":3},"end":{"line":3,"column":7}},"message":["I cannot find a `Blah` variant:\n\n3|   Blah\n     ",{"bold":false,"underline":false,"color":"RED","string":"^^^^"},"\nThese names seem close though:\n\n    ",{"bold":false,"underline":false,"color":"yellow","string":"LT"},"\n    ",{"bold":false,"underline":false,"color":"yellow","string":"EQ"},"\n    ",{"bold":false,"underline":false,"color":"yellow","string":"Err"},"\n    ",{"bold":false,"underline":false,"color":"yellow","string":"False"},"\n\nNote: Evergreen migrations need access to all custom type variants. Make sure\nboth `Blah` and `Evergreen.VX.Blah` are exposed.\n\n",{"bold":false,"underline":true,"color":null,"string":"Hint"},": Read <https://elm-lang.org/0.19.1/imports> to see how `import`\ndeclarations work in Elm."]}]}]}%

This seems pretty straightforward and I guess it'll mainly be a matter of the right decoder and then a display output. Hopefully we can reverse engineer that from the compiler error JSON type being constructed! Alternatively - I have a strong suspicion that @dillonkearns has already done this in elm-pages... maybe he'll have time to comment :)

@dillonkearns
Copy link
Collaborator

I used some code from elm-live as a starting point for turning Elm compiler JSON data into HTML in the browser. Here's how it's done in elm-pages. Hope that helps!

https://github.com/dillonkearns/elm-pages/blob/5e3c0ce3335cae971b0dfc2594151a40ddf4b30a/generator/static-code/hmr.js#L386-L408

@supermario supermario force-pushed the lamdera-next branch 8 times, most recently from 6dd95ad to 07ead2f Compare September 27, 2023 19:28
Copy link
Member Author

@supermario supermario left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @jxxcarlson – looking good overall. If you could tackle this feedback when you can, I'll do a rebase of the branch after you're done.

@@ -130,6 +146,9 @@ runWithRoot root (Flags maybePort) =
<|> route [ ("_r/:endpoint", Live.serveRpc liveState port) ]
<|> Live.openEditorHandler root
<|> Live.serveExperimental root
<|> (SnapCore.path "repl" $ Repl.endpoint artifactRef)
<|> (SnapCore.path "packageList" $ Package.handlePost artifactRef)
<|> (SnapCore.path "reportOnInstalledPackages" $ Package.reportOnInstalledPackages)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we know what's needed here, I think it might be nice to namespace this as follows:

  • repl think it makes sense to rename this torepl/js - the repl endpoint specifically for generating JS, because maybe we'll have other modes in future
  • packageList -> repl/setPackages assuming this better reflects what this endpoint does? But now thinking of it, it probably makes sense for this functionality to be merged into repl/js – so you can specify the packages and what you want to compile in one hit, avoiding a race condition if different people want to set different packages and compile different files simultaneously?
  • reportOnInstalledPackages thus probably also should get merged, or maybe it's not longer required if we can be sure the packages we specify will be the context our Elm will get compiled in?

terminal/src/Develop.hs Show resolved Hide resolved
extra/Artifacts.hs Outdated Show resolved Hide resolved
instance FromJSON Dependencies

--- curl -X POST -H "Content-Length: 0" http://localhost:8000/reportOnInstalledPackages

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For testing the endpoint that returns a list of installed packages, for example:

curl -X POST -H "Content-Length: 0" http://localhost:8000/reportOnInstalledPackages
[{"name":"elm/parser","version":"1.1.0"},{"name":"elm/core","version":"1.0.5"}]

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I not add comments explaining the purpose of this file?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this file be there? It is changed when a notebook user adds a package.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jxxcarlson yeah this is part of what we need to figure out how to virtualise entirely.

So that the expected dependencies are always sent with every request, and our server side doesn't need to write it to disk first. Inevitably the elm.json is read into a value somewhere, and then compilation continues with that values. So if we can figure that out and skip all the disk write/read stuff, that's much better all round and will also prevent race conditions when multiple people try submit things at the same time.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this reference to port 8007?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep for CORS issues locally we need it.

jxxcarlson and others added 2 commits January 17, 2024 17:43
@supermario supermario force-pushed the lamdera-next branch 2 times, most recently from 857ae96 to 433ec5e Compare May 6, 2024 13:15
@supermario supermario force-pushed the lamdera-next branch 3 times, most recently from 3f4f772 to 7b19439 Compare December 26, 2024 22:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants