State management

TODO: rewrite completely

As "state" we denote any JavaScript object which represents data point of your app which should be persisted and/or displayed in UI. State is managed and propagated automatically. There is no requirement for creating any abstractions, functions, helpers to change and propagate, as long [TBD]. Example:

<script>
  var a;
</script>
<input type="text" oninput="a=this.value" />
<p bind>a</p>

a value is observed and rendered inside <p> every time new value is assigned to a.

Worth noting is that user can create multiple ObservableContexts for multiple bindDOM calls completely separated from each other and at will manually propagate changes between those contexts. There is no single global state. Internally, state is always passed as an argument, just like config or environment in metaES nodes interpreters.

Chaining observations

Consider:

<script>
  var a, b;
</script>
<input type="text" oninput="a=this.value" />
<p bind>(b = a ? a.toUpperCase() : ''), a</p>
<p bind>b</p>

b is never set directly by user action; it's changed as a consequence of a change. Chained observations are not an explicitly designed, they are byproduct of ObservableContext nature. Currently there is no protection against circular chains.

As a reminder:

(b = a ? a.toUpperCase() : ""), a;

represents Sequence Expression, which evaluates all comma separated expressions in order and as result returns value of last expresssion.

More advanced example:

let metaFetch;
metaesEval(`path=>callcc(fetcher, path)`, fn => (metaFetch = fn), console.error, {
    fetcher: (path, c, cerr) =>
        fetch(path)
            .then(d => d.json())
            .then(c)
            .catch(cerr),
    callcc: callWithCurrentContinuation
});

document.body.appendChild(
    bindDOM(
        `
    <div>
      <script>
        function get(path) {
          loading = true;
          let result = fetch(path);
          loading = false;
          return result;
        }
        </script>
      <p if="loading">Loading...</p>
      <ul>
        <li for="let post of get(page).data.children" bind>post.data.title</li>
      </ul>
    </div>`,
        console.log,
        console.error,
        {
            page: "https://www.reddit.com/r/programming.json"
            loading: false,
            fetch: metaFetch
        }
    )
);

Here we reach out for HTTP resource and indicatie in UI loading state. get is synchronous in context of application code, but asynchronous for browser.