Skip to content

Commit

Permalink
fix(tsx): Transform top level returns into throws (#1028)
Browse files Browse the repository at this point in the history
* fix(tsx): Transform top level returns into throws

* fix: logic

* nit: use return elngth

* Create bright-plums-suffer.md
  • Loading branch information
Princesseuh authored Jul 22, 2024
1 parent 2e95e17 commit 7fa6577
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/bright-plums-suffer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@astrojs/compiler": patch
---

Transform top level returns into throws in the TSX output
54 changes: 54 additions & 0 deletions internal/js_scanner/js_scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,60 @@ import (
"github.com/withastro/compiler/internal/loc"
)

func FindTopLevelReturns(source []byte) []int {
l := js.NewLexer(parse.NewInputBytes(source))
i := 0
returns := make([]int, 0)
pairs := make(map[byte]int)
inFunction := false

for {
token, value := l.Next()

if token == js.DivToken || token == js.DivEqToken {
lns := bytes.Split(source[i+1:], []byte{'\n'})
if bytes.Contains(lns[0], []byte{'/'}) {
token, value = l.RegExp()
}
}

if token == js.ErrorToken {
if l.Err() != io.EOF {
return returns
}
break
}

if js.IsPunctuator(token) {
if value[0] == '{' {
pairs[value[0]]++
i += len(value)
continue
} else if value[0] == '}' {
pairs['{']--
}
}

// Track function declarations
if token == js.FunctionToken {
inFunction = true
}

// Track end of function declarations
if inFunction && token == js.CloseBraceToken && pairs['{'] == 1 {
inFunction = false
}

if token == js.ReturnToken && !inFunction {
returns = append(returns, i)
}

i += len(value)
}

return returns
}

type HoistedScripts struct {
Hoisted [][]byte
HoistedLocs []loc.Loc
Expand Down
23 changes: 22 additions & 1 deletion internal/printer/print-to-tsx.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package printer

import (
"fmt"
"slices"
"strings"
"unicode"

Expand Down Expand Up @@ -366,11 +367,31 @@ declare const Astro: Readonly<import('astro').AstroGlobal<%s, typeof %s`, propsI
p.addSourceMapping(loc.Loc{Start: 0})
frontmatterStart := len(p.output)
for c := n.FirstChild; c != nil; c = c.NextSibling {
topLevelReturn := js_scanner.FindTopLevelReturns([]byte(c.Data))
if c.Type == TextNode {
if len(c.Loc) > 0 {
p.addSourceMapping(c.Loc[0])
}
p.printTextWithSourcemap(c.Data, c.Loc[0])
// Remplace all the top level returns with a `throw`
if len(topLevelReturn) > 0 {
// Loop over the characters and replace the top level returns with a `throw`
newString := []byte{}

i := 0
for i < len(c.Data) {
if slices.Contains(topLevelReturn, i) {
newString = append(newString, []byte("throw ")...)
i += len("return")
} else {
newString = append(newString, c.Data[i])
i++
}
}

p.printTextWithSourcemap(string(newString), c.Loc[0])
} else {
p.printTextWithSourcemap(c.Data, c.Loc[0])
}
} else {
renderTsx(p, c, o)
}
Expand Down
44 changes: 44 additions & 0 deletions packages/compiler/test/tsx/top-level-returns.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { convertToTSX } from '@astrojs/compiler';
import { test } from 'uvu';
import * as assert from 'uvu/assert';
import { TSXPrefix } from '../utils.js';

test('transforms top-level returns to throw statements', async () => {
const input = `---
if (something) {
return Astro.redirect();
}
function thatDoesSomething() {
return "Hey";
}
class Component {
render() {
return "wow"!
}
}
---`;
const output = `${TSXPrefix}
if (something) {
throw Astro.redirect();
}
function thatDoesSomething() {
return "Hey";
}
class Component {
render() {
return "wow"!
}
}
export default function __AstroComponent_(_props: Record<string, any>): any {}
`;
const { code } = await convertToTSX(input, { sourcemap: 'external' });
assert.snapshot(code, output, 'expected code to match snapshot');
});

test.run();

0 comments on commit 7fa6577

Please sign in to comment.