From 949725318ef5cb47ff827b2e2896daa95a9529fb Mon Sep 17 00:00:00 2001 From: SeanCassiere <33615041+SeanCassiere@users.noreply.github.com> Date: Sun, 4 May 2025 03:56:56 +1200 Subject: [PATCH 1/5] fix(directive-functions-plugin): do not outlaw the generator functions --- packages/directive-functions-plugin/src/compilers.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/directive-functions-plugin/src/compilers.ts b/packages/directive-functions-plugin/src/compilers.ts index da0fe941bce..463f5e879e8 100644 --- a/packages/directive-functions-plugin/src/compilers.ts +++ b/packages/directive-functions-plugin/src/compilers.ts @@ -288,24 +288,19 @@ export function findDirectives( babel.traverse(ast, { DirectiveLiteral(nodePath) { if (nodePath.node.value === opts.directive) { - const directiveFn = nodePath.findParent((p) => p.isFunction()) as - | SupportedFunctionPath - | undefined + const directiveFn = nodePath.findParent((p) => p.isFunction()) if (!directiveFn) return // Handle class and object methods which are not supported - const isGenerator = - directiveFn.isFunction() && directiveFn.node.generator - const isClassMethod = directiveFn.isClassMethod() const isObjectMethod = directiveFn.isObjectMethod() - if (isClassMethod || isObjectMethod || isGenerator) { + if (isClassMethod || isObjectMethod) { throw codeFrameError( opts.code, directiveFn.node.loc, - `"${opts.directive}" in ${isClassMethod ? 'class' : isObjectMethod ? 'object method' : 'generator function'} not supported`, + `"${opts.directive}" in ${isClassMethod ? 'class' : isObjectMethod ? 'object method' : ''} not supported`, ) } From 02930fe904ef55dea67e3c44673d2ff9cba61f70 Mon Sep 17 00:00:00 2001 From: SeanCassiere <33615041+SeanCassiere@users.noreply.github.com> Date: Sun, 4 May 2025 03:57:38 +1200 Subject: [PATCH 2/5] test(directive-functions-plugin): test for generators --- .../tests/compiler.test.ts | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/packages/directive-functions-plugin/tests/compiler.test.ts b/packages/directive-functions-plugin/tests/compiler.test.ts index a7ff05be977..20049e0ff2b 100644 --- a/packages/directive-functions-plugin/tests/compiler.test.ts +++ b/packages/directive-functions-plugin/tests/compiler.test.ts @@ -787,4 +787,79 @@ describe('server function compilation', () => { export { bytesSignupServerFn_1 };" `) }) + + test('generator function', () => { + const code = ` + function* generator() { + 'use server' + yield 'hello' + } + ` + const client = compileDirectives({ + ...clientConfig, + code, + }) + const ssr = compileDirectives({ ...ssrConfig, code }) + + const server = compileDirectives({ + ...serverConfig, + code, + filename: `${ssr.directiveFnsById[Object.keys(ssr.directiveFnsById)[0]!]!.extractedFilename}`, + }) + + expect(client.compiledResult.code).toMatchInlineSnapshot(` + "import { createClientRpc } from "my-rpc-lib-client"; + const generator_1 = createClientRpc("test_ts--generator_1"); + const generator = generator_1;"`) + + expect(ssr.compiledResult.code).toMatchInlineSnapshot(` + "import { createSsrRpc } from "my-rpc-lib-server"; + const generator_1 = createSsrRpc("test_ts--generator_1"); + const generator = generator_1;"`) + + expect(server.compiledResult.code).toMatchInlineSnapshot(` + "import { createServerRpc } from "my-rpc-lib-server"; + const generator_1 = createServerRpc("test_ts--generator_1", function* () { + yield 'hello'; + }); + const generator = generator_1; + export { generator_1 };"`) + }) + test('async generator function', () => { + const code = ` + async function* asyncGenerator() { + 'use server' + yield 'hello' + } + ` + const client = compileDirectives({ + ...clientConfig, + code, + }) + const ssr = compileDirectives({ ...ssrConfig, code }) + + const server = compileDirectives({ + ...serverConfig, + code, + filename: `${ssr.directiveFnsById[Object.keys(ssr.directiveFnsById)[0]!]!.extractedFilename}`, + }) + + expect(client.compiledResult.code).toMatchInlineSnapshot(` + "import { createClientRpc } from "my-rpc-lib-client"; + const asyncGenerator_1 = createClientRpc("test_ts--asyncGenerator_1"); + const asyncGenerator = asyncGenerator_1;"`) + + expect(ssr.compiledResult.code).toMatchInlineSnapshot(` + "import { createSsrRpc } from "my-rpc-lib-server"; + const asyncGenerator_1 = createSsrRpc("test_ts--asyncGenerator_1"); + const asyncGenerator = asyncGenerator_1;"`) + + expect(server.compiledResult.code).toMatchInlineSnapshot(` + "import { createServerRpc } from "my-rpc-lib-server"; + const asyncGenerator_1 = createServerRpc("test_ts--asyncGenerator_1", async function* () { + yield 'hello'; + }); + const asyncGenerator = asyncGenerator_1; + export { asyncGenerator_1 };"`) + }) }) From 4a20d4921ec0fe96d94848acb9fe015b38cb0d71 Mon Sep 17 00:00:00 2001 From: SeanCassiere <33615041+SeanCassiere@users.noreply.github.com> Date: Sun, 4 May 2025 03:59:27 +1200 Subject: [PATCH 3/5] test(directive-functions-plugin): remove test blocking generators --- .../tests/compiler.test.ts | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/packages/directive-functions-plugin/tests/compiler.test.ts b/packages/directive-functions-plugin/tests/compiler.test.ts index 20049e0ff2b..3247ec6ac73 100644 --- a/packages/directive-functions-plugin/tests/compiler.test.ts +++ b/packages/directive-functions-plugin/tests/compiler.test.ts @@ -292,30 +292,6 @@ describe('server function compilation', () => { ).toThrow() }) - test('does not support generator functions', () => { - const code = ` - function* generatorServer() { - 'use server' - yield 'hello' - } - - async function* asyncGeneratorServer() { - 'use server' - yield 'hello' - } - ` - - expect(() => compileDirectives({ ...clientConfig, code })).toThrow() - expect(() => compileDirectives({ ...serverConfig, code })).toThrow() - expect(() => - compileDirectives({ - ...serverConfig, - code, - filename: serverConfig.filename + `?tsr-serverfn-split=temp`, - }), - ).toThrow() - }) - test('multiple directiveFnsById', () => { const code = ` function multiDirective() { From 8b7e5f5e895391a1b2156cd888a87b0efb3c0d60 Mon Sep 17 00:00:00 2001 From: SeanCassiere <33615041+SeanCassiere@users.noreply.github.com> Date: Sun, 4 May 2025 03:59:59 +1200 Subject: [PATCH 4/5] test(directive-functions-plugin): move to lower lexical scope --- .../tests/compiler.test.ts | 135 +++++++++--------- 1 file changed, 67 insertions(+), 68 deletions(-) diff --git a/packages/directive-functions-plugin/tests/compiler.test.ts b/packages/directive-functions-plugin/tests/compiler.test.ts index 3247ec6ac73..c4e7832912f 100644 --- a/packages/directive-functions-plugin/tests/compiler.test.ts +++ b/packages/directive-functions-plugin/tests/compiler.test.ts @@ -38,75 +38,74 @@ const serverConfig: Omit = { } describe('server function compilation', () => { - const code = ` - export const namedFunction = createServerFn(function namedFunction() { - 'use server' - return 'hello' - }) - - export const arrowFunction = createServerFn(() => { - 'use server' - return 'hello' - }) - - export const anonymousFunction = createServerFn(function () { - 'use server' - return 'hello' - }) - - export const multipleDirectives = function multipleDirectives() { - 'use server' - 'use strict' - return 'hello' - } - - export const iife = (function () { - 'use server' - return 'hello' - })() - - export default function defaultExportFn() { - 'use server' - return 'hello' - } - - export function namedExportFn() { - 'use server' - return 'hello' - } - - export const exportedArrowFunction = wrapper(() => { - 'use server' - return 'hello' - }) - - export const namedExportConst = () => { - 'use server' - return usedFn() - } - - function usedFn() { - return 'hello' - } - - function unusedFn() { - return 'hello' - } - - const namedDefaultExport = 'namedDefaultExport' - export default namedDefaultExport - - const usedButNotExported = 'usedButNotExported' - - const namedExport = 'namedExport' - - export { - namedExport - } - - ` - test('basic function declaration nested in other variable', () => { + const code = ` + export const namedFunction = createServerFn(function namedFunction() { + 'use server' + return 'hello' + }) + + export const arrowFunction = createServerFn(() => { + 'use server' + return 'hello' + }) + + export const anonymousFunction = createServerFn(function () { + 'use server' + return 'hello' + }) + + export const multipleDirectives = function multipleDirectives() { + 'use server' + 'use strict' + return 'hello' + } + + export const iife = (function () { + 'use server' + return 'hello' + })() + + export default function defaultExportFn() { + 'use server' + return 'hello' + } + + export function namedExportFn() { + 'use server' + return 'hello' + } + + export const exportedArrowFunction = wrapper(() => { + 'use server' + return 'hello' + }) + + export const namedExportConst = () => { + 'use server' + return usedFn() + } + + function usedFn() { + return 'hello' + } + + function unusedFn() { + return 'hello' + } + + const namedDefaultExport = 'namedDefaultExport' + export default namedDefaultExport + + const usedButNotExported = 'usedButNotExported' + + const namedExport = 'namedExport' + + export { + namedExport + } + + ` const client = compileDirectives({ ...clientConfig, code, From 3b896c74f8dabce17857e182694b1c5eb32a4a59 Mon Sep 17 00:00:00 2001 From: SeanCassiere <33615041+SeanCassiere@users.noreply.github.com> Date: Sun, 4 May 2025 04:14:52 +1200 Subject: [PATCH 5/5] test(directive-functions-plugin): add generators into `basic function declaration nested in other variable` --- .../tests/compiler.test.ts | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/directive-functions-plugin/tests/compiler.test.ts b/packages/directive-functions-plugin/tests/compiler.test.ts index c4e7832912f..50f35c5ea3c 100644 --- a/packages/directive-functions-plugin/tests/compiler.test.ts +++ b/packages/directive-functions-plugin/tests/compiler.test.ts @@ -44,6 +44,11 @@ describe('server function compilation', () => { 'use server' return 'hello' }) + + export const namedGeneratorFunction = createServerFn(function* namedGeneratorFunction () { + 'use server' + return 'hello' + }) export const arrowFunction = createServerFn(() => { 'use server' @@ -54,6 +59,11 @@ describe('server function compilation', () => { 'use server' return 'hello' }) + + export const anonymousGeneratorFunction = createServerFn(function* () { + 'use server' + return 'hello' + }) export const multipleDirectives = function multipleDirectives() { 'use server' @@ -85,6 +95,11 @@ describe('server function compilation', () => { 'use server' return usedFn() } + + export const namedExportConstGenerator = function* () { + 'use server' + return usedFn() + } function usedFn() { return 'hello' @@ -104,7 +119,6 @@ describe('server function compilation', () => { export { namedExport } - ` const client = compileDirectives({ ...clientConfig, @@ -122,10 +136,14 @@ describe('server function compilation', () => { "import { createClientRpc } from "my-rpc-lib-client"; const namedFunction_createServerFn_namedFunction = createClientRpc("test_ts--namedFunction_createServerFn_namedFunction"); export const namedFunction = createServerFn(namedFunction_createServerFn_namedFunction); + const namedGeneratorFunction_createServerFn_namedGeneratorFunction = createClientRpc("test_ts--namedGeneratorFunction_createServerFn_namedGeneratorFunction"); + export const namedGeneratorFunction = createServerFn(namedGeneratorFunction_createServerFn_namedGeneratorFunction); const arrowFunction_createServerFn = createClientRpc("test_ts--arrowFunction_createServerFn"); export const arrowFunction = createServerFn(arrowFunction_createServerFn); const anonymousFunction_createServerFn = createClientRpc("test_ts--anonymousFunction_createServerFn"); export const anonymousFunction = createServerFn(anonymousFunction_createServerFn); + const anonymousGeneratorFunction_createServerFn = createClientRpc("test_ts--anonymousGeneratorFunction_createServerFn"); + export const anonymousGeneratorFunction = createServerFn(anonymousGeneratorFunction_createServerFn); const multipleDirectives_multipleDirectives = createClientRpc("test_ts--multipleDirectives_multipleDirectives"); export const multipleDirectives = multipleDirectives_multipleDirectives; const iife_1 = createClientRpc("test_ts--iife_1"); @@ -138,6 +156,8 @@ describe('server function compilation', () => { export const exportedArrowFunction = wrapper(exportedArrowFunction_wrapper); const namedExportConst_1 = createClientRpc("test_ts--namedExportConst_1"); export const namedExportConst = namedExportConst_1; + const namedExportConstGenerator_1 = createClientRpc("test_ts--namedExportConstGenerator_1"); + export const namedExportConstGenerator = namedExportConstGenerator_1; function unusedFn() { return 'hello'; } @@ -152,10 +172,14 @@ describe('server function compilation', () => { "import { createSsrRpc } from "my-rpc-lib-server"; const namedFunction_createServerFn_namedFunction = createSsrRpc("test_ts--namedFunction_createServerFn_namedFunction"); export const namedFunction = createServerFn(namedFunction_createServerFn_namedFunction); + const namedGeneratorFunction_createServerFn_namedGeneratorFunction = createSsrRpc("test_ts--namedGeneratorFunction_createServerFn_namedGeneratorFunction"); + export const namedGeneratorFunction = createServerFn(namedGeneratorFunction_createServerFn_namedGeneratorFunction); const arrowFunction_createServerFn = createSsrRpc("test_ts--arrowFunction_createServerFn"); export const arrowFunction = createServerFn(arrowFunction_createServerFn); const anonymousFunction_createServerFn = createSsrRpc("test_ts--anonymousFunction_createServerFn"); export const anonymousFunction = createServerFn(anonymousFunction_createServerFn); + const anonymousGeneratorFunction_createServerFn = createSsrRpc("test_ts--anonymousGeneratorFunction_createServerFn"); + export const anonymousGeneratorFunction = createServerFn(anonymousGeneratorFunction_createServerFn); const multipleDirectives_multipleDirectives = createSsrRpc("test_ts--multipleDirectives_multipleDirectives"); export const multipleDirectives = multipleDirectives_multipleDirectives; const iife_1 = createSsrRpc("test_ts--iife_1"); @@ -168,6 +192,8 @@ describe('server function compilation', () => { export const exportedArrowFunction = wrapper(exportedArrowFunction_wrapper); const namedExportConst_1 = createSsrRpc("test_ts--namedExportConst_1"); export const namedExportConst = namedExportConst_1; + const namedExportConstGenerator_1 = createSsrRpc("test_ts--namedExportConstGenerator_1"); + export const namedExportConstGenerator = namedExportConstGenerator_1; function unusedFn() { return 'hello'; } @@ -184,12 +210,18 @@ describe('server function compilation', () => { const namedFunction_createServerFn_namedFunction = createServerRpc("test_ts--namedFunction_createServerFn_namedFunction", function namedFunction() { return 'hello'; }); + const namedGeneratorFunction_createServerFn_namedGeneratorFunction = createServerRpc("test_ts--namedGeneratorFunction_createServerFn_namedGeneratorFunction", function* namedGeneratorFunction() { + return 'hello'; + }); const arrowFunction_createServerFn = createServerRpc("test_ts--arrowFunction_createServerFn", () => { return 'hello'; }); const anonymousFunction_createServerFn = createServerRpc("test_ts--anonymousFunction_createServerFn", function () { return 'hello'; }); + const anonymousGeneratorFunction_createServerFn = createServerRpc("test_ts--anonymousGeneratorFunction_createServerFn", function* () { + return 'hello'; + }); const multipleDirectives_multipleDirectives = createServerRpc("test_ts--multipleDirectives_multipleDirectives", function multipleDirectives() { 'use strict'; @@ -210,6 +242,9 @@ describe('server function compilation', () => { const namedExportConst_1 = createServerRpc("test_ts--namedExportConst_1", () => { return usedFn(); }); + const namedExportConstGenerator_1 = createServerRpc("test_ts--namedExportConstGenerator_1", function* () { + return usedFn(); + }); function usedFn() { return 'hello'; } @@ -218,7 +253,7 @@ describe('server function compilation', () => { } const usedButNotExported = 'usedButNotExported'; const namedExportFn = namedExportFn_1; - export { namedFunction_createServerFn_namedFunction, arrowFunction_createServerFn, anonymousFunction_createServerFn, multipleDirectives_multipleDirectives, iife_1, defaultExportFn_1, namedExportFn_1, exportedArrowFunction_wrapper, namedExportConst_1 };" + export { namedFunction_createServerFn_namedFunction, namedGeneratorFunction_createServerFn_namedGeneratorFunction, arrowFunction_createServerFn, anonymousFunction_createServerFn, anonymousGeneratorFunction_createServerFn, multipleDirectives_multipleDirectives, iife_1, defaultExportFn_1, namedExportFn_1, exportedArrowFunction_wrapper, namedExportConst_1, namedExportConstGenerator_1 };" `, ) })