@@ -21,7 +21,6 @@ import type {
2121 Expression as EsExpression ,
2222 Statement as EsStatement ,
2323 ExpressionStatement as EsExpressionStatement ,
24- FunctionDeclaration as EsFunctionDeclaration ,
2524 VariableDeclaration as EsVariableDeclaration ,
2625} from 'estree' ;
2726import type {
@@ -40,23 +39,16 @@ import type {
4039} from '@lwc/template-compiler' ;
4140import type { TransformerContext } from '../../types' ;
4241
43- // const slotAttributeValueAssignment =
44- // esTemplate`const slotAttributeValue = null;`<EsVariableDeclaration>();
45-
46- // Toodles: rather than hoising this function to the top of the module, maybe it should be
47- // hoisted to the top of the template function. Many things would still be in
48- // scope that way, and it might not be quite so brittle. And it would still allow
49- // to dedupe the bullshit
5042const bGenerateShadowSlottedContent = esTemplateWithYield `
51- async function* ${ /* function name */ is . identifier } (contextfulParent) {
43+ const ${ /* function name */ is . identifier } = ( ${ /* local vars */ is . identifier } ) => async function* ${ /* function name */ 0 } (contextfulParent) {
5244 // The 'contextfulParent' variable is shadowed here so that a contextful relationship
5345 // is established between components rendered in slotted content & the "parent"
5446 // component that contains the <slot>.
5547 ${ /* shadow slot content */ is . statement }
56- }
57- ` < EsFunctionDeclaration > ;
48+ };
49+ ` < EsVariableDeclaration > ;
5850const bGenerateShadowSlottedContentRef = esTemplateWithYield `
59- const shadowSlottedContent = ${ /* reference to hoisted fn */ is . identifier } ;
51+ const shadowSlottedContent = ${ /* reference to hoisted fn */ is . identifier } ( ${ /* local vars */ is . identifier } ) ;
6052` < EsVariableDeclaration > ;
6153const bNullishGenerateShadowSlottedContent = esTemplateWithYield `
6254 const shadowSlottedContent = null;
@@ -280,20 +272,30 @@ export function getSlottedContent(
280272 // uniquely identify that node.
281273 const uniqueNodeId = `${ node . name } :${ node . location . start } :${ node . location . end } ` ;
282274
275+ const localVars = cxt . getLocalVars ( ) ;
276+ const localVarIds = localVars . map ( b . identifier ) ;
277+
283278 if ( hasShadowSlottedContent && ! cxt . slots . shadow . isDuplicate ( uniqueNodeId ) ) {
284279 // Colon characters in <lwc:component> element name will result in an invalid
285280 // JavaScript identifier if not otherwise accounted for.
286281 const kebabCmpName = kebabCaseToCamelCase ( node . name ) . replace ( ':' , '_' ) ;
287282 const shadowSlotContentFnName = cxt . slots . shadow . register ( uniqueNodeId , kebabCmpName ) ;
288283 const shadowSlottedContentFn = bGenerateShadowSlottedContent (
289284 b . identifier ( shadowSlotContentFnName ) ,
285+ // If the slot-fn were defined here instead of hoisted to the top of the module,
286+ // the local variables (e.g. from for:each) would be closed-over. When hoisted,
287+ // however, we need to curry these variables.
288+ localVarIds ,
290289 shadowSlotContent
291290 ) ;
292291 cxt . hoist . templateFn ( shadowSlottedContentFn , node ) ;
293292 }
294293
295294 const shadowSlottedContentFn = hasShadowSlottedContent
296- ? bGenerateShadowSlottedContentRef ( b . identifier ( cxt . slots . shadow . getFnName ( uniqueNodeId ) ! ) )
295+ ? bGenerateShadowSlottedContentRef (
296+ b . identifier ( cxt . slots . shadow . getFnName ( uniqueNodeId ) ! ) ,
297+ localVarIds
298+ )
297299 : bNullishGenerateShadowSlottedContent ( ) ;
298300 const lightSlottedContentMap = hasLightSlottedContent
299301 ? bContentMap ( b . identifier ( 'lightSlottedContentMap' ) )
0 commit comments