diff --git a/Declarative-Web-Framework-Design.md b/Declarative-Web-Framework-Design.md new file mode 100644 index 0000000..6c62f47 --- /dev/null +++ b/Declarative-Web-Framework-Design.md @@ -0,0 +1,127 @@ +# Declarative Web Framework + +The eventual goal of this is to create a language that compiles down to files, in a very similar way to Nix. The idea is to have a pure language that describes an impure computation. + +* Some kind of type that represents "files" on disk. This is the compile output + * Need a way of saying "generate me a path during compile-time" in a way that all of the downstreams still refer to the same path + * Could be a hash based on the file:span of the invocation? + * Lots of tools for performing string parsing and editing +* A higher-level "resource" that may compile to files. + * A resource consists of: + * Arbitrary attribute set, that can include other sub-resources + * Recommended to only have one of the following two: + * A set of "default" sub-resources to include + * A set of files to emit + * A function that operates over and modifies other resources + * Example: a database schema may be a higher-level resource. Compiling this should result in some database files + * To perform migrations, the migration CLI tool that's generated would write a file indicating the new state of the database it just learned back into the source repo to be checked in. + * I think the type signature should look something like this: + * ``` + DatabaseTable : { + name: String, + files: Set, + // Resources is essentially a set of files along with some particular fields of interest + // Here, apply is allowed to assume that all the files in the files field exist + apply: Resources -> Resources + } + ``` +* A concept of a "singleton" resource + * I think this would mostly be for the post-compilation step, where including for example any DocumentationResource should trigger a post-compilation collection of all documentation resources +* Quoting for various source code languages like Javascript + +## Stages of compilation + +1. A non-Turing complete step is used to collect everything into a flat set of resources +2. An optional post-compilation step is run, consisting of all the PostCompilationResource + +## Example components + +### Auth plugin + +``` +let db : SQLDatabase = ... +let adaptor : SQLWithDb<_> = Adaptor({ db }) +let authPlugin = AuthPlugin({ + backend: ... // some kind of config for a database adaptor + // one example would be "SQL db w/ password" + // another could be "SQL db w/ magic link" + clientStrategy: ... // some config like session cookie or jwt + allowGuests: true, +}) + +authPlugin would be { + base: Resource, + usersTable: SQLTableResource, + loginRoute: (LoginRouteOpts) -> EndpointResource, + loginComponent: (LoginComponentOpts) -> WebComponentResource, + registerRoute: (RegisterRouteOpts) -> EndpointResource, + registerComponent: (RegisterComponentOpts) -> WebComponentResource, +} +``` + +### Comments plugin + +``` +let commentsPlugin = CommentsPlugin({ + +}) + +result { + base: Resource, + component: (CommentComponentOpts) -> WebComponentResource, +} +``` + +### Example endpoint + +``` +let submitFlagComponent = ({}) => { + let endpoint = EndpointResource({ + guards: { + user: UserAuthGuard(), + flags: DbTableGuard(flagTable), + flagChecker: FlagCheckerGuard(user), + submittedFlag: PostJsonFieldGuard("flag", "string"), + }, + // This entire next part emits an AST, it does NOT actually run this code + action: do { + result <- flagChecker(submittedFlag); + flags.insert({ + userId: user.id, + flag: submittedFlag, + correct: result.correct, + }); + return result; + } + }) + let inputBox = WebComponentResource(jsxQuote!( + ({ postSubmit }) => { + const error = useState(); + const onSubmit = () => { + const result = await fetch(#{endpoint.url}, { method: "POST" }); + }; + return
+ +
; + } + )) + Resource.bundle([ endpoint, inputBox ]) +} +``` + +### Deploy to kubernetes plugin + +This would be a function that takes a resource consisting of a bunch of endpoints, database tables, etc. and produces a deploy script + +### Deploy to docker compose plugin + +Run a post-compile script that produces a docker image with a particular image name, as well as a `docker-compose.yml` file + +### Documentation + +There should be a "documentation resource" type, which gets collected all together with a search index + +## Open questions + +* Need something like multi-stage programs? Functions annotated with @stage(n). Can't imagine a situation needing this yet +* \ No newline at end of file