@@ -853,35 +853,49 @@ function isInsideStylingConstant(node: TSESTree.Node): boolean {
853853// Syntax Context Checks (non-user-facing locations)
854854// ============================================================================
855855
856- /** Known JavaScript/ React directive prologues */
857- const DIRECTIVE_PROLOGUES = new Set ( [ "use strict" , "use client" , "use server" ] )
856+ /** React directive strings */
857+ const REACT_DIRECTIVES = new Set ( [ "use client" , "use server" ] )
858858
859859/**
860- * Checks if a string literal is a JavaScript directive prologue .
860+ * Checks if a string literal is a React directive.
861861 *
862- * Directive prologues are special string literals at the start of a script/module:
863- * - "use strict" - JavaScript strict mode
864- * - "use client" - React Server Components client boundary
865- * - "use server" - React Server Components server actions
862+ * React directives are special string literals:
863+ * - "use client" - marks a client component boundary (file level)
864+ * - "use server" - marks server actions (file level or inside async functions)
866865 */
867- function isDirectivePrologue ( node : TSESTree . Node ) : boolean {
866+ function isReactDirective ( node : TSESTree . Node ) : boolean {
868867 if ( node . type !== AST_NODE_TYPES . Literal || typeof node . value !== "string" ) {
869868 return false
870869 }
871870
872- // Check if this is a known directive
873- if ( ! DIRECTIVE_PROLOGUES . has ( node . value ) ) {
871+ if ( ! REACT_DIRECTIVES . has ( node . value ) ) {
874872 return false
875873 }
876874
877- // Directive prologues must be expression statements at the program level
875+ // Must be wrapped in an expression statement
878876 const parent = node . parent
879877 if ( parent . type !== AST_NODE_TYPES . ExpressionStatement ) {
880878 return false
881879 }
882880
883881 const grandparent = parent . parent
884- return grandparent . type === AST_NODE_TYPES . Program
882+
883+ // File-level directive
884+ if ( grandparent . type === AST_NODE_TYPES . Program ) {
885+ return true
886+ }
887+
888+ // Function-level directive (e.g., "use server" inside async function)
889+ if ( grandparent . type === AST_NODE_TYPES . BlockStatement ) {
890+ const functionParent = grandparent . parent
891+ return (
892+ functionParent . type === AST_NODE_TYPES . FunctionDeclaration ||
893+ functionParent . type === AST_NODE_TYPES . FunctionExpression ||
894+ functionParent . type === AST_NODE_TYPES . ArrowFunctionExpression
895+ )
896+ }
897+
898+ return false
885899}
886900
887901/**
@@ -1387,8 +1401,8 @@ export const noUnlocalizedStrings = createRule<[Options], MessageId>({
13871401 return
13881402 }
13891403
1390- // JavaScript/ React directive prologues: "use strict", "use client", "use server"
1391- if ( isDirectivePrologue ( node ) ) {
1404+ // React directives: "use client", "use server"
1405+ if ( isReactDirective ( node ) ) {
13921406 return
13931407 }
13941408
0 commit comments