Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Rough idea] Rework plugin #144

Closed
dummdidumm opened this issue Sep 23, 2020 · 6 comments
Closed

[Rough idea] Rework plugin #144

dummdidumm opened this issue Sep 23, 2020 · 6 comments

Comments

@dummdidumm
Copy link
Member

Right now this plugin does HTML formatting itself, which means keeping up with Prettier upstream on their changes and reimplementing all the corner cases they already gone through, especially when it comes to whitespace handling.

For script/style this is not the case because their formatting is delegated to the built-in parsers.

I wonder if we could do the same for the markup part, like this:

  1. Parse the file into a Svelte AST
  2. Traverse the AST and replace all svelte-specific occurences with placeholders of the same length. Control-flow-statements like {#if are replaced with tags
  3. Let Prettier parse the markup as HTML
  4. Do our own formatting logic for all extracted Svelte-specific constructs
  5. Merge the printed result back into the printed result of the Prettier-HTML-formatter by replacing all placeholders

Example:

Input

<script>
    let a = true;
</script>

{#if a}
  <p transition:fade>hello {a}</p>
{/if}

What the HTML parser gets:

<iffff>
   <p ttttttttttttttttttt>hello ttt</p>
</if>

What this plugin will have left to do:

  • format {#if a}
  • format transition:fade
  • format {a}

Open questions

  • How do we make sure the replacements are unique so that we find them later in the printed output? Use obscure unicode characters?
  • Will this always format correctly or are there some dependencies between parent/child nodes to be printed that can no longer be formulated this way?
@Conduitry
Copy link
Member

Giving the HTML parser <iffff> ... </if>doesn't seem like a good idea because those tags don't match - and I am concerned about how we'd want to handle multi-branch things like {:else} or {:else if} or {:then} etc.

I do think that overall this would be a much more maintainable solution if it could be gotten to work, but I don't see a clear way through here though.

Is it important that the strings the HTML formatter are getting are the same length as what they're replacing? Would anything bad happen if they were longer? If not, that frees us up a bit in terms of making long, unique strings to search for afterwards.

@dummdidumm
Copy link
Member Author

dummdidumm commented Sep 23, 2020

You are right about the tags, silly overlook on my side 😄 The {:else stuff might need to be solved with a closing tag followed by another opening tag, and then replace that in the later stage with one line agaib.
About replacements: The length is kind of important because depending on the length it may introduce line breaks. For example if there are attributes and they sum up to more than the X characters allowed per line, Prettier will output each attribute into a different line.
The identifiers don't have to be unique, we should be able to just traverse them in order because prettier will not change orders I think.

@ehrencrona
Copy link
Contributor

As an alternative, would it be possible to do a Svelte AST-to-Prettier HTML AST translation? I haven't looked into this in detail, but I think it's only the node types that are different. If there is (or we add) a way to plug in handlers into Prettier for node types it doesn't know about, that would feel like a cleaner to solution.

@dummdidumm
Copy link
Member Author

I don't think the HTML AST is public API, and if it changes we would need to make branches depending on the prettier version the user uses. Passing the text as is to the HTML parser will fail because that parser trips up on Svelte syntax. Also, the Svelte AST does lose some information, for example whether or not theres whitespaces/newlines between {#if ..} and its content.

@dummdidumm
Copy link
Member Author

I found one more thing which would make this very hard to implement:

We need the Doc output from the HTML parser to add our own formatting afterwards. But we cannot reliably parse out the stringified content from that, which we would need to replace parts with our own formatting.

Example:
If we transform

{#if foo}
   bar
{/foo}

to

<iiiif>
   bar
</iiif>

We would get some Doc-Builder-soup from which we need to know which parts form the <iiif> and </iiif> to replace them.

If we on the other hand use the prettified string output from the HTML parser, we would get stuff like this

<iii
>content</iif
>

wich also will be hard to find and replace. Also the formatting might not be the same compared to using Docs for everything.

@dummdidumm
Copy link
Member Author

Closing for the reasons outlined above, #160 will get us closer to how prettier formats html.

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

No branches or pull requests

3 participants