Some minor divergence is discovered while digging in #1336. This is independent transform feature alignment, so the issue is tracked separately here.
3. Directive-Prologue Recognition
Remaining primitive
Recognize module and function directives only when they occur in the corresponding module or function-body directive prologue.
The current module-level hasDirective uses an unrestricted body search at packages/plugin-rsc/src/transforms/utils.ts:5, while inline matchDirective scans all string expression statements in a function block at packages/plugin-rsc/src/transforms/hoist.ts:280. Neither stops after the first non-directive statement, so both can transform an inert string expression that is not a JavaScript directive:
async function value() {
initialize()
'use cache' // not a directive
return read()
}
import './initialize.js'
'use server' // not a directive
The function scan should stop at initialize(), and the module scan should stop at the import. Both misplaced strings must remain untransformed.
Next.js usage and rationale
Next.js parses module and function directives through dedicated directive visitors rather than matching arbitrary string expressions. Its Server Actions DirectiveVisitor is implemented at server_actions.rs:3418.
Error fixture 8 explicitly places "use server" after const x = 1 in a function. Its output leaves the function untransformed, and its diagnostic states that the directive must be at the top of the function body. Error fixture 9 covers the corresponding module-level case after an import. Error fixture 19 is the closest "use cache" case, although it also wraps the misplaced string in parentheses.
This is not mainly diagnostic alignment. A false positive changes an ordinary function into a hoisted, wrapped, and potentially transported callable even though the source did not declare that role. Correct prologue recognition therefore protects the transform selection boundary itself.
Independent boundary
This can be tested with small positive and negative transform fixtures. The minimum generic contract is that a misplaced string does not trigger transformation. Matching Next.js's compile-time diagnostic can remain a separate validation choice. This work does not require hoist-safety diagnostics, method syntax support, generated identity changes, or runtime E2E.
"use cache"Server Functions #1336Some minor divergence is discovered while digging in #1336. This is independent transform feature alignment, so the issue is tracked separately here.
3. Directive-Prologue Recognition
Remaining primitive
Recognize module and function directives only when they occur in the corresponding module or function-body directive prologue.
The current module-level
hasDirectiveuses an unrestricted body search at packages/plugin-rsc/src/transforms/utils.ts:5, while inlinematchDirectivescans all string expression statements in a function block at packages/plugin-rsc/src/transforms/hoist.ts:280. Neither stops after the first non-directive statement, so both can transform an inert string expression that is not a JavaScript directive:The function scan should stop at
initialize(), and the module scan should stop at the import. Both misplaced strings must remain untransformed.Next.js usage and rationale
Next.js parses module and function directives through dedicated directive visitors rather than matching arbitrary string expressions. Its Server Actions
DirectiveVisitoris implemented at server_actions.rs:3418.Error fixture 8 explicitly places
"use server"afterconst x = 1in a function. Its output leaves the function untransformed, and its diagnostic states that the directive must be at the top of the function body. Error fixture 9 covers the corresponding module-level case after an import. Error fixture 19 is the closest"use cache"case, although it also wraps the misplaced string in parentheses.This is not mainly diagnostic alignment. A false positive changes an ordinary function into a hoisted, wrapped, and potentially transported callable even though the source did not declare that role. Correct prologue recognition therefore protects the transform selection boundary itself.
Independent boundary
This can be tested with small positive and negative transform fixtures. The minimum generic contract is that a misplaced string does not trigger transformation. Matching Next.js's compile-time diagnostic can remain a separate validation choice. This work does not require hoist-safety diagnostics, method syntax support, generated identity changes, or runtime E2E.