Skip to content

Conversation

@gordonbrander
Copy link
Contributor

@gordonbrander gordonbrander commented Jul 15, 2024

This PR introduces a set of interdependent changes for deep key paths on bindings, as well as the beginnings of a propagator implementation.

To implement {{deep.paths.in.bindings}} we needed to introduce the concept of a "mapped reactive cell". The simplest way to do this turned out to be to create the beginnings of a propagators implementation.

For more on propagators, see

Additions:

  • Introduce @commontools/common-propagator package which offers a basic propagator implementation
    • Some basic diamond problem fixes are included for non-transformed sources via a Lamport clock
      • We may do further work in a future PR to make this more robust, following Radul, “Propagation Networks: A Flexible and Expressive Substrate for Computation.” or scheduling techniques from signals implementations.
    • Supports mergeable datatypes via the Mergeable interface (any type that implements .merge().
      • All other data types are LWW
    • lift() function to propagator for 1-8 arguments
    • lens() to create a cell that bi-directionally reflects the lensed contents of another cell
    • key() to create a cell that bi-directionally reflects a subkey of another cell
  • Support deep indexing in view bindings {{a.b.c}}
    • Dotted paths in view template strings {{a.b.c}} are parsed into array paths `['a', 'b', 'c'] in view objects.
    • Underneath this feature is a function called path() that allows for deep pathing into objects.
      • Any type can be deep-pathed.
      • If type is Keyable (exposes a .key() method), this will be used to descend into the structure.
      • Otherwise, property access will be used to descend into the structure.
      • We implement Keyable for Cell, returning a mapped cell that bi-directionally reflects the sub-path of the parent.

Changes:

  • Move vnode, binding, section, parser into view.js. These types are all interdependent on each other. Better to have them in one module to avoid circular dependencies.
    • vnode.tag changed to vnode.name. This is more appropriate, since we use name for other view node types, and the name may not always be a tag (in the case of documentfragment).
  • Reactive, Cancel, and some other supporting types have been moved into common propagator
    • Sendable moved into @commontoos/common-propagator/reactive.js
  • Parse sections (but don't do anything with them yet)
    • We will implement sections in a followup PR.
  • Throw parse error in more cases where template string is invalid
  • html template holes are filled with names generated by tid() rather than cid().
    • It's a bit silly, but I wanted the template system to independently own its own client-ID generation.

Removed:

  • Removed State type
    • This was only being used for testing. Replaced by propgator cells.

Unchanged:

  • As before, render() will happily bind primitive values, OR any value that implements .sink().
    • Cell implements .sink()

Improvements:

  • More browser tests
  • More tests

This will let us create block structures.
These types are all interdependent upon each other. Easier to have them
in a single module.
...and change factory naming convention to just vnode, binding, block,
etc.
... mustache calls {{#these}}{{/these}} sections.
@gordonbrander gordonbrander changed the title Mustache-like blocks in html template strings Mustache-like sections in html template strings Jul 17, 2024
Lets us get deep properties on objects or classes via either the `path`
method, or by deep property access.
...and factor cancel out of renderNode. Make it part of the return
signature.
- Add tests
- Batch on microtask instead of animationframe
- Add name to cell
- Remove ID from cell
...instead of bespoke State class.
- Define propagator lens in terms of lens type.
Uses vector clock to solve diamond problem.
- a type is mergeable if it implements merge(value: this): this
- function `merge<T>(prev: T, curr: T): T` will take any two values and
  merge them using merge method if mergeable, or deferring to curr if
  not mergeable
- now we can remove the update function in the cell signature. The type
  knows how to update itself.
- This lets us simplify the cell signature
- We can drop state, which was just a wrapper for cell that had LWW
  semantics. Now all non-mergeable values have LWW semantics.
- Mergeable will let us implement things like accumulating explanations
  on the datatype about what changed and why. We can use these during
  generation.
@gordonbrander gordonbrander changed the title Mustache-like sections in html template strings Introduce deep paths for bindings and make views work with propagators Jul 25, 2024
@gordonbrander gordonbrander marked this pull request as ready for review July 25, 2024 14:45
@gordonbrander gordonbrander merged commit def90d7 into main Jul 25, 2024
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.

2 participants