@@ -13,6 +13,7 @@ import {
1313 ErrorSeverity ,
1414} from '../CompilerError' ;
1515import {
16+ EnvironmentConfig ,
1617 ExternalFunction ,
1718 ReactFunctionType ,
1819 parseEnvironmentConfig ,
@@ -276,41 +277,27 @@ export function compileProgram(
276277 program : NodePath < t . Program > ,
277278 pass : CompilerPass ,
278279) : void {
279- if ( pass . opts . sources ) {
280- if ( pass . filename === null ) {
281- const error = new CompilerError ( ) ;
282- error . pushErrorDetail (
283- new CompilerErrorDetail ( {
284- reason : `Expected a filename but found none.` ,
285- description :
286- "When the 'sources' config options is specified, the React compiler will only compile files with a name" ,
287- severity : ErrorSeverity . InvalidConfig ,
288- loc : null ,
289- } ) ,
290- ) ;
291- handleError ( error , pass , null ) ;
292- return ;
293- }
294-
295- if ( ! isFilePartOfSources ( pass . opts . sources , pass . filename ) ) {
296- return ;
297- }
298- }
299-
300- // Top level "use no forget", skip this file entirely
301- if (
302- findDirectiveDisablingMemoization ( program . node . directives , pass . opts ) !=
303- null
304- ) {
280+ if ( shouldSkipCompilation ( program , pass ) ) {
305281 return ;
306282 }
307283
308- const environment = parseEnvironmentConfig ( pass . opts . environment ?? { } ) ;
284+ /*
285+ * TODO(lauren): Remove pass.opts.environment nullcheck once PluginOptions
286+ * is validated
287+ */
288+ const environmentResult = parseEnvironmentConfig ( pass . opts . environment ?? { } ) ;
289+ if ( environmentResult . isErr ( ) ) {
290+ CompilerError . throwInvalidConfig ( {
291+ reason :
292+ 'Error in validating environment config. This is an advanced setting and not meant to be used directly' ,
293+ description : environmentResult . unwrapErr ( ) . toString ( ) ,
294+ suggestions : null ,
295+ loc : null ,
296+ } ) ;
297+ }
298+ const environment = environmentResult . unwrap ( ) ;
309299 const useMemoCacheIdentifier = program . scope . generateUidIdentifier ( 'c' ) ;
310300 const moduleName = pass . opts . runtimeModule ?? 'react/compiler-runtime' ;
311- if ( hasMemoCacheFunctionImport ( program , moduleName ) ) {
312- return ;
313- }
314301
315302 /*
316303 * Record lint errors and critical errors as depending on Forget's config,
@@ -332,7 +319,7 @@ export function compileProgram(
332319 const compiledFns : Array < CompileResult > = [ ] ;
333320
334321 const traverseFunction = ( fn : BabelFn , pass : CompilerPass ) : void => {
335- const fnType = getReactFunctionType ( fn , pass ) ;
322+ const fnType = getReactFunctionType ( fn , pass , environment ) ;
336323 if ( fnType === null || ALREADY_COMPILED . has ( fn . node ) ) {
337324 return ;
338325 }
@@ -403,24 +390,9 @@ export function compileProgram(
403390
404391 let compiledFn : CodegenFunction ;
405392 try {
406- /*
407- * TODO(lauren): Remove pass.opts.environment nullcheck once PluginOptions
408- * is validated
409- */
410- if ( environment . isErr ( ) ) {
411- CompilerError . throwInvalidConfig ( {
412- reason :
413- 'Error in validating environment config. This is an advanced setting and not meant to be used directly' ,
414- description : environment . unwrapErr ( ) . toString ( ) ,
415- suggestions : null ,
416- loc : null ,
417- } ) ;
418- }
419- const config = environment . unwrap ( ) ;
420-
421393 compiledFn = compileFn (
422394 fn ,
423- config ,
395+ environment ,
424396 fnType ,
425397 useMemoCacheIdentifier . name ,
426398 pass . opts . logger ,
@@ -514,43 +486,29 @@ export function compileProgram(
514486 externalFunctions . push ( gating ) ;
515487 }
516488
517- const lowerContextAccess = pass . opts . environment ? .lowerContextAccess ;
489+ const lowerContextAccess = environment . lowerContextAccess ;
518490 if ( lowerContextAccess && hasLoweredContextAccess ) {
519- externalFunctions . push ( tryParseExternalFunction ( lowerContextAccess ) ) ;
491+ externalFunctions . push ( lowerContextAccess ) ;
520492 }
521493
522- const enableEmitInstrumentForget =
523- pass . opts . environment ?. enableEmitInstrumentForget ;
494+ const enableEmitInstrumentForget = environment . enableEmitInstrumentForget ;
524495 if ( enableEmitInstrumentForget != null ) {
525- externalFunctions . push (
526- tryParseExternalFunction ( enableEmitInstrumentForget . fn ) ,
527- ) ;
496+ externalFunctions . push ( enableEmitInstrumentForget . fn ) ;
528497 if ( enableEmitInstrumentForget . gating != null ) {
529- externalFunctions . push (
530- tryParseExternalFunction ( enableEmitInstrumentForget . gating ) ,
531- ) ;
498+ externalFunctions . push ( enableEmitInstrumentForget . gating ) ;
532499 }
533500 }
534501
535- if ( pass . opts . environment ?. enableEmitFreeze != null ) {
536- const enableEmitFreeze = tryParseExternalFunction (
537- pass . opts . environment . enableEmitFreeze ,
538- ) ;
539- externalFunctions . push ( enableEmitFreeze ) ;
502+ if ( environment . enableEmitFreeze != null ) {
503+ externalFunctions . push ( environment . enableEmitFreeze ) ;
540504 }
541505
542- if ( pass . opts . environment ?. enableEmitHookGuards != null ) {
543- const enableEmitHookGuards = tryParseExternalFunction (
544- pass . opts . environment . enableEmitHookGuards ,
545- ) ;
546- externalFunctions . push ( enableEmitHookGuards ) ;
506+ if ( environment . enableEmitHookGuards != null ) {
507+ externalFunctions . push ( environment . enableEmitHookGuards ) ;
547508 }
548509
549- if ( pass . opts . environment ?. enableChangeDetectionForDebugging != null ) {
550- const enableChangeDetectionForDebugging = tryParseExternalFunction (
551- pass . opts . environment . enableChangeDetectionForDebugging ,
552- ) ;
553- externalFunctions . push ( enableChangeDetectionForDebugging ) ;
510+ if ( environment . enableChangeDetectionForDebugging != null ) {
511+ externalFunctions . push ( environment . enableChangeDetectionForDebugging ) ;
554512 }
555513 } catch ( err ) {
556514 handleError ( err , pass , null ) ;
@@ -593,11 +551,65 @@ export function compileProgram(
593551 }
594552}
595553
554+ function shouldSkipCompilation (
555+ program : NodePath < t . Program > ,
556+ pass : CompilerPass ,
557+ ) : boolean {
558+ if ( pass . opts . sources ) {
559+ if ( pass . filename === null ) {
560+ const error = new CompilerError ( ) ;
561+ error . pushErrorDetail (
562+ new CompilerErrorDetail ( {
563+ reason : `Expected a filename but found none.` ,
564+ description :
565+ "When the 'sources' config options is specified, the React compiler will only compile files with a name" ,
566+ severity : ErrorSeverity . InvalidConfig ,
567+ loc : null ,
568+ } ) ,
569+ ) ;
570+ handleError ( error , pass , null ) ;
571+ return true ;
572+ }
573+
574+ if ( ! isFilePartOfSources ( pass . opts . sources , pass . filename ) ) {
575+ return true ;
576+ }
577+ }
578+
579+ // Top level "use no forget", skip this file entirely
580+ const useNoForget = findDirectiveDisablingMemoization (
581+ program . node . directives ,
582+ pass . opts ,
583+ ) ;
584+ if ( useNoForget != null ) {
585+ pass . opts . logger ?. logEvent ( pass . filename , {
586+ kind : 'CompileError' ,
587+ fnLoc : null ,
588+ detail : {
589+ severity : ErrorSeverity . Todo ,
590+ reason : 'Skipped due to "use no forget" directive.' ,
591+ loc : useNoForget . loc ?? null ,
592+ suggestions : null ,
593+ } ,
594+ } ) ;
595+ return true ;
596+ }
597+ const moduleName = pass . opts . runtimeModule ?? 'react/compiler-runtime' ;
598+ if ( hasMemoCacheFunctionImport ( program , moduleName ) ) {
599+ return true ;
600+ }
601+ return false ;
602+ }
603+
596604function getReactFunctionType (
597605 fn : BabelFn ,
598606 pass : CompilerPass ,
607+ /**
608+ * TODO(mofeiZ): remove once we validate PluginOptions with Zod
609+ */
610+ environment : EnvironmentConfig ,
599611) : ReactFunctionType | null {
600- const hookPattern = pass . opts . environment ? .hookPattern ?? null ;
612+ const hookPattern = environment . hookPattern ;
601613 if ( fn . node . body . type === 'BlockStatement' ) {
602614 // Opt-outs disable compilation regardless of mode
603615 const useNoForget = findDirectiveDisablingMemoization (
0 commit comments