svelte icon indicating copy to clipboard operation
svelte copied to clipboard

feat: add a way to compile from an AST

Open benjamingwynn opened this issue 1 year ago • 1 comments

Allows the developer to compile directly from an AST, returned previously from svelte.parse.

There is currently no way to compile a modified AST to source code, this adds a function, compileAST, that provides that functionality.

Notes:

  • The second argument to new Component is currently set to null, this might break something, but for our purposes seems to be working.
  • @param {object} could be typed better.
  • compile could call compileAST underneath so we don't have to copy/paste code.

Hopefully someone has useful feedback!

benjamingwynn avatar Jun 22 '23 16:06 benjamingwynn

Thank you for the quick response! Hopefully those patches address your review notes appropriately.

Since there's no previous issue for this: What's the use case for this feature?

We're implementing an internal GUI tool to modify Svelte files similar to #5972. This tool gets the AST with parse then mutates it, we're looking for a way to get that AST back into Svelte to compile .

Although the AST isn't a public API, because parse exists at all, we'd expect there to be a way to "unparse".

As suggested it would be if compileAst would be called by compile if that doesn't result in more complex code.

My only concern with this is that we'd be always passing null as the second argument to new Component, unless we refactored out into a common function. We haven't seen anything affected by using null here, but haven't done any testing outside of our tool.

benjamingwynn avatar Jun 23 '23 13:06 benjamingwynn

@Rich-Harris is there any chance this could be included in svelte 5?

SystemParadox avatar Sep 25 '23 12:09 SystemParadox

As suggested it would be if compileAst would be called by compile if that doesn't result in more complex code.

Since there's no previous issue for this: What's the use case for this feature?

The use case for this feature would be to be able to do AST transforms. It is much easier to do transforms on an AST than on strings using regexes. Here is a little example:

<script>
	import Component2 from './Component2.svelte'
	let name = 'world';
</script>

<h1>Hello {name}!</h1>
{#if name}
	{@const someVar = "literal"}
	<Component2 some-prop="literal" some-other-prop={someVar}>test</Component2>
{/if}

That I'd like to transform to:


<script>
	import Component2 from './Component2.svelte'
	import {importedVar} from './some/path.js'
	let name = 'world';
</script>

<h1>Hello {name}!</h1>
{#if name}
	{@const someVar = "literal"}
	<Component2 some-prop={importedVar} some-other-prop={someVar}>test</Component2>
{/if}

Now, that means I want to replace ONLY the attribute literal value "literal", but not the "literal" in the variable definition.

I could do that by finding the AST type="Attribute" node with a child of type="Text" and value="literal". Then I would replace the type="Text" node with the desired new AST.

If we need to do this with something like @Rich-Harris Magic-String library, it gets complicated very quickly. One could argue, that the string positions found in the AST nodes would suffice to do accurate replacements. But that cannot be done accurately, as the positions exclude the parenthesis surrounding the attribute literal (as you can see in the screenshot below)

Screenshot 2023-12-15 at 12 14 43

There are several use cases for wanting to transform the Svelte AST, e.g. we (@ivanhofer and me) were using AST transforms for inlangs i18n library.

@Rich-Harris what is your view on this?

benjaminpreiss avatar Dec 15 '23 11:12 benjaminpreiss

One way to achieve printing the AST would be to write code generators for all of these types:

https://github.com/sveltejs/svelte/blob/main/packages/svelte/src/compiler/types/template.d.ts

And then use these generators in https://github.com/davidbonnet/astring?tab=readme-ov-file#extending

Edit:

Maybe a relatively easy way to achieve svelte AST printing is to take the svelte prettier plugin and adapting the printer so that it can be passed to astring as a custom generator?

benjaminpreiss avatar Dec 15 '23 11:12 benjaminpreiss

Just so everybody who ends up here may know, this library is now a reality: https://github.com/xeho91/svelte-ast-print It does what we need, AST -> Code for Svelte stuff.

vini-brito avatar Jul 16 '24 18:07 vini-brito