liveview-native / live_view_native_stylesheet

MIT License
10 stars 4 forks source link

Change stylesheet output to JSON #86

Open bcardarella opened 2 months ago

bcardarella commented 2 months ago

We currently emit Elixir but I believe for various reasons it will be better to emit JSON.

  1. JSON parsing is available in nearly every language so future clients won't have to implement a new parser, Elixir language parsing is not or has incomplete parsing
  2. JSON parsing is very fast in most languages
  3. We are already encoding some attribute values in JSON

I don't believe we need to change how we are currently constructing our AST, so we will keep that in Elixir format but before it writes to the stylesheet it will convert to JSON

bcardarella commented 2 months ago

The only type in Elixir that we are using that isn't supported by the :json lib is Tuple

bcardarella commented 3 weeks ago

Proposal

Stylesheet syntax:

{
  <class-name>: [
    [<identifier>, <annotations>, [<argument>]]
  ]
}

The stylesheet JSON is always key/value. Keys are always class-name and the values are always an array of AST node arrays.

AST node syntax:

First member of the AST node array is always the identifier string Second member of the AST node array is always the annotations object. Empty object is OK Third member of the AST node array is always the arguments array. Empty array is OK

@NduatiK @nelson-glauber @carson-katri thoughts?

@carson-katri this may or may not be identical or very close to what you proposed a while back, I couldn't find it in Slack

carson-katri commented 2 weeks ago

I think we'll need another element in the AST node for keyword_arguments

[<identifier>, <annotations>, [<argument>], {<keyword>: <argument>}]

For example:

background(.red, in: .circle)
[
  "background",
  {},
  [
    [".", {}, [null, "red"], {}]
  ],
  {
    "in": [".", {}, [null, "circle"], {}]
  }
]
bcardarella commented 2 weeks ago

That changes the node to a 4-element tuple. I believe we could just make the last argument in the 3rd element the json object:

[
  "background",
  {},
  [
    [".", {}, [null, "red"]],
    {"in": [".", {}, [null, "circle"]]
  ]
]
NduatiK commented 2 weeks ago

thoughts?

Looks good to me, looking at the SwiftUI stylesheet tests, I'm confident we can represent everything we currently support

NduatiK commented 1 week ago

@bcardarella, I'm hoping to work on this over the weekend. Two questions:

  1. Should all keyword lists be encoded as json objects?
  2. Do you have any preference between:
    • straight to json parsing (style -> JSON) or
    • using the AST as an intermediate step (style -> AST -> JSON)
bcardarella commented 1 week ago

I believe for our own testing it will be easier if the styles are first compiled as the currently are into the Map then we can have the specific json encoding to convert to JSON as the last step before writing to file. Considering this is a compile-time concern I don't mind the additional overhead of the additional step

NduatiK commented 6 days ago

Moved the issue here since the stylesheet parser does not have much of an effect on the produced style data.