rs-tml / rstml

Rust+html (JSX-like) parser for TokenStreams aka rsx
https://crates.io/crates/rstml
MIT License
85 stars 8 forks source link

Custom punct before blocks #11

Closed vldm closed 1 year ago

vldm commented 1 year ago

Yew support "Dynamic tag" https://yew.rs/docs/concepts/html/elements#dynamic-tag-names Which allows writing

<@{format!("h{}", level)} class="title">{ text }</@>

Current implementation of syn-rsx, instead force you to write same code in following syntax

<{format!("h{}", level)} class="title">{ text }</{format!("h{}", level)}>

To support yew syntax, we should extend transform_fn for blocks to also support outer punctuation.

Can be related to https://github.com/rs-tml/rstml/issues/8

To avoid duplication in current syntax (in open and closed tags), we can also avoid matching them if node_name has Block type, this allowing to support syntax like:

<{format!("h{}", level)} class="title">{ text }</{...}> // or any other custom syntax in closed tag block body
vldm commented 1 year ago

Thanks to @LLBlumire wildcards are now allowed in close tags, so it is now easier to use "blocks" in element name.

Currently wildcard is limited to already valid NodeName, so:

//this works:
<{"foo"}> </_>
//this doesn't:
<@{"foo"}> </ @>

Because there still might be needs for special puncts in element name place, i decide to keep this issue open for a while.

Probably one way to add custom punctuation support is to allow NodeName extension through the config.

ModProg commented 1 year ago

I would be interested in working something probably related, I need a custom syntax in the tag, in my case, I want to support <for variable in expr> for for loops. (I have similar ideas for if let, etc.) these currently would only work with an additional brace around the expression, which I do not like.

This could probably be similar to custom blocks, though the parser supplied here has more responsibility, as it needs to terminate at the closing > on its own, and it would either need to produce a valid NodeAttribute, or OpenTag requires direct support for storing plain tokens.

If you have an idea how you want this to be implemented, I'd be happy to contribute.

ModProg commented 1 year ago

Maybe we could replace the syn::Block in NodeName::Block with a NodeBlock, that way it could store arbitrary tokens, and a transform_tag could just return Result<Option<NodeName>>, if it is Ok(Some(_)) this is the value used for the OpenTag::name, if it is Ok(None) the tag will be parsed as a normal tag.

Alternatively, we could make OpenTag an enum, but we already have the NodeName enum, and I think it would work quite well.

(Perhaps we could even parse the remaining tokens in the tag as NodeAttributes, though I don't have a use case for that, and really only want to do fully custom tag syntax).

vldm commented 1 year ago

@ModProg hi, in my opinion it could be done by extending enum Node. Probably we can add variant KeywordElement/BuiltinElement with custom body. And trait with methods:

  1. peek_element(ParseStream)-> bool
  2. parse_element(RecoverableContext, ParseStream) -> Option<KeywordElementInner>

So that adding new type of elements would be moved outside of rstml.

There is two challenges that need to be solved:

  1. How to avoid duplication between ElementNode and KeywordElement
  2. If KeywordElementInner would be generic type - user should provide it through config with some reasonable default
ModProg commented 1 year ago

I guess a reasonable default would be Vec<Node> being what NodeElement's body is.

Another question, would this custom node necessarily be open tag, body, and optional closing tag, or should it be able to parse any syntax, i.e. even one not starting with <.

Technically this is something that is already supported by reparsing RawText, though a fully custom parser could probably do a bit more, i.e. allow usages of < that would be invalid in normal raw text.

if we were to support the peeking to be called even without a leading <, it could make sense to not have any NodeElement releated types here, i.e. making the Variant Node::Custom(T =Infallible/!).

ModProg commented 1 year ago

If we go with the fully custom node, I think it would make sense to expose part of NodeElement::parse_recoverable to allow custom nodes to easily parse bodies and closing tags.