Skip to content

Commit

Permalink
feat: re-use line offsets from sourcemapping logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Princesseuh committed Aug 5, 2024
1 parent 5462a40 commit f7adf78
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 135 deletions.
51 changes: 31 additions & 20 deletions internal/printer/print-to-tsx.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"github.com/withastro/compiler/internal/loc"
"github.com/withastro/compiler/internal/sourcemap"
"github.com/withastro/compiler/internal/transform"
esbuild "github.com/withastro/compiler/lib/esbuild/helpers"
"golang.org/x/net/html/atom"
)

Expand All @@ -38,13 +37,26 @@ func PrintToTSX(sourcetext string, n *Node, opts TSXOptions, transformOpts trans
return PrintResult{
Output: p.output,
SourceMapChunk: p.builder.GenerateChunk(p.output),
TSXRanges: p.ranges,
TSXRanges: finalizeRanges(string(p.output), p.ranges),
}
}

func getUTF16Length(s string) int {
// Go has a built-in module for utf16, but esbuild's is faster and slightly more friendly
return len(esbuild.StringToUTF16(s))
func finalizeRanges(content string, ranges TSXRanges) TSXRanges {
chunkBuilder := sourcemap.MakeChunkBuilder(nil, sourcemap.GenerateLineOffsetTables(content, len(strings.Split(content, "\n"))))

return TSXRanges{
Frontmatter: loc.TSXRange{
Start: chunkBuilder.OffsetAt(loc.Loc{Start: ranges.Frontmatter.Start}),
End: chunkBuilder.OffsetAt(loc.Loc{Start: ranges.Frontmatter.End}),
},
Body: loc.TSXRange{
Start: chunkBuilder.OffsetAt(loc.Loc{Start: ranges.Body.Start}),
End: chunkBuilder.OffsetAt(loc.Loc{Start: ranges.Body.End}),
},
// Scripts and styles are already using the proper positions
Scripts: ranges.Scripts,
Styles: ranges.Styles,
}
}

type TSXRanges struct {
Expand Down Expand Up @@ -324,7 +336,7 @@ func renderTsx(p *printer, n *Node, o *TSXOptions) {
props := js_scanner.GetPropsType(source)
hasGetStaticPaths := js_scanner.HasGetStaticPaths(source)
hasChildren := false
startLoc := getUTF16Length(string(p.output))
startLen := len(p.output)
for c := n.FirstChild; c != nil; c = c.NextSibling {
// This checks for the first node that comes *after* the frontmatter
// to ensure that the statement is properly closed with a `;`.
Expand All @@ -344,15 +356,15 @@ func renderTsx(p *printer, n *Node, o *TSXOptions) {
p.print("<Fragment>\n")

// Update the start location of the body to the start of the first child
startLoc = getUTF16Length(string(p.output))
startLen = len(p.output)

hasChildren = true
}
if c.PrevSibling == nil && c.Type != FrontmatterNode {
p.addNilSourceMapping()
p.print("<Fragment>\n")

startLoc = getUTF16Length(string(p.output))
startLen = len(p.output)

hasChildren = true
}
Expand All @@ -363,8 +375,8 @@ func renderTsx(p *printer, n *Node, o *TSXOptions) {

p.addNilSourceMapping()
p.setTSXBodyRange(loc.TSXRange{
Start: startLoc,
End: getUTF16Length(string(p.output)),
Start: startLen,
End: len(p.output),
})

// Only close the body with `</Fragment>` if we printed a body
Expand Down Expand Up @@ -407,7 +419,7 @@ declare const Astro: Readonly<import('astro').AstroGlobal<%s, typeof %s`, propsI

if n.Type == FrontmatterNode {
p.addSourceMapping(loc.Loc{Start: 0})
frontmatterStart := getUTF16Length(string(p.output))
frontmatterStart := len(p.output)
for c := n.FirstChild; c != nil; c = c.NextSibling {
if c.Type == TextNode {
if len(c.Loc) > 0 {
Expand All @@ -426,7 +438,7 @@ declare const Astro: Readonly<import('astro').AstroGlobal<%s, typeof %s`, propsI
}
p.setTSXFrontmatterRange(loc.TSXRange{
Start: frontmatterStart,
End: getUTF16Length(string(p.output)),
End: len(p.output),
})
return
}
Expand Down Expand Up @@ -576,10 +588,10 @@ declare const Astro: Readonly<import('astro').AstroGlobal<%s, typeof %s`, propsI
}

if _, ok := htmlEvents[a.Key]; ok {
p.addTSXScript(getUTF16Length(p.sourcetext[:a.ValLoc.Start]), getUTF16Length(p.sourcetext[:endLoc]), a.Val, "event-attribute")
p.addTSXScript(p.builder.OffsetAt(a.ValLoc), p.builder.OffsetAt(loc.Loc{Start: endLoc}), a.Val, "event-attribute")
}
if a.Key == "style" {
p.addTSXStyle(getUTF16Length(p.sourcetext[:a.ValLoc.Start]), getUTF16Length(p.sourcetext[:endLoc]), a.Val, "style-attribute", "css")
p.addTSXStyle(p.builder.OffsetAt(a.ValLoc), p.builder.OffsetAt(loc.Loc{Start: endLoc}), a.Val, "style-attribute", "css")
}
case astro.EmptyAttribute:
p.print(a.Key)
Expand Down Expand Up @@ -742,7 +754,7 @@ declare const Astro: Readonly<import('astro').AstroGlobal<%s, typeof %s`, propsI
}
p.print(">")

contentToStartTagEnd := p.sourcetext[:endLoc]
startTagEndLoc := loc.Loc{Start: endLoc}

// Render any child nodes
for c := n.FirstChild; c != nil; c = c.NextSibling {
Expand All @@ -763,16 +775,15 @@ declare const Astro: Readonly<import('astro').AstroGlobal<%s, typeof %s`, propsI
}

if n.FirstChild != nil && (n.DataAtom == atom.Script || n.DataAtom == atom.Style) {
maxLength := endLoc
tagContentEndLoc := loc.Loc{Start: endLoc}
if endLoc > len(p.sourcetext) { // Sometimes, when tags are not closed properly, endLoc can be greater than the length of the source text, wonky stuff
maxLength = len(p.sourcetext)
tagContentEndLoc.Start = len(p.sourcetext)
}
contentToContentEnd := p.sourcetext[:maxLength]
if n.DataAtom == atom.Script {
p.addTSXScript(getUTF16Length(contentToStartTagEnd), getUTF16Length(contentToContentEnd), n.FirstChild.Data, getScriptTypeFromAttrs(n.Attr))
p.addTSXScript(p.builder.OffsetAt(startTagEndLoc), p.builder.OffsetAt(tagContentEndLoc), n.FirstChild.Data, getScriptTypeFromAttrs(n.Attr))
}
if n.DataAtom == atom.Style {
p.addTSXStyle(getUTF16Length(contentToStartTagEnd), getUTF16Length(contentToContentEnd), n.FirstChild.Data, "tag", getStyleLangFromAttrs(n.Attr))
p.addTSXStyle(p.builder.OffsetAt(startTagEndLoc), p.builder.OffsetAt(tagContentEndLoc), n.FirstChild.Data, "tag", getStyleLangFromAttrs(n.Attr))
}
}

Expand Down
Loading

0 comments on commit f7adf78

Please sign in to comment.