import { extract_identifiers } from 'periscopic' ; import { BaseNode , SvelteIdentifier } from '../../interfaces' ; import { isDestructuringPatterns , isIdentifier } from '../../utils/svelteAst' ; import { usesLet } from '../utils/node-utils' ; export class TemplateScope { inits = new Set < string > ( ) ; parent ? : TemplateScope ; constructor ( parent ? ) { this . parent = parent ; } child ( ) { const child = new TemplateScope ( this ) ; return child ; } } export class TemplateScopeManager { value = new TemplateScope ( ) ; eachEnter ( node ) { this . value = this . value . child ( ) ; if ( node . context ) { this . handleScope ( node . context , node . children ) ; } if ( node . index ) { this . value . inits . add ( node . index ) ; } } eachLeave ( node ) { if ( ! node . else ) { this . value = this . value . parent ; } } awaitEnter ( node ) { this . value = this . value . child ( ) ; if ( node . value ) { this . handleScope ( node . value , node . then ?. children ) ; } if ( node . error ) { this . handleScope ( node . error , [ ] ) ; } } awaitPendingEnter ( node , parent ) { if ( node . skip || parent . type !== 'AwaitBlock' ) { return ; } this . value . inits . clear ( ) ; } awaitThenEnter ( node , parent ) { if ( node . skip || parent . type !== 'AwaitBlock' ) { return ; } this . value . inits . clear ( ) ; if ( parent . value ) { this . handleScope ( parent . value , node . children ) ; } } awaitCatchEnter ( node , parent ) { if ( node . skip || parent . type !== 'AwaitBlock' ) { return ; } this . value . inits . clear ( ) ; if ( parent . error ) { this . handleScope ( parent . error , node . children ) ; } } awaitLeave ( ) { this . value = this . value . parent ; } elseEnter ( parent ) { if ( parent . type === 'EachBlock' ) { this . value = this . value . parent ; } } componentOrSlotTemplateOrElementEnter ( node ) { const hasConstTags = node . children ?. some ( ( child ) => child . type === 'ConstTag' ) ; if ( usesLet ( node ) || hasConstTags ) { this . value = this . value . child ( ) ; this . handleScope ( { } as any , node . children ) ; } } componentOrSlotTemplateOrElementLeave ( node ) { if ( usesLet ( node ) ) { this . value = this . value . parent ; } } private handleScope ( identifierDef , children ) { if ( isIdentifier ( identifierDef ) ) { this . value . inits . add ( identifierDef . name ) ; } if ( isDestructuringPatterns ( identifierDef ) ) { const identifiers = extract_identifiers ( identifierDef ) as SvelteIdentifier [ ] ; identifiers . forEach ( ( id ) => this . value . inits . add ( id . name ) ) ; } if ( children ?. length ) { children . forEach ( ( child ) => { if ( child . type === 'ConstTag' ) { const identifiers = extract_identifiers ( child . expression . left ) as SvelteIdentifier [ ] ; identifiers . forEach ( ( id ) => this . value . inits . add ( id . name ) ) ; } } ) ; } } }