diff --git a/.changeset/fast-lemons-pay.md b/.changeset/fast-lemons-pay.md new file mode 100644 index 000000000..47988855a --- /dev/null +++ b/.changeset/fast-lemons-pay.md @@ -0,0 +1,5 @@ +--- +"@astrojs/compiler": patch +--- + +Improves detection of function body opening curly brace for exported functions. diff --git a/internal/js_scanner/js_scanner.go b/internal/js_scanner/js_scanner.go index 17fa15e24..731413d99 100644 --- a/internal/js_scanner/js_scanner.go +++ b/internal/js_scanner/js_scanner.go @@ -80,8 +80,10 @@ outer: // a specifier is found, and a line terminator has been found if token == js.ExportToken { flags := make(map[string]bool) + tokensFound := make(map[string]bool) foundIdent := false foundSemicolonOrLineTerminator := false + foundBody := false start := i i += len(value) for { @@ -94,6 +96,7 @@ outer: } i += len(nextValue) flags[string(nextValue)] = true + tokensFound[string(nextValue)] = true if next == js.ErrorToken && l.Err() == io.EOF { foundSemicolonOrLineTerminator = true @@ -113,7 +116,7 @@ outer: if next == js.LineTerminatorToken && i < len(source) && (source[i] == '&' || source[i] == '|') { continue } - if (flags["function"] || flags["=>"] || flags["interface"]) && !flags["{"] { + if (flags["function"] || flags["=>"] || flags["interface"]) && !foundBody { continue } if flags["&"] || flags["="] { @@ -125,6 +128,17 @@ outer: foundSemicolonOrLineTerminator = true } else if js.IsPunctuator(next) { + if nextValue[0] == '{' { + if flags["function"] { + // Curly braces can occur in a function parameter destructuring, which we don't want to consider + foundBody = foundBody || pairs['('] == 0 + } else if flags["=>"] { + // Arrow can also occur in type definition before arrow function body (which we don't want to consider), but `=` cannot + foundBody = foundBody || tokensFound["="] + } else { + foundBody = true + } + } if nextValue[0] == '{' || nextValue[0] == '(' || nextValue[0] == '[' { flags[string(nextValue[0])] = true pairs[nextValue[0]]++ diff --git a/internal/js_scanner/js_scanner_test.go b/internal/js_scanner/js_scanner_test.go index c54edc879..cfdfc59f4 100644 --- a/internal/js_scanner/js_scanner_test.go +++ b/internal/js_scanner/js_scanner_test.go @@ -260,6 +260,116 @@ export async function getStaticPaths() { const b = await fetch()`, want: `export async function getStaticPaths() { const content = Astro.fetchContent('**/*.md'); +}`, + }, + { + name: "getStaticPaths with curly brace on next line and destructured props", + source: `import { fn } from "package"; +export async function getStaticPaths({ paginate }) +{ + const content = Astro.fetchContent('**/*.md'); +} +const b = await fetch()`, + want: `export async function getStaticPaths({ paginate }) +{ + const content = Astro.fetchContent('**/*.md'); +}`, + }, + { + name: "getStaticPaths with curly brace on next line and param definition type in curly braces", + source: `import { fn } from "package"; +export async function getStaticPaths(input: { paginate: any }) +{ + const content = Astro.fetchContent('**/*.md'); +} +const b = await fetch()`, + want: `export async function getStaticPaths(input: { paginate: any }) +{ + const content = Astro.fetchContent('**/*.md'); +}`, + }, + { + name: "getStaticPaths with curly brace on next line and param definition type in square braces", + source: `import { fn } from "package"; +export async function getStaticPaths([{ stuff }]) +{ + const content = Astro.fetchContent('**/*.md'); +} +const b = await fetch()`, + want: `export async function getStaticPaths([{ stuff }]) +{ + const content = Astro.fetchContent('**/*.md'); +}`, + }, + { + name: "getStaticPaths with curly brace on next line and type specified with square braces 1", + source: `import { fn } from "package"; +export const getStaticPaths: () => { params: any }[] += () => +{ + const content = Astro.fetchContent('**/*.md'); +} +const b = await fetch()`, + want: `export const getStaticPaths: () => { params: any }[] += () => +{ + const content = Astro.fetchContent('**/*.md'); +}`, + }, + { + name: "getStaticPaths with curly brace on next line and type specified with square braces 2", + source: `import { fn } from "package"; +export const getStaticPaths: () => { params: any }[] = +() => +{ + const content = Astro.fetchContent('**/*.md'); +} +const b = await fetch()`, + want: `export const getStaticPaths: () => { params: any }[] = +() => +{ + const content = Astro.fetchContent('**/*.md'); +}`, + }, + { + name: "getStaticPaths with curly brace on next line and type specified with square braces 3", + source: `import { fn } from "package"; +export const getStaticPaths: () => { params: any }[] = () +=> +{ + const content = Astro.fetchContent('**/*.md'); +} +const b = await fetch()`, + want: `export const getStaticPaths: () => { params: any }[] = () +=> +{ + const content = Astro.fetchContent('**/*.md'); +}`, + }, + { + name: "getStaticPaths with curly brace on next line and type specified with square braces 4", + source: `import { fn } from "package"; +export const getStaticPaths: () => { params: any }[] = () => +{ + const content = Astro.fetchContent('**/*.md'); +} +const b = await fetch()`, + want: `export const getStaticPaths: () => { params: any }[] = () => +{ + const content = Astro.fetchContent('**/*.md'); +}`, + }, + { + name: "getStaticPaths with curly brace on next line and definition specified by anonymous function with destructured parameter", + source: `import { fn } from "package"; +export const getStaticPaths = function({ paginate }) +{ + const content = Astro.fetchContent('**/*.md'); +} +const b = await fetch()`, + want: `export const getStaticPaths = function({ paginate }) +{ + const content = Astro.fetchContent('**/*.md'); }`, }, { diff --git a/packages/compiler/test/basic/get-static-paths.ts b/packages/compiler/test/basic/get-static-paths.ts index 71109e290..8bdd23302 100644 --- a/packages/compiler/test/basic/get-static-paths.ts +++ b/packages/compiler/test/basic/get-static-paths.ts @@ -25,6 +25,29 @@ export async function getStaticPaths() ); }); +test('getStaticPaths with braces on newline and destructured params', async () => { + const FIXTURE = `--- +import A from './A.astro'; +export async function getStaticPaths({ paginate }) +{ + return [ + { params: { id: '1' } }, + { params: { id: '2' } }, + { params: { id: '3' } } + ]; +} +--- + +
+`; + const result = await transform(FIXTURE); + assert.match( + result.code, + 'export async function getStaticPaths({ paginate })\n{', + 'Expected output to contain getStaticPaths output' + ); +}); + test('getStaticPaths as const without braces', async () => { const FIXTURE = `--- import A from './A.astro';